Getting Started#
seamm_thermochemistry is the shared atomic reference-energy database and
formation-energy arithmetic for SEAMM. A raw total energy from Gaussian,
ORCA, Psi4, or VASP has an arbitrary, code-dependent zero – meaningless to
a non-expert user, and not comparable across codes. Re-expressing it as an
energy or enthalpy of formation (relative to the elements in their
standard states) fixes both problems at once, and this package is the
single place that logic and its underlying reference data live, replacing
what used to be an independent, largely-duplicated copy in each of
gaussian_step, psi4_step, and vasp_step.
Installing#
The core library only depends on seamm-util:
pip install seamm_thermochemistry
Two optional extras add more:
seamm_thermochemistry[import]– pulls inpandas/openpyxlso the legacy Excel/CSV master-file importers inimportersare usable.seamm_thermochemistry[installer]– pulls inseamm-installerso theseamm-thermochemistry-installerconsole script can fetch the published reference database from Zenodo.
Fetching the reference database#
The reference database itself (thermochemistry.db) is not shipped
inside the Python package – it is a growing dataset published separately
on Zenodo, with a version DOI for every release. Fetch the local copy with:
seamm-thermochemistry-installer install
which downloads the latest version, verifies it against Zenodo’s own
checksum, and registers its location in ~/.seamm.d/seamm.ini’s
[thermochemistry] section. seamm_thermochemistry.DEFAULT_DB_PATH
then resolves to that location automatically.
seamm-thermochemistry-installer update (which seamm-manager update runs)
brings the copy up to the latest published version – but only if the local file is
exactly one of the published versions. A database you have edited, for instance with
curated or recomputed reference energies, is kept as it is and reported; to replace it
with the published version anyway, run
seamm-thermochemistry-installer update --force, which saves the old file as
thermochemistry.db.bak-<date> first. Every replacement keeps such a backup, and a
download is checked before it replaces anything. install never overwrites an
existing database, and uninstall leaves one with local changes in place unless
given --force.
The same commands also set up what the isodesmic (CBH) thermochemistry needs, so a user has nothing more to do:
the official fragment store (
fragments-official.db, Zenodo concept 10.5281/zenodo.24139305), installed beside the reference database and verified the same way.updatereplaces it whole by a newer published version, keeping a backup, unless the installed file is not a published version (then only with--force). The installation’s ownfragments.dbis never touched.the official reference library (
references-official.db, Zenodo concept 10.5281/zenodo.24175073): enthalpies of formation that ATcT lacks, installed and updated the same way. The installation’s ownreferences.dbis never touched.the Active Thermochemical Tables, downloaded from atct.anl.gov when no version is cached. A newer ATcT version is added only on purpose, with
seamm-thermochemistry-atct download: the Thermochemistry step uses the newest cached version by default, so a new version changes its reference values.
check reports all of them and offers to install what is missing. A failure to get
the fragment store, the reference library or ATcT (no network, say) is reported and does not stop the rest.
A quick example#
from seamm_thermochemistry import ThermoDB, formation_energy
with ThermoDB("my_reference.db") as db:
db.add_element(1, "H", dfH0_0K=216.034, standard_state="1/2 H2(g)")
db.add_element(8, "O", dfH0_0K=246.79, standard_state="1/2 O2(g)")
db.add_atom_energy("H", "gaussian", "CBS-QB3", -1312.0)
db.add_atom_energy("O", "gaussian", "CBS-QB3", -197400.0)
dfE = formation_energy(
{"H": 2, "O": 1}, system_energy, db, "gaussian", "CBS-QB3"
)
Two reference conventions, one schema#
The ref_type column on atom_energy distinguishes:
"atom"– the isolated gas-phase atom (Gaussian/Psi4/ORCA’s convention). Pairs with an experimental anchor (element.dfH0_0K/dfH0_298K) to give a true, cross-code-comparable energy/enthalpy of formation."element_phase"– energy per atom of the element’s standard-state phase (bulk metal, graphite, O2(g), …) – VASP’s existing convention, needing no experimental anchor, and useful as a fallback reference for elements (e.g. Mn) where the free atom is a poor DFT target.
formation_energy(..., anchor=True) matches the existing
gaussian_step/psi4_step enthalpy-of-formation arithmetic exactly
(and gives an energy of formation, not an enthalpy, when the system
energy excludes the zero-point energy and the 0 K anchor is used).
formation_energy(..., anchor=False) matches vasp_step’s existing
DfE0 convention exactly.
formation_enthalpy and formation_gibbs_energy take the system’s total
enthalpy H(T) or Gibbs energy G(T) (electronic energy + ZPE + thermal
correction, on the same absolute scale as the atom energies) and reference it
to the elements in their standard states at T. Besides the 0 K anchor they need
each element’s standard-state H(298.15 K)-H(0 K)
(element.h298_minus_h0_std_state, tabulated per formula unit of the
standard state and halved for the diatomic gases) and, for G, the
standard-state entropy (element.s298_std_state). The result is exact at
298.15 K; at other temperatures the standard-state thermal enthalpy is scaled
linearly in T, which is accurate for gaseous standard states and approximate
for solids far from 298 K. As a check, water’s ΔfH(298.15 K) - ΔfH(0 K) comes
out as -2.90 kJ/mol with the JANAF data, matching experiment.
Importing ORCA results#
Production ORCA atom-energy scans (one CSV per method, covering many basis sets and elements) are imported with:
seamm-thermochemistry-import-orca results.csv
Each value is vetted against its expected total spin (S^2) before
being added, and duplicate values already in the database are left alone
unless they conflict – see
seamm_thermochemistry.importers.import_orca_atom_results() for the
full vetting and conflict-resolution rules, including
--prefer-lower-energy for the hard-atom case where two runs converge
to different, equally spin-clean self-consistent solutions.
Active Thermochemical Tables#
seamm_thermochemistry.atct holds a local copy of one version of the Active
Thermochemical Tables (ATcT, https://atct.anl.gov), the mutually consistent
enthalpies of formation that the isodesmic (CBH) thermochemistry in SEAMM uses as
references. Each installation downloads its own copy:
seamm-thermochemistry-atct download # from atct.anl.gov
seamm-thermochemistry-atct download --from all.json # a copy saved in a browser
seamm-thermochemistry-atct list
seamm-thermochemistry-atct lookup "C/C=C/C"
The copy lives in Parameters/thermochemistry/ATcT/<version>/ and is never
modified; a newer version goes in its own directory, so earlier results stay
reproducible. In Python:
from seamm_thermochemistry import ATcT, reaction_uncertainty
tables = ATcT() # the newest cached version
entry = tables.lookup("CCF") # fluoroethane, plain gas-phase entry
entry["dfH0_298K"], entry["uncertainty_298K"], tables.version
The selection rules follow how ATcT labels its entries: gas phase with the right
charge; double-bond stereochemistry must match (cis and trans are separate
species), while a lone stereocentre is ignored (enantiomers share a value); the
plain *0 entry is used over conformer entries unless conformer= names
one; a labelled spin state is used when multiplicity= matches it; and the
ortho/para nuclear-spin entries of small species (H2, H2O, H2O2, CH2O, ketene: at most
three heavy atoms) are never used, while on bigger species “ortho” and “para” name
positional isomers (o-tolualdehyde, p-benzyne), which are. Anything still ambiguous stops
with the candidates listed; atct_id= overrides everything.
ATcT uncertainties are 95 % confidence limits at 298.15 K, and the values of
different species are correlated. tables.covariance(ids) fetches and caches
the covariance block, and reaction_uncertainty(coefficients, uncertainties,
covariance) gives the 95 % uncertainty of a reaction enthalpy. As with the
tables, a block can be saved from a browser (the response of
https://atct.anl.gov/api/v1/covariance/species/?atctids=74-84-0*0,74-98-6*0)
and cached with seamm-thermochemistry-atct covariance --from FILE; the
diagonal is checked against the listed uncertainties, which ATcT rounds up to
0.01 kJ/mol. The correlations matter: for the CBH-2 reactions of the n-alkanes
the covariance gives reference uncertainties about 40 % smaller than
quadrature. Never convert an
ATcT value between 0 K and 298.15 K yourself, and never mix TN versions in one
reaction. The index needs RDKit (pip install seamm-thermochemistry[cbh]).
Reference values ATcT lacks#
Some CBH reference species are not in ATcT, for elements such as Ge, As or Se, or for larger organic molecules. The reference library holds enthalpies of formation for them from evaluated compilations and measurements:
printed JANAF (NIST SRD 13);
CODATA key values;
the NBS tables of 1982;
spectroscopic D0 values;
W4-17;
NIST WebBook measurements (SRD 69).
Each value keeps its original citation, the compilation it came from, its uncertainty as stated, and why it was chosen.
There are two files beside the ATcT cache. references-official.db is the
published library (Zenodo, concept DOI 10.5281/zenodo.24175073), installed by the
installer; it is read, never written. references.db is your own,
for references you add.
ReferenceResolver takes each reference
from ATcT first, then from your own references (if enabled), then from the
library’s sources in a fixed order of rank, and then from computed references.
For an element ATcT lacks, it takes all the references containing that element
from one source where it can, so that the source’s errors cancel.
A library value’s uncertainty is its 95 % uncertainty plus the source’s rms offset from ATcT, and it is combined with ATcT’s in quadrature. Results that use the library are labelled “mixed” (or “mixed: several sources”) instead of “ATcT-only”.
seamm-thermochemistry-references list and show SMILES show what the
library holds. The Thermochemistry step’s “Supplementary references” parameter
chooses whether it is used.
The fragment-energy store#
Fragments recur between targets, so their energies are kept in a store,
fragments.db next to the ATcT cache, and a species is computed once per
level of theory. A job stores its species’ energies as properties on the
systems named CBH:<SMILES>; afterwards, on the host (never on a compute
node, and never with the store on GPFS or NFS), promote them:
seamm-thermochemistry-fragments harvest ~/SEAMM/Jobs/projects/x/Job_42
seamm-thermochemistry-fragments list [SMILES]
seamm-thermochemistry-fragments lookup CC --model-chemistry MOPAC:SQM@PM7
seamm-thermochemistry-fragments duplicates
seamm-thermochemistry-fragments superseded [SMILES]
The harvest is insert-or-ignore with provenance (job, configuration, geometry hash, date): the first value wins, and an attempt whose values differ by more than 0.1 kJ/mol is logged, never overwritten, which catches another conformer or SCF solution. A record is keyed by the species (canonical SMILES, charge, multiplicity) and the fingerprints of the calculations that gave the energy and the frequencies, opaque strings that the QC step writes next to its results; E, ZPE and H(298.15 K) are separate fields, since the levels can differ. A record with no fingerprint is keyed on the model chemistry and code version, flagged unverified, and used only when nothing verified exists.
The conformer is not part of the key, so a value found later to be wrong (a
fragment harvested in a higher-energy conformer, say) is replaced only on
purpose: harvest the corrected job with --supersede "REASON". The stored
values that differ are then replaced, and the old ones move to the
superseded table with the date and the reason, where superseded lists
them; the record keeps its key, so lookups find the new values. In Python,
store.supersede(record, reason) does the same for one record.
Values that differ by less than 0.1 kJ/mol count as duplicates and are not replaced.
When a correction must reach every record of a level of theory, however small (a
dispersion correction applied to all species, say), add --force to
--supersede "REASON", or force=True in Python: every value that differs at
all is replaced, with the old ones kept in superseded as before.
The store keeps E, ZPE and H unscaled, as the calculation gave them. A ZPE
scale factor is applied when the values are used (for example
seamm-thermochemistry-ladder build ... --zpe-scale 0.9863), so changing a
factor never needs a new harvest.
A per-frequency correction is different (frequency_correction: PM7’s, from
Rozanska et al., J. Chem. Eng. Data 59, 3136 (2014), eq 1, is the only one so far).
It changes each frequency, so the ZPE, H, S and Cp, and the Thermochemistry step
applies it before they are computed. The ZPE and H it stores are the corrected ones,
and the correction’s tag (fc:<id>:v<version>:<range>) is added to the
frequency fingerprint, also by the harvest when the program gave no fingerprint, so
corrected and uncorrected thermal data never share a key. A level with a correction
gets no ZPE scale factor. Each correction says which elements it was fitted for,
where it is discontinuous (warnings) and the largest raw frequency it covers:
PM7’s slope-3.99 branch is not extrapolated above 2900 cm-1.
An energy row also keeps the parts of its energy (the HF energy, the correlation
energies, the triples, and so on) when the calculation reported them, in its
byproducts. They come from an energy parts#... property of the same level,
which the Thermochemistry step writes, and composite recipes that treat the parts
separately use them. The parts are added to a stored row that has none only for the
same calculation: the same key, and an energy that agrees within 1e-10 E_h.
Otherwise the row is left as it is and the attempt is logged.
In Python:
from seamm_thermochemistry import FragmentStore
store = FragmentStore() # read-only, empty if no file
record = store.get("CC", energy_fingerprint=fp, model_chemistry=mc)
record["E"], record["ZPE"], record["H"], record["verified"]
Reads are best effort: a missing, locked or corrupt store gives None. When a
level has both a record with thermal data (ZPE, H) and one with the energy alone
(stored by a run without thermal corrections, e.g. MOPAC’s enthalpy of formation
taken as the enthalpy), get returns the one with thermal data.
Model chemistries are stored as the bare model and the program, e.g.
CMP@R2SCAN-3C and ORCA, however they were given: the ORCA sub-steps
name a level CMP@R2SCAN-3C and the Model Chemistry step
ORCA:CMP@R2SCAN-3C. Lookups accept either spelling, and still find rows
written before the names were normalized (split_model_chemistry gives the
two parts).
Every fingerprint argument of the readers takes one fingerprint or several. A
program’s settings can depend on the species, not only on the level: ORCA uses
exact exchange (NoCOSX) for atoms and for Na, Mg, Zn, B and P, so a boron
species’ energy has another fingerprint than methane’s at the same level. A
caller passes the fingerprints it expects for each species (for ORCA,
seamm_exec.expected_fingerprints predicts them):
store.get("CC", energy_fingerprint=[fp_as_written, fp_cosx_moot])
Write-back from jobs, and the harvest of jobs that come back#
The Thermochemistry step adds the species it computes to the store itself
(write-back), through harvest_configuration, the same code the harvest runs for
each system of a job, so the rows are the same either way. It does so only when the
store is on a local disk of the machine running the job: SQLite’s locking is not
reliable on network and parallel filesystems (NFS, GPFS, Lustre).
store_is_writable() makes the check; fragment-store-writable = auto | yes |
no in the [thermochemistry] section of ~/.seamm.d/seamm.ini overrides it.
A store written by newer code, with a higher schema version (PRAGMA
user_version) than this seamm-thermochemistry knows, is never written, whatever
the setting: older code would not maintain what the newer schema adds. Opening it
for writing raises NewerSchemaError, store_is_writable() says why, and the
hook leaves the job’s marker for a JobServer with newer code. Such a store is still
read, with a warning, as the older schema.
When the step cannot write the store, it leaves harvest_fragments.json in the
job’s directory. A JobServer runs the plug-ins’ job_finished hooks when a job
ends and its files are back on the JobServer’s host; this package’s hook harvests
a job carrying that marker into the store there, once (the marker becomes
harvest_fragments.done.json, with the tallies). A job run without a JobServer
is harvested by hand, as before.
Results are checked before they go in, by write-back and by the harvest:
The structure. The bonds are perceived again from the coordinates, and must be those of the species in the key (its SMILES), whose charge and radicals must fit the structure’s charge and multiplicity; and no atoms may be too close together (
molsystem.vsepr.check_contacts, which also catches the ligands of a hypervalent centre on top of each other). A species that rearranged while it was optimized is refused.harvest --no-structure-checkturns this off.Imaginary modes (write-back): a geometry with a mode beyond 20i is refused, with every energy on it. The harvest stores such a geometry, for its provenance, but lookups never return it.
Conformers (write-back): a geometry lower in E + ZPE than every stored one of the species at its level, by more than 0.1 kJ/mol, and structurally distinct from each (RMSD above 0.05 Å after the best, symmetry-aware alignment), is added as the conformer
auto:<geometry hash>; lookups take the lowest. The same minimum computed again is only logged.
The official and local stores#
The store has two layers, two files beside the ATcT cache:
fragments.dbThe local store: everything this installation computes or harvests. It is the only file that write-back,
harvest,merge,migrateand supersede write.fragments-official.dbThe official store, published by SEAMM and replaced whole when a new version is installed. It is only read, without locking, so it may sit on a network filesystem. Its
metatable gives its version.
LayeredStore reads them as one, the local store first:
the same key in both: the local row is used, unless the official store superseded exactly that value, when the official row is used; values that differ by more than 0.1 kJ/mol are noted;
conformers come from both, and the lowest wins, a tie within 0.1 kJ/mol going to the local store; verified rows come before unverified ones in either;
an energy pairs with a geometry only on the same geometry hash, looked up in the geometry’s store first, then the other, so a local single point on an official geometry is used. Every row says which store it came from.
The command line has the tools to keep the stores in step:
seamm-thermochemistry-fragments migrate # an older store up to date
seamm-thermochemistry-fragments merge OTHER.db ... # add another copy's rows
seamm-thermochemistry-fragments export --out MINE.db [--label TEXT]
seamm-thermochemistry-fragments duplicates --layers
seamm-thermochemistry-fragments official build --version V --out NEW.db \
[--previous OLD.db] CONTRIBUTION.db ...
migrate keeps a dated copy first, adds the meta table and stores the model
chemistries bare with their program; keys do not change, and running it again does
nothing. merge is insert-or-ignore: differing values are logged, and superseded
values come along as history. export writes the local rows the official store
lacks, or has with other values, to a contribution for the next official version;
nothing about the host or user is added beyond the label. official build (for
maintainers) stops at the first contributed value that differs from one already
there, so that it is resolved with supersede and a reason; it writes the file’s
SHA-256 beside it.
official build also keeps only the rows reachable at the levels given with
--frequency-fingerprint and --energy-fingerprint (repeat each for several),
and checks every species state before writing anything:
no geometry with an imaginary mode beyond 20i (a saddle point);
the structure guard (bonds perceived again, charge, the parity of the spin, no atoms too close together);
the ground-state spin, where it is known: singlet for the silylenes, dihalocarbenes and BH of
cbh.SINGLET_GROUND_STATES, whose SMILES would make them triplets; triplet for O2, S2, SO, OCCO and cyclic C3 (cbh.TRIPLET_GROUND_STATES), which a SMILES writes closed-shell; and from ATcT when it lists a species in labelled spin states (CH2 and NH are triplets, SiH2 a singlet).
A species state that fails stops the build, unless it is excluded with a reason in
the --exclude file (columns species, charge, multiplicity, reason, and optionally
conformer, to leave out only that conformer). Rows quarantined by hand in a store
(unverified, with the model chemistry UNUSABLE: <reason>) are never found by a
lookup; migrate leaves them as they are, export skips them, and official
build drops them and lists them in its report. Nothing replaces a quarantined row
automatically: a harvest, write-back or merge that brings a row with the same key keeps
the quarantined one, logs the attempt in the history (kind quarantined) and reports
it. Releasing a quarantine is a person’s decision. release-candidates [SMILES]
lists the values kept out that passed every check of the harvest (the species, the
quarantined and new values, the job), and release ID ... --reason TEXT replaces the
quarantined rows with them; harvest --supersede <reason> (or the store’s
supersede methods) also releases. The quarantined values are kept as superseded,
with the reason. Quarantined rows are
not counted as conformers. Ions and open-shell species are checked like the rest. The
build writes <file>.report.json beside the file: the sources, the levels, the rows
kept and left out, each exclusion with its reason, and the SHA-256. Since an official
store is published, the build keeps only each job’s id in the provenance, not its
directory (--keep-job-paths keeps them); name the source files without private
paths too, as the report lists them as given. --official
FILE names an official store other than the default; lookup and geometries
read both.
Every harvest and every job’s write-back records what it did with each row – added,
a duplicate, logged, superseded, or refused and why – in the store’s
writeback_log table:
seamm-thermochemistry-fragments writeback-log --job 5700
The log is written by the harvest and by write-back (both go through
harvest_configuration); direct calls to put, put_geometry or
put_energy from a script of your own are not logged. superseded SPECIES
shows, for a species, every superseded value – of its fragment records and of its
geometry and energy rows – with the old and new values, the reason and the date.
Geometries and energies at different levels#
Thermochemistry often takes the energy from a costly level of theory (for example revDSD-PBEP86-D4 or CCSD(T)-F12) on the geometry and frequencies of a cheaper one (for example r2SCAN-3c), and one geometry serves several energy levels. The store keeps these in two more tables, beside the records above:
geometry: one row per conformer of a species at a geometry/frequency level, keyed by the species, charge, multiplicity, the frequency fingerprint and a conformer label. It holds the coordinates and their hash, the energy, the unscaled ZPE and H(298.15 K) at that level, and, when the job stored them, the harmonic frequencies, the number of imaginary modes, the rotational symmetry number and the moments of inertia.energy: one row per single point on a geometry, keyed by the geometry’s hash and the calculation’s fingerprint. The hash is the one QC steps record for a calculation (seamm_util.fingerprint.geometry_fingerprint), so copies of the store on other hosts keep working.
A combined value is never stored, only its parts: the energy at one level and the ZPE and thermal correction of the geometry’s level are combined when they are used, as ZPE factors are applied at use.
harvest fills both tables from the same properties as the records: an energy
with a ZPE or enthalpy of the same level makes a geometry row, and every energy
makes an energy row on the configuration’s geometry. It guards the pairing:
an energy whose calculation record names a different geometry is refused and reported;
a geometry row has its geometry and frequencies at one level: a row whose optimization was at another model chemistry is refused;
a geometry with an imaginary mode beyond 20i cm⁻¹ (a saddle point) is refused, with every energy on it, as in a write-back.
Jobs whose systems are not named CBH:<SMILES> (for example by an ATcT id, with
several conformers of a species) are harvested with a species map, a CSV file with the
columns job, system name and species (the store key, with the stereo of the
structure), and optionally configuration name, charge, multiplicity and
conformer label:
seamm-thermochemistry-fragments harvest --species-map map.csv --tables geometry JOB ...
--tables geometry fills only the geometry and energy tables, which can hold several
conformers of a species; the records cannot. Systems the map does not list are skipped
and reported.
For jobs that stored only the energies, the map can also give each structure’s thermal
corrections, in the columns E (kJ/mol), ZPE (kJ/mol) (unscaled), H298
(kJ/mol) (H at 298.15 K) and symmetry number. They make the geometry row, with
H - E added to the job’s energy, provided the map’s E agrees with the job’s within
0.1 kJ/mol; otherwise the structure is reported and gets no geometry row.
Duplicates and --supersede work as for the records, with the old values in a
row_history table. To see what the store holds for a species:
seamm-thermochemistry-fragments geometries CCO --model-chemistry ORCA:DFT@R2SCAN-3C
In Python:
rows = store.species_at(
"CCO",
frequency_fingerprint=freq_fp, # or frequency_model_chemistry=...
energy_fingerprint=energy_fp, # or energy_model_chemistry=...
)
rows[0]["E"], rows[0]["ZPE"], rows[0]["H - E"], rows[0]["geometry"]["conformer"]
The ladder (below) uses these tables first, and falls back on the records.
ZPE scale factors#
Harmonic zero-point energies are too large; scaled by a factor fitted for the level of
theory of the frequencies they come close to the anharmonic ones. The factors, with their
sources, are in seamm_thermochemistry.zpe, looked up from the geometry and frequency
level’s model chemistry:
from seamm_thermochemistry import zpe_scale_factor
f = zpe_scale_factor("ORCA:CMP@R2SCAN-3C")
f.factor, f.source, f.flag # 0.9899, the fit, "fitted on molecules of up to 6 atoms..."
Level |
Factor |
Source and caution |
|---|---|---|
r2SCAN-3c |
0.9899 |
fitted to 22 W4-2006 anharmonic ZPVEs; molecules of up to 6 atoms, so an extrapolation for larger ones |
PBE0(-D4)/def2-TZVP |
0.975 |
Truhlar database v5, PBE0/MG3S: basis-mismatched |
B2PLYP(-D3)/cc-pVTZ |
0.9863 |
the CBH-ANL protocol |
A dispersion correction in the method’s name is ignored in the lookup; a level that is not in the table has no factor, and the Thermochemistry step then warns and uses 1. The stored ZPEs stay unscaled.
Laddered reference values (CBH-ANL)#
ATcT values for every fragment are not self-consistent with one another at the 0.5 kJ/mol level, and CBH results referenced to them drift with molecular size (the n-alkanes, above). CBH-ANL (Elliott et al. 2023) instead takes ATcT values only for the CBH-0 species (H2, CH4, H2O, NH3, HF, … and the radical CBH-0 species) and “ladders” every other reference species from its own CBH reaction one rung below its size, computed at a high level of theory:
seamm-thermochemistry-ladder build anl-f12 CC CCC CCCC \
--energy "ORCA:QC@CCSD(T)-F12/bse:cc-pVTZ-F12" \
--frequencies "ORCA:DFT@B2PLYP-D3/bse:cc-pVTZ" --zpe-scale 0.9863
seamm-thermochemistry-ladder show anl-f12
The energies and frequencies come from the fragment store (harvest the jobs
first); the levels are settings fingerprints or model chemistry strings. The
ladder is saved as a named reference set in ladders/ next to the store,
with every value’s ATcT coefficients (so a reaction’s ATcT uncertainty is
cᵀΣc exactly), its provenance, and, for every ladder species that ATcT has,
the difference from ATcT: their RMS is the measured method term, an upper
bound since it includes ATcT’s own inconsistencies. Work at 0 K: ATcT’s 0 K
values refer to the lowest conformer, while its 298.15 K values are
conformer averages. In Python Ladder.load(name) and
ladder.entry(smiles) give the value in the layout of an ATcT entry.
Connectivity-based hierarchy (CBH) reactions#
seamm_thermochemistry.cbh builds the error-cancelling reactions of
Ramabhadran and Raghavachari’s connectivity-based hierarchy from a SMILES:
from seamm_thermochemistry import cbh
reactions = cbh.cbh_reactions("CSCCC(N)C(=O)O", rungs=[1, 2, 3])
for rung, reaction in reactions.items():
print(reaction) # CBH-2: ... -> ...
reaction.coefficients # {canonical SMILES: coefficient}
reaction.references # the species other than the target
reaction.balanced, reaction.trivial
cbh.lowest_conformer(smiles, n=20) gives the lowest MMFF94 conformer of
n RDKit embeddings (symbols, coordinates, energies), the right start for a
species whose lowest rotamer is wanted: a single embedding of a long chain is
often gauche.
Products have positive coefficients, reactants negative and the target -1.
Every fragment keeps the bond orders, charges, unpaired electrons and
stereochemistry it has in the parent, and every cut bond is replaced by
hydrogens. By default aromatic ring systems, three- and four-membered rings and
charge-separated or hypervalent groups are kept whole (protect="default";
protect="none" gives the plain Kekulé hierarchy, and a sequence of
"aromatic", "small rings", "groups", "all rings" or SMARTS
patterns chooses). A hypervalent centre (S, Se or Te with more than two bonds, P
or As with more than three, Cl, Br or I with more than one: sulfonyl, sulfite,
phosphoryl, SF5-R, ClF3, or a halogen cation such as the
[Cl+3] of FClO3) is kept together with its heavy neighbours, so that
CBH-0 gives real molecules (dimethyl sulfate → sulfuric acid and methane)
instead of hydrides such as H2SO2 or SH6; a
molecule that is one such group (SF6, dimethyl sulfone) is trivial at
every rung. A neighbour in a protected ring stays with its ring, but is added,
capped like a methyl, to every fragment that holds the centre and not the ring:
methyl phenyl sulfone gives CH4 + PhSO2Me → C6H6
+ Me2SO2 at CBH-0 (the methane removes the doubly counted
carbon); from CBH-1 up these atoms cancel by themselves. So is every pair of bonded atoms with opposite
formal charges (CO written [C-]#[O+], N-oxides, the bridges of
Al2Cl6). RDKit’s valence check rejects hypervalent
halogens (FCl(F)F); SMILES are read with seamm_thermochemistry.smiles.
mol_from_smiles, which skips that check for S, Se, Te, P, As, Cl, Br and I only;
the ATcT index and its lookups read them the same way, so ClF3, BrO2
or O=[S-](=O)=O are found like any other species.
cbh.ground_state_multiplicity(smiles) gives the spin multiplicity of a
species: its unpaired electrons + 1, except the ground-state singlets that a
SMILES writes with two unpaired electrons (SiH2, SiCl2,
SiF2, GeH2, CF2, CCl2, HCF, HCCl, BH, AlH,
BF, BCl; CH2 and NH stay triplets) and the triplets it writes
closed-shell (O2, S2, SO, OCCO, cyclic C3). A rung that reproduces the target is trivial; a rung
the formula cannot build raises RungUnavailable. cbh.unique_fragments
gives the union of the reference species over several reactions, so that a
batch of targets computes each fragment once.