#!/usr/bin/env amspython
# coding: utf-8
# ## Initialization
from scm.plams import Settings, Molecule, init, AMSJob, Units
from scm.plams.recipes.adffragment import ADFFragmentJob
# this line is not required in AMS2025+
init()
# ## Define the molecules
# For convenience we define here two molecules, normally you would read them from xyz files
def get_molecule(input_string):
job = AMSJob.from_input(input_string)
return job.molecule[""]
mol1 = get_molecule(
"""
System
Atoms
C -0.75086900 1.37782400 -2.43303700
C -0.05392100 2.51281000 -2.41769100
H -1.78964800 1.33942600 -2.09651100
H -0.30849400 0.43896500 -2.76734700
H -0.49177100 3.45043100 -2.06789100
H 0.98633900 2.54913500 -2.74329400
End
End
"""
)
mol2 = get_molecule(
"""
System
Atoms
C 0.14667300 -0.21503500 0.40053800
C 1.45297400 -0.07836900 0.12424400
C 2.23119700 1.15868100 0.12912100
C 1.78331500 2.39701500 0.38779700
H -0.48348000 0.63110600 0.67664100
H -0.33261900 -1.19332100 0.35411600
H 2.01546300 -0.97840100 -0.14506700
H 3.29046200 1.03872500 -0.12139700
H 2.45728900 3.25301000 0.35150400
H 0.74193400 2.60120700 0.64028800
End
End
"""
)
# ## Setup and run the job
common = Settings() # common settings for all 3 jobs
common.input.ams.Task = "SinglePoint"
common.input.adf.basis.type = "DZP"
common.input.adf.xc.gga = "PBE"
common.input.adf.symmetry = "NOSYM"
full = Settings() # additional settings for full system calculation
full.input.adf.etsnocv # empty block
full.input.adf.print = "etslowdin"
# normally you would read here the two molecules from xyz files.
# mol1 = Molecule("ethene.xyz")
# mol2 = Molecule("butadiene.xyz")
j = ADFFragmentJob(fragment1=mol1, fragment2=mol2, settings=common, full_settings=full)
r = j.run()
# ## Print the results
def print_eterm(energy_term, energy):
print(
f'{energy_term:>30s} {energy:16.4f} {Units.convert(energy, "au", "eV"):16.3f} {Units.convert(energy, "au", "kcal/mol"):16.2f} {Units.convert(energy, "au", "kJ/mol"):16.2f}'
)
def print_bonding_energy_terms(r):
print("Energy terms contributing to the bond energy (with respect to the fragments):")
bond_energy = r.get_energy()
decom = r.get_energy_decomposition()
print(f'\n{"term":>30s} {"Hartree":>16s} {"eV":>16s} {"kcal/mol":>16s} {"kJ/mol":>16s}')
for energy_term, energy in decom.items():
print_eterm(energy_term, energy)
print_eterm("total bond energy", bond_energy)
print("")
def print_eda_terms(job):
bond_energy = job.full.results.readrkf("Energy", "Bond Energy", "adf")
steric_interaction = job.full.results.readrkf("Energy", "Steric Total", "adf")
orbital_interaction = job.full.results.readrkf("Energy", "Orb.Int. Total", "adf")
print("\nFragment based energy decomposition analysis of the bond energy:")
print(f'\n{"term":>30s} {"Hartree":>16s} {"eV":>16s} {"kcal/mol":>16s} {"kJ/mol":>16s}')
print_eterm("Steric interaction", steric_interaction)
print_eterm("Orbital interaction", orbital_interaction)
print_eterm("total bond energy", bond_energy)
print("")
def print_nocv_decomposition():
print("NOCV decomposition of the orbital interaction term\n")
print("The NOCV eigenvalues are occupation numbers, they should come in pairs,")
print("with one negative value mirrored by a positive value.")
print("The orbital interaction energy contribution is calculated for each NOCV pair.")
print("")
nocv_eigenvalues = j.full.results.readrkf("NOCV", "NOCV_eigenvalues_restricted", "engine")
nocv_orbitalinteraction = j.full.results.readrkf("NOCV", "NOCV_oi_restricted", "engine")
n_pairs = int(len(nocv_eigenvalues) / 2)
threshold = 0.001
print(f'{"index":>9s} {"neg":>9s} {"pos":>9s} {"kcal/mol":>10s}')
for index in range(n_pairs):
pop1 = nocv_eigenvalues[index]
pop2 = nocv_eigenvalues[len(nocv_eigenvalues) - index - 1]
if (abs(pop1) + abs(pop2)) < threshold:
continue
orbitalinteraction = (
nocv_orbitalinteraction[index] + nocv_orbitalinteraction[len(nocv_orbitalinteraction) - index - 1]
)
print(f"{index:9d} {pop1:9.3f} {pop2:9.3f} {orbitalinteraction:10.2f}")
print_bonding_energy_terms(r)
print_eda_terms(j)
print_nocv_decomposition()