Skip to main content

Cloud Calculator

CloudCalculator wraps Atomiverse SinglePointEnergy jobs behind ASE's calculator interface so you can attach it directly to an ase.Atoms object.

Convenience over throughput

This integration is intentionally convenient, not maximally efficient. Each fresh ASE evaluation submits a remote single-point job, so this is usually not the best choice for tight geometry optimization loops, molecular dynamics, or other high-throughput workflows.

Basic Usage

from ase import Atoms
from atomiverse import CloudCalculator
from atomiverse.levels import GFN2_XTB

atoms = Atoms(
"H2O",
positions=[
[0.000, 0.000, 0.119],
[0.000, 0.763, -0.477],
[0.000, -0.763, -0.477],
],
)

atoms.calc = CloudCalculator(level_of_theory=GFN2_XTB)

energy = atoms.get_potential_energy() # eV
forces = atoms.get_forces() # eV/Angstrom

print(energy)
print(forces)

CloudCalculator exposes the standard ASE properties:

PropertyASE Units
energyeV
forceseV/Angstrom

Under the hood, Atomiverse runs a single-point energy calculation and converts the result from Hartree / Hartree-Angstrom units into ASE's expected units. If ASE asks only for the potential energy, CloudCalculator submits an energy-only job. If ASE asks for forces, it submits a force-capable job.

energy = atoms.get_potential_energy()  # submits an energy-only job
forces = atoms.get_forces() # submits a job with forces when needed

Preferred Use Cases

Use CloudCalculator when you want:

  • a clean ASE-native interface
  • to attach Atomiverse directly to an existing ase.Atoms workflow
  • convenient energy / force evaluation without managing jobs manually

Use direct SinglePointEnergy(...) jobs instead when you want:

  • one-off single-point calculations
  • explicit access to job IDs, dashboard naming, refresh, cancellation, or deletion
  • tighter control over large submission loops or higher-throughput workflows

Managed Cloud And BYOC

By default, CloudCalculator submits to Atomiverse managed cloud compute.

If you need to target your own registered BYOC controller, pass compute_target:

from atomiverse import CloudCalculator

atoms.calc = CloudCalculator(
level_of_theory=GFN2_XTB,
compute_target="my-cluster",
wait_for_capacity=True,
)

The same pass-through options available on SinglePointEnergy.submit() are supported:

  • compute_target
  • wait_for_capacity
  • max_wait
  • timeout

Accessing The Underlying Job

After a calculation, calc.last_job holds the submitted SinglePointEnergy instance:

calc = CloudCalculator(level_of_theory=GFN2_XTB)
atoms.calc = calc

atoms.get_potential_energy()

print(calc.last_job.job_id)
print(calc.last_job.compute_forces) # False for an energy-only call
print(calc.last_job.require_result().energy) # Hartree

This is useful when you want ASE for execution but still want access to the Atomiverse job metadata afterward.

If you need forces from the underlying job, request forces through ASE first:

atoms.get_forces()

result = calc.last_job.require_result()
print(result.forces) # Hartree/Angstrom

ASE Optimizer Example

Still not the most efficient route

This works and can be a nice integration point, but each new optimizer step may trigger a fresh remote single-point submission. For many-step optimizations, using Atomiverse jobs directly is usually the better choice.

from ase import Atoms
from ase.optimize import BFGS

from atomiverse import CloudCalculator
from atomiverse.levels import GFN2_XTB

atoms = Atoms(
"H2",
positions=[[0.0, 0.0, 0.0], [0.0, 0.0, 0.80]],
)
atoms.calc = CloudCalculator(level_of_theory=GFN2_XTB)

optimizer = BFGS(atoms)
optimizer.run(fmax=0.05)