[yt-svn] commit/yt: ngoldbaum: Merged in hyschive/yt-hyschive (pull request #2150)

commits-noreply at bitbucket.org commits-noreply at bitbucket.org
Wed May 11 11:32:16 PDT 2016


1 new commit in yt:

https://bitbucket.org/yt_analysis/yt/commits/01c911476af3/
Changeset:   01c911476af3
Branch:      yt
User:        ngoldbaum
Date:        2016-05-11 18:32:02+00:00
Summary:     Merged in hyschive/yt-hyschive (pull request #2150)

GAMER frontend
Affected #:  14 files

diff -r b61ebaeaae2e05c7e2aa6757ff23465c5cf2681d -r 01c911476af375f444f6d83cac45f5a61c9d82e4 doc/source/developing/testing.rst
--- a/doc/source/developing/testing.rst
+++ b/doc/source/developing/testing.rst
@@ -245,6 +245,12 @@
 * ``IsothermalCollapse/snap_505.hdf5``
 * ``GadgetDiskGalaxy/snapshot_200.hdf5``
 
+GAMER
+~~~~~~
+
+* ``InteractingJets/jet_000002``
+* ``WaveDarkMatter/psiDM_000020``
+
 Halo Catalog
 ~~~~~~~~~~~~
 

diff -r b61ebaeaae2e05c7e2aa6757ff23465c5cf2681d -r 01c911476af375f444f6d83cac45f5a61c9d82e4 doc/source/examining/loading_data.rst
--- a/doc/source/examining/loading_data.rst
+++ b/doc/source/examining/loading_data.rst
@@ -1021,6 +1021,34 @@
 
 yt will utilize length, mass and time to set up all other units.
 
+GAMER Data
+----------
+
+GAMER HDF5 data is supported and cared for by Hsi-Yu Schive. You can load the data like this:
+
+.. code-block:: python
+
+   import yt
+   ds = yt.load("InteractingJets/jet_000002")
+
+Currently GAMER does not assume any unit for non-cosmological simulations. To specify the units for yt,
+you need to supply conversions for length, time, and mass to ``load`` using the ``units_override`` functionality:
+
+.. code-block:: python
+
+   import yt
+   code_units = { "length_unit":(1.0,"kpc"),
+                  "time_unit"  :(3.08567758096e+13,"s"),
+                  "mass_unit"  :(1.4690033e+36,"g") }
+   ds = yt.load("InteractingJets/jet_000002", units_override=code_units)
+
+This means that the yt fields, e.g., ``("gas","density")``, will be in cgs units, but the GAMER fields,
+e.g., ``("gamer","Dens")``, will be in code units.
+
+.. rubric:: Caveats
+
+* GAMER data in raw binary format (i.e., OPT__OUTPUT_TOTAL = C-binary) is not supported.
+
 .. _loading-amr-data:
 
 Generic AMR Data

diff -r b61ebaeaae2e05c7e2aa6757ff23465c5cf2681d -r 01c911476af375f444f6d83cac45f5a61c9d82e4 doc/source/reference/code_support.rst
--- a/doc/source/reference/code_support.rst
+++ b/doc/source/reference/code_support.rst
@@ -34,6 +34,8 @@
 +-----------------------+------------+-----------+------------+-------+----------+----------+------------+----------+
 | Gadget                |     Y      |     Y     |      Y     |   Y   | Y [#f2]_ |    Y     |     Y      |   Full   |
 +-----------------------+------------+-----------+------------+-------+----------+----------+------------+----------+
+| GAMER                 |     Y      |     N     |      Y     |   Y   |    Y     |    Y     |     Y      |   Full   |
++-----------------------+------------+-----------+------------+-------+----------+----------+------------+----------+
 | Gasoline              |     Y      |     Y     |      Y     |   Y   | Y [#f2]_ |    Y     |     Y      |   Full   |
 +-----------------------+------------+-----------+------------+-------+----------+----------+------------+----------+
 | Grid Data Format (GDF)|     Y      |    N/A    |      Y     |   Y   |    Y     |    Y     |     Y      |   Full   |

diff -r b61ebaeaae2e05c7e2aa6757ff23465c5cf2681d -r 01c911476af375f444f6d83cac45f5a61c9d82e4 tests/tests.yaml
--- a/tests/tests.yaml
+++ b/tests/tests.yaml
@@ -20,6 +20,9 @@
   local_gadget_000:
     - yt/frontends/gadget/tests/test_outputs.py
 
+  local_gamer_000:
+    - yt/frontends/gamer/tests/test_outputs.py
+
   local_gdf_000:
     - yt/frontends/gdf/tests/test_outputs.py
 

diff -r b61ebaeaae2e05c7e2aa6757ff23465c5cf2681d -r 01c911476af375f444f6d83cac45f5a61c9d82e4 yt/frontends/api.py
--- a/yt/frontends/api.py
+++ b/yt/frontends/api.py
@@ -29,6 +29,7 @@
     'flash',
     'gadget',
     'gadget_fof',
+    'gamer',
     'gdf',
     'halo_catalog',
     'http_stream',

diff -r b61ebaeaae2e05c7e2aa6757ff23465c5cf2681d -r 01c911476af375f444f6d83cac45f5a61c9d82e4 yt/frontends/gamer/__init__.py
--- /dev/null
+++ b/yt/frontends/gamer/__init__.py
@@ -0,0 +1,14 @@
+"""
+API for yt.frontends.gamer
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2016, 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 b61ebaeaae2e05c7e2aa6757ff23465c5cf2681d -r 01c911476af375f444f6d83cac45f5a61c9d82e4 yt/frontends/gamer/api.py
--- /dev/null
+++ b/yt/frontends/gamer/api.py
@@ -0,0 +1,28 @@
+"""
+API for yt.frontends.gamer
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2016, 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 \
+      GAMERGrid, \
+      GAMERHierarchy, \
+      GAMERDataset
+
+from .fields import \
+      GAMERFieldInfo
+
+from .io import \
+      IOHandlerGAMER
+
+### NOT SUPPORTED YET
+#from . import tests

diff -r b61ebaeaae2e05c7e2aa6757ff23465c5cf2681d -r 01c911476af375f444f6d83cac45f5a61c9d82e4 yt/frontends/gamer/data_structures.py
--- /dev/null
+++ b/yt/frontends/gamer/data_structures.py
@@ -0,0 +1,277 @@
+"""
+GAMER-specific data structures
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2016, 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 os
+import stat
+import numpy as np
+import weakref
+
+from yt.funcs import mylog
+from yt.data_objects.grid_patch import \
+    AMRGridPatch
+from yt.geometry.grid_geometry_handler import \
+    GridIndex
+from yt.data_objects.static_output import \
+    Dataset
+from yt.utilities.file_handler import \
+    HDF5FileHandler
+from .fields import GAMERFieldInfo
+from yt.testing import assert_equal
+
+
+
+class GAMERGrid(AMRGridPatch):
+    _id_offset = 0
+
+    def __init__(self, id, index, level):
+        AMRGridPatch.__init__(self, id,
+                              filename = index.index_filename,
+                              index    = index)
+        self.Parent   = None    # do NOT initialize Parent as []
+        self.Children = []
+        self.Level    = level
+
+    def __repr__(self):
+        return 'GAMERGrid_%09i (dimension = %s)' % (self.id, self.ActiveDimensions)
+
+
+class GAMERHierarchy(GridIndex):
+    grid                 = GAMERGrid
+    _preload_implemented = True # since gamer defines "_read_chunk_data" in io.py
+    
+    def __init__(self, ds, dataset_type = 'gamer'):
+        self.dataset_type     = dataset_type
+        self.dataset          = weakref.proxy(ds)
+        self.index_filename   = self.dataset.parameter_filename
+        self.directory        = os.path.dirname(self.index_filename)
+        self._handle          = ds._handle
+        self.float_type       = 'float64' # fixed even when FLOAT8 is off
+        self._particle_handle = ds._particle_handle
+        GridIndex.__init__(self, ds, dataset_type)
+
+    def _detect_output_fields(self):
+        # find all field names in the current dataset
+        self.field_list = [ ('gamer', v) for v in self._handle['Data'].keys() ]
+    
+    def _count_grids(self):
+        # count the total number of patches at all levels  
+        self.num_grids = self.dataset.parameters['NPatch'].sum()
+        
+    def _parse_index(self):
+        parameters       = self.dataset.parameters
+        gid0             = 0
+        grid_corner      = self._handle['Tree/Corner'].value
+        convert2physical = self._handle['Tree/Corner'].attrs['Cvt2Phy']
+
+        self.grid_dimensions    [:] = parameters['PatchSize']
+        self.grid_particle_count[:] = 0
+
+        for lv in range(0, parameters['NLevel']):
+            num_grids_level = parameters['NPatch'][lv]
+            if num_grids_level == 0: break
+
+            patch_scale = parameters['PatchSize']*parameters['CellScale'][lv]
+
+            # set the level and edge of each grid
+            # (left/right_edge are YT arrays in code units)
+            self.grid_levels.flat[ gid0:gid0 + num_grids_level ] = lv
+            self.grid_left_edge[ gid0:gid0 + num_grids_level ] \
+                = grid_corner[ gid0:gid0 + num_grids_level ]*convert2physical
+            self.grid_right_edge[ gid0:gid0 + num_grids_level ] \
+                = (grid_corner[ gid0:gid0 + num_grids_level ] + patch_scale)*convert2physical
+
+            gid0 += num_grids_level
+
+        # allocate all grid objects
+        self.grids = np.empty(self.num_grids, dtype='object')
+        for i in range(self.num_grids):
+            self.grids[i] = self.grid(i, self, self.grid_levels.flat[i])
+
+        # maximum level with patches (which can be lower than MAX_LEVEL)
+        self.max_level = self.grid_levels.max()
+        
+    def _populate_grid_objects(self):
+        son_list = self._handle["Tree/Son"].value
+
+        for gid in range(self.num_grids):
+            grid     = self.grids.flat[gid]
+            son_gid0 = son_list[gid]
+
+            # set up the parent-children relationship
+            if son_gid0 >= 0:
+                grid.Children = [ self.grids.flat[son_gid0+s] for s in range(8) ]
+
+            for son_grid in grid.Children: son_grid.Parent = grid
+
+            # set up other grid attributes
+            grid._prepare_grid()
+            grid._setup_dx()
+
+        # validate the parent-children relationship in the debug mode
+        if self.dataset._debug:
+            self._validate_parent_children_relasionship()
+
+    # for _debug mode only
+    def _validate_parent_children_relasionship(self):
+        mylog.info('Validating the parent-children relationship ...')
+
+        father_list = self._handle["Tree/Father"].value
+
+        for grid in self.grids:
+            # parent->children == itself
+            if grid.Parent is not None:
+                assert grid.Parent.Children[0+grid.id%8] is grid, \
+                       'Grid %d, Parent %d, Parent->Children %d' % \
+                       (grid.id, grid.Parent.id, grid.Parent.Children[0].id)
+
+            # children->parent == itself
+            for c in grid.Children:
+                assert c.Parent is grid, \
+                       'Grid %d, Children %d, Children->Parent %d' % \
+                       (grid.id, c.id, c.Parent.id)
+
+            # all refinement grids should have parent 
+            if grid.Level > 0:
+                assert grid.Parent is not None and grid.Parent.id >= 0, \
+                       'Grid %d, Level %d, Parent %d' % \
+                       (grid.id, grid.Level, \
+                        grid.Parent.id if grid.Parent is not None else -999)
+
+            # parent index is consistent with the loaded dataset
+            if grid.Level > 0:
+                father_gid = father_list[grid.id]
+                assert father_gid == grid.Parent.id, \
+                       'Grid %d, Level %d, Parent_Found %d, Parent_Expect %d'%\
+                       (grid.id, grid.Level, grid.Parent.id, father_gid)
+
+            # edges between children and parent
+            if len(grid.Children) > 0:
+                assert_equal(grid.LeftEdge,  grid.Children[0].LeftEdge )
+                assert_equal(grid.RightEdge, grid.Children[7].RightEdge)
+        mylog.info('Check passed')
+               
+
+class GAMERDataset(Dataset):
+    _index_class      = GAMERHierarchy
+    _field_info_class = GAMERFieldInfo
+    _handle           = None
+    _debug            = False # debug mode for the GAMER frontend
+    
+    def __init__(self, filename,
+                 dataset_type      = 'gamer',
+                 storage_filename  = None,
+                 particle_filename = None, 
+                 units_override    = None,
+                 unit_system       = "cgs"):
+
+        if self._handle is not None: return
+
+        self.fluid_types      += ('gamer',)
+        self._handle           = HDF5FileHandler(filename)
+        self.particle_filename = particle_filename
+
+        if self.particle_filename is None:
+            self._particle_handle = self._handle
+        else:
+            try:
+                self._particle_handle = HDF5FileHandler(self.particle_filename)
+            except:
+                raise IOError(self.particle_filename)
+
+        # currently GAMER only supports refinement by a factor of 2
+        self.refine_by = 2
+
+        Dataset.__init__(self, filename, dataset_type,
+                         units_override = units_override,
+                         unit_system    = unit_system)
+        self.storage_filename = storage_filename
+        
+    def _set_code_unit_attributes(self):
+        # GAMER does not assume any unit yet ...
+        if len(self.units_override) == 0:
+            mylog.warning("GAMER does not assume any unit ==> " +
+                          "Use units_override to specify the units")
+
+        for unit, cgs in [("length", "cm"), ("time", "s"), ("mass", "g")]:
+            setattr(self, "%s_unit"%unit, self.quan(1.0, cgs))
+
+            if len(self.units_override) == 0:
+                mylog.warning("Assuming 1.0 = 1.0 %s", cgs)
+        
+    def _parse_parameter_file(self):
+        self.unique_identifier = \
+            int(os.stat(self.parameter_filename)[stat.ST_CTIME])
+
+        # shortcuts for different simulation information
+        KeyInfo   = self._handle['Info']['KeyInfo']
+        InputPara = self._handle['Info']['InputPara']
+        Makefile  = self._handle['Info']['Makefile']
+        SymConst  = self._handle['Info']['SymConst']
+
+        # simulation time and domain
+        self.current_time      = KeyInfo['Time'][0]
+        self.dimensionality    = 3  # always 3D
+        self.domain_left_edge  = np.array([0.,0.,0.], dtype='float64')
+        self.domain_right_edge = KeyInfo['BoxSize'].astype('float64')
+        self.domain_dimensions = KeyInfo['NX0'].astype('int64')
+
+        # periodicity
+        periodic         = InputPara['Opt__BC_Flu'][0] == 0
+        self.periodicity = (periodic,periodic,periodic)
+
+        # cosmological parameters
+        if Makefile['Comoving']:
+            self.cosmological_simulation = 1
+            self.current_redshift        = 1.0/self.current_time - 1.0
+            self.omega_matter            = InputPara['OmegaM0'] 
+            self.omega_lambda            = 1.0 - self.omega_matter
+            self.hubble_constant         = 0.6955   # H0 is not set in GAMER
+        else:
+            self.cosmological_simulation = 0
+            self.current_redshift        = 0.0
+            self.omega_matter            = 0.0
+            self.omega_lambda            = 0.0
+            self.hubble_constant         = 0.0
+
+        # code-specific parameters
+        for t in KeyInfo, InputPara, Makefile, SymConst:
+            for v in t.dtype.names: self.parameters[v] = t[v]
+
+        # reset 'Model' to be more readable
+        if KeyInfo['Model'] == 1:
+            self.parameters['Model'] = 'Hydro'
+        elif KeyInfo['Model'] == 2:
+            self.parameters['Model'] = 'MHD'
+        elif KeyInfo['Model'] == 3:
+            self.parameters['Model'] = 'ELBDM'
+        else:
+            self.parameters['Model'] = 'Unknown'
+
+        # make aliases to some frequently used variables
+        if self.parameters['Model'] == 'Hydro' or \
+           self.parameters['Model'] == 'MHD':
+            self.gamma = self.parameters["Gamma"]
+            self.mu    = self.parameters.get("mu",0.6) # mean molecular weight
+
+    @classmethod
+    def _is_valid(self, *args, **kwargs):
+        try:
+            # define a unique way to identify GAMER datasets
+            f = HDF5FileHandler(args[0])
+            if 'Info' in f['/'].keys() and 'KeyInfo' in f['/Info'].keys():
+                return True
+        except:
+            pass
+        return False

diff -r b61ebaeaae2e05c7e2aa6757ff23465c5cf2681d -r 01c911476af375f444f6d83cac45f5a61c9d82e4 yt/frontends/gamer/fields.py
--- /dev/null
+++ b/yt/frontends/gamer/fields.py
@@ -0,0 +1,110 @@
+"""
+GAMER-specific fields
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2016, 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
+from yt.utilities.physical_constants import mh, boltzmann_constant_cgs
+
+b_units   = "code_magnetic"
+pre_units = "code_mass / (code_length*code_time**2)"
+erg_units = "code_mass / (code_length*code_time**2)"
+rho_units = "code_mass / code_length**3"
+mom_units = "code_mass / (code_length**2*code_time)"
+vel_units = "code_velocity"
+pot_units = "code_length**2/code_time**2"
+
+psi_units = "code_mass**(1/2) / code_length**(3/2)"
+
+
+class GAMERFieldInfo(FieldInfoContainer):
+    known_other_fields = (
+        # hydro fields on disk (GAMER outputs conservative variables)
+        ( "Dens", (rho_units, ["density"],                 r"\rho") ),
+        ( "MomX", (mom_units, ["momentum_x"],              None   ) ),
+        ( "MomY", (mom_units, ["momentum_y"],              None   ) ),
+        ( "MomZ", (mom_units, ["momentum_z"],              None   ) ),
+        ( "Engy", (erg_units, ["total_energy_per_volume"], None   ) ),
+        ( "Pote", (pot_units, ["gravitational_potential"], None   ) ),
+
+        # psiDM fields on disk
+        ( "Real", (psi_units, ["psidm_real_part"],         None   ) ),
+        ( "Imag", (psi_units, ["psidm_imaginary_part"],    None   ) ),
+    )
+
+    known_particle_fields = (
+    )
+
+    def __init__(self, ds, field_list):
+        super(GAMERFieldInfo, self).__init__(ds, field_list)
+
+    # add primitive and other derived variables
+    def setup_fluid_fields(self):
+        unit_system = self.ds.unit_system
+
+        # velocity
+        def velocity_xyz(v):
+            def _velocity(field, data):
+                return data["gas", "momentum_%s"%v] / data["gas","density"]
+            return _velocity
+        for v in "xyz":
+            self.add_field( ("gas","velocity_%s"%v), function = velocity_xyz(v),
+                            units = unit_system["velocity"] )
+
+        # ============================================================================
+        # note that yt internal fields assume
+        #    [thermal_energy]          = [energy per mass]
+        #    [kinetic_energy]          = [energy per volume]
+        # and we further adopt
+        #    [total_energy]            = [energy per mass]
+        #    [total_energy_per_volume] = [energy per volume]
+        # ============================================================================
+
+        # kinetic energy per volume
+        def ek(data):
+            return 0.5*( data["gamer","MomX"]**2 +
+                         data["gamer","MomY"]**2 +
+                         data["gamer","MomZ"]**2 ) / data["gamer","Dens"]
+
+        # thermal energy per volume
+        def et(data):
+            return data["gamer","Engy"] - ek(data)
+
+        # thermal energy per mass (i.e., specific)
+        def _thermal_energy(field, data):
+            return et(data) / data["gamer","Dens"]
+        self.add_field( ("gas","thermal_energy"), function = _thermal_energy,
+                        units = unit_system["specific_energy"] )
+
+        # total energy per mass
+        def _total_energy(field, data):
+            return data["gamer","Engy"] / data["gamer","Dens"]
+        self.add_field( ("gas","total_energy"), function = _total_energy,
+                        units = unit_system["specific_energy"] )
+
+        # pressure
+        def _pressure(field, data):
+            return et(data)*(data.ds.gamma-1.0)
+        self.add_field( ("gas","pressure"), function = _pressure,
+                        units = unit_system["pressure"] )
+
+        # temperature
+        def _temperature(field, data):
+            return data.ds.mu*mh*data["gas","pressure"] / \
+                   (data["gas","density"]*boltzmann_constant_cgs)
+        self.add_field( ("gas","temperature"), function = _temperature,
+                        units = unit_system["temperature"] )
+
+    def setup_particle_fields(self, ptype):
+        # This will get called for every particle type.
+        pass

diff -r b61ebaeaae2e05c7e2aa6757ff23465c5cf2681d -r 01c911476af375f444f6d83cac45f5a61c9d82e4 yt/frontends/gamer/io.py
--- /dev/null
+++ b/yt/frontends/gamer/io.py
@@ -0,0 +1,90 @@
+"""
+GAMER-specific IO functions
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2016, 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
+from itertools import groupby
+
+from yt.utilities.io_handler import \
+    BaseIOHandler
+from yt.utilities.logger import ytLogger as mylog
+
+
+#-----------------------------------------------------------------------------
+# GAMER shares a similar HDF5 format, and thus io.py as well, with FLASH
+#-----------------------------------------------------------------------------
+
+
+# group grids with consecutive indices together to improve the I/O performance
+def grid_sequences(grids):
+    for k, g in groupby( enumerate(grids), lambda i_x1:i_x1[0]-i_x1[1].id ):
+        seq = list(v[1] for v in g)
+        yield seq
+
+class IOHandlerGAMER(BaseIOHandler):
+    _particle_reader = False
+    _dataset_type    = "gamer"
+
+    def __init__(self, ds):
+        super(IOHandlerGAMER, self).__init__(ds)
+        self._handle      = ds._handle
+        self._field_dtype = "float64" # fixed even when FLOAT8 is off
+
+    def _read_particle_coords(self, chunks, ptf):
+        pass
+
+    def _read_particle_fields(self, chunks, ptf, selector):
+        pass
+
+    def _read_fluid_selection(self, chunks, selector, fields, size):
+        chunks = list(chunks) # generator --> list
+
+        if any( (ftype != "gamer" for ftype, fname in fields) ):
+            raise NotImplementedError
+
+        rv = {}
+        for field in fields: rv[field] = np.empty( size, dtype=self._field_dtype )
+
+        ng = sum( len(c.objs) for c in chunks ) # c.objs is a list of grids
+        mylog.debug( "Reading %s cells of %s fields in %s grids",
+                     size, [f2 for f1, f2 in fields], ng )
+
+        for field in fields:
+            ds     = self._handle[ "/Data/%s" % field[1] ]
+            offset = 0
+            for chunk in chunks:
+                for gs in grid_sequences(chunk.objs):
+                    start = gs[ 0].id
+                    end   = gs[-1].id + 1
+                    data  = ds[start:end,:,:,:].transpose()
+                    for i, g in enumerate(gs):
+                        offset += g.select( selector, data[...,i], rv[field], offset )
+        return rv
+
+    def _read_chunk_data(self, chunk, fields):
+        rv = {}
+        if len(chunk.objs) == 0: return rv 
+
+        for g in chunk.objs: rv[g.id] = {}
+
+        for field in fields:
+            ds = self._handle[ "/Data/%s" % field[1] ]
+
+            for gs in grid_sequences(chunk.objs):
+                start = gs[ 0].id
+                end   = gs[-1].id + 1
+                data  = ds[start:end,:,:,:].transpose()
+                for i, g in enumerate(gs):
+                    rv[g.id][field] = np.asarray( data[...,i], dtype=self._field_dtype )
+        return rv

diff -r b61ebaeaae2e05c7e2aa6757ff23465c5cf2681d -r 01c911476af375f444f6d83cac45f5a61c9d82e4 yt/frontends/gamer/tests/test_outputs.py
--- /dev/null
+++ b/yt/frontends/gamer/tests/test_outputs.py
@@ -0,0 +1,63 @@
+"""
+GAMER frontend tests
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2016, 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.testing import \
+    assert_equal, \
+    requires_file, \
+    units_override_check
+from yt.utilities.answer_testing.framework import \
+    requires_ds, \
+    small_patch_amr, \
+    data_dir_load
+from yt.frontends.gamer.api import GAMERDataset
+
+
+
+jet         = "InteractingJets/jet_000002"
+_fields_jet = ("temperature", "density", "velocity_magnitude")
+jet_units   = {"length_unit":(1.0,"kpc"),
+               "time_unit"  :(3.08567758096e+13,"s"),
+               "mass_unit"  :(1.4690033e+36,"g")}
+
+ at requires_ds(jet, big_data=True)
+def test_jet():
+    ds = data_dir_load(jet, kwargs={"units_override":jet_units})
+    yield assert_equal, str(ds), "jet_000002"
+    for test in small_patch_amr(ds, _fields_jet):
+        test_jet.__name__ = test.description
+        yield test
+
+
+psiDM         = "WaveDarkMatter/psiDM_000020"
+_fields_psiDM = ("Dens", "Real", "Imag")
+
+ at requires_ds(psiDM, big_data=True)
+def test_psiDM():
+    ds = data_dir_load(psiDM)
+    yield assert_equal, str(ds), "psiDM_000020"
+    for test in small_patch_amr(ds, _fields_psiDM):
+        test_psiDM.__name__ = test.description
+        yield test
+
+
+ at requires_file(psiDM)
+def test_GAMERDataset():
+    assert isinstance(data_dir_load(psiDM), GAMERDataset)
+
+
+ at requires_file(jet)
+def test_units_override():
+    for test in units_override_check(jet):
+        yield test

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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.spacepope.org/pipermail/yt-svn-spacepope.org/attachments/20160511/0292a572/attachment.html>


More information about the yt-svn mailing list