Skip to content

decompose does not accept PrefixUnits as bases #5615

Closed

Description

@joleroi

Consider the following code

>>> import astropy.units as u
>>> myunit = u.keV
>>> myunit.decompose(bases=['eV'])
Unit("1000 eV") 
>>> myunit.decompose(bases=['TeV'])

The last line raises this UnitConversionError.

Is this behaviour intended? And if yes, is there another way to achieve what is outlined in the code snipped above, namely decomposing a given unit using TeV (or any composite unit) as base unit?

cc @adonath

Activity

  1. mhvk commented on Dec 20, 2016

    @mhvk
    Contributor

    @joleroi - decompose is specifically meant to decompose to irreducible units. In your example, I think what you want is

    myunit.compose(units=[u.TeV], include_prefix_units=True)
    [Unit("1e-09 TeV")]
    

    Note that compose() always returns a list since there may be multiple possibilities; you'd just take the first element. Also note that one still has to add include_prefix_units=True (which perhaps is a bit odd, and could be solved; see #4104).

    Stepping back from the specific issue, why do you need this? I ask because over time I found that I care less and less about what specific unit something is in: I just do calculations and at the very end, if I really care, I convert my quantities to a specific unit using quantity.to(desired_unit).

  2. joleroi commented on Dec 20, 2016

    @joleroi
    Author

    Thanks for your reply

    Stepping back from the specific issue, why do you need this?

    I need to write all quantities I have to disk in a given units system (cm, s, keV) to use them with Sherpa. Of course I could use quantity.to(desired_unit) but then I'd need to check first of what type my quantity is (energy, flux, length). Therefore I'd like to be able to express any quantity I have in given set of (non-irreducible) units. What you propose works your the use case I've described, for composite units, however, it fails.

    In [9]: myunit = u.TeV / u.m ** 2
    
    In [10]: myunit
    Out[10]: Unit("TeV / m2")
    
    In [11]: myunit.compose(units=[u.cm, u.keV], include_prefix_units=True)
    ---------------------------------------------------------------------------
    UnitsError                                Traceback (most recent call last)
    <ipython-input-11-cd39fd74ef52> in <module>()
    ----> 1 myunit.compose(units=[u.cm, u.keV], include_prefix_units=True)
    
    /home/kingj/Software/astropy/astropy/units/core.pyc in compose(self, equivalencies, units, max_depth, include_prefix_units)
       1280         return sort_results(self._compose(
       1281             equivalencies=equivalencies, namespace=units,
    -> 1282             max_depth=max_depth, depth=0, cached_results={}))
       1283 
       1284     def to_system(self, system):
    
    /home/kingj/Software/astropy/astropy/units/core.pyc in _compose(self, equivalencies, namespace, max_depth, depth, cached_results)
       1153                 "units".format(self))
       1154             cached_results[key] = result
    -> 1155             raise result
       1156 
       1157         cached_results[key] = [self]
    
    UnitsError: Cannot represent unit TeV / m2 in terms of the given units
    
    
    
  3. mhvk commented on Dec 20, 2016

    @mhvk
    Contributor

    The failure you find puzzled me at first, but on further inspection, I see at least what happens: for any of the units provided, the compose() checks whether there are any bases in common with the unit you want to recompose. And TeV/m2 is a bit annoying, in that its decomposition is 1.60218e-07 kg / s2. Since this does not include a length, the length unit gets ignored even though you explicitly passed it in.

    Back to the more general goal: it certainly makes sense to want a specific output unit system. In principle, ideally one would define an actual system (i.e., something like cgs), and use unit.to_system(...). However, trying this, it seems that it is pretty much baked in that the system should include a mass, length, and weight.

    Looking back, I see there was some discussion of this in #703. There is also a link there to a package (http://gala.adrian.pw/en/latest/units.html) that defines a unit system. Essentially, it is simply a wrapper that allows preferred units for certain physical types. This may be helpful to get moving. In the meantime, I will mark this as a feature request.

  4. added this to the Future milestone on Dec 20, 2016
  5. removed this from the Future milestone on Apr 8, 2021
  6. mhvk commented on Apr 12, 2021

    @mhvk
    Contributor

    closing in favour of #11525

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