Docs are under construction. Content may be incomplete or change.

Geometry Optimization with Tako Script

Page type: Reference
On this page

tako.optimize changes atomic coordinates and, when requested, selected cell degrees of freedom until its force-based convergence condition is met or its step budget is exhausted. It returns a promise and creates an Opt-<N>-calc workspace.

The algorithmic theory is in Geometry Optimization. This chapter defines Script construction, branching, and output handling.

Operation contract

const result = await tako.optimize(structure, {
  calculator,
  properties,
  optimizer,
  maxSteps,
  fmaxEvPerAngstrom,
  maxstepAngstrom,
  alpha,
  trajectoryFrameInterval,
  cellRelaxation,
});
SettingDefaultContract
calculatorrequiredGFN2 or MLIP calculator defining the energy/force surface
propertieslevel-dependentInclude energy and forces; cell relaxation requires supported stress
optimizer'bfgs''bfgs', 'fire', or 'mdmin'
maxSteps500Requested positive iteration budget; WASM execution is capped at 500 steps, while the current returned settings record retains the requested value
fmaxEvPerAngstrom0.01Threshold on the maximum per-atom force norm
maxstepAngstrom0.04Fixed cell: maximum atomic displacement; variable cell: limiter over the augmented N+3 optimizer rows, which can be controlled by a scaled cell row
alpha70Initial BFGS Hessian scale in eV/Ų; ignored by FIRE and MDMin
trajectoryFrameInterval1Positive frame-storage interval; first/final evidence remains operation-controlled
cellRelaxation{ mode: 'fixed' }Fixed, full, lengths, angles, or explicit custom cell mask

The generated tako.optimize settings reference is authoritative for accepted values and validation.

Fixed-cell molecular relaxation

const input = await tako.input("input/structure.extxyz");
const calculator = tako.calculator.gfn2({
  levelOfTheory: "gfn2",
  dispersion: "d4",
  charge: 0,
  unpaired: 0,
});

const properties = ["energy", "forces"];
const check = calculator.validate("optimization", { properties });
if (!check.ok) throw new Error(check.reasons.join("; "));

const result = await tako.optimize(input, {
  calculator,
  properties,
  optimizer: "bfgs",
  maxSteps: 300,
  fmaxEvPerAngstrom: 0.01,
  maxstepAngstrom: 0.04,
});

if (!result.converged) {
  throw new Error(
    `Optimization stopped unconverged after ${result.steps} steps; ` +
    `final fmax=${result.final_fmax_ev_per_angstrom} eV/A`,
  );
}

const finalStructure = tako.analysis.finalStructure(input, result);
await tako.output("output/final.extxyz", finalStructure);
await tako.output("output/result.json", result);

The explicit convergence branch is part of the scientific contract. A normally resolved promise can contain converged: false after the step budget is exhausted.

Variable-cell relaxation

const input = await tako.input("input/crystal.extxyz");
const calculator = tako.calculator.mlip({ levelOfTheory: "nequix" });
const properties = ["energy", "forces", "stress"];

const check = calculator.validate("optimization", { properties });
if (!check.ok) throw new Error(check.reasons.join("; "));

const result = await tako.optimize(input, {
  calculator,
  properties,
  optimizer: "bfgs",
  maxSteps: 300,
  fmaxEvPerAngstrom: 0.02,
  maxstepAngstrom: 0.04,
  cellRelaxation: {
    mode: "custom",
    relaxLengths: [true, true, false],
    relaxAngles: [false, false, false],
  },
});

if (!result.converged) throw new Error("Variable-cell relaxation did not converge.");
await tako.output("output/relaxed.extxyz", tako.analysis.finalStructure(input, result));
await tako.output("output/cell-summary.json", {
  cell: result.cell,
  stressEvPerAngstrom3: result.stress_ev_per_angstrom3,
  finalFmaxEvPerAngstrom: result.final_fmax_ev_per_angstrom,
});

relaxLengths and relaxAngles contain three booleans each. They define the released cell subspace; they are not post-processing filters. A nonperiodic structure cannot be cell-relaxed.

Selective dynamics

Apply Cartesian mobility flags to a new structure before calling the optimizer:

