Ethylene ADF Frontier Orbital Comparison¶
Requires: AMS2026 or later
Related documentation
Ethylene was built from the SMILES string C=C and optimized once with ADF at PBE/DZP. Two single-point calculations, PBE/DZP and B3LYP/DZP, then used that same geometry. Both calculations used an all-electron DZP basis and Normal numerical quality. Orbital energies are Kohn-Sham eigenvalues in eV.
Optimized geometry¶
The optimized C=C distance is 1.3320 Å.

Frontier orbital energies¶
Method |
HOMO (eV) |
LUMO (eV) |
Gap (eV) |
|---|---|---|---|
PBE/DZP |
-7.0061 |
-1.1879 |
5.8182 |
B3LYP/DZP |
-7.7749 |
-0.2106 |
7.5642 |
The nearest three occupied and three virtual orbitals are:
Method |
Orbital |
Energy (eV) |
Occupation |
|---|---|---|---|
PBE/DZP |
HOMO-2 |
-10.4784 |
2.0 |
PBE/DZP |
HOMO-1 |
-8.7810 |
2.0 |
PBE/DZP |
HOMO |
-7.0061 |
2.0 |
PBE/DZP |
LUMO |
-1.1879 |
0.0 |
PBE/DZP |
LUMO+1 |
0.8367 |
0.0 |
PBE/DZP |
LUMO+2 |
1.9669 |
0.0 |
B3LYP/DZP |
HOMO-2 |
-11.7766 |
2.0 |
B3LYP/DZP |
HOMO-1 |
-9.9698 |
2.0 |
B3LYP/DZP |
HOMO |
-7.7749 |
2.0 |
B3LYP/DZP |
LUMO |
-0.2106 |
0.0 |
B3LYP/DZP |
LUMO+1 |
1.3945 |
0.0 |
B3LYP/DZP |
LUMO+2 |
2.5806 |
0.0 |

