ADF Optimization and Vibrational Analysis of Formaldehyde¶
Requires: AMS2026 or later
Related documentation
Calculation¶
Formaldehyde was built from the SMILES string C=O, symmetrized, and optimized as a neutral closed-shell molecule. The optimized structure has C(2V) symmetry. ADF used PBE-D3(BJ), the all-electron DZP basis, and default numerical and SCF settings. Harmonic normal modes and IR intensities were calculated at the final optimized geometry.
Job directory: 01-run_workdir/formaldehyde_adf_pbe_dzp
Provenance: Combined ADF geometry optimization, harmonic frequencies, IR intensities, and PES-point characterization.
Optimized geometry¶
Quantity |
Value |
Unit |
|---|---|---|
C=O |
1.212143 |
angstrom |
C-H(1) |
1.115562 |
angstrom |
C-H(2) |
1.115562 |
angstrom |
mean C-H |
1.115562 |
angstrom |
H-C-H |
115.943895 |
degree |

Minimum verification¶
AMS PES-point classification: local minimum.
Negative harmonic frequencies: 0.
The optimized formaldehyde structure is a local minimum. AMS classified the PES point as local minimum, and all 6 vibrational frequencies are positive.
Vibrational modes¶
The assignments use changes in C=O distance, the two C-H distances, H-C-H angle, and displacement normal to the molecular plane. They are qualitative harmonic-mode descriptions.
Mode |
Frequency (cm^-1) |
IR intensity (km mol^-1) |
Symmetry |
Qualitative assignment |
|---|---|---|---|---|
1 |
1157.06 |
4.682 |
B1 |
CH2 out-of-plane bend |
2 |
1226.38 |
8.786 |
B2 |
CH2 in-plane rocking bend |
3 |
1487.73 |
14.647 |
A1 |
H-C-H scissoring bend |
4 |
1743.28 |
88.378 |
A1 |
C=O stretch |
5 |
2797.14 |
60.003 |
A1 |
symmetric C-H stretch |
6 |
2850.66 |
133.912 |
B2 |
asymmetric C-H stretch |
Broadened IR spectrum¶
The blue curve applies Gaussian broadening with a width of 20 cm^-1 to the calculated sticks. Red lines mark the unbroadened modes. The wavenumber axis follows the usual IR convention.

Normal-mode displacement pictures¶
The maximum atomic displacement in each outer structure is 0.25 angstrom. All views use along_pca3.
Mode 1: 1157.06 cm^-1, B1¶
Assignment: CH2 out-of-plane bend. The left and right structures use equal displacements along the normal coordinate.

Mode 2: 1226.38 cm^-1, B2¶
Assignment: CH2 in-plane rocking bend. The left and right structures use equal displacements along the normal coordinate.

Mode 3: 1487.73 cm^-1, A1¶
Assignment: H-C-H scissoring bend. The left and right structures use equal displacements along the normal coordinate.

Mode 4: 1743.28 cm^-1, A1¶
Assignment: C=O stretch. The left and right structures use equal displacements along the normal coordinate.

Mode 5: 2797.14 cm^-1, A1¶
Assignment: symmetric C-H stretch. The left and right structures use equal displacements along the normal coordinate.

Mode 6: 2850.66 cm^-1, B2¶
Assignment: asymmetric C-H stretch. The left and right structures use equal displacements along the normal coordinate.

