Pysisyphus AFIR DE-TS
A Pysisyphus AFIR double-ended transition-state (AFIR DE-TS) job locates the transition state connecting a reactant and a product geometry using the Artificial Force Induced Reaction (AFIR) method. This method applies an artificial force to drive the reactant and product together toward a common TS region, identifies the highest-energy point on the resulting path as the transition state.
What AFIR DE-TS Runs
For each submitted job, Atomiverse executes:
- Atom mapping — reorders the product atoms to match the reactant ordering, which is required for the AFIR method.
- Endpoint evaluation at the chosen level of theory.
- AFIR path search — runs the Pysisyphus AFIR algorithm to find the minimum-energy path between reactant and product.
- TS identification — the highest-energy node on the AFIR path is taken as the TS.
Your First AFIR DE-TS Job
import atomiverse
from atomiverse import (
Atoms,
JobFailedError,
PysisyphusAFIRDETS,
)
from atomiverse.levels import GFN2_XTB
atomiverse.configure(api_key="your-api-key")
reactant = Atoms.from_smiles("CC")
product = Atoms.from_smiles("C=C")
job = PysisyphusAFIRDETS(
reactant_atoms=reactant,
product_atoms=product,
level_of_theory=GFN2_XTB,
)
job.submit()
try:
result = job.require_result()
except JobFailedError as exc:
print(f"Job failed: {exc.failure.error}")
else:
print(f"Converged: {result.converged}")
print(f"TS energy: {result.ts_energy:.6f} Hartree")
print(f"Barrier: {result.reaction_barrier:.6f} Hartree")
print(f"Path nodes: {len(result.afir_path)}")
Input Parameters
Required:
reactant_atoms: reactant geometryproduct_atoms: product geometrylevel_of_theory: electronic-structure method
Optional:
charge(default0)multiplicity(default1)
The AFIR method uses the Pysisyphus AFIR algorithm internally. No manual tuning of the artificial force or path parameters is needed.
The reactant and product must have the same number of atoms and the same elemental composition.
job = PysisyphusAFIRDETS(
reactant_atoms=reactant,
product_atoms=product,
charge=0,
multiplicity=1,
level_of_theory=GFN2_XTB,
)
Result
job.require_result() returns a PysisyphusAFIRDETSResult.
| Field | Type | Description |
|---|---|---|
ts_atoms | Atoms | Converged TS geometry. |
ts_energy | float | TS energy in Hartree. |
reactant_energy | float | Reactant endpoint energy in Hartree. |
product_energy | float | Product endpoint energy in Hartree. |
afir_path | list[TrajectoryStep] | AFIR path with positions, energy, and forces. |
converged | bool | Whether the AFIR search converged. |
Convenience accessors:
| Property | Returns |
|---|---|
afir_path_atoms | list[Atoms] |
reaction_barrier | float |
result = job.require_result()
for step in result.afir_path:
print(step.energy)
print(step.forces)
print(f"TS: {result.ts_energy:.6f} Ha")
print(f"Barrier: {result.reaction_barrier:.6f} Ha")
Handling Failures
If the AFIR search crashes or cannot converge, the job transitions
to FAILED with a user-facing error message. Partial AFIR path frames may
be available in the typed failure payload.
from atomiverse import JobFailedError
job.submit()
try:
result = job.require_result()
except JobFailedError as exc:
failure = exc.failure
print(f"AFIR DE-TS failed: {failure.error}")
if failure.partial_afir_path:
print(f"Partial path frames: {len(failure.partial_afir_path)}")
last = failure.partial_afir_path[-1]
print(last.energy)
else:
print(f"TS energy: {result.ts_energy:.6f} Ha")
print(f"AFIR nodes: {len(result.afir_path)}")
Non-blocking Submission
from atomiverse import State
job.submit(wait=False)
job.refresh()
if job.state == State.DONE:
result = job.require_result()
print(f"TS energy: {result.ts_energy:.6f} Ha")
elif job.state == State.FAILED:
failure = job.require_failure()
print(failure.error)
print(f"Partial path: {len(failure.partial_afir_path)} frames")