HOMO and LUMO isosurfaces¶
The four orbital pictures below were generated by amsreport from the corresponding ADF engine result files. Contrasting colors mark opposite orbital phases.
Method |
HOMO |
LUMO |
|---|---|---|
PBE/DZP |
|
|
B3LYP/DZP |
|
|
Conclusion¶
At this fixed PBE geometry, replacing PBE with B3LYP changes the Kohn-Sham HOMO-LUMO gap by +1.7460 eV. The HOMO and LUMO isosurfaces allow the comparison to distinguish an energy shift from a qualitative change in orbital shape. These Kohn-Sham gaps are method-dependent orbital-energy differences, not optical excitation energies.
Calculation inputs¶
PBE/DZP geometry optimization¶
Task GeometryOptimization
System
Atoms
C 0.6644850805 0.0279879686 -0.0236852009
C -0.6644849893 -0.0279879318 0.0236851499
H 1.2534332310 -0.8786144292 0.0702991539
H 1.1670384263 0.9805640030 -0.1565753856
H -1.2534332920 0.8786143859 -0.0702991171
H -1.1670384566 -0.9805639965 0.1565753997
End
BondOrders
1 2 2.0
1 3 1.0
1 4 1.0
2 5 1.0
2 6 1.0
End
End
Engine adf
Basis
Core None
Type DZP
End
NumericalQuality Normal
SCF
Iterations 100
End
XC
GGA PBE
End
EndEngine
PBE/DZP single point¶
Task SinglePoint
System
Atoms
C 0.6649813115 0.0278988522 -0.0242986367
C -0.6649810155 -0.0278982997 0.0243008447
H 1.2789279657 -0.8699226278 0.0686049752
H 1.1932069166 0.9740820859 -0.1564006741
H -1.2789292580 0.8699198605 -0.0686220517
H -1.1932059203 -0.9740798711 0.1564155425
End
BondOrders
1 2 2.0
1 3 1.0
1 4 1.0
2 5 1.0
2 6 1.0
End
End
Engine adf
Basis
Core None
Type DZP
End
NumericalQuality Normal
SCF
Iterations 100
End
XC
GGA PBE
End
EndEngine
B3LYP/DZP single point¶
Task SinglePoint
System
Atoms
C 0.6649813115 0.0278988522 -0.0242986367
C -0.6649810155 -0.0278982997 0.0243008447
H 1.2789279657 -0.8699226278 0.0686049752
H 1.1932069166 0.9740820859 -0.1564006741
H -1.2789292580 0.8699198605 -0.0686220517
H -1.1932059203 -0.9740798711 0.1564155425
End
BondOrders
1 2 2.0
1 3 1.0
1 4 1.0
2 5 1.0
2 6 1.0
End
End
Engine adf
Basis
Core None
Type DZP
End
NumericalQuality Normal
SCF
Iterations 100
End
XC
Hybrid B3LYP
End
EndEngine
Prompts and Python scripts¶
Prompt (instruction for AI agent)
Use $ams2026
Compare the HOMO-LUMO gap and frontier orbitals of ethylene with two ADF
settings.
Build ethylene from SMILES C=C. Optimize the geometry once with a modest ADF
GGA setup. Then run two ADF single-point calculations on the optimized
geometry: one with the same GGA setup and one with a hybrid functional.
For both single-point calculations, extract HOMO energy, LUMO energy, HOMO-LUMO
gap, and the energies of the nearest few occupied and virtual orbitals. Keep
units clear and report orbital energies in eV.
In the report, include a table comparing the two methods, and plot the frontier
orbital energy levels as a small energy-level diagram.
Include a picture of the optimized ethylene geometry. Include HOMO and LUMO
orbital isosurface pictures generated with amsreport.
01-run.py
#!/usr/bin/env amspython
from __future__ import annotations
from scm.base import ChemicalSystem, InputParser
from scm.plams import AMSJob, Settings, finish, init
def adf_settings(task: str, functional_kind: str, functional: str) -> Settings:
settings = Settings()
settings.input.ams.Task = task
settings.input.adf.Basis.Type = "DZP"
settings.input.adf.Basis.Core = "None"
settings.input.adf.NumericalQuality = "Normal"
settings.input.adf.SCF.Iterations = 100
if functional_kind == "GGA":
settings.input.adf.XC.GGA = functional
elif functional_kind == "Hybrid":
settings.input.adf.XC.Hybrid = functional
else:
raise ValueError(f"Unsupported functional kind: {functional_kind}")
return settings
def validate_job(job: AMSJob) -> None:
InputParser().to_dict("ams", job.get_input())
def main() -> None:
init(folder="01-run_workdir")
initial_system = ChemicalSystem.from_smiles("C=C")
optimization = AMSJob(
molecule=initial_system,
settings=adf_settings("GeometryOptimization", "GGA", "PBE"),
name="ethylene_opt_pbe_dzp",
)
validate_job(optimization)
optimization.run()
if not optimization.ok():
raise RuntimeError("PBE/DZP geometry optimization failed")
optimized_system = optimization.results.get_main_system()
single_points = (
("ethylene_sp_pbe_dzp", "GGA", "PBE"),
("ethylene_sp_b3lyp_dzp", "Hybrid", "B3LYP"),
)
for name, functional_kind, functional in single_points:
job = AMSJob(
molecule=optimized_system,
settings=adf_settings("SinglePoint", functional_kind, functional),
name=name,
)
validate_job(job)
job.run()
if not job.ok():
raise RuntimeError(f"Single-point calculation failed: {name}")
finish()
if __name__ == "__main__":
main()
report.py
#!/usr/bin/env amspython
from __future__ import annotations
import os
import shutil
import subprocess
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from scm.plams import AMSJob, view
ROOT = Path(__file__).resolve().parent
FIGURES = ROOT / "figures"
TABLES = ROOT / "tables"
def latest_workdir() -> Path:
candidates = [path for path in ROOT.glob("01-run_workdir*") if path.is_dir()]
if not candidates:
raise FileNotFoundError("No 01-run_workdir directory was found")
return max(candidates, key=lambda path: path.stat().st_mtime)
def frontier_rows(job: AMSJob, method: str, count: int = 3) -> list[dict[str, object]]:
energies = np.asarray(job.results.get_orbital_energies(unit="eV"))[0]
occupations = np.asarray(job.results.get_orbital_occupations())[0]
occupied = np.flatnonzero(occupations > 1.0e-6)
virtual = np.flatnonzero(occupations <= 1.0e-6)
if len(occupied) < count or len(virtual) < count:
raise RuntimeError(f"Too few orbitals were returned for {method}")
homo_index = int(occupied[-1])
lumo_index = int(virtual[0])
selected = list(occupied[-count:]) + list(virtual[:count])
rows: list[dict[str, object]] = []
for index in selected:
if index <= homo_index:
offset = homo_index - int(index)
label = "HOMO" if offset == 0 else f"HOMO-{offset}"
else:
offset = int(index) - lumo_index
label = "LUMO" if offset == 0 else f"LUMO+{offset}"
rows.append(
{
"Method": method,
"Orbital": label,
"Energy (eV)": float(energies[index]),
"Occupation": float(occupations[index]),
}
)
return rows
def make_energy_level_plot(orbital_table: pd.DataFrame) -> None:
fig, ax = plt.subplots(figsize=(5.2, 5.0))
methods = list(orbital_table["Method"].drop_duplicates())
for x, method in enumerate(methods):
subset = orbital_table[orbital_table["Method"] == method]
for _, row in subset.iterrows():
label = str(row["Orbital"])
energy = float(row["Energy (eV)"])
frontier = label in {"HOMO", "LUMO"}
color = "#2166ac" if float(row["Occupation"]) > 0 else "#b2182b"
linewidth = 3.0 if frontier else 1.5
ax.hlines(energy, x - 0.23, x + 0.23, color=color, linewidth=linewidth)
ax.text(x + 0.27, energy, label, va="center", fontsize=8)
ax.set_xlim(-0.55, len(methods) - 0.25)
ax.set_xticks(range(len(methods)), methods)
ax.set_ylabel("Orbital energy (eV)")
ax.set_title("Frontier orbital energy levels")
ax.grid(axis="y", color="#dddddd", linewidth=0.6)
fig.tight_layout()
fig.savefig(FIGURES / "frontier_energy_levels.png", dpi=200)
plt.close(fig)
def make_amsreport_orbital(engine_rkf: Path, method_slug: str, orbital: str) -> Path:
output_dir = FIGURES / f"amsreport_{method_slug}_{orbital.lower()}"
if output_dir.exists():
shutil.rmtree(output_dir)
output_dir.mkdir(parents=True)
command = [
os.environ["AMSBIN"] + "/amsreport",
str(engine_rkf),
orbital,
"-o",
"report.html",
"-v",
"-scmgeometry 500x400",
"-v",
"-grid Fine",
"-v",
"-antialias",
"-v",
"-bgcolor #ffffff",
"-v",
"-viewplane {1 2 5}",
]
subprocess.run(command, cwd=output_dir, check=True, capture_output=True, text=True)
images = sorted(output_dir.rglob("*.jpg")) + sorted(output_dir.rglob("*.png"))
if not images:
raise RuntimeError(f"amsreport did not create an image for {method_slug} {orbital}")
return images[0].relative_to(ROOT)
def main() -> None:
FIGURES.mkdir(exist_ok=True)
TABLES.mkdir(exist_ok=True)
workdir = latest_workdir()
# Geometry optimization: establishes the one structure used by both single points.
optimization = AMSJob.load_external(str(workdir / "ethylene_opt_pbe_dzp"))
# PBE single point: supplies the GGA orbital energies and isosurfaces.
pbe = AMSJob.load_external(str(workdir / "ethylene_sp_pbe_dzp"))
# B3LYP single point: supplies the hybrid orbital energies and isosurfaces.
b3lyp = AMSJob.load_external(str(workdir / "ethylene_sp_b3lyp_dzp"))
jobs = {"PBE/DZP": pbe, "B3LYP/DZP": b3lyp}
summary_rows: list[dict[str, object]] = []
orbital_rows: list[dict[str, object]] = []
for method, job in jobs.items():
homo = float(job.results.get_homo_energies(unit="eV")[0])
lumo = float(job.results.get_lumo_energies(unit="eV")[0])
gap = float(job.results.get_smallest_homo_lumo_gap(unit="eV"))
summary_rows.append(
{"Method": method, "HOMO (eV)": homo, "LUMO (eV)": lumo, "Gap (eV)": gap}
)
orbital_rows.extend(frontier_rows(job, method))
summary = pd.DataFrame(summary_rows)
orbitals = pd.DataFrame(orbital_rows)
summary.to_csv(TABLES / "frontier_summary.csv", index=False)
orbitals.to_csv(TABLES / "frontier_orbitals.csv", index=False)
make_energy_level_plot(orbitals)
optimized_system = optimization.results.get_main_system()
view(
optimized_system,
guess_bonds=len(optimized_system.bonds) == 0,
direction="along_pca3",
width=600,
height=450,
picture_path=str(FIGURES / "optimized_ethylene.png"),
)
orbital_images: dict[tuple[str, str], Path] = {}
for method_slug, job in (("pbe", pbe), ("b3lyp", b3lyp)):
engine_rkf = Path(job.results.rkfpath(file="engine")).resolve()
for orbital in ("HOMO", "LUMO"):
orbital_images[(method_slug, orbital)] = make_amsreport_orbital(
engine_rkf, method_slug, orbital
)
carbon_indices = [i for i, atom in enumerate(optimized_system.atoms) if atom.symbol == "C"]
cc_distance = optimized_system.get_distance(carbon_indices[0], carbon_indices[1])
gap_change = float(summary.loc[summary["Method"] == "B3LYP/DZP", "Gap (eV)"].iloc[0]) - float(
summary.loc[summary["Method"] == "PBE/DZP", "Gap (eV)"].iloc[0]
)
lines = [
"# Ethylene frontier orbitals with PBE and B3LYP",
"",
"Ethylene was built from the SMILES string `C=C` and optimized once with ADF at PBE/DZP. "
"Two single-point calculations, PBE/DZP and B3LYP/DZP, then used that same geometry. "
"Both calculations used an all-electron DZP basis and Normal numerical quality. Orbital energies are Kohn-Sham eigenvalues in eV.",
"",
"## Optimized geometry",
"",
f"The optimized C=C distance is {cc_distance:.4f} Å.",
"",
"",
"",
"## Frontier orbital energies",
"",
summary.to_markdown(index=False, floatfmt=".4f"),
"",
"The nearest three occupied and three virtual orbitals are:",
"",
orbitals.to_markdown(index=False, floatfmt=("", "", ".4f", ".1f")),
"",
"",
"",
"## HOMO and LUMO isosurfaces",
"",
"The four orbital pictures below were generated by `amsreport` from the corresponding ADF engine result files. Contrasting colors mark opposite orbital phases.",
"",
"| Method | HOMO | LUMO |",
"|---|---|---|",
f"| PBE/DZP | ].as_posix()}) | ].as_posix()}) |",
f"| B3LYP/DZP | ].as_posix()}) | ].as_posix()}) |",
"",
"## Conclusion",
"",
f"At this fixed PBE geometry, replacing PBE with B3LYP changes the Kohn-Sham HOMO-LUMO gap by {gap_change:+.4f} eV. "
"The HOMO and LUMO isosurfaces allow the comparison to distinguish an energy shift from a qualitative change in orbital shape. "
"These Kohn-Sham gaps are method-dependent orbital-energy differences, not optical excitation energies.",
"",
"## Calculation inputs",
"",
]
for title, job in (
("PBE/DZP geometry optimization", optimization),
("PBE/DZP single point", pbe),
("B3LYP/DZP single point", b3lyp),
):
lines.extend([f"### {title}", "", "```ams", job.get_input().rstrip(), "```", ""])
(ROOT / "report.md").write_text("\n".join(lines), encoding="utf-8")
if __name__ == "__main__":
main()
Original Markdown report
# Ethylene frontier orbitals with PBE and B3LYP
Ethylene was built from the SMILES string `C=C` and optimized once with ADF at PBE/DZP. Two single-point calculations, PBE/DZP and B3LYP/DZP, then used that same geometry. Both calculations used an all-electron DZP basis and Normal numerical quality. Orbital energies are Kohn-Sham eigenvalues in eV.
## Optimized geometry
The optimized C=C distance is 1.3320 Å.

