tm-spec

TM-Spec ↔ Existing Standards Alignment

Date: 2026-05-09. Source: web research via WebSearch + WebFetch (see Sources section at the end). Goal — align field names, enum values, and required/optional status of TM-Spec v0.2 with mature domain standards (2025-2026) so that downstream NOMAD upload / OPTIMADE query / QCSchema interop work without ad-hoc mapping.

Notation:


1. NOMAD Metainfo (computational data schema)

Imports

Naming (key fields)

Enums

TM-Spec mismatch

| TM-Spec field | NOMAD recommends | Decision | |—|—|—| | level.xc: PBE+D3(BJ) | split into: xc_functional: ["GGA_X_PBE", "GGA_C_PBE"] + vdw_method: D3-BJ | adopt hybrid: keep xc: PBE+D3(BJ) for human-readable, add xc_libxc: [GGA_X_PBE, GGA_C_PBE] + vdw: D3-BJ for machine mapping | | level.smearing.kind: Marzari-Vanderbilt | marzari-vanderbilt (lowercase, hyphen) | adopt lowercase enum | | level.smearing.width_Ry | width in Joule | keep eV/Ry for human; add width_J when exporting to NOMAD | | level.basis.kind: PW | plane_waves | adopt plane_waves as primary, PW as alias | | code.name: QuantumESPRESSO | Run.program.name | adopt field path, value match | | hubbard.Fe-3d.formulation: Dudarev | Method.dft.dft_plus_u.formulation: Dudarev | adopt capitalisation (Dudarev/Liechtenstein) |


2. OPTIMADE (structures endpoint)

Imports

Naming (key fields, structures entry)

Enums

TM-Spec mismatch

| TM-Spec field | OPTIMADE | Decision | |—|—|—| | structure.formula: Fe16S16 | chemical_formula_descriptive: "Fe16S16" + chemical_formula_reduced: "FeS" + chemical_formula_anonymous: "AB" | adopt — add three formula fields on export | | structure.cell.a / .c / .gamma | lattice_vectors: [[a,0,0],[0,a,0],...] Cartesian Å | keep human-readable a/b/c/α/β/γ; add computed lattice_vectors | | structure.pbc: [true,true,true] | dimension_types: [1,1,1] + nperiodic_dimensions: 3 | adopt both forms (boolean primary, ints for OPTIMADE export) | | structure.wyckoff: {Fe@2a: [0,0,0]} | cartesian_site_positions + species_at_sites (no explicit Wyckoff) | keep Wyckoff for human; expand into species/positions on export | | kind: NEBCalculation | OPTIMADE has only structures/references/files/calculations/trajectories (draft) | note: TM-Spec NEB is not covered by OPTIMADE 1.3; requires trajectories extension v1.4+ |


3. QCSchema (MolSSI Quantum Chemistry Schema)

Imports

Naming (key fields)

Enums

TM-Spec mismatch

| TM-Spec field | QCSchema | Decision | |—|—|—| | level.xc: PBE+D3(BJ) | model.method: "PBE-D3BJ" (single string) | note: QCSchema is not strict about vdW; multiple encodings exist (PBE-D3, PBE+D3BJ). Adopt model.method as human string; separate model.dispersion: D3BJ in extras | | level.basis: { kind: PW, cutoff_Ry: 80 } | model.basis: "PW" (string) — no PW deep specs | mismatch: QCSchema is biased toward Gaussian basis sets. Keep TM-Spec rich basis block; on export → model.basis: "PW-80Ry" string | | structure.cell (Å) | Molecule.geometry in Bohr | note: unit conversion required on export (1 Å = 1.8897 a0) | | kind: NEBCalculation | no equivalent — QCSchema has only OptimizationResult / TorsionDriveResult | mismatch: TM-Spec NEB requires a custom QCSchema-like extension | | results.Ea_forward_eV | properties.return_energy in Hartree | note: unit conversion (1 eV = 0.0367 Ha) |


4. magCIF (IUCr magnetic CIF dictionary)

Imports

Naming (key fields)

Enums

TM-Spec mismatch

| TM-Spec field | magCIF | Decision | |—|—|—| | magnetic.state: AFM-G | no such enum. Described via BNS group + magmoms | keep TM-Spec abbreviation (AFM-G/A/C, FM, ferri, NM) — convenient shortcut. ADD optional magnetic.bns_group: "..." for magCIF export | | magnetic.collinear: true | implicit — moment vectors have only 1 non-zero component | keep boolean; verify collinearity on export | | magnetic.propagation_vector: [0,0,0] | _parent_propagation_vector.kxkykz: "0 0 0" | adopt — our format is already close | | magnetic.magmoms_uB.Fe[top]: +3.5 | _atom_site_moment.crystalaxis_z: 3.5 (per-atom) | expand on export: one moment entry per Fe in the asymmetric unit, with label | | magnetic.surrogate_warning | no equivalent in magCIF | keep — this is our original semantics for the PBE PM/itinerant proxy |


5. AFLOW Prototype Encyclopedia

Imports

Naming (label format)

Format: <stoichiometry>_<Pearson>_<SGnum>_<Wyckoff_per_element>[-<index>]

Components:

  1. Stoichiometry — A, AB, AB2, A2B3, ABC2… (alphabetical, subscripts inline).
  2. Pearson symbol — letter (a/m/o/t/h/c) + (P/I/F/R/A/B/C centering) + atom count.
  3. Space group number — IT 1-230.
  4. Wyckoff letters per element — alphabetical, separated by _.
  5. -NNN suffix — index if multiple structures share the same label.

Examples decoded (verified):

Enums

TM-Spec mismatch

| TM-Spec field | AFLOW | Decision | |—|—|—| | structure.prototype: AB_tP4_129_a_c | format match | adopt fully — our draft is already correct | | structure.space_group: { number: 129, symbol: P4/nmm } | redundant with prototype | keep SG for human readability, prototype for machine matching | | Wyckoff Fe@2a: [0,0,0] | AFLOW does not include coordinates in the label, only letters | keep our expanded Wyckoff format (coordinates + letter) |


6. AiiDA provenance graph schema

Imports

Naming (Node fields)

Enums (LinkType)

[FACT] AiiDA aiida.common.links.LinkType:

TM-Spec mismatch

| TM-Spec field | AiiDA | Decision | |—|—|—| | provenance.parents: [tm.mack.vfe.hint.smoke@2026-05-03] | edges via INPUT_CALC/INPUT_WORK + uuid links | keep human-readable parent IDs (our deliberate design choice); export mapping parent_id → uuid via aiida lookup | | provenance.author: igor@exopoiesis.space | Node.user.email | adopt field path | | provenance.compute.cost_usd / walltime_h | no native fields — stored in attributes or extras | keep our fields; export → extras.tm_compute | | provenance.hash.inputs/outputs sha256 | AiiDA hashes inputs automatically in attributes._aiida_hash | additionally adopt on export | | id: tm.<system>.<setup>.<method>.<date> | Node.label (string) + UUID | keep — id → label, UUID generated on export | | TM-Spec links by human-readable parent IDs | LinkType enum | adopt enum on serialization: kind: NEBCalculation parent type → INPUT_WORK or CALL_CALC |


7. Antimony 3 (textual SBML for reactions)

Imports

Naming (syntax)

Enums

TM-Spec mismatch

| TM-Spec field | Antimony | Decision | |—|—|—| | reactions[].rule: "H_aq^+ + Fe_Fe^× → (H–Fe)_Fe^×" | R1: H_aq + Fe_Fe -> H_Fe; k1*H_aq*Fe_free (no Unicode arrows, no Kröger-Vink superscripts) | mismatch: Antimony — ASCII identifiers only. Hybrid: keep human-readable Unicode + Kröger-Vink in TM-Spec; on export → ASCII aliases (e.g. H_aq → H_aq, (H-Fe)_Fe^× → H_Fe_x) | | reactions[].rate: "k1 * [H+] * θ_Fe_free" | k1*H_aq*theta_Fe_free | adopt rate-law string; mapping [X] → X, θ → theta_ | | reactions[].params.k1: { value: 1e-4, units: M^-1·s^-1 } | k1 = 1e-4; (units in comment) | keep our rich format; on export → comment // units: M^-1 s^-1 | | reactions[].id: R1 | R1: reaction label | adopt | | reactions[].Ea_eV: 0.043 | absent — Antimony rate-law does not expect activation energy | keep for scientific value; derive k via Arrhenius on compilation |


