def test_franck_condon(testdir):
    # FCOverlap

    fco = FranckCondonOverlap()
    fcr = FranckCondonRecursive()

    # check factorial
    assert (fco.factorial(8) == factorial(8))
    # the second test is useful according to the implementation
    assert (fco.factorial(5) == factorial(5))
    assert (fco.factorial.inv(5) == 1. / factorial(5))

    # check T=0 and n=0 equality
    S = np.array([1, 2.1, 34])
    m = 5
    assert (((fco.directT0(m, S) - fco.direct(0, m, S)) / fco.directT0(m, S) <
             1e-15).all())

    # check symmetry
    S = 2
    n = 3
    assert (fco.direct(n, m, S) == fco.direct(m, n, S))

    # ---------------------------
    # specials
    S = np.array([0, 1.5])
    delta = np.sqrt(2 * S)
    for m in [2, 7]:
        equal(
            fco.direct0mm1(m, S)**2,
            fco.direct(1, m, S) * fco.direct(m, 0, S), 1.e-17)
        equal(fco.direct0mm1(m, S), fcr.ov0mm1(m, delta), 1.e-15)
        equal(fcr.ov0mm1(m, delta),
              fcr.ov0m(m, delta) * fcr.ov1m(m, delta), 1.e-15)
        equal(fcr.ov0mm1(m, -delta), fcr.direct0mm1(m, -delta), 1.e-15)
        equal(fcr.ov0mm1(m, delta), -fcr.direct0mm1(m, -delta), 1.e-15)

        equal(
            fco.direct0mm2(m, S)**2,
            fco.direct(2, m, S) * fco.direct(m, 0, S), 1.e-17)
        equal(fco.direct0mm2(m, S), fcr.ov0mm2(m, delta), 1.e-15)
        equal(fcr.ov0mm2(m, delta),
              fcr.ov0m(m, delta) * fcr.ov2m(m, delta), 1.e-15)
        equal(fco.direct0mm2(m, S), fcr.direct0mm2(m, delta), 1.e-15)

        equal(fcr.direct0mm3(m, delta),
              fcr.ov0m(m, delta) * fcr.ov3m(m, delta), 1.e-15)

        equal(fcr.ov1mm2(m, delta),
              fcr.ov1m(m, delta) * fcr.ov2m(m, delta), 1.e-15)
        equal(fcr.direct1mm2(m, delta), fcr.ov1mm2(m, delta), 1.e-15)
Exemple #2
0
    def get_matrix_element_AlbrechtA(self, omega, gamma=0.1, ml=range(16)):
        """Evaluate Albrecht A term.

        Unit: |e|^2Angstrom^2/eV
        """
        self.read()

        self.timer.start('AlbrechtA')

        if not hasattr(self, 'fco'):
            self.fco = FranckCondonOverlap()

        # excited state forces
        F_pr = self.exF_rp.T

        m_rcc = np.zeros((self.ndof, 3, 3), dtype=complex)
        for p, energy in enumerate(self.ex0E_p):
            S_r = self.get_Huang_Rhys_factors(F_pr[p])
            me_cc = np.outer(self.ex0m_pc[p], self.ex0m_pc[p].conj())

            for m in ml:
                self.timer.start('0mm1')
                fco_r = self.fco.direct0mm1(m, S_r)
                self.timer.stop('0mm1')
                self.timer.start('einsum')
                m_rcc += np.einsum(
                    'a,bc->abc',
                    fco_r / (energy + m * self.om_r - omega - 1j * gamma),
                    me_cc)
                m_rcc += np.einsum(
                    'a,bc->abc', fco_r /
                    (energy + (m - 1) * self.om_r + omega + 1j * gamma), me_cc)
                self.timer.stop('einsum')

        self.timer.stop('AlbrechtA')
        return m_rcc
