Repository: yt-project/yt

Issue:
REQ: Supply parameters through stream handlers
An optional parameter to the stream loaders should include the parameters to update the metadata dictionary.


Discussion:

Resolving patch:
diff --git a/yt/frontends/stream/data_structures.py b/yt/frontends/stream/data_structures.py
--- a/yt/frontends/stream/data_structures.py
+++ b/yt/frontends/stream/data_structures.py
@@ -88,6 +88,8 @@ def __init__(
         io=None,
         particle_types=None,
         periodicity=(True, True, True),
+        *,
+        parameters=None,
     ):
         if particle_types is None:
             particle_types = {}
@@ -105,6 +107,10 @@ def __init__(
         self.io = io
         self.particle_types = particle_types
         self.periodicity = periodicity
+        if parameters is None:
+            self.parameters = {}
+        else:
+            self.parameters = parameters.copy()
 
     def get_fields(self):
         return self.fields.all_fields
@@ -307,6 +313,7 @@ def _parse_parameter_file(self):
         self.parameters["CosmologyHubbleConstantNow"] = 1.0
         self.parameters["CosmologyCurrentRedshift"] = 1.0
         self.parameters["HydroMethod"] = -1
+        self.parameters.update(self.stream_handler.parameters)
         if self.stream_handler.cosmology_simulation:
             self.cosmological_simulation = 1
             self.current_redshift = self.stream_handler.current_redshift
diff --git a/yt/loaders.py b/yt/loaders.py
--- a/yt/loaders.py
+++ b/yt/loaders.py
@@ -164,6 +164,8 @@ def load_uniform_grid(
     geometry="cartesian",
     unit_system="cgs",
     default_species_fields=None,
+    *,
+    parameters=None,
 ):
     r"""Load a uniform grid of data into yt as a
     :class:`~yt.frontends.stream.data_structures.StreamHandler`.
@@ -216,6 +218,9 @@ def load_uniform_grid(
     default_species_fields : string, optional
         If set, default species fields are created for H and He which also
         determine the mean molecular weight. Options are "ionized" and "neutral".
+    parameters: dictionary, optional
+        Optional dictionary used to populate the dataset parameters, useful
+        for storing dataset metadata.
 
     Examples
     --------
@@ -316,6 +321,7 @@ def load_uniform_grid(
         (length_unit, mass_unit, time_unit, velocity_unit, magnetic_unit),
         particle_types=particle_types,
         periodicity=periodicity,
+        parameters=parameters,
     )
 
     handler.name = "UniformGridData"
@@ -363,6 +369,8 @@ def load_amr_grids(
     refine_by=2,
     unit_system="cgs",
     default_species_fields=None,
+    *,
+    parameters=None,
 ):
     r"""Load a set of grids of data into yt as a
     :class:`~yt.frontends.stream.data_structures.StreamHandler`.
@@ -424,6 +432,9 @@ def load_amr_grids(
     default_species_fields : string, optional
         If set, default species fields are created for H and He which also
         determine the mean molecular weight. Options are "ionized" and "neutral".
+    parameters: dictionary, optional
+        Optional dictionary used to populate the dataset parameters, useful
+        for storing dataset metadata.
 
     Examples
     --------
@@ -541,6 +552,7 @@ def load_amr_grids(
         (length_unit, mass_unit, time_unit, velocity_unit, magnetic_unit),
         particle_types=particle_types,
         periodicity=periodicity,
+        parameters=parameters,
     )
 
     handler.name = "AMRGridData"
@@ -581,6 +593,8 @@ def load_particles(
     unit_system="cgs",
     data_source=None,
     default_species_fields=None,
+    *,
+    parameters=None,
 ):
     r"""Load a set of particles into yt as a
     :class:`~yt.frontends.stream.data_structures.StreamParticleHandler`.
@@ -627,6 +641,9 @@ def load_particles(
     default_species_fields : string, optional
         If set, default species fields are created for H and He which also
         determine the mean molecular weight. Options are "ionized" and "neutral".
+    parameters: dictionary, optional
+        Optional dictionary used to populate the dataset parameters, useful
+        for storing dataset metadata.
 
     Examples
     --------
@@ -721,6 +738,7 @@ def parse_unit(unit, dimension):
         (length_unit, mass_unit, time_unit, velocity_unit, magnetic_unit),
         particle_types=particle_types,
         periodicity=periodicity,
+        parameters=parameters,
     )
 
     handler.name = "ParticleData"
@@ -756,6 +774,8 @@ def load_hexahedral_mesh(
     periodicity=(True, True, True),
     geometry="cartesian",
     unit_system="cgs",
+    *,
+    parameters=None,
 ):
     r"""Load a hexahedral mesh of data into yt as a
     :class:`~yt.frontends.stream.data_structures.StreamHandler`.
@@ -806,7 +826,9 @@ def load_hexahedral_mesh(
         be z, x, y, this would be: ("cartesian", ("z", "x", "y")).  The same
         can be done for other coordinates, for instance:
         ("spherical", ("theta", "phi", "r")).
-
+    parameters: dictionary, optional
+        Optional dictionary used to populate the dataset parameters, useful
+        for storing dataset metadata.
     """
     from yt.frontends.stream.data_structures import (
         StreamDictFieldHandler,
@@ -867,6 +889,7 @@ def load_hexahedral_mesh(
         (length_unit, mass_unit, time_unit, velocity_unit, magnetic_unit),
         particle_types=particle_types,
         periodicity=periodicity,
+        parameters=parameters,
     )
 
     handler.name = "HexahedralMeshData"
@@ -899,6 +922,8 @@ def load_octree(
     partial_coverage=1,
     unit_system="cgs",
     default_species_fields=None,
+    *,
+    parameters=None,
 ):
     r"""Load an octree mask into yt.
 
@@ -946,6 +971,9 @@ def load_octree(
         determine the mean molecular weight. Options are "ionized" and "neutral".
     num_zones : int
         The number of zones along each dimension in an oct
+    parameters: dictionary, optional
+        Optional dictionary used to populate the dataset parameters, useful
+        for storing dataset metadata.
 
     Example
     -------
@@ -1024,6 +1052,7 @@ def load_octree(
         (length_unit, mass_unit, time_unit, velocity_unit, magnetic_unit),
         particle_types=particle_types,
         periodicity=periodicity,
+        parameters=parameters,
     )
 
     handler.name = "OctreeData"
@@ -1060,6 +1089,8 @@ def load_unstructured_mesh(
     periodicity=(False, False, False),
     geometry="cartesian",
     unit_system="cgs",
+    *,
+    parameters=None,
 ):
     r"""Load an unstructured mesh of data into yt as a
     :class:`~yt.frontends.stream.data_structures.StreamHandler`.
@@ -1130,6 +1161,9 @@ def load_unstructured_mesh(
         be z, x, y, this would be: ("cartesian", ("z", "x", "y")).  The same
         can be done for other coordinates, for instance:
         ("spherical", ("theta", "phi", "r")).
+    parameters: dictionary, optional
+        Optional dictionary used to populate the dataset parameters, useful
+        for storing dataset metadata.
 
     Examples
     --------
@@ -1259,6 +1293,7 @@ def load_unstructured_mesh(
         (length_unit, mass_unit, time_unit, velocity_unit, magnetic_unit),
         particle_types=particle_types,
         periodicity=periodicity,
+        parameters=parameters,
     )
 
     handler.name = "UnstructuredMeshData"


Test patch:
diff --git a/yt/frontends/stream/tests/test_outputs.py b/yt/frontends/stream/tests/test_outputs.py
--- a/yt/frontends/stream/tests/test_outputs.py
+++ b/yt/frontends/stream/tests/test_outputs.py
@@ -73,3 +73,14 @@ def load_particle_fields_mismatch():
         load_particles(data)
 
     assert_raises(YTInconsistentParticleFieldShape, load_particle_fields_mismatch)
+
+
+def test_parameters():
+    # simple test to check that we can pass in parameters
+    Z = np.random.uniform(size=(32, 32, 32))
+    d = np.random.uniform(size=(32, 32, 32))
+
+    data = {"density": d, "metallicity": Z}
+
+    ds = load_uniform_grid(data, (32, 32, 32), parameters={"metadata_is_nice": True})
+    assert ds.parameters["metadata_is_nice"]