Time averages¶
TimeAverage gives the mean of a quantity over the frames of a trajectory:
a column of the atoms, such as their positions, the box, or anything a
function computes from a frame, such as a radial distribution function, as
OVITO's time averaging does. Averaged positions take the thermal vibrations
out of a crystal, so that its structure shows clearly.
import numpy as np
from mdapy.analysis import RadialDistributionFunction, TimeAverage
from mdapy.build import build_crystal
from mdapy.identify import CommonNeighborAnalysis
# copper whose atoms vibrate about their sites, 0.18 Å along each axis
copper = build_crystal("fcc", 3.615, elements="Cu", repeat=(8, 8, 8))
copper = copper.with_columns(id=np.arange(1, len(copper) + 1))
rng = np.random.default_rng(0)
frames = [
copper.with_columns(
positions=copper["positions"] + rng.normal(0, 0.18, (len(copper), 3))
)
for _ in range(20)
]
positions = TimeAverage("positions").compute(frames) # (N, 3)
averaged = frames[0].with_columns(positions=positions.value)
rdf = TimeAverage(lambda f: RadialDistributionFunction(6.0).compute(f).g)
mean_g = rdf.compute(frames).value # the mean g(r) over the frames
The common neighbor analysis of one frame and of the averaged positions:
from mdapy.visualization import render, write_png
cna = CommonNeighborAnalysis()
one, mean = cna.compute(frames[0]), cna.compute(averaged)
options = dict(view="iso", width=500, height=500)
write_png(
"images/time-average.png",
np.hstack(
[
render(frames[0], color=one, **options, legend=True),
render(averaged, color=mean, **options, legend=True),
]
),
)

Left: one frame, in which the vibrations leave half of the atoms unrecognized (white) among the fcc atoms (green). Right: the positions averaged over 20 frames, all fcc.
Parameters¶
TimeAverage(quantity, *, unwrap=True)
| Name | Type | Default | Unit | Meaning |
|---|---|---|---|---|
quantity |
str or callable | a column of numbers of the atoms, such as "positions" or "csp"; "box" for the lattice vectors; or a function of a frame that gives a number, or an array of the same shape in every frame |
||
unwrap |
bool | True |
for positions: follow the atoms through the periodic boundaries, or average the positions as they are |
compute(frames) takes an iterable of systems, such as a
Trajectory or a slice of one, read one
at a time. For a column the atoms are matched by their ids, as for the
mean squared displacement, and positions are unwrapped
in the same way: by the image flags, or else through the nearest periodic
image of each step. OVITO's time averaging instead takes the atoms in the
order they come and needs the positions unwrapped beforehand.
Results¶
A TimeAverageResult:
| Attribute | Type | Meaning |
|---|---|---|
value |
float64 | the mean: of each atom in the order of the first frame for a column, (3, 3) for the box, of the shape of the function otherwise |
frames |
int32 | the number of frames |
name |
str or None |
the column; system.with_columns(result) adds name_average, a component such as positions.z written positions_z_average |
Errors¶
compute raises InvalidParameter when there are no frames, as the
mean squared displacement does for frames of other atoms,
for a column that is not numbers, and when a function gives another shape
in a later frame; MissingProperty for a column a frame lacks.
TimeAverage raises InvalidParameter for a quantity that is neither a
name nor a function.