[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