Exemple #3
0
def test_franck_condon():
    import sys
    import numpy as np

    from ase.vibrations.franck_condon import FranckCondonOverlap, FranckCondonRecursive
    from math import factorial


    def equal(x, y, tolerance=0, fail=True, msg=''):
        """Compare x and y."""

        if not np.isfinite(x - y).any() or (np.abs(x - y) > tolerance).any():
            msg = (msg + '%s != %s (error: |%s| > %.9g)' %
                   (x, y, x - y, tolerance))
            if fail:
                raise AssertionError(msg)
            else:
                sys.stderr.write('WARNING: %s\n' % msg)

    # FCOverlap

    fco = FranckCondonOverlap()
    fcr = FranckCondonRecursive()

    # check factorial
    assert(fco.factorial(8) == factorial(8))
    # the second test is useful according to the implementation
    assert(fco.factorial(5) == factorial(5))
    assert(fco.factorial.inv(5) == 1. / factorial(5))

    # check T=0 and n=0 equality
    S = np.array([1, 2.1, 34])
    m = 5
    assert(((fco.directT0(m, S) - fco.direct(0, m, S)) / fco.directT0(m, S) <
            1e-15).all())

    # check symmetry
    S = 2
    n = 3
    assert(fco.direct(n, m, S) == fco.direct(m, n, S))

    # ---------------------------
    # specials
    S = np.array([0, 1.5])
    delta = np.sqrt(2 * S)
    for m in [2, 7]:
        equal(fco.direct0mm1(m, S)**2,
              fco.direct(1, m, S) * fco.direct(m, 0, S), 1.e-17)
        equal(fco.direct0mm1(m, S), fcr.ov0mm1(m, delta), 1.e-15)
        equal(fcr.ov0mm1(m, delta),
              fcr.ov0m(m, delta) * fcr.ov1m(m, delta), 1.e-15)
        equal(fcr.ov0mm1(m, -delta), fcr.direct0mm1(m, -delta), 1.e-15)
        equal(fcr.ov0mm1(m, delta), - fcr.direct0mm1(m, -delta), 1.e-15)

        equal(fco.direct0mm2(m, S)**2,
              fco.direct(2, m, S) * fco.direct(m, 0, S), 1.e-17)
        equal(fco.direct0mm2(m, S), fcr.ov0mm2(m, delta), 1.e-15)
        equal(fcr.ov0mm2(m, delta),
              fcr.ov0m(m, delta) * fcr.ov2m(m, delta), 1.e-15)
        equal(fco.direct0mm2(m, S), fcr.direct0mm2(m, delta), 1.e-15)

        equal(fcr.direct0mm3(m, delta),
              fcr.ov0m(m, delta) * fcr.ov3m(m, delta), 1.e-15)

        equal(fcr.ov1mm2(m, delta),
              fcr.ov1m(m, delta) * fcr.ov2m(m, delta), 1.e-15)
        equal(fcr.direct1mm2(m, delta), fcr.ov1mm2(m, delta), 1.e-15)
Exemple #4
0
    def meBC(self, omega, gamma=0.1, term='BC'):
        """Evaluate Albrecht BC term.

        Returns
        -------
        Full Albrecht BC matrix element.
        Unit: e^2 Angstrom / eV / sqrt(amu)
        """
        self.read()

        if not hasattr(self, 'fco'):
            self.fco = FranckCondonOverlap()

        omL = omega + 1j * gamma
        omS_Q = omL - self.om_Q

        # excited state forces
        n_p, myp, exF_pr = self.init_parallel_excitations()
        # derivatives after normal coordinates
        exdmdr_rpc = self._collect_r(self.exdmdr_rpc, [n_p, 3],
                                     self.ex0m_pc.dtype)
        dmdq_qpc = (exdmdr_rpc.T * self.im_r).T  # unit e / sqrt(amu)
        dmdQ_Qpc = np.dot(dmdq_qpc.T, self.modes_Qq.T).T  # unit e / sqrt(amu)

        me_Qcc = np.zeros((self.ndof, 3, 3), dtype=complex)
        for p in myp:
            energy = self.ex0E_p[p]
            S_Q = self.Huang_Rhys_factors(exF_pr[p])
            # relaxed excited state energy
            # # n_vQ = np.where(self.n_vQ > 0, 1, 0)
            # # energy_v = energy - n_vQ.dot(self.om_Q * S_Q)
            energy_Q = energy - self.om_Q * S_Q

            # # me_cc = np.outer(self.ex0m_pc[p], self.ex0m_pc[p].conj())
            m_c = self.ex0m_pc[p]  # e Angstrom
            dmdQ_Qc = dmdQ_Qpc[:, p]  # e / sqrt(amu)

            wBLS_Q = np.zeros((self.ndof), dtype=complex)
            wBSL_Q = np.zeros((self.ndof), dtype=complex)
            wCLS_Q = np.zeros((self.ndof), dtype=complex)
            wCSL_Q = np.zeros((self.ndof), dtype=complex)
            for m in range(self.nm):
                f0mmQ1_Q = (self.fco.directT0(m, S_Q) +
                            np.sqrt(2) * self.fco.direct0mm2(m, S_Q))
                f0Qmm1_Q = self.fco.direct(1, m, S_Q)

                em_Q = energy_Q + m * self.om_Q
                wBLS_Q += f0mmQ1_Q / (em_Q - omL)
                wBSL_Q += f0Qmm1_Q / (em_Q - omL)
                wCLS_Q += f0mmQ1_Q / (em_Q + omS_Q)
                wCSL_Q += f0Qmm1_Q / (em_Q + omS_Q)

            # unit e^2 Angstrom / sqrt(amu)
            mdmdQ_Qcc = np.einsum('a,bc->bac', m_c, dmdQ_Qc.conj())
            dmdQm_Qcc = np.einsum('ab,c->abc', dmdQ_Qc, m_c.conj())
            if 'B' in term:
                me_Qcc += np.multiply(wBLS_Q, mdmdQ_Qcc.T).T
                me_Qcc += np.multiply(wBSL_Q, dmdQm_Qcc.T).T
            if 'C' in term:
                me_Qcc += np.multiply(wCLS_Q, mdmdQ_Qcc.T).T
                me_Qcc += np.multiply(wCSL_Q, dmdQm_Qcc.T).T

        self.comm.sum(me_Qcc)
        return me_Qcc  # unit e^2 Angstrom / eV / sqrt(amu)
