Ethylene ADF Frontier Orbital Comparison¶
PBE and B3LYP frontier-orbital energy levels.¶
Requires: AMS2026 or later
Related documentation
Ethylene was built from SMILES C=C. The geometry was optimized once with a modest ADF GGA setup, then two ADF single-point calculations were run on the optimized geometry: PBE/DZP and B3LYP/DZP. Orbital energies are reported in eV.
Job provenance¶
Role |
Method |
Job directory |
Justification |
|---|---|---|---|
Geometry optimization |
ADF/PBE/DZP |
|
Optimized the ethylene geometry once from SMILES C=C. |
GGA single point |
ADF/PBE/DZP |
|
Computed frontier orbital energies on the optimized geometry with the GGA setup. |
Hybrid single point |
ADF/B3LYP/DZP |
|
Computed frontier orbital energies on the same optimized geometry with a hybrid functional. |
Optimized geometry¶
The optimized C=C distance is 1.332 angstrom. The mean C-H distance is 1.092 angstrom.
HOMO-LUMO comparison¶
Method |
HOMO (eV) |
LUMO (eV) |
Gap (eV) |
HOMO index |
LUMO index |
|---|---|---|---|---|---|
ADF/PBE/DZP |
-7.036 |
-1.235 |
5.801 |
6 |
7 |
ADF/B3LYP/DZP |
-7.853 |
-0.292 |
7.561 |
6 |
7 |
Frontier orbital energy windows¶
ADF/PBE/DZP¶
Orbital |
Index |
Occupation |
Energy (eV) |
|---|---|---|---|
HOMO-3 |
3 |
2.000 |
-11.754 |
HOMO-2 |
4 |
2.000 |
-10.519 |
HOMO-1 |
5 |
2.000 |
-8.797 |
HOMO |
6 |
2.000 |
-7.036 |
LUMO |
7 |
0.000 |
-1.235 |
LUMO+1 |
8 |
0.000 |
0.886 |
LUMO+2 |
9 |
0.000 |
2.018 |
LUMO+3 |
10 |
0.000 |
2.059 |
ADF/B3LYP/DZP¶
Orbital |
Index |
Occupation |
Energy (eV) |
|---|---|---|---|
HOMO-3 |
3 |
2.000 |
-13.120 |
HOMO-2 |
4 |
2.000 |
-11.871 |
HOMO-1 |
5 |
2.000 |
-10.026 |
HOMO |
6 |
2.000 |
-7.853 |
LUMO |
7 |
0.000 |
-0.292 |
LUMO+1 |
8 |
0.000 |
1.473 |
LUMO+2 |
9 |
0.000 |
2.696 |
LUMO+3 |
10 |
0.000 |
2.778 |
Energy-level diagram¶
AMSreport orbital isosurfaces¶
These images were generated by amsreport from each single-point adf.rkf file.
Method |
HOMO |
LUMO |
|---|---|---|
ADF/PBE/DZP |
|
|
ADF/B3LYP/DZP |
|
|
Calculation inputs¶
Geometry optimization: ADF/PBE/DZP¶
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
Type DZP
End
NumericalQuality Basic
XC
GGA PBE
End
EndEngine
GGA single point: ADF/PBE/DZP¶
Properties
OrbitalsInfo yes
End
Task SinglePoint
System
Atoms
C 0.6651665049 0.0281045107 -0.0235971144
C -0.6651713207 -0.0281053452 0.0236173947
H 1.2802120569 -0.8698054143 0.0685226284
H 1.1943503882 0.9738532541 -0.1567756217
H -1.2801922123 0.8698550678 -0.0682160798
H -1.1943654169 -0.9739020730 0.1564487929
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
Type DZP
End
NumericalQuality Basic
XC
GGA PBE
End
EndEngine
Hybrid single point: ADF/B3LYP/DZP¶
Properties
OrbitalsInfo yes
End
Task SinglePoint
System
Atoms
C 0.6651665049 0.0281045107 -0.0235971144
C -0.6651713207 -0.0281053452 0.0236173947
H 1.2802120569 -0.8698054143 0.0685226284
H 1.1943503882 0.9738532541 -0.1567756217
H -1.2801922123 0.8698550678 -0.0682160798
H -1.1943654169 -0.9739020730 0.1564487929
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
Type DZP
End
NumericalQuality Basic
XC
Hybrid B3LYP
End
EndEngine
Conclusion¶
With this modest DZP setup, the B3LYP single point increases the HOMO-LUMO gap from 5.801 eV for PBE to 7.561 eV. The increase is mainly from a lower HOMO and a higher LUMO relative to the PBE values.
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 pathlib import Path
from scm.base import ChemicalSystem
from scm.plams import AMSJob, Settings, init, finish, view
try:
from scm.input_classes import AMS
except ImportError:
from scm.input_classes.drivers import AMS
WORKDIR = "01-run_workdir"
def adf_settings(task: str, xc_type: str, xc_name: str) -> Settings:
settings = Settings()
settings.input.AMS.Task = task
if task == "SinglePoint":
settings.input.AMS.Properties.OrbitalsInfo = "Yes"
settings.input.ADF.Basis.Type = "DZP"
settings.input.ADF.NumericalQuality = "Basic"
setattr(settings.input.ADF.XC, xc_type, xc_name)
AMS.from_settings(settings)
return settings
def run_job(name: str, system: ChemicalSystem, settings: Settings) -> AMSJob:
job = AMSJob(name=name, molecule=system, settings=settings)
print(f"\n--- {name} input ---")
print(job.get_input())
print(f"--- end {name} input ---\n")
result = job.run()
if not result.ok():
raise RuntimeError(f"AMS job failed: {name}")
return job
def main() -> None:
init(folder=WORKDIR)
try:
outdir = Path("figures")
outdir.mkdir(exist_ok=True)
ethylene = ChemicalSystem.from_smiles("C=C")
opt_settings = adf_settings("GeometryOptimization", "GGA", "PBE")
opt_job = run_job("ethylene_opt_pbe_dzp", ethylene, opt_settings)
optimized = opt_job.results.get_main_system()
view(
optimized,
guess_bonds=True,
direction="along_pca3",
width=500,
height=360,
picture_path=str(outdir / "optimized_ethylene.png"),
)
gga_sp = run_job(
"ethylene_sp_pbe_dzp",
optimized,
adf_settings("SinglePoint", "GGA", "PBE"),
)
hybrid_sp = run_job(
"ethylene_sp_b3lyp_dzp",
optimized,
adf_settings("SinglePoint", "Hybrid", "B3LYP"),
)
print("Finished jobs:")
for job in (opt_job, gga_sp, hybrid_sp):
print(f"{job.name}: {job.path}")
finally:
finish()
if __name__ == "__main__":
main()
report.py
#!/usr/bin/env amspython
from __future__ import annotations
from dataclasses import dataclass
import os
from pathlib import Path
import shutil
import subprocess
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from scm.plams import AMSJob
@dataclass(frozen=True)
class JobRef:
label: str
method: str
path: Path
justification: str
def latest_workdir(prefix: str) -> Path:
candidates = [p for p in Path(".").glob(f"{prefix}*") if p.is_dir()]
if not candidates:
raise FileNotFoundError(f"No PLAMS workdir matching {prefix}*")
return max(candidates, key=lambda p: p.stat().st_mtime)
def frontier_window(job: AMSJob, n_each_side: int = 3) -> tuple[pd.DataFrame, dict[str, float]]:
energies = np.asarray(job.results.get_orbital_energies(unit="eV"))[0]
occupations = np.asarray(job.results.get_orbital_occupations())[0]
occupied = np.where(occupations > 1.0e-6)[0]
virtual = np.where(occupations <= 1.0e-6)[0]
if len(occupied) == 0 or len(virtual) == 0:
raise RuntimeError(f"Could not identify occupied and virtual orbitals for {job.name}")
homo_idx = int(occupied[-1])
lumo_idx = int(virtual[virtual > homo_idx][0])
start = max(0, homo_idx - n_each_side)
stop = min(len(energies), lumo_idx + n_each_side + 1)
rows: list[dict[str, object]] = []
for idx in range(start, stop):
label = f"HOMO{idx - homo_idx:+d}" if idx <= homo_idx else f"LUMO{idx - lumo_idx:+d}"
label = label.replace("+0", "").replace("-0", "")
rows.append(
{
"Orbital": label,
"Index": idx + 1,
"Occupation": float(occupations[idx]),
"Energy (eV)": float(energies[idx]),
}
)
summary = {
"HOMO (eV)": float(job.results.get_homo_energies(unit="eV")[0]),
"LUMO (eV)": float(job.results.get_lumo_energies(unit="eV")[0]),
"Gap (eV)": float(job.results.get_smallest_homo_lumo_gap(unit="eV")),
"HOMO index": homo_idx + 1,
"LUMO index": lumo_idx + 1,
}
return pd.DataFrame(rows), summary
def plot_levels(windows: dict[str, pd.DataFrame], output: Path) -> None:
fig, ax = plt.subplots(figsize=(5.8, 3.6))
x_positions = {"PBE/DZP": 0.0, "B3LYP/DZP": 1.0}
colors = {"occupied": "#1f77b4", "virtual": "#d62728"}
for method, df in windows.items():
x = x_positions[method]
for _, row in df.iterrows():
occ = float(row["Occupation"])
energy = float(row["Energy (eV)"])
color = colors["occupied" if occ > 1.0e-6 else "virtual"]
ax.hlines(energy, x - 0.22, x + 0.22, color=color, linewidth=2)
if row["Orbital"] in {"HOMO", "LUMO"}:
ax.text(x + 0.26, energy, str(row["Orbital"]), va="center", fontsize=8)
ax.set_xticks(list(x_positions.values()), list(x_positions.keys()))
ax.set_ylabel("Orbital energy (eV)")
ax.set_xlim(-0.55, 1.65)
ax.grid(axis="y", color="#dddddd", linewidth=0.8)
ax.spines[["top", "right"]].set_visible(False)
ax.plot([], [], color=colors["occupied"], label="Occupied")
ax.plot([], [], color=colors["virtual"], label="Virtual")
ax.legend(frameon=False, fontsize=8, loc="lower right")
fig.tight_layout()
fig.savefig(output, dpi=180)
plt.close(fig)
def generate_amsreport_image(result_file: Path, orbital: str, html_file: Path, image_file: Path) -> None:
amsbin = Path(os.environ["AMSBIN"])
command = [
"xvfb-run",
"-a",
str(amsbin / "amsreport"),
str(result_file),
orbital,
"-o",
str(html_file),
"-v",
"-grid Fine",
"-v",
"-antialias",
"-v",
"-bgcolor #ffffff",
"-v",
"-scmgeometry 500x500",
]
subprocess.run(command, check=True)
generated = html_file.with_suffix(".jpgs") / "0.jpg"
if not generated.exists() or generated.stat().st_size == 0:
raise RuntimeError(f"AMSreport did not create a usable image for {orbital} from {result_file}")
shutil.copyfile(generated, image_file)
def fmt_df(df: pd.DataFrame, digits: int = 3) -> str:
return df.to_markdown(index=False, floatfmt=f".{digits}f")
def main() -> None:
workdir = latest_workdir("01-run_workdir")
refs = [
JobRef(
"Geometry optimization",
"ADF/PBE/DZP",
workdir / "ethylene_opt_pbe_dzp",
"Optimized the ethylene geometry once from SMILES C=C.",
),
JobRef(
"GGA single point",
"ADF/PBE/DZP",
workdir / "ethylene_sp_pbe_dzp",
"Computed frontier orbital energies on the optimized geometry with the GGA setup.",
),
JobRef(
"Hybrid single point",
"ADF/B3LYP/DZP",
workdir / "ethylene_sp_b3lyp_dzp",
"Computed frontier orbital energies on the same optimized geometry with a hybrid functional.",
),
]
jobs = {ref.label: AMSJob.load_external(str(ref.path)) for ref in refs}
windows: dict[str, pd.DataFrame] = {}
summary_rows: list[dict[str, object]] = []
for ref in refs[1:]:
df, summary = frontier_window(jobs[ref.label])
method_key = "PBE/DZP" if "PBE" in ref.method else "B3LYP/DZP"
windows[method_key] = df
summary_rows.append({"Method": ref.method, **summary})
figures = Path("figures")
figures.mkdir(exist_ok=True)
plot_levels(windows, figures / "frontier_energy_levels.png")
amsreport_dir = Path("amsreport_images")
amsreport_dir.mkdir(exist_ok=True)
generate_amsreport_image(
refs[1].path / "adf.rkf",
"HOMO",
amsreport_dir / "pbe_homo.html",
figures / "pbe_homo_amsreport.jpg",
)
generate_amsreport_image(
refs[1].path / "adf.rkf",
"LUMO",
amsreport_dir / "pbe_lumo.html",
figures / "pbe_lumo_amsreport.jpg",
)
generate_amsreport_image(
refs[2].path / "adf.rkf",
"HOMO",
amsreport_dir / "b3lyp_homo.html",
figures / "b3lyp_homo_amsreport.jpg",
)
generate_amsreport_image(
refs[2].path / "adf.rkf",
"LUMO",
amsreport_dir / "b3lyp_lumo.html",
figures / "b3lyp_lumo_amsreport.jpg",
)
opt_system = jobs["Geometry optimization"].results.get_main_system()
cc_distance = opt_system.get_distance(0, 1, unit="angstrom")
ch_distances = [opt_system.get_distance(0, i, unit="angstrom") for i in (2, 3)]
ch_distances += [opt_system.get_distance(1, i, unit="angstrom") for i in (4, 5)]
summary_df = pd.DataFrame(summary_rows)
report = [
"# Ethylene ADF Frontier Orbital Comparison",
"",
"Ethylene was built from SMILES `C=C`. The geometry was optimized once with a modest ADF GGA setup, then two ADF single-point calculations were run on the optimized geometry: PBE/DZP and B3LYP/DZP. Orbital energies are reported in eV.",
"",
"## Job provenance",
"",
"| Role | Method | Job directory | Justification |",
"|---|---|---|---|",
]
for ref in refs:
report.append(f"| {ref.label} | {ref.method} | `{ref.path}` | {ref.justification} |")
report += [
"",
"## Optimized geometry",
"",
f"The optimized C=C distance is {cc_distance:.3f} angstrom. The mean C-H distance is {np.mean(ch_distances):.3f} angstrom.",
"",
"",
"",
"## HOMO-LUMO comparison",
"",
fmt_df(summary_df[["Method", "HOMO (eV)", "LUMO (eV)", "Gap (eV)", "HOMO index", "LUMO index"]]),
"",
"## Frontier orbital energy windows",
"",
"### ADF/PBE/DZP",
"",
fmt_df(windows["PBE/DZP"]),
"",
"### ADF/B3LYP/DZP",
"",
fmt_df(windows["B3LYP/DZP"]),
"",
"## Energy-level diagram",
"",
"",
"",
"## AMSreport orbital isosurfaces",
"",
"These images were generated by `amsreport` from each single-point `adf.rkf` file.",
"",
"| Method | HOMO | LUMO |",
"|---|---|---|",
"| ADF/PBE/DZP |  |  |",
"| ADF/B3LYP/DZP |  |  |",
"",
"## Calculation inputs",
"",
]
for ref in refs:
report += [
f"### {ref.label}: {ref.method}",
"",
"```ams",
jobs[ref.label].get_input(),
"```",
"",
]
report += [
"## Conclusion",
"",
f"With this modest DZP setup, the B3LYP single point increases the HOMO-LUMO gap from {summary_rows[0]['Gap (eV)']:.3f} eV for PBE to {summary_rows[1]['Gap (eV)']:.3f} eV. The increase is mainly from a lower HOMO and a higher LUMO relative to the PBE values.",
"",
]
Path("report.md").write_text("\n".join(report), encoding="utf-8")
print(Path("report.md").resolve())
if __name__ == "__main__":
main()
Original Markdown report
# Ethylene ADF Frontier Orbital Comparison
Ethylene was built from SMILES `C=C`. The geometry was optimized once with a modest ADF GGA setup, then two ADF single-point calculations were run on the optimized geometry: PBE/DZP and B3LYP/DZP. Orbital energies are reported in eV.
## Job provenance
| Role | Method | Job directory | Justification |
|---|---|---|---|
| Geometry optimization | ADF/PBE/DZP | `01-run_workdir/ethylene_opt_pbe_dzp` | Optimized the ethylene geometry once from SMILES C=C. |
| GGA single point | ADF/PBE/DZP | `01-run_workdir/ethylene_sp_pbe_dzp` | Computed frontier orbital energies on the optimized geometry with the GGA setup. |
| Hybrid single point | ADF/B3LYP/DZP | `01-run_workdir/ethylene_sp_b3lyp_dzp` | Computed frontier orbital energies on the same optimized geometry with a hybrid functional. |
## Optimized geometry
The optimized C=C distance is 1.332 angstrom. The mean C-H distance is 1.092 angstrom.

## HOMO-LUMO comparison
| Method | HOMO (eV) | LUMO (eV) | Gap (eV) | HOMO index | LUMO index |
|:--------------|------------:|------------:|-----------:|-------------:|-------------:|
| ADF/PBE/DZP | -7.036 | -1.235 | 5.801 | 6 | 7 |
| ADF/B3LYP/DZP | -7.853 | -0.292 | 7.561 | 6 | 7 |
## Frontier orbital energy windows
### ADF/PBE/DZP
| Orbital | Index | Occupation | Energy (eV) |
|:----------|--------:|-------------:|--------------:|
| HOMO-3 | 3 | 2.000 | -11.754 |
| HOMO-2 | 4 | 2.000 | -10.519 |
| HOMO-1 | 5 | 2.000 | -8.797 |
| HOMO | 6 | 2.000 | -7.036 |
| LUMO | 7 | 0.000 | -1.235 |
| LUMO+1 | 8 | 0.000 | 0.886 |
| LUMO+2 | 9 | 0.000 | 2.018 |
| LUMO+3 | 10 | 0.000 | 2.059 |
### ADF/B3LYP/DZP
| Orbital | Index | Occupation | Energy (eV) |
|:----------|--------:|-------------:|--------------:|
| HOMO-3 | 3 | 2.000 | -13.120 |
| HOMO-2 | 4 | 2.000 | -11.871 |
| HOMO-1 | 5 | 2.000 | -10.026 |
| HOMO | 6 | 2.000 | -7.853 |
| LUMO | 7 | 0.000 | -0.292 |
| LUMO+1 | 8 | 0.000 | 1.473 |
| LUMO+2 | 9 | 0.000 | 2.696 |
| LUMO+3 | 10 | 0.000 | 2.778 |
## Energy-level diagram

