Skip to content

Commit

Permalink
Merge pull request #15450 from mhvk/masked-multi-op-ufunc-with-scalars
Browse files Browse the repository at this point in the history
Ensure mask calculation is correct also for multi-op ufunc with scalars
  • Loading branch information
mhvk committed Oct 10, 2023
2 parents bc46c86 + 42d3104 commit f641d16
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 1 deletion.
4 changes: 3 additions & 1 deletion astropy/utils/masked/core.py
Expand Up @@ -697,7 +697,9 @@ def _combine_masks(self, masks, out=None, where=True, copy=True):
np.copyto(out, masks[0], where=where)
return out

out = np.logical_or(masks[0], masks[1], out=out, where=where)
# [...] at the end to ensure we have an array, not a scalar, and
# thus can be used for in-place changes in the loop.
out = np.logical_or(masks[0], masks[1], out=out, where=where)[...]
for mask in masks[2:]:
np.logical_or(out, mask, out=out, where=where)
return out
Expand Down
22 changes: 22 additions & 0 deletions astropy/utils/masked/tests/test_functions.py
Expand Up @@ -5,6 +5,7 @@
coverage. Complete coverage of all numpy functions is done
with less detailed tests in test_function_helpers.
"""
import erfa.ufunc as erfa_ufunc
import numpy as np
import pytest
from numpy.testing import assert_array_equal
Expand Down Expand Up @@ -151,6 +152,27 @@ def test_3op_ufunc(self):
assert_array_equal(ma_mb.unmasked, expected_data)
assert_array_equal(ma_mb.mask, expected_mask)

def test_multi_op_ufunc(self):
mask = [True, False, False]
iy = Masked([2000, 2001, 2002], mask=mask)
im = Masked([1, 2, 3], mask=mask)
idy = Masked([10, 20, 25], mask=mask)
ihr = Masked([11, 12, 13], mask=[False, False, True])
imn = np.array([50, 51, 52])
isc = np.array([12.5, 13.6, 14.7])
result = erfa_ufunc.dtf2d("utc", iy, im, idy, ihr, imn, isc)
# Also test scalar
result0 = erfa_ufunc.dtf2d("utc", iy[0], im[0], idy[0], ihr[0], imn[0], isc[0])
expected = erfa_ufunc.dtf2d(
"utc", iy.unmasked, im.unmasked, idy.unmasked, ihr.unmasked, imn, isc
)
expected_mask = np.array([True, False, True])
for res, res0, exp in zip(result, result0, expected):
assert_array_equal(res.unmasked, exp)
assert_array_equal(res.mask, expected_mask)
assert res0.unmasked == exp[0]
assert res0.mask == expected_mask[0]

@pytest.mark.parametrize("axis", (0, 1, None))
def test_add_reduce(self, axis):
ma_reduce = np.add.reduce(self.ma, axis=axis)
Expand Down
2 changes: 2 additions & 0 deletions docs/changes/utils/15450.bugfix.rst
@@ -0,0 +1,2 @@
Ufuncs with more than 2 operands (such as ``erfa.dtf2d``) now work
also if all inputs are scalars and more than two inputs have masks.

0 comments on commit f641d16

Please sign in to comment.