Skip to content
Back to top

# HOOMD examples

`gsd.hoomd` provides high-level access to HOOMD schema GSD files.

View the page source to find unformatted example code.

## Import the module

    In [1]: import gsd.hoomd

## Define a frame

    In [2]: frame = gsd.hoomd.Frame()

    In [3]: frame.particles.N = 4

    In [4]: frame.particles.types = ['A', 'B']

    In [5]: frame.particles.typeid = [0,0,1,1]

    In [6]: frame.particles.position = [[0,0,0],[1,1,1], [-1,-1,-1], [1,-1,-1]]

    In [7]: frame.configuration.box = [3, 3, 3, 0, 0, 0]

`gsd.hoomd.Frame` stores the state of a single system configuration, or frame, in the file. Instantiate this class to create a system configuration. All fields default to `None`. Each field is written to the file when not `None` and when the data does not match the data in the first frame or defaults specified in the schema.

## Create a hoomd gsd file

    In [8]: f = gsd.hoomd.open(name='file.gsd', mode='w')

Use `gsd.hoomd.open` to open a GSD file as a `gsd.hoomd.HOOMDTrajectory` instance.

## Write frames to a gsd file

    In [9]: def create_frame(i):
       ...:     frame = gsd.hoomd.Frame()
       ...:     frame.configuration.step = i
       ...:     frame.particles.N = 4+i
       ...:     frame.particles.position = numpy.random.random(size=(4+i,3))
       ...:     return frame
       ...:

    In [10]: f = gsd.hoomd.open(name='example.gsd', mode='w')

    In [11]: f.extend( (create_frame(i) for i in range(10)) )

    In [12]: f.append( create_frame(10) )

    In [13]: len(f)
    Out[13]: 1

`gsd.hoomd.HOOMDTrajectory` is similar to a sequence of `gsd.hoomd.Frame` objects. The `append` and `extend` methods add frames to the trajectory.

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 [14]: f = gsd.hoomd.open(name='example.gsd', mode='r')

    In [15]: frame = f[5]

    In [16]: frame.configuration.step
    Out[16]: np.uint64(5)

    In [17]: frame.particles.N
    Out[17]: np.uint32(9)

    In [18]: frame.particles.position
    Out[18]:
    array([[0.33167037, 0.49996185, 0.9227541 ],
           [0.7595035 , 0.682161  , 0.48774573],
           [0.15730919, 0.7209693 , 0.8439383 ],
           [0.83303636, 0.28049225, 0.47476554],
           [0.37031552, 0.22556333, 0.72174   ],
           [0.50900847, 0.7794539 , 0.5062351 ],
           [0.38004163, 0.2520163 , 0.17475954],
           [0.0943386 , 0.81951725, 0.20328596],
           [0.17104487, 0.90501195, 0.41239545]], dtype=float32)

`gsd.hoomd.HOOMDTrajectory` supports random indexing of frames in the file. Indexing into a trajectory returns a `gsd.hoomd.Frame`.

## Slicing and selection

Use the slicing operator to select individual frames or a subset of a trajectory.

    In [19]: f = gsd.hoomd.open(name='example.gsd', mode='r')

    In [20]: for frame in f[5:-2]:
       ....:     print(frame.configuration.step, end=' ')
       ....:
    5 6 7 8
    In [21]: every_2nd_frame = f[::2]  # create a view of a trajectory subset

    In [22]: for frame in every_2nd_frame[:4]:
       ....:     print(frame.configuration.step, end=' ')
       ....:
    0 2 4 6

Slicing a trajectory creates a trajectory view, which can then be queried for length or sliced again.

## Pure python reader

    In [23]: f = gsd.pygsd.GSDFile(open('example.gsd', 'rb'))

    In [24]: trajectory = gsd.hoomd.HOOMDTrajectory(f);

    In [25]: trajectory[3].particles.position
    Out[25]:
    array([[0.31016624, 0.9260119 , 0.0828925 ],
           [0.3706801 , 0.22477262, 0.9663977 ],
           [0.39215398, 0.51308197, 0.9026207 ],
           [0.51869553, 0.24225543, 0.11951804],
           [0.7035143 , 0.7180118 , 0.22967325],
           [0.17313758, 0.72416914, 0.91406703],
           [0.775013  , 0.70293087, 0.2959552 ]], 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 [26]: with gsd.hoomd.open(name='log-example.gsd', mode='w') as f:
       ....:     frame = gsd.hoomd.Frame()
       ....:     frame.particles.N = 4
       ....:     for i in range(10):
       ....:         frame.configuration.step = i*100
       ....:         frame.log['particles/net_force'] = numpy.array([[-1,2,-3+i],
       ....:                                                            [0,2,-4],
       ....:                                                            [-3,2,1],
       ....:                                                            [1,2,3]],
       ....:                                                           dtype=numpy.float32)
       ....:         frame.log['value/potential_energy'] = 1.5+i
       ....:         f.append(frame)
       ....:

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 [27]: log = gsd.hoomd.read_log(name='log-example.gsd', scalar_only=True)

    In [28]: list(log.keys())
    Out[28]: ['configuration/step', 'log/value/potential_energy']

    In [29]: log['log/value/potential_energy']
    Out[29]: array([ 1.5,  2.5,  3.5,  4.5,  5.5,  6.5,  7.5,  8.5,  9.5, 10.5])

    In [30]: log['configuration/step']
    Out[30]: array([  0, 100, 200, 300, 400, 500, 600, 700, 800, 900], dtype=uint64)

Read logged data from the `log` dictionary.

Note

Logged data must be a convertible to a numpy array of a supported type.

    In [31]: with gsd.hoomd.open(name='example.gsd', mode='w') as f:
       ....:     frame = gsd.hoomd.Frame()
       ....:     frame.particles.N = 4
       ....:     frame.log['invalid'] = dict(a=1, b=5)
       ....:     f.append(frame)
       ....:
    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    Cell In[31], line 5
          3 frame.particles.N = 4
          4 frame.log['invalid'] = dict(a=1, b=5)
    ----> 5 f.append(frame)

    File /build/python-gsd-xhAg2e/python-gsd-4.2.0/.pybuild/cpython3_3.13_gsd/build/gsd/hoomd.py:776, in HOOMDTrajectory.append(self, frame)
        774 # write log data
        775 for log, data in frame.log.items():
    --> 776     self.file.write_chunk('log/' + log, data)
        778 self.file.end_frame()
        780 # This implementation must be able to read back frame 0, flush it.
        781 # Allow the user to control when other frames are flushed.

    File /build/python-gsd-xhAg2e/python-gsd-4.2.0/.pybuild/cpython3_3.13_gsd/build/gsd/fl.pyx:640, in gsd.fl.GSDFile.write_chunk()
        638         data_ptr = __get_ptr_float64(data_array)
        639     else:
    --> 640         raise ValueError("invalid type for chunk: " + name)
        641
        642 if self.debug:

    ValueError: invalid type for chunk: log/invalid

## Use multiprocessing

    import multiprocessing

    def count_particles(args):
       t, frame_idx = args
       return len(t[frame_idx].particles.position)

    with gsd.hoomd.open(name='example.gsd', mode='r') as t:
       with multiprocessing.Pool(processes=multiprocessing.cpu_count()) as pool:
          result = pool.map(count_particles, [(t, frame_idx) for frame_idx in range(len(t))])

     result

`gsd.hoomd.HOOMDTrajectory` can be pickled when in read mode to allow for multiprocessing through Python’s `multiprocessing` library. Here `count_particles` 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 'example.gsd'
    ...
    File: example.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)