8. PHREEQC v3 (aqueous geochemistry)

Imports

Naming (SOLUTION block identifiers)

Enums

TM-Spec mismatch

| TM-Spec field | PHREEQC | Decision | |—|—|—| | environment.composition_molal: { Fe(2): 1e-3, S(-2): 5e-4 } | Fe(2) 1.0e-3 mol/kgw | adopt PHREEQC element(valence) notation verbatim — our format is already close | | environment.T: 363.15 K | temp 90 (°C) | mismatch: PHREEQC uses °C. Decision: keep K as primary, add computed temp_C on export | | environment.pH: 6.0 | match | adopt | | environment.redox.Eh: -0.40 V_SHE | pe (dimensionless) — no direct Eh | note: convert Eh→pe = Eh/(0.05916·T_factor). Keep Eh; auto-derive pe. | | environment.database: phreeqc/llnl.dat | DATABASE phreeqc.dat keyword | adopt path → DATABASE keyword | | environment.saturation_targets: {mackinawite: equilibrium} | EQUILIBRIUM_PHASES block | keep our short dict; expand into EQUILIBRIUM_PHASES on export |


9. Materials Project — emmet-core (TaskDoc / MaterialsDoc)

Imports

Naming (TaskDoc top-level fields)

Enums

TM-Spec mismatch

| TM-Spec field | emmet-core | Decision | |—|—|—| | results.Ea_forward_eV: { value: 0.043, ci95: [...] } | no native CI — output.energy is a plain float | keep our rich format; on export → output.energy: 0.043 + extras.ci95: [...] | | results.status: PASS / PRELIMINARY / FAIL / RETRACTED | state: successful/unsuccessful/error | partial mapping: PASS→successful, FAIL→unsuccessful, RETRACTED→error, PRELIMINARY→no equivalent. Keep our enum. | | results.paper_quotable: bool | no equivalent | keep — our original semantics | | results.validated_by: [chemist@opus, physicist@opus] | no equivalent | keep — our original semantics (optionally → extras.validators) | | calculation.code.name: QuantumESPRESSO | builder_meta.pymatgen_version + parser-implicit | mismatch: emmet/atomate2 is VASP-only. Note: TM-Spec extension to non-VASP codes adds code.* on top of the emmet schema. | | task_type: NEB | match for NEB | adopt when mapping kind: NEBCalculation → task_type: NEB |


10. pymatgen-analysis-defects + doped (defect schemas)

Imports

Naming (key fields)

Enums

TM-Spec mismatch

| TM-Spec field | pymatgen/doped | Decision | |—|—|—| | defects.reactions[]: "Fe_Fe^× → V_Fe'' + Fe(removed)" | Kröger-Vink not native. Defect represented as Vacancy(structure=..., site=...) object | keep Kröger-Vink (more scientific) + add parsed defects.objects[].name: "v_Fe" for machine handling | | defects.population.V_Fe: { count: 1, conc: 1/144 } | Defect has no concentration field — that lives in DefectEntry context | keep; export → DefectEntry list per supercell | | H_i^• notation (charged interstitial) | doped: H_i + separate charge_state: +1 | adopt: separate notation into name: H_i + charge: +1 on export | | defects.population.H_int.site: tetrahedral_cavity | doped: wyckoff label or conv_cell_frac_coords | keep human description; add wyckoff label on export |


11. CHGNet and MACE foundation MLIP (config schema)

MACE-MP-0 variants

CHGNet variants

TM-Spec recommendation

TM-Spec extension for kind: MLIPBenchmark (v0.2):

calculation:
  method: MLIP
  level:
    backend: MACE                       # MACE | CHGNet | M3GNet | NequIP | ...
    model: mace-mp-0
    variant: medium-mpa-0               # see foundation_models.py
    version: 0.3.13                     # mace package version
    device: cuda
    fine_tuned: false
    fine_tune_dataset: null             # if fine_tuned=true: ref to dataset

Summary of recommendations

TM-Spec field Current draft Standard recommends Source Decision
calculation.level.xc PBE+D3(BJ) xc_libxc: [GGA_X_PBE, GGA_C_PBE] + vdw: D3-BJ NOMAD/LibXC hybrid: keep human + add LibXC alias
calculation.level.smearing.kind Marzari-Vanderbilt marzari-vanderbilt lowercase NOMAD adopt lowercase enum
calculation.level.basis.kind PW plane_waves NOMAD adopt primary plane_waves, alias PW
calculation.code.name QuantumESPRESSO match (NOMAD Run.program.name) NOMAD adopt field path, no value change
calculation.hubbard.formulation Dudarev Dudarev capitalised NOMAD adopt as-is
structure.formula Fe16S16 chemical_formula_descriptive + _reduced + _anonymous OPTIMADE adopt: add three formula fields on export
structure.cell.{a,c,gamma} human a/b/c/α/β/γ lattice_vectors: [[ax,ay,az],...] Å OPTIMADE keep human, add computed lattice_vectors
structure.pbc [true,true,true] dimension_types: [1,1,1] OPTIMADE keep boolean primary, add ints for export
structure.prototype AB_tP4_129_a_c match AFLOW adopt verbatim
defects.reactions[] Kröger-Vink string Vacancy(name="v_Fe") + charge_state: -2 pymatgen-defects + doped keep Kröger-Vink + add machine defects.objects[]
defects.population[].site tetrahedral_cavity wyckoff label doped adopt — add wyckoff
magnetic.state AFM-G shortcut BNS magnetic space group symbol magCIF keep shortcut + add opt bns_group
magnetic.magmoms_uB Fe[top]: +3.5 _atom_site_moment.crystalaxis_z: 3.5 per atom magCIF keep dict; expand on export
environment.composition_molal Fe(2): 1.0e-3 match (PHREEQC element-valence + mol/kgw default) PHREEQC adopt verbatim — our format is already correct
environment.T 363.15 K temp 90 °C PHREEQC keep K, computed temp_C on export
environment.redox.Eh -0.40 V_SHE pe dimensionless PHREEQC keep Eh, auto-derive pe
reactions[].rule Unicode arrows + Kröger-Vink ASCII identifiers H_Fe + ... Antimony keep Unicode primary + add ASCII alias on export
reactions[].rate k1 * [H+] * θ_Fe_free k1*H_aq*theta_Fe_free Antimony adopt ASCII on export, [X]→X, θ→theta_
workflow.kind: NEB match task_type: NEB atomate2/emmet adopt mapping to task_type on export
workflow.endpoints {A,B} extxyz refs atomate2 NEB Maker — images list atomate2 keep {A,B,images}; map on export
results.status PASS/PRELIMINARY/FAIL/RETRACTED successful/unsuccessful/error emmet keep our richer enum, partial mapping on export
results.paper_quotable bool no equivalent — keep — original TM-Spec semantics
provenance.parents[] human IDs UUIDs + LinkType edges AiiDA keep human IDs, lookup map on export
provenance.compute.cost_usd float extras.tm_compute AiiDA keep primary, AiiDA extras on export

