Example: Vibration resolved electronic spectrum: plams¶
Download GOFREQ_LR-TDDFTB_anthracene_S0S1fcf.run
#!/bin/sh
cp $TEST_DIRECTORY/GOFREQ_LR-TDDFTB_anthracene_S0S1fcf.plms .
cp $TEST_DIRECTORY/anthracene.xyz .
$AMSBIN/plams GOFREQ_LR-TDDFTB_anthracene_S0S1fcf.plms
Download GOFREQ_LR-TDDFTB_anthracene_S0S1fcf.plms
import sys
import numpy as np
config.log.stdout = 0
# This test calculates the vibrational fine structure of the S_0 -> S_1 transition in anthracene.
molfile = "anthracene.xyz"
excit = 1
# Common settings for all DFTB calculations:
comin = Settings()
comin.input.DFTB.resourcesdir = "DFTB.org/3ob-freq-1-2"
comin.input.DFTB.model = "DFTB3"
# ========= auxilliary functions ==================================================================
def get_total_energy(results):
nprop = results.readrkf("Properties", "nEntries", file="dftb")
for i in range(1, nprop + 1):
if results.readrkf("Properties", "Subtype(%i)" % i, file="dftb").strip() == "DFTB Final Energy":
return results.readrkf("Properties", "Value(%i)" % i, file="dftb")
return None
def get_zero_point_energy(results):
freqs = results.readrkf("Vibrations", "Frequencies[cm-1]", file="dftb")
if isinstance(freqs, list):
return Units.convert(0.5 * sum(freqs), "cm^-1", "Hartree")
else:
return Units.convert(0.5 * freqs, "cm^-1", "Hartree")
def extract_spectrum(fcf_results):
return np.array(fcf_results.readkf("Fcf", "spectrum")).reshape(2, -1).transpose()
# ========= STEP 1: Ground state ==================================================================
# Optimize ground state geometry:
gs_mol_unoptimized = Molecule(filename=molfile)
gs_go = AMSJob(name="gs_go", molecule=gs_mol_unoptimized, settings=comin)
gs_go.settings.input.ams.Task = "GeometryOptimization"
gs_go.settings.input.ams.GeometryOptimization.convergence = "Gradients=1.0e-5"
gs_go_results = gs_go.run()
if not gs_go.check():
print("ERROR: Ground state optimization crashed")
sys.exit(1)
if gs_go_results.grep_output("Optimization Did Not Converge"):
print("ERROR: Ground state optimization did not converge")
sys.exit(1)
gs_mol_optimized = gs_go_results.get_molecule("Molecule")
# Calculate frequencies and normal modes of the ground state:
gs_freq = AMSJob(name="gs_freq", molecule=gs_mol_optimized, settings=comin)
gs_freq.settings.input.ams.Task = "SinglePoint"
gs_freq.settings.input.ams.properties.NormalModes = "true"
gs_freq.settings.input.ams.NumericalDifferentiation.Parallel.nCoresPerGroup = 1
gs_freq_results = gs_freq.run()
if not gs_freq.check():
print("ERROR: Ground state frequency calculation crashed")
sys.exit(1)
# Calculate vertical excitations:
gs_excit = AMSJob(name="gs_excit", molecule=gs_mol_optimized, settings=comin)
gs_excit.settings.input.ams.Task = "SinglePoint"
gs_excit.settings.input.DFTB.properties.excitations.tddftb.calc = "singlet"
gs_excit.settings.input.DFTB.properties.excitations.tddftb.lowest = excit + 9
gs_excit.settings.input.DFTB.properties.excitations.tddftb["print"] = "evcontribs"
gs_excit_results = gs_excit.run()
if not gs_excit.check():
print("ERROR: Ground state excitations calculation crashed")
sys.exit(1)
# Print ground state energies:
print("Energies in the ground state equilibrium geometry:")
E_DFTB_RGS = get_total_energy(gs_excit_results)
E_ZPE_RGS = get_zero_point_energy(gs_freq_results)
Delta_RGS = gs_excit_results.readrkf("Excitations SS A", "excenergies", file="dftb")[excit - 1]
E_GS = E_DFTB_RGS + E_ZPE_RGS
print(" E_DFTB(R_GS) = %f eV" % (Units.convert(E_DFTB_RGS, "Hartree", "eV")))
print(" E_ZPE(R_GS) = %f eV" % (Units.convert(E_ZPE_RGS, "Hartree", "eV")))
print(" E_GS = %f eV" % (Units.convert(E_GS, "Hartree", "eV")))
# ========= STEP 2: Excited state =================================================================
# Optimize the excited state geometry:
ex_go = AMSJob(name="ex_go", molecule=gs_mol_optimized, settings=comin)
ex_go.settings.input.ams.Task = "GeometryOptimization"
ex_go.settings.input.ams.GeometryOptimization.convergence = "Gradients=1.0e-5"
ex_go.settings.input.DFTB.properties.excitations.tddftb.calc = "singlet"
ex_go.settings.input.DFTB.properties.excitations.tddftb.lowest = excit
ex_go.settings.input.DFTB.properties.excitations.tddftb["print"] = "evcontribs"
ex_go.settings.input.DFTB.properties.excitations.tddftbgradients.excitation = excit
ex_go.settings.input.DFTB.properties.excitations.tddftbgradients.eigenfollow = "true"
ex_go.settings.input.ams.log.info = "TDDFTBExcitationFollowerModule"
ex_go_results = ex_go.run()
if not ex_go.check():
print("ERROR: Excited state optimization crashed")
sys.exit(1)
if ex_go_results.grep_output("Optimization Did Not Converge"):
print("ERROR: Excited state optimization did not converge")
sys.exit(1)
ex_mol_optimized = ex_go_results.get_molecule("Molecule")
# Check if the potential energy surface was switched during the optimization:
# (This happens if the optimizer goes through a conical intersection.)
PES_switches = ex_go_results.grep_file("ams.log", "TD-DFTB Eigenfollower switching PES:")
if PES_switches:
newexcit = int(PES_switches[-1].split()[-1])
print("PES switched during EXGO!!! %i -> %i" % (excit, newexcit))
else:
newexcit = excit
# Calculate frequencies and normal modes of the excited state:
ex_freq = AMSJob(name="ex_freq", molecule=ex_mol_optimized, settings=comin)
ex_freq.settings.input.ams.Task = "SinglePoint"
ex_freq.settings.input.ams.properties.NormalModes = "true"
ex_freq.settings.input.ams.NumericalDifferentiation.Parallel.nCoresPerGroup = 1
ex_freq.settings.input.DFTB.properties.excitations.tddftb.calc = "singlet"
ex_freq.settings.input.DFTB.properties.excitations.tddftb.lowest = newexcit
ex_freq.settings.input.DFTB.properties.excitations.tddftb["print"] = "evcontribs"
ex_freq.settings.input.DFTB.properties.excitations.tddftbgradients.excitation = newexcit
ex_freq_results = ex_freq.run()
if not ex_freq.check():
print("ERROR: Excited state frequency calculation crashed")
sys.exit(1)
# Calculate vertical excitations in excited state geometry:
ex_excit = AMSJob(name="ex_excit", molecule=ex_mol_optimized, settings=comin)
ex_excit.settings.input.ams.Task = "SinglePoint"
ex_excit.settings.input.DFTB.properties.excitations.tddftb.calc = "singlet"
ex_excit.settings.input.DFTB.properties.excitations.tddftb.lowest = newexcit + 9
ex_excit.settings.input.DFTB.properties.excitations.tddftb["print"] = "evcontribs"
ex_excit_results = ex_excit.run()
if not ex_excit.check():
print("ERROR: Excited state geometry excitations calculation crashed")
sys.exit(1)
# Print excited state energies:
print("Energies in the excited state equilibrium geometry:")
E_DFTB_REX = get_total_energy(ex_excit_results)
E_ZPE_REX = get_zero_point_energy(ex_freq_results)
Delta_REX = ex_excit_results.readrkf("Excitations SS A", "excenergies", file="dftb")[excit - 1]
E_EX = E_DFTB_REX + E_ZPE_REX + Delta_REX
print(" E_DFTB(R_EX) = %f eV" % (Units.convert(E_DFTB_REX, "Hartree", "eV")))
print(" E_ZPE(R_EX) = %f eV" % (Units.convert(E_ZPE_REX, "Hartree", "eV")))
print(" Delta(R_EX) = %f eV" % (Units.convert(Delta_REX, "Hartree", "eV")))
print(" E_EX = %f eV" % (Units.convert(E_EX, "Hartree", "eV")))
# Print excitation energies:
print("Excitation energies:")
print(" Delta(R_GS) = %f eV" % (Units.convert(Delta_RGS, "Hartree", "eV")))
print(" E_0-0 = %f eV" % (Units.convert(E_EX - E_GS, "Hartree", "eV")))
print(" Diff = %f eV" % (Units.convert(Delta_RGS - (E_EX - E_GS), "Hartree", "eV")))
# ========= STEP 3: Vibrational fine structure with the FCF program ===============================
# Settings for the FCF program
fcfin = Settings()
fcfin.input.spectrum.spcmin = "0.0"
fcfin.input.spectrum.spcmax = "5000.0"
fcfin.input.spectrum.spclen = "501"
fcfin.input.spectrum.lineshape = "Stick"
fcfin.input.numericalquality = "Basic"
fcfin.input.translate = True
fcfin.input.rotate = True
# Calculate vibrational fine structure
fcf = FCFJob(
name="fcf",
settings=fcfin,
inputjob1=gs_freq_results.rkfpath(file="dftb"),
inputjob2=ex_freq_results.rkfpath(file="dftb"),
)
fcf_results = fcf.run()
if not fcf.check():
print("ERROR: FCF calculation failed")
sys.exit(1)
# Extract and print the spectrum:
spectrum = extract_spectrum(fcf_results)
np.set_printoptions(formatter={"float": " {: 0.8f} ".format}, threshold=1e6)
print("Vibrational fine structure:")
print("Energy [cm^-1] Intensity")
print(spectrum)