[Yt-svn] commit/yt: 2 new changesets
Bitbucket
commits-noreply at bitbucket.org
Fri Jul 29 12:52:53 PDT 2011
2 new changesets in yt:
http://bitbucket.org/yt_analysis/yt/changeset/91b117ca654b/
changeset: 91b117ca654b
branch: yt
user: brittonsmith
date: 2011-07-29 21:52:35
summary: Removed derived dust temperature field.
affected #: 1 file (404 bytes)
--- a/yt/frontends/enzo/fields.py Mon Jul 25 09:53:27 2011 -0400
+++ b/yt/frontends/enzo/fields.py Fri Jul 29 15:52:35 2011 -0400
@@ -213,7 +213,7 @@
_default_fields = ["Density","Temperature",
"x-velocity","y-velocity","z-velocity",
"x-momentum","y-momentum","z-momentum",
- "Bx", "By", "Bz", "Dust_Temperature_Density"]
+ "Bx", "By", "Bz", "Dust_Temperature"]
# else:
# _default_fields = ["Density","Temperature","Gas_Energy","Total_Energy",
# "x-velocity","y-velocity","z-velocity"]
@@ -246,6 +246,8 @@
EnzoFieldInfo["Temperature"]._units = r"\rm{K}"
EnzoFieldInfo["Temperature"].units = r"K"
+EnzoFieldInfo["Dust_Temperature"]._units = r"\rm{K}"
+EnzoFieldInfo["Dust_Temperature"].units = r"K"
def _convertVelocity(data):
return data.convert("x-velocity")
@@ -255,17 +257,6 @@
f._convert_function = _convertVelocity
f.take_log = False
-# Dust temperature - raw field is T_dust * Density
-def _dust_temperature(field, data):
- return data['Dust_Temperature_Density'] / data['Density']
-def _convert_dust_temperature(data):
- ef = (1.0 + data.pf.current_redshift)**3.0
- return data.convert("Density") / ef
-add_field("Dust_Temperature", function=_dust_temperature,
- convert_function=_convert_dust_temperature, take_log=True,
- validators=[ValidateDataField('Dust_Temperature_Density')],
- units = r"K")
-
def _spdensity(field, data):
blank = na.zeros(data.ActiveDimensions, dtype='float32')
if data.NumberOfParticles == 0: return blank
http://bitbucket.org/yt_analysis/yt/changeset/26614b0e924b/
changeset: 26614b0e924b
branch: yt
user: brittonsmith
date: 2011-07-29 21:52:48
summary: Merged.
affected #: 22 files (49.0 KB)
--- a/yt/analysis_modules/halo_finding/halo_objects.py Fri Jul 29 15:52:35 2011 -0400
+++ b/yt/analysis_modules/halo_finding/halo_objects.py Fri Jul 29 15:52:48 2011 -0400
@@ -228,7 +228,8 @@
r"""Returns a sphere source.
This will generate a new, empty sphere source centered on this halo,
- with the maximum radius of the halo.
+ with the maximum radius of the halo. This can be used like any other
+ data container in yt.
Parameters
----------
@@ -974,6 +975,34 @@
"""
return self.max_radius
+ def get_sphere(self):
+ r"""Returns a sphere source.
+
+ This will generate a new, empty sphere source centered on this halo,
+ with the maximum radius of the halo. This can be used like any other
+ data container in yt.
+
+ Parameters
+ ----------
+ center_of_mass : bool, optional
+ True chooses the center of mass when calculating the maximum radius.
+ False chooses from the maximum density location for HOP halos
+ (it has no effect for FOF halos).
+ Default = True.
+
+ Returns
+ -------
+ sphere : `yt.data_objects.api.AMRSphereBase`
+ The empty data source.
+
+ Examples
+ --------
+ >>> sp = halos[0].get_sphere()
+ """
+ cen = self.center_of_mass()
+ r = self.maximum_radius()
+ return self.pf.h.sphere(cen, r)
+
class HaloList(object):
_fields = ["particle_position_%s" % ax for ax in 'xyz']
@@ -1337,7 +1366,11 @@
locations = []
for line in lines:
line = line.split()
- locations.append(line[1:])
+ # Prepend the hdf5 file names with the full path.
+ temp = []
+ for item in line[1:]:
+ temp.append(self.pf.fullpath + '/' + item)
+ locations.append(temp)
lines.close()
return locations
@@ -2216,4 +2249,4 @@
LoadedHaloList.__init__(self, pf, self.basename)
-
\ No newline at end of file
+
--- a/yt/data_objects/grid_patch.py Fri Jul 29 15:52:35 2011 -0400
+++ b/yt/data_objects/grid_patch.py Fri Jul 29 15:52:48 2011 -0400
@@ -54,12 +54,13 @@
'start_index', 'filename', '__weakref__', 'dds',
'_child_mask', '_child_indices', '_child_index_mask',
'_parent_id', '_children_ids']
- def __init__(self, id, filename = None, hierarchy = None):
+
+ def __init__(self, id, filename=None, hierarchy=None):
self.data = {}
self.field_parameters = {}
self.id = id
if hierarchy: self.hierarchy = weakref.proxy(hierarchy)
- self.pf = self.hierarchy.parameter_file # weakref already
+ self.pf = self.hierarchy.parameter_file # weakref already
self._child_mask = self._child_indices = self._child_index_mask = None
self.start_index = None
@@ -67,6 +68,7 @@
"""
Return the integer starting index for each dimension at the current
level.
+
"""
if self.start_index != None:
return self.start_index
@@ -161,7 +163,7 @@
def keys(self):
return self.data.keys()
-
+
def get_data(self, field):
"""
Returns a field or set of fields for a key or set of keys
@@ -230,7 +232,7 @@
cond = na.logical_and(cond, self.RightEdge[y] >= LE[:,y])
cond = na.logical_and(cond, self.LeftEdge[y] <= RE[:,y])
return cond
-
+
def __repr__(self):
return "AMRGridPatch_%04i" % (self.id)
@@ -373,7 +375,7 @@
mask[startIndex[0]:endIndex[0],
startIndex[1]:endIndex[1],
startIndex[2]:endIndex[2]] = tofill
-
+
def __generate_child_mask(self):
"""
Generates self.child_mask, which is zero where child grids exist (and
@@ -475,7 +477,7 @@
na.multiply(new_field, 0.125, new_field)
if self.pf.field_info[field].take_log:
new_field = na.log10(new_field)
-
+
new_field[:,:, -1] = 2.0*new_field[:,:,-2] - new_field[:,:,-3]
new_field[:,:, 0] = 2.0*new_field[:,:,1] - new_field[:,:,2]
--- a/yt/data_objects/static_output.py Fri Jul 29 15:52:35 2011 -0400
+++ b/yt/data_objects/static_output.py Fri Jul 29 15:52:48 2011 -0400
@@ -47,11 +47,11 @@
class __metaclass__(type):
def __init__(cls, name, b, d):
type.__init__(cls, name, b, d)
- output_type_registry[name]=cls
+ output_type_registry[name] = cls
mylog.debug("Registering: %s as %s", name, cls)
def __new__(cls, filename=None, *args, **kwargs):
- if not isinstance(filename, types.StringTypes):
+ if not isinstance(filename, types.StringTypes):
obj = object.__new__(cls)
obj.__init__(filename, *args, **kwargs)
return obj
@@ -69,21 +69,27 @@
"""
self.data_style = data_style
self.file_style = file_style
+ self.conversion_factors = {}
+ self.parameters = {}
+
+ # path stuff
self.parameter_filename = str(filename)
self.basename = os.path.basename(filename)
self.directory = os.path.expanduser(os.path.dirname(filename))
self.fullpath = os.path.abspath(self.directory)
- self._instantiated = time.time()
if len(self.directory) == 0:
self.directory = "."
- self.conversion_factors = {}
- self.parameters = {}
+
+ # to get the timing right, do this before the heavy lifting
+ self._instantiated = time.time()
+
self._parse_parameter_file()
self._set_units()
+
# Because we need an instantiated class to check the pf's existence in
# the cache, we move that check to here from __new__. This avoids
# double-instantiation.
- if ytcfg.getboolean('yt','serialize'):
+ if ytcfg.getboolean('yt', 'serialize'):
try:
_pf_store.check_pf(self)
except NoParameterShelf:
@@ -111,9 +117,7 @@
return False
def __getitem__(self, key):
- """
- Returns _units, parameters, or _conversion_factors in that order
- """
+ """ Returns units, parameters, or conversion_factors in that order. """
for d in [self.units, self.time_units, self.parameters, \
self.conversion_factors]:
if key in d: return d[key]
@@ -121,8 +125,9 @@
def keys(self):
"""
- Returns a list of possible keys, from _units, parameters and
- _conversion_factors
+ Returns a list of possible keys, from units, parameters and
+ conversion_factors.
+
"""
return self.units.keys() \
+ self.time_units.keys() \
@@ -137,7 +142,7 @@
def get_smallest_appropriate_unit(self, v):
max_nu = 1e30
good_u = None
- for unit in ['mpc','kpc','pc','au','rsun','cm']:
+ for unit in ['mpc', 'kpc', 'pc', 'au', 'rsun', 'cm']:
vv = v*self[unit]
if vv < max_nu and vv > 1.0:
good_u = unit
@@ -146,7 +151,8 @@
def has_key(self, key):
"""
- Returns true or false
+ Checks units, parameters, and conversion factors. Returns a boolean.
+
"""
return key in self.units or \
key in self.time_units or \
@@ -162,19 +168,19 @@
self._instantiated_hierarchy = self._hierarchy_class(
self, data_style=self.data_style)
return self._instantiated_hierarchy
- h = hierarchy
+ h = hierarchy # alias
@parallel_root_only
def print_key_parameters(self):
for a in ["current_time", "domain_dimensions", "domain_left_edge",
- "domain_right_edge", "cosmological_simulation"]:
+ "domain_right_edge", "cosmological_simulation"]:
if not hasattr(self, a):
mylog.error("Missing %s in parameter file definition!", a)
continue
v = getattr(self, a)
mylog.info("Parameters: %-25s = %s", a, v)
if hasattr(self, "cosmological_simulation") and \
- getattr(self, "cosmological_simulation"):
+ getattr(self, "cosmological_simulation"):
for a in ["current_redshift", "omega_lambda", "omega_matter",
"hubble_constant"]:
if not hasattr(self, a):
--- a/yt/frontends/castro/data_structures.py Fri Jul 29 15:52:35 2011 -0400
+++ b/yt/frontends/castro/data_structures.py Fri Jul 29 15:52:48 2011 -0400
@@ -1,5 +1,5 @@
"""
-Data structures for Castro.
+Data structures for Castro.
Author: J. S. Oishi <jsoishi at gmail.com>
Affiliation: KIPAC/SLAC/Stanford
@@ -69,7 +69,7 @@
self.filename = filename
self._offset = offset
self._paranoid = paranoia
-
+
# should error check this
self.ActiveDimensions = (dimensions.copy()).astype('int32')#.transpose()
self.start_index = start.copy()#.transpose()
@@ -134,14 +134,14 @@
#self._setup_classes()
# This also sets up the grid objects
- self.read_global_header(header_filename, self.parameter_file.paranoid_read)
+ self.read_global_header(header_filename, self.parameter_file.paranoid_read)
self.read_particle_header()
self.__cache_endianness(self.levels[-1].grids[-1])
AMRHierarchy.__init__(self, pf, self.data_style)
self._setup_data_io()
self._setup_field_list()
self._populate_hierarchy()
-
+
def read_global_header(self, filename, paranoid_read):
"""
read the global header file for an Castro plotfile output.
@@ -280,7 +280,7 @@
self.num_grids = grid_counter
self.float_type = 'float64'
- self.maxLevel = self.n_levels - 1
+ self.maxLevel = self.n_levels - 1
self.max_level = self.n_levels - 1
header_file.close()
@@ -320,7 +320,7 @@
header = inFile.readline()
inFile.close()
header.strip()
-
+
# parse it. the patter is in CastroDefs.py
headerRe = re.compile(castro_FAB_header_pattern)
bytesPerReal, endian, start, stop, centerType, nComponents = headerRe.search(header).groups()
@@ -340,7 +340,7 @@
stop = na.array(map(int, start_stop[1].split(',')))
dimension = stop - start + 1
return dimension, start, stop
-
+
def _populate_grid_objects(self):
mylog.debug("Creating grid objects")
self.grids = na.concatenate([level.grids for level in self.levels])
@@ -437,7 +437,7 @@
particle_type=True)
def _count_grids(self):
- """this is already provided in
+ """this is already provided in
"""
pass
@@ -452,7 +452,7 @@
def _parse_hierarchy(self):
pass
-
+
def _detect_fields(self):
pass
@@ -482,13 +482,13 @@
self._data_file = None
self._data_mode = None
self._max_locations = {}
-
+
class CastroLevel:
def __init__(self, level, ngrids):
self.level = level
self.ngrids = ngrids
self.grids = []
-
+
class CastroStaticOutput(StaticOutput):
"""
@@ -551,10 +551,12 @@
pfn = os.path.join(pfname)
if not os.path.exists(pfn): return False
castro = any(("castro." in line for line in open(pfn)))
+ nyx = any(("nyx." in line for line in open(pfn)))
+ castro = castro and (not nyx) # it's only castro if it's not nyx
maestro = os.path.exists(os.path.join(pname, "job_info"))
orion = (not castro) and (not maestro)
return castro
-
+
def _parse_parameter_file(self):
"""
Parses the parameter file and establishes the various
@@ -596,7 +598,7 @@
self.parameters[paramName] = t[0]
else:
self.parameters[paramName] = t
-
+
elif param.startswith("geometry.prob_hi"):
self.domain_right_edge = \
na.array([float(i) for i in vals.split()])
@@ -649,7 +651,7 @@
"""
Parses the BoxLib header file to get any parameters stored
there. Hierarchy information is read out of this file in
- CastroHierarchy.
+ CastroHierarchy.
Currently, only Time is read here.
"""
@@ -660,7 +662,7 @@
self.current_time = float(lines[3+n_fields])
-
+
def _set_units(self):
"""
Generates the conversion to various physical _units based on the parameter file
@@ -680,7 +682,7 @@
self.conversion_factors["Time"] = 1.0
for unit in mpc_conversion.keys():
self.units[unit] = mpc_conversion[unit] / mpc_conversion["cm"]
-
+
self.conversion_factors = defaultdict(lambda: 1.0)
self.time_units['1'] = 1
self.units['1'] = 1.0
--- a/yt/frontends/castro/definitions.py Fri Jul 29 15:52:35 2011 -0400
+++ b/yt/frontends/castro/definitions.py Fri Jul 29 15:52:48 2011 -0400
@@ -5,7 +5,7 @@
Affiliation: KIPAC/SLAC/Stanford
Homepage: http://yt.enzotools.org/
License:
- Copyright (C) 2008-20010 J.S. Oishi. All Rights Reserved.
+ Copyright (C) 2008-2010 J.S. Oishi. All Rights Reserved.
This file is part of yt.
@@ -89,4 +89,4 @@
castro_particle_field_names = \
['particle_position_%s' % ax for ax in 'xyz'] + \
['particle_mass'] + \
- ['particle_velocity_%s' % ax for ax in 'xyz']
+ ['particle_velocity_%s' % ax for ax in 'xyz']
--- a/yt/frontends/chombo/fields.py Fri Jul 29 15:52:35 2011 -0400
+++ b/yt/frontends/chombo/fields.py Fri Jul 29 15:52:48 2011 -0400
@@ -41,39 +41,38 @@
add_field = add_chombo_field
add_field("density", function=lambda a,b: None, take_log=True,
- validators = [ValidateDataField("density")],
- units=r"\rm{g}/\rm{cm}^3")
-
+ validators=[ValidateDataField("density")],
+ units=r"\rm{g} / \rm{cm}^3")
ChomboFieldInfo["density"]._projected_units =r"\rm{g}/\rm{cm}^2"
add_field("X-momentum", function=lambda a,b: None, take_log=False,
- validators = [ValidateDataField("X-Momentum")],
- units=r"",display_name=r"B_x")
+ validators=[ValidateDataField("X-Momentum")],
+ units=r"", display_name=r"x momentum")
ChomboFieldInfo["X-momentum"]._projected_units=r""
add_field("Y-momentum", function=lambda a,b: None, take_log=False,
- validators = [ValidateDataField("Y-Momentum")],
- units=r"",display_name=r"B_y")
+ validators=[ValidateDataField("Y-Momentum")],
+ units=r"", display_name=r"y momentum")
ChomboFieldInfo["Y-momentum"]._projected_units=r""
add_field("Z-momentum", function=lambda a,b: None, take_log=False,
- validators = [ValidateDataField("Z-Momentum")],
- units=r"",display_name=r"B_z")
+ validators=[ValidateDataField("Z-Momentum")],
+ units=r"", display_name=r"z momentum")
ChomboFieldInfo["Z-momentum"]._projected_units=r""
add_field("X-magnfield", function=lambda a,b: None, take_log=False,
- validators = [ValidateDataField("X-Magnfield")],
- units=r"",display_name=r"B_x")
+ validators=[ValidateDataField("X-Magnfield")],
+ units=r"", display_name=r"B_x")
ChomboFieldInfo["X-magnfield"]._projected_units=r""
add_field("Y-magnfield", function=lambda a,b: None, take_log=False,
- validators = [ValidateDataField("Y-Magnfield")],
- units=r"",display_name=r"B_y")
+ validators=[ValidateDataField("Y-Magnfield")],
+ units=r"", display_name=r"B_y")
ChomboFieldInfo["Y-magnfield"]._projected_units=r""
add_field("Z-magnfield", function=lambda a,b: None, take_log=False,
- validators = [ValidateDataField("Z-Magnfield")],
- units=r"",display_name=r"B_z")
+ validators=[ValidateDataField("Z-Magnfield")],
+ units=r"", display_name=r"B_z")
ChomboFieldInfo["Z-magnfield"]._projected_units=r""
def _MagneticEnergy(field,data):
@@ -81,21 +80,17 @@
data["Y-magnfield"]**2 +
data["Z-magnfield"]**2)/2.
add_field("MagneticEnergy", function=_MagneticEnergy, take_log=True,
- units=r"",display_name=r"B^2/8\pi")
+ units=r"", display_name=r"B^2 / 8 \pi")
ChomboFieldInfo["MagneticEnergy"]._projected_units=r""
def _xVelocity(field, data):
- """generate x-velocity from x-momentum and density
-
- """
+ """ Generate x-velocity from x-momentum and density. """
return data["X-momentum"]/data["density"]
add_field("x-velocity",function=_xVelocity, take_log=False,
units=r'\rm{cm}/\rm{s}')
def _yVelocity(field,data):
- """generate y-velocity from y-momentum and density
-
- """
+ """ Generate y-velocity from y-momentum and density. """
#try:
# return data["xvel"]
#except KeyError:
@@ -104,10 +99,7 @@
units=r'\rm{cm}/\rm{s}')
def _zVelocity(field,data):
- """generate z-velocity from z-momentum and density
-
- """
+ """ Generate z-velocity from z-momentum and density. """
return data["Z-momentum"]/data["density"]
add_field("z-velocity",function=_zVelocity, take_log=False,
units=r'\rm{cm}/\rm{s}')
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/yt/frontends/nyx/api.py Fri Jul 29 15:52:48 2011 -0400
@@ -0,0 +1,29 @@
+"""
+API for yt.frontends.nyx
+
+Author: Casey W. Stark <caseywstark at gmail.com>
+Affiliation: UC Berkeley
+Homepage: http://yt.enzotools.org/
+License:
+ Copyright (C) 2011 Casey W. Stark, Matthew Turk. All Rights Reserved.
+
+ This file is part of yt.
+
+ yt is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from .data_structures import NyxGrid, NyxHierarchy, NyxStaticOutput
+from .fields import NyxFieldContainer, nyx_fields, add_nyx_field
+from .io import IOHandlerNative
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/yt/frontends/nyx/data_structures.py Fri Jul 29 15:52:48 2011 -0400
@@ -0,0 +1,759 @@
+"""
+Data structures for Nyx.
+
+Author: Casey W. Stark <caseywstark at gmail.com>
+Affiliation: UC Berkeley
+Author: J. S. Oishi <jsoishi at gmail.com>
+Affiliation: KIPAC/SLAC/Stanford
+Homepage: http://yt.enzotools.org/
+License:
+ Copyright (C) 2011 Casey W. Stark, J. S. Oishi, Matthew Turk. All Rights
+ Reserved.
+
+ This file is part of yt.
+
+ yt is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from collections import defaultdict
+import itertools
+import os
+import re
+from stat import ST_CTIME
+from string import strip, rstrip
+import weakref
+
+import numpy as na
+
+from yt.funcs import *
+from yt.data_objects.grid_patch import AMRGridPatch
+from yt.data_objects.hierarchy import AMRHierarchy
+from yt.data_objects.static_output import StaticOutput
+from yt.utilities.amr_utils import get_box_grids_level
+from yt.utilities.definitions import mpc_conversion
+
+from .definitions import parameter_type_dict, nyx_to_enzo_dict, \
+ fab_header_pattern, nyx_particle_field_names
+from .utils import boxlib_bool_to_int
+from .fields import NyxFieldContainer, add_field
+
+
+class NyxGrid(AMRGridPatch):
+ _id_offset = 0
+
+ def __init__(self, left_edge, right_edge, index, level, filename, offset,
+ dimensions, start, stop, **kwargs):
+ """ Build a grid that understands Nyx's boxlib format. """
+ # passes index as the patch ``id``
+ AMRGridPatch.__init__(self, index, **kwargs)
+ self.filename = filename
+ self._offset = offset
+
+ # @todo: enzo-isms.
+ # Must copy to avoid refs, in case the user alters the args later.
+ self.ActiveDimensions = (dimensions.copy()).astype('int32')
+ self.start_index = start.copy()
+ self.stop_index = stop.copy()
+ self.LeftEdge = left_edge.copy()
+ self.RightEdge = right_edge.copy()
+ self.index = index
+ self.Level = level
+
+ def get_global_startindex(self):
+ return self.start_index
+
+ def _prepare_grid(self):
+ """ Copies all the appropriate attributes from the hierarchy. """
+ # This is definitely the slowest part of generating the hierarchy
+ h = self.hierarchy # alias
+ h.grid_levels[self.id, 0] = self.Level
+ h.grid_left_edge[self.id,:] = self.LeftEdge[:]
+ h.grid_right_edge[self.id,:] = self.RightEdge[:]
+
+ # Might still work
+ #self.Time = h.gridTimes[self.id,0]
+ #self.NumberOfParticles = h.gridNumberOfParticles[self.id,0]
+
+ # @todo: enzo-isms
+ self.field_indexes = h.field_indexes
+ self.Children = h.gridTree[self.id]
+ pIDs = h.gridReverseTree[self.id]
+
+ if len(pIDs) > 0:
+ self.Parent = [weakref.proxy(h.grids[pID]) for pID in pIDs]
+ else:
+ self.Parent = None
+
+ def _setup_dx(self):
+ # So first we figure out what the index is. We don't assume that
+ # dx=dy=dz, at least here. We probably do elsewhere.
+ id = self.id - self._id_offset
+ if self.Parent is not None:
+ self.dds = self.Parent[0].dds / self.pf.refine_by
+ else:
+ LE, RE = self.hierarchy.grid_left_edge[id,:], \
+ self.hierarchy.grid_right_edge[id,:]
+ self.dds = na.array((RE - LE) / self.ActiveDimensions)
+
+ if self.pf.dimensionality < 2: self.dds[1] = 1.0
+ if self.pf.dimensionality < 3: self.dds[2] = 1.0
+ self.data['dx'], self.data['dy'], self.data['dz'] = self.dds
+
+ def __repr__(self):
+ return "NyxGrid_%04i" % (self.id)
+
+class NyxHierarchy(AMRHierarchy):
+ grid = NyxGrid
+
+ def __init__(self, pf, data_style="nyx_native"):
+ self.field_info = NyxFieldContainer()
+ self.field_indexes = {}
+ self.parameter_file = weakref.proxy(pf)
+ self.directory = pf.path
+ header_path = os.path.join(self.directory, "Header") # make a kwarg?
+
+ self.data_style = data_style
+ #self._setup_classes()
+
+ # This also sets up the grid objects
+ self.read_global_header(header_path)
+ self.read_particle_header()
+ self.__cache_endianness(self.levels[-1].grids[-1])
+
+ # @todo: should be first line
+ AMRHierarchy.__init__(self, pf, self.data_style)
+ self._setup_data_io()
+ self._setup_field_list()
+ self._populate_hierarchy()
+
+ def read_global_header(self, header_path):
+ """ Read the global header file for an Nyx plotfile output. """
+ counter = 0
+ header_file = open(header_path, 'r')
+ self.__global_header_lines = header_file.readlines()
+
+ # parse the file
+ self.nyx_version = self.__global_header_lines[0].rstrip()
+ self.n_fields = int(self.__global_header_lines[1])
+
+ # why the 2?
+ counter = self.n_fields + 2
+ self.field_list = []
+ for i, line in enumerate(self.__global_header_lines[2:counter]):
+ self.field_list.append(line.rstrip())
+
+ # figure out dimensions and make sure it's 3D
+ self.dimension = int(self.__global_header_lines[counter])
+ if self.dimension != 3:
+ raise RunTimeError("Current data is %iD. yt only supports Nyx data in 3D" % self.dimension)
+
+ counter += 1
+ self.Time = float(self.__global_header_lines[counter])
+ counter += 1
+ self.finest_grid_level = int(self.__global_header_lines[counter])
+ self.n_levels = self.finest_grid_level + 1
+ counter += 1
+
+ # quantities with _unnecessary are also stored in the inputs
+ # file and are not needed. they are read in and stored in
+ # case in the future we want to enable a "backwards" way of
+ # taking the data out of the Header file and using it to fill
+ # in in the case of a missing inputs file
+ self.domainLeftEdge_unnecessary = na.array(map(float, self.__global_header_lines[counter].split()))
+ counter += 1
+ self.domainRightEdge_unnecessary = na.array(map(float, self.__global_header_lines[counter].split()))
+ counter += 1
+ self.refinementFactor_unnecessary = self.__global_header_lines[counter].split() #na.array(map(int, self.__global_header_lines[counter].split()))
+ counter += 1
+ self.globalIndexSpace_unnecessary = self.__global_header_lines[counter]
+ counter += 1
+ self.timestepsPerLevel_unnecessary = self.__global_header_lines[counter]
+ counter += 1
+
+ self.dx = na.zeros((self.n_levels, 3))
+ for i, line in enumerate(self.__global_header_lines[counter:counter + self.n_levels]):
+ self.dx[i] = na.array(map(float, line.split()))
+ counter += self.n_levels
+ self.geometry = int(self.__global_header_lines[counter])
+ if self.geometry != 0:
+ raise RunTimeError("yt only supports cartesian coordinates.")
+ counter += 1
+
+ # @todo: this is just to debug. eventually it should go away.
+ linebreak = int(self.__global_header_lines[counter])
+ if linebreak != 0:
+ raise RunTimeError("INTERNAL ERROR! This should be a zero.")
+ counter += 1
+
+ # each level is one group with ngrids on it. each grid has 3 lines of 2
+ # reals
+ self.levels = []
+ grid_counter = 0
+ file_finder_pattern = r"FabOnDisk: (\w+_D_[0-9]{4}) (\d+)\n"
+ re_file_finder = re.compile(file_finder_pattern)
+ dim_finder_pattern = r"\(\((\d+,\d+,\d+)\) \((\d+,\d+,\d+)\) \(\d+,\d+,\d+\)\)\n"
+ re_dim_finder = re.compile(dim_finder_pattern)
+ data_files_pattern = r"Level_[\d]/"
+ data_files_finder = re.compile(data_files_pattern)
+
+ for level in range(0, self.n_levels):
+ tmp = self.__global_header_lines[counter].split()
+ # should this be grid_time or level_time??
+ lev, ngrids, grid_time = int(tmp[0]), int(tmp[1]), float(tmp[2])
+ counter += 1
+ nsteps = int(self.__global_header_lines[counter])
+ counter += 1
+ self.levels.append(NyxLevel(lev, ngrids))
+
+ # Open level header, extract file names and offsets for each grid
+ # read slightly out of order here: at the end of the lo, hi pairs
+ # for x, y, z is a *list* of files types in the Level directory.
+ # Each type has Header and a number of data files (one per
+ # processor)
+ tmp_offset = counter + 3 * ngrids
+ nfiles = 0
+ key_off = 0
+ files = {}
+ offsets = {}
+ while nfiles + tmp_offset < len(self.__global_header_lines) \
+ and data_files_finder.match(self.__global_header_lines[nfiles + tmp_offset]):
+ filen = os.path.join(self.parameter_file.path, \
+ self.__global_header_lines[nfiles + tmp_offset].strip())
+ # open each "_H" header file, and get the number of
+ # components within it
+ level_header_file = open(filen + '_H', 'r').read()
+ start_stop_index = re_dim_finder.findall(level_header_file) # just take the last one
+ grid_file_offset = re_file_finder.findall(level_header_file)
+ ncomp_this_file = int(level_header_file.split('\n')[2])
+
+ for i in range(ncomp_this_file):
+ key = self.field_list[i + key_off]
+ f, o = zip(*grid_file_offset)
+ files[key] = f
+ offsets[key] = o
+ self.field_indexes[key] = i
+
+ key_off += ncomp_this_file
+ nfiles += 1
+
+ # convert dict of lists to list of dicts
+ fn = []
+ off = []
+ lead_path = os.path.join(self.parameter_file.path,
+ 'Level_%i' % level)
+ for i in range(ngrids):
+ fi = [os.path.join(lead_path, files[key][i]) for key in self.field_list]
+ of = [int(offsets[key][i]) for key in self.field_list]
+ fn.append(dict(zip(self.field_list, fi)))
+ off.append(dict(zip(self.field_list, of)))
+
+ for grid in range(0, ngrids):
+ gfn = fn[grid] # filename of file containing this grid
+ gfo = off[grid] # offset within that file
+ xlo, xhi = map(float, self.__global_header_lines[counter].split())
+ counter += 1
+ ylo, yhi = map(float, self.__global_header_lines[counter].split())
+ counter += 1
+ zlo, zhi = map(float, self.__global_header_lines[counter].split())
+ counter += 1
+ lo = na.array([xlo, ylo, zlo])
+ hi = na.array([xhi, yhi, zhi])
+ dims, start, stop = self.__calculate_grid_dimensions(start_stop_index[grid])
+ self.levels[-1].grids.append(self.grid(lo, hi, grid_counter,
+ level, gfn, gfo, dims, start, stop,
+ hierarchy=self))
+ grid_counter += 1 # this is global, and shouldn't be reset
+ # for each level
+
+ # already read the filenames above...
+ counter += nfiles
+ self.num_grids = grid_counter
+ self.float_type = 'float64'
+
+ self.maxLevel = self.n_levels - 1
+ self.max_level = self.n_levels - 1
+ header_file.close()
+
+ def read_particle_header(self):
+ # We need to get particle offsets and particle counts
+ if not self.parameter_file.use_particles:
+ self.pgrid_info = na.zeros((self.num_grids, 3), dtype='int64')
+ return
+ self.field_list += nyx_particle_field_names[:]
+ header = open(os.path.join(self.parameter_file.path, "DM", "Header"))
+ version = header.readline()
+ ndim = header.readline()
+ nfields = header.readline()
+ ntotalpart = int(header.readline())
+ dummy = header.readline() # nextid
+ maxlevel = int(header.readline()) # max level
+
+ # Skip over how many grids on each level; this is degenerate
+ for i in range(maxlevel + 1):dummy = header.readline()
+
+ grid_info = na.fromiter((int(i) for line in header.readlines()
+ for i in line.split()),
+ dtype='int64',
+ count=3*self.num_grids).reshape((self.num_grids, 3))
+ self.pgrid_info = grid_info
+
+ def __cache_endianness(self, test_grid):
+ """
+ Cache the endianness and bytes per real of the grids by using a test
+ grid and assuming that all grids have the same endianness. This is a
+ pretty safe assumption since Nyx uses one file per processor (@todo:
+ make sure this is still true, I don't think so). If you are running on a
+ cluster with different endian processors, then you are disappoint.
+
+ """
+ # open the test file & grab the header
+ inFile = open(os.path.expanduser(test_grid.filename[self.field_list[0]]), 'rb')
+ header = inFile.readline()
+ inFile.close()
+ header.strip()
+
+ headerRe = re.compile(fab_header_pattern)
+ bytesPerReal, endian, start, stop, centerType, nComponents = \
+ headerRe.search(header).groups()
+ self._bytesPerReal = int(bytesPerReal)
+ if self._bytesPerReal == int(endian[0]):
+ dtype = '<'
+ elif self._bytesPerReal == int(endian[-1]):
+ dtype = '>'
+ else:
+ raise ValueError("FAB header is neither big nor little endian. Perhaps the file is corrupt?")
+
+ dtype += ('f%i' % self._bytesPerReal) # always a floating point
+ self._dtype = dtype
+
+ def __calculate_grid_dimensions(self, start_stop):
+ start = na.array(map(int, start_stop[0].split(',')))
+ stop = na.array(map(int, start_stop[1].split(',')))
+ dimension = stop - start + 1
+ return dimension, start, stop
+
+ def _populate_grid_objects(self):
+ mylog.debug("Creating grid objects")
+
+ self.grids = na.concatenate([level.grids for level in self.levels])
+ basedir = self.parameter_file.path
+ for g, pg in itertools.izip(self.grids, self.pgrid_info):
+ g.particle_filename = os.path.join(basedir, "DM",
+ "Level_%s" % (g.Level),
+ "DATA_%04i" % pg[0])
+ g.NumberOfParticles = pg[1]
+ g._particle_offset = pg[2]
+
+ self.grid_particle_count[:,0] = self.pgrid_info[:,1]
+ del self.pgrid_info # if this is all pgrid_info is used for...
+
+ gls = na.concatenate([level.ngrids * [level.level] for level in self.levels])
+ self.grid_levels[:] = gls.reshape((self.num_grids, 1))
+ grid_dcs = na.concatenate([level.ngrids*[self.dx[level.level]]
+ for level in self.levels], axis=0)
+
+ self.grid_dxs = grid_dcs[:,0].reshape((self.num_grids, 1))
+ self.grid_dys = grid_dcs[:,1].reshape((self.num_grids, 1))
+ self.grid_dzs = grid_dcs[:,2].reshape((self.num_grids, 1))
+
+ left_edges = []
+ right_edges = []
+ dims = []
+ for level in self.levels:
+ left_edges += [g.LeftEdge for g in level.grids]
+ right_edges += [g.RightEdge for g in level.grids]
+ dims += [g.ActiveDimensions for g in level.grids]
+
+ self.grid_left_edge = na.array(left_edges)
+ self.grid_right_edge = na.array(right_edges)
+ self.grid_dimensions = na.array(dims)
+ self.gridReverseTree = [] * self.num_grids
+ self.gridReverseTree = [ [] for i in range(self.num_grids)] # why the same thing twice?
+ self.gridTree = [ [] for i in range(self.num_grids)] # meh
+
+ mylog.debug("Done creating grid objects")
+
+ def _populate_hierarchy(self):
+ self.__setup_grid_tree()
+
+ for i, grid in enumerate(self.grids):
+ if (i%1e4) == 0:
+ mylog.debug("Prepared % 7i / % 7i grids", i, self.num_grids)
+
+ grid._prepare_grid()
+ grid._setup_dx()
+
+ def __setup_grid_tree(self):
+ mask = na.empty(self.grids.size, dtype='int32')
+ for i, grid in enumerate(self.grids):
+ get_box_grids_level(grid.LeftEdge, grid.RightEdge, grid.Level + 1,
+ self.grid_left_edge, self.grid_right_edge,
+ self.grid_levels, mask)
+ children = self.grids[mask.astype("bool")]
+ for child in children:
+ self.gridReverseTree[child.id].append(i)
+ self.gridTree[i].append(weakref.proxy(child))
+
+ def _setup_classes(self):
+ dd = self._get_data_reader_dict()
+ dd["field_indexes"] = self.field_indexes
+ AMRHierarchy._setup_classes(self, dd)
+ self.object_types.sort()
+
+ def _get_grid_children(self, grid):
+ mask = na.zeros(self.num_grids, dtype='bool')
+ grids, grid_ind = self.get_box_grids(grid.LeftEdge, grid.RightEdge)
+ mask[grid_ind] = True
+ mask = na.logical_and(mask, (self.grid_levels == (grid.Level + 1)).flat)
+ return self.grids[mask]
+
+ def _setup_field_list(self):
+ self.derived_field_list = []
+
+ for field in self.field_info:
+ try:
+ fd = self.field_info[field].get_dependencies(pf=self.parameter_file)
+ except:
+ continue
+ available = na.all([f in self.field_list for f in fd.requested])
+ if available: self.derived_field_list.append(field)
+
+ for field in self.field_list:
+ if field not in self.derived_field_list:
+ self.derived_field_list.append(field)
+
+ if self.parameter_file.use_particles:
+ # We know which particle fields will exist -- pending further
+ # changes in the future.
+ for field in nyx_particle_field_names:
+ def external_wrapper(f):
+ def _convert_function(data):
+ return data.convert(f)
+ return _convert_function
+ cf = external_wrapper(field)
+ # Note that we call add_field on the field_info directly. This
+ # will allow the same field detection mechanism to work for 1D,
+ # 2D and 3D fields.
+ self.pf.field_info.add_field(field, lambda a, b: None,
+ convert_function=cf,
+ take_log=False, particle_type=True)
+
+ def _count_grids(self):
+ """ this is already provided in ??? """
+ pass
+
+ def _initialize_grid_arrays(self):
+ mylog.debug("Allocating arrays for %s grids", self.num_grids)
+ self.grid_dimensions = na.ones((self.num_grids, 3), 'int32')
+ self.grid_left_edge = na.zeros((self.num_grids, 3), self.float_type)
+ self.grid_right_edge = na.ones((self.num_grids, 3), self.float_type)
+ self.grid_levels = na.zeros((self.num_grids, 1), 'int32')
+ self.grid_particle_count = na.zeros((self.num_grids, 1), 'int32')
+
+ def _parse_hierarchy(self):
+ pass
+
+ def _detect_fields(self):
+ pass
+
+ def _setup_unknown_fields(self):
+ # Doesn't seem useful
+ for field in self.field_list:
+ if field in self.parameter_file.field_info: continue
+ mylog.info("Adding %s to list of fields", field)
+ cf = None
+ if self.parameter_file.has_key(field):
+ def external_wrapper(f):
+ def _convert_function(data):
+ return data.convert(f)
+ return _convert_function
+ cf = external_wrapper(field)
+ add_field(field, lambda a, b: None, convert_function=cf,
+ take_log=False)
+
+ def _setup_derived_fields(self):
+ pass
+
+ def _initialize_state_variables(self):
+ """
+ Override not to re-initialize num_grids in AMRHierarchy.__init__
+
+ """
+ self._parallel_locking = False
+ self._data_file = None
+ self._data_mode = None
+ self._max_locations = {}
+
+class NyxLevel:
+ def __init__(self, level, ngrids):
+ self.level = level
+ self.ngrids = ngrids
+ self.grids = []
+
+class NyxStaticOutput(StaticOutput):
+ """
+ This class is a stripped down class that simply reads and parses *filename*,
+ without looking at the Nyx hierarchy.
+
+ """
+ _hierarchy_class = NyxHierarchy
+ _fieldinfo_class = NyxFieldContainer
+
+ @classmethod
+ def _is_valid(cls, *args, **kwargs):
+ # fill our args
+ pname = args[0].rstrip("/")
+ dn = os.path.dirname(pname)
+ if len(args) > 1:
+ kwargs['paramFilename'] = args[1]
+
+ pfname = kwargs.get("paramFilename", os.path.join(dn, "inputs"))
+
+ # @todo: new Nyx output.
+ # We check for the job_info file's existence because this is currently
+ # what distinguishes Nyx data from MAESTRO data.
+ pfn = os.path.join(pfname)
+ if not os.path.exists(pfn): return False
+ nyx = any(("nyx." in line for line in open(pfn)))
+ maestro = os.path.exists(os.path.join(pname, "job_info"))
+ orion = (not nyx) and (not maestro)
+ return nyx
+
+ def __init__(self, plotname, param_filename="inputs",
+ fparam_filename="probin", data_style="nyx_native",
+ storage_filename=None):
+ """
+ Need to override for Nyx file structure, for now.
+
+ The paramfile is usually called "inputs" and there may be a fortran
+ inputs file usually called "probin". `plotname` here will be a directory
+ name as per BoxLib, data_style will be one of
+
+ * Native
+ * IEEE (not implemented in yt)
+ * ASCII (not implemented in yt)
+
+ """
+ self.storage_filename = storage_filename
+ self.parameter_filename = param_filename
+ self.parameter_file_path = os.path.abspath(self.parameter_filename)
+ self.fparameter_filename = fparam_filename
+ self.fparameter_file_path = os.path.abspath(self.fparameter_filename)
+ self.path = os.path.abspath(plotname) # data folder
+
+ self.fparameters = {}
+
+ # @todo: quick fix...
+ self.use_particles = False
+
+ # @todo: first line
+ # runs ``self._parse_parameter_file()``, ``self._set_units()``, and
+ # ``self.print_key_parameters()``
+ StaticOutput.__init__(self, plotname.rstrip("/"), data_style=data_style)
+
+ # @todo: field pruning should happen here
+ self.field_info = self._fieldinfo_class()
+
+ # @todo: check all of these and hopefully factor out of the constructor.
+ # These should maybe not be hardcoded?
+ self.parameters["HydroMethod"] = "nyx" # always PPM DE
+ self.parameters["Time"] = 1. # default unit is 1...
+ self.parameters["DualEnergyFormalism"] = 0 # always off.
+ self.parameters["EOSType"] = -1 # default
+
+ # @todo: hopefully delete this after implementing new Nyx output
+ if self.fparameters.has_key("mu"):
+ self.parameters["mu"] = self.fparameters["mu"]
+
+ def _parse_parameter_file(self):
+ """
+ Parses the parameter file and establishes the various dictionaries.
+
+ """
+ # More boxlib madness...
+ self._parse_header_file()
+
+ if os.path.isfile(self.fparameter_file_path):
+ self._parse_fparameter_file()
+
+ # Let's read the file
+ self.unique_identifier = int(os.stat(self.parameter_filename)[ST_CTIME])
+ lines = open(self.parameter_file_path).readlines()
+
+ for line in lines:
+ if line.find("#") >= 1: # Keep the commented lines...
+ line = line[:line.find("#")]
+ line = line.strip()
+ if len(line) < 2 or line.find("#") == 0: # ...but skip comments
+ continue
+
+ try:
+ param, val_string = map(strip, line.split("="))
+ except ValueError:
+ mylog.error("ValueError: '%s'", line)
+
+ vals = val_string.split()
+
+ # @todo: don't do this here...
+ if nyx_to_enzo_dict.has_key(param):
+ param_name = nyx_to_enzo_dict[param]
+ vals = map(parameter_type_dict[param_name], vals)
+ if len(vals) == 1:
+ self.parameters[param_name] = vals[0]
+ else:
+ # don't know why this is special
+ if param_name == "RefineBy":
+ self.parameters[param_name] = vals[0]
+ else:
+ self.parameters[param_name] = vals
+
+ elif param.startswith("geometry.prob_hi"):
+ self.domain_right_edge = na.array([float(i) for i in vals])
+ elif param.startswith("geometry.prob_lo"):
+ self.domain_left_edge = na.array([float(i) for i in vals])
+ elif param.startswith("particles.write_in_plotfile"):
+ self.use_particles = boxlib_bool_to_int(vals[0])
+
+ # aliases we need
+ self.parameters["TopGridRank"] = len(self.parameters["TopGridDimensions"])
+ self.dimensionality = self.parameters["TopGridRank"]
+ self.domain_dimensions = self.parameters["TopGridDimensions"]
+ self.refine_by = self.parameters.get("RefineBy", 2) # 2 is silent default? Makes sense I suppose.
+
+ if self.parameters.has_key("ComovingCoordinates") \
+ and self.parameters["ComovingCoordinates"]:
+ self.cosmological_simulation = 1
+ self.omega_lambda = self.parameters["CosmologyOmegaLambdaNow"]
+ self.omega_matter = self.parameters["CosmologyOmegaMatterNow"]
+ self.hubble_constant = self.parameters["CosmologyHubbleConstantNow"]
+
+ # So broken. We will fix this in the new Nyx output format
+ a_file = open(os.path.join(self.path, "comoving_a"))
+ line = a_file.readline().strip()
+ a_file.close()
+ self.parameters["CosmologyCurrentRedshift"] = 1 / float(line) - 1
+ self.cosmological_scale_factor = float(line)
+
+ # alias
+ self.current_redshift = self.parameters["CosmologyCurrentRedshift"]
+
+ else:
+ # @todo: automatic defaults
+ self.current_redshift = self.omega_lambda = self.omega_matter = \
+ self.hubble_constant = self.cosmological_simulation = 0.0
+
+ def _parse_header_file(self):
+ """
+ Parses the BoxLib header file to get any parameters stored there.
+ Hierarchy information is read out of this file in NyxHierarchy.
+
+ Currently, only Time is read here.
+
+ """
+ # @todo: header filename option? probably not.
+ header_file = open(os.path.join(self.path, "Header"))
+ lines = header_file.readlines() # hopefully this is small
+ header_file.close()
+
+ n_fields = int(lines[1]) # this could change
+ self.current_time = float(lines[3 + n_fields]) # very fragile
+
+ def _parse_fparameter_file(self):
+ """
+ Parses the fortran parameter file for Nyx. Most of this will be useless,
+ but this is where it keeps mu = mass per particle/m_hydrogen. Also it
+ contains the cosmological variables.
+
+ """
+ # @todo: delete after new Nyx output
+ lines = open(self.fparameter_file_path).readlines()
+ for line in lines:
+ if line.count("=") == 1:
+ nyx_param, val_string = map(strip, line.split("="))
+
+ # Check if we care about this param. If so, translate it.
+ if nyx_to_enzo_dict.has_key(nyx_param):
+ param = nyx_to_enzo_dict[nyx_param]
+ else:
+ continue
+
+ # parse vals string and correct for fortran double syntax
+ vals = val_string.split()
+ if val_string.count("'") == 0: # must be floats
+ vals = map(float, [val.replace('D', 'e').replace('d', 'e')
+ for val in vals])
+
+ # single element or array?
+ if len(vals) == 1:
+ self.parameters[param] = vals[0]
+ else:
+ self.parameters[param] = vals
+
+ def _set_units(self):
+ """
+ Generates the conversion to various physical _units based on the
+ parameter file.
+
+ """
+ self.units = {}
+ self.time_units = {}
+
+ if len(self.parameters) == 0: # don't think this is possible, but safe
+ self._parse_parameter_file()
+
+ # Masses are always in $ M_{\odot} $
+ self.units["particle_mass"] = 1.989e33
+
+ mylog.warning("Length units: setting 1.0 = 1.0 Mpc.")
+ self.units.update(mpc_conversion)
+ self.units["density"] = self.units["particle_mass"]/(self.units["cm"])**3
+ self.units["particle_mass_density"] = self.units["density"]
+ self.units["Density"] = 1
+
+ # @todo: enzo-isms
+ mylog.warning("Time units: setting 1.0 = Mpc/km s ~ 10^12 yr .")
+ self.time_units["s"] = 1.0 / 3.08568025e19
+ self.conversion_factors["Time"] = 1.0 / 3.08568025e19
+
+ # velocities are not comoving!
+ # Nyx is in km/s so we need to convert to cm/s, hence 1e5
+ cf = 1e5 * (self.cosmological_scale_factor)
+ for ax in "xyz":
+ self.units["particle_velocity_%s" % ax] = cf
+
+ # misc
+ self.conversion_factors = defaultdict(lambda: 1.0) # what is this for? - Steffen: this is to get 1.0 for values not in the dict
+ self.time_units["1"] = 1
+ self.units["1"] = 1.0
+ self.units["unitary"] = 1.0 / (self.domain_right_edge -
+ self.domain_left_edge).max()
+
+ # time
+ seconds = self.time_units["s"]
+ self.time_units["days"] = seconds / (3600 * 24.0)
+ self.time_units["years"] = seconds / (3600 * 24.0 * 365)
+
+
+ # not the most useful right now, but someday
+ for key in nyx_particle_field_names:
+ self.conversion_factors[key] = 1.0
+
+ def _setup_nounits_units(self):
+ z = 0
+
+ def _localize(self, f, default):
+ if f is None:
+ return os.path.join(self.directory, default)
+ return f
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/yt/frontends/nyx/definitions.py Fri Jul 29 15:52:48 2011 -0400
@@ -0,0 +1,91 @@
+"""
+Definitions specific to Nyx
+
+Author: Casey W. Stark <caseywstark at gmail.com>
+Affiliation: UC Berkeley
+Author: J. S. Oishi <jsoishi at gmail.com>
+Affiliation: KIPAC/SLAC/Stanford
+Homepage: http://yt.enzotools.org/
+License:
+ Copyright (C) 2011 Casey W. Stark, J. S. Oishi, Matthew Turk. All Rights
+ Reserved.
+
+ This file is part of yt.
+
+ yt is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from utils import boxlib_bool_to_int
+
+# This gives the type of each parameter we want, used to cast with a ``map()``
+# @todo: get rid of enzo parameters we do not need
+parameter_type_dict = {
+ "CosmologyCurrentRedshift": float,
+ "CosmologyComovingBoxSize": float,
+ "CosmologyOmegaMatterNow": float,
+ "CosmologyOmegaLambdaNow": float,
+ "CosmologyHubbleConstantNow": float,
+ "CosmologyInitialRedshift": float,
+ "DualEnergyFormalismEta1": float,
+ "DualEnergyFormalismEta2": float,
+ "MetaDataString": str,
+ "HydroMethod": int,
+ "DualEnergyFormalism": int,
+ "InitialTime": float,
+ "ComovingCoordinates": boxlib_bool_to_int,
+ "DensityUnits": float,
+ "LengthUnits": float,
+ "LengthUnit": float,
+ "TemperatureUnits": float,
+ "TimeUnits": float,
+ "GravitationalConstant": float,
+ "Gamma": float,
+ "MultiSpecies": int,
+ "CompilerPrecision": str,
+ "CurrentTimeIdentifier": int,
+ "RefineBy": int,
+ "BoundaryConditionName": str,
+ "TopGridRank": int,
+ "TopGridDimensions": int,
+ "EOSSoundSpeed": float,
+ "EOSType": int,
+ "NumberOfParticleAttributes": int,
+}
+
+# Provides translation between parameters in the nyx `inputs` file names to the
+# enzo/yt name expected throughout the code. The key is nyx name, value is
+# enzo/yt equivalent.
+nyx_to_enzo_dict = {
+ "amr.n_cell": "TopGridDimensions",
+ "amr.ref_ratio": "RefineBy",
+ "materials.gamma": "Gamma",
+ "castro.use_comoving": "ComovingCoordinates",
+ "castro.redshift_in": "CosmologyInitialRedshift",
+ "comoving_OmL": "CosmologyOmegaLambdaNow",
+ "comoving_OmM": "CosmologyOmegaMatterNow",
+ "comoving_h": "CosmologyHubbleConstantNow"
+}
+
+# is this the same as nyx_to_enzo.
+yt_to_nyx_fields_dict = {}
+nyx_to_yt_fields_dict = {}
+
+fab_header_pattern = r"^FAB \(\((\d+), \([0-9 ]+\)\),\(\d+, \(([0-9 ]+)\)\)\)\(\((\d+,\d+,\d+)\) \((\d+,\d+,\d+)\) \((\d+,\d+,\d+)\)\) (\d+)\n"
+
+# need to specify units eventually
+nyx_particle_field_names = ['particle_position_%s' % ax for ax in 'xyz'] + \
+ ['particle_mass'] + \
+ ['particle_velocity_%s' % ax for ax in 'xyz']
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/yt/frontends/nyx/fields.py Fri Jul 29 15:52:48 2011 -0400
@@ -0,0 +1,153 @@
+"""
+Field specifications for Nyx
+
+Author: Casey W. Stark <caseywstark at gmail.com>
+Affiliation: UC Berkeley
+Author: J. S. Oishi <jsoishi at gmail.com>
+Affiliation: KIPAC/SLAC/Stanford
+Homepage: http://yt.enzotools.org/
+License:
+ Copyright (C) 2011 Casey W. Stark, J. S. Oishi, Matthew Turk. All Rights
+ Reserved.
+
+ This file is part of yt.
+
+ yt is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+import yt.data_objects.universal_fields
+
+from yt.data_objects.field_info_container import CodeFieldInfoContainer, \
+ ValidateParameter, ValidateDataField, ValidateProperty, ValidateSpatial, \
+ ValidateGridType
+from yt.utilities.physical_constants import mh, kboltz
+
+class NyxFieldContainer(CodeFieldInfoContainer):
+ """ All nyx-specific fields are stored in here. """
+ _shared_state = {}
+ _field_list = {}
+
+nyx_fields = NyxFieldContainer()
+add_field = nyx_fields.add_field
+add_nyx_field = add_field # alias for API
+
+# Density
+add_field("density", function=lambda a, b: None, take_log=True,
+ validators=[ValidateDataField("density")],
+ units=r"\rm{g}} / \rm{cm}^3",
+ projected_units =r"\rm{g}} / \rm{cm}^2")
+nyx_fields["density"]._projected_units =r"\rm{g}} / \rm{cm}^2"
+
+add_field("Density", function=lambda a, b: b["density"], take_log=True,
+ units=r"\rm{g}} / \rm{cm}^3",
+ projected_units =r"\rm{g}} / \rm{cm}^2")
+
+# Particle mass in units of $ M_{\odot}
+def _convertParticleMassMsun(data):
+ return (1/1.989e33)
+def _particle_mass_m_sun(field, data):
+ return data["particle_mass"]
+add_field("ParticleMassMsun", function=_particle_mass_m_sun,
+ validators=[ValidateSpatial(0), ValidateDataField("particle_mass")],
+ particle_type=True, convert_function=_convertParticleMassMsun, take_log=True, units=r"\rm{M_{\odot}}")
+
+add_field("Dark_Matter_Density", function=lambda a, b: b["particle_mass_density"], take_log=True,
+ units=r"\rm{g}} / \rm{cm}^3",particle_type=True,
+ projected_units =r"\rm{g}} / \rm{cm}^2")
+
+
+# Energy Density
+# @todo: ``energy_density``
+add_field("total_energy", function=lambda a, b: None, take_log=True,
+ validators=[ValidateDataField("total_energy")],
+ units=r"\rm{M_{\odot}} (\rm{km} / \rm{s})^2")
+
+# Momentum in each dimension.
+# @todo: ``momentum_x``
+add_field("x-momentum", function=lambda a, b: None, take_log=False,
+ validators=[ValidateDataField("x-momentum")],
+ units=r"\rm{M_{\odot}} \rm{km} / \rm{s}")
+add_field("y-momentum", function=lambda a, b: None, take_log=False,
+ validators=[ValidateDataField("y-momentum")],
+ units=r"\rm{M_{\odot}} \rm{km} / \rm{s}")
+add_field("z-momentum", function=lambda a, b: None, take_log=False,
+ validators=[ValidateDataField("z-momentum")],
+ units=r"\rm{M_{\odot}} \rm{km} / \rm{s}")
+
+### Now derived fields
+
+# Velocity fields in each dimension
+# @todo: ``velocity_x``
+def _x_velocity(field, data):
+ """ Generate x-velocity from x-momentum and density. """
+ return data["x-momentum"] / data["density"]
+add_field("x-velocity", function=_x_velocity, take_log=False,
+ units=r"\rm{km} / \rm{s}")
+
+def _y_velocity(field, data):
+ """ Generate y-velocity from y-momentum and density. """
+ return data["y-momentum"] / data["density"]
+add_field("y-velocity", function=_y_velocity, take_log=False,
+ units=r"\rm{km} / \rm{s}")
+
+def _z_velocity(field, data):
+ """ Generate z-velocity from z-momentum and density. """
+ return data["z-momentum"] / data["density"]
+add_field("z-velocity", function=_z_velocity, take_log=False,
+ units=r"\rm{km} / \rm{s}")
+
+# The gas **thermal** energy.
+# @todo: should be called ``gas_energy`` whether it is data or derived
+def _thermal_energy(field, data):
+ """
+ Generate thermal (gas energy). Dual Energy Formalism was implemented by
+ Stella, but this isn't how it's called, so I'll leave that commented out for
+ now.
+
+ """
+ #if data.pf["DualEnergyFormalism"]:
+ # return data["Gas_Energy"]
+ #else:
+ return data["Total_Energy"] - 0.5 * data["density"] * (
+ data["x-velocity"]**2.0
+ + data["y-velocity"]**2.0
+ + data["z-velocity"]**2.0 )
+add_field("ThermalEnergy", function=_thermal_energy,
+ units=r"\rm{M_{\odot}} (\rm{km} / \rm{s})^2")
+
+# Gas pressure
+# @todo: eventually figure out a way to detect when using radiation and change
+# this.
+def _pressure(field, data):
+ """
+ Computed using
+
+ $$ pressure = (\gamma - 1.0) * e$$
+
+ where e is thermal energy density. Note that this will need to be modified
+ when radiation is accounted for.
+
+ """
+ return (data.pf["Gamma"] - 1.0) * data["ThermalEnergy"]
+add_field("Pressure", function=_pressure,
+ units=r"\rm{M_{\odot}} (\rm{km} / \rm{s})^2 / \rm{Mpc}^3")
+
+# Gas temperature
+def _temperature(field, data):
+ return ((data.pf["Gamma"] - 1.0) * data.pf["mu"] * mh *
+ data["ThermalEnergy"] / (kboltz * data["Density"]))
+add_field("Temperature", function=_temperature, take_log=False,
+ units=r"\rm{Kelvin}")
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/yt/frontends/nyx/io.py Fri Jul 29 15:52:48 2011 -0400
@@ -0,0 +1,141 @@
+"""
+Nyx data-file handling functions (basically a boxlib reader)
+
+Author: Casey W. Stark <caseywstark at gmail.com>
+Affiliation: UC Berkeley
+Author: Matthew Turk <matthewturk at gmail.com>
+Author: J. S. Oishi <jsoishi at gmail.com>
+Affiliation: KIPAC/SLAC/Stanford
+Homepage: http://yt.enzotools.org/
+License:
+ Copyright (C) 2011 Casey W. Stark, Matthew Turk. All Rights Reserved.
+
+ This file is part of yt.
+
+ yt is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+"""
+
+import os
+import numpy as na
+from yt.utilities.amr_utils import read_castro_particles
+from yt.utilities.io_handler import BaseIOHandler
+
+from definitions import fab_header_pattern, nyx_particle_field_names, \
+ yt_to_nyx_fields_dict
+
+class IOHandlerNative(BaseIOHandler):
+ """ File handler that can somehow read the native boxlib format. """
+
+ _data_style = "nyx_native"
+
+ def modify(self, field):
+ return field.swapaxes(0, 2)
+
+ def _read_particle_field(self, grid, field):
+ offset = grid._particle_offset
+ filen = os.path.expanduser(grid.particle_filename)
+ off = grid._particle_offset
+ tr = na.zeros(grid.NumberOfParticles, dtype='float64')
+ read_castro_particles(filen, off,
+ nyx_particle_field_names.index(field),
+ len(nyx_particle_field_names), tr)
+ return tr
+
+ def _read_data_set(self, grid, field):
+ """ reads packed multiFABs output by BoxLib in "NATIVE" format. """
+ if field in nyx_particle_field_names:
+ return self._read_particle_field(grid, field)
+ filen = os.path.expanduser(grid.filename[field])
+ off = grid._offset[field]
+ inFile = open(filen, 'rb')
+ inFile.seek(off)
+ header = inFile.readline()
+ header.strip()
+
+ """
+ if grid._paranoid:
+ mylog.warn("Castro Native reader: Paranoid read mode.")
+ header_re = re.compile(fab_header_pattern)
+ bytesPerReal, endian, start, stop, centerType, nComponents = \
+ headerRe.search(header).groups()
+
+ # we will build up a dtype string, starting with endian.
+ # @todo: this code is ugly.
+ bytesPerReal = int(bytesPerReal)
+ if bytesPerReal == int(endian[0]):
+ dtype = '<'
+ elif bytesPerReal == int(endian[-1]):
+ dtype = '>'
+ else:
+ raise ValueError("FAB header is neither big nor little endian. Perhaps the file is corrupt?")
+
+ dtype += ('f%i' % bytesPerReal) # always a floating point
+
+ # determine size of FAB
+ start = na.array(map(int, start.split(',')))
+ stop = na.array(map(int, stop.split(',')))
+
+ gridSize = stop - start + 1
+
+ error_count = 0
+ if (start != grid.start).any():
+ print "Paranoia Error: Cell_H and %s do not agree on grid start." % grid.filename
+ error_count += 1
+ if (stop != grid.stop).any():
+ print "Paranoia Error: Cell_H and %s do not agree on grid stop." % grid.filename
+ error_count += 1
+ if (gridSize != grid.ActiveDimensions).any():
+ print "Paranoia Error: Cell_H and %s do not agree on grid dimensions." % grid.filename
+ error_count += 1
+ if bytesPerReal != grid.hierarchy._bytesPerReal:
+ print "Paranoia Error: Cell_H and %s do not agree on bytes per real number." % grid.filename
+ error_count += 1
+ if (bytesPerReal == grid.hierarchy._bytesPerReal and dtype != grid.hierarchy._dtype):
+ print "Paranoia Error: Cell_H and %s do not agree on endianness." % grid.filename
+ error_count += 1
+
+ if error_count > 0:
+ raise RunTimeError("Paranoia unveiled %i differences between Cell_H and %s." % (error_count, grid.filename))
+ else:
+ """
+ start = grid.start_index
+ stop = grid.stop_index
+ dtype = grid.hierarchy._dtype
+ bytesPerReal = grid.hierarchy._bytesPerReal
+
+ nElements = grid.ActiveDimensions.prod()
+
+ # one field has nElements * bytesPerReal bytes and is located
+ # nElements * bytesPerReal * field_index from the offset location
+ if yt_to_nyx_fields_dict.has_key(field):
+ fieldname = yt_to_nyx_fields_dict[field]
+ else:
+ fieldname = field
+ field_index = grid.field_indexes[fieldname]
+ inFile.seek(int(nElements*bytesPerReal*field_index),1)
+ field = na.fromfile(inFile, count=nElements, dtype=dtype)
+ field = field.reshape(grid.ActiveDimensions[::-1]).swapaxes(0,2)
+
+ # @todo: we can/should also check against the max and min in the header
+ # file
+
+ inFile.close()
+ return field
+
+ def _read_data_slice(self, grid, field, axis, coord):
+ # wishful thinking?
+ sl = [slice(None), slice(None), slice(None)]
+ sl[axis] = slice(coord, coord + 1)
+ #sl = tuple(reversed(sl))
+ return self._read_data_set(grid, field)[sl]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/yt/frontends/nyx/setup.py Fri Jul 29 15:52:48 2011 -0400
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+import setuptools
+import os, sys, os.path
+
+import os.path
+
+def configuration(parent_package='', top_path=None):
+ from numpy.distutils.misc_util import Configuration
+ config = Configuration('nyx', parent_package, top_path)
+ config.make_config_py() # installs __config__.py
+ config.make_svn_version_py()
+ return config
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/yt/frontends/nyx/utils.py Fri Jul 29 15:52:48 2011 -0400
@@ -0,0 +1,36 @@
+"""
+Utilities for dealing with Nyx data
+
+Author: Casey W. Stark <caseywstark at gmail.com>
+Affiliation: UC Berkeley
+Homepage: http://yt.enzotools.org/
+License:
+ Copyright (C) 2011 Casey W. Stark, Matthew Turk. All Rights Reserved.
+
+ This file is part of yt.
+
+ yt is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+def boxlib_bool_to_int(v):
+ try:
+ return int(v)
+ except ValueError:
+ pass
+ v = v.upper().strip()
+ if v[0] == 'T':
+ return 1
+ elif v[0] == 'F':
+ return 0
\ No newline at end of file
--- a/yt/frontends/orion/data_structures.py Fri Jul 29 15:52:35 2011 -0400
+++ b/yt/frontends/orion/data_structures.py Fri Jul 29 15:52:48 2011 -0400
@@ -494,8 +494,9 @@
pfn = os.path.join(pfname)
if not os.path.exists(pfn): return False
castro = any(("castro." in line for line in open(pfn)))
+ nyx = any(("nyx." in line for line in open(pfn)))
maestro = os.path.exists(os.path.join(pname, "job_info"))
- orion = (not castro) and (not maestro)
+ orion = (not castro) and (not maestro) and (not nyx)
return orion
def _parse_parameter_file(self):
--- a/yt/frontends/setup.py Fri Jul 29 15:52:35 2011 -0400
+++ b/yt/frontends/setup.py Fri Jul 29 15:52:48 2011 -0400
@@ -9,6 +9,7 @@
config.add_subpackage("chombo")
config.add_subpackage("enzo")
config.add_subpackage("flash")
+ config.add_subpackage("nyx")
config.add_subpackage("orion")
config.add_subpackage("ramses")
config.add_subpackage("tiger")
--- a/yt/gui/reason/html/js/reason.js Fri Jul 29 15:52:35 2011 -0400
+++ b/yt/gui/reason/html/js/reason.js Fri Jul 29 15:52:48 2011 -0400
@@ -55,7 +55,9 @@
}
var repl_input = new Ext.FormPanel({
+ title: 'YT Input',
url: 'push',
+ flex: 0.2,
layout: 'fit',
padding: 5,
height: '100%',
@@ -133,7 +135,7 @@
title: 'YT Output',
id: 'output_container',
autoScroll: true,
- flex: 0.7,
+ flex: 0.8,
items: []
});
--- a/yt/mods.py Fri Jul 29 15:52:35 2011 -0400
+++ b/yt/mods.py Fri Jul 29 15:52:48 2011 -0400
@@ -14,12 +14,12 @@
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
@@ -60,6 +60,9 @@
from yt.frontends.castro.api import \
CastroStaticOutput, CastroFieldInfo, add_castro_field
+from yt.frontends.nyx.api import \
+ NyxStaticOutput, nyx_fields, add_nyx_field
+
from yt.frontends.orion.api import \
OrionStaticOutput, OrionFieldInfo, add_orion_field
--- a/yt/utilities/parameter_file_storage.py Fri Jul 29 15:52:35 2011 -0400
+++ b/yt/utilities/parameter_file_storage.py Fri Jul 29 15:52:48 2011 -0400
@@ -33,7 +33,7 @@
parallel_simple_proxy
output_type_registry = {}
-_field_names = ('hash','bn','fp','tt','ctid','class_name','last_seen')
+_field_names = ('hash', 'bn', 'fp', 'tt', 'ctid', 'class_name', 'last_seen')
class NoParameterShelf(Exception):
pass
@@ -49,6 +49,14 @@
return "%s" % self.name
class ParameterFileStore(object):
+ """
+ This class is designed to be a semi-persistent storage for parameter
+ files. By identifying each parameter file with a unique hash, objects
+ can be stored independently of parameter files -- when an object is
+ loaded, the parameter file is as well, based on the hash. For
+ storage concerns, only a few hundred will be retained in cache.
+
+ """
_shared_state = {}
_distributed = True
@@ -60,13 +68,11 @@
self.__dict__ = cls._shared_state
return self
- def __init__(self, in_memory = False):
+ def __init__(self, in_memory=False):
"""
- This class is designed to be a semi-persistent storage for parameter
- files. By identifying each parameter file with a unique hash, objects
- can be stored independently of parameter files -- when an object is
- loaded, the parameter file is as well, based on the hash. For
- storage concerns, only a few hundred will be retained in cache.
+ Create the parameter file database if yt is configured to store them.
+ Otherwise, use read-only settings.
+
"""
if ytcfg.getboolean("yt", "StoreParameterFiles"):
self._read_only = False
@@ -92,29 +98,23 @@
# these will be broadcast
def _get_db_name(self):
- base_file_name = ytcfg.get("yt","ParameterFileStore")
+ base_file_name = ytcfg.get("yt", "ParameterFileStore")
if not os.access(os.path.expanduser("~/"), os.W_OK):
return os.path.abspath(base_file_name)
return os.path.expanduser("~/.yt/%s" % base_file_name)
def get_pf_hash(self, hash):
- """
- This returns a parameter file based on a hash.
- """
+ """ This returns a parameter file based on a hash. """
return self._convert_pf(self._records[hash])
def get_pf_ctid(self, ctid):
- """
- This returns a parameter file based on a CurrentTimeIdentifier.
- """
+ """ This returns a parameter file based on a CurrentTimeIdentifier. """
for h in self._records:
if self._records[h]['ctid'] == ctid:
return self._convert_pf(self._records[h])
def _adapt_pf(self, pf):
- """
- This turns a parameter file into a CSV entry
- """
+ """ This turns a parameter file into a CSV entry. """
return dict(bn=pf.basename,
fp=pf.fullpath,
tt=pf.current_time,
@@ -123,9 +123,7 @@
last_seen=pf._instantiated)
def _convert_pf(self, pf_dict):
- """
- This turns a CSV entry into a parameter file
- """
+ """ This turns a CSV entry into a parameter file. """
bn = pf_dict['bn']
fp = pf_dict['fp']
fn = os.path.join(fp, bn)
@@ -145,7 +143,7 @@
def check_pf(self, pf):
"""
This will ensure that the parameter file (*pf*) handed to it is
- recorded in the storage unit. In doing so, it will update path
+ recorded in the storage unit. In doing so, it will update path
and "last_seen" information.
"""
hash = pf._hash()
@@ -160,9 +158,7 @@
self.insert_pf(pf)
def insert_pf(self, pf):
- """
- This will insert a new *pf* and flush the database to disk.
- """
+ """ This will insert a new *pf* and flush the database to disk. """
self._records[pf._hash()] = self._adapt_pf(pf)
self.flush_db()
@@ -176,16 +172,13 @@
self.flush_db()
def flush_db(self):
- """
- This flushes the storage to disk.
- """
+ """ This flushes the storage to disk. """
if self._read_only: return
self._write_out()
self.read_db()
def get_recent(self, n=10):
- recs = sorted(self._records.values(),
- key = lambda a: -a['last_seen'])[:n]
+ recs = sorted(self._records.values(), key=lambda a: -a['last_seen'])[:n]
return recs
@parallel_simple_proxy
@@ -204,10 +197,8 @@
@parallel_simple_proxy
def read_db(self):
- """
- This will read the storage device from disk.
- """
- f=open(self._get_db_name(), 'rb')
+ """ This will read the storage device from disk. """
+ f = open(self._get_db_name(), 'rb')
vals = csv.DictReader(f, _field_names)
db = {}
for v in vals:
--- a/yt/visualization/plot_modifications.py Fri Jul 29 15:52:35 2011 -0400
+++ b/yt/visualization/plot_modifications.py Fri Jul 29 15:52:48 2011 -0400
@@ -60,13 +60,17 @@
class VelocityCallback(PlotCallback):
_type_name = "velocity"
- def __init__(self, factor=16):
+ def __init__(self, factor=16, scale=None, scale_units=None):
"""
Adds a 'quiver' plot of velocity to the plot, skipping all but
every *factor* datapoint
+ *scale* is the data units per arrow length unit using *scale_units*
+ (see matplotlib.axes.Axes.quiver for more info)
"""
PlotCallback.__init__(self)
self.factor = factor
+ self.scale = scale
+ self.scale_units = scale_units
def __call__(self, plot):
# Instantiation of these is cheap
@@ -77,7 +81,7 @@
else:
xv = "%s-velocity" % (x_names[plot.data.axis])
yv = "%s-velocity" % (y_names[plot.data.axis])
- qcb = QuiverCallback(xv, yv, self.factor)
+ qcb = QuiverCallback(xv, yv, self.factor, self.scale, self.scale_units)
return qcb(plot)
class MagFieldCallback(PlotCallback):
@@ -102,16 +106,20 @@
class QuiverCallback(PlotCallback):
_type_name = "quiver"
- def __init__(self, field_x, field_y, factor):
+ def __init__(self, field_x, field_y, factor, scale, scale_units):
"""
Adds a 'quiver' plot to any plot, using the *field_x* and *field_y*
- from the associated data, skipping every *factor* datapoints.
+ from the associated data, skipping every *factor* datapoints
+ *scale* is the data units per arrow length unit using *scale_units*
+ (see matplotlib.axes.Axes.quiver for more info)
"""
PlotCallback.__init__(self)
self.field_x = field_x
self.field_y = field_y
self.bv_x = self.bv_y = 0
self.factor = factor
+ self.scale = scale
+ self.scale_units = scale_units
def __call__(self, plot):
x0, x1 = plot.xlim
@@ -137,7 +145,7 @@
(x0, x1, y0, y1),).transpose()
X = na.mgrid[0:plot.image._A.shape[0]-1:nx*1j]# + 0.5*factor
Y = na.mgrid[0:plot.image._A.shape[1]-1:ny*1j]# + 0.5*factor
- plot._axes.quiver(X,Y, pixX, pixY)
+ plot._axes.quiver(X,Y, pixX, pixY, scale=self.scale, scale_units=self.scale_units)
plot._axes.set_xlim(xx0,xx1)
plot._axes.set_ylim(yy0,yy1)
plot._axes.hold(False)
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