Skip to content

Qualitative MO correlation diagrams: central atom orbitals, terminal atom symmetry orbitals (TASOs), and symmetry labels #132

Open

Description

@ohlincha

Build the qualitative MO correlation diagram a chemist actually draws: central
atom orbitals on the left, ligand SALCs on the right, the molecular orbitals in
the middle, with the correlation lines and symmetry labels between them.

TASO = terminal atom symmetry orbitals -- the symmetry-adapted combinations
built from the outer atoms' orbitals, as opposed to the central atom's, which
enter the diagram on their own. (An earlier revision of this issue guessed
"SALC"; TASO is the term Andy used and is the more specific one, since it names
which atoms the combinations are built from.)

Fine to restrict the first implementation to small, high-symmetry molecules --
AH_n, octahedral and tetrahedral ML_n. That is where the diagram is taught and
where it is worth the most.

Why this is more than a drawing

ECCE already has the hard parts. Orbital energies, occupancies and symmetry
labels are extracted for several codes (ORBENG, ORBOCC, ORBSYM), and
MoPanel already lists them with their irreducible representation. What is
missing is the decomposition: which fragment orbitals each MO is built from,
and how much of each. With the AO coefficients in hand that is a projection --
form the TASOs for the terminal set, project each MO onto them and onto the
central atom's AOs, and the correlation lines and their weights fall out.

