Skip to content

Allow units to have multiple physical types #11202

Closed

Description

@namurphy

Description

The physical_type attribute for UnitBase instances currently returns a string that describes what a particular unit measures:

>>> import astropy.units as u
>>> (u.barn * u.Mpc).physical_type
'volume'

However, sometimes a set of units corresponds to multiple physical types. For example, a 1 Pa ≡ 1 J · m-3, so a pascal can represent both pressure and energy density. In addition, a kessel run can be retconned from distance to time.

Units to physical type is not a one-to-one mapping. Each set of units can map to multiple physical types. Each physical type should usually map to one set of units, though there can be some exceptions to this (for example, the temperature_energy equivalency that lets eV represent energy as well as temperature).

I propose that we enable each unit to correspond to multiple physical types instead of limiting them to a single physical type. This would change backward compatibility.

Draft design and brainstorm for the API

A possibility would be to create a PhysicalType class. Instances of PhysicalType could be created for each set of units and become the physical_type attribute, and contain a collection of all of the possible physical types that each set of units could have.

Essential behavior of physical_type attribute

I'd like to allow the following behavior.

>>> import astropy.units as u
>>> u.Pa.physical_type 
"pressure, energy density"
>>> u.Pa.physical_type  # not sure if this should be a list or str
["pressure", "energy density"]
>>> u.Pa.physical_type == "pressure"
True
>>> u.Pa.physical_type == "energy_density"
True

The last two lines would require defining PhysicalType.__eq__ to be able to handle multiple physical types (e.g., by making sure "pressure" or "energy" is in the collection of physical types).

Handling equivalencies

The physical type will also depend on which equivalencies are enabled.

>>> u.eV.physical_type == "temperature"
False
>>> u.set_enabled_equivalencies(u.temperature_energy())
>>> u.eV.physical_type == "temperature"
True

Allowing users to specify the physical type for units or quantities

It would also be helpful for users to be able to specify the physical type in more detail. I'm not sure if this would be best done for units or quantities, and I have a feeling this could be more difficult to implement. A possible API for the unit approach would be:

>>> specific_pressure_unit = create_unit_with_specific_physical_type(u.Pa, physical_type="pressure")
>>> specific_pressure_unit.physical_type = "pressure"
>>> specific_pressure_unit.physical_type == "energy density"
False
>>> u.Pa.physical_type == "energy density"  # we don't want to change the physical type of the original unit
True

For a Quantity instance, this could be something like

>>> pressure = u.Quantity(1.0, u.Pa, physical_type="pressure")
>>> pressure.physical_type == "pressure"
True
>>> pressure.physical_type == "energy density"
False

It appears that Quantity does not have a physical_type attribute so this would be particularly new.

Activity

  1. pllim commented on Dec 31, 2020

    @pllim
    Member

    cc @mhvk and @adrn

  2. namurphy commented on Dec 31, 2020

    @namurphy
    ContributorAuthor

    The reason why this issue came about is that, for PlasmaPy, I was thinking that it'd be useful to have a way for a user to provide a physical type, and then get the appropriate SI units for that physical type. My strategy up until now has been to do a web search which often works, but sometimes I end up going to the Wikipedia article on dynamic viscosity and then somehow find myself reading Wikipedia articles on Star Trek: The Animated Series. Functionality along these lines would be really helpful for dimensional analysis too.

    Edited to add links to relevant Wikipedia articles.

  3. mhvk commented on Dec 31, 2020

    @mhvk
    Contributor

    One suggestion would be to have only a master dict from physical_type to unit (or physical type ID). We could then still have a PhysicalType class, but equality would be something like

    def __eq__(self, other):
        return _unit_physical_mapping[self] == _unit_physical_mapping[other]
    

    We might then not have a dict keyed by unit, but rather let get_physical_type filter keys whose values are the correct unit/physical-type-ID. (One might return a set.)

  4. mhvk commented on Dec 31, 2020

    @mhvk
    Contributor

    p.s. I also like the idea of equivalencies working. In that case, equality should really be more like

    def __eq__(self, other):
        return self.unit.is_equivalent(other.unit)
    

    (where .unit can re-infer the unit from the physical type ID if necessary)

  5. namurphy commented on Dec 31, 2020

    @namurphy
    ContributorAuthor

    One suggestion would be to have only a master dict from physical_type to unit (or physical type ID).

    We might then not have a dict keyed by unit, but rather let get_physical_type filter keys whose values are the correct unit/physical-type-ID. (One might return a set.)

    @mhvk — I like these ideas! Using a dict behind the scenes and returning a set both sound sensible to me.

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