let constrained = tako.structure.fix(input, [0, 1, 2, 3]);
constrained = tako.structure.fix(constrained, [4], {
  move: [false, false, true],
});

Omitting move freezes all components of the listed atoms. In move, true means that component is free. Retain the constrained input artifact: the final coordinates alone do not reveal which degrees of freedom were excluded.

The current optimization convergence trace can include raw force on frozen atoms, so a plateau can reflect anchor forces rather than genuine convergence. Report the constrained-force convention and inspect free-atom motion.

Result schema

FieldType and unitMeaning
convergedbooleanForce criterion met within the budget
stepsintegerAccepted optimizer steps; zero is possible for an already converged input
final_energy_evnumber, eVFinal potential energy
final_energy_hartreenumber, EhSame final energy in Hartree when supplied
final_fmax_ev_per_angstromnumber, eV/ÅFixed cell: maximum per-atom force norm; variable cell: maximum over the augmented atomic and scaled cell-force rows
framesarrayStored optimization frames
frames[].stepintegerOptimizer step index
frames[].energy_evnumber, eVFrame energy
frames[].fmax_ev_per_angstromnumber, eV/ÅFixed cell: frame maximum per-atom force norm; variable cell: maximum over atomic and scaled cell-force rows
frames[].maxstep_angstromnumber, ÅFixed cell: accepted maximum atomic displacement; variable cell: maximum generalized-row step, which need not belong to an atom
frames[].atomsatom arrayFrame atom identities and positions
frames[].cell.vectors3×3 array, ÅPeriodic lattice vectors when present
atomsatom arrayFinal atom identifiers, elements, Cartesian coordinates in Å, and optional selective-dynamics flags
cell.vectors3×3 array, ÅFinal lattice vectors for a periodic structure; cell is null for a nonperiodic structure
stress_ev_per_angstrom33×3 array, eV/ųFinal stress when requested and supported

tako.analysis.energyEv(result) refuses an explicitly unconverged result. tako.analysis.finalStructure(input, result) reconstructs the final structure without asserting convergence; call it only inside an explicit branch whose purpose is clear.

Staged continuation

async function optimizeStage(input, settings) {
  const result = await tako.optimize(input, settings);
  return {
    result,
    structure: tako.analysis.finalStructure(input, result),
  };
}

const coarse = await optimizeStage(input, {
  calculator,
  properties: ["energy", "forces"],
  optimizer: "fire",
  maxSteps: 300,
  fmaxEvPerAngstrom: 0.05,
  maxstepAngstrom: 0.02,
});

if (!coarse.result.converged) {
  throw new Error("Coarse stage did not reach its declared gate.");
}

const fine = await optimizeStage(coarse.structure, {
  calculator,
  properties: ["energy", "forces"],
  optimizer: "bfgs",
  maxSteps: 300,
  fmaxEvPerAngstrom: 0.01,
  maxstepAngstrom: 0.04,
});

if (!fine.result.converged) throw new Error("Fine stage did not converge.");
await tako.output("output/final.extxyz", fine.structure);
await tako.output("output/stages.json", {
  coarse: coarse.result,
  fine: fine.result,
});

The second call begins from the first geometry but starts a new optimizer workspace and curvature state. Retaining both results prevents the staged history from being mistaken for one uninterrupted BFGS trajectory.

Failure handling

ConditionContractResponse
Calculator validation rejects optimization or stressNo run should startChange the calculator/property request
Structure has no cell while cell relaxation is activeOperation rejects the requestAdd a physically meaningful periodic cell or use fixed mode
Promise rejectsValidation, asset, engine, reset, cancellation, or worker failureRead the workspace log and preserve the error
Promise resolves with converged: falseStep budget ended without satisfying the force gateInspect trajectory and trace before continuing or changing settings
Geometry becomes chemically invalidNumerical steps left the intended basin or model domainReject the run; repair/resample the input rather than reporting its final energy
Energy helper throws on unconverged resultAnalysis guard is workingBranch on converged; read raw energy only for clearly labelled diagnostics

Cancellation rejects with Canceled by user and is not a numerical checkpoint. A later optimization can begin from an explicitly saved structure, but it does not resume the cancelled optimizer’s internal state.