Quickstart¶
Reading and writing of trajectories¶
Reading and writing with automatic filetype detection¶
The garnett.read()
and garnett.write()
functions will automatically determine the type of a trajectory from its file extension.
This can be used to quickly load and save Trajectory
objects.
import garnett
# Load a GSD file...
with garnett.read('dump.gsd') as traj:
print(len(traj))
# ...do things with the trajectory, then output a GTAR file
garnett.write(traj, 'output.tar')
Using reader and writer classes¶
Readers and writers are defined in the reader
and writer
modules.
The following code uses the PosFileReader
and PosFileWriter
as an example.
from garnett.reader import PosFileReader
from garnett.writer import PosFileWriter
pos_reader = PosFileReader()
pos_writer = PosFileWriter()
with open('posfile.pos') as file:
# Access the trajectory
traj = pos_reader.read(file)
# Write to standard out:
pos_writer.write(traj)
# or directly to a file:
with open('out.pos', 'w') as posfile:
pos_writer.write(traj, posfile)
Data access¶
Indexing and slicing¶
Once you read a trajectory, access individual frames or sub-trajectories by indexing and slicing:
# Select individual frames:
first_frame = traj[0]
last_frame = traj[-1]
n_th_frame = traj[n]
# and so on
# Create a sub-trajectory from the ith frame
# to the (j-1)th frame:
sub_trajectory = traj[i:j]
# We can use advanced slicing techniques:
every_second_frame = traj[::2]
the_last_ten_frames = traj[-10::]
The actual trajectory data is then either accessed on a per trajectory or per frame basis.
Trajectory array access¶
Access positions, orientations and types as coherent numpy arrays, by calling the load_arrays()
method.
This method will load the complete trajectory into memory and make positions, orientations and types available via properties:
traj.load_arrays()
traj.N # M
traj.positions # MxNx3
traj.orientations # MxNx4
traj.velocities # MxNx3
traj.mass # MxN
traj.charge # MxN
traj.diameter # MxN
traj.moment_inertia # MxNx3
traj.angmom # MxNx4
traj.image # MxNx4
traj.types # MxN
traj.type_ids # MxN
traj.type # list of type names ordered by type_id
# where M=len(traj) is the number of frames and N=max((len(f) for f in traj))
# is the is the maximum number of particles in any frame.
Individual frame access¶
Inidividual frame objects can be accessed via indexing of a (sub-)trajectory object:
frame = traj[i]
frame.box # garnett.trajectory.Box object
frame.types # N
frame.positions # Nx3
frame.orientations # Nx4
frame.velocities # Nx3
frame.mass # N
frame.charge # N
frame.diameter # N
frame.moment_inertia # Nx3
frame.angmom # Nx4
frame.data # A dictionary of lists for each attribute
frame.data_key # A list of strings
frame.shapedef # A ordered dictionary of instances of ShapeDefinition
Iterating over trajectories¶
Iterating over trajectories is the most memory-efficient form of data access. Each frame will be loaded prior to access and unloaded post access, such that there is only one frame loaded into memory at the same time.
# Iterate over a trajectory directly for read-only data access
for frame in traj:
print(frame.positions)
Efficient modification of trajectories¶
Use a combination of reading, writing, and iteration for memory-efficient modification of large trajectory data. This is an example on how to modify frames in-place:
import numpy as np
import garnett as gt
def center(frame):
frame.positions -= np.average(frame.positions, axis=0)
return frame
with gt.read('in.pos') as traj:
traj_centered = Trajectory((center(frame) for frame in traj))
gt.write(traj_centered, 'out.pos')
Loading trajectories into memory¶
The Trajectory
class is designed to be memory-efficient.
This means that loading all trajectory data into memory requires an explicit call of the load()
or load_arrays()
methods.
# Make trajectory data accessible via arrays:
traj.load_arrays()
traj.positions
# Load all frames:
traj.load()
frame = traj[i]
traj.positions # load() also loads arrays
Note
In general, loading all frames with load()
is more expensive than just loading arrays with load_arrays()
.
Loading all frames also loads the arrays.
Sub-trajectories inherit already loaded data:
traj.load_arrays()
sub_traj = traj[i:j]
sub_traj.positions
Tip
If you are only interested in sub-trajectory data, consider to call load()
or load_arrays()
only for the sub-trajectory.
Example use with HOOMD-blue¶
The garnett frames can be used to initialize HOOMD-blue by creating snapshots with the make_snapshot()
method or by copying the frame data to existing snapshots with the copyto_snapshot()
methods:
from hoomd import init
import garnett as gt
with gt.read('cube.pos') as traj:
# Initialize from last frame
snapshot = traj[-1].make_snapshot()
system = init.read_snapshot(snapshot)
# Restore last frame
snapshot = system.take_snapshot()
traj[-1].copyto_snapshot(snapshot)