Interactions

An interaction is any object paired with a neighbour finder in MDSys's interactions list. Each step, simulate! calls update_acceleration! on every (interaction, finder) pair to accumulate forces, and a logger may separately call energy to record that interaction's contribution.

Built-in interactions

ExTinyMD.LennardJones — Type
LennardJones(; ϵ = 1.0, cutoff = 3.5, σ = 1.0)

Pairwise Lennard-Jones interaction, E(r) = 4ϵ[(σ/r)^12 - (σ/r)^6] for r < cutoff, evaluated over the pairs in the associated neighbour finder.

source
ExTinyMD.SubLennardJones — Type
SubLennardJones(sub_down, sub_up; ϵ = 1.0, cutoff = 3.5, σ = 1.0)

Lennard-Jones interaction between each particle and two flat substrates at z = sub_down and z = sub_up, acting only in z on particles within cutoff of a wall (see SubNeighborFinder).

source
ExTinyMD.ExternalField — Type
ExternalField(; E = Point((0.0, 0.0, 0.0)))

A uniform external electric field E; each particle feels a force charge * E. Pair with a NoNeighborFinder, since no neighbour list is needed.

source

The electrostatic interactions (Ewald3D, Ewald2D, ICMEwald2D, ICMEwald3D) are documented separately on the Electrostatics page — they share the same update_acceleration!/energy contract described below, but also work standalone, without any MDSys.

The interaction contract

ExTinyMD.update_acceleration! — Function
update_acceleration!(interaction, neighborfinder, sys, info)

Accumulate the acceleration contributed by interaction into info.particle_info[i].acceleration for every particle i. This is the interface every AbstractInteraction implements to plug into simulate!; NoInteraction is a no-op. See README.md for how to add a new interaction.

source
ExTinyMD.energy — Function
energy(interaction, neighborfinder, sys, info) -> T

The energy contributed by interaction. This is the interface every energy-reporting AbstractInteraction implements (used by EnergyLogger); not every interaction defines a method — one that only ever appears inside a logger-free MDSys need not.

source

To add a new interaction, define a struct (optionally <: AbstractInteraction, though this is not required — dispatch only needs the methods below) and implement:

function ExTinyMD.update_acceleration!(
    interaction::YourInteraction,
    neighborfinder::YourFinder,
    sys::MDSys{T},
    info::SimulationInfo{T},
) where {T<:Number}
    update_finder!(neighborfinder, info)
    # accumulate into info.particle_info[i].acceleration for every particle i,
    # using neighborfinder.neighbor_list (or neighborfinder.up_neighbor /
    # down_neighbor for a SubNeighborFinder-style finder) to find pairs.
    return nothing
end

update_acceleration! accumulates — it must not overwrite info.particle_info[i].acceleration, since VerletProcess zeroes it once per step before calling every interaction in turn.

If the interaction should also be logged with EnergyLogger, add a matching method for energy:

function ExTinyMD.energy(
    interaction::YourInteraction,
    neighborfinder::YourFinder,
    sys::MDSys{T},
    info::SimulationInfo{T},
) where {T<:Number}
    # return the total energy, without mutating anything
end

LennardJones in src/interactions/lennard_jones.jl is the simplest complete example of both methods; the electrostatics adapter in src/interactions/electrostatics/adapter.jl is a more involved one, showing how to bridge to a framework-free core API (see Electrostatics).