## Frontier orbital energies
| Method | HOMO (eV) | LUMO (eV) | Gap (eV) |
|:----------|------------:|------------:|-----------:|
| PBE/DZP | -7.0061 | -1.1879 | 5.8182 |
| B3LYP/DZP | -7.7749 | -0.2106 | 7.5642 |
The nearest three occupied and three virtual orbitals are:
| Method | Orbital | Energy (eV) | Occupation |
|:----------|:----------|--------------:|-------------:|
| PBE/DZP | HOMO-2 | -10.4784 | 2.0 |
| PBE/DZP | HOMO-1 | -8.7810 | 2.0 |
| PBE/DZP | HOMO | -7.0061 | 2.0 |
| PBE/DZP | LUMO | -1.1879 | 0.0 |
| PBE/DZP | LUMO+1 | 0.8367 | 0.0 |
| PBE/DZP | LUMO+2 | 1.9669 | 0.0 |
| B3LYP/DZP | HOMO-2 | -11.7766 | 2.0 |
| B3LYP/DZP | HOMO-1 | -9.9698 | 2.0 |
| B3LYP/DZP | HOMO | -7.7749 | 2.0 |
| B3LYP/DZP | LUMO | -0.2106 | 0.0 |
| B3LYP/DZP | LUMO+1 | 1.3945 | 0.0 |
| B3LYP/DZP | LUMO+2 | 2.5806 | 0.0 |

## HOMO and LUMO isosurfaces
The four orbital pictures below were generated by `amsreport` from the corresponding ADF engine result files. Contrasting colors mark opposite orbital phases.
| Method | HOMO | LUMO |
|---|---|---|
| PBE/DZP |  |  |
| B3LYP/DZP |  |  |
## Conclusion
At this fixed PBE geometry, replacing PBE with B3LYP changes the Kohn-Sham HOMO-LUMO gap by +1.7460 eV. The HOMO and LUMO isosurfaces allow the comparison to distinguish an energy shift from a qualitative change in orbital shape. These Kohn-Sham gaps are method-dependent orbital-energy differences, not optical excitation energies.
## Calculation inputs
### PBE/DZP geometry optimization
```ams
Task GeometryOptimization
System
Atoms
C 0.6644850805 0.0279879686 -0.0236852009
C -0.6644849893 -0.0279879318 0.0236851499
H 1.2534332310 -0.8786144292 0.0702991539
H 1.1670384263 0.9805640030 -0.1565753856
H -1.2534332920 0.8786143859 -0.0702991171
H -1.1670384566 -0.9805639965 0.1565753997
End
BondOrders
1 2 2.0
1 3 1.0
1 4 1.0
2 5 1.0
2 6 1.0
End
End
Engine adf
Basis
Core None
Type DZP
End
NumericalQuality Normal
SCF
Iterations 100
End
XC
GGA PBE
End
EndEngine
```
### PBE/DZP single point
```ams
Task SinglePoint
System
Atoms
C 0.6649813115 0.0278988522 -0.0242986367
C -0.6649810155 -0.0278982997 0.0243008447
H 1.2789279657 -0.8699226278 0.0686049752
H 1.1932069166 0.9740820859 -0.1564006741
H -1.2789292580 0.8699198605 -0.0686220517
H -1.1932059203 -0.9740798711 0.1564155425
End
BondOrders
1 2 2.0
1 3 1.0
1 4 1.0
2 5 1.0
2 6 1.0
End
End
Engine adf
Basis
Core None
Type DZP
End
NumericalQuality Normal
SCF
Iterations 100
End
XC
GGA PBE
End
EndEngine
```
### B3LYP/DZP single point
```ams
Task SinglePoint
System
Atoms
C 0.6649813115 0.0278988522 -0.0242986367
C -0.6649810155 -0.0278982997 0.0243008447
H 1.2789279657 -0.8699226278 0.0686049752
H 1.1932069166 0.9740820859 -0.1564006741
H -1.2789292580 0.8699198605 -0.0686220517
H -1.1932059203 -0.9740798711 0.1564155425
End
BondOrders
1 2 2.0
1 3 1.0
1 4 1.0
2 5 1.0
2 6 1.0
End
End
Engine adf
Basis
Core None
Type DZP
End
NumericalQuality Normal
SCF
Iterations 100
End
XC
Hybrid B3LYP
End
EndEngine
```
Note on AI-generated content¶
This page was generated by a Python script. That Python script was AI-generated.
All numbers, figures, and tables are extracted or postprocessed from actual AMS calculations, and can be transparently regenerated from the provided Python scripts.
Any scientific reasoning or citations was written by AI. This page is the actual one-shot output from using the ams2026 skill with an AI coding agent.



