示例#1
0
def setup_gradient_fields(registry, grad_field, field_units, slice_info=None):

    geom = registry.ds.geometry
    if is_curvilinear(geom):
        mylog.warning(
            "In %s geometry, gradient fields may contain artifacts near cartesian axes."
            % geom)

    assert (isinstance(grad_field, tuple))
    ftype, fname = grad_field
    if slice_info is None:
        sl_left = slice(None, -2, None)
        sl_right = slice(2, None, None)
        div_fac = 2.0
    else:
        sl_left, sl_right, div_fac = slice_info
    slice_3d = (slice(1, -1), slice(1, -1), slice(1, -1))

    def grad_func(axi, ax):
        slice_3dl = slice_3d[:axi] + (sl_left, ) + slice_3d[axi + 1:]
        slice_3dr = slice_3d[:axi] + (sl_right, ) + slice_3d[axi + 1:]

        def func(field, data):
            ds = div_fac * data[ftype, "d%s" % ax]
            if ax == "theta":
                ds *= data[ftype, "r"]
            if ax == "phi":
                ds *= data[ftype, "r"] * np.sin(data[ftype, "theta"])
            f = data[grad_field][slice_3dr] / ds[slice_3d]
            f -= data[grad_field][slice_3dl] / ds[slice_3d]
            new_field = np.zeros_like(data[grad_field], dtype=np.float64)
            new_field = data.ds.arr(new_field, f.units)
            new_field[slice_3d] = f
            return new_field

        return func

    field_units = Unit(field_units, registry=registry.ds.unit_registry)
    grad_units = field_units / registry.ds.unit_system["length"]

    for axi, ax in enumerate(registry.ds.coordinates.axis_order):
        f = grad_func(axi, ax)
        registry.add_field((ftype, "%s_gradient_%s" % (fname, ax)),
                           sampling_type="local",
                           function=f,
                           validators=[ValidateSpatial(1, [grad_field])],
                           units=grad_units)

    create_magnitude_field(registry,
                           "%s_gradient" % fname,
                           grad_units,
                           ftype=ftype,
                           validators=[ValidateSpatial(1, [grad_field])])
示例#2
0
 def __init__(self, ds, field_list, slice_info=None):
     self._show_field_errors = []
     self.ds = ds
     # Now we start setting things up.
     self.field_list = field_list
     self.slice_info = slice_info
     self.field_aliases = {}
     self.species_names = []
     if ds is not None and is_curvilinear(ds.geometry):
         self.curvilinear = True
     else:
         self.curvilinear = False
     self.setup_fluid_aliases()
示例#3
0
def setup_gradient_fields(registry, grad_field, field_units, slice_info=None):
    # Current implementation for gradient is not valid for curvilinear geometries
    if is_curvilinear(registry.ds.geometry): return

    assert (isinstance(grad_field, tuple))
    ftype, fname = grad_field
    if slice_info is None:
        sl_left = slice(None, -2, None)
        sl_right = slice(2, None, None)
        div_fac = 2.0
    else:
        sl_left, sl_right, div_fac = slice_info
    slice_3d = (slice(1, -1), slice(1, -1), slice(1, -1))

    def grad_func(axi, ax):
        slice_3dl = slice_3d[:axi] + (sl_left, ) + slice_3d[axi + 1:]
        slice_3dr = slice_3d[:axi] + (sl_right, ) + slice_3d[axi + 1:]

        def func(field, data):
            ds = div_fac * data[ftype, "d%s" % ax]
            f = data[grad_field][slice_3dr] / ds[slice_3d]
            f -= data[grad_field][slice_3dl] / ds[slice_3d]
            new_field = np.zeros_like(data[grad_field], dtype=np.float64)
            new_field = data.ds.arr(new_field, f.units)
            new_field[slice_3d] = f
            return new_field

        return func

    field_units = Unit(field_units, registry=registry.ds.unit_registry)
    grad_units = field_units / registry.ds.unit_system["length"]

    for axi, ax in enumerate('xyz'):
        f = grad_func(axi, ax)
        registry.add_field((ftype, "%s_gradient_%s" % (fname, ax)),
                           sampling_type="cell",
                           function=f,
                           validators=[ValidateSpatial(1, [grad_field])],
                           units=grad_units)
    create_magnitude_field(registry,
                           "%s_gradient" % fname,
                           grad_units,
                           ftype=ftype,
                           validators=[ValidateSpatial(1, [grad_field])])
示例#4
0
def create_vector_fields(registry,
                         basename,
                         field_units,
                         ftype="gas",
                         slice_info=None):
    from yt.units.unit_object import Unit

    # slice_info would be the left, the right, and the factor.
    # For example, with the old Enzo-ZEUS fields, this would be:
    # slice(None, -2, None)
    # slice(1, -1, None)
    # 1.0
    # Otherwise, we default to a centered difference.
    if slice_info is None:
        sl_left = slice(None, -2, None)
        sl_right = slice(2, None, None)
        div_fac = 2.0
    else:
        sl_left, sl_right, div_fac = slice_info

    xn, yn, zn = [(ftype, f"{basename}_{ax}") for ax in "xyz"]

    # Is this safe?
    if registry.ds.dimensionality < 3:
        zn = ("index", "zeros")
    if registry.ds.dimensionality < 2:
        yn = ("index", "zeros")

    create_relative_field(
        registry,
        basename,
        field_units,
        ftype=ftype,
        slice_info=slice_info,
        validators=[ValidateParameter(f"bulk_{basename}")],
    )

    create_magnitude_field(
        registry,
        basename,
        field_units,
        ftype=ftype,
        slice_info=slice_info,
        validators=[ValidateParameter(f"bulk_{basename}")],
    )

    if not is_curvilinear(registry.ds.geometry):

        # The following fields are invalid for curvilinear geometries
        def _spherical_radius_component(field, data):
            """The spherical radius component of the vector field

            Relative to the coordinate system defined by the *normal* vector,
            *center*, and *bulk_* field parameters.
            """
            normal = data.get_field_parameter("normal")
            vectors = obtain_relative_velocity_vector(data, (xn, yn, zn),
                                                      f"bulk_{basename}")
            theta = data["index", "spherical_theta"]
            phi = data["index", "spherical_phi"]
            rv = get_sph_r_component(vectors, theta, phi, normal)
            # Now, anywhere that radius is in fact zero, we want to zero out our
            # return values.
            rv[np.isnan(theta)] = 0.0
            return rv

        registry.add_field(
            (ftype, f"{basename}_spherical_radius"),
            sampling_type="local",
            function=_spherical_radius_component,
            units=field_units,
            validators=[
                ValidateParameter("normal"),
                ValidateParameter("center"),
                ValidateParameter(f"bulk_{basename}"),
            ],
        )
        create_los_field(registry,
                         basename,
                         field_units,
                         ftype=ftype,
                         slice_info=slice_info)

        def _radial(field, data):
            return data[ftype, f"{basename}_spherical_radius"]

        def _radial_absolute(field, data):
            return np.abs(data[ftype, f"{basename}_spherical_radius"])

        def _tangential(field, data):
            return np.sqrt(data[ftype, f"{basename}_spherical_theta"]**2.0 +
                           data[ftype, f"{basename}_spherical_phi"]**2.0)

        registry.add_field(
            (ftype, f"radial_{basename}"),
            sampling_type="local",
            function=_radial,
            units=field_units,
            validators=[
                ValidateParameter("normal"),
                ValidateParameter("center")
            ],
        )

        registry.add_field(
            (ftype, f"radial_{basename}_absolute"),
            sampling_type="local",
            function=_radial_absolute,
            units=field_units,
        )

        registry.add_field(
            (ftype, f"tangential_{basename}"),
            sampling_type="local",
            function=_tangential,
            units=field_units,
        )

        def _spherical_theta_component(field, data):
            """The spherical theta component of the vector field

            Relative to the coordinate system defined by the *normal* vector,
            *center*, and *bulk_* field parameters.
            """
            normal = data.get_field_parameter("normal")
            vectors = obtain_relative_velocity_vector(data, (xn, yn, zn),
                                                      f"bulk_{basename}")
            theta = data["index", "spherical_theta"]
            phi = data["index", "spherical_phi"]
            return get_sph_theta_component(vectors, theta, phi, normal)

        registry.add_field(
            (ftype, f"{basename}_spherical_theta"),
            sampling_type="local",
            function=_spherical_theta_component,
            units=field_units,
            validators=[
                ValidateParameter("normal"),
                ValidateParameter("center"),
                ValidateParameter(f"bulk_{basename}"),
            ],
        )

        def _spherical_phi_component(field, data):
            """The spherical phi component of the vector field

            Relative to the coordinate system defined by the *normal* vector,
            *center*, and *bulk_* field parameters.
            """
            normal = data.get_field_parameter("normal")
            vectors = obtain_relative_velocity_vector(data, (xn, yn, zn),
                                                      f"bulk_{basename}")
            phi = data["index", "spherical_phi"]
            return get_sph_phi_component(vectors, phi, normal)

        registry.add_field(
            (ftype, f"{basename}_spherical_phi"),
            sampling_type="local",
            function=_spherical_phi_component,
            units=field_units,
            validators=[
                ValidateParameter("normal"),
                ValidateParameter("center"),
                ValidateParameter(f"bulk_{basename}"),
            ],
        )

        def _cp_vectors(ax):
            def _cp_val(field, data):
                vec = data.get_field_parameter(f"cp_{ax}_vec")
                tr = data[xn[0], f"relative_{xn[1]}"] * vec.d[0]
                tr += data[yn[0], f"relative_{yn[1]}"] * vec.d[1]
                tr += data[zn[0], f"relative_{zn[1]}"] * vec.d[2]
                return tr

            return _cp_val

        for ax in "xyz":
            registry.add_field(
                (ftype, f"cutting_plane_{basename}_{ax}"),
                sampling_type="local",
                function=_cp_vectors(ax),
                units=field_units,
            )

        def _divergence(field, data):
            ds = div_fac * just_one(data["index", "dx"])
            f = data[xn[0], f"relative_{xn[1]}"][sl_right, 1:-1, 1:-1] / ds
            f -= data[xn[0], f"relative_{xn[1]}"][sl_left, 1:-1, 1:-1] / ds
            ds = div_fac * just_one(data["index", "dy"])
            f += data[yn[0], f"relative_{yn[1]}"][1:-1, sl_right, 1:-1] / ds
            f -= data[yn[0], f"relative_{yn[1]}"][1:-1, sl_left, 1:-1] / ds
            ds = div_fac * just_one(data["index", "dz"])
            f += data[zn[0], f"relative_{zn[1]}"][1:-1, 1:-1, sl_right] / ds
            f -= data[zn[0], f"relative_{zn[1]}"][1:-1, 1:-1, sl_left] / ds
            new_field = data.ds.arr(np.zeros(data[xn].shape, dtype=np.float64),
                                    f.units)
            new_field[1:-1, 1:-1, 1:-1] = f
            return new_field

        def _divergence_abs(field, data):
            return np.abs(data[ftype, f"{basename}_divergence"])

        field_units = Unit(field_units, registry=registry.ds.unit_registry)
        div_units = field_units / registry.ds.unit_system["length"]

        registry.add_field(
            (ftype, f"{basename}_divergence"),
            sampling_type="local",
            function=_divergence,
            units=div_units,
            validators=[
                ValidateSpatial(1),
                ValidateParameter(f"bulk_{basename}")
            ],
        )

        registry.add_field(
            (ftype, f"{basename}_divergence_absolute"),
            sampling_type="local",
            function=_divergence_abs,
            units=div_units,
        )

        def _tangential_over_magnitude(field, data):
            tr = (data[ftype, f"tangential_{basename}"] /
                  data[ftype, f"{basename}_magnitude"])
            return np.abs(tr)

        registry.add_field(
            (ftype, f"tangential_over_{basename}_magnitude"),
            sampling_type="local",
            function=_tangential_over_magnitude,
            take_log=False,
        )

        def _cylindrical_radius_component(field, data):
            """The cylindrical radius component of the vector field

            Relative to the coordinate system defined by the *normal* vector,
            *center*, and *bulk_* field parameters.
            """
            normal = data.get_field_parameter("normal")
            vectors = obtain_relative_velocity_vector(data, (xn, yn, zn),
                                                      f"bulk_{basename}")
            theta = data["index", "cylindrical_theta"]
            return get_cyl_r_component(vectors, theta, normal)

        registry.add_field(
            (ftype, f"{basename}_cylindrical_radius"),
            sampling_type="local",
            function=_cylindrical_radius_component,
            units=field_units,
            validators=[ValidateParameter("normal")],
        )

        registry.alias(
            (ftype, f"cylindrical_radial_{basename}"),
            (ftype, f"{basename}_cylindrical_radius"),
            deprecate=("4.0.0", "4.1.0"),
        )

        def _cylindrical_radial_absolute(field, data):
            """This field is deprecated and will be removed in a future version"""
            return np.abs(data[ftype, f"{basename}_cylindrical_radius"])

        registry.add_deprecated_field(
            (ftype, f"cylindrical_radial_{basename}_absolute"),
            function=_cylindrical_radial_absolute,
            sampling_type="local",
            since="4.0.0",
            removal="4.1.0",
            units=field_units,
            validators=[ValidateParameter("normal")],
        )

        def _cylindrical_theta_component(field, data):
            """The cylindrical theta component of the vector field

            Relative to the coordinate system defined by the *normal* vector,
            *center*, and *bulk_* field parameters.
            """
            normal = data.get_field_parameter("normal")
            vectors = obtain_relative_velocity_vector(data, (xn, yn, zn),
                                                      f"bulk_{basename}")
            theta = data["index", "cylindrical_theta"].copy()
            theta = np.tile(theta, (3, ) + (1, ) * len(theta.shape))
            return get_cyl_theta_component(vectors, theta, normal)

        registry.add_field(
            (ftype, f"{basename}_cylindrical_theta"),
            sampling_type="local",
            function=_cylindrical_theta_component,
            units=field_units,
            validators=[
                ValidateParameter("normal"),
                ValidateParameter("center"),
                ValidateParameter(f"bulk_{basename}"),
            ],
        )

        def _cylindrical_tangential_absolute(field, data):
            """This field is deprecated and will be removed in a future release"""
            return np.abs(data[ftype, f"cylindrical_tangential_{basename}"])

        registry.alias(
            (ftype, f"cylindrical_tangential_{basename}"),
            (ftype, f"{basename}_cylindrical_theta"),
            deprecate=("4.0.0", "4.1.0"),
        )

        registry.add_deprecated_field(
            (ftype, f"cylindrical_tangential_{basename}_absolute"),
            function=_cylindrical_tangential_absolute,
            sampling_type="local",
            since="4.0.0",
            removal="4.1.0",
            units=field_units,
        )

        def _cylindrical_z_component(field, data):
            """The cylindrical z component of the vector field

            Relative to the coordinate system defined by the *normal* vector,
            *center*, and *bulk_* field parameters.
            """
            normal = data.get_field_parameter("normal")
            vectors = obtain_relative_velocity_vector(data, (xn, yn, zn),
                                                      f"bulk_{basename}")
            return get_cyl_z_component(vectors, normal)

        registry.add_field(
            (ftype, f"{basename}_cylindrical_z"),
            sampling_type="local",
            function=_cylindrical_z_component,
            units=field_units,
            validators=[
                ValidateParameter("normal"),
                ValidateParameter("center"),
                ValidateParameter(f"bulk_{basename}"),
            ],
        )

    else:  # Create Cartesian fields for curvilinear coordinates

        def _cartesian_x(field, data):
            if registry.ds.geometry == "polar":

                return data[(ftype, f"{basename}_r")] * np.cos(
                    data[(ftype, "theta")])

            elif registry.ds.geometry == "cylindrical":

                if data.ds.dimensionality == 2:
                    return data[(ftype, f"{basename}_r")]
                elif data.ds.dimensionality == 3:
                    return data[(ftype, f"{basename}_r")] * np.cos(data[
                        (ftype, "theta")]) - data[
                            (ftype, f"{basename}_theta")] * np.sin(data[
                                (ftype, "theta")])

            elif registry.ds.geometry == "spherical":

                if data.ds.dimensionality == 2:
                    return data[(ftype, f"{basename}_r")] * np.sin(data[
                        (ftype, "theta")]) + data[
                            (ftype, f"{basename}_theta")] * np.cos(data[
                                (ftype, "theta")])
                elif data.ds.dimensionality == 3:
                    return (data[(ftype, f"{basename}_r")] * np.sin(data[
                        (ftype, "theta")]) * np.cos(data[(ftype, "phi")]) +
                            data[(ftype, f"{basename}_theta")] * np.cos(data[
                                (ftype, "theta")]) * np.cos([(ftype, "phi")]) -
                            data[(ftype, f"{basename}_phi")] *
                            np.sin(data[(ftype, "phi")]))

        # it's redundant to define a cartesian x field for 1D data
        if registry.ds.dimensionality > 1:
            registry.add_field(
                (ftype, f"{basename}_cartesian_x"),
                sampling_type="local",
                function=_cartesian_x,
                units=field_units,
                display_field=True,
            )

        def _cartesian_y(field, data):
            if registry.ds.geometry == "polar":

                return data[(ftype, f"{basename}_r")] * np.sin(
                    data[(ftype, "theta")])

            elif registry.ds.geometry == "cylindrical":

                if data.ds.dimensionality == 2:
                    return data[(ftype, f"{basename}_z")]
                elif data.ds.dimensionality == 3:
                    return data[(ftype, f"{basename}_r")] * np.sin(data[
                        (ftype, "theta")]) + data[
                            (ftype, f"{basename}_theta")] * np.cos(data[
                                (ftype, "theta")])

            elif registry.ds.geometry == "spherical":

                if data.ds.dimensionality == 2:
                    return data[(ftype, f"{basename}_r")] * np.cos(data[(
                        ftype, "theta")]) - data[f"{basename}_theta"] * np.sin(
                            data[(ftype, "theta")])
                elif data.ds.dimensionality == 3:
                    return (data[(ftype, f"{basename}_r")] * np.sin(data[
                        (ftype, "theta")]) * np.sin(data[(ftype, "phi")]) +
                            data[(ftype, f"{basename}_theta")] * np.cos(data[
                                (ftype, "theta")]) * np.sin([(ftype, "phi")]) +
                            data[(ftype, f"{basename}_phi")] *
                            np.cos(data[(ftype, "phi")]))

        if registry.ds.dimensionality >= 2:
            registry.add_field(
                (ftype, f"{basename}_cartesian_y"),
                sampling_type="local",
                function=_cartesian_y,
                units=field_units,
                display_field=True,
            )

        def _cartesian_z(field, data):
            if registry.ds.geometry == "cylindrical":
                return data[(ftype, f"{basename}_z")]
            elif registry.ds.geometry == "spherical":
                return data[(ftype, f"{basename}_r")] * np.cos(data[
                    (ftype, "theta")]) - data[
                        (ftype, f"{basename}_theta")] * np.sin(data[
                            (ftype, "theta")])

        if registry.ds.dimensionality == 3:
            registry.add_field(
                (ftype, f"{basename}_cartesian_z"),
                sampling_type="local",
                function=_cartesian_z,
                units=field_units,
                display_field=True,
            )
示例#5
0
def setup_gradient_fields(registry, grad_field, field_units, slice_info=None):

    geom = registry.ds.geometry
    if is_curvilinear(geom):
        mylog.warning(
            "In %s geometry, gradient fields may contain "
            "artifacts near cartesian axes.",
            geom,
        )

    assert isinstance(grad_field, tuple)
    ftype, fname = grad_field
    if slice_info is None:
        sl_left = slice(None, -2, None)
        sl_right = slice(2, None, None)
        div_fac = 2.0
    else:
        sl_left, sl_right, div_fac = slice_info
    slice_3d = (slice(1, -1), slice(1, -1), slice(1, -1))

    def grad_func(axi, ax):
        slice_3dl = slice_3d[:axi] + (sl_left, ) + slice_3d[axi + 1:]
        slice_3dr = slice_3d[:axi] + (sl_right, ) + slice_3d[axi + 1:]

        def func(field, data):
            block_order = getattr(data, "_block_order", "C")
            if block_order == "F":
                # Fortran-ordering: we need to swap axes here and
                # reswap below
                field_data = data[grad_field].swapaxes(0, 2)
            else:
                field_data = data[grad_field]
            dx = div_fac * data[ftype, f"d{ax}"]
            if ax == "theta":
                dx *= data[ftype, "r"]
            if ax == "phi":
                dx *= data[ftype, "r"] * np.sin(data[ftype, "theta"])
            f = field_data[slice_3dr] / dx[slice_3d]
            f -= field_data[slice_3dl] / dx[slice_3d]
            new_field = np.zeros_like(data[grad_field], dtype=np.float64)
            new_field = data.ds.arr(new_field, field_data.units / dx.units)
            new_field[slice_3d] = f

            if block_order == "F":
                new_field = new_field.swapaxes(0, 2)

            return new_field

        return func

    field_units = Unit(field_units, registry=registry.ds.unit_registry)
    grad_units = field_units / registry.ds.unit_system["length"]

    for axi, ax in enumerate(registry.ds.coordinates.axis_order):
        f = grad_func(axi, ax)
        registry.add_field(
            (ftype, f"{fname}_gradient_{ax}"),
            sampling_type="local",
            function=f,
            validators=[ValidateSpatial(1, [grad_field])],
            units=grad_units,
        )

    create_magnitude_field(
        registry,
        f"{fname}_gradient",
        grad_units,
        ftype=ftype,
        validators=[ValidateSpatial(1, [grad_field])],
    )
示例#6
0
def setup_fluid_vector_fields(registry, ftype="gas", slice_info=None):
    # Current implementation for gradient is not valid for curvilinear geometries
    if is_curvilinear(registry.ds.geometry): return

    unit_system = registry.ds.unit_system
    # slice_info would be the left, the right, and the factor.
    # For example, with the old Enzo-ZEUS fields, this would be:
    # slice(None, -2, None)
    # slice(1, -1, None)
    # 1.0
    # Otherwise, we default to a centered difference.
    if slice_info is None:
        sl_left = slice(None, -2, None)
        sl_right = slice(2, None, None)
        div_fac = 2.0
    else:
        sl_left, sl_right, div_fac = slice_info
    sl_center = slice(1, -1, None)

    def _baroclinic_vorticity_x(field, data):
        rho2 = data[ftype, "density"].astype(np.float64)**2
        return (data[ftype, "pressure_gradient_y"] *
                data[ftype, "density_gradient_z"] -
                data[ftype, "pressure_gradient_z"] *
                data[ftype, "density_gradient_z"]) / rho2

    def _baroclinic_vorticity_y(field, data):
        rho2 = data[ftype, "density"].astype(np.float64)**2
        return (data[ftype, "pressure_gradient_z"] *
                data[ftype, "density_gradient_x"] -
                data[ftype, "pressure_gradient_x"] *
                data[ftype, "density_gradient_z"]) / rho2

    def _baroclinic_vorticity_z(field, data):
        rho2 = data[ftype, "density"].astype(np.float64)**2
        return (data[ftype, "pressure_gradient_x"] *
                data[ftype, "density_gradient_y"] -
                data[ftype, "pressure_gradient_y"] *
                data[ftype, "density_gradient_x"]) / rho2

    bv_validators = [
        ValidateSpatial(1, [(ftype, "density"), (ftype, "pressure")])
    ]
    for ax in 'xyz':
        n = "baroclinic_vorticity_%s" % ax
        registry.add_field((ftype, n),
                           sampling_type="cell",
                           function=eval("_%s" % n),
                           validators=bv_validators,
                           units=unit_system["frequency"]**2)

    create_magnitude_field(registry,
                           "baroclinic_vorticity",
                           unit_system["frequency"]**2,
                           ftype=ftype,
                           slice_info=slice_info,
                           validators=bv_validators)

    def _vorticity_x(field, data):
        vz = data[ftype, "relative_velocity_z"]
        vy = data[ftype, "relative_velocity_y"]
        f = ((vz[sl_center, sl_right, sl_center] -
              vz[sl_center, sl_left, sl_center]) /
             (div_fac * just_one(data["index", "dy"])))
        f -= ((vy[sl_center, sl_center, sl_right] -
               vy[sl_center, sl_center, sl_left]) /
              (div_fac * just_one(data["index", "dz"])))
        new_field = data.ds.arr(np.zeros_like(vz, dtype=np.float64), f.units)
        new_field[sl_center, sl_center, sl_center] = f
        return new_field

    def _vorticity_y(field, data):
        vx = data[ftype, "relative_velocity_x"]
        vz = data[ftype, "relative_velocity_z"]
        f = ((vx[sl_center, sl_center, sl_right] -
              vx[sl_center, sl_center, sl_left]) /
             (div_fac * just_one(data["index", "dz"])))
        f -= ((vz[sl_right, sl_center, sl_center] -
               vz[sl_left, sl_center, sl_center]) /
              (div_fac * just_one(data["index", "dx"])))
        new_field = data.ds.arr(np.zeros_like(vz, dtype=np.float64), f.units)
        new_field[sl_center, sl_center, sl_center] = f
        return new_field

    def _vorticity_z(field, data):
        vx = data[ftype, "relative_velocity_x"]
        vy = data[ftype, "relative_velocity_y"]
        f = ((vy[sl_right, sl_center, sl_center] -
              vx[sl_left, sl_center, sl_center]) /
             (div_fac * just_one(data["index", "dx"])))
        f -= ((vx[sl_center, sl_right, sl_center] -
               vx[sl_center, sl_left, sl_center]) /
              (div_fac * just_one(data["index", "dy"])))
        new_field = data.ds.arr(np.zeros_like(vy, dtype=np.float64), f.units)
        new_field[sl_center, sl_center, sl_center] = f
        return new_field

    vort_validators = [
        ValidateSpatial(1, [(ftype, "velocity_%s" % d) for d in 'xyz']),
        ValidateParameter('bulk_velocity')
    ]

    for ax in 'xyz':
        n = "vorticity_%s" % ax
        registry.add_field((ftype, n),
                           sampling_type="cell",
                           function=eval("_%s" % n),
                           units=unit_system["frequency"],
                           validators=vort_validators)
    create_magnitude_field(registry,
                           "vorticity",
                           unit_system["frequency"],
                           ftype=ftype,
                           slice_info=slice_info,
                           validators=vort_validators)
    create_squared_field(registry,
                         "vorticity",
                         unit_system["frequency"]**2,
                         ftype=ftype,
                         slice_info=slice_info,
                         validators=vort_validators)

    def _vorticity_stretching_x(field, data):
        return data[ftype, "velocity_divergence"] * data[ftype, "vorticity_x"]

    def _vorticity_stretching_y(field, data):
        return data[ftype, "velocity_divergence"] * data[ftype, "vorticity_y"]

    def _vorticity_stretching_z(field, data):
        return data[ftype, "velocity_divergence"] * data[ftype, "vorticity_z"]

    for ax in 'xyz':
        n = "vorticity_stretching_%s" % ax
        registry.add_field((ftype, n),
                           sampling_type="cell",
                           function=eval("_%s" % n),
                           units=unit_system["frequency"]**2,
                           validators=vort_validators)

    create_magnitude_field(registry,
                           "vorticity_stretching",
                           unit_system["frequency"]**2,
                           ftype=ftype,
                           slice_info=slice_info,
                           validators=vort_validators)

    def _vorticity_growth_x(field, data):
        return -data[ftype, "vorticity_stretching_x"] - \
          data[ftype, "baroclinic_vorticity_x"]

    def _vorticity_growth_y(field, data):
        return -data[ftype, "vorticity_stretching_y"] - \
          data[ftype, "baroclinic_vorticity_y"]

    def _vorticity_growth_z(field, data):
        return -data[ftype, "vorticity_stretching_z"] - \
          data[ftype, "baroclinic_vorticity_z"]

    for ax in 'xyz':
        n = "vorticity_growth_%s" % ax
        registry.add_field((ftype, n),
                           sampling_type="cell",
                           function=eval("_%s" % n),
                           units=unit_system["frequency"]**2,
                           validators=vort_validators)

    def _vorticity_growth_magnitude(field, data):
        result = np.sqrt(data[ftype, "vorticity_growth_x"]**2 +
                         data[ftype, "vorticity_growth_y"]**2 +
                         data[ftype, "vorticity_growth_z"]**2)
        dot = data.ds.arr(np.zeros(result.shape), "")
        for ax in "xyz":
            dot += (data[ftype, "vorticity_%s" % ax] *
                    data[ftype, "vorticity_growth_%s" % ax]).to_ndarray()
        result = np.sign(dot) * result
        return result

    registry.add_field((ftype, "vorticity_growth_magnitude"),
                       sampling_type="cell",
                       function=_vorticity_growth_magnitude,
                       units=unit_system["frequency"]**2,
                       validators=vort_validators,
                       take_log=False)

    def _vorticity_growth_magnitude_absolute(field, data):
        return np.sqrt(data[ftype, "vorticity_growth_x"]**2 +
                       data[ftype, "vorticity_growth_y"]**2 +
                       data[ftype, "vorticity_growth_z"]**2)

    registry.add_field((ftype, "vorticity_growth_magnitude_absolute"),
                       sampling_type="cell",
                       function=_vorticity_growth_magnitude_absolute,
                       units=unit_system["frequency"]**2,
                       validators=vort_validators)

    def _vorticity_growth_timescale(field, data):
        domegax_dt = data[ftype, "vorticity_x"] / data[ftype,
                                                       "vorticity_growth_x"]
        domegay_dt = data[ftype, "vorticity_y"] / data[ftype,
                                                       "vorticity_growth_y"]
        domegaz_dt = data[ftype, "vorticity_z"] / data[ftype,
                                                       "vorticity_growth_z"]
        return np.sqrt(domegax_dt**2 + domegay_dt**2 + domegaz_dt**2)

    registry.add_field((ftype, "vorticity_growth_timescale"),
                       sampling_type="cell",
                       function=_vorticity_growth_timescale,
                       units=unit_system["time"],
                       validators=vort_validators)

    ########################################################################
    # With radiation pressure
    ########################################################################

    def _vorticity_radiation_pressure_x(field, data):
        rho = data[ftype, "density"].astype(np.float64)
        return (data[ftype, "radiation_acceleration_y"] *
                data[ftype, "density_gradient_z"] -
                data[ftype, "radiation_acceleration_z"] *
                data[ftype, "density_gradient_y"]) / rho

    def _vorticity_radiation_pressure_y(field, data):
        rho = data[ftype, "density"].astype(np.float64)
        return (data[ftype, "radiation_acceleration_z"] *
                data[ftype, "density_gradient_x"] -
                data[ftype, "radiation_acceleration_x"] *
                data[ftype, "density_gradient_z"]) / rho

    def _vorticity_radiation_pressure_z(field, data):
        rho = data[ftype, "density"].astype(np.float64)
        return (data[ftype, "radiation_acceleration_x"] *
                data[ftype, "density_gradient_y"] -
                data[ftype, "radiation_acceleration_y"] *
                data[ftype, "density_gradient_x"]) / rho

    vrp_validators = [
        ValidateSpatial(1, [(ftype, "density"),
                            (ftype, "radiation_acceleration_x"),
                            (ftype, "radiation_acceleration_y"),
                            (ftype, "radiation_acceleration_z")])
    ]
    for ax in 'xyz':
        n = "vorticity_radiation_pressure_%s" % ax
        registry.add_field((ftype, n),
                           sampling_type="cell",
                           function=eval("_%s" % n),
                           units=unit_system["frequency"]**2,
                           validators=vrp_validators)

    create_magnitude_field(registry,
                           "vorticity_radiation_pressure",
                           unit_system["frequency"]**2,
                           ftype=ftype,
                           slice_info=slice_info,
                           validators=vrp_validators)

    def _vorticity_radiation_pressure_growth_x(field, data):
        return -data[ftype, "vorticity_stretching_x"] - \
          data[ftype, "baroclinic_vorticity_x"] \
          -data[ftype, "vorticity_radiation_pressure_x"]

    def _vorticity_radiation_pressure_growth_y(field, data):
        return -data[ftype, "vorticity_stretching_y"] - \
          data[ftype, "baroclinic_vorticity_y"] \
          -data[ftype, "vorticity_radiation_pressure_y"]

    def _vorticity_radiation_pressure_growth_z(field, data):
        return -data[ftype, "vorticity_stretching_z"] - \
          data[ftype, "baroclinic_vorticity_z"] \
          -data[ftype, "vorticity_radiation_pressure_z"]

    for ax in 'xyz':
        n = "vorticity_radiation_pressure_growth_%s" % ax
        registry.add_field((ftype, n),
                           sampling_type="cell",
                           function=eval("_%s" % n),
                           units=unit_system["frequency"]**2,
                           validators=vrp_validators)

    def _vorticity_radiation_pressure_growth_magnitude(field, data):
        result = np.sqrt(
            data[ftype, "vorticity_radiation_pressure_growth_x"]**2 +
            data[ftype, "vorticity_radiation_pressure_growth_y"]**2 +
            data[ftype, "vorticity_radiation_pressure_growth_z"]**2)
        dot = data.ds.arr(np.zeros(result.shape), "")
        for ax in "xyz":
            dot += (data[ftype, "vorticity_%s" % ax] *
                    data[ftype, "vorticity_growth_%s" % ax]).to_ndarray()
        result = np.sign(dot) * result
        return result

    registry.add_field(
        (ftype, "vorticity_radiation_pressure_growth_magnitude"),
        sampling_type="cell",
        function=_vorticity_radiation_pressure_growth_magnitude,
        units=unit_system["frequency"]**2,
        validators=vrp_validators,
        take_log=False)

    def _vorticity_radiation_pressure_growth_magnitude_absolute(field, data):
        return np.sqrt(
            data[ftype, "vorticity_radiation_pressure_growth_x"]**2 +
            data[ftype, "vorticity_radiation_pressure_growth_y"]**2 +
            data[ftype, "vorticity_radiation_pressure_growth_z"]**2)

    registry.add_field(
        (ftype, "vorticity_radiation_pressure_growth_magnitude_absolute"),
        sampling_type="cell",
        function=_vorticity_radiation_pressure_growth_magnitude_absolute,
        units="s**(-2)",
        validators=vrp_validators)

    def _vorticity_radiation_pressure_growth_timescale(field, data):
        domegax_dt = data[ftype, "vorticity_x"] / \
          data[ftype, "vorticity_radiation_pressure_growth_x"]
        domegay_dt = data[ftype, "vorticity_y"] / \
          data[ftype, "vorticity_radiation_pressure_growth_y"]
        domegaz_dt = data[ftype, "vorticity_z"] / \
          data[ftype, "vorticity_radiation_pressure_growth_z"]
        return np.sqrt(domegax_dt**2 + domegay_dt**2 + domegaz_dt**2)

    registry.add_field(
        (ftype, "vorticity_radiation_pressure_growth_timescale"),
        sampling_type="cell",
        function=_vorticity_radiation_pressure_growth_timescale,
        units=unit_system["time"],
        validators=vrp_validators)

    def _shear(field, data):
        """
        Shear is defined as [(dvx/dy + dvy/dx)^2 + (dvz/dy + dvy/dz)^2 +
                             (dvx/dz + dvz/dx)^2 ]^(0.5)
        where dvx/dy = [vx(j-1) - vx(j+1)]/[2dy]
        and is in units of s^(-1)
        (it's just like vorticity except add the derivative pairs instead
         of subtracting them)
        """
        if data.ds.dimensionality > 1:
            vx = data[ftype, "relative_velocity_x"]
            vy = data[ftype, "relative_velocity_y"]
            dvydx = ((vy[sl_right, sl_center, sl_center] -
                      vy[sl_left, sl_center, sl_center]) /
                     (div_fac * just_one(data["index", "dx"])))
            dvxdy = ((vx[sl_center, sl_right, sl_center] -
                      vx[sl_center, sl_left, sl_center]) /
                     (div_fac * just_one(data["index", "dy"])))
            f = (dvydx + dvxdy)**2.0
            del dvydx, dvxdy
        if data.ds.dimensionality > 2:
            vz = data[ftype, "relative_velocity_z"]
            dvzdy = ((vz[sl_center, sl_right, sl_center] -
                      vz[sl_center, sl_left, sl_center]) /
                     (div_fac * just_one(data["index", "dy"])))
            dvydz = ((vy[sl_center, sl_center, sl_right] -
                      vy[sl_center, sl_center, sl_left]) /
                     (div_fac * just_one(data["index", "dz"])))
            f += (dvzdy + dvydz)**2.0
            del dvzdy, dvydz
            dvxdz = ((vx[sl_center, sl_center, sl_right] -
                      vx[sl_center, sl_center, sl_left]) /
                     (div_fac * just_one(data["index", "dz"])))
            dvzdx = ((vz[sl_right, sl_center, sl_center] -
                      vz[sl_left, sl_center, sl_center]) /
                     (div_fac * just_one(data["index", "dx"])))
            f += (dvxdz + dvzdx)**2.0
            del dvxdz, dvzdx
        np.sqrt(f, out=f)
        new_field = data.ds.arr(np.zeros_like(data[ftype, "velocity_x"]),
                                f.units)
        new_field[sl_center, sl_center, sl_center] = f
        return new_field

    registry.add_field((ftype, "shear"),
                       sampling_type="cell",
                       function=_shear,
                       validators=[
                           ValidateSpatial(1, [(ftype, "velocity_x"),
                                               (ftype, "velocity_y"),
                                               (ftype, "velocity_z")]),
                           ValidateParameter('bulk_velocity')
                       ],
                       units=unit_system["frequency"])

    def _shear_criterion(field, data):
        """
        Divide by c_s to leave shear in units of length**-1, which 
        can be compared against the inverse of the local cell size (1/dx) 
        to determine if refinement should occur.
        """
        return data[ftype, "shear"] / data[ftype, "sound_speed"]

    registry.add_field((ftype, "shear_criterion"),
                       sampling_type="cell",
                       function=_shear_criterion,
                       units=unit_system["length"]**-1,
                       validators=[
                           ValidateSpatial(1, [(ftype, "sound_speed"),
                                               (ftype, "velocity_x"),
                                               (ftype, "velocity_y"),
                                               (ftype, "velocity_z")])
                       ])

    def _shear_mach(field, data):
        """
        Dimensionless shear (shear_mach) is defined nearly the same as shear, 
        except that it is scaled by the local dx/dy/dz and the local sound speed.
        So it results in a unitless quantity that is effectively measuring 
        shear in mach number.  

        In order to avoid discontinuities created by multiplying by dx/dy/dz at
        grid refinement boundaries, we also multiply by 2**GridLevel.

        Shear (Mach) = [(dvx + dvy)^2 + (dvz + dvy)^2 +
                        (dvx + dvz)^2  ]^(0.5) / c_sound
        """
        if data.ds.dimensionality > 1:
            vx = data[ftype, "relative_velocity_x"]
            vy = data[ftype, "relative_velocity_y"]
            dvydx = (vy[sl_right, sl_center, sl_center] -
                     vy[sl_left, sl_center, sl_center]) / div_fac
            dvxdy = (vx[sl_center, sl_right, sl_center] -
                     vx[sl_center, sl_left, sl_center]) / div_fac
            f = (dvydx + dvxdy)**2.0
            del dvydx, dvxdy
        if data.ds.dimensionality > 2:
            vz = data[ftype, "relative_velocity_z"]
            dvzdy = (vz[sl_center, sl_right, sl_center] -
                     vz[sl_center, sl_left, sl_center]) / div_fac
            dvydz = (vy[sl_center, sl_center, sl_right] -
                     vy[sl_center, sl_center, sl_left]) / div_fac
            f += (dvzdy + dvydz)**2.0
            del dvzdy, dvydz
            dvxdz = (vx[sl_center, sl_center, sl_right] -
                     vx[sl_center, sl_center, sl_left]) / div_fac
            dvzdx = (vz[sl_right, sl_center, sl_center] -
                     vz[sl_left, sl_center, sl_center]) / div_fac
            f += (dvxdz + dvzdx)**2.0
            del dvxdz, dvzdx
        f *= (
            2.0**data["index", "grid_level"][sl_center, sl_center, sl_center] /
            data[ftype, "sound_speed"][sl_center, sl_center, sl_center])**2.0
        np.sqrt(f, out=f)
        new_field = data.ds.arr(np.zeros_like(vx), f.units)
        new_field[sl_center, sl_center, sl_center] = f
        return new_field

    vs_fields = [(ftype, "sound_speed"), (ftype, "velocity_x"),
                 (ftype, "velocity_y"), (ftype, "velocity_z")]
    registry.add_field((ftype, "shear_mach"),
                       sampling_type="cell",
                       function=_shear_mach,
                       units="",
                       validators=[
                           ValidateSpatial(1, vs_fields),
                           ValidateParameter('bulk_velocity')
                       ])