Writing a reader plugin

Readers are discovered via the astrosylva.readers entry-point group. Adding one is three small pieces of work: subclass astrosylva.readers.TreeReader, register an entry point, and yield astrosylva.Forest objects.

Skeleton

from astrosylva.readers import TreeReader
from astrosylva.schema import HALO_DTYPE, Forest, Metadata

class MyReader(TreeReader):
    name = "myformat"
    aliases = ("mf",)

    def metadata(self) -> Metadata:
        return Metadata(cosmology={"HubbleParam": 0.7})

    def __len__(self) -> int:
        return self._n_forests

    def __iter__(self):
        for forest_id, halos in self._walk():
            yield Forest(forest_id=forest_id, halos=halos)

Entry point

In pyproject.toml:

[project.entry-points."astrosylva.readers"]
myformat = "mypkg.reader:MyReader"

Reader responsibilities

A reader must:

  1. Convert all units to the canonical ones documented in Canonical schema.

  2. Remap “no host” sentinels to hostIndex == nodeIndex.

  3. Populate any metadata it can introspect from its input.

  4. Validate its required source keys via astrosylva.readers.ReaderSource.require().

Bundled readers

Reader

Required source keys

consistent_trees

input_path, forests_path, locations_path

lhalotree

tree_file (single) or tree_files (list)

sublink

tree_file (single) or tree_files (list)

ahf

snapshots (list of dicts)

LHaloTree

Reads the 104-byte Millennium / L-Galaxies binary halo struct. Each tree in the LHaloTree file maps to one Galacticus Forest; local pointers (Descendant, FirstHaloInFOFgroup) are rewritten into a global nodeIndex space (a running counter across trees and chunks). Scale-factor lookup uses the same options as SubLink (snapshot_table / scale_factors / redshifts, strict_scale_factors).

Status: proxies in use. scaleRadius comes from SubHalfMass (half-mass radius), angularMomentum from the Spin vector (Millennium’s specific-J), and dimensionless spin is left at 0.0.