AMS input¶
Properties
NormalModes yes
PESPointCharacter yes
End
Task GeometryOptimization
System
Atoms
C 0.0000000000 0.0000000000 0.0337596501
O 0.0000000000 0.0000000000 -1.1856950809
H 0.0000000000 0.9391319492 0.5759677154
H 0.0000000000 -0.9391319492 0.5759677154
End
BondOrders
1 2 2.0
1 3 1.0
1 4 1.0
End
End
Engine adf
Basis
Core None
Type DZP
End
XC
Dispersion GRIMME3 BJDAMP
GGA PBE
End
EndEngine
Conclusion¶
The optimized formaldehyde structure is a local minimum. AMS classified the PES point as local minimum, and all 6 vibrational frequencies are positive. The optimized bond metrics are C=O 1.212143 angstrom, mean C-H 1.115562 angstrom, and H-C-H 115.9439 degrees.
Prompts and Python scripts¶
Prompt (instruction for AI agent)
Use $ams2026
Optimize formaldehyde and calculate its vibrational frequencies with ADF.
Build formaldehyde from SMILES C=O and symmetrize. Run an ADF geometry
optimization with a modest GGA functional, a small-to-medium basis set,
and dispersion.
Verify that the optimized structure is a minimum with no imaginary
frequencies. Report the optimized C=O and C-H bond lengths and the H-C-H angle.
In the report, include a table of vibrational frequencies, IR intensities,
symmetries, and qualitative mode assignments. Plot a simple broadened IR
spectrum from the calculated frequencies and intensities.
For each normal mode, use plot_image_grid along_pca3 to show three pictures
side-by-side where you have displaced-in-negative-direction, optimized
structure, displaced-in-positive-direction.
01-run.py
#!/usr/bin/env amspython
from __future__ import annotations
from pathlib import Path
from scm.base import ChemicalSystem, InputParser
from scm.plams import AMSJob, Settings, finish, init
def build_formaldehyde() -> tuple[ChemicalSystem, str]:
"""Build formaldehyde from the requested SMILES and impose molecular symmetry."""
system = ChemicalSystem.from_smiles("C=O")
point_group = system.symmetrize_molecule(tolerance=0.10)
return system, point_group
def adf_settings() -> Settings:
settings = Settings()
settings.input.ams.Task = "GeometryOptimization"
settings.input.ams.Properties.NormalModes = "Yes"
settings.input.ams.Properties.PESPointCharacter = "Yes"
settings.input.adf.Basis.Type = "DZP"
settings.input.adf.Basis.Core = "None"
settings.input.adf.XC.GGA = "PBE"
settings.input.adf.XC.Dispersion = "GRIMME3 BJDAMP"
return settings
def main() -> None:
system, point_group = build_formaldehyde()
settings = adf_settings()
job = AMSJob(molecule=system, settings=settings, name="formaldehyde_adf_pbe_dzp")
input_text = job.get_input()
InputParser().to_dict("ams", input_text)
Path("validated_input.in").write_text(input_text, encoding="utf-8")
print(f"Built formaldehyde from SMILES C=O and symmetrized it to {point_group}.")
print("Validated the serialized AMS/ADF input against the installed input definitions.")
init(folder="01-run_workdir")
results = job.run()
if not job.ok():
raise RuntimeError(f"AMS job did not finish successfully: {results.job.path}")
print(f"Completed job: {job.path}")
finish()
if __name__ == "__main__":
main()
report.py
#!/usr/bin/env amspython
from __future__ import annotations
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from scm.plams import AMSJob, plot_image_grid, view
ROOT = Path(__file__).resolve().parent
TABLES = ROOT / "tables"
FIGURES = ROOT / "figures"
JOB_NAME = "formaldehyde_adf_pbe_dzp"
def latest_job_path() -> Path:
workdirs = [path for path in ROOT.glob("01-run_workdir*") if path.is_dir()]
if not workdirs:
raise FileNotFoundError("No 01-run_workdir directory was found")
latest = max(workdirs, key=lambda path: path.stat().st_mtime)
job_path = latest / JOB_NAME
if not job_path.is_dir():
raise FileNotFoundError(f"Expected AMS job directory: {job_path}")
return job_path
def atom_indices(system) -> tuple[int, int, list[int]]:
carbon = [i for i, atom in enumerate(system.atoms) if atom.symbol == "C"]
oxygen = [i for i, atom in enumerate(system.atoms) if atom.symbol == "O"]
hydrogens = [i for i, atom in enumerate(system.atoms) if atom.symbol == "H"]
if len(carbon) != 1 or len(oxygen) != 1 or len(hydrogens) != 2:
raise ValueError("The optimized system does not have the expected CH2O composition")
return carbon[0], oxygen[0], hydrogens
def symmetry_labels(job: AMSJob, count: int) -> list[str]:
raw = job.results.readrkf("Vibrations", "IrReps", file="engine")
if isinstance(raw, str):
labels = raw.split()
else:
labels = [str(value).strip() for value in np.asarray(raw).reshape(-1)]
if len(labels) != count:
raise ValueError(f"Found {len(labels)} symmetry labels for {count} modes")
return labels
def internal_derivatives(system, mode: np.ndarray) -> dict[str, float]:
c_idx, o_idx, h_idx = atom_indices(system)
step = 0.01
plus = system.copy()
minus = system.copy()
plus.coords[:] = np.asarray(system.coords) + step * mode
minus.coords[:] = np.asarray(system.coords) - step * mode
def central(value_plus: float, value_minus: float) -> float:
return (value_plus - value_minus) / (2.0 * step)
d_co = central(plus.get_distance(c_idx, o_idx), minus.get_distance(c_idx, o_idx))
d_ch = [
central(plus.get_distance(c_idx, h), minus.get_distance(c_idx, h))
for h in h_idx
]
d_angle = central(
plus.get_angle(h_idx[0], c_idx, h_idx[1], unit="degree"),
minus.get_angle(h_idx[0], c_idx, h_idx[1], unit="degree"),
)
coords = np.asarray(system.coords)
molecular_normal = np.cross(coords[o_idx] - coords[c_idx], coords[h_idx[0]] - coords[c_idx])
molecular_normal /= np.linalg.norm(molecular_normal)
oop = sum(abs(np.dot(mode[h] - mode[c_idx], molecular_normal)) for h in h_idx)
return {"co": d_co, "ch1": d_ch[0], "ch2": d_ch[1], "angle": d_angle, "oop": oop}
def assign_modes(frequencies: np.ndarray, modes: np.ndarray, system) -> list[str]:
metrics = [internal_derivatives(system, mode) for mode in modes]
assignments = [""] * len(frequencies)
high = [i for i, frequency in enumerate(frequencies) if frequency > 2200.0]
low = [i for i in range(len(frequencies)) if i not in high]
for i in high:
same_phase = metrics[i]["ch1"] * metrics[i]["ch2"] >= 0.0
assignments[i] = "symmetric C-H stretch" if same_phase else "asymmetric C-H stretch"
if low:
oop_idx = max(low, key=lambda i: metrics[i]["oop"])
assignments[oop_idx] = "CH2 out-of-plane bend"
remaining = [i for i in low if i != oop_idx]
if remaining:
co_idx = max(remaining, key=lambda i: abs(metrics[i]["co"]))
assignments[co_idx] = "C=O stretch"
remaining.remove(co_idx)
if remaining:
scissor_idx = max(remaining, key=lambda i: abs(metrics[i]["angle"]))
assignments[scissor_idx] = "H-C-H scissoring bend"
remaining.remove(scissor_idx)
for i in remaining:
assignments[i] = "CH2 in-plane rocking bend"
return [assignment or "mixed vibration" for assignment in assignments]
def make_mode_grids(system, modes: np.ndarray) -> list[Path]:
grid_paths: list[Path] = []
optimized_image = FIGURES / "optimized_structure.png"
view(
system,
guess_bonds=len(system.bonds) == 0,
direction="along_pca3",
width=500,
height=400,
picture_path=str(optimized_image),
)
for number, mode in enumerate(modes, start=1):
max_norm = float(np.linalg.norm(mode, axis=1).max())
scale = 0.25 / max_norm
negative = system.copy()
positive = system.copy()
negative.coords[:] = np.asarray(system.coords) - scale * mode
positive.coords[:] = np.asarray(system.coords) + scale * mode
images = {}
for label, structure in [
("negative displacement", negative),
("optimized structure", system),
("positive displacement", positive),
]:
image_path = FIGURES / f"mode_{number:02d}_{label.replace(' ', '_')}.png"
images[label] = view(
structure,
guess_bonds=len(structure.bonds) == 0,
direction="along_pca3",
width=360,
height=300,
picture_path=str(image_path),
)
grid_path = FIGURES / f"mode_{number:02d}_grid.png"
plot_image_grid(images, rows=1, figsize=(12, 3.5), save_path=str(grid_path))
plt.close("all")
grid_paths.append(grid_path)
return grid_paths
def markdown_image(path: Path, alt: str) -> str:
return f".as_posix()})"
def format_input(input_text: str) -> str:
return f"```ams\n{input_text.rstrip()}\n```"
def main() -> None:
TABLES.mkdir(exist_ok=True)
FIGURES.mkdir(exist_ok=True)
job_path = latest_job_path()
job = AMSJob.load_external(str(job_path))
provenance = "Combined ADF geometry optimization, harmonic frequencies, IR intensities, and PES-point characterization."
system = job.results.get_main_system()
symmetry_probe = system.copy()
optimized_point_group = symmetry_probe.symmetrize_molecule(tolerance=0.05)
frequencies = np.asarray(job.results.get_frequencies(unit="cm^-1"), dtype=float)
intensities = np.asarray(job.results.get_ir_intensities(), dtype=float)
modes = np.asarray(job.results.get_normal_modes(), dtype=float)
labels = symmetry_labels(job, len(frequencies))
assignments = assign_modes(frequencies, modes, system)
c_idx, o_idx, h_idx = atom_indices(system)
co_length = system.get_distance(c_idx, o_idx)
ch_lengths = [system.get_distance(c_idx, h) for h in h_idx]
hch_angle = system.get_angle(h_idx[0], c_idx, h_idx[1], unit="degree")
try:
pes_character = str(job.results.readrkf("AMSResults", "PESPointCharacter", file="engine")).strip()
except KeyError:
pes_character = str(job.results.readrkf("AMSResults", "PESPointCharacter", file="ams")).strip()
imaginary = frequencies[frequencies < 0.0]
is_minimum = len(imaginary) == 0 and "minimum" in pes_character.lower()
frequency_table = pd.DataFrame(
{
"Mode": np.arange(1, len(frequencies) + 1),
"Frequency (cm^-1)": np.round(frequencies, 2),
"IR intensity (km mol^-1)": np.round(intensities, 3),
"Symmetry": labels,
"Qualitative assignment": assignments,
}
)
frequency_table.to_csv(TABLES / "vibrational_modes.csv", index=False)
geometry_table = pd.DataFrame(
{
"Quantity": ["C=O", "C-H(1)", "C-H(2)", "mean C-H", "H-C-H"],
"Value": [co_length, ch_lengths[0], ch_lengths[1], np.mean(ch_lengths), hch_angle],
"Unit": ["angstrom", "angstrom", "angstrom", "angstrom", "degree"],
}
)
geometry_table.to_csv(TABLES / "optimized_geometry.csv", index=False)
spectrum_x, spectrum_y = job.results.get_ir_spectrum(
broadening_type="gaussian",
broadening_width=20,
min_x=400,
max_x=3400,
x_spacing=1.0,
)
fig, ax = plt.subplots(figsize=(8, 4.5))
ax.plot(spectrum_x, spectrum_y, color="#214f8b", linewidth=1.6)
ax.vlines(frequencies, 0.0, intensities, color="#a33a2b", linewidth=0.8, alpha=0.7)
ax.set_xlim(3400, 400)
ax.set_xlabel(r"Wavenumber (cm$^{-1}$)")
ax.set_ylabel(r"IR intensity (km mol$^{-1}$)")
ax.set_title("Harmonic IR spectrum, Gaussian width 20 cm$^{-1}$")
fig.tight_layout()
spectrum_path = FIGURES / "ir_spectrum.png"
fig.savefig(spectrum_path, dpi=180)
plt.close(fig)
mode_grid_paths = make_mode_grids(system, modes)
mode_sections = []
for row, grid_path in zip(frequency_table.itertuples(index=False), mode_grid_paths):
mode_sections.append(
f"### Mode {row.Mode}: {row._1:.2f} cm^-1, {row.Symmetry}\n\n"
f"Assignment: {row._4}. The left and right structures use equal displacements along the normal coordinate.\n\n"
f"{markdown_image(grid_path, f'Mode {row.Mode} displacement grid')}"
)
if is_minimum:
conclusion = (
"The optimized formaldehyde structure is a local minimum. AMS classified the PES point as "
f"{pes_character}, and all {len(frequencies)} vibrational frequencies are positive."
)
else:
conclusion = (
"The minimum test did not pass. The PES classification is "
f"{pes_character}, and the number of negative frequencies is {len(imaginary)}."
)
report = f"""# ADF optimization and vibrational analysis of formaldehyde
## Calculation
Formaldehyde was built from the SMILES string `C=O`, symmetrized, and optimized as a neutral closed-shell molecule. The optimized structure has {optimized_point_group} symmetry. ADF used PBE-D3(BJ), the all-electron DZP basis, and default numerical and SCF settings. Harmonic normal modes and IR intensities were calculated at the final optimized geometry.
Job directory: `{job_path.relative_to(ROOT)}`
Provenance: {provenance}
## Optimized geometry
{geometry_table.to_markdown(index=False, floatfmt='.6f')}
{markdown_image(FIGURES / 'optimized_structure.png', 'Optimized formaldehyde structure')}
## Minimum verification
AMS PES-point classification: `{pes_character}`.
Negative harmonic frequencies: {len(imaginary)}.
{conclusion}
## Vibrational modes
The assignments use changes in C=O distance, the two C-H distances, H-C-H angle, and displacement normal to the molecular plane. They are qualitative harmonic-mode descriptions.
{frequency_table.to_markdown(index=False)}
## Broadened IR spectrum
The blue curve applies Gaussian broadening with a width of 20 cm^-1 to the calculated sticks. Red lines mark the unbroadened modes. The wavenumber axis follows the usual IR convention.
{markdown_image(spectrum_path, 'Broadened harmonic IR spectrum')}
## Normal-mode displacement pictures
The maximum atomic displacement in each outer structure is 0.25 angstrom. All views use `along_pca3`.
{chr(10).join(mode_sections)}
## AMS input
{format_input(job.get_input())}
## Conclusion
{conclusion} The optimized bond metrics are C=O {co_length:.6f} angstrom, mean C-H {np.mean(ch_lengths):.6f} angstrom, and H-C-H {hch_angle:.4f} degrees.
"""
(ROOT / "report.md").write_text(report, encoding="utf-8")
print(f"Wrote {ROOT / 'report.md'}")
print(conclusion)
if __name__ == "__main__":
main()
Original Markdown report
# ADF optimization and vibrational analysis of formaldehyde
## Calculation
Formaldehyde was built from the SMILES string `C=O`, symmetrized, and optimized as a neutral closed-shell molecule. The optimized structure has C(2V) symmetry. ADF used PBE-D3(BJ), the all-electron DZP basis, and default numerical and SCF settings. Harmonic normal modes and IR intensities were calculated at the final optimized geometry.
Job directory: `01-run_workdir/formaldehyde_adf_pbe_dzp`
Provenance: Combined ADF geometry optimization, harmonic frequencies, IR intensities, and PES-point characterization.
## Optimized geometry
| Quantity | Value | Unit |
|:-----------|-----------:|:---------|
| C=O | 1.212143 | angstrom |
| C-H(1) | 1.115562 | angstrom |
| C-H(2) | 1.115562 | angstrom |
| mean C-H | 1.115562 | angstrom |
| H-C-H | 115.943895 | degree |

