Energy Analysis with Tako Script
On this page
- Extract energy with the exact contract
- Extract final structure cautiously
- Build a comparable series
- Use reactionEnergy as arithmetic only
- Extract a reaction barrier with reactionBarrier
- Calculate binding and adsorption energies
- Combine matching harmonic ZPE
- Calculate a model-energy voltage
- Use lowerHull with prepared formation energies
- Do not call parser-only pseudo APIs
- Preserve quantity and correction provenance
- Distinguish workflow ranking from public helpers
Tako Script provides small extraction and arithmetic helpers, not a thermochemistry engine. Public analysis functions are energyEv, finalStructure, reactionEnergy, reactionBarrier, and lowerHull. There is no public maxForceNorm, selectMinimum, result.selectStructure, voltage helper, adsorption-energy helper, or automatic function. Theory and correction layers are defined in Comparable Energies and Thermodynamic Cycles.
Extract energy with the exact contract
const energyEv = tako.analysis.energyEv(result);
The helper requires an object. It rejects explicit error/failure payloads, ok: false, success: false, status error/failed, and explicit top-level converged: false. Missing converged is accepted.
It selects the first finite supported value in this order:
energy_ev,energyEv,final_energy_ev,finalEnergyEv;energy_hartree,energyHartree,final_energy_hartree,finalEnergyHartree, converted with 27.211386245988 eV/Eh;- nested
energy.ev; - recursively, the last item in
frames.
It does not accept a generic numeric energy, nested Hartree, numeric strings, or nested vibration ZPE. A malformed preferred field is skipped. A valid top-level energy wins even if a later frame is invalid, so validate operation-specific invariants before calling.
function requireConvergedOptimization(result) {
if (result.kind !== "optimization" || result.converged !== true) {
throw new Error("A converged optimization result is required");
}
return tako.analysis.energyEv(result);
}
For MD, the helper can return final_energy_ev; treat it as an endpoint potential energy, not a comparison-ready thermodynamic value.
Extract final structure cautiously
const final = tako.analysis.finalStructure(input, result);
The helper first accepts a complete final_structure, finalStructure, or structure. Otherwise it merges the last frame’s atoms positionally onto the input and replaces the cell when present. Otherwise it silently returns the original input.
It does not guard errors/convergence, validate atom identity/count, or validate finite coordinates. It ignores native top-level atoms/cell unless a last frame is usable. A short frame truncates atoms; a long one can invent fallback X atoms. Validate explicitly:
if (result.converged !== true) throw new Error("Optimization did not converge");
const final = tako.analysis.finalStructure(input, result);
if (final.atoms.length !== input.atoms.length) throw new Error("Atom count changed");
for (let i = 0; i < input.atoms.length; i += 1) {
if (final.atoms[i].element !== input.atoms[i].element) {
throw new Error(`Atom identity changed at index ${i}`);
}
}
Build a comparable series
const rows = [];
for (const path of candidatePaths) {
const structure = await tako.input(path);
const result = await tako.singlePoint(structure, {
calculator,
properties: ["energy", "forces"],
});
rows.push({ path, energyEv: tako.analysis.energyEv(result) });
}
const referenceEv = Math.min(...rows.map((row) => row.energyEv));
const relative = rows
.map((row) => ({ ...row, relativeEnergyEv: row.energyEv - referenceEv }))
.sort((a, b) => a.energyEv - b.energyEv);
await tako.output("output/relative-energies.json", relative);
This is valid only when composition, charge/spin, method asset/settings, environment, and geometry policy match. Encode those invariants in the report, not only in comments.
Use reactionEnergy as arithmetic only
const deltaEv = tako.analysis.reactionEnergy({
reactants: [energyA, energyB],
products: [energyC],
});
The implementation is simply sum(products) minus sum(reactants). It performs no finite-number, unit, coefficient, species, balance, convergence, or provenance check. Empty lists yield zero; NaN and Infinity propagate.
Represent coefficients explicitly and validate first:
function finiteEnergy(value, label) {
if (!Number.isFinite(value)) throw new Error(`${label} is not finite`);
return value;
}
const deltaEv = tako.analysis.reactionEnergy({
reactants: [2 * finiteEnergy(eH2, "H2"), finiteEnergy(eO2, "O2")],
products: [2 * finiteEnergy(eH2O, "H2O")],
});
The helper cannot verify that is balanced. Preserve a machine-readable stoichiometry table.
Extract a reaction barrier with reactionBarrier
tako.analysis.reactionBarrier(result, options?) is the convergence-guarded accessor for a tako.reactionPath result. It requires the neb and reaction_barrier records to exist (otherwise it throws “Value is not a tako.reactionPath result”), rejects embedded error payloads, and by default refuses an unconverged band: when neb.converged is not true it throws unless you pass { allowUnconverged: true } explicitly.
const path = await tako.reactionPath(initialStructure, settings);
const barrier = tako.analysis.reactionBarrier(path);
await tako.output("output/barrier.json", barrier);
// { barrierEv, reactionEnergyEv, saddleImage, energiesEv,
// relativeEnergiesEv, converged, residualEvPerAngstrom }
The returned object reads reaction_barrier.barrier_ev, .reaction_energy_ev, .saddle_image, .energies_ev, and .relative_energies_ev, plus neb.residual_ev_per_angstrom, and throws if any required field is missing or non-finite. We recommend this helper over raw field access at analysis boundaries: raw access silently accepts an unconverged band, while the helper makes allowUnconverged an auditable, deliberate choice. The barrier remains a model electronic energy — the interpretation limits in Nudged Elastic Band Method and the zero-point/thermal boundaries in Comparable Energies still apply.
Calculate binding and adsorption energies
No dedicated helper exists:
const bindingEv = eComplex - eFragmentA - eFragmentB;
const adsorptionEv = eSlabAdsorbate - eCleanSlab - eAdsorbateReference;
Use one calculator protocol. Define whether fragments are relaxed or frozen in complex geometry. For periodic adsorption, enforce identical slab cell, constraints, coverage, and composition. Sort only after rejecting failed/unconverged cases.
Combine matching harmonic ZPE
Vibration ZPE is nested and energyEv will not extract it:
function zpeEv(vibrationResult) {
const value = vibrationResult?.vibrations?.zero_point_energy_ev;
if (!Number.isFinite(value)) throw new Error("Missing finite molecular ZPE");
return value;
}
const correctedEv = electronicEv + zpeEv(vibrationResult);
Verify identical geometry/method/charge/spin and absence of meaningful imaginary modes. Tako supplies no temperature-dependent correction.
For a reaction:
const deltaE0Ev = deltaElectronicEv + tako.analysis.reactionEnergy({
reactants: reactantZpesEv,
products: productZpesEv,
});
Calculate a model-energy voltage
No voltage helper exists. For insertion between two compositions:
const inserted = x2 - x1;
if (!(inserted > 0)) throw new Error("x2 must exceed x1");
const deltaEv = eHostX2 - eHostX1 - inserted * metalReferenceEvPerAtom;
const voltageV = -deltaEv / (inserted * electronsPerInsertedAtom);
With eV and elementary-electron count, the result is volts numerically. Label it model-energy voltage unless a complete cycle was constructed.
Use lowerHull with prepared formation energies
lowerHull consumes supplied composition/energy points. It does not calculate formation energies or validate phase provenance. Normalize per consistent formula unit or atom before calling and retain original cell multiplicities.
Each point has finite numeric x, finite numeric y, and a nonempty label; otherwise the helper throws. It copies and sorts points by increasing x, then y, then locale label. It then compares each point with the currently retained representative. If their x values differ by at most , the later point is rejected. Consequently the smallest-x point survives a near-equal group even when its y is higher; y selects the lowest only when x is exactly equal. Grouping is representative-based, not a transitive clustering of adjacent spacings: a chain of pairwise-near points can start a new group once a point lies more than from the retained representative.
The lower convex chain removes a middle candidate only when the left segment slope is strictly greater than the right segment slope. Exactly collinear points are retained as stable hull points rather than collapsed to endpoints. This affects the number of voltage/chemical-potential segments and should be preserved when reproducing results.
const hull = tako.analysis.lowerHull(points);
// hull.points: fully sorted input copies
// hull.stable: retained lower-chain points, including collinear points
// hull.rejected: same-composition higher energies and above-hull points
// hull.segments: { from, to, dx, dy, slope } between stable neighbors
Labels are used to classify and order rejected results. Use unique labels; duplicate labels can make stable/rejected bookkeeping ambiguous even when coordinates differ. Record the definition and energy normalization with the hull.
Do not call parser-only pseudo APIs
Workflow parsing recognizes tokens such as tako.analysis.selectMinimum and tako.result.selectStructure, but they are not public runtime functions. Generated workflows may replace them with ordinary JavaScript reduction and finalStructure. Adsorption-site generators and ion-ordering helpers can likewise degrade to active-input fallbacks.
Use ordinary JavaScript explicitly:
const best = candidates.reduce((left, right) =>
left.energyEv <= right.energyEv ? left : right
);
Inspect exported workflow code before treating it as a scientific selection.
Preserve quantity and correction provenance
Write raw energies and a ledger:
await tako.output("output/energy-cycle.json", {
quantity: "GFN2+D4 model-energy binding difference",
signConvention: "complex - fragmentA - fragmentB",
units: "eV",
terms,
corrections: {
zpe: false,
thermal: false,
entropy: false,
standardState: false,
},
valueEv: bindingEv,
});
Do not name the field freeEnergyEv unless the required free-energy model was actually evaluated.
Distinguish workflow ranking from public helpers
The workflow runner uses a more permissive extractor than energyEv: it can accept adsorptionEnergyEv, adsorption_energy_ev, energy_ev, energyEv, or generic numeric energy, then a final frame, without an error/convergence guard. It omits optimization final_energy_ev unless a frame supplies energy. A workflow ranking can therefore differ from a Script ranking and can rank failed custom records.
For consequential comparisons, load results and apply explicit validation in Script rather than trusting workflow-node order.
The analysis namespace inventory is generated in Analysis and Output API, while operation-specific raw schemas remain in the generated settings pages.