# Molecule specification grammar

This is the complete reference for the **`atom=`** string grammar accepted by `qc.chk.new(...)`. The
[molecular-input chapter](../20-guide/molecular-input.md) is the tutorial introduction; this page is the
precise, exhaustive specification. The grammar is Gaussian-compatible.

## Atom-line grammar

Each atom is one line (atoms separated by newline or `;`):

```text
Element-label[-Atom-type[-Charge]][(param=value,...)] [freeze-code] x y z
```

| Field | Required | Description |
|---|---|---|
| `Element-label` | ✓ | Chemical symbol, atomic number, or special symbol |
| `-Atom-type` | — | MM force-field type (e.g. `CT`, `O`, `Bq`) |
| `-Charge` | — | MM partial charge (float) |
| `(param=value,...)` | — | Nuclear / fragment parameters |
| `freeze-code` | — | Integer: `0` = free, `−1` = frozen |
| `x y z` | ✓ | Cartesian coordinates (in `unit=`, default ångström) |

## Element label

```text
(chemical-symbol | atomic-number) [identifier]
```

- **Chemical symbol** — `H`, `He`, `C`, `Fe`, … (case-insensitive).
- **Atomic number** — `1`, `6`, `26`, ….
- **Identifier** — an optional label suffix after the symbol/number, not length-limited (`C1`, `C2`, `O_a`,
  `Fe3`). The label is used for basis-dictionary lookup and per-atom selection.

```text
C        # carbon
C1       # carbon, labelled "C1"
6        # carbon by atomic number
Fe3      # iron, labelled "Fe3"
```

## Atom type (MM field)

```text
Element-AtomType
Element-AtomType-Charge
Element-AtomType--NegCharge     ← double-dash for a negative charge
```

The MM type is stored (`ParsedAtomLine.mm`) but does not currently affect quantum-chemical integrals. `Bq` as
an atom type (e.g. `O-Bq`) creates a **ghost atom** (below).

```text
C-CT          # SP3 aliphatic carbon
C-CT-0.32     # partial charge +0.32
O-O--0.5      # partial charge -0.5 via double-dash
```

## Nuclear parameters

Given in parentheses after the element label, comma-separated:

| Keyword | Type | Meaning |
|---|---|---|
| `Iso=n` | `u32` | Isotope mass number (`Iso=13` → ¹³C) |
| `Spin=n` | `i32` | Nuclear spin in units of ½ |
| `ZEff=n` | `f64` | Effective nuclear charge (spin-orbit, ESR g-tensor) |
| `ZNuc=n` | `f64` | **Override** the nuclear charge `z` |
| `QMom=n` | `f64` | Nuclear quadrupole moment |
| `NMagM=n` | `f64` | Nuclear magnetic moment (nuclear magnetons) |
| `RadNuclear=r` | `f64` | Finite-nucleus radius (a.u.) |
| `Fragment=n` | `u32` | Fragment number (counterpoise / `Guess=Fragment`) |
| `RESNum` / `RESName` / `PDBName` | str | PDB metadata (accepted, ignored in QC) |

```text
C(Iso=13,Fragment=2)  0.0 0.0 0.0
O(ZNuc=8.0)           0.0 0.0 0.0
```

Most of this metadata is parsed and stored but does not yet affect the Hamiltonian or optimizer.

## Freeze code

An integer between the label and the coordinates: `0` = free (default), `−1` = frozen. It is parsed and
stored (`ParsedAtomLine.frozen`); the geometry optimizer does **not** yet consume it.

```text
C  0  0.000 0.000 0.000   # free
C -1  0.000 0.000 1.500   # frozen (parsed, not yet enforced)
```

## Special atoms

### Ghost atoms (`Element-Bq`)

**Nuclear charge 0, no electrons, but full basis functions** from the named element — for counterpoise/BSSE.
Ghosts **are** counted by `natom()` (they carry AO functions) but contribute 0 to `nelectron()` and
`nuclear_energy()`.

```text
O-Bq     # ghost oxygen
H-Bq     # ghost hydrogen (inherits the "H" basis automatically)
```

Basis lookup priority for a ghost: (1) the atom label key, (2) the base element symbol, (3) the element
fallback.

### Dummy atoms (`X`, `Xx`)

Pure geometric reference points: **no nuclear charge, no electrons, no basis functions**. Recognized forms
(case-insensitive): `X`, `Xx`, `X1`, `X-ref`. Stored in `dummy_atoms()`; **not** counted by `natom()`.

### Translation vectors (`TV`)

For periodic systems, append lattice vectors after the geometry (one `TV` for a 1-D polymer, two for a sheet,
three for a crystal). Stored in `translation_vectors()` (bohr); not counted by `natom()`/`ndummy()`.

```text
C   0.000 0.000 0.000
C   0.000 0.000 1.420
TV  2.460 0.000 0.000
```

## Charge / spin

In the public API, pass `charge=` and `spin=` to `qc.chk.new(...)`. `spin` is the **Gaussian multiplicity
2S+1** (1 = singlet, 2 = doublet, 3 = triplet). The raw text form (for the low-level parser) is
`charge mult`, or per-fragment `total_charge total_mult  frag1_charge frag1_mult  …`.

## Invariants (summary)

| Rule | |
|---|---|
| Ghost & dummy atoms | contribute **no electrons** and **no nuclear repulsion** |
| Ghost atoms | **do** carry AO basis functions; counted by `natom()` |
| Dummy atoms | **no** basis functions; **not** counted by `natom()` |
| Translation vectors | not counted by `natom()` / `ndummy()` |
| Stored coordinates | always **bohr** (converted from `unit=` on input) |

See the [molecular-input chapter](../20-guide/molecular-input.md) for worked, verified examples of every
special atom.
