# Buggy code
def _count_grids(self):
    """Sets ``self.num_grids`` to be the total number of grids in the simulation.

    The number of grids is determined by their respective memory footprint.
    """
    f = self.dataset._handle
    bp = self.dataset.base_path
    mp = self.dataset.meshes_path
    pp = self.dataset.particles_path

    self.meshshapes = {}
    self.numparts = {}

    self.num_grids = 0

    for mesh in f[bp + mp].keys():
        if type(f[bp + mp + mesh]) is h5.Group:
            shape = f[bp + mp + mesh + "/" + list(f[bp + mp + mesh].keys())[0]].shape
        else:
            shape = f[bp + mp + mesh].shape
        spacing = tuple(f[bp + mp + mesh].attrs["gridSpacing"])
        offset = tuple(f[bp + mp + mesh].attrs["gridGlobalOffset"])
        unit_si = f[bp + mp + mesh].attrs["gridUnitSI"]
        self.meshshapes[mesh] = (shape, spacing, offset, unit_si)
    for species in f[bp + pp].keys():
        if "particlePatches" in f[bp + pp + "/" + species].keys():
            for patch, size in enumerate(
                f[bp + pp + "/" + species + "/particlePatches/numParticles"]
            ):
                self.numparts[species + "#" + str(patch)] = size
        else:
            axis = list(f[bp + pp + species + "/position"].keys())[0]
            if is_const_component(f[bp + pp + species + "/position/" + axis]):
                self.numparts[species] = f[
                    bp + pp + species + "/position/" + axis
                ].attrs["shape"]
            else:
                self.numparts[species] = f[
                    bp + pp + species + "/position/" + axis
                ].len()

    # Limit values per grid by resulting memory footprint
    self.vpg = int(self.dataset.gridsize / 4)  # 4Byte per value (f32)

    # Meshes of the same size do not need separate chunks
    for shape, spacing, offset, unit_si in set(self.meshshapes.values()):
        self.num_grids += min(shape[0], int(np.ceil(reduce(mul, shape) * self.vpg**-1)))

    # Same goes for particle chunks if they are not inside particlePatches
    patches = {}
    no_patches = {}
    for k, v in self.numparts.items():
        if "#" in k:
            patches[k] = v
        else:
            no_patches[k] = v
    for size in set(no_patches.values()):
        self.num_grids += int(np.ceil(size * self.vpg**-1))
    for size in patches.values():
        self.num_grids += int(np.ceil(size * self.vpg**-1))


# Traceback (KeyError)
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-6-606762cc9ee1> in <module>()
----> 1 yt.load('./example-ptcl/hdf5/data00000400.h5')

~/miniconda3/lib/python3.6/site-packages/yt/convenience.py in load(*args, **kwargs)
84     candidates = find_lowest_subclasses(candidates)
85     if len(candidates) == 1:
---> 86         return candidates[0](*args, **kwargs)
87     if len(candidates) == 0:
88         if ytcfg.get("yt", "enzo_db") != '' \

~/miniconda3/lib/python3.6/site-packages/yt/frontends/open_pmd/data_structures.py in __init__(self, filename, dataset_type, storage_filename, units_override, unit_system, **kwargs)
385         self.storage_filename = storage_filename
386         self.fluid_types += ("openPMD",)
--> 387         particles = tuple(str(c) for c in self._handle[self.base_path + self.particles_path].keys())
388         if len(particles) > 1:
389             # Only use on-disk particle names if there is more than one species

~/miniconda3/lib/python3.6/site-packages/yt/utilities/file_handler.py in __getitem__(self, key)
43
44     def __getitem__(self, key):
---> 45         return self.handle[key]
46
47     def __contains__(self, item):

h5py/_objects.pyx in h5py._objects.with_phil.wrapper (/Users/ilan/minonda/conda-bld/h5py_1496887972496/work/h5py/_objects.c:2846)()

h5py/_objects.pyx in h5py._objects.with_phil.wrapper (/Users/ilan/minonda/conda-bld/h5py_1496887972496/work/h5py/_objects.c:2804)()

~/miniconda3/lib/python3.6/site-packages/h5py/_hl/group.py in __getitem__(self, name)
167                 raise ValueError("Invalid HDF5 object reference")
168         else:
--> 169             oid = h5o.open(self.id, self._e(name), lapl=self._lapl)
170
171         otype = h5i.get_type(oid)

h5py/_objects.pyx in h5py._objects.with_phil.wrapper (/Users/ilan/minonda/conda-bld/h5py_1496887972496/work/h5py/_objects.c:2846)()

h5py/_objects.pyx in h5py._objects.with_phil.wrapper (/Users/ilan/minonda/conda-bld/h5py_1496887972496/work/h5py/_objects.c:2804)()

h5py/h5o.pyx in h5py.h5o.open (/Users/ilan/minonda/conda-bld/h5py_1496887972496/work/h5py/h5o.c:3740)()

KeyError: "Unable to open object (Object 'particles' doesn't exist)"

# Fixed code
def _count_grids(self):
    """Sets ``self.num_grids`` to be the total number of grids in the simulation.

    The number of grids is determined by their respective memory footprint.
    """
    f = self.dataset._handle
    bp = self.dataset.base_path
    mp = self.dataset.meshes_path
    pp = self.dataset.particles_path

    self.meshshapes = {}
    self.numparts = {}

    self.num_grids = 0

    try:
        meshes = f[bp + mp]
        for mname in meshes.keys():
            mesh = meshes[mname]
            if type(mesh) is h5.Group:
                shape = mesh[list(mesh.keys())[0]].shape
            else:
                shape = mesh.shape
            spacing = tuple(mesh.attrs["gridSpacing"])
            offset = tuple(mesh.attrs["gridGlobalOffset"])
            unit_si = mesh.attrs["gridUnitSI"]
            self.meshshapes[mname] = (shape, spacing, offset, unit_si)
    except KeyError:
        pass

    try:
        particles = f[bp + pp]
        for pname in particles.keys():
            species = particles[pname]
            if "particlePatches" in species.keys():
                for patch, size in enumerate(species["/particlePatches/numParticles"]):
                    self.numparts[pname + "#" + str(patch)] = size
            else:
                axis = list(species["/position"].keys())[0]
                if is_const_component(species["/position/" + axis]):
                    self.numparts[pname] = species["/position/" + axis].attrs["shape"]
                else:
                    self.numparts[pname] = species["/position/" + axis].len()
    except KeyError:
        pass

    # Limit values per grid by resulting memory footprint
    self.vpg = int(self.dataset.gridsize / 4)  # 4Byte per value (f32)

    # Meshes of the same size do not need separate chunks
    for shape, spacing, offset, unit_si in set(self.meshshapes.values()):
        self.num_grids += min(shape[0], int(np.ceil(reduce(mul, shape) * self.vpg**-1)))

    # Same goes for particle chunks if they are not inside particlePatches
    patches = {}
    no_patches = {}
    for k, v in self.numparts.items():
        if "#" in k:
            patches[k] = v
        else:
            no_patches[k] = v
    for size in set(no_patches.values()):
        self.num_grids += int(np.ceil(size * self.vpg**-1))
    for size in patches.values():
        self.num_grids += int(np.ceil(size * self.vpg**-1))