## AMSreport orbital isosurfaces
These images were generated by `amsreport` from each single-point `adf.rkf` file.
| Method | HOMO | LUMO |
|---|---|---|
| ADF/PBE/DZP |  |  |
| ADF/B3LYP/DZP |  |  |
## Calculation inputs
### Geometry optimization: ADF/PBE/DZP
```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
Type DZP
End
NumericalQuality Basic
XC
GGA PBE
End
EndEngine
```
### GGA single point: ADF/PBE/DZP
```ams
Properties
OrbitalsInfo yes
End
Task SinglePoint
System
Atoms
C 0.6651665049 0.0281045107 -0.0235971144
C -0.6651713207 -0.0281053452 0.0236173947
H 1.2802120569 -0.8698054143 0.0685226284
H 1.1943503882 0.9738532541 -0.1567756217
H -1.2801922123 0.8698550678 -0.0682160798
H -1.1943654169 -0.9739020730 0.1564487929
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
Type DZP
End
NumericalQuality Basic
XC
GGA PBE
End
EndEngine
```
### Hybrid single point: ADF/B3LYP/DZP
```ams
Properties
OrbitalsInfo yes
End
Task SinglePoint
System
Atoms
C 0.6651665049 0.0281045107 -0.0235971144
C -0.6651713207 -0.0281053452 0.0236173947
H 1.2802120569 -0.8698054143 0.0685226284
H 1.1943503882 0.9738532541 -0.1567756217
H -1.2801922123 0.8698550678 -0.0682160798
H -1.1943654169 -0.9739020730 0.1564487929
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
Type DZP
End
NumericalQuality Basic
XC
Hybrid B3LYP
End
EndEngine
```
## Conclusion
With this modest DZP setup, the B3LYP single point increases the HOMO-LUMO gap from 5.801 eV for PBE to 7.561 eV. The increase is mainly from a lower HOMO and a higher LUMO relative to the PBE values.



