Example: Excited state gradients: plams

Download SP_LR-TDDFTB_gradients.run

#!/bin/sh

cp $AMSHOME/examples/dftb/SP_LR-TDDFTB_gradients/SP_LR-TDDFTB_gradients.plms .
cp -r $AMSHOME/examples/dftb/SP_LR-TDDFTB_gradients/molecules .
cp -r $AMSHOME/examples/dftb/SP_LR-TDDFTB_gradients/numgrad_precalc .

export NSCM=1
$AMSBIN/plams SP_LR-TDDFTB_gradients.plms

Download SP_LR-TDDFTB_gradients.plms

import numpy as np
import os.path


# our test molecules and their excitations for which we want to calculate the gradients
tests = [
    ("acetamide", "singlet", 2, False),
    ("acetone", "singlet", 5, False),
    ("adenine", "singlet", 2, False),
    ("benzene", "singlet", 1, False),
    ("benzoquinone", "singlet", 1, False),
    ("butadiene", "singlet", 1, False),
    ("carbonmonoxide", "singlet", 8, False),
    ("cyclopentadiene", "singlet", 1, False),
    ("cyclopropene", "singlet", 1, False),
    ("cytosine", "singlet", 2, False),
    ("ethene", "singlet", 2, False),
    ("formaldehyde", "singlet", 4, False),
    ("formamide", "singlet", 2, False),
    ("furan", "singlet", 1, False),
    ("hexatriene", "singlet", 1, False),
    ("imidazole", "singlet", 2, False),
    ("naphthalene", "singlet", 1, False),
    ("nitrogen", "singlet", 8, False),
    ("norbornadiene", "singlet", 1, False),
    ("octatetraene", "singlet", 1, False),
    ("propanamide", "singlet", 2, False),
    ("pyrazine", "singlet", 3, False),
    ("pyridazine", "singlet", 4, False),
    ("pyridine", "singlet", 3, False),
    ("pyrimidine", "singlet", 6, False),
    ("pyrrole", "singlet", 3, False),
    ("tetrazine", "singlet", 6, False),
    ("thymine", "singlet", 3, False),
    ("triazine", "singlet", 6, False),
    ("uracil", "singlet", 3, False),
    ("betacarotene", "singlet", 1, False),
    ("acetamide", "triplet", 3, False),
    ("acetone", "triplet", 1, False),
    ("adenine", "triplet", 4, False),
    ("benzene", "triplet", 1, False),
    ("benzoquinone", "triplet", 4, False),
    ("butadiene", "triplet", 1, False),
    ("carbonmonoxide", "triplet", 3, False),
    ("cyclopentadiene", "triplet", 2, False),
    ("cyclopropene", "triplet", 1, False),
    ("cytosine", "triplet", 3, False),
    ("ethene", "triplet", 1, False),
    ("formaldehyde", "triplet", 7, False),
    ("formamide", "triplet", 10, False),
    ("furan", "triplet", 2, False),
    ("hexatriene", "triplet", 2, False),
    ("imidazole", "triplet", 1, False),
    ("naphthalene", "triplet", 9, False),
    ("nitrogen", "triplet", 1, False),
    ("norbornadiene", "triplet", 2, False),
    ("octatetraene", "triplet", 1, False),
    ("propanamide", "triplet", 1, False),
    ("pyrazine", "triplet", 4, False),
    ("pyridazine", "triplet", 1, False),
    ("pyridine", "triplet", 5, False),
    ("pyrimidine", "triplet", 1, False),
    ("pyrrole", "triplet", 2, False),
    ("tetrazine", "triplet", 6, False),
    ("thymine", "triplet", 4, False),
    ("triazine", "triplet", 5, False),
    ("uracil", "triplet", 2, False),
    ("betacarotene", "triplet", 1, False),
    ("acetamide", "singlet", 2, True),
    ("acetone", "singlet", 5, True),
    ("adenine", "singlet", 2, True),
    ("benzene", "singlet", 1, True),
    ("benzoquinone", "singlet", 1, True),
    ("butadiene", "singlet", 1, True),
    ("carbonmonoxide", "singlet", 8, True),
    ("cyclopentadiene", "singlet", 1, True),
    ("cyclopropene", "singlet", 1, True),
    ("cytosine", "singlet", 2, True),
    ("ethene", "singlet", 2, True),
    ("formaldehyde", "singlet", 4, True),
    ("formamide", "singlet", 2, True),
    ("furan", "singlet", 1, True),
    ("hexatriene", "singlet", 1, True),
    ("imidazole", "singlet", 2, True),
    ("naphthalene", "singlet", 1, True),
    ("nitrogen", "singlet", 8, True),
    ("norbornadiene", "singlet", 1, True),
    ("octatetraene", "singlet", 1, True),
    ("propanamide", "singlet", 2, True),
    ("pyrazine", "singlet", 3, True),
    ("pyridazine", "singlet", 4, True),
    ("pyridine", "singlet", 3, True),
    ("pyrimidine", "singlet", 6, True),
    ("pyrrole", "singlet", 3, True),
    ("tetrazine", "singlet", 6, True),
    ("thymine", "singlet", 3, True),
    ("triazine", "singlet", 6, True),
    ("uracil", "singlet", 3, True),
    ("betacarotene", "singlet", 1, True),
    ("acetamide", "triplet", 3, True),
    ("acetone", "triplet", 1, True),
    ("adenine", "triplet", 4, True),
    ("benzene", "triplet", 1, True),
    ("benzoquinone", "triplet", 4, True),
    ("butadiene", "triplet", 1, True),
    ("carbonmonoxide", "triplet", 3, True),
    ("cyclopentadiene", "triplet", 2, True),
    ("cyclopropene", "triplet", 1, True),
    ("cytosine", "triplet", 3, True),
    ("ethene", "triplet", 1, True),
    ("formaldehyde", "triplet", 7, True),
    ("formamide", "triplet", 10, True),
    ("furan", "triplet", 2, True),
    ("hexatriene", "triplet", 2, True),
    ("imidazole", "triplet", 1, True),
    ("naphthalene", "triplet", 9, True),
    ("nitrogen", "triplet", 1, True),
    ("norbornadiene", "triplet", 2, True),
    ("octatetraene", "triplet", 1, True),
    ("propanamide", "triplet", 1, True),
    ("pyrazine", "triplet", 4, True),
    ("pyridazine", "triplet", 1, True),
    ("pyridine", "triplet", 5, True),
    ("pyrimidine", "triplet", 1, True),
    ("pyrrole", "triplet", 2, True),
    ("tetrazine", "triplet", 6, True),
    ("thymine", "triplet", 4, True),
    ("triazine", "triplet", 5, True),
    ("uracil", "triplet", 2, True),
    ("betacarotene", "triplet", 1, True),
]