## Minimum verification
AMS PES-point classification: `local minimum`.
Negative harmonic frequencies: 0.
The optimized formaldehyde structure is a local minimum. AMS classified the PES point as local minimum, and all 6 vibrational frequencies are positive.
## Vibrational modes
The assignments use changes in C=O distance, the two C-H distances, H-C-H angle, and displacement normal to the molecular plane. They are qualitative harmonic-mode descriptions.
| Mode | Frequency (cm^-1) | IR intensity (km mol^-1) | Symmetry | Qualitative assignment |
|-------:|--------------------:|---------------------------:|:-----------|:--------------------------|
| 1 | 1157.06 | 4.682 | B1 | CH2 out-of-plane bend |
| 2 | 1226.38 | 8.786 | B2 | CH2 in-plane rocking bend |
| 3 | 1487.73 | 14.647 | A1 | H-C-H scissoring bend |
| 4 | 1743.28 | 88.378 | A1 | C=O stretch |
| 5 | 2797.14 | 60.003 | A1 | symmetric C-H stretch |
| 6 | 2850.66 | 133.912 | B2 | asymmetric C-H stretch |
## Broadened IR spectrum
The blue curve applies Gaussian broadening with a width of 20 cm^-1 to the calculated sticks. Red lines mark the unbroadened modes. The wavenumber axis follows the usual IR convention.

