Пример #1
0
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)
Пример #2
0
    def meA(self, omega, gamma=0.1):
        """Evaluate Albrecht A term.

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

        self.timer.start('AlbrechtA')

        if not hasattr(self, 'fcr'):
            self.fcr = FranckCondonRecursive()

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

        n_p, myp, exF_pr = self.init_parallel_excitations()
        exF_pr = np.where(np.abs(exF_pr) > 1e-2, exF_pr, 0)

        m_Qcc = np.zeros((self.ndof, 3, 3), dtype=complex)
        for p in myp:
            energy = self.ex0E_p[p]
            d_Q = self.unitless_displacements(exF_pr[p])
            energy_Q = energy - self.om_Q * d_Q**2 / 2.
            me_cc = np.outer(self.ex0m_pc[p], self.ex0m_pc[p].conj())

            wm_Q = np.zeros((self.ndof), dtype=complex)
            wp_Q = np.zeros((self.ndof), dtype=complex)
            for m in range(self.nm):
                self.timer.start('0mm1')
                fco_Q = self.fcr.direct0mm1(m, d_Q)
                self.timer.stop('0mm1')

                self.timer.start('weight_Q')
                e_Q = energy_Q + m * self.om_Q
                wm_Q += fco_Q / (e_Q - omL)
                wp_Q += fco_Q / (e_Q + omS_Q)
                self.timer.stop('weight_Q')
            self.timer.start('einsum')
            m_Qcc += np.einsum('a,bc->abc', wm_Q, me_cc)
            m_Qcc += np.einsum('a,bc->abc', wp_Q, me_cc.conj())
            self.timer.stop('einsum')
        self.comm.sum(m_Qcc)

        self.timer.stop('AlbrechtA')
        return m_Qcc  # e^2 Angstrom^2 / eV
Пример #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)
Пример #4
0
    def meAmult(self, omega, gamma=0.1):
        """Evaluate Albrecht A term.

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

        if not hasattr(self, 'fcr'):
            self.fcr = FranckCondonRecursive()

        omL = omega + 1j * gamma
        omS_v = omL - self.om_v
        nv = len(self.om_v)
        om_Q = self.om_Q[self.skip:]
        nQ = len(om_Q)

        # n_v:
        #     how many FC factors are involved
        # nvib_ov:
        #     delta functions to switch contributions depending on order o
        # ind_ov:
        #     Q indicees
        # n_ov:
        #     # of vibrational excitations
        n_v = self.d_vQ.sum(axis=1)  # multiplicity

        nvib_ov = np.empty((self.combinations, nv), dtype=int)
        om_ov = np.zeros((self.combinations, nv), dtype=float)
        n_ov = np.zeros((self.combinations, nv), dtype=int)
        d_ovQ = np.zeros((self.combinations, nv, nQ), dtype=int)
        for o in range(self.combinations):
            nvib_ov[o] = np.array(n_v == (o + 1))
            for v in range(nv):
                try:
                    om_ov[o, v] = om_Q[self.ind_v[v][o]]
                    d_ovQ[o, v, self.ind_v[v][o]] = 1
                except IndexError:
                    pass
        # XXXX change ????
        n_ov[0] = self.n_vQ.max(axis=1)
        n_ov[1] = nvib_ov[1]

        n_p, myp, exF_pr = self.init_parallel_excitations()

        m_vcc = np.zeros((nv, 3, 3), dtype=complex)
        for p in myp:
            energy = self.ex0E_p[p]
            d_Q = self.unitless_displacements(exF_pr[p])[self.skip:]
            S_Q = d_Q**2 / 2.
            energy_v = energy - self.d_vQ.dot(om_Q * S_Q)
            me_cc = np.outer(self.ex0m_pc[p], self.ex0m_pc[p].conj())

            fco1_mQ = np.empty((self.nm, nQ), dtype=float)
            fco2_mQ = np.empty((self.nm, nQ), dtype=float)
            for m in range(self.nm):
                fco1_mQ[m] = self.fcr.direct0mm1(m, d_Q)
                fco2_mQ[m] = self.fcr.direct0mm2(m, d_Q)

            wm_v = np.zeros((nv), dtype=complex)
            wp_v = np.zeros((nv), dtype=complex)
            for m in range(self.nm):
                fco1_v = np.where(n_ov[0] == 2, d_ovQ[0].dot(fco2_mQ[m]),
                                  d_ovQ[0].dot(fco1_mQ[m]))

                em_v = energy_v + m * om_ov[0]
                # multiples of same kind
                fco_v = nvib_ov[0] * fco1_v
                wm_v += fco_v / (em_v - omL)
                wp_v += fco_v / (em_v + omS_v)
                if nvib_ov[1].any():
                    # multiples of mixed type
                    for n in range(self.nm):
                        fco2_v = d_ovQ[1].dot(fco1_mQ[n])
                        e_v = em_v + n * om_ov[1]
                        fco_v = nvib_ov[1] * fco1_v * fco2_v
                        wm_v += fco_v / (e_v - omL)
                        wp_v += fco_v / (e_v + omS_v)

            m_vcc += np.einsum('a,bc->abc', wm_v, me_cc)
            m_vcc += np.einsum('a,bc->abc', wp_v, me_cc.conj())
        self.comm.sum(m_vcc)

        return m_vcc  # e^2 Angstrom^2 / eV
Пример #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
S = 2