HOOMD¶
gsd.hoomd
provides high-level access to HOOMD schema GSD files.
View the page source to find unformatted example code.
Define a snapshot¶
In [1]: s = gsd.hoomd.Snapshot()
In [2]: s.particles.N = 4
In [3]: s.particles.types = ['A', 'B']
In [4]: s.particles.typeid = [0,0,1,1]
In [5]: s.particles.position = [[0,0,0],[1,1,1], [-1,-1,-1], [1,-1,-1]]
In [6]: s.configuration.box = [3, 3, 3, 0, 0, 0]
gsd.hoomd
represents the state of a single frame with an instance of
the class gsd.hoomd.Snapshot
. Instantiate this class to create a
system configuration. All fields default to None
and are only written into
the file if not None
and do not match the data in the first frame or
defaults specified in the schema.
Create a hoomd gsd file¶
In [7]: f = gsd.hoomd.open(name='file.gsd', mode='wb')
Write frames to a gsd file¶
In [8]: def create_frame(i):
...: s = gsd.hoomd.Snapshot()
...: s.configuration.step = i
...: s.particles.N = 4+i
...: s.particles.position = numpy.random.random(size=(4+i,3))
...: return s
...:
In [9]: f = gsd.hoomd.open(name='test.gsd', mode='wb')
In [10]: f.extend( (create_frame(i) for i in range(10)) )
In [11]: f.append( create_frame(10) )
In [12]: len(f)
Out[12]: 11
Use gsd.hoomd.open
to open a GSD file with the high level interface
gsd.hoomd.HOOMDTrajectory
. It behaves like a list
, with
append
and
extend
methods.
Note
gsd.hoomd.HOOMDTrajectory
currently does not support files opened in
append mode.
Tip
When using extend
, pass in a
generator or generator expression to avoid storing the entire
trajectory in memory before writing it out.
Randomly index frames¶
In [13]: f = gsd.hoomd.open(name='test.gsd', mode='rb')
In [14]: snap = f[5]
In [15]: snap.configuration.step
Out[15]: 5
In [16]: snap.particles.N
Out[16]: 9
In [17]: snap.particles.position
Out[17]:
array([[1.0090252e-01, 1.2697770e-01, 8.3151418e-01],
[3.0592948e-01, 9.5838189e-01, 8.0269945e-01],
[8.9280909e-01, 6.2354222e-02, 3.9890173e-01],
[5.6603861e-01, 5.9274304e-01, 9.8189354e-01],
[2.3613523e-01, 4.5365587e-01, 2.5194898e-01],
[8.2568115e-01, 6.2175477e-01, 6.7545468e-01],
[8.0791616e-01, 8.4495259e-05, 5.5440587e-01],
[8.5159767e-01, 3.1477225e-01, 2.2971131e-01],
[4.5910826e-01, 1.6157266e-01, 4.0942749e-01]], dtype=float32)
gsd.hoomd.HOOMDTrajectory
supports random indexing of frames in the file.
Indexing into a trajectory returns a gsd.hoomd.Snapshot
.
Slicing and selection¶
Use the slicing operator to select individual frames or a subset of a trajectory.
In [18]: f = gsd.hoomd.open(name='test.gsd', mode='rb')
In [19]: for s in f[5:-2]:
....: print(s.configuration.step, end=' ')
....:
5 6 7 8
In [20]: every_2nd_frame = f[::2] # create a view of a trajectory subset
In [21]: for s in every_2nd_frame[:4]:
....: print(s.configuration.step, end=' ')
....:
0 2 4 6
Slicing a trajectory creates a trajectory view, which can then be queried for length or sliced again. Selecting individual frames from a view works exactly like selecting individual frames from the original trajectory object.
Pure python reader¶
In [22]: f = gsd.pygsd.GSDFile(open('test.gsd', 'rb'))
In [23]: t = gsd.hoomd.HOOMDTrajectory(f);
In [24]: t[3].particles.position
Out[24]:
array([[0.50029236, 0.25948378, 0.765157 ],
[0.6452491 , 0.66116315, 0.8199301 ],
[0.899342 , 0.6564898 , 0.6485002 ],
[0.98641735, 0.8828696 , 0.08654012],
[0.6466805 , 0.5999297 , 0.61616707],
[0.01945949, 0.9876428 , 0.39746737],
[0.9313278 , 0.43891996, 0.760128 ]], dtype=float32)
You can use GSD without needing to compile C code to read GSD files
using gsd.pygsd.GSDFile
in combination with gsd.hoomd.HOOMDTrajectory
. It
only supports the rb
mode and does not read files as fast as the C
implementation. It takes in a python file-like object, so it can be used with
in-memory IO classes, and grid file classes that access data over the internet.
Warning
gsd.pygsd
is slow. Use gsd.hoomd.open
whenever possible.
Access logged data¶
In [25]: with gsd.hoomd.open(name='example.gsd', mode='wb') as f:
....: s = gsd.hoomd.Snapshot()
....: s.particles.N = 4
....: s.log['particles/net_force'] = numpy.array([[-1,2,-3],
....: [0,2,-4],
....: [-3,2,1],
....: [1,2,3]], dtype=numpy.float32)
....: s.log['value/potential_energy'] = [1.5]
....: f.append(s)
....:
Logged data is stored in the log
dictionary as numpy arrays. Place data into
this dictionary directly without the ‘log/’ prefix and gsd will include it in
the output. Store per-particle quantities with the prefix particles/
. Choose
another prefix for other quantities.
In [26]: f = gsd.hoomd.open(name='example.gsd', mode='rb')
In [27]: s = f[0]
In [28]: s.log['particles/net_force']
Out[28]:
array([[-1., 2., -3.],
[ 0., 2., -4.],
[-3., 2., 1.],
[ 1., 2., 3.]], dtype=float32)
In [29]: s.log['value/potential_energy']
Out[29]: array([1.5])
Read logged data from the log
dictionary.
Note
Logged data must be a convertible to a numpy array of a supported type.
In [30]: with gsd.hoomd.open(name='example.gsd', mode='wb') as f:
....: s = gsd.hoomd.Snapshot()
....: s.particles.N = 4
....: s.log['invalid'] = dict(a=1, b=5)
....: f.append(s)
....:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-30-afa7e9459779> in <module>
3 s.particles.N = 4
4 s.log['invalid'] = dict(a=1, b=5)
----> 5 f.append(s)
~/checkouts/readthedocs.org/user_builds/gsd/conda/v2.4.2/lib/python3.7/site-packages/gsd-2.4.2-py3.7-linux-x86_64.egg/gsd/hoomd.py in append(self, snapshot)
754 # write log data
755 for log, data in snapshot.log.items():
--> 756 self.file.write_chunk('log/' + log, data)
757
758 self.file.end_frame()
gsd/fl.pyx in gsd.fl.GSDFile.write_chunk()
ValueError: invalid type for chunk: log/invalid
Access state data¶
In [31]: with gsd.hoomd.open(name='test2.gsd', mode='wb') as f:
....: s = gsd.hoomd.Snapshot()
....: s.particles.types = ['A', 'B']
....: s.state['hpmc/convex_polygon/N'] = [3, 4]
....: s.state['hpmc/convex_polygon/vertices'] = [[-1, -1],
....: [1, -1],
....: [1, 1],
....: [-2, -2],
....: [2, -2],
....: [2, 2],
....: [-2, 2]]
....: f.append(s)
....:
State data is stored in the state
dictionary as numpy arrays. Place data
into this dictionary directly without the ‘state/’ prefix and gsd will include
it in the output. Shape vertices are stored in a packed format. In this example,
type ‘A’ has 3 vertices (the first 3 in the list) and type ‘B’ has 4 (the next
4).
In [32]: with gsd.hoomd.open(name='test2.gsd', mode='rb') as f:
....: s = f[0]
....: print(s.state['hpmc/convex_polygon/N'])
....: print(s.state['hpmc/convex_polygon/vertices'])
....:
[3 4]
[[-1. -1.]
[ 1. -1.]
[ 1. 1.]
[-2. -2.]
[ 2. -2.]
[ 2. 2.]
[-2. 2.]]
Access read state data in the same way.
Use multiprocessing¶
import multiprocessing
def cnt_part(args):
t, frame = args
return len(t[frame].particles.position)
with gsd.hoomd.open(name='test.gsd', mode='rb') as t:
with multiprocessing.Pool(processes=multiprocessing.cpu_count()) as pool:
result = pool.map(cnt_part, [(t, frame) for frame in range(len(t))])
result
gsd.hoomd.HOOMDTrajectory
can be pickled when in read mode to allow for
multiprocessing through pythons native multiprocessing library. Here
cnt_part
finds the number of particles in each frame and appends it to a
list.
Using the command line¶
The GSD library provides a command line interface for reading files with first-class support for reading HOOMD GSD files. The CLI opens a Python interpreter with a file opened in a specified mode.
$ gsd read -s hoomd 'test.gsd'
...
File: test.gsd
Number of frames: 11
The GSD file handle is available via the "handle" variable.
For supported schema, you may access the trajectory using the "traj" variable.
Type "help(handle)" or "help(traj)" for more information.
The gsd and gsd.fl packages are always loaded.
Schema-specific modules (e.g. gsd.hoomd) are loaded if available.
>>> len(traj)
11
>>> traj[0].particles.position.shape == (4, 3)
True
>>> handle.read_chunk(0, 'particles/N')
array([4], dtype=uint32)