## Normal-mode displacement pictures
The maximum atomic displacement in each outer structure is 0.25 angstrom. All views use `along_pca3`.
### Mode 1: 1157.06 cm^-1, B1
Assignment: CH2 out-of-plane bend. The left and right structures use equal displacements along the normal coordinate.

### Mode 2: 1226.38 cm^-1, B2
Assignment: CH2 in-plane rocking bend. The left and right structures use equal displacements along the normal coordinate.

### Mode 3: 1487.73 cm^-1, A1
Assignment: H-C-H scissoring bend. The left and right structures use equal displacements along the normal coordinate.

### Mode 4: 1743.28 cm^-1, A1
Assignment: C=O stretch. The left and right structures use equal displacements along the normal coordinate.

### Mode 5: 2797.14 cm^-1, A1
Assignment: symmetric C-H stretch. The left and right structures use equal displacements along the normal coordinate.

### Mode 6: 2850.66 cm^-1, B2
Assignment: asymmetric C-H stretch. The left and right structures use equal displacements along the normal coordinate.

## AMS input
```ams
Properties
NormalModes yes
PESPointCharacter yes
End
Task GeometryOptimization
System
Atoms
C 0.0000000000 0.0000000000 0.0337596501
O 0.0000000000 0.0000000000 -1.1856950809
H 0.0000000000 0.9391319492 0.5759677154
H 0.0000000000 -0.9391319492 0.5759677154
End
BondOrders
1 2 2.0
1 3 1.0
1 4 1.0
End
End
Engine adf
Basis
Core None
Type DZP
End
XC
Dispersion GRIMME3 BJDAMP
GGA PBE
End
EndEngine
```
## Conclusion
The optimized formaldehyde structure is a local minimum. AMS classified the PES point as local minimum, and all 6 vibrational frequencies are positive. The optimized bond metrics are C=O 1.212143 angstrom, mean C-H 1.115562 angstrom, and H-C-H 115.9439 degrees.
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.