Exemple #5
0
def equal(x, y, tolerance=0, fail=True, msg=''):
    """Compare x and y."""

    if not np.isfinite(x - y).any() or (np.abs(x - y) > tolerance).any():
        msg = (msg + '%s != %s (error: |%s| > %.9g)' %
               (x, y, x - y, tolerance))
        if fail:
            raise AssertionError(msg)
        else:
            sys.stderr.write('WARNING: %s\n' % msg)


# FCOverlap

fco = FranckCondonOverlap()
fcr = FranckCondonRecursive()

# check factorial
assert (fco.factorial(8) == factorial(8))
# the second test is useful according to the implementation
assert (fco.factorial(5) == factorial(5))
assert (fco.factorial.inv(5) == 1. / factorial(5))

# check T=0 and n=0 equality
S = np.array([1, 2.1, 34])
m = 5
assert (((fco.directT0(m, S) - fco.direct(0, m, S)) / fco.directT0(m, S) <
         1e-15).all())

# check symmetry
Exemple #6
0
    def get_matrix_element_AlbrechtBC(self,
                                      omega,
                                      gamma=0.1,
                                      ml=[1],
                                      term='BC'):
        """Evaluate Albrecht B and/or C term(s)."""
        self.read()

        self.timer.start('AlbrechtBC')

        if not hasattr(self, 'fco'):
            self.fco = FranckCondonOverlap()

        # excited state forces
        F_pr = self.exF_rp.T

        m_rcc = np.zeros((self.ndof, 3, 3), dtype=complex)
        for p, energy in enumerate(self.ex0E_p):
            S_r = self.get_Huang_Rhys_factors(F_pr[p])

            for m in ml:
                self.timer.start('Franck-Condon overlaps')
                fc1mm1_r = self.fco.direct(1, m, S_r)
                fc0mm02_r = self.fco.direct(0, m, S_r)
                fc0mm02_r += np.sqrt(2) * self.fco.direct0mm2(m, S_r)
                # XXXXX
                fc1mm1_r[-1] = 1
                fc0mm02_r[-1] = 1
                print(m, fc1mm1_r[-1], fc0mm02_r[-1])
                self.timer.stop('Franck-Condon overlaps')

                self.timer.start('me dervivatives')
                dm_rc = []
                r = 0
                for a in self.indices:
                    for i in 'xyz':
                        dm_rc.append(
                            (self.expm_rpc[r, p] - self.exmm_rpc[r, p]) *
                            self.im[r])
                        print('pm=', self.expm_rpc[r, p], self.exmm_rpc[r, p])
                        r += 1
                dm_rc = np.array(dm_rc) / (2 * self.delta)
                self.timer.stop('me dervivatives')

                self.timer.start('map to modes')
                # print('dm_rc[2], dm_rc[5]', dm_rc[2], dm_rc[5])
                print('dm_rc=', dm_rc)
                dm_rc = np.dot(dm_rc.T, self.modes.T).T
                print('dm_rc[-1][2]', dm_rc[-1][2])
                self.timer.stop('map to modes')

                self.timer.start('multiply')
                # me_cc = np.outer(self.ex0m_pc[p], self.ex0m_pc[p].conj())
                for r in range(self.ndof):
                    if 'B' in term:
                        # XXXX
                        denom = (1. / (energy + m * 0 * self.om_r[r] - omega -
                                       1j * gamma))
                        # ok print('denom=', denom)
                        m_rcc[r] += (
                            np.outer(dm_rc[r], self.ex0m_pc[p].conj()) *
                            fc1mm1_r[r] * denom)
                        if r == 5:
                            print('m_rcc[r]=', m_rcc[r][2, 2])
                        m_rcc[r] += (
                            np.outer(self.ex0m_pc[p], dm_rc[r].conj()) *
                            fc0mm02_r[r] * denom)
                    if 'C' in term:
                        denom = (1. /
                                 (energy +
                                  (m - 1) * self.om_r[r] + omega + 1j * gamma))
                        m_rcc[r] += (
                            np.outer(self.ex0m_pc[p], dm_rc[r].conj()) *
                            fc1mm1_r[r] * denom)
                        m_rcc[r] += (
                            np.outer(dm_rc[r], self.ex0m_pc[p].conj()) *
                            fc0mm02_r[r] * denom)
                self.timer.stop('multiply')
        print('m_rcc[-1]=', m_rcc[-1][2, 2])

        self.timer.start('pre_r')
        with np.errstate(divide='ignore'):
            pre_r = np.where(self.om_r > 0,
                             np.sqrt(units._hbar**2 / 2. / self.om_r), 0)
            # print('BC: pre_r=', pre_r)
        for r, p in enumerate(pre_r):
            m_rcc[r] *= p
        self.timer.stop('pre_r')
        self.timer.stop('AlbrechtBC')
        return m_rcc