(Resonant-)Raman spectra of gas-phase water
This tutorial shows how to calculate (resonant-)Raman spectra of a single water molecule in the gas-phase. The theoretical background can be found in Ref. [1].
Accurate Forces from an IR calculation
A pre-condition for accurate forces and thus accurate vibrational frequencies
is relaxation with a rather small maximal force and a smaller gid-spacing
than is needed for excitated state calculations.
This is possible using the Vibrations
or
Infrared
modules.
from ase import optimize
from ase.build import molecule
from ase.vibrations.infrared import Infrared
from gpaw import GPAW, FermiDirac
from gpaw.utilities.adjust_cell import adjust_cell
h = 0.20
atoms = molecule('H2O')
adjust_cell(atoms, 4, h=h)
# relax the molecule
calc = GPAW(mode='fd', xc='PBE', h=h, occupations=FermiDirac(width=0.1))
atoms.calc = calc
dyn = optimize.FIRE(atoms)
dyn.run(fmax=0.01)
atoms.write('relaxed.traj')
# finite displacement for vibrations
atoms.calc = calc.new(symmetry={'point_group': False})
ir = Infrared(atoms, name='ir')
ir.run()
We can get the resulting frequencies
# web-page: H2O_ir_summary.txt
from ase import io
from ase.vibrations.infrared import Infrared
atoms = io.read('relaxed.traj')
ir = Infrared(atoms, name='ir')
with open('H2O_ir_summary.txt', 'w') as fd:
ir.summary(log=fd)
with the result:
-------------------------------------
Mode Frequency Intensity
# meV cm^-1 (D/Å)^2 amu^-1
-------------------------------------
0 27.6i 223.0i 0.0190
1 24.2i 195.1i 0.5695
2 20.7i 167.0i 4.5901
3 19.5i 157.4i 0.1126
4 16.4i 132.5i 0.0030
5 29.7 239.9 1.8388
6 198.7 1602.7 1.6509
7 461.5 3722.0 0.0679
8 474.3 3825.4 1.2355
-------------------------------------
Zero-point energy: 0.582 eV
Static dipole moment: 1.825 D
Maximum force on atom in `equilibrium`: 0.0094 eV/Å
Only the last three vibrations are meaningful.
Static Raman from polarizabilities
The photon energy of the excitation laser in Raman experiments is often well below electronic excitations of the molecules. Then the approximation to obtain Raman spectra from static polarizabilities is valid. Here, we use the static polariability obtained from external electric fields.
from ase.vibrations.raman import StaticRamanCalculator
from ase.io import read
from gpaw import GPAW, FermiDirac
from gpaw.utilities.adjust_cell import adjust_cell
from gpaw.external import static_polarizability
h = 0.2
xc = 'PBE'
atoms = read('relaxed.traj')
adjust_cell(atoms, 4., h=h)
atoms.calc = GPAW(mode='fd', xc=xc, h=h,
occupations=FermiDirac(width=0.1),
symmetry={'point_group': False})
atoms.get_potential_energy()
class Polarizability:
def __call__(self, atoms):
return static_polarizability(atoms)
name = exname = 'static_raman'
ram = StaticRamanCalculator(
atoms, Polarizability, name=name)
ram.run()
ram.summary()
We can get the resulting frequencies and intensities
# web-page: H2O_Placzek_static_summary.txt
from ase import io
from ase.vibrations.placzek import PlaczekStatic
atoms = io.read('relaxed.traj')
ram = PlaczekStatic(atoms, name='static_raman')
with open('H2O_Placzek_static_summary.txt', 'w') as fd:
ram.summary(log=fd)
with the result:
-------------------------------------
Mode Frequency Intensity
# meV cm^-1 [A^4/amu]
-------------------------------------
0 0.0 0.0 0.00
1 0.0 0.0 0.00
2 0.0 0.0 0.00
3 0.0 0.0 0.00
4 0.0 0.0 0.02
5 32.2 260.1 0.00
6 199.1 1605.6 0.87
7 461.3 3720.5 112.74
8 474.1 3823.9 27.21
-------------------------------------
Again, only the last three vibrations are meaningful.
Resonant Raman: Excitations at each displacement
We need to calculate the excitations at each displament and use
linear response TDDFT for this. This is the most time consuming
part of the calculation an we therfore use the coarser grid spacing
of h=0.25
. We restrict to the first excitations
of the water molecule by setting
{'restrict': {'energy_range': erange, 'eps': 0.4}}
.
Note, that the number of bands in the calculation is connected
to this.
from ase.vibrations.resonant_raman import ResonantRamanCalculator
from ase.io import read
from gpaw import GPAW, FermiDirac
from gpaw.utilities.adjust_cell import adjust_cell
from gpaw.lrtddft import LrTDDFT
h = 0.25
xc = 'PBE'
atoms = read('relaxed.traj')
adjust_cell(atoms, 4., h=h)
atoms.calc = GPAW(mode='fd', xc=xc, h=h, nbands=50,
occupations=FermiDirac(width=0.1),
eigensolver='cg', symmetry={'point_group': False},
convergence={'eigenstates': 1.e-5, 'bands': -10})
atoms.get_potential_energy()
erange = 17
ext = '_erange{0}'.format(erange)
gsname = exname = 'rraman' + ext
rr = ResonantRamanCalculator(
atoms, LrTDDFT, name=gsname, exname=exname,
exkwargs={'restrict': {'energy_range': erange, 'eps': 0.4}},)
rr.run()
Raman intensities
We have to choose an approximation to evaluate the Raman intensities.
The most common is the Placzek approximation which we also apply here.
We may use summary()
similar to Infrared
,
but the Raman intensity depends on the excitation frequency.
# web-page: H2O_rraman_summary.txt
from ase import io
from ase.vibrations.placzek import Placzek
from gpaw.lrtddft import LrTDDFT
atoms = io.read('relaxed.traj')
pz = Placzek(atoms, LrTDDFT,
name='ir', # use ir-calculation for frequencies
exname='rraman_erange17') # use LrTDDFT for intensities
omega = 0 # excitation frequency
gamma = 0.2 # width
with open('H2O_rraman_summary.txt', 'w') as fd:
pz.summary(omega, gamma, log=fd)
with the result:
-------------------------------------
excitation at 0 eV
gamma 0.2 eV
method: standard
approximation: PlaczekAlpha
Mode Frequency Intensity
# meV cm^-1 [A^4/amu]
-------------------------------------
0 0.0 0.0 0.01
1 0.0 0.0 0.00
2 0.0 0.0 0.01
3 0.0 0.0 0.41
4 0.0 0.0 1.12
5 29.7 239.9 0.12
6 198.7 1602.7 43.33
7 461.5 3722.0 154.76
8 474.3 3825.4 57.14
-------------------------------------
Zero-point energy: 0.582 eV
Note, that the absolute intensity [1] is given in the summary.
Raman spectrum
The Raman spectrum be compared to experiment shown above can be obtained with the following script
# web-page: H2O_rraman_spectrum.png
import matplotlib.pyplot as plt
from ase import io
from ase.vibrations.placzek import Placzek
from gpaw.lrtddft import LrTDDFT
atoms = io.read('relaxed.traj')
pz = Placzek(atoms, LrTDDFT,
name='ir', # use ir-calculation for frequencies
exname='rraman_erange17') # use LrTDDFT for intensities
gamma = 0.2 # width
for i, omega in enumerate([2.41, 8]): # photon energies
plt.subplot(211 + i)
x, y = pz.get_spectrum(omega, gamma,
start=1000, end=4000, type='Lorentzian')
plt.text(0.1, 0.8, f'{omega} eV', transform=plt.gca().transAxes)
plt.plot(x, y)
plt.ylabel('cross section')
plt.xlabel('frequency [cm$^{-1}$]')
plt.savefig('H2O_rraman_spectrum.png')
The figure shows the sensitivity of relative peak heights on the scattered photons energy.