File: excitation_list.py

package info (click to toggle)
python-ase 3.21.1-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 13,936 kB
  • sloc: python: 122,428; xml: 946; makefile: 111; javascript: 47
file content (147 lines) | stat: -rw-r--r-- 4,582 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import numpy as np

from ase.units import Hartree, Bohr


class Excitation:
    """Base class for a single excitation"""
    def __init__(self, energy, index, mur, muv=None, magn=None):
        """
        Parameters
        ----------
        energy: float
          Energy realtive to the ground state
        index: int
          Excited state index
        mur: list of three floats or complex numbers
          Length form dipole matrix element
        muv: list of three floats or complex numbers or None
          Velocity form dipole matrix element, default None
        magn: list of three floats or complex numbers or None
          Magnetic matrix element, default None
        """
        self.energy = energy
        self.index = index
        self.mur = mur
        self.muv = muv
        self.magn = magn
        self.fij = 1.

    def outstring(self):
        """Format yourself as a string"""
        string = '{0:g}  {1}  '.format(self.energy, self.index)

        def format_me(me):
            string = ''
            if me.dtype == float:
                for m in me:
                    string += ' {0:g}'.format(m)
            else:
                for m in me:
                    string += ' {0.real:g}{0.imag:+g}j'.format(m)
            return string

        string += '  ' + format_me(self.mur)
        if self.muv is not None:
            string += '  ' + format_me(self.muv)
        if self.magn is not None:
            string += '  ' + format_me(self.magn)
        string += '\n'

        return string

    @classmethod
    def fromstring(cls, string):
        """Initialize yourself from a string"""
        l = string.split()
        energy = float(l.pop(0))
        index = int(l.pop(0))
        mur = np.array([float(l.pop(0)) for i in range(3)])
        try:
            muv = np.array([float(l.pop(0)) for i in range(3)])
        except IndexError:
            muv = None
        try:
            magn = np.array([float(l.pop(0)) for i in range(3)])
        except IndexError:
            magn = None
       
        return cls(energy, index, mur, muv, magn)

    def get_dipole_me(self, form='r'):
        """Return the excitations dipole matrix element
        including the occupation factor sqrt(fij)"""
        if form == 'r':  # length form
            me = - self.mur
        elif form == 'v':  # velocity form
            me = - self.muv
        else:
            raise RuntimeError('Unknown form >' + form + '<')
        return np.sqrt(self.fij) * me

    def get_dipole_tensor(self, form='r'):
        """Return the oscillator strength tensor"""
        me = self.get_dipole_me(form)
        return 2 * np.outer(me, me.conj()) * self.energy / Hartree

    def get_oscillator_strength(self, form='r'):
        """Return the excitations dipole oscillator strength."""
        me2_c = self.get_dipole_tensor(form).diagonal().real
        return np.array([np.sum(me2_c) / 3.] + me2_c.tolist())


class ExcitationList(list):
    """Base class for excitions from the ground state"""
    def __init__(self):
        # initialise empty list
        super().__init__()
        
        # set default energy scale to get eV
        self.energy_to_eV_scale = 1.


def polarizability(exlist, omega, form='v',
                   tensor=False, index=0):
    """Evaluate the photon energy dependent polarizability
    from the sum over states

    Parameters
    ----------
    exlist: ExcitationList
    omega:
        Photon energy (eV)
    form: {'v', 'r'}
        Form of the dipole matrix element, default 'v'
    index: {0, 1, 2, 3}
        0: averaged, 1,2,3:alpha_xx, alpha_yy, alpha_zz, default 0
    tensor: boolean
        if True returns alpha_ij, i,j=x,y,z
        index is ignored, default False

    Returns
    -------
    alpha:
        Unit (e^2 Angstrom^2 / eV).
        Multiply with Bohr * Ha to get (Angstrom^3)
        shape = (omega.shape,) if tensor == False
        shape = (omega.shape, 3, 3) else
    """
    omega = np.asarray(omega)
    om2 = 1. * omega**2
    esc = exlist.energy_to_eV_scale

    if tensor:
        if not np.isscalar(om2):
            om2 = om2[:, None, None]
        alpha = np.zeros(omega.shape + (3, 3),
                         dtype=om2.dtype)
        for ex in exlist:
            alpha += ex.get_dipole_tensor(form=form) / (
                (ex.energy * esc)**2 - om2)
    else:
        alpha = np.zeros_like(om2)
        for ex in exlist:
            alpha += ex.get_oscillator_strength(form=form)[index] / (
                (ex.energy * esc)**2 - om2)

    return alpha * Bohr**2 * Hartree