Source code for yt.frontends.gizmo.data_structures

import os

import numpy as np

from yt.frontends.gadget.data_structures import GadgetHDF5Dataset
from yt.utilities.cosmology import Cosmology
from yt.utilities.logger import ytLogger as mylog
from yt.utilities.on_demand_imports import _h5py as h5py

from .fields import GizmoFieldInfo


[docs] class GizmoDataset(GadgetHDF5Dataset): _load_requirements = ["h5py"] _field_info_class = GizmoFieldInfo @classmethod def _is_valid(cls, filename: str, *args, **kwargs) -> bool: if cls._missing_load_requirements(): return False need_groups = ["Header"] veto_groups = ["Config", "Constants", "FOF", "Group", "Subhalo"] valid = True valid_fname = filename # If passed arg is a directory, look for the .0 file in that dir if os.path.isdir(filename): valid_files = [] for f in os.listdir(filename): fname = os.path.join(filename, f) fext = os.path.splitext(fname)[-1] if ( (".0" in f) and (fext not in {".ewah", ".kdtree"}) and os.path.isfile(fname) ): valid_files.append(fname) if len(valid_files) == 0: valid = False elif len(valid_files) > 1: valid = False else: valid_fname = valid_files[0] try: fh = h5py.File(valid_fname, mode="r") valid = all(ng in fh["/"] for ng in need_groups) and not any( vg in fh["/"] for vg in veto_groups ) # From Apr 2021, 7f1f06f, public gizmo includes a header variable # GIZMO_version, which is set to the year of the most recent commit # We should prefer this to checking the metallicity, which might # not exist if "GIZMO_version" not in fh["/Header"].attrs: dmetal = "/PartType0/Metallicity" if dmetal not in fh or ( fh[dmetal].ndim > 1 and fh[dmetal].shape[1] < 11 ): valid = False fh.close() except Exception: valid = False return valid def _set_code_unit_attributes(self): super()._set_code_unit_attributes() def _parse_parameter_file(self): hvals = self._get_hvals() self.dimensionality = 3 self.refine_by = 2 self.parameters["HydroMethod"] = "sph" # Set standard values # We may have an overridden bounding box. if self.domain_left_edge is None and hvals["BoxSize"] != 0: self.domain_left_edge = np.zeros(3, "float64") self.domain_right_edge = np.ones(3, "float64") * hvals["BoxSize"] self.domain_dimensions = np.ones(3, "int32") self._periodicity = (True, True, True) self.cosmological_simulation = 1 self.current_redshift = hvals.get("Redshift", 0.0) if "Redshift" not in hvals: mylog.info("Redshift is not set in Header. Assuming z=0.") if "ComovingIntegrationOn" in hvals: # In 1d8479, Nov 2020, public GIZMO updated the names of the Omegas # to include an _, added baryons and radiation and added the # ComovingIntegrationOn field. ComovingIntegrationOn is always set, # but the Omega's are only included if ComovingIntegrationOn is true mylog.debug("Reading cosmological parameters using post-1d8479 format") self.cosmological_simulation = hvals["ComovingIntegrationOn"] if self.cosmological_simulation: self.omega_lambda = hvals["Omega_Lambda"] self.omega_matter = hvals["Omega_Matter"] self.omega_baryon = hvals["Omega_Baryon"] self.omega_radiation = hvals["Omega_Radiation"] self.hubble_constant = hvals["HubbleParam"] elif "OmegaLambda" in hvals: # Should still support GIZMO versions prior to 1d8479 too mylog.info( "ComovingIntegrationOn does not exist, falling back to OmegaLambda", ) self.omega_lambda = hvals["OmegaLambda"] self.omega_matter = hvals["Omega0"] self.hubble_constant = hvals["HubbleParam"] self.cosmological_simulation = self.omega_lambda != 0.0 else: # If these are not set it is definitely not a cosmological dataset. mylog.debug("No cosmological information found, assuming defaults") self.omega_lambda = 0.0 self.omega_matter = 0.0 # Just in case somebody asks for it. self.cosmological_simulation = 0 # Hubble is set below for Omega Lambda = 0. if not self.cosmological_simulation: mylog.info( "ComovingIntegrationOn != 1 or (not found " "and OmegaLambda is 0.0), so we are turning off Cosmology.", ) self.hubble_constant = 1.0 # So that scaling comes out correct self.current_redshift = 0.0 # This may not be correct. self.current_time = hvals["Time"] else: # Now we calculate our time based on the cosmology, because in # ComovingIntegration hvals["Time"] will in fact be the expansion # factor, not the actual integration time, so we re-calculate # global time from our Cosmology. cosmo = Cosmology( hubble_constant=self.hubble_constant, omega_matter=self.omega_matter, omega_lambda=self.omega_lambda, ) self.current_time = cosmo.lookback_time(self.current_redshift, 1e6) mylog.info( "Calculating time from %0.3e to be %0.3e seconds", hvals["Time"], self.current_time, ) self.parameters = hvals prefix = os.path.join(self.directory, self.basename.split(".", 1)[0]) if hvals["NumFiles"] > 1: self.filename_template = f"{prefix}.%(num)s{self._suffix}" else: self.filename_template = self.parameter_filename self.file_count = hvals["NumFiles"]