<html><body>
<p>12 new commits in yt:</p>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/54edcb134b37/">https://bitbucket.org/yt_analysis/yt/commits/54edcb134b37/</a> Changeset:   54edcb134b37 Branch:      yt User:        hyschive Date:        2016-04-28 15:54:24+00:00 Summary:     GAMER frontend Affected #:  10 files</p>
<p>diff -r 77db965d0a537a9884d6db3c5ad7595dc3070ba0 -r 54edcb134b37e2dd39b65f111a7f4b9bb47737d9 yt/frontends/api.py --- a/yt/frontends/api.py +++ b/yt/frontends/api.py @@ -29,6 +29,7 @@</p>
<pre>'flash',
'gadget',
'gadget_fof',</pre>
<p>+    ‘gamer’,</p>
<pre>'gdf',
'halo_catalog',
'http_stream',</pre>
<p>diff -r 77db965d0a537a9884d6db3c5ad7595dc3070ba0 -r 54edcb134b37e2dd39b65f111a7f4b9bb47737d9 yt/frontends/gamer/__init__.py --- /dev/null +++ b/yt/frontends/gamer/__init__.py @@ -0,0 +1,14 @@ +""" +API for yt.frontends.gamer + + + +""" + +#----------------------------------------------------------------------------- +# Copyright © 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. +#-----------------------------------------------------------------------------</p>
<p>diff -r 77db965d0a537a9884d6db3c5ad7595dc3070ba0 -r 54edcb134b37e2dd39b65f111a7f4b9bb47737d9 yt/frontends/gamer/api.py --- /dev/null +++ b/yt/frontends/gamer/api.py @@ -0,0 +1,28 @@ +""" +API for yt.frontends.gamer + + + +""" + +#----------------------------------------------------------------------------- +# Copyright © 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</p>
<p>diff -r 77db965d0a537a9884d6db3c5ad7595dc3070ba0 -r 54edcb134b37e2dd39b65f111a7f4b9bb47737d9 yt/frontends/gamer/data_structures.py --- /dev/null +++ b/yt/frontends/gamer/data_structures.py @@ -0,0 +1,303 @@ +""" +GAMER-specific data structures + + + +""" + +#----------------------------------------------------------------------------- +# Copyright © 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 yt.utilities.physical_ratios import cm_per_mpc +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 +        self.PID      = None    # patch ID adopted in GAMER +        self.CID      = None    # cluster ID in the GAMER HDF5 output + +    def __repr__(self): +        return ‘GAMERGrid_%09i (dimension = %s)’ % (self.id, self.ActiveDimensions) + + +class GAMERHierarchy(GridIndex): +    grid = GAMERGrid + +    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 +        # choose an arbitrary grid since they all have the same fields +        Grid = self._handle['Level_00']['Cluster_%09i'%0]['Patch_%09i'%0] +        self.field_list = [ ('gamer’, v) for v in Grid.dtype.names ] + +    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): +        f    = self._handle +        Para = self.dataset.parameters +        GID0 = 0 + +        self.grid_dimensions    [:] = Para['PatchSize'] +        self.grid_particle_count[:] = 0 + +        for lv in range(0, Para['NLevel']): +            NP = Para['NPatch'][lv] +            if NP == 0: break + +            Scale  = Para['CellScale'][lv] +            PScale = Para['PatchSize']*Scale +            CrList = f['PatchMap'][ ‘Level_%d%d'%(lv/10,lv%10) ]['CornerList'].value +            Cr2Phy = f['PatchMap'][ ‘Level_%d%d'%(lv/10,lv%10) ]['CornerList'].attrs['Cvt2Phy’] + +            # set the level and edge of each grid +            # (left/right_edge are YT arrays in code units) +            self.grid_levels.flat[ GID0:GID0+NP ] = lv +            self.grid_left_edge  [ GID0:GID0+NP ] = CrList[:]*Cr2Phy +            self.grid_right_edge [ GID0:GID0+NP ] = (CrList[:] + PScale)*Cr2Phy + +            GID0 += NP + +        # 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): +        f  = self._handle +        NP = self.dataset.parameters['NPatch'] +        NC = f['SimuInfo']['KeyInfo']['H5_MaxDsetPerGroup'] + +        for lv in range(0, self.dataset.parameters['NLevel']): +            if NP[lv] == 0: break + +            # converting HDF5 dataset to numpy array in advance (using .value) +            # is much faster than using h5py directly +            SonList    = f['PatchMap'][ ‘Level_%02i'%lv ]['SonList'].value +#           SonList    = f['PatchMap'][ ‘Level_%02i'%lv ]['SonList’] +            SonGID0    = NP[0:lv+1].sum() +            GID0       = NP[0:lv  ].sum() + +            # set the parent-children relationship +            for PID in range(0, NP[lv]): +                Grid   = self.grids.flat[GID0+PID] +                CID    = PID / NC +                SonPID = SonList[PID] + +                if SonPID >= 0: +                    Grid.Children = [ self.grids.flat[SonGID0+SonPID+s] \ +                                      for s in range(0,8) ] + +                for SonGrid in Grid.Children: SonGrid.Parent = Grid + +                # record the patch and cluster indices +                Grid.PID = PID +                Grid.CID = CID + +                # 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 …’) + +        f    = self._handle +        Para = self.dataset.parameters + +        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: +                NC     = f['SimuInfo']['KeyInfo']['H5_MaxDsetPerGroup'] +                PID    = Grid.PID +                CID    = PID / NC +                LvName = ‘Level_%02i’   % Grid.Level +                CName  = ‘Cluster_%09i’ % CID +                PName  = ‘Patch_%09i’   % PID +                FaGID  = f[LvName][CName][PName].attrs['Info']['Father'] \ +                         + Para['NPatch'][0:Grid.Level-1].sum() +                assert FaGID == Grid.Parent.id, \ +                       ‘Grid %d, Level %d, Parent_Found %d, Parent_Expect %d'%\ +                       (Grid.id, Grid.Level, Grid.Parent.id, FaGID) + +            # 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            = True  # turn on the debug mode +    _debug            = False # turn on the debug mode + +    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['SimuInfo']['KeyInfo'] +        InputPara = self._handle['SimuInfo']['InputPara'] +        Makefile  = self._handle['SimuInfo']['Makefile'] +        SymConst  = self._handle['SimuInfo']['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 +        self.parameters['Model'] =      ‘Hydro’ if KeyInfo['Model'] == 1 \ +                                   else ‘MHD’   if KeyInfo['Model'] == 2 \ +                                   else ‘ELBDM’ if KeyInfo['Model'] == 3 \ +                                   else ‘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 ‘PatchMap’ in f['/'].keys(): +                return True +        except: +            pass +        return False</p>
<p>diff -r 77db965d0a537a9884d6db3c5ad7595dc3070ba0 -r 54edcb134b37e2dd39b65f111a7f4b9bb47737d9 yt/frontends/gamer/fields.py --- /dev/null +++ b/yt/frontends/gamer/fields.py @@ -0,0 +1,89 @@ +""" +GAMER-specific fields + + + +""" + +#----------------------------------------------------------------------------- +# Copyright © 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"],            None   ) ), +        ( “Pote”, (pot_units, ["gravitational_potential"], None   ) ), + +        # psiDM fields on disk +        ( “Real”, (psi_units, ["real_part"],               None   ) ), +        ( “Imag”, (psi_units, ["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"] ) + +        # 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) + +        # 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</p>
<p>diff -r 77db965d0a537a9884d6db3c5ad7595dc3070ba0 -r 54edcb134b37e2dd39b65f111a7f4b9bb47737d9 yt/frontends/gamer/io.py --- /dev/null +++ b/yt/frontends/gamer/io.py @@ -0,0 +1,85 @@ +""" +GAMER-specific IO functions + + + +""" + +#----------------------------------------------------------------------------- +# Copyright © 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 yt.funcs import mylog +from yt.utilities.io_handler import \ +    BaseIOHandler + +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): +        # This needs to <strong>yield</strong> a series of tuples of (ptype, (x, y, z)). +        # chunks is a list of chunks, and ptf is a dict where the keys are +        # ptypes and the values are lists of fields. +        pass + +    def _read_particle_fields(self, chunks, ptf, selector): +        # This gets called after the arrays have been allocated.  It needs to +        # yield ((ptype, field), data) where data is the masked results of +        # reading ptype, field and applying the selector to the data read in. +        # Selector objects have a .select_points(x,y,z) that returns a mask, so +        # you need to do your masking here. +        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 ) +        offset = 0 +        for chunk in chunks: +            data = self._read_chunk_data( chunk, fields ) +            for g in chunk.objs: +                for field in fields: +                    ds    = data[g.id].pop(field) +                    # array return from g.select (i.e., rv[field]) is flat +                    ncell = g.select( selector, ds, rv[field], offset ) +                offset += ncell +                data.pop(g.id) +        return rv + +    def _read_chunk_data(self, chunk, fields): +        data = {} +        if len(chunk.objs) == 0: return data + +        for g in chunk.objs: +            data[g.id] = {} +            LvName = ‘Level_%02i’   % g.Level +            CName  = ‘Cluster_%09i’ % g.CID +            PName  = ‘Patch_%09i’   % g.PID + +            for field in fields: +                # transpose x-z since YT assumes that consecutive cells along z +                # are contiguous in memory +                data[g.id][field] \ +                = self._handle[LvName][CName][PName][ field[1] ].swapaxes(0,2) +        return data +</p>
<p>diff -r 77db965d0a537a9884d6db3c5ad7595dc3070ba0 -r 54edcb134b37e2dd39b65f111a7f4b9bb47737d9 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 © 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")} + +@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, <em>fields_jet): +        test_jet.__name</em>_ = test.description +        yield test + + +psiDM         = “WaveDarkMatter/psiDM_000020” +_fields_psiDM = ("Dens", “Real”, “Imag”) + +@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, <em>fields_psiDM): +        test_psiDM.__name</em>_ = test.description +        yield test + + +@requires_file(psiDM) +def test_GAMERDataset(): +    assert isinstance(data_dir_load(psiDM), GAMERDataset) + + +@requires_file(jet) +def test_units_override(): +    for test in units_override_check(jet): +        yield test</p>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/624aeedcc39f/">https://bitbucket.org/yt_analysis/yt/commits/624aeedcc39f/</a> Changeset:   624aeedcc39f Branch:      yt User:        hyschive Date:        2016-04-28 16:21:52+00:00 Summary:     Add answer test for GAMER in tests/tests.yaml Affected #:  1 file</p>
<p>diff -r 54edcb134b37e2dd39b65f111a7f4b9bb47737d9 -r 624aeedcc39fc7f53acb792ec82f7113c4ea44d4 tests/tests.yaml --- a/tests/tests.yaml +++ b/tests/tests.yaml @@ -20,6 +20,9 @@</p>
<pre>  local_gadget_000:
    - yt/frontends/gadget/tests/test_outputs.py
</pre>
<p>+  local_gamer_000: +    – yt/frontends/gamer/tests/test_outputs.py +</p>
<pre>  local_gdf_000:
    - yt/frontends/gdf/tests/test_outputs.py
</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/178141e68361/">https://bitbucket.org/yt_analysis/yt/commits/178141e68361/</a> Changeset:   178141e68361 Branch:      yt User:        hyschive Date:        2016-04-28 20:12:13+00:00 Summary:     Fixing flake8 errors Affected #:  1 file</p>
<p>diff -r 624aeedcc39fc7f53acb792ec82f7113c4ea44d4 -r 178141e68361b4c7a0f9efa46279e55750180a3a yt/frontends/gamer/data_structures.py --- a/yt/frontends/gamer/data_structures.py +++ b/yt/frontends/gamer/data_structures.py @@ -27,7 +27,6 @@</p>
<pre>    Dataset
from yt.utilities.file_handler import \
    HDF5FileHandler</pre>
<p>-from yt.utilities.physical_ratios import cm_per_mpc</p>
<pre>from .fields import GAMERFieldInfo
from yt.testing import assert_equal
</pre>
<p>@@ -281,10 +280,11 @@</p>
<pre>            for v in t.dtype.names: self.parameters[v] = t[v]

        # reset 'Model' to be more readable</pre>
<ul><li><p>self.parameters['Model'] =      ‘Hydro’ if KeyInfo['Model'] == 1 \</p></li>
<li><p>else ‘MHD’   if KeyInfo['Model'] == 2 \</p></li>
<li><p>else ‘ELBDM’ if KeyInfo['Model'] == 3 \</p></li>
<li><p>else ‘Unknown’</p></li></ul>
<p>+        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’ +</p>
<pre>         # make aliases to some frequently used variables
         if self.parameters['Model'] == 'Hydro' or \
self.parameters['Model'] == 'MHD':</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/60d8b92ce7f0/">https://bitbucket.org/yt_analysis/yt/commits/60d8b92ce7f0/</a> Changeset:   60d8b92ce7f0 Branch:      yt User:        hyschive Date:        2016-04-28 20:24:23+00:00 Summary:     Fixing minor python style for if … elif … Affected #:  1 file</p>
<p>diff -r 178141e68361b4c7a0f9efa46279e55750180a3a -r 60d8b92ce7f0575441bf988d77446d5c3c9605e1 yt/frontends/gamer/data_structures.py --- a/yt/frontends/gamer/data_structures.py +++ b/yt/frontends/gamer/data_structures.py @@ -280,10 +280,14 @@</p>
<pre>            for v in t.dtype.names: self.parameters[v] = t[v]

        # reset 'Model' to be more readable</pre>
<ul><li><p>if KeyInfo['Model'] == 1:   self.parameters['Model'] = ‘Hydro’</p></li>
<li><p>elif KeyInfo['Model'] == 2: self.parameters['Model'] = ‘MHD’</p></li>
<li><p>elif KeyInfo['Model'] == 3: self.parameters['Model'] = ‘ELBDM’</p></li>
<li><p>else:                       self.parameters['Model'] = ‘Unknown’</p></li></ul>
<p>+        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’</p>
<pre># make aliases to some frequently used variables
if self.parameters['Model'] == 'Hydro' or \</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/648dc24665ab/">https://bitbucket.org/yt_analysis/yt/commits/648dc24665ab/</a> Changeset:   648dc24665ab Branch:      yt User:        hyschive Date:        2016-04-28 21:13:37+00:00 Summary:     Adding YT document Affected #:  2 files</p>
<p>diff -r 60d8b92ce7f0575441bf988d77446d5c3c9605e1 -r 648dc24665ab1575417ce7beb4f3add3f9b805cd doc/source/examining/loading_data.rst --- a/doc/source/examining/loading_data.rst +++ b/doc/source/examining/loading_data.rst @@ -806,6 +806,20 @@</p>
<pre>* Please be careful that the units are correctly utilized; yt assumes cgs by default, but conversion to
  other :ref:`unit systems <unit_systems>` is also possible.
</pre>
<p>+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") + +.. rubric:: Caveats + +* GAMER data in raw binary format is not supported. +</p>
<pre>.. _loading-gadget-data:

Gadget Data</pre>
<p>diff -r 60d8b92ce7f0575441bf988d77446d5c3c9605e1 -r 648dc24665ab1575417ce7beb4f3add3f9b805cd doc/source/reference/code_support.rst --- a/doc/source/reference/code_support.rst +++ b/doc/source/reference/code_support.rst @@ -34,6 +34,8 @@</p>
<pre>+-----------------------+------------+-----------+------------+-------+----------+----------+------------+----------+
| Gadget                |     Y      |     Y     |      Y     |   Y   | Y [#f2]_ |    Y     |     Y      |   Full   |
+-----------------------+------------+-----------+------------+-------+----------+----------+------------+----------+</pre>
<p>+| GAMER                 |     Y      |     N     |      Y     |   Y   |    Y     |    Y     |     Y      |   Full   | ++-----------------------+------------+-----------+------------+-------+----------+----------+------------+----------+</p>
<pre>| Gasoline              |     Y      |     Y     |      Y     |   Y   | Y [#f2]_ |    Y     |     Y      |   Full   |
+-----------------------+------------+-----------+------------+-------+----------+----------+------------+----------+
| Grid Data Format (GDF)|     Y      |    N/A    |      Y     |   Y   |    Y     |    Y     |     Y      |   Full   |</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/7ed56d5c8cf4/">https://bitbucket.org/yt_analysis/yt/commits/7ed56d5c8cf4/</a> Changeset:   7ed56d5c8cf4 Branch:      yt User:        hyschive Date:        2016-05-06 17:43:23+00:00 Summary:     Rewrite data_structures.py to support the new GAMER data format Affected #:  1 file</p>
<p>diff -r 648dc24665ab1575417ce7beb4f3add3f9b805cd -r 7ed56d5c8cf442841dcbd4cfd826abad414566a8 yt/frontends/gamer/data_structures.py --- a/yt/frontends/gamer/data_structures.py +++ b/yt/frontends/gamer/data_structures.py @@ -42,8 +42,6 @@</p>
<pre>self.Parent   = None    # do NOT initialize Parent as []
self.Children = []
self.Level    = level</pre>
<ul><li><p>self.PID      = None    # patch ID adopted in GAMER</p></li>
<li><p>self.CID      = None    # cluster ID in the GAMER HDF5 output</p></li></ul>
<pre>def __repr__(self):
    return 'GAMERGrid_%09i (dimension = %s)' % (self.id, self.ActiveDimensions)</pre>
<p>@@ -64,18 +62,17 @@</p>
<pre>def _detect_output_fields(self):
    # find all field names in the current dataset</pre>
<ul><li><p># choose an arbitrary grid since they all have the same fields</p></li>
<li><p>Grid = self._handle['Level_00']['Cluster_%09i'%0]['Patch_%09i'%0]</p></li>
<li><p>self.field_list = [ ('gamer', v) for v in Grid.dtype.names ]</p></li></ul>
<p>+        self.field_list = [ ('gamer', v) for v in self._handle['Data'].keys() ]</p>
<pre>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):</pre>
<ul><li><p>f    = self._handle</p></li>
<li><p>Para = self.dataset.parameters</p></li>
<li><p>GID0 = 0</p></li></ul>
<p>+        Para   = self.dataset.parameters +        GID0   = 0 +        CrList = self._handle['Tree/Corner'].value +        Cr2Phy = self._handle['Tree/Corner'].attrs['Cvt2Phy']</p>
<pre>self.grid_dimensions    [:] = Para['PatchSize']
self.grid_particle_count[:] = 0</pre>
<p>@@ -84,16 +81,13 @@</p>
<pre>            NP = Para['NPatch'][lv]
            if NP == 0: break
</pre>
<ul><li><p>Scale  = Para['CellScale'][lv]</p></li>
<li><p>PScale = Para['PatchSize']*Scale</p></li>
<li><p>CrList = f['PatchMap'][ 'Level_%d%d'%(lv/10,lv%10) ]['CornerList'].value</p></li>
<li><p>Cr2Phy = f['PatchMap'][ ‘Level_%d%d'%(lv/10,lv%10) ]['CornerList'].attrs['Cvt2Phy’]</p></li></ul>
<p>+            PScale = Para['PatchSize']*Para['CellScale'][lv]</p>
<pre># set the level and edge of each grid
# (left/right_edge are YT arrays in code units)
self.grid_levels.flat[ GID0:GID0+NP ] = lv</pre>
<ul><li><p>self.grid_left_edge  [ GID0:GID0+NP ] = CrList[:]*Cr2Phy</p></li>
<li><p>self.grid_right_edge [ GID0:GID0+NP ] = (CrList[:] + PScale)*Cr2Phy</p></li></ul>
<p>+            self.grid_left_edge  [ GID0:GID0+NP ] = CrList[ GID0:GID0+NP ]*Cr2Phy +            self.grid_right_edge [ GID0:GID0+NP ] = (CrList[ GID0:GID0+NP ] + PScale)*Cr2Phy</p>
<pre>            GID0 += NP
</pre>
<p>@@ -106,39 +100,21 @@</p>
<pre>    self.max_level = self.grid_levels.max()
    
def _populate_grid_objects(self):</pre>
<ul><li><p>f  = self._handle</p></li>
<li><p>NP = self.dataset.parameters['NPatch']</p></li>
<li><p>NC = f['SimuInfo']['KeyInfo']['H5_MaxDsetPerGroup']</p></li></ul>
<p>+        son_list = self._handle["Tree/Son"].value</p>
<ul><li><p>for lv in range(0, self.dataset.parameters['NLevel']):</p></li>
<li><p>if NP[lv] == 0: break</p></li></ul>
<p>+        for gid in range(self.num_grids): +            grid     = self.grids.flat[gid] +            son_gid0 = son_list[gid]</p>
<ul><li><p># converting HDF5 dataset to numpy array in advance (using .value)</p></li>
<li><p># is much faster than using h5py directly</p></li>
<li><p>SonList    = f['PatchMap'][ 'Level_%02i'%lv ]['SonList'].value</p></li></ul>
<p>-#           SonList    = f['PatchMap'][ ‘Level_%02i'%lv ]['SonList’]</p>
<ul><li><p>SonGID0    = NP[0:lv+1].sum()</p></li>
<li><p>GID0       = NP[0:lv  ].sum()</p></li></ul>
<p>+            # set up the parent-children relationship +            if son_gid0 >= 0: +                grid.Children = [ self.grids.flat[son_gid0+s] for s in range(8) ]</p>
<ul><li><p># set the parent-children relationship</p></li>
<li><p>for PID in range(0, NP[lv]):</p></li>
<li><p>Grid   = self.grids.flat[GID0+PID]</p></li>
<li><p>CID    = PID / NC</p></li>
<li><p>SonPID = SonList[PID]</p></li></ul>
<p>+            for son_grid in grid.Children: son_grid.Parent = grid</p>
<ul><li><p>if SonPID >= 0:</p></li>
<li><p>Grid.Children = [ self.grids.flat[SonGID0+SonPID+s] \</p></li>
<li><p>for s in range(0,8) ]</p></li></ul>
<p>–</p>
<ul><li><p>for SonGrid in Grid.Children: SonGrid.Parent = Grid</p></li></ul>
<p>–</p>
<ul><li><p># record the patch and cluster indices</p></li>
<li><p>Grid.PID = PID</p></li>
<li><p>Grid.CID = CID</p></li></ul>
<p>–</p>
<ul><li><p># set up other grid attributes</p></li>
<li><p>Grid._prepare_grid()</p></li>
<li><p>Grid._setup_dx()</p></li></ul>
<p>+            # set up other grid attributes +            grid._prepare_grid() +            grid._setup_dx()</p>
<pre># validate the parent-children relationship in the debug mode
if self.dataset._debug:</pre>
<p>@@ -148,47 +124,40 @@</p>
<pre>    def _validate_parent_children_relasionship(self):
        mylog.info('Validating the parent-children relationship ...')
</pre>
<ul><li><p>f    = self._handle</p></li>
<li><p>Para = self.dataset.parameters</p></li></ul>
<p>+        Para        = self.dataset.parameters +        father_list = self._handle["Tree/Father"].value</p>
<ul><li><p>for Grid in self.grids:</p></li></ul>
<p>+        for grid in self.grids:</p>
<pre># parent->children == itself</pre>
<ul><li><p>if Grid.Parent is not None:</p></li>
<li><p>assert Grid.Parent.Children[0+Grid.id%8] is Grid, \</p></li></ul>
<p>+            if grid.Parent is not None: +                assert grid.Parent.Children[0+grid.id%8] is grid, \</p>
<pre>'Grid %d, Parent %d, Parent->Children %d' % \</pre>
<ul><li><p>(Grid.id, Grid.Parent.id, Grid.Parent.Children[0].id)</p></li></ul>
<p>+                       (grid.id, grid.Parent.id, grid.Parent.Children[0].id)</p>
<pre># children->parent == itself</pre>
<ul><li><p>for c in Grid.Children:</p></li>
<li><p>assert c.Parent is Grid, \</p></li></ul>
<p>+            for c in grid.Children: +                assert c.Parent is grid, \</p>
<pre>'Grid %d, Children %d, Children->Parent %d' % \</pre>
<ul><li><p>(Grid.id, c.id, c.Parent.id)</p></li></ul>
<p>+                       (grid.id, c.id, c.Parent.id)</p>
<pre># all refinement grids should have parent</pre>
<ul><li><p>if Grid.Level > 0:</p></li>
<li><p>assert Grid.Parent is not None and Grid.Parent.id >= 0, \</p></li></ul>
<p>+            if grid.Level > 0: +                assert grid.Parent is not None and grid.Parent.id >= 0, \</p>
<pre>'Grid %d, Level %d, Parent %d' % \</pre>
<ul><li><p>(Grid.id, Grid.Level, \</p></li>
<li><p>Grid.Parent.id if Grid.Parent is not None else -999)</p></li></ul>
<p>+                       (grid.id, grid.Level, \ +                        grid.Parent.id if grid.Parent is not None else -999)</p>
<pre># parent index is consistent with the loaded dataset</pre>
<ul><li><p>if Grid.Level > 0:</p></li>
<li><p>NC     = f['SimuInfo']['KeyInfo']['H5_MaxDsetPerGroup']</p></li>
<li><p>PID    = Grid.PID</p></li>
<li><p>CID    = PID / NC</p></li>
<li><p>LvName = ‘Level_%02i’   % Grid.Level</p></li>
<li><p>CName  = ‘Cluster_%09i’ % CID</p></li>
<li><p>PName  = ‘Patch_%09i’   % PID</p></li>
<li><p>FaGID  = f[LvName][CName][PName].attrs['Info']['Father'] \</p></li>
<li><p>+ Para['NPatch'][0:Grid.Level-1].sum()</p></li>
<li><p>assert FaGID == Grid.Parent.id, \</p></li></ul>
<p>+            if grid.Level > 0: +                father_gid = father_list[grid.id] +                assert father_gid == grid.Parent.id, \</p>
<pre>'Grid %d, Level %d, Parent_Found %d, Parent_Expect %d'%\</pre>
<ul><li><p>(Grid.id, Grid.Level, Grid.Parent.id, FaGID)</p></li></ul>
<p>+                       (grid.id, grid.Level, grid.Parent.id, FaGID)</p>
<pre># edges between children and parent</pre>
<ul><li><p>if len(Grid.Children) > 0:</p></li>
<li><p>assert_equal(Grid.LeftEdge,  Grid.Children[0].LeftEdge )</p></li>
<li><p>assert_equal(Grid.RightEdge, Grid.Children[7].RightEdge)</p></li></ul>
<p>+            if len(grid.Children) > 0: +                assert_equal(grid.LeftEdge,  grid.Children[0].LeftEdge ) +                assert_equal(grid.RightEdge, grid.Children[7].RightEdge)</p>
<pre>        mylog.info('Check passed')
               
</pre>
<p>@@ -196,8 +165,7 @@</p>
<pre>_index_class      = GAMERHierarchy
_field_info_class = GAMERFieldInfo
_handle           = None</pre>
<p>-#   _debug            = True  # turn on the debug mode</p>
<ul><li><p>_debug            = False # turn on the debug mode</p></li></ul>
<p>+    _debug            = True  # turn on/off the debug mode</p>
<pre>     def __init__(self, filename,
dataset_type      = 'gamer',</pre>
<p>@@ -245,10 +213,10 @@</p>
<pre>            int(os.stat(self.parameter_filename)[stat.ST_CTIME])

        # shortcuts for different simulation information</pre>
<ul><li><p>KeyInfo   = self._handle['SimuInfo']['KeyInfo']</p></li>
<li><p>InputPara = self._handle['SimuInfo']['InputPara']</p></li>
<li><p>Makefile  = self._handle['SimuInfo']['Makefile']</p></li>
<li><p>SymConst  = self._handle['SimuInfo']['SymConst']</p></li></ul>
<p>+        KeyInfo   = self._handle['Info']['KeyInfo'] +        InputPara = self._handle['Info']['InputPara'] +        Makefile  = self._handle['Info']['Makefile'] +        SymConst  = self._handle['Info']['SymConst']</p>
<pre># simulation time and domain
self.current_time      = KeyInfo['Time'][0]</pre>
<p>@@ -300,7 +268,7 @@</p>
<pre>         try:
# define a unique way to identify GAMER datasets
f = HDF5FileHandler(args[0])</pre>
<ul><li><p>if ‘PatchMap’ in f['/'].keys():</p></li></ul>
<p>+            if ‘Info’ in f['/'].keys() and ‘KeyInfo’ in f['/Info'].keys():</p>
<pre>    return True
         except:
pass</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/04b6be68c57d/">https://bitbucket.org/yt_analysis/yt/commits/04b6be68c57d/</a> Changeset:   04b6be68c57d Branch:      yt User:        hyschive Date:        2016-05-07 01:02:16+00:00 Summary:     Revise io.py to support the new GAMER output format Affected #:  2 files</p>
<p>diff -r 7ed56d5c8cf442841dcbd4cfd826abad414566a8 -r 04b6be68c57d6b6ed0b71d2538a2f0a0c8a299ee yt/frontends/gamer/data_structures.py --- a/yt/frontends/gamer/data_structures.py +++ b/yt/frontends/gamer/data_structures.py @@ -48,7 +48,8 @@</p>
<pre>class GAMERHierarchy(GridIndex):</pre>
<ul><li><p>grid = GAMERGrid</p></li></ul>
<p>+    grid                 = GAMERGrid +    _preload_implemented = True # since gamer defines “_read_chunk_data” in io.py</p>
<pre>def __init__(self, ds, dataset_type = 'gamer'):
    self.dataset_type     = dataset_type</pre>
<p>@@ -165,7 +166,7 @@</p>
<pre>_index_class      = GAMERHierarchy
_field_info_class = GAMERFieldInfo
_handle           = None</pre>
<ul><li><p>_debug            = True  # turn on/off the debug mode</p></li></ul>
<p>+    _debug            = False # turn on/off the debug mode</p>
<pre>     def __init__(self, filename,
dataset_type      = 'gamer',</pre>
<p>diff -r 7ed56d5c8cf442841dcbd4cfd826abad414566a8 -r 04b6be68c57d6b6ed0b71d2538a2f0a0c8a299ee yt/frontends/gamer/io.py --- a/yt/frontends/gamer/io.py +++ b/yt/frontends/gamer/io.py @@ -14,9 +14,24 @@</p>
<pre>#-----------------------------------------------------------------------------

import numpy as np</pre>
<p>-from yt.funcs import mylog +from itertools import groupby +</p>
<pre>from yt.utilities.io_handler import \
    BaseIOHandler</pre>
<p>+from yt.utilities.logger import ytLogger as mylog +from yt.geometry.selection_routines import AlwaysSelector + + +#----------------------------------------------------------------------------- +# 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</p>
<pre>class IOHandlerGAMER(BaseIOHandler):
    _particle_reader = False</pre>
<p>@@ -28,20 +43,11 @@</p>
<pre>        self._field_dtype = "float64" # fixed even when FLOAT8 is off

    def _read_particle_coords(self, chunks, ptf):</pre>
<ul><li><p># This needs to <strong>yield</strong> a series of tuples of (ptype, (x, y, z)).</p></li>
<li><p># chunks is a list of chunks, and ptf is a dict where the keys are</p></li>
<li><p># ptypes and the values are lists of fields. pass</p></li></ul>
<pre>def _read_particle_fields(self, chunks, ptf, selector):</pre>
<ul><li><p># This gets called after the arrays have been allocated.  It needs to</p></li>
<li><p># yield ((ptype, field), data) where data is the masked results of</p></li>
<li><p># reading ptype, field and applying the selector to the data read in.</p></li>
<li><p># Selector objects have a .select_points(x,y,z) that returns a mask, so</p></li>
<li><p># you need to do your masking here. pass</p></li></ul>
<p>–</p>
<pre>    def _read_fluid_selection(self, chunks, selector, fields, size):
        chunks = list(chunks) # generator --> list
</pre>
<p>@@ -54,32 +60,32 @@</p>
<pre>         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 )</pre>
<ul><li><p>offset = 0</p></li>
<li><p>for chunk in chunks:</p></li>
<li><p>data = self._read_chunk_data( chunk, fields )</p></li>
<li><p>for g in chunk.objs:</p></li>
<li><p>for field in fields:</p></li>
<li><p>ds    = data[g.id].pop(field)</p></li>
<li><p># array return from g.select (i.e., rv[field]) is flat</p></li>
<li><p>ncell = g.select( selector, ds, rv[field], offset )</p></li>
<li><p>offset += ncell</p></li>
<li><p>data.pop(g.id)</p></li></ul>
<p>+ +        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 )</p>
<pre>        return rv

    def _read_chunk_data(self, chunk, fields):</pre>
<ul><li><p>data = {}</p></li>
<li><p>if len(chunk.objs) == 0: return data</p></li></ul>
<p>+        rv = {} +        if len(chunk.objs) == 0: return rv</p>
<ul><li><p>for g in chunk.objs:</p></li>
<li><p>data[g.id] = {}</p></li>
<li><p>LvName = ‘Level_%02i’   % g.Level</p></li>
<li><p>CName  = ‘Cluster_%09i’ % g.CID</p></li>
<li><p>PName  = ‘Patch_%09i’   % g.PID</p></li></ul>
<p>+        for g in chunk.objs: rv[g.id] = {}</p>
<ul><li><p>for field in fields:</p></li>
<li><p># transpose x-z since YT assumes that consecutive cells along z</p></li>
<li><p># are contiguous in memory</p></li>
<li><p>data[g.id][field] \</p></li>
<li><p>= self._handle[LvName][CName][PName][ field[1] ].swapaxes(0,2)</p></li>
<li><p>return data</p></li></ul>
<p>+        for field in fields: +            ds = f[ “/Data/%s” % field[1] ]</p>
<p>+            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</p>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/c6788b76342d/">https://bitbucket.org/yt_analysis/yt/commits/c6788b76342d/</a> Changeset:   c6788b76342d Branch:      yt User:        hyschive Date:        2016-05-07 02:17:21+00:00 Summary:     Fix the typo in io.py Affected #:  1 file</p>
<p>diff -r 04b6be68c57d6b6ed0b71d2538a2f0a0c8a299ee -r c6788b76342d85496891318350ffe8e58e52fb49 yt/frontends/gamer/io.py --- a/yt/frontends/gamer/io.py +++ b/yt/frontends/gamer/io.py @@ -80,7 +80,7 @@</p>
<pre>        for g in chunk.objs: rv[g.id] = {}

        for field in fields:</pre>
<ul><li><p>ds = f[ “/Data/%s” % field[1] ]</p></li></ul>
<p>+            ds = self._handle[ “/Data/%s” % field[1] ]</p>
<pre>for gs in grid_sequences(chunk.objs):
    start = gs[ 0].id</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/8a110e6a0156/">https://bitbucket.org/yt_analysis/yt/commits/8a110e6a0156/</a> Changeset:   8a110e6a0156 Branch:      yt User:        hyschive Date:        2016-05-07 21:39:08+00:00 Summary:     Rename internal variables, add thermal_energy and total_energy fields, update doc Affected #:  5 files</p>
<p>diff -r c6788b76342d85496891318350ffe8e58e52fb49 -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 doc/source/developing/testing.rst --- a/doc/source/developing/testing.rst +++ b/doc/source/developing/testing.rst @@ -245,6 +245,12 @@</p>
<pre>* ``IsothermalCollapse/snap_505.hdf5``
* ``GadgetDiskGalaxy/snapshot_200.hdf5``
</pre>
<p>+GAMER +~~~~~~ + +* ``InteractingJets/jet_000002`` +* ``WaveDarkMatter/psiDM_000020`` +</p>
<pre>Halo Catalog
~~~~~~~~~~~~
</pre>
<p>diff -r c6788b76342d85496891318350ffe8e58e52fb49 -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 doc/source/examining/loading_data.rst --- a/doc/source/examining/loading_data.rst +++ b/doc/source/examining/loading_data.rst @@ -816,9 +816,23 @@</p>
<pre>   import yt
   ds = yt.load("InteractingJets/jet_000002")
</pre>
<p>+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. +</p>
<pre>.. rubric:: Caveats
</pre>
<p>-* GAMER data in raw binary format is not supported. +* GAMER data in raw binary format (i.e., OPT__OUTPUT_TOTAL = C-binary) is not supported.</p>
<pre>.. _loading-gadget-data:
</pre>
<p>diff -r c6788b76342d85496891318350ffe8e58e52fb49 -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 yt/frontends/gamer/data_structures.py --- a/yt/frontends/gamer/data_structures.py +++ b/yt/frontends/gamer/data_structures.py @@ -58,7 +58,7 @@</p>
<pre>self.directory        = os.path.dirname(self.index_filename)
self._handle          = ds._handle
self.float_type       = 'float64' # fixed even when FLOAT8 is off</pre>
<p>-#       self._particle_handle = ds._particle_handle +        self._particle_handle = ds._particle_handle</p>
<pre>        GridIndex.__init__(self, ds, dataset_type)

    def _detect_output_fields(self):</pre>
<p>@@ -70,27 +70,29 @@</p>
<pre>    self.num_grids = self.dataset.parameters['NPatch'].sum()
    
def _parse_index(self):</pre>
<ul><li><p>Para   = self.dataset.parameters</p></li>
<li><p>GID0   = 0</p></li>
<li><p>CrList = self._handle['Tree/Corner'].value</p></li>
<li><p>Cr2Phy = self._handle['Tree/Corner'].attrs['Cvt2Phy']</p></li></ul>
<p>+        parameters       = self.dataset.parameters +        gid0             = 0 +        grid_corner      = self._handle['Tree/Corner'].value +        convert2physical = self._handle['Tree/Corner'].attrs['Cvt2Phy']</p>
<ul><li><p>self.grid_dimensions    [:] = Para['PatchSize']</p></li></ul>
<p>+        self.grid_dimensions    [:] = parameters['PatchSize']</p>
<pre>        self.grid_particle_count[:] = 0
</pre>
<ul><li><p>for lv in range(0, Para['NLevel']):</p></li>
<li><p>NP = Para['NPatch'][lv]</p></li>
<li><p>if NP == 0: break</p></li></ul>
<p>+        for lv in range(0, parameters['NLevel']): +            num_grids_level = parameters['NPatch'][lv] +            if num_grids_level == 0: break</p>
<ul><li><p>PScale = Para['PatchSize']*Para['CellScale'][lv]</p></li></ul>
<p>+            patch_scale = parameters['PatchSize']*parameters['CellScale'][lv]</p>
<pre># set the level and edge of each grid
# (left/right_edge are YT arrays in code units)</pre>
<ul><li><p>self.grid_levels.flat[ GID0:GID0+NP ] = lv</p></li>
<li><p>self.grid_left_edge  [ GID0:GID0+NP ] = CrList[ GID0:GID0+NP ]*Cr2Phy</p></li>
<li><p>self.grid_right_edge [ GID0:GID0+NP ] = (CrList[ GID0:GID0+NP ] + PScale)*Cr2Phy</p></li></ul>
<p>+            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</p>
<ul><li><p>GID0 += NP</p></li></ul>
<p>+            gid0 += num_grids_level</p>
<pre># allocate all grid objects
self.grids = np.empty(self.num_grids, dtype='object')</pre>
<p>@@ -125,7 +127,6 @@</p>
<pre>    def _validate_parent_children_relasionship(self):
        mylog.info('Validating the parent-children relationship ...')
</pre>
<ul><li><p>Para        = self.dataset.parameters father_list = self._handle["Tree/Father"].value</p>
<p>for grid in self.grids:</p></li></ul>
<p>@@ -153,7 +154,7 @@</p>
<pre>father_gid = father_list[grid.id]
assert father_gid == grid.Parent.id, \
       'Grid %d, Level %d, Parent_Found %d, Parent_Expect %d'%\</pre>
<ul><li><p>(grid.id, grid.Level, grid.Parent.id, FaGID)</p></li></ul>
<p>+                       (grid.id, grid.Level, grid.Parent.id, father_gid)</p>
<pre># edges between children and parent
if len(grid.Children) > 0:</pre>
<p>@@ -166,7 +167,7 @@</p>
<pre>_index_class      = GAMERHierarchy
_field_info_class = GAMERFieldInfo
_handle           = None</pre>
<ul><li><p>_debug            = False # turn on/off the debug mode</p></li></ul>
<p>+    _debug            = False # debug mode for the GAMER frontend</p>
<pre>     def __init__(self, filename,
dataset_type      = 'gamer',</pre>
<p>@@ -227,7 +228,7 @@</p>
<pre>        self.domain_dimensions = KeyInfo['NX0'].astype('int64')

        # periodicity</pre>
<ul><li><p>periodic = InputPara['Opt__BC_Flu'][0] == 0</p></li></ul>
<p>+        periodic         = InputPara['Opt__BC_Flu'][0] == 0</p>
<pre>        self.periodicity = (periodic,periodic,periodic)

        # cosmological parameters</pre>
<p>diff -r c6788b76342d85496891318350ffe8e58e52fb49 -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 yt/frontends/gamer/fields.py --- a/yt/frontends/gamer/fields.py +++ b/yt/frontends/gamer/fields.py @@ -34,12 +34,12 @@</p>
<pre>( "MomX", (mom_units, ["momentum_x"],              None   ) ),
( "MomY", (mom_units, ["momentum_y"],              None   ) ),
( "MomZ", (mom_units, ["momentum_z"],              None   ) ),</pre>
<ul><li><p>( “Engy”, (erg_units, ["total_energy"],            None   ) ),</p></li></ul>
<p>+        ( “Engy”, (erg_units, ["total_energy_per_volume"], None   ) ),</p>
<pre>        ( "Pote", (pot_units, ["gravitational_potential"], None   ) ),

        # psiDM fields on disk</pre>
<ul><li><p>( “Real”, (psi_units, ["real_part"],               None   ) ),</p></li>
<li><p>( “Imag”, (psi_units, ["imaginary_part"],          None   ) ),</p></li></ul>
<p>+        ( “Real”, (psi_units, ["psidm_real_part"],         None   ) ), +        ( “Imag”, (psi_units, ["psidm_imaginary_part"],    None   ) ),</p>
<pre>    )

    known_particle_fields = (</pre>
<p>@@ -61,6 +61,15 @@</p>
<pre>            self.add_field( ("gas","velocity_%s"%v), function = velocity_xyz(v),
                            units = unit_system["velocity"] )
</pre>
<p>+        # ============================================================================ +        # 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] +        # ============================================================================ +</p>
<pre>         # kinetic energy per volume
         def ek(data):
return 0.5*( data["gamer","MomX"]**2 +</pre>
<p>@@ -71,6 +80,18 @@</p>
<pre>        def et(data):
            return data["gamer","Engy"] - ek(data)
</pre>
<p>+        # 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"] ) +</p>
<pre>         # pressure
         def _pressure(field, data):
return et(data)*(data.ds.gamma-1.0)</pre>
<p>diff -r c6788b76342d85496891318350ffe8e58e52fb49 -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 yt/frontends/gamer/io.py --- a/yt/frontends/gamer/io.py +++ b/yt/frontends/gamer/io.py @@ -19,7 +19,6 @@</p>
<pre>from yt.utilities.io_handler import \
    BaseIOHandler
from yt.utilities.logger import ytLogger as mylog</pre>
<p>-from yt.geometry.selection_routines import AlwaysSelector</p>
<pre>#-----------------------------------------------------------------------------</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/e551ce706857/">https://bitbucket.org/yt_analysis/yt/commits/e551ce706857/</a> Changeset:   e551ce706857 Branch:      yt User:        hyschive Date:        2016-05-08 22:28:46+00:00 Summary:     Merged with changeset 7f7ccbc9329e Affected #:  46 files</p>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd doc/source/analyzing/analysis_modules/photon_simulator.rst --- a/doc/source/analyzing/analysis_modules/photon_simulator.rst +++ b/doc/source/analyzing/analysis_modules/photon_simulator.rst @@ -478,7 +478,8 @@</p>
<pre>import yt
import numpy as np</pre>
<ul><li><p>from yt.utilities.physical_constants import cm_per_kpc, K_per_keV, mp</p></li></ul>
<p>+   from yt.utilities.physical_ratios import cm_per_kpc, K_per_keV +   from yt.units import mp</p>
<pre>from yt.utilities.cosmology import Cosmology
from yt.analysis_modules.photon_simulator.api import *
import aplpy</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd doc/source/analyzing/analysis_modules/xray_emission_fields.rst --- a/doc/source/analyzing/analysis_modules/xray_emission_fields.rst +++ b/doc/source/analyzing/analysis_modules/xray_emission_fields.rst @@ -32,7 +32,7 @@</p>
<pre>  from yt.analysis_modules.spectral_integrator.api import \
       add_xray_emissivity_field
</pre>
<ul><li><p>xray_fields = add_xray_emissivity_field(0.5, 7.0)</p></li></ul>
<p>+  xray_fields = add_xray_emissivity_field(ds, 0.5, 7.0)</p>
<pre>Additional keyword arguments are:
</pre>
<p>@@ -49,7 +49,8 @@</p>
<pre>* **constant_metallicity** (*float*): If specified, assume a constant
  metallicity for the emission from metals.  The *with_metals* keyword</pre>
<ul><li><p>must be set to False to use this.  Default: None.</p></li></ul>
<p>+   must be set to False to use this. It should be given in unit of solar metallicity. +   Default: None.</p>
<pre>The resulting fields can be used like all normal fields. The function will return the names of
the created fields in a Python list.</pre>
<p>@@ -60,7 +61,7 @@</p>
<pre>  from yt.analysis_modules.spectral_integrator.api import \
       add_xray_emissivity_field
</pre>
<ul><li><p>xray_fields = add_xray_emissivity_field(0.5, 7.0, filename="apec_emissivity.h5")</p></li></ul>
<p>+  xray_fields = add_xray_emissivity_field(ds, 0.5, 7.0, filename="apec_emissivity.h5")</p>
<pre>ds = yt.load("enzo_tiny_cosmology/DD0046/DD0046")
plot = yt.SlicePlot(ds, 'x', 'xray_luminosity_0.5_7.0_keV')</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd doc/source/analyzing/units/1)_Symbolic_Units.ipynb --- a/doc/source/analyzing/units/1)_Symbolic_Units.ipynb +++ b/doc/source/analyzing/units/1)_Symbolic_Units.ipynb @@ -155,7 +155,7 @@</p>
<pre>"outputs": [],
"source": [
 "from yt.units.yt_array import YTQuantity\n",</pre>
<ul><li><p>“from yt.utilities.physical_constants import kboltz\n”,</p></li></ul>
<p>+    “from yt.units import kboltz\n”,</p>
<pre>"from numpy.random import random\n",
"import numpy as np\n",
"\n",</pre>
<p>@@ -446,7 +446,7 @@</p>
<pre>},
"outputs": [],
"source": [</pre>
<ul><li><p>“from yt.utilities.physical_constants import G, kboltz\n”,</p></li></ul>
<p>+    “from yt.units import G, kboltz\n”,</p>
<pre>"\n",
"print (\"Newton's constant: \", G)\n",
"print (\"Newton's constant in MKS: \", G.in_mks(), \"\\n\")\n",</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd doc/source/analyzing/units/2)_Fields_and_unit_conversion.ipynb --- a/doc/source/analyzing/units/2)_Fields_and_unit_conversion.ipynb +++ b/doc/source/analyzing/units/2)_Fields_and_unit_conversion.ipynb @@ -467,7 +467,7 @@</p>
<pre>"metadata": {},
"outputs": [],
"source": [</pre>
<ul><li><p>“from yt.utilities.physical_constants import kboltz\n”,</p></li></ul>
<p>+    “from yt.units import kboltz\n”,</p>
<pre>  "kb = kboltz.to_astropy()"
 ]
},</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd doc/source/analyzing/units/6)_Unit_Equivalencies.ipynb --- a/doc/source/analyzing/units/6)_Unit_Equivalencies.ipynb +++ b/doc/source/analyzing/units/6)_Unit_Equivalencies.ipynb @@ -41,7 +41,7 @@</p>
<pre>"print (dd[\"temperature\"].to_equivalent(\"eV\", \"thermal\"))\n",
"\n",
"# Rest energy of the proton\n",</pre>
<ul><li><p>“from yt.utilities.physical_constants import mp\n”,</p></li></ul>
<p>+    “from yt.units import mp\n”,</p>
<pre> "E_p = mp.to_equivalent(\"GeV\", \"mass_energy\")\n",
 "print (E_p)"
]</pre>
<p>@@ -61,7 +61,7 @@</p>
<pre>},
"outputs": [],
"source": [</pre>
<ul><li><p>“from yt.utilities.physical_constants import clight\n”,</p></li></ul>
<p>+    “from yt.units import clight\n”,</p>
<pre>"v = 0.1*clight\n",
"g = v.to_equivalent(\"dimensionless\", \"lorentz\")\n",
"print (g)\n",</pre>
<p>@@ -166,7 +166,7 @@</p>
<pre>},
"outputs": [],
"source": [</pre>
<ul><li><p>“from yt.utilities.physical_constants import qp # the elementary charge in esu\n”,</p></li></ul>
<p>+    “from yt.units import qp # the elementary charge in esu\n”,</p>
<pre>"qp_SI = qp.to_equivalent(\"C\",\"SI\") # convert to Coulombs\n",
"print (qp)\n",
"print (qp_SI)"</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd doc/source/analyzing/units/7)_Unit_Systems.ipynb --- a/doc/source/analyzing/units/7)_Unit_Systems.ipynb +++ b/doc/source/analyzing/units/7)_Unit_Systems.ipynb @@ -324,7 +324,7 @@</p>
<pre>},
"outputs": [],
"source": [</pre>
<ul><li><p>“from yt.utilities.physical_constants import G\n”,</p></li></ul>
<p>+    “from yt.units import G\n”,</p>
<pre>  "print (G.in_base(\"mks\"))"
 ]
},</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd doc/source/cookbook/tests/test_cookbook.py --- a/doc/source/cookbook/tests/test_cookbook.py +++ b/doc/source/cookbook/tests/test_cookbook.py @@ -15,6 +15,26 @@</p>
<pre>import subprocess

</pre>
<p>+def run_with_capture(*args, **kwargs): +    sp = subprocess.Popen(*args, +                          stdout=subprocess.PIPE, +                          stderr=subprocess.PIPE, +                          **kwargs) +    out, err = sp.communicate() +    if out: +        sys.stdout.write(out.decode("UTF-8")) +    if err: +        sys.stderr.write(err.decode("UTF-8")) + +    if sp.returncode != 0: +        retstderr = " “.join(args[0]) +        retstderr += “\n\nTHIS IS THE REAL CAUSE OF THE FAILURE:\n” +        retstderr += err.decode("UTF-8”) + “\n” +        raise subprocess.CalledProcessError(sp.returncode, retstderr) + +    return sp.returncode + +</p>
<pre>PARALLEL_TEST = {"rockstar_nest.py": "3"}
BLACKLIST = ["opengl_ipython.py", "opengl_vr.py"]
</pre>
<p>@@ -37,10 +57,16 @@</p>
<pre>def check_recipe(cmd):
    '''Run single recipe'''</pre>
<ul><li><p>try:</p></li>
<li><p>subprocess.check_call(cmd)</p></li>
<li><p>result = True</p></li>
<li><p>except subprocess.CalledProcessError as e:</p></li>
<li><p>print(("Stdout output:\n", e.output))</p></li>
<li><p>result = False</p></li>
<li><p>assert result</p></li></ul>
<p>+    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, +                            stderr=subprocess.PIPE) +    out, err = proc.communicate() +    if out: +        sys.stdout.write(out.decode("utf8")) +    if err: +        sys.stderr.write(err.decode("utf8")) + +    if proc.returncode != 0: +        retstderr = " “.join(cmd) +        retstderr += “\n\nTHIS IS THE REAL CAUSE OF THE FAILURE:\n” +        retstderr += err.decode("UTF-8”) + “\n” +        raise subprocess.CalledProcessError(proc.returncode, retstderr)</p>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd doc/source/developing/creating_derived_fields.rst --- a/doc/source/developing/creating_derived_fields.rst +++ b/doc/source/developing/creating_derived_fields.rst @@ -71,9 +71,9 @@</p>
<pre>a dimensionless float or array.

If your field definition includes physical constants rather than defining a</pre>
<p>-constant as a float, you can import it from ``yt.utilities.physical_constants`` +constant as a float, you can import it from ``yt.units``</p>
<pre>to get a predefined version of the constant with the correct units. If you know</pre>
<p>-the units your data is supposed to have ahead of time, you can import unit +the units your data is supposed to have ahead of time, you can also import unit</p>
<pre>symbols like ``g`` or ``cm`` from the ``yt.units`` namespace and multiply the
return value of your field function by the appropriate combination of unit
symbols for your field's units. You can also convert floats or NumPy arrays into</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd doc/source/developing/testing.rst --- a/doc/source/developing/testing.rst +++ b/doc/source/developing/testing.rst @@ -538,7 +538,13 @@</p>
<pre>      local_pw_000:
</pre>
<p>-would regenerate answers for OWLS frontend. +would regenerate answers for OWLS frontend. + +When adding tests to an existing set of answers (like ``local_owls_000`` or ``local_varia_000``), +it is considered best practice to first submit a pull request adding the tests WITHOUT incrementing +the version number. Then, allow the tests to run (resulting in “no old answer” errors for the missing +answers). If no other failures are present, you can then increment the version number to regenerate +the answers. This way, we can avoid accidently covering up test breakages.</p>
<pre>Adding New Answer Tests
~~~~~~~~~~~~~~~~~~~~~~~</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd doc/source/installing.rst --- a/doc/source/installing.rst +++ b/doc/source/installing.rst @@ -18,26 +18,27 @@</p>
<pre>* If you do not have root access on your computer, are not comfortable managing
  python packages, or are working on a supercomputer or cluster computer, you</pre>
<ul><li><p>will probably want to use the bash all-in-one installation script.  This builds</p></li>
<li><p>Python, NumPy, Matplotlib, and yt from source to set up an isolated scientific</p></li>
<li><p>python environment inside of a single folder in your home directory. See</p></li>
<li><p>:ref:`install-script` for more details.</p></li></ul>
<p>+  will probably want to use the bash all-in-one installation script.  This +  creates a python environment using the `miniconda python +  distrubtion <<a href="http://conda.pydata.org/miniconda.html">http://conda.pydata.org/miniconda.html</a>>`_ and the +  `conda <<a href="http://conda.pydata.org/docs/">http://conda.pydata.org/docs/</a>>`_ package manager inside of a single +  folder in your home directory. See :ref:`install-script` for more details.</p>
<pre>* If you use the `Anaconda <https://store.continuum.io/cshop/anaconda/>`_ python</pre>
<ul><li><p>distribution see :ref:`anaconda-installation` for details on how to install</p></li>
<li><p>yt using the ``conda`` package manager.  Source-based installation from the</p></li>
<li><p>mercurial repository or via ``pip`` should also work under Anaconda. Note that</p></li>
<li><p>this is currently the only supported installation mechanism on Windows.</p></li></ul>
<p>+  distribution and already have ``conda`` installed, see +  :ref:`anaconda-installation` for details on how to install yt using the +  ``conda`` package manager. Note that this is currently the only supported +  installation mechanism on Windows.</p>
<p>-* If you already have a scientific python software stack installed on your</p>
<ul><li><p>computer and are comfortable installing python packages,</p></li></ul>
<p>+* If you want to build a development version of yt or are comfortable with +  compilers and know your way around python packaging,</p>
<pre>:ref:`source-installation` will probably be the best choice. If you have set
up python using a source-based package manager like `Homebrew
<http://brew.sh>`_ or `MacPorts <http://www.macports.org/>`_ this choice will</pre>
<ul><li><p>let you install yt using the python installed by the package manager. Similarly</p></li>
<li><p>for python environments set up via Linux package managers so long as you</p></li>
<li><p>have the necessary compilers installed (e.g. the ``build-essentials``</p></li>
<li><p>package on Debian and Ubuntu).</p></li></ul>
<p>+  let you install yt using the python installed by the package +  manager. Similarly, this will also work for python environments set up via +  Linux package managers so long as you have the necessary compilers installed +  (e.g. the ``build-essentials`` package on Debian and Ubuntu).</p>
<pre>.. note::
  See `Parallel Computation</pre>
<p>@@ -53,19 +54,21 @@</p>
<pre>Before you install yt, you must decide which branch (i.e. version) of the code
you prefer to use:
</pre>
<p>-* ``yt`` — The most up-to-date <strong>development</strong> version with the most current features but sometimes unstable (yt-3.x) -* ``stable`` — The latest stable release of yt-3.x -* ``yt-2.x`` — The latest stable release of yt-2.x +* ``yt`` — The most up-to-date <strong>development</strong> version with the most current +  features but sometimes unstable (the development version of the next ``yt-3.x`` +  release). +* ``stable`` — The latest stable release of ``yt-3.x``. +* ``yt-2.x`` — The last stable release of ``yt-2.x``.</p>
<p>-If this is your first time using the code, we recommend using ``stable``, -unless you specifically need some piece of brand-new functionality only -available in ``yt`` or need to run an old script developed for ``yt-2.x``. -There were major API and functionality changes made in yt after version 2.7 -in moving to version 3.0.  For a detailed description of the changes -between versions 2.x (e.g. branch ``yt-2.x``) and 3.x (e.g. branches ``yt`` and -``stable``) see :ref:`yt3differences`.  Lastly, don't feel like you're locked -into one branch when you install yt, because you can easily change the active -branch by following the instructions in :ref:`switching-between-yt-versions`. +If this is your first time using the code, we recommend using ``stable``, unless +you specifically need some piece of brand-new functionality only available in +``yt`` or need to run an old script developed for ``yt-2.x``.  There were major +API and functionality changes made in yt for version 3.0.  For a detailed +description of the changes between versions 2.x (e.g. branch ``yt-2.x``) and 3.x +(e.g. branches ``yt`` and ``stable``) see :ref:`yt3differences`.  Lastly, don't +feel like you're locked into one branch when you install yt, because you can +easily change the active branch by following the instructions in +:ref:`switching-between-yt-versions`.</p>
<pre>.. _install-script:
</pre>
<p>@@ -74,9 +77,8 @@</p>
<pre>Because installation of all of the interlocking parts necessary to install yt
itself can be time-consuming, yt provides an all-in-one installation script</pre>
<p>-which downloads and builds a fully-isolated Python + NumPy + Matplotlib + HDF5 + -Mercurial installation. Since the install script compiles yt's dependencies from -source, you must have C, C++, and optionally Fortran compilers installed. +which downloads and builds a fully-isolated installation of Python that includes +NumPy, Matplotlib, H5py, Mercurial, and yt.</p>
<pre>The install script supports UNIX-like systems, including Linux, OS X, and most
supercomputer and cluster environments. It is particularly suited for deployment</pre>
<p>@@ -94,30 +96,62 @@</p>
<pre>^^^^^^^^^^^^^^^^^^^^^^^^^^

To get the installation script for the ``stable`` branch of the code,</pre>
<p>-download it from: +download it using the following command:</p>
<pre>.. code-block:: bash
</pre>
<ul><li><p>wget <a href="http://bitbucket.org/yt_analysis/yt/raw/stable/doc/install_script.sh">http://bitbucket.org/yt_analysis/yt/raw/stable/doc/install_script.sh</a></p></li></ul>
<p>+  $ wget <a href="http://bitbucket.org/yt_analysis/yt/raw/stable/doc/install_script.sh">http://bitbucket.org/yt_analysis/yt/raw/stable/doc/install_script.sh</a></p>
<p>-If you wish to install a different version of yt (see -:ref:`above <branches-of-yt>`), replace ``stable`` with the appropriate -branch name (e.g. ``yt``, ``yt-2.x``) in the path above to get the correct -install script. – -By default, the bash install script will install an array of items, but there -are additional packages that can be downloaded and installed (e.g. SciPy, enzo, -etc.). The script has all of these options at the top of the file. You should be -able to open it and edit it without any knowledge of bash syntax.  To execute -it, run: +If you do not have ``wget``, the following should also work:</p>
<pre>.. code-block:: bash
</pre>
<ul><li><p>bash install_script.sh</p></li></ul>
<p>+  $ curl -OL <a href="http://bitbucket.org/yt_analysis/yt/raw/stable/doc/install_script.sh">http://bitbucket.org/yt_analysis/yt/raw/stable/doc/install_script.sh</a> + +If you wish to install a different version of yt (see :ref:`branches-of-yt`), +replace ``stable`` with the appropriate branch name (e.g. ``yt``, ``yt-2.x``) in +the path above to get the correct install script. + +By default, the bash install script will create a python environment based on +the `miniconda python distrubtion <<a href="http://conda.pydata.org/miniconda.html">http://conda.pydata.org/miniconda.html</a>>`_, +and will install yt's dependencies using the `conda +<<a href="http://conda.pydata.org/docs/">http://conda.pydata.org/docs/</a>>`_ package manager. To avoid needing a +compilation environment to run the install script, yt itself will also be +installed using `conda`. + +If you would like to customize your yt installation, you can edit the values of +several variables that are defined at the top of the script. + +If you would like to build yt from source, you will need to edit the install +script and set ``INST_YT_SOURCE=1`` near the top. This will clone a copy of the +yt mercurial repository and build yt form source. The default is +``INST_YT_SOURCE=0``, which installs yt from a binary conda package. + +The install script can also build python and all yt dependencies from source. To +switch to this mode, set ``INST_CONDA=0`` at the top of the install script. If +you choose this mode, you must also set ``INST_YT_SOURCE=1``. + +In addition, you can tell the install script to download and install some +additional packages --- currently these include +`PyX <<a href="http://pyx.sourceforge.net/">http://pyx.sourceforge.net/</a>>`_, the `Rockstar halo +finder <<a href="http://arxiv.org/abs/1110.4372">http://arxiv.org/abs/1110.4372</a>>`_, `SciPy <<a href="https://www.scipy.org/">https://www.scipy.org/</a>>`_, +`Astropy <<a href="http://www.astropy.org/">http://www.astropy.org/</a>>`_, and the necessary dependencies for +:ref:`unstructured mesh rendering <unstructured_mesh_rendering>`. The script has +all of the options for installing optional packages near the top of the +file. You should be able to open it and edit it without any knowledge of bash +syntax. For example, to install scipy, change ``INST_SCIPY=0`` to +``INST_SCIPY=1``. + +To execute the install script, run: + +.. code-block:: bash + +  $ bash install_script.sh</p>
<pre>Because the installer is downloading and building a variety of packages from</pre>
<p>-source, this will likely take a while (e.g. 20 minutes), but you will get -updates of its status at the command line throughout. +source, this will likely take a few minutes, especially if you have a slow +internet connection or have ``INST_CONDA=0`` set. You will get updates of its +status at the command prompt throughout.</p>
<pre>If you receive errors during this process, the installer will provide you
with a large amount of information to assist in debugging your problems.  The</pre>
<p>@@ -127,26 +161,63 @@</p>
<pre>potentially figure out what went wrong.  If you have problems, though, do not
hesitate to :ref:`contact us <asking-for-help>` for assistance.
</pre>
<p>+If the install script errors out with a message about being unable to import the +python SSL bindings, this means that the Python built by the install script was +unable to link against the OpenSSL library. This likely means that you installed +with ``INST_CONDA=0`` on a recent version of OSX, or on a cluster that has a +very out of date installation of OpenSSL. In both of these cases you will either +need to install OpenSSL yourself from the system package manager or consider +using ``INST_CONDA=1``, since conda-based installs can install the conda package +for OpenSSL. +</p>
<pre>.. _activating-yt:

Activating Your Installation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Once the installation has completed, there will be instructions on how to set up</pre>
<p>-your shell environment to use yt by executing the activate script.  You must -run this script in order to have yt properly recognized by your system.  You can -either add it to your login script, or you must execute it in each shell session -prior to working with yt. +your shell environment to use yt. + +Activating Conda-based installs (``INST_CONDA=1``) +"""""""""""""""""""""""""""""""""""""""""""""""""" + +For conda-based installs, you will need to ensure that the installation's +``yt-conda/bin`` directory is prepended to your ``PATH`` environment variable. + +For Bash-style shells, you can use the following command in a terminal session +to temporarily activate the yt installation:</p>
<pre>.. code-block:: bash
</pre>
<ul><li><p>source <yt installation directory>/bin/activate</p></li></ul>
<p>+  $ export PATH=/path/to/yt-conda/bin:$PATH + +and on csh-style shells: + +.. code-block:: csh + +  $ setenv PATH /path/to/yt-conda/bin:$PATH + +If you would like to permanently activate yt, you can also update the init file +appropriate for your shell and OS (e.g. .bashrc, .bash_profile, .cshrc, .zshrc) +to include the same command. + +Activating source-based installs (``INST_CONDA=0``) +""""""""""""""""""""""""""""""""""""""""""""""""""" + +For this installation method, you must run an ``activate`` script to activate +the yt environment in a terminal session. You must run this script in order to +have yt properly recognized by your system.  You can either add it to your login +script, or you must execute it in each shell session prior to working with yt. + +.. code-block:: bash + +  $ source <yt installation directory>/bin/activate</p>
<pre>If you use csh or tcsh as your shell, activate that version of the script:

.. code-block:: bash
</pre>
<ul><li><p>source <yt installation directory>/bin/activate.csh</p></li></ul>
<p>+  $ source <yt installation directory>/bin/activate.csh</p>
<pre>If you don't like executing outside scripts on your computer, you can set
the shell variables manually.  ``YT_DEST`` needs to point to the root of the</pre>
<p>@@ -166,14 +237,21 @@</p>
<pre>.. code-block:: bash
</pre>
<ul><li><p>yt update</p></li></ul>
<p>+  $ yt update</p>
<p>-Additionally, if you want to make sure you have the latest dependencies -associated with yt and update the codebase simultaneously, type this: +Additionally, if you ran the install script with ``INST_CONDA=0`` and want to +make sure you have the latest dependencies associated with yt and update the +codebase simultaneously, type this:</p>
<pre>.. code-block:: bash
</pre>
<ul><li><p>yt update --all</p></li></ul>
<p>+  $ yt update --all + +If you ran the install script with ``INST_CONDA=1`` and want to update your dependencies, run: + +.. code-block:: bash + +  $ conda update --all</p>
<pre>.. _removing-yt:
</pre>
<p>@@ -192,35 +270,26 @@</p>
<pre>Installing yt Using Anaconda
++++++++++++++++++++++++++++
</pre>
<p>-Perhaps the quickest way to get yt up and running is to install it using the -`Anaconda Python Distribution <<a href="https://store.continuum.io/cshop/anaconda/">https://store.continuum.io/cshop/anaconda/</a>>`_, -which will provide you with a easy-to-use environment for installing Python -packages. – -If you do not want to install the full anaconda python distribution, you can -install a bare-bones Python installation using miniconda.  To install miniconda, -visit <a href="http://repo.continuum.io/miniconda/">http://repo.continuum.io/miniconda/</a> and download ``Miniconda-latest-…`` -script for your platform and system architecture. Next, run the script, e.g.: – -.. code-block:: bash –</p>
<ul><li><p>bash Miniconda-latest-Linux-x86_64.sh</p></li></ul>
<p>–</p>
<pre>For both the Anaconda and Miniconda installations, make sure that the Anaconda
``bin`` directory is in your path, and then issue:

.. code-block:: bash
</pre>
<ul><li><p>conda install yt</p></li></ul>
<p>+  $ conda install yt</p>
<pre>which will install stable branch of yt along with all of its dependencies.
</pre>
<p>+.. _nightly-conda-builds: + +Nightly Conda Builds +^^^^^^^^^^^^^^^^^^^^ +</p>
<pre>If you would like to install latest development version of yt, you can download
it from our custom anaconda channel:

.. code-block:: bash
</pre>
<ul><li><p>conda install -c <a href="http://use.yt/with_conda/">http://use.yt/with_conda/</a> yt</p></li></ul>
<p>+  $ conda install -c <a href="http://use.yt/with_conda/">http://use.yt/with_conda/</a> yt</p>
<pre>New packages for development branch are built after every pull request is
merged. In order to make sure you are running latest version, it's recommended</pre>
<p>@@ -228,28 +297,26 @@</p>
<pre>.. code-block:: bash
</pre>
<ul><li><p>conda update -c <a href="http://use.yt/with_conda/">http://use.yt/with_conda/</a> yt</p></li></ul>
<p>+  $ conda update -c <a href="http://use.yt/with_conda/">http://use.yt/with_conda/</a> yt</p>
<pre>Location of our channel can be added to ``.condarc`` to avoid retyping it during
each *conda* invocation. Please refer to `Conda Manual
<http://conda.pydata.org/docs/config.html#channel-locations-channels>`_ for
detailed instructions.
</pre>
<p>+.. _conda-source-build:</p>
<p>-Obtaining Source Code -^^^^^^^^^^^^^^^^^^^^^ +Building yt from Source For Conda-based Installs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^</p>
<p>-There are two ways to get the yt source code when using an Anaconda -installation. – -Option 1: – -Ensure that you have all build dependencies installed in your current +First, ensure that you have all build dependencies installed in your current</p>
<pre>conda environment:

.. code-block:: bash
</pre>
<ul><li><p>conda install cython mercurial sympy ipython h5py matplotlib</p></li></ul>
<p>+  $ conda install cython mercurial sympy ipython matplotlib + +In addition, you will need a C compiler installed.</p>
<pre>.. note::
  </pre>
<p>@@ -260,87 +327,124 @@</p>
<pre>  .. code-block:: bash
</pre>
<ul><li><p>export CONDA_DIR=$(python -c ‘import sys; print(sys.executable.split("/bin/python")[0])’)</p></li>
<li><p>conda create -y -n py27 python=2.7 mercurial</p></li>
<li><p>ln -s ${CONDA_DIR}/envs/py27/bin/hg ${CONDA_DIR}/bin</p></li></ul>
<p>+   $ export CONDA_DIR=$(python -c ‘import sys; print(sys.executable.split("/bin/python")[0])’) +   $ conda create -y -n py27 python=2.7 mercurial +   $ ln -s ${CONDA_DIR}/envs/py27/bin/hg ${CONDA_DIR}/bin</p>
<pre>Clone the yt repository with:

.. code-block:: bash
</pre>
<ul><li><p>hg clone <a href="https://bitbucket.org/yt_analysis/yt">https://bitbucket.org/yt_analysis/yt</a></p></li></ul>
<p>+  $ hg clone <a href="https://bitbucket.org/yt_analysis/yt">https://bitbucket.org/yt_analysis/yt</a></p>
<pre>Once inside the yt directory, update to the appropriate branch and</pre>
<p>-run ``setup.py``. For example, the following commands will allow you +run ``setup.py develop``. For example, the following commands will allow you</p>
<pre>to see the tip of the development branch.

.. code-block:: bash
</pre>
<ul><li><p>hg up yt</p></li>
<li><p>python setup.py develop</p></li></ul>
<p>+  $ hg pull +  $ hg update yt +  $ python setup.py develop</p>
<pre>This will make sure you are running a version of yt corresponding to the
most up-to-date source code.
</pre>
<p>-Option 2: +.. _rockstar-conda:</p>
<p>-Recipes to build conda packages for yt are available at -<a href="https://github.com/conda/conda-recipes">https://github.com/conda/conda-recipes</a>.  To build the yt conda recipe, first -clone the conda-recipes repository +Rockstar Halo Finder for Conda-based installations +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The easiest way to set rockstar up in a conda-based python envrionment is to run +the install script with both ``INST_CONDA=1`` and ``INST_ROCKSTAR=1``. + +If you want to do this manually, you will need to follow these +instructions. First, clone Matt Turk's fork of rockstar and compile it:</p>
<pre>.. code-block:: bash
</pre>
<ul><li><p>git clone <a href="https://github.com/conda/conda-recipes">https://github.com/conda/conda-recipes</a></p></li></ul>
<p>+  $ hg clone <a href="https://bitbucket.org/MatthewTurk/rockstar">https://bitbucket.org/MatthewTurk/rockstar</a> +  $ cd rockstar +  $ make lib</p>
<p>-Then navigate to the repository root and invoke ``conda build``: +Next, copy `librockstar.so` into the `lib` folder of your anaconda installation:</p>
<pre>.. code-block:: bash
</pre>
<ul><li><p>cd conda-recipes</p></li>
<li><p>conda build ./yt/</p></li></ul>
<p>+  $ cp librockstar.so /path/to/anaconda/lib</p>
<p>-Note that building a yt conda package requires a C compiler. +Finally, you will need to recompile yt to enable the rockstar interface. Clone a +copy of the yt mercurial repository (see :ref:`conda-source-build`), or navigate +to a clone that you have already made, and do the following: + +.. code-block:: bash + +  $ cd /path/to/yt-hg +  $ ./clean.sh +  $ echo /path/to/rockstar > rockstar.cfg +  $ python setup.py develop + +Here ``/path/to/yt-hg`` is the path to your clone of the yt mercurial repository +and ``/path/to/rockstar`` is the path to your clone of Matt Turk's fork of +rockstar. + +Finally, to actually use rockstar, you will need to ensure the folder containing +`librockstar.so` is in your LD_LIBRARY_PATH: + +.. code-block:: bash + +  $ export LD_LIBRARY_PATH=/path/to/anaconda/lib + +You should now be able to enter a python session and import the rockstar +interface: + +.. code-block:: python + +  >>> from yt.analysis_modules.halo_finding.rockstar import rockstar_interface + +If this python import fails, then you have not installed rockstar and yt's +rockstar interface correctly.</p>
<pre>.. _windows-installation:

Installing yt on Windows
^^^^^^^^^^^^^^^^^^^^^^^^
</pre>
<p>-Installation on 64-bit Microsoft Windows platforms is supported using Anaconda (see -:ref:`anaconda-installation`). Also see :ref:`windows-developing` for details on how to build yt -from source in Windows. +Installation on 64-bit Microsoft Windows platforms is supported using Anaconda +(see :ref:`anaconda-installation`). Also see :ref:`windows-developing` for +details on how to build yt from source in Windows.</p>
<pre>.. _source-installation:
</pre>
<p>-Installing yt Using pip or from Source -++++++++++++++++++++++++++++++++++++++ +Installing yt Using ``pip`` or From Source +++++++++++++++++++++++++++++++++++++++++++ + +.. note:: + +  If you wish to install yt from source in a conda-based installation of yt, +  see :ref:`conda-source-build`.</p>
<pre>To install yt from source, you must make sure you have yt's dependencies</pre>
<p>-installed on your system. +installed on your system. Right now, the dependencies to build yt from +source include:</p>
<p>-If you use a Linux OS, use your distro's package manager to install these yt -dependencies on your system: +- ``mercurial`` +- A C compiler such as ``gcc`` or ``clang`` +- ``Python 2.7``, ``Python 3.4``, or ``Python 3.5``</p>
<p>— ``HDF5`` — ``zeromq`` — ``sqlite`` — ``mercurial`` – -Then install the required Python packages with ``pip``: +In addition, building yt from source requires several python packages +which can be installed with ``pip``:</p>
<pre>.. code-block:: bash
</pre>
<ul><li><p>$ pip install numpy matplotlib cython h5py nose sympy</p></li></ul>
<p>+  $ pip install numpy matplotlib cython sympy</p>
<p>-If you're using IPython notebooks, you can install its dependencies -with ``pip`` as well: +You may also want to install some of yt's optional dependencies, including +``jupyter``, ``h5py`` (which in turn depends on the HDF5 library), ``scipy``, or +``astropy``,</p>
<p>-.. code-block:: bash –</p>
<ul><li><p>$ pip install ipython[notebook]</p></li></ul>
<p>– -From here, you can use ``pip`` (which comes with ``Python``) to install the latest -stable version of yt: +From here, you can use ``pip`` (which comes with ``Python``) to install the +latest stable version of yt:</p>
<pre>.. code-block:: bash
</pre>
<p>@@ -353,46 +457,30 @@</p>
<pre>.. code-block:: bash
</pre>
<ul><li><p>hg clone <a href="https://bitbucket.org/yt_analysis/yt">https://bitbucket.org/yt_analysis/yt</a></p></li>
<li><p>cd yt</p></li>
<li><p>hg update yt</p></li>
<li><p>python setup.py install --user --prefix=</p></li></ul>
<p>+  $ hg clone <a href="https://bitbucket.org/yt_analysis/yt">https://bitbucket.org/yt_analysis/yt</a> +  $ cd yt +  $ hg update yt +  $ python setup.py install --user --prefix=</p>
<pre>.. note::
</pre>
<ul><li><p>If you maintain your own user-level python installation separate from the OS-level python</p></li>
<li><p>installation, you can leave off ``--user --prefix=``, although you might need</p></li>
<li><p>``sudo`` depending on where python is installed. See `This StackOverflow</p></li>
<li><p>discussion</p></li></ul>
<p>+  If you maintain your own user-level python installation separate from the +  OS-level python installation, you can leave off ``--user --prefix=``, although +  you might need ``sudo`` depending on where python is installed. See `This +  StackOverflow discussion</p>
<pre>  <http://stackoverflow.com/questions/4495120/combine-user-with-prefix-error-with-setup-py-install>`_
  if you are curious why ``--prefix=`` is neccessary on some systems.
</pre>
<p>-.. note:: –</p>
<ul><li><p>yt requires version 18.0 or higher of ``setuptools``. If you see</p></li>
<li><p>error messages about this package, you may need to update it. For</p></li>
<li><p>example, with pip via</p></li></ul>
<p>–</p>
<ul><li><p>.. code-block:: bash</p></li></ul>
<p>–</p>
<ul><li><p>pip install --upgrade setuptools</p></li></ul>
<p>–</p>
<ul><li><p>or your preferred method. If you have ``distribute`` installed, you</p></li>
<li><p>may also see error messages for it if it's out of date. You can</p></li>
<li><p>update with pip via</p></li></ul>
<p>–</p>
<ul><li><p>.. code-block:: bash</p></li></ul>
<p>–</p>
<ul><li><p>pip install --upgrade distribute</p></li></ul>
<p>–</p>
<ul><li><p>or via your preferred method.</p></li></ul>
<p>– –</p>
<pre>This will install yt into a folder in your home directory
(``$HOME/.local/lib64/python2.7/site-packages`` on Linux,
``$HOME/Library/Python/2.7/lib/python/site-packages/`` on OSX) Please refer to
the ``setuptools`` documentation for the additional options.
</pre>
<p>+If you are unable to locate the ``yt`` executable (i.e. ``yt version`` failes), +then you likely need to add the ``$HOME/.local/bin`` (or the equivalent on your +OS) to your PATH. Some linux distributions do not include this directory in the +default search path. +</p>
<pre>If you choose this installation method, you do not need to run any activation
script since this will install yt into your global python environment.
</pre>
<p>@@ -401,15 +489,35 @@</p>
<pre>.. code-block:: bash
</pre>
<ul><li><p>hg clone <a href="https://bitbucket.org/yt_analysis/yt">https://bitbucket.org/yt_analysis/yt</a></p></li>
<li><p>cd yt</p></li>
<li><p>hg update yt</p></li>
<li><p>python setup.py develop --user --prefix=</p></li></ul>
<p>+  $ hg clone <a href="https://bitbucket.org/yt_analysis/yt">https://bitbucket.org/yt_analysis/yt</a> +  $ cd yt +  $ hg update yt +  $ python setup.py develop --user --prefix=</p>
<pre>As above, you can leave off ``--user --prefix=`` if you want to install yt into the default
package install path.  If you do not have write access for this location, you
might need to use ``sudo``.
</pre>
<p>+Build errors with ``setuptools`` or ``distribute`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Building yt requires version 18.0 or higher of ``setuptools``. If you see error +messages about this package, you may need to update it. For example, with pip +via + +.. code-block:: bash + +  $ pip install --upgrade setuptools + +or your preferred method. If you have ``distribute`` installed, you may also see +error messages for it if it's out of date. You can update with pip via + +.. code-block:: bash + +  $ pip install --upgrade distribute + +or via your preferred method. +</p>
<pre>Keeping yt Updated via Mercurial
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
</pre>
<p>@@ -424,7 +532,7 @@</p>
<pre>.. code-block:: bash
</pre>
<ul><li><p>yt update</p></li></ul>
<p>+  $ yt update</p>
<pre>This will detect that you have installed yt from the mercurial repository, pull
any changes from Bitbucket, and then recompile yt if necessary.</pre>
<p>@@ -439,7 +547,7 @@</p>
<pre>.. code-block:: bash
</pre>
<ul><li><p>yt --help</p></li></ul>
<p>+  $ yt --help</p>
<pre>If this works, you should get a list of the various command-line options for
yt, which means you have successfully installed yt.  Congratulations!</pre>
<p>@@ -453,21 +561,57 @@</p>
<pre>.. _switching-between-yt-versions:
</pre>
<p>-Switching versions of yt: yt-2.x, yt-3.x, stable, and dev ---------------------------------------------------------- +Switching versions of yt: ``yt-2.x``, ``stable``, and ``yt`` branches +---------------------------------------------------------------------</p>
<p>-With the release of version 3.0 of yt, development of the legacy yt 2.x series -has been relegated to bugfixes.  That said, we will continue supporting the 2.x -series for the foreseeable future.  This makes it easy to use scripts written -for older versions of yt without substantially updating them to support the -new field naming or unit systems in yt version 3. +Here we explain how to switch between different development branches of yt.</p>
<p>-Currently, the yt-2.x codebase is contained in a named branch in the yt -mercurial repository.  Thus, depending on the method you used to install -yt, there are different instructions for switching versions. +If You Installed yt Using the Bash Install Script ++++++++++++++++++++++++++++++++++++++++++++++++++</p>
<p>-If You Installed yt Using the Installer Script -++++++++++++++++++++++++++++++++++++++++++++++ +The instructions for how to switch between branches depend on whether you ran +the install script with ``INST_YT_SOURCE=0`` (the default) or +``INST_YT_SOURCE=1``. You can determine which option you used by inspecting the +output: + +.. code-block:: bash + +  $ yt version + +If the output from this command looks like: + +.. code-block:: none + +  The current version and changeset for the code is: + +  --- +  Version = 3.2.3 +  --- + +i.e. it does not refer to a specific changeset hash, then you originally chose +``INST_YT_SOURCE=0``. + +On the other hand, if the output from ``yt version`` looks like: + +.. code-block:: none + +  The current version and changeset for the code is: + +  --- +  Version = 3.3-dev +  Changeset = d8eec89b2c86 (yt) tip +  --- + +i.e. it refers to a specific changeset in the yt mercurial repository, then +you installed using ``INST_YT_SOURCE=1``. + +Conda-based installs (``INST_YT_SOURCE=0``) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In this case you can either install one of the nightly conda builds (see :ref:`nightly-conda-builds`), or you can follow the instructions above to build yt from source under conda (see :ref:`conda-source-build`). + +Source-based installs (``INST_YT_SOURCE=1``) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^</p>
<pre>You already have the mercurial repository, so you simply need to switch
which version you're using.  Navigate to the root of the yt mercurial</pre>
<p>@@ -476,9 +620,9 @@</p>
<pre>.. code-block:: bash
</pre>
<ul><li><p>cd yt-<machine>/src/yt-hg</p></li>
<li><p>hg update <desired-version></p></li>
<li><p>python setup.py develop</p></li></ul>
<p>+  $ cd yt-<machine>/src/yt-hg +  $ hg update <desired-version> +  $ python setup.py develop</p>
<pre>Valid versions to jump to are described in :ref:`branches-of-yt`.
</pre>
<p>@@ -494,8 +638,8 @@</p>
<pre>.. code-block:: bash
</pre>
<ul><li><p>pip uninstall yt</p></li>
<li><p>hg clone <a href="https://bitbucket.org/yt_analysis/yt">https://bitbucket.org/yt_analysis/yt</a></p></li></ul>
<p>+  $ pip uninstall yt +  $ hg clone <a href="https://bitbucket.org/yt_analysis/yt">https://bitbucket.org/yt_analysis/yt</a></p>
<pre>Now, to switch between versions, you need to navigate to the root of
the mercurial yt repository. Use mercurial to</pre>
<p>@@ -503,9 +647,9 @@</p>
<pre>.. code-block:: bash
</pre>
<ul><li><p>cd yt</p></li>
<li><p>hg update <desired-version></p></li>
<li><p>python setup.py install --user --prefix=</p></li></ul>
<p>+  $ cd yt +  $ hg update <desired-version> +  $ python setup.py install --user --prefix=</p>
<pre>Valid versions to jump to are described in :ref:`branches-of-yt`).
</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd setup.cfg --- a/setup.cfg +++ b/setup.cfg @@ -10,10 +10,10 @@</p>
<pre>[flake8]
# we exclude:</pre>
<p>-#      api.py and __init__.py files to avoid spurious unused import errors -#      _mpl_imports.py for the same reason +#      api.py, mods.py, _mpl_imports.py, and __init__.py files to avoid spurious +#      unused import errors</p>
<pre>#      autogenerated __config__.py files
#      vendored libraries</pre>
<p>-exclude = */api.py,*/__init__.py,*/__config__.py,yt/visualization/_mpl_imports.py,yt/utilities/lodgeit.py,yt/utilities/poster/*,yt/extern/*,yt/mods.py +exclude = */api.py,*/__init__.py,*/__config__.py,yt/visualization/_mpl_imports.py,yt/utilities/lodgeit.py,yt/utilities/lru_cache.py,yt/utilities/poster/*,yt/extern/*,yt/mods.py</p>
<pre>max-line-length=999
ignore = E111,E121,E122,E123,E124,E125,E126,E127,E128,E129,E131,E201,E202,E211,E221,E222,E227,E228,E241,E301,E203,E225,E226,E231,E251,E261,E262,E265,E266,E302,E303,E402,E502,E701,E703,E731,W291,W292,W293,W391,W503</pre>
<p>\ No newline at end of file</p>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd yt/analysis_modules/absorption_spectrum/absorption_spectrum.py --- a/yt/analysis_modules/absorption_spectrum/absorption_spectrum.py +++ b/yt/analysis_modules/absorption_spectrum/absorption_spectrum.py @@ -394,7 +394,8 @@</p>
<pre>#    10; this will assure we don't get spikes in the deposited
#    spectra from uneven numbers of vbins per bin
resolution = thermal_width / self.bin_width</pre>
<ul><li><p>n_vbins_per_bin = 10**(np.ceil(np.log10(subgrid_resolution/resolution)).clip(0, np.inf))</p></li></ul>
<p>+            n_vbins_per_bin = (10 ** (np.ceil( np.log10( subgrid_resolution / +                               resolution) ).clip(0, np.inf) ) ).astype('int')</p>
<pre>            vbin_width = self.bin_width.d / n_vbins_per_bin

            # a note to the user about which lines components are unresolved</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd yt/analysis_modules/spectral_integrator/spectral_frequency_integrator.py --- a/yt/analysis_modules/spectral_integrator/spectral_frequency_integrator.py +++ b/yt/analysis_modules/spectral_integrator/spectral_frequency_integrator.py @@ -176,7 +176,7 @@</p>
<pre>constant_metallicity: float, optional
    If specified, assume a constant metallicity for the emission
    from metals.  The *with_metals* keyword must be set to False</pre>
<ul><li><p>to use this.</p></li></ul>
<p>+        to use this. It should be given in unit of solar metallicity.</p>
<pre>        Default: None.

    This will create three fields:</pre>
<p>@@ -245,7 +245,7 @@</p>
<pre>emiss_name = "xray_emissivity_%s_%s_keV" % (e_min, e_max)
ds.add_field(("gas", emiss_name), function=_emissivity_field,</pre>
<ul><li><p>display_name=r"\epsilon_{X}\ (%s-%s\ keV)" % (e_min, e_max),</p></li></ul>
<p>+                 display_name=r"\epsilon_{X} (%s-%s keV)" % (e_min, e_max),</p>
<pre>                 units="erg/cm**3/s")

    def _luminosity_field(field, data):</pre>
<p>@@ -253,7 +253,7 @@</p>
<pre>lum_name = "xray_luminosity_%s_%s_keV" % (e_min, e_max)
ds.add_field(("gas", lum_name), function=_luminosity_field,</pre>
<ul><li><p>display_name=r"\rm{L}_{X}\ (%s-%s\ keV)" % (e_min, e_max),</p></li></ul>
<p>+                 display_name=r"\rm{L}_{X} (%s-%s keV)" % (e_min, e_max),</p>
<pre>                 units="erg/s")

    def _photon_emissivity_field(field, data):</pre>
<p>@@ -273,7 +273,7 @@</p>
<pre>phot_name = "xray_photon_emissivity_%s_%s_keV" % (e_min, e_max)
ds.add_field(("gas", phot_name), function=_photon_emissivity_field,</pre>
<ul><li><p>display_name=r"\epsilon_{X}\ (%s-%s\ keV)" % (e_min, e_max),</p></li></ul>
<p>+                 display_name=r"\epsilon_{X} (%s-%s keV)" % (e_min, e_max),</p>
<pre>                 units="photons/cm**3/s")

    return emiss_name, lum_name, phot_name</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd yt/extern/functools32.py --- a/yt/extern/functools32.py +++ /dev/null @@ -1,423 +0,0 @@ -"""functools.py – Tools for working with functions and callable objects -""" -# Python module wrapper for <em>functools C module -# to allow utilities written in Python to be added -# to the functools module. -# Written by Nick Coghlan <ncoghlan at gmail.com> -# and Raymond Hettinger <python at rcn.com> -#   Copyright © 2006-2010 Python Software Foundation. -# See C source code for <em>functools credits/copyright – -__all</em></em> = ['update_wrapper', ‘wraps’, ‘WRAPPER_ASSIGNMENTS’, ‘WRAPPER_UPDATES’,</p>
<ul><li><p>‘total_ordering’, ‘cmp_to_key’, ‘lru_cache’, ‘reduce’, ‘partial’]</p></li></ul>
<p>– -from _functools import partial, reduce -from collections import MutableMapping, namedtuple -from .reprlib32 import recursive_repr as _recursive_repr -from weakref import proxy as _proxy -import sys as _sys -try:</p>
<ul><li><p>from _thread import allocate_lock as Lock</p></li></ul>
<p>-except:</p>
<ul><li><p>from ._dummy_thread32 import allocate_lock as Lock</p></li></ul>
<p>– -################################################################################ -### OrderedDict -################################################################################ – -class _Link(object):</p>
<ul><li><p><em>_slots</em>_ = ‘prev’, ‘next’, ‘key’, ‘__weakref__’</p></li></ul>
<p>– -class OrderedDict(dict):</p>
<ul><li><p>‘Dictionary that remembers insertion order’</p></li>
<li><p># An inherited dict maps keys to values.</p></li>
<li><p># The inherited dict provides <em>_getitem_</em>, <em>_len_</em>, <em>_contains_</em>, and get.</p></li>
<li><p># The remaining methods are order-aware.</p></li>
<li><p># Big-O running times for all methods are the same as regular dictionaries.</p></li></ul>
<p>–</p>
<ul><li><p># The internal self.__map dict maps keys to links in a doubly linked list.</p></li>
<li><p># The circular doubly linked list starts and ends with a sentinel element.</p></li>
<li><p># The sentinel element never gets deleted (this simplifies the algorithm).</p></li>
<li><p># The sentinel is in self.__hardroot with a weakref proxy in self.__root.</p></li>
<li><p># The prev links are weakref proxies (to prevent circular references).</p></li>
<li><p># Individual links are kept alive by the hard reference in self.__map.</p></li>
<li><p># Those hard references disappear when a key is deleted from an OrderedDict.</p></li></ul>
<p>–</p>
<ul><li><p>def __init__(self, *args, **kwds):</p></li>
<li><p>'''Initialize an ordered dictionary.  The signature is the same as</p></li>
<li><p>regular dictionaries, but keyword arguments are not recommended because</p></li>
<li><p>their insertion order is arbitrary.</p></li></ul>
<p>–</p>
<ul><li><p>'''</p></li>
<li><p>if len(args) > 1:</p></li>
<li><p>raise TypeError('expected at most 1 arguments, got %d' % len(args))</p></li>
<li><p>try:</p></li>
<li><p>self.__root</p></li>
<li><p>except AttributeError:</p></li>
<li><p>self.__hardroot = _Link()</p></li>
<li><p>self.__root = root = _proxy(self.__hardroot)</p></li>
<li><p>root.prev = root.next = root</p></li>
<li><p>self.__map = {}</p></li>
<li><p>self.__update(*args, **kwds)</p></li></ul>
<p>–</p>
<ul><li><p>def __setitem__(self, key, value,</p></li>
<li><p>dict_setitem=dict.__setitem__, proxy=_proxy, Link=_Link):</p></li>
<li><p>‘od.__setitem__(i, y) <==> od[i]=y’</p></li>
<li><p># Setting a new item creates a new link at the end of the linked list,</p></li>
<li><p># and the inherited dictionary is updated with the new key/value pair.</p></li>
<li><p>if key not in self:</p></li>
<li><p>self.__map[key] = link = Link()</p></li>
<li><p>root = self.__root</p></li>
<li><p>last = root.prev</p></li>
<li><p>link.prev, link.next, link.key = last, root, key</p></li>
<li><p>last.next = link</p></li>
<li><p>root.prev = proxy(link)</p></li>
<li><p>dict_setitem(self, key, value)</p></li></ul>
<p>–</p>
<ul><li><p>def __delitem__(self, key, dict_delitem=dict.__delitem__):</p></li>
<li><p>‘od.__delitem__(y) <==> del od[y]’</p></li>
<li><p># Deleting an existing item uses self.__map to find the link which gets</p></li>
<li><p># removed by updating the links in the predecessor and successor nodes.</p></li>
<li><p>dict_delitem(self, key)</p></li>
<li><p>link = self.__map.pop(key)</p></li>
<li><p>link_prev = link.prev</p></li>
<li><p>link_next = link.next</p></li>
<li><p>link_prev.next = link_next</p></li>
<li><p>link_next.prev = link_prev</p></li></ul>
<p>–</p>
<ul><li><p>def __iter__(self):</p></li>
<li><p>‘od.__iter__() <==> iter(od)’</p></li>
<li><p># Traverse the linked list in order.</p></li>
<li><p>root = self.__root</p></li>
<li><p>curr = root.next</p></li>
<li><p>while curr is not root:</p></li>
<li><p>yield curr.key</p></li>
<li><p>curr = curr.next</p></li></ul>
<p>–</p>
<ul><li><p>def __reversed__(self):</p></li>
<li><p>‘od.__reversed__() <==> reversed(od)’</p></li>
<li><p># Traverse the linked list in reverse order.</p></li>
<li><p>root = self.__root</p></li>
<li><p>curr = root.prev</p></li>
<li><p>while curr is not root:</p></li>
<li><p>yield curr.key</p></li>
<li><p>curr = curr.prev</p></li></ul>
<p>–</p>
<ul><li><p>def clear(self):</p></li>
<li><p>‘od.clear() -> None.  Remove all items from od.’</p></li>
<li><p>root = self.__root</p></li>
<li><p>root.prev = root.next = root</p></li>
<li><p>self.__map.clear()</p></li>
<li><p>dict.clear(self)</p></li></ul>
<p>–</p>
<ul><li><p>def popitem(self, last=True):</p></li>
<li><p>'''od.popitem() -> (k, v), return and remove a (key, value) pair.</p></li>
<li><p>Pairs are returned in LIFO order if last is true or FIFO order if false.</p></li></ul>
<p>–</p>
<ul><li><p>'''</p></li>
<li><p>if not self:</p></li>
<li><p>raise KeyError('dictionary is empty')</p></li>
<li><p>root = self.__root</p></li>
<li><p>if last:</p></li>
<li><p>link = root.prev</p></li>
<li><p>link_prev = link.prev</p></li>
<li><p>link_prev.next = root</p></li>
<li><p>root.prev = link_prev</p></li>
<li><p>else:</p></li>
<li><p>link = root.next</p></li>
<li><p>link_next = link.next</p></li>
<li><p>root.next = link_next</p></li>
<li><p>link_next.prev = root</p></li>
<li><p>key = link.key</p></li>
<li><p>del self.__map[key]</p></li>
<li><p>value = dict.pop(self, key)</p></li>
<li><p>return key, value</p></li></ul>
<p>–</p>
<ul><li><p>def move_to_end(self, key, last=True):</p></li>
<li><p>'''Move an existing element to the end (or beginning if last==False).</p></li></ul>
<p>–</p>
<ul><li><p>Raises KeyError if the element does not exist.</p></li>
<li><p>When last=True, acts like a fast version of self[key]=self.pop(key).</p></li></ul>
<p>–</p>
<ul><li><p>'''</p></li>
<li><p>link = self.__map[key]</p></li>
<li><p>link_prev = link.prev</p></li>
<li><p>link_next = link.next</p></li>
<li><p>link_prev.next = link_next</p></li>
<li><p>link_next.prev = link_prev</p></li>
<li><p>root = self.__root</p></li>
<li><p>if last:</p></li>
<li><p>last = root.prev</p></li>
<li><p>link.prev = last</p></li>
<li><p>link.next = root</p></li>
<li><p>last.next = root.prev = link</p></li>
<li><p>else:</p></li>
<li><p>first = root.next</p></li>
<li><p>link.prev = root</p></li>
<li><p>link.next = first</p></li>
<li><p>root.next = first.prev = link</p></li></ul>
<p>–</p>
<ul><li><p>def __sizeof__(self):</p></li>
<li><p>sizeof = _sys.getsizeof</p></li>
<li><p>n = len(self) + 1                       # number of links including root</p></li>
<li><p>size = sizeof(self.__dict__)            # instance dictionary</p></li>
<li><p>size += sizeof(self.__map) * 2          # internal dict and inherited dict</p></li>
<li><p>size += sizeof(self.__hardroot) * n     # link objects</p></li>
<li><p>size += sizeof(self.__root) * n         # proxy objects</p></li>
<li><p>return size</p></li></ul>
<p>–</p>
<ul><li><p>update = __update = MutableMapping.update</p></li>
<li><p>keys = MutableMapping.keys</p></li>
<li><p>values = MutableMapping.values</p></li>
<li><p>items = MutableMapping.items</p></li>
<li><p><em>_ne</em>_ = MutableMapping.__ne__</p></li></ul>
<p>–</p>
<ul><li><p>__marker = object()</p></li></ul>
<p>–</p>
<ul><li><p>def pop(self, key, default=__marker):</p></li>
<li><p>'''od.pop(k[,d]) -> v, remove specified key and return the corresponding</p></li>
<li><p>value.  If key is not found, d is returned if given, otherwise KeyError</p></li>
<li><p>is raised.</p></li></ul>
<p>–</p>
<ul><li><p>'''</p></li>
<li><p>if key in self:</p></li>
<li><p>result = self[key]</p></li>
<li><p>del self[key]</p></li>
<li><p>return result</p></li>
<li><p>if default is self.__marker:</p></li>
<li><p>raise KeyError(key)</p></li>
<li><p>return default</p></li></ul>
<p>–</p>
<ul><li><p>def setdefault(self, key, default=None):</p></li>
<li><p>‘od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od’</p></li>
<li><p>if key in self:</p></li>
<li><p>return self[key]</p></li>
<li><p>self[key] = default</p></li>
<li><p>return default</p></li></ul>
<p>–</p>
<ul><li><p>@_recursive_repr()</p></li>
<li><p>def __repr__(self):</p></li>
<li><p>‘od.__repr__() <==> repr(od)’</p></li>
<li><p>if not self:</p></li>
<li><p>return ‘%s()’ % (self.__class__.__name__,)</p></li>
<li><p>return ‘%s(%r)’ % (self.__class__.__name__, list(self.items()))</p></li></ul>
<p>–</p>
<ul><li><p>def __reduce__(self):</p></li>
<li><p>‘Return state information for pickling’</p></li>
<li><p>items = [[k, self[k]] for k in self]</p></li>
<li><p>inst_dict = vars(self).copy()</p></li>
<li><p>for k in vars(OrderedDict()):</p></li>
<li><p>inst_dict.pop(k, None)</p></li>
<li><p>if inst_dict:</p></li>
<li><p>return (self.__class__, (items,), inst_dict)</p></li>
<li><p>return self.__class__, (items,)</p></li></ul>
<p>–</p>
<ul><li><p>def copy(self):</p></li>
<li><p>‘od.copy() -> a shallow copy of od’</p></li>
<li><p>return self.__class__(self)</p></li></ul>
<p>–</p>
<ul><li><p>@classmethod</p></li>
<li><p>def fromkeys(cls, iterable, value=None):</p></li>
<li><p>'''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S.</p></li>
<li><p>If not specified, the value defaults to None.</p></li></ul>
<p>–</p>
<ul><li><p>'''</p></li>
<li><p>self = cls()</p></li>
<li><p>for key in iterable:</p></li>
<li><p>self[key] = value</p></li>
<li><p>return self</p></li></ul>
<p>–</p>
<ul><li><p>def __eq__(self, other):</p></li>
<li><p>'''od.__eq__(y) <==> od==y.  Comparison to another OD is order-sensitive</p></li>
<li><p>while comparison to a regular mapping is order-insensitive.</p></li></ul>
<p>–</p>
<ul><li><p>'''</p></li>
<li><p>if isinstance(other, OrderedDict):</p></li>
<li><p>return len(self)==len(other) and \</p></li>
<li><p>all(p==q for p, q in zip(self.items(), other.items()))</p></li>
<li><p>return dict.__eq__(self, other)</p></li></ul>
<p>– -# update_wrapper() and wraps() are tools to help write -# wrapper functions that can handle naive introspection – -WRAPPER_ASSIGNMENTS = ('__module__', ‘__name__’, ‘__doc__’) -WRAPPER_UPDATES = ('__dict__',) -def update_wrapper(wrapper,</p>
<ul><li><p>wrapped,</p></li>
<li><p>assigned = WRAPPER_ASSIGNMENTS,</p></li>
<li><p>updated = WRAPPER_UPDATES):</p></li>
<li><p>"""Update a wrapper function to look like the wrapped function</p></li></ul>
<p>–</p>
<ul><li><p>wrapper is the function to be updated</p></li>
<li><p>wrapped is the original function</p></li>
<li><p>assigned is a tuple naming the attributes assigned directly</p></li>
<li><p>from the wrapped function to the wrapper function (defaults to</p></li>
<li><p>functools.WRAPPER_ASSIGNMENTS)</p></li>
<li><p>updated is a tuple naming the attributes of the wrapper that</p></li>
<li><p>are updated with the corresponding attribute from the wrapped</p></li>
<li><p>function (defaults to functools.WRAPPER_UPDATES)</p></li>
<li><p>"""</p></li>
<li><p>wrapper.__wrapped__ = wrapped</p></li>
<li><p>for attr in assigned:</p></li>
<li><p>try:</p></li>
<li><p>value = getattr(wrapped, attr)</p></li>
<li><p>except AttributeError:</p></li>
<li><p>pass</p></li>
<li><p>else:</p></li>
<li><p>setattr(wrapper, attr, value)</p></li>
<li><p>for attr in updated:</p></li>
<li><p>getattr(wrapper, attr).update(getattr(wrapped, attr, {}))</p></li>
<li><p># Return the wrapper so this can be used as a decorator via partial()</p></li>
<li><p>return wrapper</p></li></ul>
<p>– -def wraps(wrapped,</p>
<ul><li><p>assigned = WRAPPER_ASSIGNMENTS,</p></li>
<li><p>updated = WRAPPER_UPDATES):</p></li>
<li><p>"""Decorator factory to apply update_wrapper() to a wrapper function</p></li></ul>
<p>–</p>
<ul><li><p>Returns a decorator that invokes update_wrapper() with the decorated</p></li>
<li><p>function as the wrapper argument and the arguments to wraps() as the</p></li>
<li><p>remaining arguments. Default arguments are as for update_wrapper().</p></li>
<li><p>This is a convenience function to simplify applying partial() to</p></li>
<li><p>update_wrapper().</p></li>
<li><p>"""</p></li>
<li><p>return partial(update_wrapper, wrapped=wrapped,</p></li>
<li><p>assigned=assigned, updated=updated)</p></li></ul>
<p>– -def total_ordering(cls):</p>
<ul><li><p>"""Class decorator that fills in missing ordering methods"""</p></li>
<li><p>convert = {</p></li>
<li><p>‘__lt__’: [('__gt__', lambda self, other: not (self < other or self == other)),</p></li>
<li><p>('__le__', lambda self, other: self < other or self == other),</p></li>
<li><p>('__ge__', lambda self, other: not self < other)],</p></li>
<li><p>‘__le__’: [('__ge__', lambda self, other: not self <= other or self == other),</p></li>
<li><p>('__lt__', lambda self, other: self <= other and not self == other),</p></li>
<li><p>('__gt__', lambda self, other: not self <= other)],</p></li>
<li><p>‘__gt__’: [('__lt__', lambda self, other: not (self > other or self == other)),</p></li>
<li><p>('__ge__', lambda self, other: self > other or self == other),</p></li>
<li><p>('__le__', lambda self, other: not self > other)],</p></li>
<li><p>‘__ge__’: [('__le__', lambda self, other: (not self >= other) or self == other),</p></li>
<li><p>('__gt__', lambda self, other: self >= other and not self == other),</p></li>
<li><p>('__lt__', lambda self, other: not self >= other)]</p></li>
<li><p>}</p></li>
<li><p>roots = set(dir(cls)) & set(convert)</p></li>
<li><p>if not roots:</p></li>
<li><p>raise ValueError('must define at least one ordering operation: < ><= >=')</p></li>
<li><p>root = max(roots)       # prefer <em>_lt</em>_ to <em>_le</em>_ to <em>_gt</em>_ to <em>_ge</em>_</p></li>
<li><p>for opname, opfunc in convert[root]:</p></li>
<li><p>if opname not in roots:</p></li>
<li><p>opfunc.__name__ = opname</p></li>
<li><p>opfunc.__doc__ = getattr(int, opname).__doc__</p></li>
<li><p>setattr(cls, opname, opfunc)</p></li>
<li><p>return cls</p></li></ul>
<p>– -def cmp_to_key(mycmp):</p>
<ul><li><p>"""Convert a cmp= function into a key= function"""</p></li>
<li><p>class K(object):</p></li>
<li><p><em>_slots</em>_ = ['obj']</p></li>
<li><p>def __init__(self, obj):</p></li>
<li><p>self.obj = obj</p></li>
<li><p>def __lt__(self, other):</p></li>
<li><p>return mycmp(self.obj, other.obj) < 0</p></li>
<li><p>def __gt__(self, other):</p></li>
<li><p>return mycmp(self.obj, other.obj) > 0</p></li>
<li><p>def __eq__(self, other):</p></li>
<li><p>return mycmp(self.obj, other.obj) == 0</p></li>
<li><p>def __le__(self, other):</p></li>
<li><p>return mycmp(self.obj, other.obj) <= 0</p></li>
<li><p>def __ge__(self, other):</p></li>
<li><p>return mycmp(self.obj, other.obj) >= 0</p></li>
<li><p>def __ne__(self, other):</p></li>
<li><p>return mycmp(self.obj, other.obj) != 0</p></li>
<li><p><em>_hash</em>_ = None</p></li>
<li><p>return K</p></li></ul>
<p>– -_CacheInfo = namedtuple("CacheInfo", “hits misses maxsize currsize”) – -def lru_cache(maxsize=100):</p>
<ul><li><p>"""Least-recently-used cache decorator.</p></li></ul>
<p>–</p>
<ul><li><p>If <strong>maxsize</strong> is set to None, the LRU features are disabled and the cache</p></li>
<li><p>can grow without bound.</p></li></ul>
<p>–</p>
<ul><li><p>Arguments to the cached function must be hashable.</p></li></ul>
<p>–</p>
<ul><li><p>View the cache statistics named tuple (hits, misses, maxsize, currsize) with</p></li>
<li><p>f.cache_info().  Clear the cache and statistics with f.cache_clear().</p></li>
<li><p>Access the underlying function with f.__wrapped__.</p></li></ul>
<p>–</p>
<ul><li><p>See:  <a href="http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used">http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used</a></p></li></ul>
<p>–</p>
<ul><li><p>"""</p></li>
<li><p># Users should only access the lru_cache through its public API:</p></li>
<li><p>#       cache_info, cache_clear, and f.__wrapped__</p></li>
<li><p># The internals of the lru_cache are encapsulated for thread safety and</p></li>
<li><p># to allow the implementation to change (including a possible C version).</p></li></ul>
<p>–</p>
<ul><li><p>def decorating_function(user_function,</p></li>
<li><p>tuple=tuple, sorted=sorted, len=len, KeyError=KeyError):</p></li></ul>
<p>–</p>
<ul><li><p>hits, misses = [0], [0]</p></li>
<li><p>kwd_mark = (object(),)          # separates positional and keyword args</p></li>
<li><p>lock = Lock()                   # needed because OrderedDict isn't threadsafe</p></li></ul>
<p>–</p>
<ul><li><p>if maxsize is None:</p></li>
<li><p>cache = dict()              # simple cache without ordering or size limit</p></li></ul>
<p>–</p>
<ul><li><p>@wraps(user_function)</p></li>
<li><p>def wrapper(*args, **kwds):</p></li>
<li><p>key = args</p></li>
<li><p>if kwds:</p></li>
<li><p>key += kwd_mark + tuple(sorted(kwds.items()))</p></li>
<li><p>try:</p></li>
<li><p>result = cache[key]</p></li>
<li><p>hits[0] += 1</p></li>
<li><p>return result</p></li>
<li><p>except KeyError:</p></li>
<li><p>pass</p></li>
<li><p>result = user_function(*args, **kwds)</p></li>
<li><p>cache[key] = result</p></li>
<li><p>misses[0] += 1</p></li>
<li><p>return result</p></li>
<li><p>else:</p></li>
<li><p>cache = OrderedDict()           # ordered least recent to most recent</p></li>
<li><p>cache_popitem = cache.popitem</p></li>
<li><p>cache_renew = cache.move_to_end</p></li></ul>
<p>–</p>
<ul><li><p>@wraps(user_function)</p></li>
<li><p>def wrapper(*args, **kwds):</p></li>
<li><p>key = args</p></li>
<li><p>if kwds:</p></li>
<li><p>key += kwd_mark + tuple(sorted(kwds.items()))</p></li>
<li><p>with lock:</p></li>
<li><p>try:</p></li>
<li><p>result = cache[key]</p></li>
<li><p>cache_renew(key)    # record recent use of this key</p></li>
<li><p>hits[0] += 1</p></li>
<li><p>return result</p></li>
<li><p>except KeyError:</p></li>
<li><p>pass</p></li>
<li><p>result = user_function(*args, **kwds)</p></li>
<li><p>with lock:</p></li>
<li><p>cache[key] = result     # record recent use of this key</p></li>
<li><p>misses[0] += 1</p></li>
<li><p>if len(cache) > maxsize:</p></li>
<li><p>cache_popitem(0)    # purge least recently used cache entry</p></li>
<li><p>return result</p></li></ul>
<p>–</p>
<ul><li><p>def cache_info():</p></li>
<li><p>"""Report cache statistics"""</p></li>
<li><p>with lock:</p></li>
<li><p>return _CacheInfo(hits[0], misses[0], maxsize, len(cache))</p></li></ul>
<p>–</p>
<ul><li><p>def cache_clear():</p></li>
<li><p>"""Clear the cache and cache statistics"""</p></li>
<li><p>with lock:</p></li>
<li><p>cache.clear()</p></li>
<li><p>hits[0] = misses[0] = 0</p></li></ul>
<p>–</p>
<ul><li><p>wrapper.cache_info = cache_info</p></li>
<li><p>wrapper.cache_clear = cache_clear</p></li>
<li><p>return wrapper</p></li></ul>
<p>–</p>
<ul><li><p>return decorating_function</p></li></ul>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd yt/fields/field_aliases.py --- a/yt/fields/field_aliases.py +++ b/yt/fields/field_aliases.py @@ -79,8 +79,8 @@</p>
<pre>("TangentialVelocity",               "tangential_velocity"),
("CuttingPlaneVelocityX",            "cutting_plane_velocity_x"),
("CuttingPlaneVelocityY",            "cutting_plane_velocity_y"),</pre>
<ul><li><p>("CuttingPlaneBX",                   "cutting_plane_bx"),</p></li>
<li><p>("CuttingPlaneBy",                   "cutting_plane_by"),</p></li></ul>
<p>+    ("CuttingPlaneBX",                   “cutting_plane_magnetic_field_x"), +    ("CuttingPlaneBy”,                   "cutting_plane_magnetic_field_y"),</p>
<pre>("MeanMolecularWeight",              "mean_molecular_weight"),
("particle_density",                 "particle_density"),
("ThermalEnergy",                    "thermal_energy"),</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd yt/fields/fluid_fields.py --- a/yt/fields/fluid_fields.py +++ b/yt/fields/fluid_fields.py @@ -54,6 +54,7 @@</p>
<pre>    unit_system = registry.ds.unit_system

    create_vector_fields(registry, "velocity", unit_system["velocity"], ftype, slice_info)</pre>
<p>+    create_vector_fields(registry, “magnetic_field”, unit_system["magnetic_field"], ftype, slice_info)</p>
<pre>def _cell_mass(field, data):
    return data[ftype, "density"] * data[ftype, "cell_volume"]</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd yt/fields/local_fields.py --- a/yt/fields/local_fields.py +++ b/yt/fields/local_fields.py @@ -25,7 +25,10 @@</p>
<pre>class LocalFieldInfoContainer(FieldInfoContainer):
    def add_field(self, name, function=None, **kwargs):
        if not isinstance(name, tuple):</pre>
<ul><li><p>name = ('gas', name)</p></li></ul>
<p>+            if kwargs.setdefault('particle_type', False): +                name = ('all', name) +            else: +                name = ('gas', name)</p>
<pre>override = kwargs.get("force_override", False)
# Handle the case where the field has already been added.
if not override and name in self:</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd yt/fields/vector_operations.py --- a/yt/fields/vector_operations.py +++ b/yt/fields/vector_operations.py @@ -183,13 +183,15 @@</p>
<pre>     def _cp_vectors(ax):
         def _cp_val(field, data):
vec = data.get_field_parameter("cp_%s_vec" % (ax))</pre>
<ul><li><p>bv = data.get_field_parameter("bulk_%s" % basename)</p></li>
<li><p>if bv is None: bv = np.zeros(3)</p></li>
<li><p>tr  = (data[xn] – bv[0]) * vec[0]</p></li>
<li><p>tr += (data[yn] – bv[1]) * vec[1]</p></li>
<li><p>tr += (data[zn] – bv[2]) * vec[2]</p></li></ul>
<p>+            bv = data.get_field_parameter("bulk_%s" % basename, None) +            if bv is None: +                bv = data.ds.arr(np.zeros(3), data[xn].units) +            tr  = (data[xn] – bv[0]) * vec.d[0] +            tr += (data[yn] – bv[1]) * vec.d[1] +            tr += (data[zn] – bv[2]) * vec.d[2]</p>
<pre>return tr
         return _cp_val</pre>
<p>+</p>
<pre>     registry.add_field((ftype, "cutting_plane_%s_x" % basename),
function=_cp_vectors('x'),
units=field_units)</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd yt/frontends/fits/misc.py --- a/yt/frontends/fits/misc.py +++ b/yt/frontends/fits/misc.py @@ -16,7 +16,6 @@</p>
<pre>from yt.fields.derived_field import ValidateSpatial
from yt.funcs import mylog
from yt.utilities.on_demand_imports import _astropy</pre>
<p>-from yt.visualization._mpl_imports import FigureCanvasAgg</p>
<pre>from yt.units.yt_array import YTQuantity, YTArray
from yt.utilities.fits_image import FITSImageData
if PY3:</pre>
<p>@@ -258,6 +257,7 @@</p>
<pre>        self.pw.save(name=name, mpl_kwargs=mpl_kwargs)

    def _repr_html_(self):</pre>
<p>+        from yt.visualization._mpl_imports import FigureCanvasAgg</p>
<pre>         ret = ''
         for k, v in self.plots.items():
canvas = FigureCanvasAgg(v)</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd yt/frontends/flash/data_structures.py --- a/yt/frontends/flash/data_structures.py +++ b/yt/frontends/flash/data_structures.py @@ -192,12 +192,26 @@</p>
<pre>        self.particle_filename = particle_filename

        if self.particle_filename is None:</pre>
<ul><li><p>self._particle_handle = self._handle</p></li></ul>
<p>+            # try to guess the particle filename +            try: +                self._particle_handle = HDF5FileHandler(filename.replace('plt_cnt', ‘part')) +                self.particle_filename = filename.replace('plt_cnt’, ‘part’) +                mylog.info('Particle file found: %s' % self.particle_filename.split('/')[-1]) +            except IOError: +                self._particle_handle = self._handle</p>
<pre>else:</pre>
<p>+            # particle_filename is specified by user</p>
<pre>try:
    self._particle_handle = HDF5FileHandler(self.particle_filename)
except:
    raise IOError(self.particle_filename)</pre>
<p>+        # Check if the particle file has the same time +        if self._particle_handle != self._handle: +            part_time = self._particle_handle.handle.get('real scalars')[0][1] +            plot_time = self._handle.handle.get('real scalars')[0][1] +            if not np.isclose(part_time, plot_time): +                raise IOError('%s and  %s are not at the same time.' % (self.particle_filename, filename)) +</p>
<pre># These should be explicitly obtained from the file, but for now that
# will wait until a reorganization of the source tree and better
# generalization.</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd yt/frontends/http_stream/data_structures.py --- a/yt/frontends/http_stream/data_structures.py +++ b/yt/frontends/http_stream/data_structures.py @@ -15,6 +15,7 @@</p>
<pre># The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
</pre>
<p>+import json</p>
<pre>import numpy as np
import time
</pre>
<p>@@ -24,15 +25,11 @@</p>
<pre>    ParticleDataset
from yt.frontends.sph.fields import \
    SPHFieldInfo</pre>
<p>+from yt.funcs import \ +    get_requests</p>
<pre>from yt.geometry.particle_geometry_handler import \
    ParticleIndex
</pre>
<p>-try:</p>
<ul><li><p>import requests</p></li>
<li><p>import json</p></li></ul>
<p>-except ImportError:</p>
<ul><li><p>requests = None</p></li></ul>
<p>–</p>
<pre>class HTTPParticleFile(ParticleFile):
    pass
</pre>
<p>@@ -49,8 +46,9 @@</p>
<pre>dataset_type = "http_particle_stream",
n_ref = 64, over_refine_factor=1,
unit_system="cgs"):</pre>
<ul><li><p>if requests is None:</p></li>
<li><p>raise RuntimeError</p></li></ul>
<p>+        if get_requests() is None: +            raise ImportError( +                “This functionality depends on the requests package”)</p>
<pre>self.base_url = base_url
self.n_ref = n_ref
self.over_refine_factor = over_refine_factor</pre>
<p>@@ -66,6 +64,7 @@</p>
<pre>        self.parameters["HydroMethod"] = "sph"

        # Here's where we're going to grab the JSON index file</pre>
<p>+        requests = get_requests()</p>
<pre>         hreq = requests.get(self.base_url + "/yt_index.json")
         if hreq.status_code != 200:
raise RuntimeError</pre>
<p>@@ -108,6 +107,9 @@</p>
<pre>     def _is_valid(self, *args, **kwargs):
         if not args[0].startswith("http://"):
return False</pre>
<p>+        requests = get_requests() +        if requests is None: +            return False</p>
<pre>         hreq = requests.get(args[0] + "/yt_index.json")
         if hreq.status_code == 200:
return True</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd yt/frontends/http_stream/io.py --- a/yt/frontends/http_stream/io.py +++ b/yt/frontends/http_stream/io.py @@ -18,24 +18,21 @@</p>
<pre>import numpy as np

from yt.funcs import \</pre>
<p>+    get_requests, \</p>
<pre>    mylog
from yt.utilities.io_handler import \
    BaseIOHandler
from yt.utilities.lib.geometry_utils import \
    compute_morton
</pre>
<p>-try:</p>
<ul><li><p>import requests</p></li></ul>
<p>-except ImportError:</p>
<ul><li><p>requests = None</p></li></ul>
<p>–</p>
<pre>class IOHandlerHTTPStream(BaseIOHandler):
    _dataset_type = "http_particle_stream"
    _vector_fields = ("Coordinates", "Velocity", "Velocities")

    def __init__(self, ds):</pre>
<ul><li><p>if requests is None:</p></li>
<li><p>raise RuntimeError</p></li></ul>
<p>+        if get_requests() is None: +            raise ImportError( +                “This functionality depends on the requests package”)</p>
<pre>self._url = ds.base_url
# This should eventually manage the IO and cache it
self.total_bytes = 0</pre>
<p>@@ -47,6 +44,7 @@</p>
<pre>         s = "%s/%s/%s/%s" % (self._url,
data_file.file_id, ftype, fname)
         mylog.info("Loading URL %s", s)</pre>
<p>+        requests = get_requests()</p>
<pre>         resp = requests.get(s)
         if resp.status_code != 200:
raise RuntimeError</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd yt/frontends/owls/fields.py --- a/yt/frontends/owls/fields.py +++ b/yt/frontends/owls/fields.py @@ -222,41 +222,40 @@</p>
<pre>        """ returns a function that calculates the ion density of a particle.
        """
</pre>
<ul><li><p>def _ion_density(field, data):</p></li></ul>
<p>+        def get_owls_ion_density_field(ion, ftype, itab): +            def _func(field, data):</p>
<ul><li><p># get element symbol from ion string. ion string will</p></li>
<li><p># be a member of the tuple _ions (i.e. si13)</p></li>
<li><p>#--------------------------------------------------------</p></li>
<li><p>if ion[0:2].isalpha():</p></li>
<li><p>symbol = ion[0:2].capitalize()</p></li>
<li><p>else:</p></li>
<li><p>symbol = ion[0:1].capitalize()</p></li></ul>
<p>+                # get element symbol from ion string. ion string will +                # be a member of the tuple _ions (i.e. si13) +                #-------------------------------------------------------- +                if ion[0:2].isalpha(): +                    symbol = ion[0:2].capitalize() +                else: +                    symbol = ion[0:1].capitalize()</p>
<ul><li><p># mass fraction for the element</p></li>
<li><p>#--------------------------------------------------------</p></li>
<li><p>m_frac = data[ftype, symbol+"_fraction"]</p></li></ul>
<p>+                # mass fraction for the element +                #-------------------------------------------------------- +                m_frac = data[ftype, symbol+"_fraction"]</p>
<ul><li><p># get nH and T for lookup</p></li>
<li><p>#--------------------------------------------------------</p></li>
<li><p>log_nH = np.log10( data["PartType0", “H_number_density”] )</p></li>
<li><p>log_T = np.log10( data["PartType0", “Temperature”] )</p></li></ul>
<p>+                # get nH and T for lookup +                #-------------------------------------------------------- +                log_nH = np.log10( data["PartType0", “H_number_density”] ) +                log_T = np.log10( data["PartType0", “Temperature”] )</p>
<ul><li><p># get name of owls_ion_file for given ion</p></li>
<li><p>#--------------------------------------------------------</p></li>
<li><p>owls_ion_path = self._get_owls_ion_data_dir()</p></li>
<li><p>fname = os.path.join( owls_ion_path, ion+".hdf5" )</p></li></ul>
<p>+                # get name of owls_ion_file for given ion +                #-------------------------------------------------------- +                itab.set_iz( data.ds.current_redshift )</p>
<ul><li><p># create ionization table for this redshift</p></li>
<li><p>#--------------------------------------------------------</p></li>
<li><p>itab = oit.IonTableOWLS( fname )</p></li>
<li><p>itab.set_iz( data.ds.current_redshift )</p></li></ul>
<p>–</p>
<ul><li><p># find ion balance using log nH and log T</p></li>
<li><p>#--------------------------------------------------------</p></li>
<li><p>i_frac = itab.interp( log_nH, log_T )</p></li>
<li><p>return data[ftype,"Density"] * m_frac * i_frac</p></li></ul>
<p>–</p>
<ul><li><p>return _ion_density</p></li></ul>
<p>+                # find ion balance using log nH and log T +                #-------------------------------------------------------- +                i_frac = itab.interp( log_nH, log_T ) +                return data[ftype,"Density"] * m_frac * i_frac +            return _func + +        ion_path = self._get_owls_ion_data_dir() +        fname = os.path.join( ion_path, ion+".hdf5" ) +        itab = oit.IonTableOWLS( fname ) +        return get_owls_ion_density_field(ion, ftype, itab)</p>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd yt/frontends/owls/owls_ion_tables.py --- a/yt/frontends/owls/owls_ion_tables.py +++ b/yt/frontends/owls/owls_ion_tables.py @@ -1,8 +1,8 @@ -""" +"""</p>
<pre>OWLS ion tables

A module to handle the HM01 UV background spectra and ionization data from the</pre>
<p>-OWLS photoionization equilibrium lookup tables. +OWLS photoionization equilibrium lookup tables.</p>
<p>@@ -17,27 +17,28 @@</p>
<pre>#-----------------------------------------------------------------------------

from yt.utilities.on_demand_imports import _h5py as h5py</pre>
<p>+import yt.extern.six as six</p>
<pre>import numpy as np



</pre>
<p>-def h5rd( fname, path, dtype=None ): +def h5rd(fname, path, dtype=None):</p>
<pre>""" Read Data. Return a dataset located at <path> in file <fname> as</pre>
<ul><li><p>a numpy array.</p></li></ul>
<p>+    a numpy array.</p>
<pre>    e.g. rd( fname, '/PartType0/Coordinates' ). """

    data = None</pre>
<ul><li><p>with h5py.File( fname, ‘r’ ) as h5f:</p></li>
<li><p>ds = h5f[path]</p></li>
<li><p>if dtype is None:</p></li>
<li><p>dtype = ds.dtype</p></li>
<li><p>data = np.zeros( ds.shape, dtype=dtype )</p></li>
<li><p>data = ds.value</p></li></ul>
<p>+    fid = h5py.h5f.open(six.b(fname), h5py.h5f.ACC_RDONLY) +    dg = h5py.h5d.open(fid, path.encode('ascii')) +    if dtype is None: +       dtype = dg.dtype +    data = np.zeros(dg.shape, dtype=dtype) +    dg.read(h5py.h5s.ALL, h5py.h5s.ALL, data) +    fid.close()</p>
<pre>    return data

</pre>
<p>–</p>
<pre>class IonTableSpectrum:

    """ A class to handle the HM01 spectra in the OWLS ionization tables. """</pre>
<p>@@ -45,17 +46,16 @@</p>
<pre>    def __init__(self, ion_file):

        where = '/header/spectrum/gammahi'</pre>
<ul><li><p>self.GH1 = h5rd( ion_file, where ) # GH1[1/s]</p></li></ul>
<p>+        self.GH1 = h5rd(ion_file, where) # GH1[1/s]</p>
<pre>where = '/header/spectrum/logenergy_ryd'</pre>
<ul><li><p>self.logryd = h5rd( ion_file, where ) # E[ryd]</p></li></ul>
<p>+        self.logryd = h5rd(ion_file, where) # E[ryd]</p>
<pre>where = '/header/spectrum/logflux'</pre>
<ul><li><p>self.logflux = h5rd( ion_file, where ) # J[ergs/s/Hz/Sr/cm^2]</p></li></ul>
<p>+        self.logflux = h5rd(ion_file, where) # J[ergs/s/Hz/Sr/cm^2]</p>
<pre>where = '/header/spectrum/redshift'</pre>
<ul><li><p>self.z = h5rd( ion_file, where ) # z</p></li></ul>
<p>– +        self.z = h5rd(ion_file, where) # z</p>
<pre>def return_table_GH1_at_z(self,z):</pre>
<p>@@ -68,9 +68,9 @@</p>
<pre>         else:
i_zhi = i_zlo
i_zlo = i_zlo - 1</pre>
<p>– +</p>
<pre>z_frac = (z - self.z[i_zlo]) / (self.z[i_zhi] - self.z[i_zlo])</pre>
<p>– +</p>
<pre># find GH1 from table
#-----------------------------------------------------------------
logGH1_all = np.log10( self.GH1 )</pre>
<p>@@ -80,8 +80,6 @@</p>
<pre>        GH1_table = 10.0**logGH1_table

        return GH1_table</pre>
<p>– –</p>
<pre>class IonTableOWLS:</pre>
<p>@@ -90,7 +88,7 @@</p>
<pre>DELTA_nH = 0.25
DELTA_T = 0.1</pre>
<p>– +</p>
<pre>    def __init__(self, ion_file):

        self.ion_file = ion_file</pre>
<p>@@ -104,13 +102,13 @@</p>
<pre># read the ionization fractions
# linear values stored in file so take log here</pre>
<ul><li><p># ionbal is the ionization balance (i.e. fraction)</p></li></ul>
<p>+        # ionbal is the ionization balance (i.e. fraction)</p>
<pre>#---------------------------------------------------------------</pre>
<ul><li><p>self.ionbal = h5rd( ion_file, ‘/ionbal’ ).astype(np.float64)</p></li></ul>
<p>+        self.ionbal = h5rd( ion_file, ‘/ionbal’ ).astype(np.float64)</p>
<pre>        self.ionbal_orig = self.ionbal.copy()
</pre>
<ul><li><p>ipositive = np.where( self.ionbal > 0.0 )</p></li>
<li><p>izero = np.where( self.ionbal <= 0.0 )</p></li></ul>
<p>+        ipositive = self.ionbal > 0.0 +        izero = np.logical_not(ipositive)</p>
<pre>        self.ionbal[izero] = self.ionbal[ipositive].min()

        self.ionbal = np.log10( self.ionbal )</pre>
<p>@@ -118,7 +116,7 @@</p>
<pre># load in background spectrum
#---------------------------------------------------------------</pre>
<ul><li><p>self.spectrum = IonTableSpectrum( ion_file )</p></li></ul>
<p>+        self.spectrum = IonTableSpectrum( ion_file )</p>
<pre># calculate the spacing along each dimension
#---------------------------------------------------------------</pre>
<p>@@ -129,9 +127,6 @@</p>
<pre>        self.order_str = '[log nH, log T, z]'

</pre>
<p>– – –</p>
<pre># sets iz and fz
#-----------------------------------------------------
def set_iz( self, z ):</pre>
<p>@@ -149,11 +144,11 @@</p>
<pre>                    self.fz = ( z - self.z[iz] ) / self.dz[iz]
                    break
</pre>
<p>– +</p>
<pre># interpolate the table at a fixed redshift for the input</pre>
<ul><li><p># values of nH and T ( input should be log ).  A simple</p></li>
<li><p># tri-linear interpolation is used.</p></li></ul>
<p>+    # values of nH and T ( input should be log ).  A simple +    # tri-linear interpolation is used.</p>
<pre>    #-----------------------------------------------------
    def interp( self, nH, T ):
</pre>
<p>@@ -162,7 +157,7 @@</p>
<pre>         if nH.size != T.size:
raise ValueError(' owls_ion_tables: array size mismatch !!! ')</pre>
<p>– +</p>
<pre>        # field discovery will have nH.size == 1 and T.size == 1
        # in that case we simply return 1.0
</pre>
<p>@@ -185,14 +180,14 @@</p>
<pre>x_T_clip = np.clip( x_T, 0.0, self.T.size-1.001 )
fT,iT = np.modf( x_T_clip )
iT = iT.astype( np.int32 )</pre>
<p>– +</p>
<pre>        # short names for previously calculated iz and fz
        #-----------------------------------------------------
        iz = self.iz
        fz = self.fz
</pre>
<p>– +</p>
<pre># calculate interpolated value
# use tri-linear interpolation on the log values
#-----------------------------------------------------</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd yt/frontends/sdf/data_structures.py --- a/yt/frontends/sdf/data_structures.py +++ b/yt/frontends/sdf/data_structures.py @@ -27,6 +27,8 @@</p>
<pre>    ParticleIndex
from yt.data_objects.static_output import \
    Dataset, ParticleFile</pre>
<p>+from yt.funcs import \ +    get_requests</p>
<pre>from .fields import \
    SDFFieldInfo
from yt.utilities.sdf import \</pre>
<p>@@ -34,11 +36,6 @@</p>
<pre>    SDFIndex,\
    HTTPSDFRead
</pre>
<p>-try:</p>
<ul><li><p>import requests</p></li></ul>
<p>-except ImportError:</p>
<ul><li><p>requests = None</p></li></ul>
<p>–</p>
<pre>@contextlib.contextmanager
def safeopen(*args, **kwargs):
    if sys.version[0] != '3':</pre>
<p>@@ -195,7 +192,9 @@</p>
<pre>def _is_valid(cls, *args, **kwargs):
    sdf_header = kwargs.get('sdf_header', args[0])
    if sdf_header.startswith("http"):</pre>
<ul><li><p>if requests is None: return False</p></li></ul>
<p>+            requests = get_requests() +            if requests is None: +                return False</p>
<pre>hreq = requests.get(sdf_header, stream=True)
if hreq.status_code != 200: return False
# Grab a whole 4k page.</pre>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd yt/funcs.py --- a/yt/funcs.py +++ b/yt/funcs.py @@ -953,3 +953,10 @@</p>
<pre>         raise RuntimeError(
"Please install palettable to use colorbrewer colormaps")
     return bmap.get_mpl_colormap(N=cmap[2])</pre>
<p>+ +def get_requests(): +    try: +        import requests +    except ImportError: +        requests = None +    return requests</p>
<p>diff -r 8a110e6a0156e23c47f7c9d5d71d9d402dd65cf3 -r e551ce7068575e92b30888d53ced01619343c5cd yt/geometry/oct_container.pyx --- a/yt/geometry/oct_container.pyx +++ b/yt/geometry/oct_container.pyx @@ -317,6 +317,41 @@</p>
<pre>        oinfo.level = level
        return cur
</pre>
<p>+    def locate_positions(self, np.float64_t[:,:] positions): +        """ +        This routine, meant to be called by other internal routines, returns a +        list of oct IDs and a dictionary of Oct info for all the positions +        supplied.  Positions must be in code_length. +        """ +        cdef np.float64_t factor = (1 << self.oref) +        cdef dict all_octs = {} +        cdef OctInfo oi +        cdef Oct* o = NULL +        cdef np.float64_t pos[3] +        cdef np.ndarray[np.uint8_t, ndim=1] recorded +        cdef np.ndarray[np.int64_t, ndim=1] oct_id +        oct_id = np.ones(positions.shape[0], dtype="int64") * -1 +        recorded = np.zeros(self.nocts, dtype="uint8") +        cdef np.int64_t i, j, k +        for i in range(positions.shape[0]): +            for j in range(3): +                pos[j] = positions[i,j] +            o = self.get(pos, &oi) +            if o == NULL: +                raise RuntimeError +            if recorded[o.domain_ind] == 0: +                left_edge = np.asarray(<np.float64_t[:3]>oi.left_edge).copy() +                dds = np.asarray(<np.float64_t[:3]>oi.dds).copy() +                right_edge = left_edge + dds*factor +                all_octs[o.domain_ind] = dict( +                    left_edge = left_edge, +                    right_edge = right_edge, +                    level = oi.level +                ) +                recorded[o.domain_ind] = 1 +            oct_id[i] = o.domain_ind +        return oct_id, all_octs +</p>
<pre>def domain_identify(self, SelectorObject selector):
    cdef np.ndarray[np.uint8_t, ndim=1] domain_mask
    domain_mask = np.zeros(self.num_domains, dtype="uint8")</pre>
<p>This diff is so big that we needed to truncate the remainder.</p>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/f59ea84b302c/">https://bitbucket.org/yt_analysis/yt/commits/f59ea84b302c/</a> Changeset:   f59ea84b302c Branch:      yt User:        hyschive Date:        2016-05-09 01:19:05+00:00 Summary:     Put GAMER <strong>*after</strong>* Gadget in doc/source/examining/loading_data.rst Affected #:  1 file</p>
<p>diff -r e551ce7068575e92b30888d53ced01619343c5cd -r f59ea84b302cb1782464fcb72591dd4f818e4511 doc/source/examining/loading_data.rst --- a/doc/source/examining/loading_data.rst +++ b/doc/source/examining/loading_data.rst @@ -806,34 +806,6 @@</p>
<pre>* Please be careful that the units are correctly utilized; yt assumes cgs by default, but conversion to
  other :ref:`unit systems <unit_systems>` is also possible.
</pre>
<p>-GAMER Data ----------- – -GAMER HDF5 data is supported and cared for by Hsi-Yu Schive. You can load the data like this: – -.. code-block:: python –</p>
<ul><li><p>import yt</p></li>
<li><p>ds = yt.load("InteractingJets/jet_000002")</p></li></ul>
<p>– -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 –</p>
<ul><li><p>import yt</p></li>
<li><p>code_units = { "length_unit":(1.0,"kpc"),</p></li>
<li><p>“time_unit”  :(3.08567758096e+13,"s"),</p></li>
<li><p>“mass_unit”  :(1.4690033e+36,"g") }</p></li>
<li><p>ds = yt.load("InteractingJets/jet_000002", units_override=code_units)</p></li></ul>
<p>– -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. –</p>
<pre>.. _loading-gadget-data:

Gadget Data</pre>
<p>@@ -1049,6 +1021,34 @@</p>
<pre>yt will utilize length, mass and time to set up all other units.
</pre>
<p>+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. +</p>
<pre>.. _loading-amr-data:

Generic AMR Data</pre>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/01c911476af3/">https://bitbucket.org/yt_analysis/yt/commits/01c911476af3/</a> Changeset:   01c911476af3 Branch:      yt User:        ngoldbaum Date:        2016-05-11 18:32:02+00:00 Summary:     Merged in hyschive/yt-hyschive (pull request #2150)</p>
<p>GAMER frontend Affected #:  14 files</p>
<p>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 @@</p>
<pre>* ``IsothermalCollapse/snap_505.hdf5``
* ``GadgetDiskGalaxy/snapshot_200.hdf5``
</pre>
<p>+GAMER +~~~~~~ + +* ``InteractingJets/jet_000002`` +* ``WaveDarkMatter/psiDM_000020`` +</p>
<pre>Halo Catalog
~~~~~~~~~~~~
</pre>
<p>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 @@</p>
<pre>yt will utilize length, mass and time to set up all other units.
</pre>
<p>+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. +</p>
<pre>.. _loading-amr-data:

Generic AMR Data</pre>
<p>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 @@</p>
<pre>+-----------------------+------------+-----------+------------+-------+----------+----------+------------+----------+
| Gadget                |     Y      |     Y     |      Y     |   Y   | Y [#f2]_ |    Y     |     Y      |   Full   |
+-----------------------+------------+-----------+------------+-------+----------+----------+------------+----------+</pre>
<p>+| GAMER                 |     Y      |     N     |      Y     |   Y   |    Y     |    Y     |     Y      |   Full   | ++-----------------------+------------+-----------+------------+-------+----------+----------+------------+----------+</p>
<pre>| Gasoline              |     Y      |     Y     |      Y     |   Y   | Y [#f2]_ |    Y     |     Y      |   Full   |
+-----------------------+------------+-----------+------------+-------+----------+----------+------------+----------+
| Grid Data Format (GDF)|     Y      |    N/A    |      Y     |   Y   |    Y     |    Y     |     Y      |   Full   |</pre>
<p>diff -r b61ebaeaae2e05c7e2aa6757ff23465c5cf2681d -r 01c911476af375f444f6d83cac45f5a61c9d82e4 tests/tests.yaml --- a/tests/tests.yaml +++ b/tests/tests.yaml @@ -20,6 +20,9 @@</p>
<pre>  local_gadget_000:
    - yt/frontends/gadget/tests/test_outputs.py
</pre>
<p>+  local_gamer_000: +    – yt/frontends/gamer/tests/test_outputs.py +</p>
<pre>  local_gdf_000:
    - yt/frontends/gdf/tests/test_outputs.py
</pre>
<p>diff -r b61ebaeaae2e05c7e2aa6757ff23465c5cf2681d -r 01c911476af375f444f6d83cac45f5a61c9d82e4 yt/frontends/api.py --- a/yt/frontends/api.py +++ b/yt/frontends/api.py @@ -29,6 +29,7 @@</p>
<pre>'flash',
'gadget',
'gadget_fof',</pre>
<p>+    ‘gamer’,</p>
<pre>'gdf',
'halo_catalog',
'http_stream',</pre>
<p>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 © 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. +#-----------------------------------------------------------------------------</p>
<p>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 © 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</p>
<p>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 © 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</p>
<p>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 © 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</p>
<p>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 © 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</p>
<p>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 © 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")} + +@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, <em>fields_jet): +        test_jet.__name</em>_ = test.description +        yield test + + +psiDM         = “WaveDarkMatter/psiDM_000020” +_fields_psiDM = ("Dens", “Real”, “Imag”) + +@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, <em>fields_psiDM): +        test_psiDM.__name</em>_ = test.description +        yield test + + +@requires_file(psiDM) +def test_GAMERDataset(): +    assert isinstance(data_dir_load(psiDM), GAMERDataset) + + +@requires_file(jet) +def test_units_override(): +    for test in units_override_check(jet): +        yield test</p>
<p>Repository URL: <a href="https://bitbucket.org/yt_analysis/yt/">https://bitbucket.org/yt_analysis/yt/</a></p>
<p>—</p>
<p>This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.</p>

<img src="http://link.bitbucket.org/wf/open?upn=ll4ctv0L-2ByeRZFC1LslHcg6aJmnQ70VruLbmeLQr27BwCyi02gWXg94ux2bw2Y0diik5cgg4qdLdBRAYfPqvTL1mLUPf-2BlRL-2FBGRHDciaMSP0JtL-2FgkmR2x32-2B-2BHtnRAr8UvJqSucydsanC5Q3Ilz3-2FyKNukr2vxpzKxAC-2Fxx5-2BdMaQ0GILpZWC4vV6TISdwwj8Zq7KoaLxI6jJpzvhWN-2BfblIbBrNUnCHynQqC-2BbWQ-3D" alt="" width="1" height="1" border="0" style="height:1px !important;width:1px !important;border-width:0 !important;margin-top:0 !important;margin-bottom:0 !important;margin-right:0 !important;margin-left:0 !important;padding-top:0 !important;padding-bottom:0 !important;padding-right:0 !important;padding-left:0 !important;"/>
</body></html>