Skip to content

Commit

Permalink
Merge pull request #384 from davidhassell/dask-seterr
Browse files Browse the repository at this point in the history
dask:`Data.seterr`
  • Loading branch information
davidhassell authored Apr 22, 2022
2 parents 2ad48d1 + 3a27195 commit 92fde31
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 223 deletions.
200 changes: 0 additions & 200 deletions cf/data/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,30 +131,6 @@ def wrapper(*args, **kwargs):
_year_length = 365.242198781
_month_length = _year_length / 12

# --------------------------------------------------------------------
# _seterr = How floating-point errors in the results of arithmetic
# operations are handled. These defaults are those of
# numpy 1.10.1.
# --------------------------------------------------------------------
_seterr = {
"divide": "warn",
"invalid": "warn",
"over": "warn",
"under": "ignore",
}

# --------------------------------------------------------------------
# _seterr_raise_to_ignore = As _seterr but with any values of 'raise'
# changed to 'ignore'.
# --------------------------------------------------------------------
_seterr_raise_to_ignore = _seterr.copy()


for key, value in _seterr.items():
if value == "raise":
_seterr_raise_to_ignore[key] = "ignore"
# --- End: for

_empty_set = set()

_units_None = Units()
Expand Down Expand Up @@ -5747,182 +5723,6 @@ def mask(self):

return mask_data_obj

@staticmethod
def seterr(all=None, divide=None, over=None, under=None, invalid=None):
"""Set how floating-point errors in the results of arithmetic
operations are handled.
The options for handling floating-point errors are:
============ ========================================================
Treatment Action
============ ========================================================
``'ignore'`` Take no action. Allows invalid values to occur in the
result data array.
``'warn'`` Print a `RuntimeWarning` (via the Python `warnings`
module). Allows invalid values to occur in the result
data array.
``'raise'`` Raise a `FloatingPointError` exception.
============ ========================================================
The different types of floating-point errors are:
================= ================================= =================
Error Description Default treatment
================= ================================= =================
Division by zero Infinite result obtained from ``'warn'``
finite numbers.
Overflow Result too large to be expressed. ``'warn'``
Invalid operation Result is not an expressible ``'warn'``
number, typically indicates that
a NaN was produced.
Underflow Result so close to zero that some ``'ignore'``
precision was lost.
================= ================================= =================
Note that operations on integer scalar types (such as int16) are
handled like floating point, and are affected by these settings.
If called without any arguments then the current behaviour is
returned.
.. seealso:: `cf.Data.mask_fpe`, `mask_invalid`
:Parameters:
all: `str`, optional
Set the treatment for all types of floating-point errors
at once. The default is not to change the current
behaviour.
divide: `str`, optional
Set the treatment for division by zero. The default is not
to change the current behaviour.
over: `str`, optional
Set the treatment for floating-point overflow. The default
is not to change the current behaviour.
under: `str`, optional
Set the treatment for floating-point underflow. The
default is not to change the current behaviour.
invalid: `str`, optional
Set the treatment for invalid floating-point
operation. The default is not to change the current
behaviour.
:Returns:
`dict`
The behaviour prior to the change, or the current
behaviour if no new values are specified.
**Examples**
Set treatment for all types of floating-point errors to
``'raise'`` and then reset to the previous behaviours:
>>> cf.Data.seterr()
{'divide': 'warn', 'invalid': 'warn', 'over': 'warn', 'under': 'ignore'}
>>> old = cf.Data.seterr('raise')
>>> cf.Data.seterr(**old)
{'divide': 'raise', 'invalid': 'raise', 'over': 'raise', 'under': 'raise'}
>>> cf.Data.seterr()
{'divide': 'warn', 'invalid': 'warn', 'over': 'warn', 'under': 'ignore'}
Set the treatment of division by zero to ``'ignore'`` and overflow
to ``'warn'`` without changing the treatment of underflow and
invalid operation:
>>> cf.Data.seterr(divide='ignore', over='warn')
{'divide': 'warn', 'invalid': 'warn', 'over': 'warn', 'under': 'ignore'}
>>> cf.Data.seterr()
{'divide': 'ignore', 'invalid': 'warn', 'over': 'ignore', 'under': 'ignore'}
Some examples with data arrays:
>>> d = cf.Data([0., 1])
>>> e = cf.Data([1., 2])
>>> old = cf.Data.seterr('ignore')
>>> e/d
<CF Data: [inf, 2.0] >
>>> e**12345
<CF Data: [1.0, inf] >
>>> cf.Data.seterr(divide='warn')
{'divide': 'ignore', 'invalid': 'ignore', 'over': 'ignore', 'under': 'ignore'}
>>> e/d
RuntimeWarning: divide by zero encountered in divide
<CF Data: [inf, 2.0] >
>>> e**12345
<CF Data: [1.0, inf] >
>>> old = cf.Data.mask_fpe(False)
>>> cf.Data.seterr(over='raise')
{'divide': 'warn', 'invalid': 'ignore', 'over': 'ignore', 'under': 'ignore'}
>>> e/d
RuntimeWarning: divide by zero encountered in divide
<CF Data: [inf, 2.0] >
>>> e**12345
FloatingPointError: overflow encountered in power
>>> cf.Data.mask_fpe(True)
False
>>> cf.Data.seterr(divide='ignore')
{'divide': 'warn', 'invalid': 'ignore', 'over': 'raise', 'under': 'ignore'}
>>> e/d
<CF Data: [inf, 2.0] >
>>> e**12345
<CF Data: [1.0, --] >
"""
old = _seterr.copy()

if all:
_seterr.update(
{"divide": all, "invalid": all, "under": all, "over": all}
)
if all == "raise":
_seterr_raise_to_ignore.update(
{
"divide": "ignore",
"invalid": "ignore",
"under": "ignore",
"over": "ignore",
}
)

else:
if divide:
_seterr["divide"] = divide
if divide == "raise":
_seterr_raise_to_ignore["divide"] = "ignore"

if over:
_seterr["over"] = over
if over == "raise":
_seterr_raise_to_ignore["over"] = "ignore"

if under:
_seterr["under"] = under
if under == "raise":
_seterr_raise_to_ignore["under"] = "ignore"

if invalid:
_seterr["invalid"] = invalid
if invalid == "raise":
_seterr_raise_to_ignore["invalid"] = "ignore"
# --- End: if

return old

# `arctan2`, AT2 seealso
@daskified(_DASKIFIED_VERBOSE)
@_inplace_enabled(default=False)
Expand Down
151 changes: 151 additions & 0 deletions cf/data/mixin/deprecations.py
Original file line number Diff line number Diff line change
Expand Up @@ -464,3 +464,154 @@ def partition_boundaries(self):
_DEPRECATION_ERROR_METHOD(
"TODODASK - consider using 'chunks' instead"
) # pragma: no cover

