Skip to content

ParticleGroup.from_hdf5 - #156

Merged
ChristopherMayes merged 35 commits into
ChristopherMayes:masterfrom
electronsandstuff:pierce/from_hdf5
Sep 1, 2026
Merged

ParticleGroup.from_hdf5#156
ChristopherMayes merged 35 commits into
ChristopherMayes:masterfrom
electronsandstuff:pierce/from_hdf5

Conversation

@electronsandstuff

@electronsandstuff electronsandstuff commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Per discussion with @ChristopherMayes, this PR adds a new method .from_hdf5 to ParticleGroup with a time_offset argument. Additional cleanup is performed.

  • Add pre-commit to conda env
  • Add .vscode to .gitignore
  • Add unit tests for all existing input types for __init__ argument h5
    • Path, h5py.File, h5py.Group, "legacy" group with no species
  • New exceptions.py with custom BeamPhysics exceptions for HDF5 file load errors
  • load_bunch_data and __init__ are broken into methods to handle each atomic part of loading the only species in the only iteration of a particle group.
    • load_species_data gets the array dict from one species
    • _only_species_group loads the only species in the OpenPMD iteration passed to it (or passes through to handle "legacy" version w/o species)
    • _only_iteration_group gets the only iteration, raising on none or multiple. Handles files, groups, paths.
    • _only_iteration_only_species_group handles the file loading, existing behavior of passing through raw species group.
  • Move load_bunch_data to readers.py and keep import there for legacy support
  • Time offset loading methods
    • load_time_offset to load from an open species group
    • load_only_time_offset loads from only species from only iteration with same input semantics as .from_hdf5
  • Add t_offset to ParticleGroupt.write
  • Updated documentation
    • docs/examples/write_examples.ipynb updated to use read w/o time offset
    • docs/examples/read_examples.ipynb demostrates .from_hdf5 and time offset methods
    • New docs/api/readers.md
  • Add explicit check for openPMD attribute in root group of OpenPMD files. In ParticleGroup.__init__ warn if not valid (to preserve legacy behavior), in from_hdf5 raise.

Note: this PR also includes the changes noted in #152. It was intended as a stacked PR, but due to working out of a fork is set up to target main instead and will supersede it.

@electronsandstuff
electronsandstuff marked this pull request as ready for review August 25, 2026 07:16

@ken-lauer ken-lauer left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this looks good in general

Comment thread beamphysics/readers.py
Comment thread beamphysics/readers.py Outdated
Comment thread beamphysics/readers.py
# particle_paths returns absolute paths. Strip the leading separator so that
# they resolve relative to h5, which may itself be a group within a file.
path = paths[0].strip("/")
return h5[path] if path else h5["."]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is h5["."] just to consistently return a Group instead of the File?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But File is a subclass of Group?

(I don't see an issue with doing this, really, it's just a bit of a curiosity with respect to covariance/contrainvariance...)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

h5[""] also raises if you strip the path and it was /.

Comment thread beamphysics/readers.py
logger.debug("Loading iteration %s from %s", paths[0], h5.name)

# particle_paths returns absolute paths. Strip the leading separator so that
# they resolve relative to h5, which may itself be a group within a file.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a thing in the standard? I always assumed attrs/etc had to be at the top level

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not a part of the standard. However, I know multiple people we work with that use this as a feature.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this one of those upstream issues you had made by chance?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, no, I can add it, however.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking more into it, the standard already has a feature to allow embedding with basePath and I think asking them to allow for a second method of doing this defeats the point of a standard.

Since I know some people do this, but it's non-standards-compliant behavior and from Chris's comment earlier today, I'm going to add a warning here that this is non standards compliant, but keep it here to avoid breaking code immediately.

Comment thread beamphysics/readers.py
return value[0]


def _only_iteration_group(h5: File | Group) -> Group:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels like these specialized "load just one" helpers should be a wrapper around a more general one that walks - i.e., yields as a generator - (h5_group, iteration, species) in a given file.

I think that can wait until a future refactor.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this feels like a larger project of adding support for iterations and species - complicated, from personal experience. Let's revisit later.

Comment thread beamphysics/readers.py Outdated
Comment thread beamphysics/readers.py Outdated
Comment thread beamphysics/writers.py
electronsandstuff and others added 4 commits August 29, 2026 20:30
Comment thread beamphysics/writers.py
Comment thread beamphysics/readers.py Outdated
@electronsandstuff

Copy link
Copy Markdown
Contributor Author

I also added a warning to _only_iteration_only_species_group for the "legacy file" loading branch.

@ChristopherMayes
ChristopherMayes merged commit a77cd91 into ChristopherMayes:master Sep 1, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants