# Interface Definition

The `AtomsCalculator`

interface is designed to provide easy to use and easy to read high level functions for standard molecular mechanics, while at the same time being flexible and extensible. Moreover the flexible low-level interface is designed to be compatible with `Lux.jl`

to enable training of parameterized models. Due to this tension (ease of use vs flexibility) there are two alternative ways to call and implement the interface, which are described in separate sections below.

A new calculator need not implement the entire interface, or indeed both interfaces to be useful. Moreover, `AtomsCalculators`

provides various utilities to help with the implementation.

Most interface functions have two common inputs: an `AtomsBase.AbstractSystem{D}`

compatible structure and a "calculator" that specifies details of the calculation method. Throughout this documentation:

`sys`

: always specifies a system, usually an`AtomsBase.AbstractSystem{D}`

`calc`

: always specifies a calculator implementing (part of) the`AtomsCalculators`

interface.

## High-Level Interface

The high-level interface provides function prototypes for potential energy, forces and virial calculations.

### Minimal high-level interface

A minimal implementation of an `AtomsCalculators`

calculator should provide (however, see alternatives below)

`energy_unit(calc)`

: return energy unit used by the calculator`length_unit(calc)`

: return length unit used by the calculator`potential_energy(sys, calc; kwargs...)`

: return potential energy of the system as a`Unitful.Energy`

`forces(sys, calc; kwargs...)`

return forces as an`AbstractVector{SVector{D, <: Unitful.Force}}`

`virial(sys, calc; kwargs...)`

return virial (not stress!) as a`SMatrix{D, D, Unitful.Energy}`

#### Remarks

- Methods must accept keyword arguments, but they can be ignored. For a discussion of some standard keyword arguments that a calculator may wish to support see Reserved Keyword Arguments.
- If a calculator does not implement a function, then it can simply choose not to provide that method. A simulator that relies on that function will then simply fail. For example a QM/MM force mixing scheme may be unable to provide
`potential_energy`

.

### Extended high-level interface

The extended interface can be automatically generated from the minimal interface, but for various reasons (in particular performance), some calculators may prefer to implement their own methods for the following functions.

Several utility functions are derived from `energy_unit`

and `length_unit`

which can be overloaded by a calculator implementation:

`force_unit(calc)`

: compute force unit (default from energy and length units)`promote_force_type(sys, calc)`

: determine type of force`zero_energy(sys, calc)`

: initialize potential energy`zero_forces(sys, calc)`

: initilize a force vector`zero_virial(sys, calc)`

: initialize a virial matrix

A calculator may provide non-allocating and or combined calculations that can sometimes be preferred for performance reasons. All of these return results as a `NamedTuple`

.

`energy_forces(sys, calc)`

`energy_forces!(f, sys, calc)`

`energy_forces_virial(sys, calc)`

`energy_forces_virial!(f, sys, calc)`

To avoid writing too much boiler-plate code to support the full interface, see the utilities section of the docs.

## Low-Level Interface

All high-level functionality listed above can also be accessed via "low-level" calls with user-specifiable parameters through `calculate`

methods. The low-level `calculate`

interface follows the Lux model for parameters and state. This means that when calculations are performed with the `calculate`

interface calculators **must act as immutable** structs that are passed to the `calculate`

function together with `parameters`

and `state`

. All calculations then return an output and a state. Note, we only require calculators **act** immutable but not to be technically immutable. For example the same calculator can implement the high-level interface and then mutate an internal state.

### General structure of the low-level interface

The low level interface is built around a `calculate`

function

where,

`property`

is the property to be computed e.g.`PotentialEnergy()`

,`sys`

is an system,`calc`

is a calculator,`ps`

either`nothing`

or a nested`NamedTuple`

storing the calculator parameters,`st`

either`nothing`

or a nested`NamedTuple`

storing the calculator state`kwargs...`

must be allowed but can be ignored; with caveats - see Reserved Keyword Arguments

Irrespective of which property is required, the return type is *always* a `NamedTuple`

with keys indicating the name of properties being computed. The content of this `NamedTuple`

is not required to be restricted to the requested property (or, properties - more on this below).

### Calculator State and Parameters

To manage parameters and state, `AtomsCalculators`

provides prototypes that can be overloaded:

`get_state(calc)`

: return a`NamedTuple`

or`ComponentArray`

containing the entire mutable state of the calculator;`set_state!(calc, st)`

: set the state of the calculator, may be mutating or non-mutating;`get_parameters(calc)`

: return a`NamedTuple`

or`ComponentArray`

containing all parameters;`set_parameters!(calc, ps)`

: set the parameters of the calculator, may be mutating or non-mutating.

This functionality is somewhat separate from Lux

```
ps, st = Lux.setup(rng, model)
ps = LuxCore.initparameters(rng, model)
```

The difference is that `Lux.setup`

initializes parameters, whereas, `*_state`

and `*_parameters`

is intended to read and write existing (already fitted) parameters. In addition, a calculator need not implement `LuxCore.initparams`

and `LuxCore.initstate`

, but it has the option to do so.

The default implementations for `*_state`

and `*_parameters`

assume a stateless and parameter-free calculator.

The calls `set_state!`

and `set_parameters!`

may be mutating (hence the !) but need not be mutating. The correct usage is therefore

```
new_calc = set_state!(calc, st)
new_calc = set_parameters!(calc, ps)
```

In general, the caller should not assume that `new_calc`

and `calc`

are references to the same object.

### Molecular mechanics with the low-level interface

The three basic properties to perform molecular mechanics simulations are energy, forces and virials, defined through

With these properties, the following calling conventions are analogous:

`calculate(Energy(), sys, calc, ps, st)`

is analogous to`potential_energy(sys, calc)`

`calculate(Forces(), sys, calc, ps, st)`

is analogous to`forces(sys, calc)`

`calculate(Virial(), sys, calc, ps, st)`

is analogous to`virial(sys, calc)`

Energies, forces and virials can be obtained from the output `NamedTuple`

via

```
out = calculate(Energy(), sys, calc, ps, st)
out.energy
out = calculate(Forces(), sys, calc, ps, st)
out.forces
out = calculate(Virial(), sys, calc, ps, st)
out.virial
```

### Multiple properties

Multiple properties can be requested from a calculator by bundling them into a tuple. For example,

```
efv = calculate( (Energy(), Forces(), Virial()), sys, calc, ps, st)
efv.energy
efv.forces
efv.virial
```

### Extensions

A calculator can extend the `calculate`

interface without having to make a pull request to `AtomsCalculators`

. For example, a site potential could supply the possibility of returning site energies, which could be implemented as follows.

```
struct SiteEnergies end
out = calculate(SiteEnergies(), sys, calc, ps, st)
out.siteenergies::AbstractVector{<: Unitful.Energy}
```

If such an extension could be of value to a broader developer or user base, then an issue and/or PR to AtomsCalculators would be very welcome.

## Recommended Keyword Arguments

The following keyword arguments are used consistently throughout the AtomsBase / AtomsCalculators ecosystem.

`domain`

: the domain over which to evaluate an energy, normally used for site potentials where partial energies can be evaluated. Calculators that do not provide this functionality may wish to throw an error is a partial energy is requested to avoid silent bugs.`executor`

: a label or type specifying how to execute the calculator (e.g. in serial, multi-threaded, distributed)`nlist`

: a possibly precomputed neighbourlist