@staticmethod
def seterr(all=None, divide=None, over=None, under=None, invalid=None):
"""Set how floating-point errors in the results of arithmetic
operations are handled.
Deprecated at version TODODASK. It is currently not possible
to control how floating-point errors are handled, due to the
use of `dask` for handling all array manipulations. This may
change in the future (see
https://github.com/dask/dask/issues/3245 for more details).
The options for handling floating-point errors are:
============ ========================================================
Treatment Action
============ ========================================================
``'ignore'`` Take no action. Allows invalid values to occur in the
result data array.
``'warn'`` Print a `RuntimeWarning` (via the Python `warnings`
module). Allows invalid values to occur in the result
data array.
``'raise'`` Raise a `FloatingPointError` exception.
============ ========================================================
The different types of floating-point errors are:
================= ================================= =================
Error Description Default treatment
================= ================================= =================
Division by zero Infinite result obtained from ``'warn'``
finite numbers.
Overflow Result too large to be expressed. ``'warn'``
Invalid operation Result is not an expressible ``'warn'``
number, typically indicates that
a NaN was produced.
Underflow Result so close to zero that some ``'ignore'``
precision was lost.
================= ================================= =================
Note that operations on integer scalar types (such as int16) are
handled like floating point, and are affected by these settings.
If called without any arguments then the current behaviour is
returned.
.. seealso:: `cf.Data.mask_fpe`, `mask_invalid`
:Parameters:
all: `str`, optional
Set the treatment for all types of floating-point errors
at once. The default is not to change the current
behaviour.
divide: `str`, optional
Set the treatment for division by zero. The default is not
to change the current behaviour.
over: `str`, optional
Set the treatment for floating-point overflow. The default
is not to change the current behaviour.
under: `str`, optional
Set the treatment for floating-point underflow. The
default is not to change the current behaviour.
invalid: `str`, optional
Set the treatment for invalid floating-point
operation. The default is not to change the current
behaviour.
:Returns:
`dict`
The behaviour prior to the change, or the current
behaviour if no new values are specified.
**Examples:**
Set treatment for all types of floating-point errors to
``'raise'`` and then reset to the previous behaviours:
>>> cf.Data.seterr()
{'divide': 'warn', 'invalid': 'warn', 'over': 'warn', 'under': 'ignore'}
>>> old = cf.Data.seterr('raise')
>>> cf.Data.seterr(**old)
{'divide': 'raise', 'invalid': 'raise', 'over': 'raise', 'under': 'raise'}
>>> cf.Data.seterr()
{'divide': 'warn', 'invalid': 'warn', 'over': 'warn', 'under': 'ignore'}
Set the treatment of division by zero to ``'ignore'`` and overflow
to ``'warn'`` without changing the treatment of underflow and
invalid operation:
>>> cf.Data.seterr(divide='ignore', over='warn')
{'divide': 'warn', 'invalid': 'warn', 'over': 'warn', 'under': 'ignore'}
>>> cf.Data.seterr()
{'divide': 'ignore', 'invalid': 'warn', 'over': 'ignore', 'under': 'ignore'}
Some examples with data arrays:
>>> d = cf.Data([0., 1])
>>> e = cf.Data([1., 2])
>>> old = cf.Data.seterr('ignore')
>>> e/d
<CF Data: [inf, 2.0] >
>>> e**12345
<CF Data: [1.0, inf] >
>>> cf.Data.seterr(divide='warn')
{'divide': 'ignore', 'invalid': 'ignore', 'over': 'ignore', 'under': 'ignore'}
>>> e/d
RuntimeWarning: divide by zero encountered in divide
<CF Data: [inf, 2.0] >
>>> e**12345
<CF Data: [1.0, inf] >
>>> old = cf.Data.mask_fpe(False)
>>> cf.Data.seterr(over='raise')
{'divide': 'warn', 'invalid': 'ignore', 'over': 'ignore', 'under': 'ignore'}
>>> e/d
RuntimeWarning: divide by zero encountered in divide
<CF Data: [inf, 2.0] >
>>> e**12345
FloatingPointError: overflow encountered in power
>>> cf.Data.mask_fpe(True)
False
>>> cf.Data.seterr(divide='ignore')
{'divide': 'warn', 'invalid': 'ignore', 'over': 'raise', 'under': 'ignore'}
>>> e/d
<CF Data: [inf, 2.0] >
>>> e**12345
<CF Data: [1.0, --] >
"""
raise DeprecationError(
"Data method 'seterr' has been deprecated at version TODODASK "
"and is not available.\n\n"
"It is currently not possible to control how floating-point errors "
"are handled, due to the use of `dask` for handling all array "
"manipulations. This may change in the future (see "
"https://github.com/dask/dask/issues/3245 for more details)."
)
Loading

0 comments on commit 92fde31

Please sign in to comment.