# numpy setup
# np.set_printoptions(precision=8, suppress=True)
np.set_printoptions(formatter={"float": " {: 0.8f} ".format})

# plams set up
config.log.stdout = 0

# common input for all tests
comin = Settings()
comin.input.ams.task = "SinglePoint"
comin.input.ams.properties.gradients = True
comin.input.DFTB.model = "SCC-DFTB"
comin.input.DFTB.resourcesdir = "DFTB.org/mio-1-1"
comin.input.DFTB.properties.excitations.tddftb["print"] = "evcontribs"

failedtests = []
for test in tests:
    molname = test[0]
    multi = test[1]
    excit = test[2]
    ldep = test[3]
    if multi == "singlet":
        kfsec = "SS"
    else:
        kfsec = "ST"
    if ldep:
        ldpf = "ldep"
    else:
        ldpf = "noldep"

    print("\nTESTING: " + molname + " " + multi + " " + str(excit) + " " + ldpf)
    teststr = molname + "_" + multi + "_" + str(excit) + "_" + ldpf

    comin_thistest = comin.copy()
    comin_thistest.input.DFTB.properties.excitations.tddftb.calc = multi
    comin_thistest.input.DFTB.properties.excitations.tddftb.lowest = excit
    if ldep:
        comin_thistest.input.DFTB.scc.orbitaldependent = "yes"
    mol = Molecule(filename="./molecules/" + molname + ".xyz")

    # numerical gradient
    if os.path.isfile("./numgrad_precalc/" + teststr + ".npy"):
        print("Precalculated numerical gradient found -> reading from file")
        numgrad = np.load("./numgrad_precalc/" + teststr + ".npy")
    else:
        print("Precalculated numerical gradient not found -> calculating")
        numgradjob = AMSNumGradJob(name=teststr + "_numgrad", molecule=mol, npoints=3, step=0.001)
        numgradjob.settings.child = comin_thistest
        numgradresults = numgradjob.run()

        def exenergy(results):
            if excit == 1:
                return results.readrkf("Excitations " + kfsec + " A", "excenergies", file="dftb")
            else:
                return results.readrkf("Excitations " + kfsec + " A", "excenergies", file="dftb")[excit - 1]

        numgrad = np.empty([len(mol), 3])
        for n in range(1, len(mol) + 1):
            numgrad[n - 1, 0] = numgradresults.get_gradient(n, "x", func=exenergy)
            numgrad[n - 1, 1] = numgradresults.get_gradient(n, "y", func=exenergy)
            numgrad[n - 1, 2] = numgradresults.get_gradient(n, "z", func=exenergy)
        numgrad = Units.conversion_ratio("bohr", "angstrom") * numgrad

        # write numerical gradient to file
        print("Saving numerical gradient to file")
        np.save("./numgrad_precalc/" + teststr + ".npy", numgrad)
    print("Numerical gradient =")
    print(numgrad)

    # analytical gradient
    job = AMSJob(name=teststr + "_anagrad", molecule=mol, settings=comin_thistest)
    job.settings.input.DFTB.properties.excitations.tddftbgradients.excitation = excit
    results = job.run()
    anagrad = np.array(results.readrkf("Excitations " + kfsec + " A", "gradient " + str(excit), file="dftb")).reshape(
        (-1, 3)
    )
    print("Analytical gradient =")
    print(anagrad)

    # print the difference between analytical and numerical gradients
    diff = numgrad - anagrad
    print("Deviation =")
    print(diff)

    # check if the difference is small enough
    passed = np.allclose(numgrad, anagrad, atol=1e-4)
    if passed:
        print("TEST FINISHED: PASSED!")
    else:
        print("TEST FINISHED: FAILED!")
        failedtests.append(test)

print("\nTESTS PASSED: " + str(len(tests) - len(failedtests)) + "/" + str(len(tests)))
for test in failedtests:
    molname = test[0]
    multi = test[1]
    excit = test[2]
    ldep = test[3]
    if ldep:
        ldpf = "ldep"
    else:
        ldpf = "noldep"
    print("FAILED: " + molname + " " + multi + " " + str(excit) + " " + ldpf)