[yt-svn] commit/yt: 19 new changesets
commits-noreply at bitbucket.org
commits-noreply at bitbucket.org
Tue Jun 27 11:15:06 PDT 2017
19 new commits in yt:
https://bitbucket.org/yt_analysis/yt/commits/b7d230b3c819/
Changeset: b7d230b3c819
User: brittonsmith
Date: 2017-06-05 04:13:34+00:00
Summary: Adding Enzo-P frontend.
Affected #: 8 files
diff -r 2848c2031acc2b429d4effd45c4abf70d215cc80 -r b7d230b3c819c2fde33f9deafb57724d14426dd5 yt/frontends/api.py
--- a/yt/frontends/api.py
+++ b/yt/frontends/api.py
@@ -25,6 +25,7 @@
'chombo',
'eagle',
'enzo',
+ 'enzo_p',
'exodus_ii',
'fits',
'flash',
diff -r 2848c2031acc2b429d4effd45c4abf70d215cc80 -r b7d230b3c819c2fde33f9deafb57724d14426dd5 yt/frontends/enzo_p/api.py
--- /dev/null
+++ b/yt/frontends/enzo_p/api.py
@@ -0,0 +1,26 @@
+"""
+API for yt.frontends.enzo_p
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2017, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+from .data_structures import \
+ EnzoPGrid, \
+ EnzoPHierarchy, \
+ EnzoPDataset
+
+from .fields import \
+ EnzoPFieldInfo
+add_enzop_field = EnzoPFieldInfo.add_field
+
+from .io import \
+ EPIOHandler
diff -r 2848c2031acc2b429d4effd45c4abf70d215cc80 -r b7d230b3c819c2fde33f9deafb57724d14426dd5 yt/frontends/enzo_p/data_structures.py
--- /dev/null
+++ b/yt/frontends/enzo_p/data_structures.py
@@ -0,0 +1,353 @@
+"""
+Data structures for Enzo-P
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2017, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+from yt.utilities.on_demand_imports import \
+ _h5py as h5py
+import numpy as np
+import os
+import stat
+
+from yt.funcs import \
+ ensure_tuple, \
+ get_pbar, \
+ setdefaultattr
+from yt.data_objects.grid_patch import \
+ AMRGridPatch
+from yt.data_objects.static_output import \
+ Dataset
+from yt.fields.field_info_container import \
+ NullFunc
+from yt.geometry.grid_geometry_handler import \
+ GridIndex
+from yt.utilities.logger import \
+ ytLogger as mylog
+
+from .fields import \
+ EnzoPFieldInfo
+
+from yt.frontends.enzo_p.misc import \
+ get_block_info, \
+ get_root_blocks, \
+ get_root_block_id
+
+class EnzoPGrid(AMRGridPatch):
+ """
+ Class representing a single EnzoP Grid instance.
+ """
+
+ def __init__(self, id, index, block_name, filename = None):
+ """
+ Returns an instance of EnzoPGrid with *id*, associated with
+ *filename* and *index*.
+ """
+ # All of the field parameters will be passed to us as needed.
+ AMRGridPatch.__init__(self, id, filename=filename, index=index)
+ self.block_name = block_name
+ self._children_ids = []
+ self._parent_id = -1
+ self.Level = -1
+
+ def __repr__(self):
+ return "EnzoPBlock_%s" % self.block_name
+
+ @property
+ def Parent(self):
+ if self._parent_id == -1: return None
+ return self.index.grids[self._parent_id - self._id_offset]
+
+ @property
+ def Children(self):
+ return [self.index.grids[cid - self._id_offset]
+ for cid in self._children_ids]
+
+class EnzoPHierarchy(GridIndex):
+
+ _strip_path = False
+ grid = EnzoPGrid
+ _preload_implemented = True
+
+ def __init__(self, ds, dataset_type):
+
+ self.dataset_type = dataset_type
+ self.directory = os.path.dirname(ds.parameter_filename)
+ self.index_filename = ds.parameter_filename
+ if os.path.getsize(self.index_filename) == 0:
+ raise IOError(-1,"File empty", self.index_filename)
+
+ GridIndex.__init__(self, ds, dataset_type)
+ self.dataset.dataset_type = self.dataset_type
+
+ def _count_grids(self):
+ fblock_size = 32768
+ f = open(self.ds.parameter_filename, "r")
+ file_size = f.seek(0, 2)
+ nblocks = np.ceil(float(file_size) /
+ fblock_size).astype(np.int64)
+ offset = f.seek(0)
+ ngrids = 0
+ for ib in range(nblocks):
+ my_block = min(fblock_size, file_size - offset)
+ buff = f.read(my_block)
+ ngrids += buff.count("\n")
+ offset += my_block
+ f.close()
+ self.num_grids = ngrids
+ self.dataset_type = "enzo_p"
+
+ def _parse_index(self):
+ self.grids = np.empty(self.num_grids, dtype='object')
+
+ pbar = get_pbar("Parsing Hierarchy ", self.num_grids)
+ f = open(self.ds.parameter_filename, "r")
+ fblock_size = 32768
+ file_size = f.seek(0, 2)
+ nblocks = np.ceil(float(file_size) /
+ fblock_size).astype(np.int64)
+ offset = f.seek(0)
+ lstr = ""
+ # place child blocks after the root blocks
+ rbdim = self.ds.root_block_dimensions
+ nroot_blocks = rbdim.prod()
+ child_id = nroot_blocks
+ child_id_queue = np.empty((self.num_grids - nroot_blocks, 2),
+ dtype=np.int64)
+
+ slope = self.ds.domain_width / \
+ self.ds.arr(np.ones(3), "code_length")
+
+ for ib in range(nblocks):
+ fblock = min(fblock_size, file_size - offset)
+ buff = lstr + f.read(fblock)
+ bnl = 0
+ for inl in range(buff.count("\n")):
+ nnl = buff.find("\n", bnl)
+ line = buff[bnl:nnl]
+ block_name, block_file = line.split()
+ level, left, right = get_block_info(block_name)
+
+ rbindex = get_root_block_id(block_name)
+ rbid = rbindex[0] * rbdim[1:].prod() + \
+ rbindex[1] * rbdim[2:].prod() + rbindex[2]
+ if level == 0:
+ grid_id = rbid
+ parent_id = -1
+ else:
+ grid_id = child_id
+ parent_id = rbid
+ # Queue up the child ids and set them later
+ # when all the grids have been created.
+ child_id_queue[child_id - nroot_blocks] = \
+ rbid, child_id
+ child_id += 1
+
+ my_grid = self.grid(
+ grid_id, self, block_name,
+ filename=os.path.join(self.directory, block_file))
+ my_grid.Level = level
+ my_grid._parent_id = parent_id
+
+ self.grids[grid_id] = my_grid
+ self.grid_levels[grid_id] = level
+ self.grid_left_edge[grid_id] = left
+ self.grid_right_edge[grid_id] = right
+ self.grid_dimensions[grid_id] = self.ds.active_grid_dimensions
+
+ bnl = nnl + 1
+ pbar.update(1)
+ lstr = buff[bnl:]
+ offset += fblock
+
+ f.close()
+ pbar.finish()
+
+ self.grid_left_edge = self.grid_left_edge * slope + \
+ self.ds.domain_left_edge
+ self.grid_right_edge = self.grid_right_edge * slope + \
+ self.ds.domain_left_edge
+
+ for rbid, child_id in child_id_queue:
+ self.grids[rbid]._children_ids.append(child_id)
+
+ def _populate_grid_objects(self):
+ for g in self.grids:
+ g._prepare_grid()
+ g._setup_dx()
+ self.max_level = self.grid_levels.max()
+
+ def _setup_derived_fields(self):
+ super(EnzoPHierarchy, self)._setup_derived_fields()
+ for fname, field in self.ds.field_info.items():
+ if not field.particle_type: continue
+ if isinstance(fname, tuple): continue
+ if field._function is NullFunc: continue
+
+ def _detect_output_fields(self):
+ self.field_list = []
+ # Do this only on the root processor to save disk work.
+ if self.comm.rank in (0, None):
+ mylog.info("Gathering a field list (this may take a moment.)")
+ field_list = set()
+ random_sample = self._generate_random_grids()
+ for grid in random_sample:
+ if not hasattr(grid, 'filename'): continue
+ try:
+ gf = self.io._read_field_names(grid)
+ except self.io._read_exception:
+ raise IOError("Grid %s is a bit funky?", grid.id)
+ mylog.debug("Grid %s has: %s", grid.id, gf)
+ field_list = field_list.union(gf)
+ if "AppendActiveParticleType" in self.dataset.parameters:
+ ap_fields = self._detect_active_particle_fields()
+ field_list = list(set(field_list).union(ap_fields))
+ if not any(f[0] == 'io' for f in field_list):
+ if 'io' in self.dataset.particle_types_raw:
+ ptypes_raw = list(self.dataset.particle_types_raw)
+ ptypes_raw.remove('io')
+ self.dataset.particle_types_raw = tuple(ptypes_raw)
+
+ if 'io' in self.dataset.particle_types:
+ ptypes = list(self.dataset.particle_types)
+ ptypes.remove('io')
+ self.dataset.particle_types = tuple(ptypes)
+ ptypes = self.dataset.particle_types
+ ptypes_raw = self.dataset.particle_types_raw
+ else:
+ field_list = None
+ ptypes = None
+ ptypes_raw = None
+ self.field_list = list(self.comm.mpi_bcast(field_list))
+ self.dataset.particle_types = list(self.comm.mpi_bcast(ptypes))
+ self.dataset.particle_types_raw = list(self.comm.mpi_bcast(ptypes_raw))
+
+ def _generate_random_grids(self):
+ if self.num_grids > 40:
+ starter = np.random.randint(0, 20)
+ random_sample = np.mgrid[starter:len(self.grids)-1:20j].astype("int32")
+ # We also add in a bit to make sure that some of the grids have
+ # particles
+ gwp = self.grid_particle_count > 0
+ if np.any(gwp) and not np.any(gwp[(random_sample,)]):
+ # We just add one grid. This is not terribly efficient.
+ first_grid = np.where(gwp)[0][0]
+ random_sample.resize((21,))
+ random_sample[-1] = first_grid
+ mylog.debug("Added additional grid %s", first_grid)
+ mylog.debug("Checking grids: %s", random_sample.tolist())
+ else:
+ random_sample = np.mgrid[0:max(len(self.grids),1)].astype("int32")
+ return self.grids[(random_sample,)]
+
+class EnzoPDataset(Dataset):
+ """
+ Enzo-P-specific output, set at a fixed time.
+ """
+ _index_class = EnzoPHierarchy
+ _field_info_class = EnzoPFieldInfo
+
+ def __init__(self, filename, dataset_type=None,
+ file_style = None,
+ parameter_override = None,
+ conversion_override = None,
+ storage_filename = None,
+ units_override=None,
+ unit_system="cgs"):
+ """
+ This class is a stripped down class that simply reads and parses
+ *filename* without looking at the index. *dataset_type* gets passed
+ to the index to pre-determine the style of data-output. However,
+ it is not strictly necessary. Optionally you may specify a
+ *parameter_override* dictionary that will override anything in the
+ paarmeter file and a *conversion_override* dictionary that consists
+ of {fieldname : conversion_to_cgs} that will override the #DataCGS.
+ """
+ self.fluid_types += ("enzop",)
+ if parameter_override is None: parameter_override = {}
+ self._parameter_override = parameter_override
+ if conversion_override is None: conversion_override = {}
+ self._conversion_override = conversion_override
+ self.storage_filename = storage_filename
+ Dataset.__init__(self, filename, dataset_type, file_style=file_style,
+ units_override=units_override, unit_system=unit_system)
+
+ def _parse_parameter_file(self):
+ """
+ Parses the parameter file and establishes the various
+ dictionaries.
+ """
+
+ f = open(self.parameter_filename, "r")
+ # get dimension from first block name
+ b0, fn0 = f.readline().strip().split()
+ level0, left0, right0 = get_block_info(b0, min_dim=0)
+ root_blocks = get_root_blocks(b0)
+ f.close()
+ self.dimensionality = left0.size
+ self.periodicity = \
+ ensure_tuple(np.ones(self.dimensionality, dtype=bool))
+
+ fh = h5py.File(os.path.join(self.directory, fn0), "r")
+ self.domain_left_edge = fh.attrs["lower"]
+ self.domain_right_edge = fh.attrs["upper"]
+
+ # all blocks are the same size
+ ablock = fh[list(fh.keys())[0]]
+ self.current_time = ablock.attrs["time"][0]
+ gsi = ablock.attrs["enzo_GridStartIndex"]
+ gei = ablock.attrs["enzo_GridEndIndex"]
+ self.ghost_zones = gsi[0]
+ self.root_block_dimensions = root_blocks
+ self.active_grid_dimensions = gei - gsi + 1
+ self.grid_dimensions = ablock.attrs["enzo_GridDimension"]
+ self.domain_dimensions = root_blocks * self.active_grid_dimensions
+ fh.close()
+
+ self.periodicity += (False, ) * (3 - self.dimensionality)
+
+ # WIP hard-coded for now
+ self.refine_by = 2
+ self.cosmological_simulation = 0
+ self.gamma = 5. / 3.
+ self.particle_types = ()
+ self.particle_types_raw = self.particle_types
+ self.unique_identifier = \
+ str(int(os.stat(self.parameter_filename)[stat.ST_CTIME]))
+
+ def _set_code_unit_attributes(self):
+ setdefaultattr(self, 'length_unit', self.quan(1, "cm"))
+ setdefaultattr(self, 'mass_unit', self.quan(1, "g"))
+ setdefaultattr(self, 'time_unit', self.quan(1, "s"))
+ setdefaultattr(self, 'velocity_unit',
+ self.length_unit / self.time_unit)
+ magnetic_unit = np.sqrt(4*np.pi * self.mass_unit /
+ (self.time_unit**2 * self.length_unit))
+ magnetic_unit = np.float64(magnetic_unit.in_cgs())
+ setdefaultattr(self, 'magnetic_unit',
+ self.quan(magnetic_unit, "gauss"))
+
+ @classmethod
+ def _is_valid(cls, *args, **kwargs):
+ fn = args[0]
+ ddir = os.path.dirname(fn)
+ if not fn.endswith(".block_list"):
+ return False
+ try:
+ with open(fn, "r") as f:
+ block, block_file = f.readline().strip().split()
+ get_block_info(block)
+ if not os.path.exists(os.path.join(ddir, block_file)):
+ return False
+ except:
+ return False
+ return True
diff -r 2848c2031acc2b429d4effd45c4abf70d215cc80 -r b7d230b3c819c2fde33f9deafb57724d14426dd5 yt/frontends/enzo_p/definitions.py
--- /dev/null
+++ b/yt/frontends/enzo_p/definitions.py
@@ -0,0 +1,15 @@
+"""
+Definitions specific to Enzo-P
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2017, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
diff -r 2848c2031acc2b429d4effd45c4abf70d215cc80 -r b7d230b3c819c2fde33f9deafb57724d14426dd5 yt/frontends/enzo_p/fields.py
--- /dev/null
+++ b/yt/frontends/enzo_p/fields.py
@@ -0,0 +1,64 @@
+"""
+Fields specific to Enzo-P
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+from yt.fields.field_info_container import \
+ FieldInfoContainer
+
+rho_units = "code_mass / code_length**3"
+vel_units = "code_velocity"
+acc_units = "code_velocity / code_time"
+energy_units = "code_velocity**2"
+
+known_species_names = {
+}
+
+NODAL_FLAGS = {
+ 'BxF': [1, 0, 0],
+ 'ByF': [0, 1, 0],
+ 'BzF': [0, 0, 1],
+ 'Ex': [0, 1, 1],
+ 'Ey': [1, 0, 1],
+ 'Ez': [1, 1, 0],
+ 'AvgElec0': [0, 1, 1],
+ 'AvgElec1': [1, 0, 1],
+ 'AvgElec2': [1, 1, 0],
+}
+
+class EnzoPFieldInfo(FieldInfoContainer):
+ known_other_fields = (
+ ("velocity_x", (vel_units, ["velocity_x"], None)),
+ ("velocity_y", (vel_units, ["velocity_y"], None)),
+ ("velocity_z", (vel_units, ["velocity_z"], None)),
+ ("acceleration_x", (acc_units, ["acceleration_x"], None)),
+ ("acceleration_y", (acc_units, ["acceleration_y"], None)),
+ ("acceleration_z", (acc_units, ["acceleration_z"], None)),
+ ("density", (rho_units, ["density"], None)),
+ ("total_density", (rho_units, ["total_density"], None)),
+ ("total_energy", (energy_units, ["total_energy"], None)),
+ ("internal_energy", (energy_units, ["internal_energy"], None)),
+ )
+
+ known_particle_fields = (
+ ("x", ("code_length", [], None)),
+ ("y", ("code_length", [], None)),
+ ("z", ("code_length", [], None)),
+ ("vx", (vel_units, [], None)),
+ ("vy", (vel_units, [], None)),
+ ("vz", (vel_units, [], None)),
+ ("ax", (acc_units, [], None)),
+ ("ay", (acc_units, [], None)),
+ ("az", (acc_units, [], None)),
+ ("mass", ("code_mass", [], None)),
+ )
diff -r 2848c2031acc2b429d4effd45c4abf70d215cc80 -r b7d230b3c819c2fde33f9deafb57724d14426dd5 yt/frontends/enzo_p/io.py
--- /dev/null
+++ b/yt/frontends/enzo_p/io.py
@@ -0,0 +1,160 @@
+"""
+Enzo-P-specific IO functions
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2017, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+from yt.utilities.io_handler import \
+ BaseIOHandler
+from yt.utilities.logger import ytLogger as mylog
+from yt.extern.six import b, iteritems
+from yt.utilities.on_demand_imports import _h5py as h5py
+from yt.geometry.selection_routines import GridSelector
+import numpy as np
+
+
+_convert_mass = ("particle_mass","mass")
+
+_particle_position_names = {}
+
+class EPIOHandler(BaseIOHandler):
+
+ _dataset_type = "enzo_p"
+ _base = slice(None)
+ _field_dtype = "float64"
+
+ def __init__(self, *args, **kwargs):
+ super(EPIOHandler, self).__init__(*args, **kwargs)
+ self._base = self.ds.dimensionality * \
+ (slice(self.ds.ghost_zones,
+ -self.ds.ghost_zones),)
+
+ def _read_field_names(self, grid):
+ if grid.filename is None: return []
+ f = h5py.File(grid.filename, "r")
+ try:
+ group = f[grid.block_name]
+ except KeyError:
+ group = f
+ fields = []
+ dtypes = set([])
+ for name, v in iteritems(group):
+ if not hasattr(v, "shape") or v.dtype == "O":
+ continue
+ # mesh fields are "field <name>"
+ if name.startswith("field"):
+ dummy, fname = name.split(maxsplit=1)
+ fields.append(("enzop", fname))
+ dtypes.add(v.dtype)
+ # particle fields are "particle <type><name>"
+ else:
+ dummy, ftype, fname = name.split(maxsplit=2)
+ fields.append((ftype, fname))
+
+ if len(dtypes) == 1:
+ # Now, if everything we saw was the same dtype, we can go ahead and
+ # set it here. We do this because it is a HUGE savings for 32 bit
+ # floats, since our numpy copying/casting is way faster than
+ # h5py's, for some reason I don't understand. This does *not* need
+ # to be correct -- it will get fixed later -- it just needs to be
+ # okay for now.
+ self._field_dtype = list(dtypes)[0]
+ f.close()
+ return fields
+
+ @property
+ def _read_exception(self):
+ return (KeyError,)
+
+ def _read_particle_coords(self, chunks, ptf):
+ for rv in self._read_particle_fields(chunks, ptf, None):
+ yield rv
+
+ def _read_particle_fields(self, chunks, ptf, selector):
+ chunks = list(chunks)
+ for chunk in chunks: # These should be organized by grid filename
+ f = None
+ for g in chunk.objs:
+ if g.filename is None: continue
+ if f is None:
+ f = h5py.File(g.filename, "r")
+ nap = sum(g.NumberOfActiveParticles.values())
+ if g.NumberOfParticles == 0 and nap == 0:
+ continue
+ ds = f.get(g.block_name)
+ for ptype, field_list in sorted(ptf.items()):
+ if ptype != "io":
+ if g.NumberOfActiveParticles[ptype] == 0: continue
+ pds = ds.get("Particles/%s" % ptype)
+ else:
+ pds = ds
+ pn = _particle_position_names.get(ptype,
+ r"particle_position_%s")
+ x, y, z = (np.asarray(pds.get(pn % ax).value, dtype="=f8")
+ for ax in 'xyz')
+ if selector is None:
+ # This only ever happens if the call is made from
+ # _read_particle_coords.
+ yield ptype, (x, y, z)
+ continue
+ mask = selector.select_points(x, y, z, 0.0)
+ if mask is None: continue
+ for field in field_list:
+ data = np.asarray(pds.get(field).value, "=f8")
+ if field in _convert_mass:
+ data *= g.dds.prod(dtype="f8")
+ yield (ptype, field), data[mask]
+ if f: f.close()
+
+ def io_iter(self, chunks, fields):
+ for chunk in chunks:
+ fid = None
+ filename = -1
+ for obj in chunk.objs:
+ if obj.filename is None: continue
+ if obj.filename != filename:
+ # Note one really important thing here: even if we do
+ # implement LRU caching in the _read_obj_field function,
+ # we'll still be doing file opening and whatnot. This is a
+ # problem, but one we can return to.
+ if fid is not None:
+ fid.close()
+ fid = h5py.h5f.open(b(obj.filename), h5py.h5f.ACC_RDONLY)
+ filename = obj.filename
+ for field in fields:
+ data = None
+ yield field, obj, self._read_obj_field(
+ obj, field, (fid, data))
+ if fid is not None:
+ fid.close()
+
+ def _read_obj_field(self, obj, field, fid_data):
+ if fid_data is None: fid_data = (None, None)
+ fid, data = fid_data
+ if fid is None:
+ close = True
+ fid = h5py.h5f.open(b(obj.filename), h5py.h5f.ACC_RDONLY)
+ else:
+ close = False
+ ftype, fname = field
+ node = "/%s/field %s" % (obj.block_name, fname)
+ dg = h5py.h5d.open(fid, b(node))
+ rdata = np.empty(self.ds.grid_dimensions[:self.ds.dimensionality],
+ dtype=self._field_dtype)
+ dg.read(h5py.h5s.ALL, h5py.h5s.ALL, rdata)
+ if close:
+ fid.close()
+ data = rdata[self._base].T
+ if self.ds.dimensionality < 3:
+ nshape = data.shape + (1,)*(3 - self.ds.dimensionality)
+ data = np.reshape(data, nshape)
+ return data
diff -r 2848c2031acc2b429d4effd45c4abf70d215cc80 -r b7d230b3c819c2fde33f9deafb57724d14426dd5 yt/frontends/enzo_p/misc.py
--- /dev/null
+++ b/yt/frontends/enzo_p/misc.py
@@ -0,0 +1,62 @@
+"""
+Miscellaneous functions that are Enzo-P-specific
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2017, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+import numpy as np
+
+def bdecode(block):
+ if ":" in block:
+ level = len(block) - block.find(":") - 1
+ else:
+ level = 0
+ bst = block.replace(":", "")
+ d = float(2**len(bst))
+ left = int(bst, 2)
+ right = left + 1
+ left /= d
+ right /= d
+ return level, left, right
+
+def get_block_info(block, min_dim=3):
+ mybs = block[1:].split("_")
+ dim = max(len(mybs), min_dim)
+ left = np.zeros(dim)
+ right = np.ones(dim)
+ for i, myb in enumerate(mybs):
+ level, left[i], right[i] = bdecode(myb)
+ return level, left, right
+
+def get_root_blocks(block, min_dim=3):
+ mybs = block[1:].split("_")
+ dim = max(len(mybs), min_dim)
+ nb = np.ones(dim, dtype=int)
+ for i, myb in enumerate(mybs):
+ if ":" in myb:
+ s = myb.find(":")
+ else:
+ s = len(myb)
+ nb[i] = 2**s
+ return nb
+
+def get_root_block_id(block, min_dim=3):
+ mybs = block[1:].split("_")
+ dim = max(len(mybs), min_dim)
+ rbid = np.zeros(dim, dtype=int)
+ for i, myb in enumerate(mybs):
+ if ":" in myb:
+ s = myb.find(":")
+ else:
+ s = len(myb)
+ rbid[i] = int(myb[:s], 2)
+ return rbid
https://bitbucket.org/yt_analysis/yt/commits/d4099de18b00/
Changeset: d4099de18b00
User: brittonsmith
Date: 2017-06-10 15:02:25+00:00
Summary: Make id_offset zero.
Affected #: 1 file
diff -r b7d230b3c819c2fde33f9deafb57724d14426dd5 -r d4099de18b00698f234f0d38659ff1fa7d37ad1d yt/frontends/enzo_p/data_structures.py
--- a/yt/frontends/enzo_p/data_structures.py
+++ b/yt/frontends/enzo_p/data_structures.py
@@ -47,6 +47,8 @@
Class representing a single EnzoP Grid instance.
"""
+ _id_offset = 0
+
def __init__(self, id, index, block_name, filename = None):
"""
Returns an instance of EnzoPGrid with *id*, associated with
https://bitbucket.org/yt_analysis/yt/commits/d9901478d1a3/
Changeset: d9901478d1a3
User: brittonsmith
Date: 2017-06-10 15:05:32+00:00
Summary: Removing unused code and fixing some naming conventions.
Affected #: 4 files
diff -r d4099de18b00698f234f0d38659ff1fa7d37ad1d -r d9901478d1a32df4b1c39bca38b6de51f86280d9 yt/frontends/enzo_p/api.py
--- a/yt/frontends/enzo_p/api.py
+++ b/yt/frontends/enzo_p/api.py
@@ -23,4 +23,4 @@
add_enzop_field = EnzoPFieldInfo.add_field
from .io import \
- EPIOHandler
+ EnzoPIOHandler
diff -r d4099de18b00698f234f0d38659ff1fa7d37ad1d -r d9901478d1a32df4b1c39bca38b6de51f86280d9 yt/frontends/enzo_p/data_structures.py
--- a/yt/frontends/enzo_p/data_structures.py
+++ b/yt/frontends/enzo_p/data_structures.py
@@ -62,7 +62,7 @@
self.Level = -1
def __repr__(self):
- return "EnzoPBlock_%s" % self.block_name
+ return "EnzoPGrid_%04d" % self.id
@property
def Parent(self):
diff -r d4099de18b00698f234f0d38659ff1fa7d37ad1d -r d9901478d1a32df4b1c39bca38b6de51f86280d9 yt/frontends/enzo_p/fields.py
--- a/yt/frontends/enzo_p/fields.py
+++ b/yt/frontends/enzo_p/fields.py
@@ -24,18 +24,6 @@
known_species_names = {
}
-NODAL_FLAGS = {
- 'BxF': [1, 0, 0],
- 'ByF': [0, 1, 0],
- 'BzF': [0, 0, 1],
- 'Ex': [0, 1, 1],
- 'Ey': [1, 0, 1],
- 'Ez': [1, 1, 0],
- 'AvgElec0': [0, 1, 1],
- 'AvgElec1': [1, 0, 1],
- 'AvgElec2': [1, 1, 0],
-}
-
class EnzoPFieldInfo(FieldInfoContainer):
known_other_fields = (
("velocity_x", (vel_units, ["velocity_x"], None)),
diff -r d4099de18b00698f234f0d38659ff1fa7d37ad1d -r d9901478d1a32df4b1c39bca38b6de51f86280d9 yt/frontends/enzo_p/io.py
--- a/yt/frontends/enzo_p/io.py
+++ b/yt/frontends/enzo_p/io.py
@@ -26,14 +26,14 @@
_particle_position_names = {}
-class EPIOHandler(BaseIOHandler):
+class EnzoPIOHandler(BaseIOHandler):
_dataset_type = "enzo_p"
_base = slice(None)
_field_dtype = "float64"
def __init__(self, *args, **kwargs):
- super(EPIOHandler, self).__init__(*args, **kwargs)
+ super(EnzoPIOHandler, self).__init__(*args, **kwargs)
self._base = self.ds.dimensionality * \
(slice(self.ds.ghost_zones,
-self.ds.ghost_zones),)
https://bitbucket.org/yt_analysis/yt/commits/86012baa2428/
Changeset: 86012baa2428
User: brittonsmith
Date: 2017-06-10 16:27:45+00:00
Summary: Removing unused imports.
Affected #: 1 file
diff -r d9901478d1a32df4b1c39bca38b6de51f86280d9 -r 86012baa2428bd65b01a46be0135c82ba1c1508a yt/frontends/enzo_p/io.py
--- a/yt/frontends/enzo_p/io.py
+++ b/yt/frontends/enzo_p/io.py
@@ -15,10 +15,8 @@
from yt.utilities.io_handler import \
BaseIOHandler
-from yt.utilities.logger import ytLogger as mylog
from yt.extern.six import b, iteritems
from yt.utilities.on_demand_imports import _h5py as h5py
-from yt.geometry.selection_routines import GridSelector
import numpy as np
https://bitbucket.org/yt_analysis/yt/commits/928c2a920c44/
Changeset: 928c2a920c44
User: brittonsmith
Date: 2017-06-10 20:47:57+00:00
Summary: Small reorg.
Affected #: 1 file
diff -r 86012baa2428bd65b01a46be0135c82ba1c1508a -r 928c2a920c4423513ff42ec8a238378935bb19d6 yt/frontends/enzo_p/data_structures.py
--- a/yt/frontends/enzo_p/data_structures.py
+++ b/yt/frontends/enzo_p/data_structures.py
@@ -19,24 +19,23 @@
import os
import stat
-from yt.funcs import \
- ensure_tuple, \
- get_pbar, \
- setdefaultattr
from yt.data_objects.grid_patch import \
AMRGridPatch
from yt.data_objects.static_output import \
Dataset
from yt.fields.field_info_container import \
NullFunc
+from yt.funcs import \
+ ensure_tuple, \
+ get_pbar, \
+ setdefaultattr
from yt.geometry.grid_geometry_handler import \
GridIndex
from yt.utilities.logger import \
ytLogger as mylog
-from .fields import \
+from yt.frontends.enzo_p.fields import \
EnzoPFieldInfo
-
from yt.frontends.enzo_p.misc import \
get_block_info, \
get_root_blocks, \
@@ -126,9 +125,6 @@
child_id_queue = np.empty((self.num_grids - nroot_blocks, 2),
dtype=np.int64)
- slope = self.ds.domain_width / \
- self.ds.arr(np.ones(3), "code_length")
-
for ib in range(nblocks):
fblock = min(fblock_size, file_size - offset)
buff = lstr + f.read(fblock)
@@ -174,6 +170,8 @@
f.close()
pbar.finish()
+ slope = self.ds.domain_width / \
+ self.ds.arr(np.ones(3), "code_length")
self.grid_left_edge = self.grid_left_edge * slope + \
self.ds.domain_left_edge
self.grid_right_edge = self.grid_right_edge * slope + \
https://bitbucket.org/yt_analysis/yt/commits/13e795ec0568/
Changeset: 13e795ec0568
User: brittonsmith
Date: 2017-06-11 03:10:08+00:00
Summary: Fix parent/child indexing.
Affected #: 1 file
diff -r 928c2a920c4423513ff42ec8a238378935bb19d6 -r 13e795ec0568113d87009c82bce7f82400c6b337 yt/frontends/enzo_p/data_structures.py
--- a/yt/frontends/enzo_p/data_structures.py
+++ b/yt/frontends/enzo_p/data_structures.py
@@ -47,6 +47,7 @@
"""
_id_offset = 0
+ _refine_by = 2
def __init__(self, id, index, block_name, filename = None):
"""
@@ -56,21 +57,59 @@
# All of the field parameters will be passed to us as needed.
AMRGridPatch.__init__(self, id, filename=filename, index=index)
self.block_name = block_name
- self._children_ids = []
+ self._children_ids = None
self._parent_id = -1
self.Level = -1
def __repr__(self):
return "EnzoPGrid_%04d" % self.id
+ def get_parent_id(self, desc_block_name):
+ if self.block_name == desc_block_name:
+ raise RuntimeError("Child and parent are the same!")
+ dim = self.index.ds.dimensionality
+ d_block = desc_block_name[1:].replace(":", "")
+ parent = self
+
+ while True:
+ a_block = parent.block_name[1:].replace(":", "")
+ gengap = (len(d_block) - len(a_block)) / dim
+ if gengap <= 1:
+ return parent.id
+ cid = ""
+ for aind, dind in zip(a_block.split("_"),
+ d_block.split("_")):
+ assert dind[:len(aind)] == aind
+ cid += dind[len(aind)]
+ cid = int(cid, 2)
+ parent = self.index.grids[parent._children_ids[cid]]
+
+ def add_child(self, child):
+ if self._children_ids is None:
+ self._children_ids = \
+ -1*np.ones(self._refine_by**
+ self.index.ds.dimensionality,
+ dtype=np.int64)
+
+ a_block = self.block_name[1:].replace(":", "")
+ d_block = child.block_name[1:].replace(":", "")
+ cid = ""
+ for aind, dind in zip(a_block.split("_"),
+ d_block.split("_")):
+ cid += dind[len(aind)]
+ cid = int(cid, 2)
+ self._children_ids[cid] = child.id
+
@property
def Parent(self):
if self._parent_id == -1: return None
- return self.index.grids[self._parent_id - self._id_offset]
+ return self.index.grids[self._parent_id]
@property
def Children(self):
- return [self.index.grids[cid - self._id_offset]
+ if self._children_ids is None:
+ return []
+ return [self.index.grids[cid]
for cid in self._children_ids]
class EnzoPHierarchy(GridIndex):
@@ -122,8 +161,6 @@
rbdim = self.ds.root_block_dimensions
nroot_blocks = rbdim.prod()
child_id = nroot_blocks
- child_id_queue = np.empty((self.num_grids - nroot_blocks, 2),
- dtype=np.int64)
for ib in range(nblocks):
fblock = min(fblock_size, file_size - offset)
@@ -143,11 +180,7 @@
parent_id = -1
else:
grid_id = child_id
- parent_id = rbid
- # Queue up the child ids and set them later
- # when all the grids have been created.
- child_id_queue[child_id - nroot_blocks] = \
- rbid, child_id
+ parent_id = self.grids[rbid].get_parent_id(block_name)
child_id += 1
my_grid = self.grid(
@@ -162,6 +195,9 @@
self.grid_right_edge[grid_id] = right
self.grid_dimensions[grid_id] = self.ds.active_grid_dimensions
+ if level > 0:
+ self.grids[parent_id].add_child(my_grid)
+
bnl = nnl + 1
pbar.update(1)
lstr = buff[bnl:]
@@ -177,9 +213,6 @@
self.grid_right_edge = self.grid_right_edge * slope + \
self.ds.domain_left_edge
- for rbid, child_id in child_id_queue:
- self.grids[rbid]._children_ids.append(child_id)
-
def _populate_grid_objects(self):
for g in self.grids:
g._prepare_grid()
https://bitbucket.org/yt_analysis/yt/commits/311ca721b1bb/
Changeset: 311ca721b1bb
User: brittonsmith
Date: 2017-06-11 03:13:51+00:00
Summary: Refactor duplicate code.
Affected #: 2 files
diff -r 13e795ec0568113d87009c82bce7f82400c6b337 -r 311ca721b1bb2d7fb562fc567145d40e088f0b29 yt/frontends/enzo_p/data_structures.py
--- a/yt/frontends/enzo_p/data_structures.py
+++ b/yt/frontends/enzo_p/data_structures.py
@@ -38,6 +38,7 @@
EnzoPFieldInfo
from yt.frontends.enzo_p.misc import \
get_block_info, \
+ get_child_index, \
get_root_blocks, \
get_root_block_id
@@ -76,12 +77,7 @@
gengap = (len(d_block) - len(a_block)) / dim
if gengap <= 1:
return parent.id
- cid = ""
- for aind, dind in zip(a_block.split("_"),
- d_block.split("_")):
- assert dind[:len(aind)] == aind
- cid += dind[len(aind)]
- cid = int(cid, 2)
+ cid = get_child_index(a_block, d_block)
parent = self.index.grids[parent._children_ids[cid]]
def add_child(self, child):
@@ -93,11 +89,7 @@
a_block = self.block_name[1:].replace(":", "")
d_block = child.block_name[1:].replace(":", "")
- cid = ""
- for aind, dind in zip(a_block.split("_"),
- d_block.split("_")):
- cid += dind[len(aind)]
- cid = int(cid, 2)
+ cid = get_child_index(a_block, d_block)
self._children_ids[cid] = child.id
@property
diff -r 13e795ec0568113d87009c82bce7f82400c6b337 -r 311ca721b1bb2d7fb562fc567145d40e088f0b29 yt/frontends/enzo_p/misc.py
--- a/yt/frontends/enzo_p/misc.py
+++ b/yt/frontends/enzo_p/misc.py
@@ -60,3 +60,11 @@
s = len(myb)
rbid[i] = int(myb[:s], 2)
return rbid
+
+def get_child_index(anc_id, desc_id):
+ cid = ""
+ for aind, dind in zip( anc_id.split("_"),
+ desc_id.split("_")):
+ cid += dind[len(aind)]
+ cid = int(cid, 2)
+ return cid
https://bitbucket.org/yt_analysis/yt/commits/8456a962c594/
Changeset: 8456a962c594
User: brittonsmith
Date: 2017-06-11 03:41:25+00:00
Summary: Speed up indexing by checking id of last parent before searching.
Affected #: 2 files
diff -r 311ca721b1bb2d7fb562fc567145d40e088f0b29 -r 8456a962c59444495d2bc04ee78668ff902d6adc yt/frontends/enzo_p/data_structures.py
--- a/yt/frontends/enzo_p/data_structures.py
+++ b/yt/frontends/enzo_p/data_structures.py
@@ -40,7 +40,8 @@
get_block_info, \
get_child_index, \
get_root_blocks, \
- get_root_block_id
+ get_root_block_id, \
+ is_parent
class EnzoPGrid(AMRGridPatch):
"""
@@ -154,6 +155,7 @@
nroot_blocks = rbdim.prod()
child_id = nroot_blocks
+ last_pid = None
for ib in range(nblocks):
fblock = min(fblock_size, file_size - offset)
buff = lstr + f.read(fblock)
@@ -172,7 +174,13 @@
parent_id = -1
else:
grid_id = child_id
- parent_id = self.grids[rbid].get_parent_id(block_name)
+ # Try the last parent_id first
+ if last_pid is not None and \
+ is_parent(self.grids[last_pid].block_name, block_name):
+ parent_id = last_pid
+ else:
+ parent_id = self.grids[rbid].get_parent_id(block_name)
+ last_pid = parent_id
child_id += 1
my_grid = self.grid(
diff -r 311ca721b1bb2d7fb562fc567145d40e088f0b29 -r 8456a962c59444495d2bc04ee78668ff902d6adc yt/frontends/enzo_p/misc.py
--- a/yt/frontends/enzo_p/misc.py
+++ b/yt/frontends/enzo_p/misc.py
@@ -68,3 +68,10 @@
cid += dind[len(aind)]
cid = int(cid, 2)
return cid
+
+def is_parent(anc_block, desc_block):
+ for aind, dind in zip( anc_block.split("_"),
+ desc_block.split("_")):
+ if not dind.startswith(aind):
+ return False
+ return True
https://bitbucket.org/yt_analysis/yt/commits/844319d899d2/
Changeset: 844319d899d2
User: brittonsmith
Date: 2017-06-15 21:09:29+00:00
Summary: Adding some docs for Enzo-P loading.
Affected #: 1 file
diff -r 8456a962c59444495d2bc04ee78668ff902d6adc -r 844319d899d2c387b45f69a62ea3318d17f5d94a doc/source/examining/loading_data.rst
--- a/doc/source/examining/loading_data.rst
+++ b/doc/source/examining/loading_data.rst
@@ -482,6 +482,36 @@
fields. Projections, volume rendering, and many of the analysis modules will not
work.
+.. _loading-enzop-data:
+
+Enzo-P Data
+-----------
+
+Enzo-P outputs have three types of files.
+
+.. code-block:: none
+
+ hello-0200/
+ hello-0200/hello-0200.block_list
+ hello-0200/hello-0200.file_list
+ hello-0200/hello-0200.hello-c0020-p0000.h5
+
+To load Enzo-P data into yt, provide the block list file:
+
+.. code-block:: python
+
+ import yt
+ ds = yt.load("hello-0200/hello-0200.block_list")
+
+Mesh fields are fully supported for 1, 2, and 3D datasets.
+
+.. rubric:: Caveats
+
+ * The Enzo-P output format is still evolving somewhat as the code is being
+ actively developed. This frontend will be updated as development continues.
+ * Units are currently assumed to be in CGS.
+ * Particles are not yet supported.
+
.. _loading-exodusii-data:
Exodus II Data
https://bitbucket.org/yt_analysis/yt/commits/a184cbee5372/
Changeset: a184cbee5372
User: brittonsmith
Date: 2017-06-15 22:45:19+00:00
Summary: Adding tests for Enzo-P frontend.
Affected #: 4 files
diff -r 844319d899d2c387b45f69a62ea3318d17f5d94a -r a184cbee5372e4cf1d9d28cd3985c568cef0b28f tests/tests.yaml
--- a/tests/tests.yaml
+++ b/tests/tests.yaml
@@ -14,6 +14,9 @@
local_enzo_003:
- yt/frontends/enzo
+ local_enzo_p_001:
+ - yt/frontends/enzo_p/tests/test_outputs.py
+
local_fits_001:
- yt/frontends/fits/tests/test_outputs.py
diff -r 844319d899d2c387b45f69a62ea3318d17f5d94a -r a184cbee5372e4cf1d9d28cd3985c568cef0b28f yt/frontends/enzo_p/api.py
--- a/yt/frontends/enzo_p/api.py
+++ b/yt/frontends/enzo_p/api.py
@@ -24,3 +24,5 @@
from .io import \
EnzoPIOHandler
+
+from . import tests
diff -r 844319d899d2c387b45f69a62ea3318d17f5d94a -r a184cbee5372e4cf1d9d28cd3985c568cef0b28f yt/frontends/enzo_p/tests/test_outputs.py
--- /dev/null
+++ b/yt/frontends/enzo_p/tests/test_outputs.py
@@ -0,0 +1,78 @@
+"""
+Enzo-P frontend tests
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2017, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+from yt.utilities.on_demand_imports import \
+ _h5py as h5py
+import numpy as np
+
+from yt.testing import \
+ assert_almost_equal, \
+ assert_equal, \
+ requires_file, \
+ units_override_check, \
+ assert_array_equal
+from yt.utilities.answer_testing.framework import \
+ create_obj, \
+ data_dir_load, \
+ requires_ds, \
+ PixelizedProjectionValuesTest, \
+ FieldValuesTest
+from yt.frontends.enzo_p.api import EnzoPDataset
+
+_fields = ("density", "total_energy",
+ "velocity_x", "velocity_y")
+
+hello_world = "hello-0200/hello-0200.block_list"
+
+
+ at requires_file(hello_world)
+def test_EnzoPDataset():
+ assert isinstance(data_dir_load(hello_world), EnzoPDataset)
+
+ at requires_ds(hello_world)
+def test_hello_world():
+ ds = data_dir_load(hello_world)
+
+ dso = [ None, ("sphere", ("max", (0.25, 'unitary')))]
+ for dobj_name in dso:
+ for field in _fields:
+ for axis in [0, 1, 2]:
+ for weight_field in [None, "density"]:
+ yield PixelizedProjectionValuesTest(
+ hello_world, axis, field, weight_field,
+ dobj_name)
+ yield FieldValuesTest(hello_world, field, dobj_name)
+ dobj = create_obj(ds, dobj_name)
+ s1 = dobj["ones"].sum()
+ s2 = sum(mask.sum() for block, mask in dobj.blocks)
+ assert_equal(s1, s2)
+
+ at requires_file(hello_world)
+def test_hierarchy():
+ ds = data_dir_load(hello_world)
+
+ fh = h5py.File(ds.index.grids[0].filename, "r")
+ for grid in ds.index.grids:
+ assert_array_equal(
+ grid.LeftEdge.d, fh[grid.block_name].attrs["enzo_GridLeftEdge"])
+ assert_array_equal(
+ ds.index.grid_left_edge[grid.id], grid.LeftEdge)
+ assert_array_equal(
+ ds.index.grid_right_edge[grid.id], grid.RightEdge)
+ for child in grid.Children:
+ assert (child.LeftEdge >= grid.LeftEdge).all()
+ assert (child.RightEdge <= grid.RightEdge).all()
+ assert child.Parent.id == grid.id
+ fh.close()
https://bitbucket.org/yt_analysis/yt/commits/f2f5c185fff9/
Changeset: f2f5c185fff9
User: brittonsmith
Date: 2017-06-15 22:58:05+00:00
Summary: Remove unused imports.
Affected #: 1 file
diff -r a184cbee5372e4cf1d9d28cd3985c568cef0b28f -r f2f5c185fff99b39b81cef2e6ff26843d8df89b4 yt/frontends/enzo_p/tests/test_outputs.py
--- a/yt/frontends/enzo_p/tests/test_outputs.py
+++ b/yt/frontends/enzo_p/tests/test_outputs.py
@@ -18,10 +18,8 @@
import numpy as np
from yt.testing import \
- assert_almost_equal, \
assert_equal, \
requires_file, \
- units_override_check, \
assert_array_equal
from yt.utilities.answer_testing.framework import \
create_obj, \
@@ -74,5 +72,5 @@
for child in grid.Children:
assert (child.LeftEdge >= grid.LeftEdge).all()
assert (child.RightEdge <= grid.RightEdge).all()
- assert child.Parent.id == grid.id
+ assert_equal(child.Parent.id, grid.id)
fh.close()
https://bitbucket.org/yt_analysis/yt/commits/9779c454903c/
Changeset: 9779c454903c
User: brittonsmith
Date: 2017-06-16 16:45:39+00:00
Summary: Remove unused import.
Affected #: 1 file
diff -r f2f5c185fff99b39b81cef2e6ff26843d8df89b4 -r 9779c454903c9df0abf28b57cde16b12be62833b yt/frontends/enzo_p/tests/test_outputs.py
--- a/yt/frontends/enzo_p/tests/test_outputs.py
+++ b/yt/frontends/enzo_p/tests/test_outputs.py
@@ -15,7 +15,6 @@
from yt.utilities.on_demand_imports import \
_h5py as h5py
-import numpy as np
from yt.testing import \
assert_equal, \
https://bitbucket.org/yt_analysis/yt/commits/6a3f77cea4e3/
Changeset: 6a3f77cea4e3
User: brittonsmith
Date: 2017-06-23 02:40:49+00:00
Summary: Use ds associated with Grid object.
Affected #: 1 file
diff -r 9779c454903c9df0abf28b57cde16b12be62833b -r 6a3f77cea4e3e77fb7ecb569a1b345354efc114f yt/frontends/enzo_p/data_structures.py
--- a/yt/frontends/enzo_p/data_structures.py
+++ b/yt/frontends/enzo_p/data_structures.py
@@ -69,7 +69,7 @@
def get_parent_id(self, desc_block_name):
if self.block_name == desc_block_name:
raise RuntimeError("Child and parent are the same!")
- dim = self.index.ds.dimensionality
+ dim = self.ds.dimensionality
d_block = desc_block_name[1:].replace(":", "")
parent = self
@@ -84,8 +84,7 @@
def add_child(self, child):
if self._children_ids is None:
self._children_ids = \
- -1*np.ones(self._refine_by**
- self.index.ds.dimensionality,
+ -1*np.ones(self._refine_by**self.ds.dimensionality,
dtype=np.int64)
a_block = self.block_name[1:].replace(":", "")
https://bitbucket.org/yt_analysis/yt/commits/fb9b5b8183e3/
Changeset: fb9b5b8183e3
User: brittonsmith
Date: 2017-06-23 17:34:24+00:00
Summary: seek does not return position in python2.
Affected #: 1 file
diff -r 6a3f77cea4e3e77fb7ecb569a1b345354efc114f -r fb9b5b8183e3b82cf654929b923e904bc5af6967 yt/frontends/enzo_p/data_structures.py
--- a/yt/frontends/enzo_p/data_structures.py
+++ b/yt/frontends/enzo_p/data_structures.py
@@ -124,10 +124,12 @@
def _count_grids(self):
fblock_size = 32768
f = open(self.ds.parameter_filename, "r")
- file_size = f.seek(0, 2)
+ f.seek(0, 2)
+ file_size = f.tell()
nblocks = np.ceil(float(file_size) /
fblock_size).astype(np.int64)
- offset = f.seek(0)
+ f.seek(0)
+ offset = f.tell()
ngrids = 0
for ib in range(nblocks):
my_block = min(fblock_size, file_size - offset)
@@ -144,10 +146,12 @@
pbar = get_pbar("Parsing Hierarchy ", self.num_grids)
f = open(self.ds.parameter_filename, "r")
fblock_size = 32768
- file_size = f.seek(0, 2)
+ f.seek(0, 2)
+ file_size = f.tell()
nblocks = np.ceil(float(file_size) /
fblock_size).astype(np.int64)
- offset = f.seek(0)
+ f.seek(0)
+ offset = f.tell()
lstr = ""
# place child blocks after the root blocks
rbdim = self.ds.root_block_dimensions
https://bitbucket.org/yt_analysis/yt/commits/bab566948258/
Changeset: bab566948258
User: brittonsmith
Date: 2017-06-23 17:55:53+00:00
Summary: Remove random grid sampling and active particle stuff from field detection.
Affected #: 2 files
diff -r fb9b5b8183e3b82cf654929b923e904bc5af6967 -r bab56694825855ead177bdb07b2d1ab52324c34c yt/frontends/enzo_p/data_structures.py
--- a/yt/frontends/enzo_p/data_structures.py
+++ b/yt/frontends/enzo_p/data_structures.py
@@ -233,30 +233,10 @@
self.field_list = []
# Do this only on the root processor to save disk work.
if self.comm.rank in (0, None):
- mylog.info("Gathering a field list (this may take a moment.)")
- field_list = set()
- random_sample = self._generate_random_grids()
- for grid in random_sample:
- if not hasattr(grid, 'filename'): continue
- try:
- gf = self.io._read_field_names(grid)
- except self.io._read_exception:
- raise IOError("Grid %s is a bit funky?", grid.id)
- mylog.debug("Grid %s has: %s", grid.id, gf)
- field_list = field_list.union(gf)
- if "AppendActiveParticleType" in self.dataset.parameters:
- ap_fields = self._detect_active_particle_fields()
- field_list = list(set(field_list).union(ap_fields))
- if not any(f[0] == 'io' for f in field_list):
- if 'io' in self.dataset.particle_types_raw:
- ptypes_raw = list(self.dataset.particle_types_raw)
- ptypes_raw.remove('io')
- self.dataset.particle_types_raw = tuple(ptypes_raw)
-
- if 'io' in self.dataset.particle_types:
- ptypes = list(self.dataset.particle_types)
- ptypes.remove('io')
- self.dataset.particle_types = tuple(ptypes)
+ # Just check the first grid.
+ grid = self.grids[0]
+ field_list = self.io._read_field_names(grid)
+ mylog.debug("Grid %s has: %s", grid.id, field_list)
ptypes = self.dataset.particle_types
ptypes_raw = self.dataset.particle_types_raw
else:
@@ -267,24 +247,6 @@
self.dataset.particle_types = list(self.comm.mpi_bcast(ptypes))
self.dataset.particle_types_raw = list(self.comm.mpi_bcast(ptypes_raw))
- def _generate_random_grids(self):
- if self.num_grids > 40:
- starter = np.random.randint(0, 20)
- random_sample = np.mgrid[starter:len(self.grids)-1:20j].astype("int32")
- # We also add in a bit to make sure that some of the grids have
- # particles
- gwp = self.grid_particle_count > 0
- if np.any(gwp) and not np.any(gwp[(random_sample,)]):
- # We just add one grid. This is not terribly efficient.
- first_grid = np.where(gwp)[0][0]
- random_sample.resize((21,))
- random_sample[-1] = first_grid
- mylog.debug("Added additional grid %s", first_grid)
- mylog.debug("Checking grids: %s", random_sample.tolist())
- else:
- random_sample = np.mgrid[0:max(len(self.grids),1)].astype("int32")
- return self.grids[(random_sample,)]
-
class EnzoPDataset(Dataset):
"""
Enzo-P-specific output, set at a fixed time.
diff -r fb9b5b8183e3b82cf654929b923e904bc5af6967 -r bab56694825855ead177bdb07b2d1ab52324c34c yt/frontends/enzo_p/io.py
--- a/yt/frontends/enzo_p/io.py
+++ b/yt/frontends/enzo_p/io.py
@@ -13,6 +13,8 @@
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
+from yt.utilities.exceptions import \
+ YTException
from yt.utilities.io_handler import \
BaseIOHandler
from yt.extern.six import b, iteritems
@@ -42,7 +44,9 @@
try:
group = f[grid.block_name]
except KeyError:
- group = f
+ raise YTException(
+ message="Grid %s is missing from data file %s." %
+ (grid.block_name, grid.filename), ds=self.ds)
fields = []
dtypes = set([])
for name, v in iteritems(group):
https://bitbucket.org/yt_analysis/yt/commits/50348a24b3de/
Changeset: 50348a24b3de
User: brittonsmith
Date: 2017-06-23 17:57:53+00:00
Summary: except Exception.
Affected #: 1 file
diff -r bab56694825855ead177bdb07b2d1ab52324c34c -r 50348a24b3de0508d0c7a352812af6332f6e586c yt/frontends/enzo_p/data_structures.py
--- a/yt/frontends/enzo_p/data_structures.py
+++ b/yt/frontends/enzo_p/data_structures.py
@@ -346,6 +346,6 @@
get_block_info(block)
if not os.path.exists(os.path.join(ddir, block_file)):
return False
- except:
+ except Exception:
return False
return True
https://bitbucket.org/yt_analysis/yt/commits/8c521408507e/
Changeset: 8c521408507e
User: brittonsmith
Date: 2017-06-24 01:31:03+00:00
Summary: Remove unused exception.
Affected #: 1 file
diff -r 50348a24b3de0508d0c7a352812af6332f6e586c -r 8c521408507efadd335160f0897c7384c8cf1230 yt/frontends/enzo_p/io.py
--- a/yt/frontends/enzo_p/io.py
+++ b/yt/frontends/enzo_p/io.py
@@ -73,10 +73,6 @@
f.close()
return fields
- @property
- def _read_exception(self):
- return (KeyError,)
-
def _read_particle_coords(self, chunks, ptf):
for rv in self._read_particle_fields(chunks, ptf, None):
yield rv
https://bitbucket.org/yt_analysis/yt/commits/a3d48abcba9a/
Changeset: a3d48abcba9a
User: brittonsmith
Date: 2017-06-26 17:45:19+00:00
Summary: Remove py2 incompatible use of string.split.
Affected #: 1 file
diff -r 8c521408507efadd335160f0897c7384c8cf1230 -r a3d48abcba9a22160b0fece959b2eda1c183e2de yt/frontends/enzo_p/io.py
--- a/yt/frontends/enzo_p/io.py
+++ b/yt/frontends/enzo_p/io.py
@@ -54,12 +54,12 @@
continue
# mesh fields are "field <name>"
if name.startswith("field"):
- dummy, fname = name.split(maxsplit=1)
+ dummy, fname = name.split(" ", 1)
fields.append(("enzop", fname))
dtypes.add(v.dtype)
# particle fields are "particle <type><name>"
else:
- dummy, ftype, fname = name.split(maxsplit=2)
+ dummy, ftype, fname = name.split(" ", 2)
fields.append((ftype, fname))
if len(dtypes) == 1:
https://bitbucket.org/yt_analysis/yt/commits/b8ae5d5e6168/
Changeset: b8ae5d5e6168
User: ngoldbaum
Date: 2017-06-27 18:14:47+00:00
Summary: Merge pull request #1447 from brittonsmith/enzop
Add Enzo-P frontend
Affected #: 12 files
diff -r 272125cbb417b446f20fec4d38e3c1e4efa54375 -r b8ae5d5e61686d61d691f33ace5397ffcf7f5c35 doc/source/examining/loading_data.rst
--- a/doc/source/examining/loading_data.rst
+++ b/doc/source/examining/loading_data.rst
@@ -482,6 +482,36 @@
fields. Projections, volume rendering, and many of the analysis modules will not
work.
+.. _loading-enzop-data:
+
+Enzo-P Data
+-----------
+
+Enzo-P outputs have three types of files.
+
+.. code-block:: none
+
+ hello-0200/
+ hello-0200/hello-0200.block_list
+ hello-0200/hello-0200.file_list
+ hello-0200/hello-0200.hello-c0020-p0000.h5
+
+To load Enzo-P data into yt, provide the block list file:
+
+.. code-block:: python
+
+ import yt
+ ds = yt.load("hello-0200/hello-0200.block_list")
+
+Mesh fields are fully supported for 1, 2, and 3D datasets.
+
+.. rubric:: Caveats
+
+ * The Enzo-P output format is still evolving somewhat as the code is being
+ actively developed. This frontend will be updated as development continues.
+ * Units are currently assumed to be in CGS.
+ * Particles are not yet supported.
+
.. _loading-exodusii-data:
Exodus II Data
diff -r 272125cbb417b446f20fec4d38e3c1e4efa54375 -r b8ae5d5e61686d61d691f33ace5397ffcf7f5c35 tests/tests.yaml
--- a/tests/tests.yaml
+++ b/tests/tests.yaml
@@ -14,6 +14,9 @@
local_enzo_003:
- yt/frontends/enzo
+ local_enzo_p_001:
+ - yt/frontends/enzo_p/tests/test_outputs.py
+
local_fits_001:
- yt/frontends/fits/tests/test_outputs.py
diff -r 272125cbb417b446f20fec4d38e3c1e4efa54375 -r b8ae5d5e61686d61d691f33ace5397ffcf7f5c35 yt/frontends/api.py
--- a/yt/frontends/api.py
+++ b/yt/frontends/api.py
@@ -25,6 +25,7 @@
'chombo',
'eagle',
'enzo',
+ 'enzo_p',
'exodus_ii',
'fits',
'flash',
diff -r 272125cbb417b446f20fec4d38e3c1e4efa54375 -r b8ae5d5e61686d61d691f33ace5397ffcf7f5c35 yt/frontends/enzo_p/api.py
--- /dev/null
+++ b/yt/frontends/enzo_p/api.py
@@ -0,0 +1,28 @@
+"""
+API for yt.frontends.enzo_p
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2017, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+from .data_structures import \
+ EnzoPGrid, \
+ EnzoPHierarchy, \
+ EnzoPDataset
+
+from .fields import \
+ EnzoPFieldInfo
+add_enzop_field = EnzoPFieldInfo.add_field
+
+from .io import \
+ EnzoPIOHandler
+
+from . import tests
diff -r 272125cbb417b446f20fec4d38e3c1e4efa54375 -r b8ae5d5e61686d61d691f33ace5397ffcf7f5c35 yt/frontends/enzo_p/data_structures.py
--- /dev/null
+++ b/yt/frontends/enzo_p/data_structures.py
@@ -0,0 +1,351 @@
+"""
+Data structures for Enzo-P
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2017, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+from yt.utilities.on_demand_imports import \
+ _h5py as h5py
+import numpy as np
+import os
+import stat
+
+from yt.data_objects.grid_patch import \
+ AMRGridPatch
+from yt.data_objects.static_output import \
+ Dataset
+from yt.fields.field_info_container import \
+ NullFunc
+from yt.funcs import \
+ ensure_tuple, \
+ get_pbar, \
+ setdefaultattr
+from yt.geometry.grid_geometry_handler import \
+ GridIndex
+from yt.utilities.logger import \
+ ytLogger as mylog
+
+from yt.frontends.enzo_p.fields import \
+ EnzoPFieldInfo
+from yt.frontends.enzo_p.misc import \
+ get_block_info, \
+ get_child_index, \
+ get_root_blocks, \
+ get_root_block_id, \
+ is_parent
+
+class EnzoPGrid(AMRGridPatch):
+ """
+ Class representing a single EnzoP Grid instance.
+ """
+
+ _id_offset = 0
+ _refine_by = 2
+
+ def __init__(self, id, index, block_name, filename = None):
+ """
+ Returns an instance of EnzoPGrid with *id*, associated with
+ *filename* and *index*.
+ """
+ # All of the field parameters will be passed to us as needed.
+ AMRGridPatch.__init__(self, id, filename=filename, index=index)
+ self.block_name = block_name
+ self._children_ids = None
+ self._parent_id = -1
+ self.Level = -1
+
+ def __repr__(self):
+ return "EnzoPGrid_%04d" % self.id
+
+ def get_parent_id(self, desc_block_name):
+ if self.block_name == desc_block_name:
+ raise RuntimeError("Child and parent are the same!")
+ dim = self.ds.dimensionality
+ d_block = desc_block_name[1:].replace(":", "")
+ parent = self
+
+ while True:
+ a_block = parent.block_name[1:].replace(":", "")
+ gengap = (len(d_block) - len(a_block)) / dim
+ if gengap <= 1:
+ return parent.id
+ cid = get_child_index(a_block, d_block)
+ parent = self.index.grids[parent._children_ids[cid]]
+
+ def add_child(self, child):
+ if self._children_ids is None:
+ self._children_ids = \
+ -1*np.ones(self._refine_by**self.ds.dimensionality,
+ dtype=np.int64)
+
+ a_block = self.block_name[1:].replace(":", "")
+ d_block = child.block_name[1:].replace(":", "")
+ cid = get_child_index(a_block, d_block)
+ self._children_ids[cid] = child.id
+
+ @property
+ def Parent(self):
+ if self._parent_id == -1: return None
+ return self.index.grids[self._parent_id]
+
+ @property
+ def Children(self):
+ if self._children_ids is None:
+ return []
+ return [self.index.grids[cid]
+ for cid in self._children_ids]
+
+class EnzoPHierarchy(GridIndex):
+
+ _strip_path = False
+ grid = EnzoPGrid
+ _preload_implemented = True
+
+ def __init__(self, ds, dataset_type):
+
+ self.dataset_type = dataset_type
+ self.directory = os.path.dirname(ds.parameter_filename)
+ self.index_filename = ds.parameter_filename
+ if os.path.getsize(self.index_filename) == 0:
+ raise IOError(-1,"File empty", self.index_filename)
+
+ GridIndex.__init__(self, ds, dataset_type)
+ self.dataset.dataset_type = self.dataset_type
+
+ def _count_grids(self):
+ fblock_size = 32768
+ f = open(self.ds.parameter_filename, "r")
+ f.seek(0, 2)
+ file_size = f.tell()
+ nblocks = np.ceil(float(file_size) /
+ fblock_size).astype(np.int64)
+ f.seek(0)
+ offset = f.tell()
+ ngrids = 0
+ for ib in range(nblocks):
+ my_block = min(fblock_size, file_size - offset)
+ buff = f.read(my_block)
+ ngrids += buff.count("\n")
+ offset += my_block
+ f.close()
+ self.num_grids = ngrids
+ self.dataset_type = "enzo_p"
+
+ def _parse_index(self):
+ self.grids = np.empty(self.num_grids, dtype='object')
+
+ pbar = get_pbar("Parsing Hierarchy ", self.num_grids)
+ f = open(self.ds.parameter_filename, "r")
+ fblock_size = 32768
+ f.seek(0, 2)
+ file_size = f.tell()
+ nblocks = np.ceil(float(file_size) /
+ fblock_size).astype(np.int64)
+ f.seek(0)
+ offset = f.tell()
+ lstr = ""
+ # place child blocks after the root blocks
+ rbdim = self.ds.root_block_dimensions
+ nroot_blocks = rbdim.prod()
+ child_id = nroot_blocks
+
+ last_pid = None
+ for ib in range(nblocks):
+ fblock = min(fblock_size, file_size - offset)
+ buff = lstr + f.read(fblock)
+ bnl = 0
+ for inl in range(buff.count("\n")):
+ nnl = buff.find("\n", bnl)
+ line = buff[bnl:nnl]
+ block_name, block_file = line.split()
+ level, left, right = get_block_info(block_name)
+
+ rbindex = get_root_block_id(block_name)
+ rbid = rbindex[0] * rbdim[1:].prod() + \
+ rbindex[1] * rbdim[2:].prod() + rbindex[2]
+ if level == 0:
+ grid_id = rbid
+ parent_id = -1
+ else:
+ grid_id = child_id
+ # Try the last parent_id first
+ if last_pid is not None and \
+ is_parent(self.grids[last_pid].block_name, block_name):
+ parent_id = last_pid
+ else:
+ parent_id = self.grids[rbid].get_parent_id(block_name)
+ last_pid = parent_id
+ child_id += 1
+
+ my_grid = self.grid(
+ grid_id, self, block_name,
+ filename=os.path.join(self.directory, block_file))
+ my_grid.Level = level
+ my_grid._parent_id = parent_id
+
+ self.grids[grid_id] = my_grid
+ self.grid_levels[grid_id] = level
+ self.grid_left_edge[grid_id] = left
+ self.grid_right_edge[grid_id] = right
+ self.grid_dimensions[grid_id] = self.ds.active_grid_dimensions
+
+ if level > 0:
+ self.grids[parent_id].add_child(my_grid)
+
+ bnl = nnl + 1
+ pbar.update(1)
+ lstr = buff[bnl:]
+ offset += fblock
+
+ f.close()
+ pbar.finish()
+
+ slope = self.ds.domain_width / \
+ self.ds.arr(np.ones(3), "code_length")
+ self.grid_left_edge = self.grid_left_edge * slope + \
+ self.ds.domain_left_edge
+ self.grid_right_edge = self.grid_right_edge * slope + \
+ self.ds.domain_left_edge
+
+ def _populate_grid_objects(self):
+ for g in self.grids:
+ g._prepare_grid()
+ g._setup_dx()
+ self.max_level = self.grid_levels.max()
+
+ def _setup_derived_fields(self):
+ super(EnzoPHierarchy, self)._setup_derived_fields()
+ for fname, field in self.ds.field_info.items():
+ if not field.particle_type: continue
+ if isinstance(fname, tuple): continue
+ if field._function is NullFunc: continue
+
+ def _detect_output_fields(self):
+ self.field_list = []
+ # Do this only on the root processor to save disk work.
+ if self.comm.rank in (0, None):
+ # Just check the first grid.
+ grid = self.grids[0]
+ field_list = self.io._read_field_names(grid)
+ mylog.debug("Grid %s has: %s", grid.id, field_list)
+ ptypes = self.dataset.particle_types
+ ptypes_raw = self.dataset.particle_types_raw
+ else:
+ field_list = None
+ ptypes = None
+ ptypes_raw = None
+ self.field_list = list(self.comm.mpi_bcast(field_list))
+ self.dataset.particle_types = list(self.comm.mpi_bcast(ptypes))
+ self.dataset.particle_types_raw = list(self.comm.mpi_bcast(ptypes_raw))
+
+class EnzoPDataset(Dataset):
+ """
+ Enzo-P-specific output, set at a fixed time.
+ """
+ _index_class = EnzoPHierarchy
+ _field_info_class = EnzoPFieldInfo
+
+ def __init__(self, filename, dataset_type=None,
+ file_style = None,
+ parameter_override = None,
+ conversion_override = None,
+ storage_filename = None,
+ units_override=None,
+ unit_system="cgs"):
+ """
+ This class is a stripped down class that simply reads and parses
+ *filename* without looking at the index. *dataset_type* gets passed
+ to the index to pre-determine the style of data-output. However,
+ it is not strictly necessary. Optionally you may specify a
+ *parameter_override* dictionary that will override anything in the
+ paarmeter file and a *conversion_override* dictionary that consists
+ of {fieldname : conversion_to_cgs} that will override the #DataCGS.
+ """
+ self.fluid_types += ("enzop",)
+ if parameter_override is None: parameter_override = {}
+ self._parameter_override = parameter_override
+ if conversion_override is None: conversion_override = {}
+ self._conversion_override = conversion_override
+ self.storage_filename = storage_filename
+ Dataset.__init__(self, filename, dataset_type, file_style=file_style,
+ units_override=units_override, unit_system=unit_system)
+
+ def _parse_parameter_file(self):
+ """
+ Parses the parameter file and establishes the various
+ dictionaries.
+ """
+
+ f = open(self.parameter_filename, "r")
+ # get dimension from first block name
+ b0, fn0 = f.readline().strip().split()
+ level0, left0, right0 = get_block_info(b0, min_dim=0)
+ root_blocks = get_root_blocks(b0)
+ f.close()
+ self.dimensionality = left0.size
+ self.periodicity = \
+ ensure_tuple(np.ones(self.dimensionality, dtype=bool))
+
+ fh = h5py.File(os.path.join(self.directory, fn0), "r")
+ self.domain_left_edge = fh.attrs["lower"]
+ self.domain_right_edge = fh.attrs["upper"]
+
+ # all blocks are the same size
+ ablock = fh[list(fh.keys())[0]]
+ self.current_time = ablock.attrs["time"][0]
+ gsi = ablock.attrs["enzo_GridStartIndex"]
+ gei = ablock.attrs["enzo_GridEndIndex"]
+ self.ghost_zones = gsi[0]
+ self.root_block_dimensions = root_blocks
+ self.active_grid_dimensions = gei - gsi + 1
+ self.grid_dimensions = ablock.attrs["enzo_GridDimension"]
+ self.domain_dimensions = root_blocks * self.active_grid_dimensions
+ fh.close()
+
+ self.periodicity += (False, ) * (3 - self.dimensionality)
+
+ # WIP hard-coded for now
+ self.refine_by = 2
+ self.cosmological_simulation = 0
+ self.gamma = 5. / 3.
+ self.particle_types = ()
+ self.particle_types_raw = self.particle_types
+ self.unique_identifier = \
+ str(int(os.stat(self.parameter_filename)[stat.ST_CTIME]))
+
+ def _set_code_unit_attributes(self):
+ setdefaultattr(self, 'length_unit', self.quan(1, "cm"))
+ setdefaultattr(self, 'mass_unit', self.quan(1, "g"))
+ setdefaultattr(self, 'time_unit', self.quan(1, "s"))
+ setdefaultattr(self, 'velocity_unit',
+ self.length_unit / self.time_unit)
+ magnetic_unit = np.sqrt(4*np.pi * self.mass_unit /
+ (self.time_unit**2 * self.length_unit))
+ magnetic_unit = np.float64(magnetic_unit.in_cgs())
+ setdefaultattr(self, 'magnetic_unit',
+ self.quan(magnetic_unit, "gauss"))
+
+ @classmethod
+ def _is_valid(cls, *args, **kwargs):
+ fn = args[0]
+ ddir = os.path.dirname(fn)
+ if not fn.endswith(".block_list"):
+ return False
+ try:
+ with open(fn, "r") as f:
+ block, block_file = f.readline().strip().split()
+ get_block_info(block)
+ if not os.path.exists(os.path.join(ddir, block_file)):
+ return False
+ except Exception:
+ return False
+ return True
diff -r 272125cbb417b446f20fec4d38e3c1e4efa54375 -r b8ae5d5e61686d61d691f33ace5397ffcf7f5c35 yt/frontends/enzo_p/definitions.py
--- /dev/null
+++ b/yt/frontends/enzo_p/definitions.py
@@ -0,0 +1,15 @@
+"""
+Definitions specific to Enzo-P
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2017, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
diff -r 272125cbb417b446f20fec4d38e3c1e4efa54375 -r b8ae5d5e61686d61d691f33ace5397ffcf7f5c35 yt/frontends/enzo_p/fields.py
--- /dev/null
+++ b/yt/frontends/enzo_p/fields.py
@@ -0,0 +1,52 @@
+"""
+Fields specific to Enzo-P
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+from yt.fields.field_info_container import \
+ FieldInfoContainer
+
+rho_units = "code_mass / code_length**3"
+vel_units = "code_velocity"
+acc_units = "code_velocity / code_time"
+energy_units = "code_velocity**2"
+
+known_species_names = {
+}
+
+class EnzoPFieldInfo(FieldInfoContainer):
+ known_other_fields = (
+ ("velocity_x", (vel_units, ["velocity_x"], None)),
+ ("velocity_y", (vel_units, ["velocity_y"], None)),
+ ("velocity_z", (vel_units, ["velocity_z"], None)),
+ ("acceleration_x", (acc_units, ["acceleration_x"], None)),
+ ("acceleration_y", (acc_units, ["acceleration_y"], None)),
+ ("acceleration_z", (acc_units, ["acceleration_z"], None)),
+ ("density", (rho_units, ["density"], None)),
+ ("total_density", (rho_units, ["total_density"], None)),
+ ("total_energy", (energy_units, ["total_energy"], None)),
+ ("internal_energy", (energy_units, ["internal_energy"], None)),
+ )
+
+ known_particle_fields = (
+ ("x", ("code_length", [], None)),
+ ("y", ("code_length", [], None)),
+ ("z", ("code_length", [], None)),
+ ("vx", (vel_units, [], None)),
+ ("vy", (vel_units, [], None)),
+ ("vz", (vel_units, [], None)),
+ ("ax", (acc_units, [], None)),
+ ("ay", (acc_units, [], None)),
+ ("az", (acc_units, [], None)),
+ ("mass", ("code_mass", [], None)),
+ )
diff -r 272125cbb417b446f20fec4d38e3c1e4efa54375 -r b8ae5d5e61686d61d691f33ace5397ffcf7f5c35 yt/frontends/enzo_p/io.py
--- /dev/null
+++ b/yt/frontends/enzo_p/io.py
@@ -0,0 +1,158 @@
+"""
+Enzo-P-specific IO functions
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2017, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+from yt.utilities.exceptions import \
+ YTException
+from yt.utilities.io_handler import \
+ BaseIOHandler
+from yt.extern.six import b, iteritems
+from yt.utilities.on_demand_imports import _h5py as h5py
+import numpy as np
+
+
+_convert_mass = ("particle_mass","mass")
+
+_particle_position_names = {}
+
+class EnzoPIOHandler(BaseIOHandler):
+
+ _dataset_type = "enzo_p"
+ _base = slice(None)
+ _field_dtype = "float64"
+
+ def __init__(self, *args, **kwargs):
+ super(EnzoPIOHandler, self).__init__(*args, **kwargs)
+ self._base = self.ds.dimensionality * \
+ (slice(self.ds.ghost_zones,
+ -self.ds.ghost_zones),)
+
+ def _read_field_names(self, grid):
+ if grid.filename is None: return []
+ f = h5py.File(grid.filename, "r")
+ try:
+ group = f[grid.block_name]
+ except KeyError:
+ raise YTException(
+ message="Grid %s is missing from data file %s." %
+ (grid.block_name, grid.filename), ds=self.ds)
+ fields = []
+ dtypes = set([])
+ for name, v in iteritems(group):
+ if not hasattr(v, "shape") or v.dtype == "O":
+ continue
+ # mesh fields are "field <name>"
+ if name.startswith("field"):
+ dummy, fname = name.split(" ", 1)
+ fields.append(("enzop", fname))
+ dtypes.add(v.dtype)
+ # particle fields are "particle <type><name>"
+ else:
+ dummy, ftype, fname = name.split(" ", 2)
+ fields.append((ftype, fname))
+
+ if len(dtypes) == 1:
+ # Now, if everything we saw was the same dtype, we can go ahead and
+ # set it here. We do this because it is a HUGE savings for 32 bit
+ # floats, since our numpy copying/casting is way faster than
+ # h5py's, for some reason I don't understand. This does *not* need
+ # to be correct -- it will get fixed later -- it just needs to be
+ # okay for now.
+ self._field_dtype = list(dtypes)[0]
+ f.close()
+ return fields
+
+ def _read_particle_coords(self, chunks, ptf):
+ for rv in self._read_particle_fields(chunks, ptf, None):
+ yield rv
+
+ def _read_particle_fields(self, chunks, ptf, selector):
+ chunks = list(chunks)
+ for chunk in chunks: # These should be organized by grid filename
+ f = None
+ for g in chunk.objs:
+ if g.filename is None: continue
+ if f is None:
+ f = h5py.File(g.filename, "r")
+ nap = sum(g.NumberOfActiveParticles.values())
+ if g.NumberOfParticles == 0 and nap == 0:
+ continue
+ ds = f.get(g.block_name)
+ for ptype, field_list in sorted(ptf.items()):
+ if ptype != "io":
+ if g.NumberOfActiveParticles[ptype] == 0: continue
+ pds = ds.get("Particles/%s" % ptype)
+ else:
+ pds = ds
+ pn = _particle_position_names.get(ptype,
+ r"particle_position_%s")
+ x, y, z = (np.asarray(pds.get(pn % ax).value, dtype="=f8")
+ for ax in 'xyz')
+ if selector is None:
+ # This only ever happens if the call is made from
+ # _read_particle_coords.
+ yield ptype, (x, y, z)
+ continue
+ mask = selector.select_points(x, y, z, 0.0)
+ if mask is None: continue
+ for field in field_list:
+ data = np.asarray(pds.get(field).value, "=f8")
+ if field in _convert_mass:
+ data *= g.dds.prod(dtype="f8")
+ yield (ptype, field), data[mask]
+ if f: f.close()
+
+ def io_iter(self, chunks, fields):
+ for chunk in chunks:
+ fid = None
+ filename = -1
+ for obj in chunk.objs:
+ if obj.filename is None: continue
+ if obj.filename != filename:
+ # Note one really important thing here: even if we do
+ # implement LRU caching in the _read_obj_field function,
+ # we'll still be doing file opening and whatnot. This is a
+ # problem, but one we can return to.
+ if fid is not None:
+ fid.close()
+ fid = h5py.h5f.open(b(obj.filename), h5py.h5f.ACC_RDONLY)
+ filename = obj.filename
+ for field in fields:
+ data = None
+ yield field, obj, self._read_obj_field(
+ obj, field, (fid, data))
+ if fid is not None:
+ fid.close()
+
+ def _read_obj_field(self, obj, field, fid_data):
+ if fid_data is None: fid_data = (None, None)
+ fid, data = fid_data
+ if fid is None:
+ close = True
+ fid = h5py.h5f.open(b(obj.filename), h5py.h5f.ACC_RDONLY)
+ else:
+ close = False
+ ftype, fname = field
+ node = "/%s/field %s" % (obj.block_name, fname)
+ dg = h5py.h5d.open(fid, b(node))
+ rdata = np.empty(self.ds.grid_dimensions[:self.ds.dimensionality],
+ dtype=self._field_dtype)
+ dg.read(h5py.h5s.ALL, h5py.h5s.ALL, rdata)
+ if close:
+ fid.close()
+ data = rdata[self._base].T
+ if self.ds.dimensionality < 3:
+ nshape = data.shape + (1,)*(3 - self.ds.dimensionality)
+ data = np.reshape(data, nshape)
+ return data
diff -r 272125cbb417b446f20fec4d38e3c1e4efa54375 -r b8ae5d5e61686d61d691f33ace5397ffcf7f5c35 yt/frontends/enzo_p/misc.py
--- /dev/null
+++ b/yt/frontends/enzo_p/misc.py
@@ -0,0 +1,77 @@
+"""
+Miscellaneous functions that are Enzo-P-specific
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2017, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+import numpy as np
+
+def bdecode(block):
+ if ":" in block:
+ level = len(block) - block.find(":") - 1
+ else:
+ level = 0
+ bst = block.replace(":", "")
+ d = float(2**len(bst))
+ left = int(bst, 2)
+ right = left + 1
+ left /= d
+ right /= d
+ return level, left, right
+
+def get_block_info(block, min_dim=3):
+ mybs = block[1:].split("_")
+ dim = max(len(mybs), min_dim)
+ left = np.zeros(dim)
+ right = np.ones(dim)
+ for i, myb in enumerate(mybs):
+ level, left[i], right[i] = bdecode(myb)
+ return level, left, right
+
+def get_root_blocks(block, min_dim=3):
+ mybs = block[1:].split("_")
+ dim = max(len(mybs), min_dim)
+ nb = np.ones(dim, dtype=int)
+ for i, myb in enumerate(mybs):
+ if ":" in myb:
+ s = myb.find(":")
+ else:
+ s = len(myb)
+ nb[i] = 2**s
+ return nb
+
+def get_root_block_id(block, min_dim=3):
+ mybs = block[1:].split("_")
+ dim = max(len(mybs), min_dim)
+ rbid = np.zeros(dim, dtype=int)
+ for i, myb in enumerate(mybs):
+ if ":" in myb:
+ s = myb.find(":")
+ else:
+ s = len(myb)
+ rbid[i] = int(myb[:s], 2)
+ return rbid
+
+def get_child_index(anc_id, desc_id):
+ cid = ""
+ for aind, dind in zip( anc_id.split("_"),
+ desc_id.split("_")):
+ cid += dind[len(aind)]
+ cid = int(cid, 2)
+ return cid
+
+def is_parent(anc_block, desc_block):
+ for aind, dind in zip( anc_block.split("_"),
+ desc_block.split("_")):
+ if not dind.startswith(aind):
+ return False
+ return True
diff -r 272125cbb417b446f20fec4d38e3c1e4efa54375 -r b8ae5d5e61686d61d691f33ace5397ffcf7f5c35 yt/frontends/enzo_p/tests/test_outputs.py
--- /dev/null
+++ b/yt/frontends/enzo_p/tests/test_outputs.py
@@ -0,0 +1,75 @@
+"""
+Enzo-P frontend tests
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2017, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+from yt.utilities.on_demand_imports import \
+ _h5py as h5py
+
+from yt.testing import \
+ assert_equal, \
+ requires_file, \
+ assert_array_equal
+from yt.utilities.answer_testing.framework import \
+ create_obj, \
+ data_dir_load, \
+ requires_ds, \
+ PixelizedProjectionValuesTest, \
+ FieldValuesTest
+from yt.frontends.enzo_p.api import EnzoPDataset
+
+_fields = ("density", "total_energy",
+ "velocity_x", "velocity_y")
+
+hello_world = "hello-0200/hello-0200.block_list"
+
+
+ at requires_file(hello_world)
+def test_EnzoPDataset():
+ assert isinstance(data_dir_load(hello_world), EnzoPDataset)
+
+ at requires_ds(hello_world)
+def test_hello_world():
+ ds = data_dir_load(hello_world)
+
+ dso = [ None, ("sphere", ("max", (0.25, 'unitary')))]
+ for dobj_name in dso:
+ for field in _fields:
+ for axis in [0, 1, 2]:
+ for weight_field in [None, "density"]:
+ yield PixelizedProjectionValuesTest(
+ hello_world, axis, field, weight_field,
+ dobj_name)
+ yield FieldValuesTest(hello_world, field, dobj_name)
+ dobj = create_obj(ds, dobj_name)
+ s1 = dobj["ones"].sum()
+ s2 = sum(mask.sum() for block, mask in dobj.blocks)
+ assert_equal(s1, s2)
+
+ at requires_file(hello_world)
+def test_hierarchy():
+ ds = data_dir_load(hello_world)
+
+ fh = h5py.File(ds.index.grids[0].filename, "r")
+ for grid in ds.index.grids:
+ assert_array_equal(
+ grid.LeftEdge.d, fh[grid.block_name].attrs["enzo_GridLeftEdge"])
+ assert_array_equal(
+ ds.index.grid_left_edge[grid.id], grid.LeftEdge)
+ assert_array_equal(
+ ds.index.grid_right_edge[grid.id], grid.RightEdge)
+ for child in grid.Children:
+ assert (child.LeftEdge >= grid.LeftEdge).all()
+ assert (child.RightEdge <= grid.RightEdge).all()
+ assert_equal(child.Parent.id, grid.id)
+ fh.close()
Repository URL: https://bitbucket.org/yt_analysis/yt/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
More information about the yt-svn
mailing list