Skip to content

erfa.p2s does not accept units except for distance #16873

Closed

Description

@mhvk

Description

In liberfa/pyerfa#149, @maxnoe reported the following error, which had him puzzled (transferred here since astropy.units.quantity_helpers.erfa is responsible for making pyerfa work with units).

from erfa.ufunc import s2p as spherical_to_cartesian
import astropy.units as u
import numpy  as np
 
lon = np.pi / 2
lat = np.pi / 4
 
spherical_to_cartesian(lon, lat, 5 * u.km)

results in this relatively unhelpful error:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[3], line 8
      5 lon = np.pi / 2
      6 lat = np.pi / 4
----> 8 spherical_to_cartesian(lon, lat, 5 * u.km)

File ~/.local/conda/envs/cta-dev/lib/python3.11/site-packages/astropy/units/quantity.py:691, in Quantity.__array_ufunc__(self, function, method, *inputs, **kwargs)
    689     return NotImplemented
    690 else:
--> 691     raise e

File ~/.local/conda/envs/cta-dev/lib/python3.11/site-packages/astropy/units/quantity.py:636, in Quantity.__array_ufunc__(self, function, method, *inputs, **kwargs)
    631 # Determine required conversion functions -- to bring the unit of the
    632 # input to that expected (e.g., radian for np.sin), or to get
    633 # consistent units between two inputs (e.g., in np.add) --
    634 # and the unit of the result (or tuple of units for nout > 1).
    635 try:
--> 636     converters, unit = converters_and_unit(function, method, *inputs)
    638     out = kwargs.get("out", None)
    639     # Avoid loop back by turning any Quantity output into array views.

File ~/.local/conda/envs/cta-dev/lib/python3.11/site-packages/astropy/units/quantity_helper/converters.py:181, in converters_and_unit(function, method, *args)
    178 units = [getattr(arg, "unit", None) for arg in args]
    180 # Determine possible conversion functions, and the result unit.
--> 181 converters, result_unit = ufunc_helper(function, *units)
    183 if any(converter is False for converter in converters):
    184     # for multi-argument ufuncs with a quantity and a non-quantity,
    185     # the quantity normally needs to be dimensionless, *except*
   (...)
    188     # can just have the unit of the quantity
    189     # (this allows, e.g., `q > 0.` independent of unit)
    190     try:
    191         # Don't fold this loop in the test above: this rare case
    192         # should not make the common case slower.

File ~/.local/conda/envs/cta-dev/lib/python3.11/site-packages/astropy/units/quantity_helper/erfa.py:70, in helper_s2p(f, unit1, unit2, unit3)
     67 from astropy.units.si import radian
     69 try:
---> 70     return [get_converter(unit1, radian), get_converter(unit2, radian), None], unit3
     71 except UnitsError:
     72     raise UnitTypeError(
     73         f"Can only apply '{f.__name__}' function to quantities with angle units"
     74     )

File ~/.local/conda/envs/cta-dev/lib/python3.11/site-packages/astropy/units/quantity_helper/helpers.py:42, in get_converter(from_unit, to_unit)
     38 def get_converter(from_unit, to_unit):
     39     """Like Unit._get_converter, except returns None if no scaling is needed,
     40     i.e., if the inferred scale is unity.
     41     """
---> 42     converter = from_unit._get_converter(to_unit)
     43     return None if converter is unit_scale_converter else converter

AttributeError: 'NoneType' object has no attribute '_get_converter'

Expected behavior

No response

How to Reproduce

No response

Versions

import astropy
try:
    astropy.system_info()
except AttributeError:
    import platform; print(platform.platform())
    import sys; print("Python", sys.version)
    import astropy; print("astropy", astropy.__version__)
    import numpy; print("Numpy", numpy.__version__)
    import erfa; print("pyerfa", erfa.__version__)
    try:
        import scipy
        print("Scipy", scipy.__version__)
    except ImportError:
        print("Scipy not installed")
    try:
        import matplotlib
        print("Matplotlib", matplotlib.__version__)
    except ImportError:
        print("Matplotlib not installed")
# Paste the result here

Activity

  1. mhvk commented on Aug 23, 2024

    @mhvk
    ContributorAuthor

    This is a little tricky: in general, once units are involved, we treat numbers/arrays as dimensionless, and here the function needs angular units. So, in that sense, the error is logical. Note that you don't normally notice this for something like np.sin, since if the argument has no unit, it never reaches the units machinery and hence the number is interpreted as being in radians by np.sin itself. But if you do np.sin(0.5, out=u.Quantity()), you get exactly the same confusing error message.

    I think, though, that this issue is mostly about the confusing error message - which should be fixable! - is that the case?

  2. maxnoe commented on Aug 24, 2024

    @maxnoe
    Member

    Yes, sure, if this is not easy to fix, something like "either all or none of the arguments must be provided as quantities" would be fine I guess

  3. mhvk commented on Aug 25, 2024

    @mhvk
    ContributorAuthor

    See #16878 for a fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions