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

commits-noreply at bitbucket.org commits-noreply at bitbucket.org
Mon Dec 7 18:57:41 PST 2015


1 new commit in yt:

https://bitbucket.org/yt_analysis/yt/commits/753456ba481f/
Changeset:   753456ba481f
Branch:      yt
User:        ngoldbaum
Date:        2015-12-08 02:57:31+00:00
Summary:     Merged in MatthewTurk/yt (pull request #1885)

Implement argmin and argmax
Affected #:  9 files

diff -r 4a8fa18eaf118a4249c1e31c6b31c8ab6997d66b -r 753456ba481faf74ba9e4f7e6def423537be8b32 doc/source/analyzing/objects.rst
--- a/doc/source/analyzing/objects.rst
+++ b/doc/source/analyzing/objects.rst
@@ -468,6 +468,19 @@
 
 All of these projections supply the data object as their base input.
 
+Often, it can be useful to sample a field at the minimum and maximum of a
+different field.  You can use the ``argmax`` and ``argmin`` operations to do
+this.::
+
+  reg.argmin("density", axis="temperature")
+
+This will return the temperature at the minimum density.
+
+If you don't specify an ``axis``, it will return the spatial position of
+the maximum value of the queried field.  Here is an example:::
+
+  x, y, z = reg.argmin("density")
+
 Available Derived Quantities
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -494,11 +507,15 @@
     | Usage: ``extrema(fields, non_zero=False)``
     | The extrema of a field or list of fields.
 
-**Maximum Location**
-    | Class :class:`~yt.data_objects.derived_quantities.MaxLocation`
-    | Usage: ``max_location(fields)``
-    | The maximum of a field or list of fields as well
-      as the x,y,z location of that maximum.
+**Maximum Location Sampling**
+    | Class :class:`~yt.data_objects.derived_quantities.SampleAtMaxFieldValues`
+    | Usage: ``sample_at_max_field_values(fields, sample_fields)``
+    | The value of sample_fields at the maximum value in fields.
+
+**Minimum Location Sampling**
+    | Class :class:`~yt.data_objects.derived_quantities.SampleAtMinFieldValues`
+    | Usage: ``sample_at_min_field_values(fields, sample_fields)``
+    | The value of sample_fields at the minimum value in fields.
 
 **Minimum Location**
     | Class :class:`~yt.data_objects.derived_quantities.MinLocation`
@@ -506,6 +523,12 @@
     | The minimum of a field or list of fields as well
       as the x,y,z location of that minimum.
 
+**Maximum Location**
+    | Class :class:`~yt.data_objects.derived_quantities.MaxLocation`
+    | Usage: ``max_location(fields)``
+    | The maximum of a field or list of fields as well
+      as the x,y,z location of that maximum.
+
 **Spin Parameter**
     | Class :class:`~yt.data_objects.derived_quantities.SpinParameter`
     | Usage: ``spin_parameter(use_gas=True, use_particles=True)``

diff -r 4a8fa18eaf118a4249c1e31c6b31c8ab6997d66b -r 753456ba481faf74ba9e4f7e6def423537be8b32 yt/analysis_modules/halo_analysis/halo_callbacks.py
--- a/yt/analysis_modules/halo_analysis/halo_callbacks.py
+++ b/yt/analysis_modules/halo_analysis/halo_callbacks.py
@@ -123,7 +123,7 @@
     s_ds = halo.data_object.ds
     old_sphere = halo.data_object
     max_vals = old_sphere.quantities.max_location(field)
-    new_center = s_ds.arr(max_vals[2:])
+    new_center = s_ds.arr(max_vals[1:])
     new_sphere = s_ds.sphere(new_center.in_units("code_length"),
                                old_sphere.radius.in_units("code_length"))
     mylog.info("Moving sphere center from %s to %s." % (old_sphere.center,

diff -r 4a8fa18eaf118a4249c1e31c6b31c8ab6997d66b -r 753456ba481faf74ba9e4f7e6def423537be8b32 yt/data_objects/data_containers.py
--- a/yt/data_objects/data_containers.py
+++ b/yt/data_objects/data_containers.py
@@ -613,10 +613,84 @@
 
     # Numpy-like Operations
     def argmax(self, field, axis=None):
-        raise NotImplementedError
+        r"""Return the values at which the field is maximized.
+
+        This will, in a parallel-aware fashion, find the maximum value and then
+        return to you the values at that maximum location that are requested
+        for "axis".  By default it will return the spatial positions (in the
+        natural coordinate system), but it can be any field
+
+        Parameters
+        ----------
+        field : string or tuple of strings
+            The field to maximize.
+        axis : string or list of strings, optional
+            If supplied, the fields to sample along; if not supplied, defaults
+            to the coordinate fields.  This can be the name of the coordinate
+            fields (i.e., 'x', 'y', 'z') or a list of fields, but cannot be 0,
+            1, 2.
+
+        Returns
+        -------
+        A list of YTQuantities as specified by the axis argument.
+
+        Examples
+        --------
+
+        >>> temp_at_max_rho = reg.argmax("density", axis="temperature")
+        >>> max_rho_xyz = reg.argmax("density")
+        >>> t_mrho, v_mrho = reg.argmax("density", axis=["temperature",
+        ...                 "velocity_magnitude"])
+        >>> x, y, z = reg.argmax("density")
+
+        """
+        if axis is None:
+            mv, pos0, pos1, pos2 = self.quantities.max_location(field)
+            return pos0, pos1, pos2
+        rv = self.quantities.sample_at_max_field_values(field, axis)
+        if len(rv) == 2:
+            return rv[1]
+        return rv[1:]
 
     def argmin(self, field, axis=None):
-        raise NotImplementedError
+        r"""Return the values at which the field is minimized.
+
+        This will, in a parallel-aware fashion, find the minimum value and then
+        return to you the values at that minimum location that are requested
+        for "axis".  By default it will return the spatial positions (in the
+        natural coordinate system), but it can be any field
+
+        Parameters
+        ----------
+        field : string or tuple of strings
+            The field to minimize.
+        axis : string or list of strings, optional
+            If supplied, the fields to sample along; if not supplied, defaults
+            to the coordinate fields.  This can be the name of the coordinate
+            fields (i.e., 'x', 'y', 'z') or a list of fields, but cannot be 0,
+            1, 2.
+
+        Returns
+        -------
+        A list of YTQuantities as specified by the axis argument.
+
+        Examples
+        --------
+
+        >>> temp_at_min_rho = reg.argmin("density", axis="temperature")
+        >>> min_rho_xyz = reg.argmin("density")
+        >>> t_mrho, v_mrho = reg.argmin("density", axis=["temperature",
+        ...                 "velocity_magnitude"])
+        >>> x, y, z = reg.argmin("density")
+
+        """
+        if axis is None:
+            mv, pos0, pos1, pos2 = self.quantities.min_location(field)
+            return pos0, pos1, pos2
+        rv = self.quantities.sample_at_min_field_values(field, axis)
+        if len(rv) == 2:
+            return rv[1]
+        return rv[1:]
 
     def _compute_extrema(self, field):
         if self._extrema_cache is None:

diff -r 4a8fa18eaf118a4249c1e31c6b31c8ab6997d66b -r 753456ba481faf74ba9e4f7e6def423537be8b32 yt/data_objects/derived_quantities.py
--- a/yt/data_objects/derived_quantities.py
+++ b/yt/data_objects/derived_quantities.py
@@ -522,10 +522,57 @@
         return [self.data_source.ds.arr([mis.min(), mas.max()])
                 for mis, mas in zip(values[::2], values[1::2])]
 
-class MaxLocation(DerivedQuantity):
+class SampleAtMaxFieldValues(DerivedQuantity):
     r"""
-    Calculates the maximum value plus the index, x, y, and z position
-    of the maximum.
+    Calculates the maximum value and returns whichever fields are asked to be
+    sampled.
+
+    Parameters
+    ----------
+    field : field
+        The field over which the extrema are to be calculated.
+    sample_fields : list of fields
+        The fields to sample and return at the minimum value.
+
+    Examples
+    --------
+
+    >>> ds = load("IsolatedGalaxy/galaxy0030/galaxy0030")
+    >>> ad = ds.all_data()
+    >>> print ad.quantities.sample_at_max_field_values(("gas", "density"),
+    ...         ["temperature", "velocity_magnitude"])
+
+    """
+    def count_values(self, field, sample_fields):
+        # field itself, then index, then the number of sample fields
+        self.num_vals = 1 + len(sample_fields)
+
+    def __call__(self, field, sample_fields):
+        rv = super(SampleAtMaxFieldValues, self).__call__(field, sample_fields)
+        if len(rv) == 1: rv = rv[0]
+        return rv
+
+    def process_chunk(self, data, field, sample_fields):
+        field = data._determine_fields(field)[0]
+        ma = array_like_field(data, -HUGE, field)
+        vals = [array_like_field(data, -1, sf) for sf in sample_fields]
+        maxi = -1
+        if data[field].size > 0:
+            maxi = self._func(data[field])
+            ma = data[field][maxi]
+            vals = [data[sf][maxi] for sf in sample_fields]
+        return (ma,) + tuple(vals)
+
+    def reduce_intermediate(self, values):
+        i = self._func(values[0]) # ma is values[0]
+        return [val[i] for val in values]
+
+    def _func(self, arr):
+        return np.argmax(arr)
+
+class MaxLocation(SampleAtMaxFieldValues):
+    r"""
+    Calculates the maximum value plus the x, y, and z position of the maximum.
 
     Parameters
     ----------
@@ -540,36 +587,39 @@
     >>> print ad.quantities.max_location(("gas", "density"))
 
     """
-    def count_values(self, *args, **kwargs):
-        self.num_vals = 5
-
     def __call__(self, field):
-        rv = super(MaxLocation, self).__call__(field)
+        sample_fields = get_position_fields(field, self.data_source)
+        rv = super(MaxLocation, self).__call__(field, sample_fields)
         if len(rv) == 1: rv = rv[0]
         return rv
 
-    def process_chunk(self, data, field):
-        field = data._determine_fields(field)[0]
-        ma = array_like_field(data, -HUGE, field)
-        position_fields = get_position_fields(field, data)
-        mx = array_like_field(data, -1, position_fields[0])
-        my = array_like_field(data, -1, position_fields[1])
-        mz = array_like_field(data, -1, position_fields[2])
-        maxi = -1
-        if data[field].size > 0:
-            maxi = np.argmax(data[field])
-            ma = data[field][maxi]
-            mx, my, mz = [data[ax][maxi] for ax in position_fields]
-        return (ma, maxi, mx, my, mz)
+class SampleAtMinFieldValues(SampleAtMaxFieldValues):
+    r"""
+    Calculates the minimum value and returns whichever fields are asked to be
+    sampled.
 
-    def reduce_intermediate(self, values):
-        i = np.argmax(values[0]) # ma is values[0]
-        return [val[i] for val in values]
+    Parameters
+    ----------
+    field : field
+        The field over which the extrema are to be calculated.
+    sample_fields : list of fields
+        The fields to sample and return at the minimum value.
 
-class MinLocation(DerivedQuantity):
+    Examples
+    --------
+
+    >>> ds = load("IsolatedGalaxy/galaxy0030/galaxy0030")
+    >>> ad = ds.all_data()
+    >>> print ad.quantities.sample_at_min_field_values(("gas", "density"),
+    ...         ["temperature", "velocity_magnitude"])
+
+    """
+    def _func(self, arr):
+        return np.argmin(arr)
+
+class MinLocation(SampleAtMinFieldValues):
     r"""
-    Calculates the minimum value plus the index, x, y, and z position
-    of the minimum.
+    Calculates the minimum value plus the x, y, and z position of the minimum.
 
     Parameters
     ----------
@@ -584,32 +634,12 @@
     >>> print ad.quantities.min_location(("gas", "density"))
 
     """
-    def count_values(self, *args, **kwargs):
-        self.num_vals = 5
-
     def __call__(self, field):
-        rv = super(MinLocation, self).__call__(field)
+        sample_fields = get_position_fields(field, self.data_source)
+        rv = super(MinLocation, self).__call__(field, sample_fields)
         if len(rv) == 1: rv = rv[0]
         return rv
 
-    def process_chunk(self, data, field):
-        field = data._determine_fields(field)[0]
-        ma = array_like_field(data, HUGE, field)
-        position_fields = get_position_fields(field, data)
-        mx = array_like_field(data, -1, position_fields[0])
-        my = array_like_field(data, -1, position_fields[1])
-        mz = array_like_field(data, -1, position_fields[2])
-        mini = -1
-        if data[field].size > 0:
-            mini = np.argmin(data[field])
-            ma = data[field][mini]
-            mx, my, mz = [data[ax][mini] for ax in position_fields]
-        return (ma, mini, mx, my, mz)
-
-    def reduce_intermediate(self, values):
-        i = np.argmin(values[0]) # ma is values[0]
-        return [val[i] for val in values]
-
 class SpinParameter(DerivedQuantity):
     r"""
     Calculates the dimensionless spin parameter.

diff -r 4a8fa18eaf118a4249c1e31c6b31c8ab6997d66b -r 753456ba481faf74ba9e4f7e6def423537be8b32 yt/data_objects/static_output.py
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -625,7 +625,7 @@
         """
         mylog.debug("Searching for maximum value of %s", field)
         source = self.all_data()
-        max_val, maxi, mx, my, mz = \
+        max_val, mx, my, mz = \
             source.quantities.max_location(field)
         mylog.info("Max Value is %0.5e at %0.16f %0.16f %0.16f",
               max_val, mx, my, mz)
@@ -637,7 +637,7 @@
         """
         mylog.debug("Searching for minimum value of %s", field)
         source = self.all_data()
-        min_val, maxi, mx, my, mz = \
+        min_val, mx, my, mz = \
             source.quantities.min_location(field)
         mylog.info("Min Value is %0.5e at %0.16f %0.16f %0.16f",
               min_val, mx, my, mz)

diff -r 4a8fa18eaf118a4249c1e31c6b31c8ab6997d66b -r 753456ba481faf74ba9e4f7e6def423537be8b32 yt/data_objects/tests/test_derived_quantities.py
--- a/yt/data_objects/tests/test_derived_quantities.py
+++ b/yt/data_objects/tests/test_derived_quantities.py
@@ -55,6 +55,68 @@
                         ad["cell_mass"].sum())
         yield assert_rel_equal, my_std, a_std, 12
 
+def test_max_location():
+    for nprocs in [1, 2, 4, 8]:
+        ds = fake_random_ds(16, nprocs = nprocs, fields = ("density", ))
+        ad = ds.all_data()
+
+        mv, x, y, z = ad.quantities.max_location(("gas", "density"))
+
+        yield assert_equal, mv, ad["density"].max()
+
+        mi = np.argmax(ad["density"])
+
+        yield assert_equal, ad["x"][mi], x
+        yield assert_equal, ad["y"][mi], y
+        yield assert_equal, ad["z"][mi], z
+
+def test_min_location():
+    for nprocs in [1, 2, 4, 8]:
+        ds = fake_random_ds(16, nprocs = nprocs, fields = ("density", ))
+        ad = ds.all_data()
+
+        mv, x, y, z = ad.quantities.min_location(("gas", "density"))
+
+        yield assert_equal, mv, ad["density"].min()
+
+        mi = np.argmin(ad["density"])
+
+        yield assert_equal, ad["x"][mi], x
+        yield assert_equal, ad["y"][mi], y
+        yield assert_equal, ad["z"][mi], z
+
+def test_sample_at_min_field_values():
+    for nprocs in [1, 2, 4, 8]:
+        ds = fake_random_ds(16, nprocs = nprocs,
+            fields = ("density", "temperature", "velocity_x"))
+        ad = ds.all_data()
+
+        mv, temp, vm = ad.quantities.sample_at_min_field_values(
+            "density", ["temperature", "velocity_x"])
+
+        yield assert_equal, mv, ad["density"].min()
+
+        mi = np.argmin(ad["density"])
+
+        yield assert_equal, ad["temperature"][mi], temp
+        yield assert_equal, ad["velocity_x"][mi], vm
+
+def test_sample_at_max_field_values():
+    for nprocs in [1, 2, 4, 8]:
+        ds = fake_random_ds(16, nprocs = nprocs,
+            fields = ("density", "temperature", "velocity_x"))
+        ad = ds.all_data()
+
+        mv, temp, vm = ad.quantities.sample_at_max_field_values(
+            "density", ["temperature", "velocity_x"])
+
+        yield assert_equal, mv, ad["density"].max()
+
+        mi = np.argmax(ad["density"])
+
+        yield assert_equal, ad["temperature"][mi], temp
+        yield assert_equal, ad["velocity_x"][mi], vm
+
 if __name__ == "__main__":
     for i in test_extrema():
         i[0](*i[1:])

diff -r 4a8fa18eaf118a4249c1e31c6b31c8ab6997d66b -r 753456ba481faf74ba9e4f7e6def423537be8b32 yt/data_objects/tests/test_numpy_ops.py
--- a/yt/data_objects/tests/test_numpy_ops.py
+++ b/yt/data_objects/tests/test_numpy_ops.py
@@ -1,4 +1,5 @@
 from yt.testing import fake_random_ds, fake_amr_ds, assert_equal
+import numpy as np
 
 
 def setup():
@@ -93,3 +94,51 @@
         qrho, qtemp = ad.min(["density", "temperature"])
         yield assert_equal, qrho, ad["density"].min()
         yield assert_equal, qtemp, ad["temperature"].min()
+
+def test_argmin():
+    for nprocs in [-1, 1, 2, 16]:
+        if nprocs == -1:
+            ds = fake_amr_ds(fields=("density","temperature"))
+        else:
+            ds = fake_random_ds(32, nprocs=nprocs,
+                fields=("density","temperature"))
+
+        ad = ds.all_data()
+
+        q = ad.argmin("density", axis=["density"])
+        yield assert_equal, q, ad["density"].min()
+
+        q1, q2 = ad.argmin("density", axis=["density", "temperature"])
+        mi = np.argmin(ad["density"])
+        yield assert_equal, q1, ad["density"].min()
+        yield assert_equal, q2, ad["temperature"][mi]
+
+        pos = ad.argmin("density")
+        mi = np.argmin(ad["density"])
+        yield assert_equal, pos[0], ad["x"][mi]
+        yield assert_equal, pos[1], ad["y"][mi]
+        yield assert_equal, pos[2], ad["z"][mi]
+
+def test_argmax():
+    for nprocs in [-1, 1, 2, 16]:
+        if nprocs == -1:
+            ds = fake_amr_ds(fields=("density","temperature"))
+        else:
+            ds = fake_random_ds(32, nprocs=nprocs,
+                fields=("density","temperature"))
+
+        ad = ds.all_data()
+
+        q = ad.argmax("density", axis=["density"])
+        yield assert_equal, q, ad["density"].max()
+
+        q1, q2 = ad.argmax("density", axis=["density", "temperature"])
+        mi = np.argmax(ad["density"])
+        yield assert_equal, q1, ad["density"].max()
+        yield assert_equal, q2, ad["temperature"][mi]
+
+        pos = ad.argmax("density")
+        mi = np.argmax(ad["density"])
+        yield assert_equal, pos[0], ad["x"][mi]
+        yield assert_equal, pos[1], ad["y"][mi]
+        yield assert_equal, pos[2], ad["z"][mi]

diff -r 4a8fa18eaf118a4249c1e31c6b31c8ab6997d66b -r 753456ba481faf74ba9e4f7e6def423537be8b32 yt/frontends/artio/data_structures.py
--- a/yt/frontends/artio/data_structures.py
+++ b/yt/frontends/artio/data_structures.py
@@ -199,7 +199,7 @@
         if finest_levels is not False:
             source.min_level = self.max_level - finest_levels
         mylog.debug("Searching for maximum value of %s", field)
-        max_val, maxi, mx, my, mz = \
+        max_val, mx, my, mz = \
             source.quantities["MaxLocation"](field)
         mylog.info("Max Value is %0.5e at %0.16f %0.16f %0.16f",
                    max_val, mx, my, mz)

diff -r 4a8fa18eaf118a4249c1e31c6b31c8ab6997d66b -r 753456ba481faf74ba9e4f7e6def423537be8b32 yt/geometry/object_finding_mixin.py
--- a/yt/geometry/object_finding_mixin.py
+++ b/yt/geometry/object_finding_mixin.py
@@ -79,7 +79,7 @@
             source = self.all_data()
         mylog.debug("Searching %s grids for maximum value of %s",
                     len(source._grids), field)
-        max_val, maxi, mx, my, mz = \
+        max_val, mx, my, mz = \
             source.quantities["MaxLocation"]( field )
         mylog.info("Max Value is %0.5e at %0.16f %0.16f %0.16f", 
               max_val, mx, my, mz)

Repository URL: https://bitbucket.org/yt_analysis/yt/

--

This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.



More information about the yt-svn mailing list