Actions for TM-Spec v0.2

  1. Aliases for NOMAD interop — add optional fields xc_libxc[], vdw, temp_C, pe_derived, lattice_vectors_A. Primary fields remain human-readable.
  2. magnetic.bns_group — optional field for magCIF export.
  3. Lowercase smearing enum — rename Marzari-Vanderbilt → marzari-vanderbilt in draft (breaking change, before schema publication).
  4. basis.kind — plane_waves primary, PW alias.
  5. Defect machine layer — add defects.objects[].name (auto-generated: v_Fe, H_i) + charge_state separate from ^•/'' notation.
  6. Antimony export tooling — tm-spec → antimony function in tools/tm_spec_export.py with auto-aliasing Unicode → ASCII identifiers.
  7. task_type mapping table — NEBCalculation → "NEB", USCalculation → "Umbrella Sampling" (TM-Spec extension to emmet enum).
  8. MLIP backend schema (v0.2 kind MLIPBenchmark) — backend, model, variant, version, fine_tuned. Use MACE/CHGNet variant names.

12. TM-Spec v0.3 additions (geometry_origin, preflight)

Added 2026-06-01 for the v0.3 additive bump. Both additions were checked against the standards already surveyed above; neither imports a single scalar field, so both export rather than import.

(a) endpoint.geometry_origin

There is no single scalar field in the surveyed standards that records “how this geometry was obtained” as a (method × relaxation) shortcut. The closest constructs are combinations or structural conventions, so geometry_origin is a human shortcut (in the spirit of magnetic.state) with an export alias onto emmet / NOMAD.

TM-Spec value emmet run_type × task_type NOMAD / QCSchema Decision
dft_relaxed "<XC> Structure Optimization" (CalcType = f"{run_type} {task_type}") [FACT] electronic_structure_method = DFT [CLAIM] export alias to emmet CalcType
dft_static "<XC> Static" [FACT] electronic_structure_method = DFT [CLAIM] export alias to emmet CalcType
mlip_relaxed emmet is VASP/DFT-only — no MLIP task_type [FACT] NOMAD electronic_structure_method enum includes ML [CLAIM] export to NOMAD method=ML; no emmet target
experimental / as_built / unknown no equivalent no equivalent keep — original TM-Spec semantics

Notes:

Decision: keep a human-shortcut enum geometry_origin; provide an export alias onto emmet run_type × task_type and NOMAD electronic_structure_method. Energy comparisons across endpoints are valid only for dft_relaxed.

Update 2026-06-02 (additive, still 0.3): geometry_origin is now also available on structure ($defs.structure.properties.geometry_origin, same enum). Rationale: a NEB doc has one geometry per endpoint (endpoint-level is preferred there), but a single-structure doc — SinglePointCalculation / RelaxCalculation, e.g. a NOMAD import — has no endpoint block, so its origin belongs on structure.geometry_origin. The NOMAD importer now writes structure.geometry_origin directly (previously it could only record the origin in the G09_geometry_origin sanity gate, a workaround). The G09 gate is still emitted because it carries the gate-vocabulary verdict the prodromos planner reads. Same enum, same G09_geometry_origin gate, no version bump.

(b) preflight

preflight is a predictive pre-flight assessment produced BEFORE the expensive calculation. No surveyed standard has an equivalent: they are all retrospective or descriptive.

Standard What it offers Why it does not cover preflight
W3C PROV-O provenance of things that happened retrospective by design; a plan for a future run is out of scope [FACT]
P-Plan (PROV extension) models a workflow template (steps, variables) describes a plan’s structure, not a probabilistic GO / NO-GO verdict [CLAIM]
RO-Crate packages inputs/outputs/metadata packs results, does not predict them [FACT]
emmet / NOMAD / QCSchema / AiiDA post-hoc status (state, success, exit_status, process_state) only report what already ran; no pre-run probability or strategy tree [FACT]

Notes:

Decision: keep preflight original; align only engine onto QCSchema provenance; treat the shared gate-ID registry as a TM-Spec contribution.


Sources

NOMAD Metainfo

OPTIMADE

QCSchema (MolSSI)

W3C PROV-O / P-Plan (provenance, retrospective scope)

emmet calc-type enums

magCIF

AFLOW Prototype Encyclopedia

AiiDA

Antimony 3 / Tellurium

PHREEQC v3

Materials Project / emmet / atomate2 / pymatgen-defects / doped

MACE and CHGNet