The MOPAC orbital work (#128) makes the AO coefficients available for a
semiempirical code, which is the cheap end where a user can iterate on a
structure in seconds. That is a good match for a teaching diagram.

What would have to be built

  1. A point group table. Character tables for at least the common groups
    (C_2v, C_3v, D_2h, D_3h, D_4h, T_d, O_h), with irrep labels, symmetry
    operations and the reduction formula. This is a data file, not code -- the
    same shape as data/client/config/properties. ECCE already carries
    symmetry labels from the codes but has no understanding of them; it cannot
    answer "is a1 symmetric under C_2" today.

  2. Symmetry detection, or trust the code. The point group is already known
    to the calculation in most cases -- the codereg dialogs are handed a
    symmetry group in globals.py's argv, and several parsers extract it. Start
    by trusting that rather than writing a perception algorithm.

  3. TASO construction. Apply the projection operator to the terminal atoms'
    AO set to get the symmetry-adapted combinations and their irreps. The
    central atom's own orbitals need no such treatment -- they already
    transform as irreps of the full group, which is the asymmetry that makes
    the two sides of the diagram different objects rather than one procedure
    applied twice.

  4. Projection and the diagram itself. A new property panel, in the family
    of MoPanel; clicking a level should show that MO in the viewer, which is
    the wiring VizPropertyPanel already provides.

Worth deciding early

  • Core orbitals. Worth showing as a separate, collapsed block rather than
    as diagram levels -- they are on every diagram as a footnote and would
    otherwise compress the valence region that matters. Note that semiempirical
    codes have no core orbitals at all, so the panel must be honest about which
    it is showing rather than implying they are absent.
  • Degenerate sets must be drawn as one level of the right multiplicity, and
    the multiplicity must come from the irrep, not from counting near-equal
    energies -- an accidental near-degeneracy is not a degenerate set.

Andy's framing: "This is something exciting." Agreed -- it is the one thing in
this area that a general-purpose viewer does not already do better.

Activity

  1. changed the title [-]Qualitative MO correlation diagrams: central atom orbitals, ligand SALCs, and symmetry labels[/-] [+]Qualitative MO correlation diagrams: central atom orbitals, terminal atom symmetry orbitals (TASOs), and symmetry labels[/+] on Sep 24, 2026
  2. ohlincha commented on Sep 24, 2026

    @ohlincha
    CollaboratorAuthor

    Roadmap

    What already exists (surveyed before planning, and it changes the shape of this)

    • Point group detection works today. SymmetryOps::find(Fragment&, threshold)
      returns the Schoenflies name. It shells out to src/apps/symmetry/autosym.f,
      NWChem's symmetry library. So no perception algorithm has to be written.
    • Symmetry operation matrices exist, in that same Fortran (gensym.f,
      dosymops.f, symops(maxops*3,4)), but only to generate and clean
      structures. They are not exposed to C++.
    • Irrep names exist for 46 groups, in data/client/config/PointGroups,
      loaded by PointGroup. Names only — no classes, no characters.
    • ORBSYM is already extracted for several codes, and MoPanel already
      displays it.

    So the missing pieces are narrower than "understand symmetry": characters,
    operations reachable from C++, projection, and the drawing.

    The oracle, decided first

    Every phase below has something to be checked against, which matters because a
    wrong correlation diagram looks like a correlation diagram.

    1. Character tables check themselves. The great orthogonality theorem makes
      the data file self-verifying: rows orthogonal, columns orthogonal, the sum
      of |chi|^2 over operations equal to the group order, the squared dimensions
      summing to the order. A transcription error cannot survive that, which is
      the right property for a hand-entered table of 46 groups.
    2. ORBSYM is a free, independent oracle for the whole symmetry pipeline.
      The code has already labelled every MO with its irrep. If our own projection
      assigns an MO to a different irrep than NWChem or Gaussian did, one of us is
      wrong and it is almost certainly us. This checks detection, orientation,
      characters and projection in one comparison, on any existing job, with
      no new fixtures.
    3. Textbooks for the TASOs. CH4's four H 1s orbitals reduce to a1 + t2,
      water's two to a1 + b2, SF6's six to a1g + eg + t1u. Unambiguous and in
      every inorganic text.

    Phase 1 -- character tables

    Extend data/client/config/PointGroups (or a sibling file, to avoid
    disturbing a format other code reads) with, per group: the classes with their
    operation counts, and the character of each irrep in each class.

    Start with the groups the target molecules need: C2v, C3v, C4v, D2h, D3h, D4h,
    Td, Oh, plus C1 and Cs as trivial cases. The other 36 can follow.

    Deliverable: PointGroup::characters(), classes(), order(), and the
    reduction formula n_i = (1/h) sum_R chi_i(R)* chi(R).
    Test: orthogonality, as above. Self-verifying, so this phase is cheap and
    low risk despite being data entry.

    Phase 2 -- symmetry operations in the molecule's frame

    The characters are abstract; projection needs the actual 3x3 matrices oriented
    to this molecule -- where the C3 axis really points.

    Two routes, and the choice matters:

    • (a) Surface what the Fortran already computes. gensym.f builds exactly
      these matrices. Adding an entry point that returns them alongside the group
      name is much less work than reimplementing, and it cannot disagree with the
      detector, since it is the detector.
    • (b) Reimplement in C++ from the inertia tensor and numerical tests.

    Recommend (a), and note that the existing find() already writes and reads
    a temporary file, so extending that exchange is a small change rather than new
    plumbing. Only if the Fortran turns out not to expose the frame should (b) be
    considered.

    Test: every operation must map the molecule onto itself -- for each atom,
    R x_i is another atom of the same element within tolerance. That is a
    complete check and needs no reference data.

    Phase 3 -- TASOs

    Partition the atoms into orbits under the group. The central atom is the orbit
    of size one lying on all the elements; the terminal atoms form the others.

    For each orbit and each AO type, build the reducible representation (the
    character of an operation is the number of basis functions it leaves in place,
    with sign), reduce it, then apply the projection operator to get the actual
    combinations, orthonormalising within each irrep.

    Deliverable: a list of TASOs, each with an irrep and coefficients over the
    terminal AOs.
    Test: the textbook reductions above.

    The central atom needs no such treatment -- its orbitals already transform
    as irreps of the full group. That asymmetry is why the two sides of the diagram
    are different objects rather than one procedure run twice, and it is worth
    encoding as such rather than generalising prematurely.

    Phase 4 -- projecting the real MOs

    For each MO, its overlap with each central AO and each TASO, weighted
    Mulliken-style through the overlap matrix S.

    S is nearly free now. The Gaussian overlap integral is a strict
    simplification of the Coulomb integral added for #129 -- same Hermite
    expansion, no Boys function -- so this is roughly forty lines in
    CoulombIntegrals, testable the same way against the closed form for two
    Gaussians, which tests/slater already computes.

    Deliverable: per-MO fragment decomposition, which is what sets the weight of
    each correlation line.
    Test: oracle 2. The irrep carrying the largest weight must match the
    code's own ORBSYM label, for every MO of every test job.

    Phase 5 -- the diagram

    A VizPropertyPanel subclass, in MoPanel's family, so clicking a level shows
    that orbital in the viewer through wiring that already exists.

    Decisions worth making deliberately rather than by default:

    • Degenerate sets are drawn as one level with the multiplicity taken from
      the irrep's dimension, never from counting near-equal energies. An accidental
      near-degeneracy is not a degenerate set.
    • Fragment energies. The MO energies are real; the left and right columns
      are not, and textbook diagrams place them from estimated valence orbital
      ionization energies. Either ship a small VOIE table as data and label the
      axis as qualitative for those columns, or place them purely by connectivity.
      This is the one place where the diagram is a drawing rather than a
      measurement, and it should say so on the panel.
    • Core orbitals as a separate collapsed block, not as levels, or they
      compress the valence region that matters. Semiempirical codes have none at
      all, so the panel must state which it is showing rather than let their
      absence read as a result.

    Ordering, and where the risk actually is

    Phases 1 and 2 are prerequisites with complete mechanical tests, so they are
    safe to do first and cheap to verify. Phase 3 has a textbook oracle. Phase 4 is
    where the whole pipeline gets checked against ORBSYM, and is therefore the
    point at which we learn whether any of this is right -- worth reaching early,
    even with a crude diagram
    , rather than after the drawing is polished.

    Phase 5 is the only part with no automated oracle. It goes last and should stay
    small.

    The likeliest failure is not the group theory but the frame: a detected
    group whose operations are expressed in a standard orientation that does not
    match the coordinates the MO coefficients were computed in. Phase 2's
    self-check (every operation maps the molecule onto itself) catches a wrong
    frame immediately, which is why it is worth doing even though it looks like a
    formality.

    Scope

    Restrict the first implementation to a clear central atom with equivalent
    terminal atoms -- AH_n and ML_n. Detect that shape and decline gracefully
    otherwise; benzene and ethene have no central atom and are a different diagram,
    not a harder case of this one.

  3. ohlincha commented on Sep 24, 2026

    @ohlincha
    CollaboratorAuthor

    Phases 1 and 2 are done, and cheaper than the roadmap estimated

    Phase 1 — character tables. Thirteen groups (C1, Cs, Ci, C2, C2v, C3v, C4v, C2h, D2h, D3h, D4h, Td, Oh), plus CharacterTable in C++ with the reduction formula. 987 checks.

    Phase 2 — the operations. Not the reimplementation the roadmap allowed for. gensym has always turned a group name into its operation matrices; spgen holds the generators, and cleansym/genmol/genmollat/getfrag all use the result. Nothing ever exposed them. src/apps/symmetry/symops.f is a forty-line wrapper, so the operations are the ones the structure tools have always used and cannot drift from them.

    Three findings worth recording

    1. gensym does not return the identity. It hands back the other h−1 operations — what the structure tools need, and not a complete group. Found by checking rather than reading: all thirteen groups came back exactly one short, consistently, which is a different thing from a bug. symops writes it first.

    2. The two data sources cross-validate. PNNL's Fortran generator tables and the hand-entered character tables are independent, and neither was derived from the other. They agree for every group on:

    • the group order
    • the number of conjugacy classes (which must equal the number of irreps)
    • the class sizes

    The matrices are also checked to be a group — determinants ±1, identity present, and closure under multiplication. Self-tested by corrupting one operation and watching closure fail.

    3. The frame problem is already solved — but there is a trap.

    The roadmap called the frame the likeliest failure: a detected group whose operations are in an orientation that doesn't match the coordinates the MO coefficients were computed in.

    autosym returns the molecule in the group's standard frame, and SymmetryOps::readSymmetry() writes those coordinates back into the fragment. So the operations and the coordinates already agree.

    The trap is that SymmetryOps::find() mutates the fragment. That is deliberate — FindSymmetryCmd is the Builder's "Find Symmetry", whose job is to symmetrise the structure. But MO analysis must never do it: the MO coefficients were computed against the original coordinates, and reorienting the molecule moves the AO centres out from under them, silently.

    So Phase 3 has to:

    • run detection on a copy, never the live fragment
    • recover the transform T between the original and standard frames (Kabsch on the atom positions)
    • express the operations back in the original frame as T⁻¹ R T

    The roadmap's Phase 2 test — every operation maps the molecule onto itself — is exactly the check for that, and now has something concrete to check.

    Next

    Phase 3, TASO construction: atom orbits under the group, then the projection operator. The textbook oracle stands (CH₄'s four H 1s → a₁ + t₂, SF₆'s six → a₁g + eg + t₁ᵤ).

  4. ohlincha commented on Sep 24, 2026

    @ohlincha
    CollaboratorAuthor

    Phase 3 design note: matching operations to named classes

    Checked before building on it, because it looked like it might be a blocker and is not.

    The reduction formula needs, for each operation, the character of the irrep — which means knowing which named class each matrix belongs to. Conjugacy classes are easy to compute from the matrices, but naming them is not automatic: several groups have two classes with the same size, trace and determinant.

    The worked cases:

    • C2v — σ(xz) and σ(yz) are both (det −1, trace +1, size 1). Distinguished by which axis they preserve: diag(1,-1,1) vs diag(-1,1,1). The class names in CharacterTables already encode this (sv_xz, sv_yz), deliberately.
    • D4h — the five C₂-type operations (det +1, trace −1) resolve as diag(-1,-1,1) = C₂(z), then diag(-1,1,-1) and diag(1,-1,-1) = the axis-aligned 2C₂′, and two with zero x/y diagonal entries = the diagonal 2C₂″. The standard convention (primed along the axes, double-primed along the diagonals) is recoverable straight from the matrices.
    • Oh — 6C₂ and 3C₂ share (det +1, trace −1) but differ in class size, so no extra work.

    So the rule is: conjugacy class → (determinant, trace, size) for the operation type, then axis orientation where that is not unique. Not ambiguous, but not free either — it needs a per-group convention rather than a generic matcher, and getting it wrong swaps B1/B2 (or B1g/B2g) silently.

    This is also exactly where ORBSYM earns its place as the oracle: a swapped convention shows up immediately as a disagreement with the code's own label, on any existing job. Worth noting that codes themselves sometimes differ here, so a disagreement wants checking rather than assuming we are wrong.

    Phase 3 can proceed on that basis. The first target stays CH₄: four H 1s orbitals give χ = (4, 1, 0, 0, 2) over (E, 8C₃, 3C₂, 6S₄, 6σd), which reduces to a₁ + t₂ — none of the ambiguous cases above, so it exercises the machinery without depending on the convention work.

  5. 24 remaining items

  6. ohlincha commented on Oct 11, 2026

    @ohlincha
    CollaboratorAuthor

    Decision (2026-10-11): where G16 or ORCA ran a slightly unsymmetric structure in a lower group (e.g. water in Cs), the diagram draws the higher group found on its symmetrised copy (C2v), with labels computed from the orbitals and cross-checked against the code's labels, and a note saying so (d790f1d).

  7. ohlincha commented on Oct 11, 2026

    @ohlincha
    CollaboratorAuthor

    Character tables added (d3ce098): C3–C6, C3h–C6h, S4, S6, S8, T, Th, O, I, Ih (43 groups in all). Complex-conjugate pairs are stored as one real two-dimensional E (2cos(2πk/n)), flagged separable, with norm 2h in the checks and in reduce(). All groups pass the orthogonality, dimension, class-count and Cartesian checks and the symops cross-check; Gaussian 16 labels for C3 and C3h match. The MO diagram now falls back to C1 only for groups still without a table (C7, C8, D8h …).

  8. ohlincha commented on Oct 11, 2026

    @ohlincha
    CollaboratorAuthor

    Homonuclear diatomics, ECCE-QM C2 (after b84c402), Andy's review 2026-10-11, to fix after 9.0.0-beta.2:

    1. Counts: the diagram shows four bonding and two antibonding levels (2σg, 2σu, 1πu, 3σg bonding; 1πg*, 3σu* antibonding). Taught (and correct for a homonuclear diatomic from 2s/2p): equal numbers, one antibonding partner per bonding combination — 2σg/2σu*, 1πu/1πg*, 3σg/3σu*. 2σu must be σ*₂s (antibonding) in C2 as in N2, whatever the s–p mixing does to its energy.
    2. Partner pairing (colours): 2σu is paired with 3σu* (same irrep), but the partners of a homonuclear diatomic are the g/u combinations of the same fragment orbitals: 2σg↔2σu*, 3σg↔3σu*, 1πu↔1πg*. Pair by fragment-orbital parentage (which AO pair each MO is the in-/out-of-phase combination of), not by irrep.
    3. He2: add tabulated free-atom valence (1s) energies for He so its fragment columns are drawn (Andy: yes).
      Tests: the ecceqm-c2/n2/he2 goldens plus the G16/ORCA N2/CO fixtures; counts and pairs asserted.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions