Growing-String DE-TS
A growing-string double-ended transition-state (GS-DE-TS) job locates the transition state connecting a reactant and a product geometry using the growing-string method. This method builds a chain of interpolated geometries (a "string") and grows it toward the minimum-energy path, taking the highest-energy node as the TS.
What GS-DE-TS Runs
For each submitted job, Atomiverse executes:
- Atom mapping — reorders product atoms to match the reactant ordering.
- Growing-string search — builds and grows the string between reactant and product using pyGSM.
- String path is produced with energies of all nodes; the highest-energy node is taken as the TS.
Your First GS-DE-TS Job
import atomiverse
from atomiverse import Atoms, GrowingStringDETS, JobFailedError
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 = GrowingStringDETS(
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"String nodes: {len(result.gsm_path)}")
Input Parameters
Required:
reactant_atoms: reactant geometryproduct_atoms: product geometrylevel_of_theory: electronic-structure method
Optional:
charge(default0)multiplicity(default1)
The string resolution is determined adaptively — growth stops automatically once the geometric change between new nodes falls below a convergence threshold. No manual image count is needed.
The reactant and product must have the same number of atoms and the same elemental composition.
job = GrowingStringDETS(
reactant_atoms=reactant,
product_atoms=product,
charge=0,
multiplicity=1,
level_of_theory=GFN2_XTB,
)
Result
job.require_result() returns a GrowingStringDETSResult.
| Field | Type | Description |
|---|---|---|
ts_atoms | Atoms | Converged TS geometry. |
ts_energy | float | TS energy in Hartree. |
gsm_path | list[TrajectoryStep] | Final string path with positions, energy, and forces. |
ts_optimization_trajectory | list[TrajectoryStep] | TS refinement optimization trajectory. |
converged | bool | Whether the growing-string search converged. |
imaginary_frequency_cm1 | float | None | Imaginary frequency of the converged TS. |
Convenience accessors:
| Property | Returns |
|---|---|
gsm_path_atoms | list[Atoms] |
ts_optimization_atoms | list[Atoms] |
reaction_barrier | float |
result = job.require_result()
for step in result.gsm_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 growing-string search crashes or cannot converge, the job transitions
to FAILED with a user-facing error message. Partial GSM 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"GS-DE-TS failed: {failure.error}")
if failure.partial_gsm_path:
print(f"Partial path frames: {len(failure.partial_gsm_path)}")
last = failure.partial_gsm_path[-1]
print(last.energy)
else:
print(f"TS energy: {result.ts_energy:.6f} Ha")
print(f"GSM nodes: {len(result.gsm_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_gsm_path)} frames")