Coverage for gpaw/lrtddft/spectrum.py: 57%
96 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-12 00:18 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-12 00:18 +0000
1import sys
2import numpy as np
4from ase.units import _hbar, _c, _e, _me, Hartree, Bohr
5from gpaw import __version__ as version
6from gpaw.utilities.folder import Folder
9def get_folded_spectrum(
10 exlist=None,
11 emin=None,
12 emax=None,
13 de=None,
14 energyunit='eV',
15 folding='Gauss',
16 width=0.08, # Gauss/Lorentz width
17 form='r'):
18 """Return folded spectrum."""
20 x = []
21 y = []
22 for ex in exlist:
23 x.append(ex.get_energy() * Hartree)
24 y.append(ex.get_oscillator_strength(form))
26 if energyunit == 'nm':
27 # transform to experimentally used wavelength [nm]
28 x = 1.e+9 * 2 * np.pi * _hbar * _c / _e / np.array(x)
29 elif energyunit != 'eV':
30 raise RuntimeError('currently only eV and nm are supported')
32 if folding is None:
33 return x, y
34 else:
35 return Folder(width, folding).fold(x, y, de, emin, emax)
38def spectrum(exlist=None,
39 filename=None,
40 emin=None,
41 emax=None,
42 de=None,
43 energyunit='eV',
44 folding='Gauss',
45 width=0.08, # Gauss/Lorentz width
46 comment=None,
47 form='r'):
48 """Write out a folded spectrum.
50 Parameters
51 ----------
52 exlist: ExcitationList
53 filename:
54 File name for the output file, STDOUT if not given
55 emin:
56 min. energy, set to cover all energies if not given
57 emax:
58 max. energy, set to cover all energies if not given
59 de:
60 energy spacing
61 energyunit: {'eV', 'nm'}
62 Energy unit, default 'eV'
63 folding: {'Gauss', 'Lorentz'}
64 width:
65 folding width in terms of the chosen energyunit
66 """
68 # output
69 out = sys.stdout
70 if filename is not None:
71 with open(filename, 'w') as out:
72 if comment:
73 print('#', comment, file=out)
75 print('# Photoabsorption spectrum from linear response TD-DFT',
76 file=out)
77 print('# GPAW version:', version, file=out)
78 if folding is not None: # fold the spectrum
79 print(f'# {folding} folded, width={width:g} [{energyunit}]',
80 file=out)
81 if form == 'r':
82 out.write('# length form')
83 else:
84 assert form == 'v'
85 out.write('# velocity form')
86 print('# om [%s] osz osz x osz y osz z'
87 % energyunit, file=out)
89 energies, values = get_folded_spectrum(exlist, emin, emax, de,
90 energyunit, folding,
91 width, form)
93 for e, val in zip(energies, values):
94 print('%10.5f %12.7e %12.7e %11.7e %11.7e' %
95 (e, val[0], val[1], val[2], val[3]), file=out)
98def get_adsorbance_pre_factor(atoms):
99 """Return the absorbance pre-factor for solids. Unit m^-1.
101 Use this factor to multiply the folded oscillatior strength
102 obtained from spectrum()
104 Robert C. Hilborn, Am. J. Phys. 50, 982 (1982)
105 """
106 return np.pi * _e**2 / 2. / _me / _c
109def rotatory_spectrum(exlist=None,
110 filename=None,
111 emin=None,
112 emax=None,
113 de=None,
114 energyunit='eV',
115 folding='Gauss',
116 width=0.08, # Gauss/Lorentz width
117 comment=None):
118 """Write out a folded rotatory spectrum.
120 See spectrum() for explanation of the parameters.
121 """
123 # output
124 out = sys.stdout
125 if filename is not None:
126 with open(filename, 'w') as out:
127 if comment:
128 print('#', comment, file=out)
130 print('# Rotatory spectrum from linear response TD-DFT', file=out)
131 print('# GPAW version:', version, file=out)
132 if folding is not None: # fold the spectrum
133 print(f'# {folding} folded, width={width:g} [{energyunit}]',
134 file=out)
135 print(f'# om [{energyunit}] R [cgs]', file=out)
137 x = []
138 y = []
139 for ex in exlist:
140 x.append(ex.get_energy() * Hartree)
141 y.append(ex.get_rotatory_strength())
143 if energyunit == 'nm':
144 # transform to experimentally used wavelength [nm]
145 x = 1.e+9 * 2 * np.pi * _hbar * _c / _e / np.array(x)
146 y = np.array(y)
147 elif energyunit != 'eV':
148 raise RuntimeError('currently only eV and nm are supported')
150 if folding is None:
151 energies, values = x, y
152 else:
153 energies, values = Folder(width, folding).fold(x, y, de,
154 emin, emax)
155 for e, val in zip(energies, values):
156 print(f'{e:10.5f} {val:12.7e}', file=out)
159class Writer(Folder):
160 """Object to write data to a file"""
161 def __init__(self, folding=None, width=0.08):
162 """Evaluate the polarizability from sum over states.
164 Parameters
165 ----------
166 folding : string or None(default)
167 Name of the folding function, see gpaw/folder.py for options.
168 None means do not fold at all.
169 width : float
170 The width to be transferred to the folding function.
171 """
172 self.folding = folding
173 if folding is not None:
174 Folder.__init__(self, width, folding)
176 def write(self, filename=None,
177 emin=None, emax=None, de=None,
178 comment=None):
180 out = sys.stdout
181 if filename is not None:
182 with open(filename, 'w') as out:
183 print('#', self.title, file=out)
184 print('# GPAW version:', version, file=out)
185 if comment:
186 print('#', comment, file=out)
187 if self.folding is not None:
188 print('# {} folded, width={:g} [eV]'.format(self.folding,
189 self.width), file=out)
190 energies, values = self.fold(self.energies, self.values,
191 de, emin, emax)
192 else:
193 energies, values = self.energies, self.values
195 print('#', self.fields, file=out)
197 for e, val in zip(energies, values):
198 string = '%10.5f' % e
199 for vf in val:
200 string += ' %12.7e' % vf
201 print(string, file=out)
204def polarizability(exlist, omega, form='v',
205 tensor=False, index=0):
206 """Evaluate the polarizability from sum over states.
208 Parameters
209 ----------
210 exlist: ExcitationList
211 omega:
212 Photon energy (eV)
213 form: {'v', 'r'}
214 Form of the dipole matrix element
215 index: {0, 1, 2, 3}
216 0: averaged, 1,2,3:alpha_xx, alpha_yy, alpha_zz
217 tensor:
218 if True returns alpha_ij, i,j=x,y,z
219 index is ignored
221 Returns
222 -------
223 alpha:
224 Unit (e^2 Angstrom^2 / eV).
225 Multiply with Bohr * Ha to get (Angstrom^3)
226 """
227 if tensor:
228 alpha = np.zeros(np.array(omega).shape + (3, 3), dtype=complex)
229 for ex in exlist:
230 alpha += ex.get_dipole_tensor(form=form) / (
231 (ex.energy * Hartree)**2 - omega**2)
232 else:
233 alpha = np.zeros_like(omega)
234 for ex in exlist:
235 alpha += ex.get_oscillator_strength(form=form)[index] / (
236 (ex.energy * Hartree)**2 - omega**2)
238 return alpha * Bohr**2 * Hartree