GSoC 2026: Week 5 & 6 - Stress Testing and Parallelization

Based on meeting discussions, it was suggested to add periodic boundary box info and energies to the Universe as well. This was done and charges have also been added on a “if exists” basis.

These weeks have been spent stress testing the integration as well as manually checking some of the MDAnalysis tools on the output Universe. Some of the tools tested were RMSD, RMSF, AlignTraj, PCA, DistanceMatrix, DensityAnalysis and LinearDensity. All of these tools successfully ran on the generated Universe, provided the given WESTPA simulation output had the required parameters.

Coming to parallelization, MDAnalysis uses its AnalysisBase backend which uses the split-apply-combine scheme to efficiently split groups to workers, compute observables, and combine all the objects from all the workers which then gets merged together giving a simular result to serial analysis.
This poses a major challenge for HDF5 files. HDF5 file handles are bound to the operating system and cannot be serialized (pickled) to be sent across different worker processes. If we try to pass an open file to a worker, Python will crash.

This is solved by:

Stripping File Handles

When MDAnalysis decides to split the workload, it uses Python’s pickle library to package up your reader and send it to the workers. Right before this happens, it call __getstate__ which intercepts this process, explicitly closes all open HDF5 file handles (self._current_h5 and self._h5), and sets their variables to None. This strips away the “unpicklable” OS-level pointers, allowing the pure data (like the frame index) to transmit safely.

def __getstate__(self):
        if self._current_h5 is not None:
            self._current_h5.close()
        if self._h5 is not None:
            self._h5.close()

        state = self.__dict__.copy()
        state['_h5'] = None
        state['_current_h5'] = None
        state['_current_path'] = None
        return state

Rebuilding the Worker’s State

When the worker process receives the package and wakes up, it calls __setstate__. The reader uses this moment to cleanly reconstruct itself in the new memory space. It re-opens the main west.h5 file restores all the attributes that sometimes gets wiped out during multiprocessing.

def __setstate__(self, state):
        self.__dict__.update(state)
        self._h5 = h5py.File(self.filename, 'r')
        self._current_h5 = None
        self._current_path = None
        if hasattr(self, 'ts') and hasattr(self, '_reader_dt'):
            self.ts.dt = self._reader_dt


With this, we can use backend=multiprocessing and give ‘n’ number of workers to perform tasks in parallel, which may run certain analysis much faster than running in serial. Checking this on InterRDF:
universe
With this in place, all goals for the midterm deadline are complete. The next task is to allow users to save back analysis data back into their westpa file as well as start work on the CLI tool which wraps the entire parser and reader and allows users to effortlessly use this tool.

Summary

  • Stress tested the reader to improve on speed.
  • Manually checked some MDAnalysis tools on the generated Universe.
  • Added periodic box info, energies and charges on a “if exists” basis.
  • Added support for running analysis using MDAnalysis’s parallelization backends.
  • Added some more testcases for this.