from astropy import units as u
import itertools
__all__ = ['units_to_strings', 'create_spectral_equivalencies_list',
'create_flux_equivalencies_list', 'check_if_unit_is_per_solid_angle']
[docs]
def units_to_strings(unit_list):
"""Convert equivalencies into readable versions of the units.
Parameters
----------
unit_list : list
List of either `astropy.units` or strings that can be converted
to `astropy.units`.
Returns
-------
result : list
A list of the units with their best (i.e., most readable) string version.
"""
return [u.Unit(unit).to_string() for unit in unit_list]
[docs]
def create_spectral_equivalencies_list(spectral_axis_unit,
exclude=[u.jupiterRad, u.earthRad, u.solRad,
u.lyr, u.AU, u.pc, u.Bq, u.micron, u.lsec]):
"""Get all possible conversions from current spectral_axis_unit."""
if spectral_axis_unit in (u.pix, u.dimensionless_unscaled):
return []
# Get unit equivalencies.
try:
curr_spectral_axis_unit_equivalencies = spectral_axis_unit.find_equivalent_units(
equivalencies=u.spectral())
except u.core.UnitConversionError:
return []
# Get local units.
locally_defined_spectral_axis_units = ['Angstrom', 'nm',
'um', 'Hz', 'erg']
local_units = [u.Unit(unit) for unit in locally_defined_spectral_axis_units]
# Remove overlap units.
curr_spectral_axis_unit_equivalencies = list(set(curr_spectral_axis_unit_equivalencies)
- set(local_units + exclude))
# Convert equivalencies into readable versions of the units and sorted alphabetically.
spectral_axis_unit_equivalencies_titles = sorted(units_to_strings(
curr_spectral_axis_unit_equivalencies))
# Concatenate both lists with the local units coming first.
return sorted(units_to_strings(local_units)) + spectral_axis_unit_equivalencies_titles
[docs]
def create_flux_equivalencies_list(flux_unit, spectral_axis_unit):
"""Get all possible conversions for flux from current flux units."""
if ((flux_unit in (u.count, u.dimensionless_unscaled))
or (spectral_axis_unit in (u.pix, u.dimensionless_unscaled))):
return []
# Get unit equivalencies. Value passed into u.spectral_density() is irrelevant.
try:
curr_flux_unit_equivalencies = flux_unit.find_equivalent_units(
equivalencies=u.spectral_density(1 * spectral_axis_unit),
include_prefix_units=False)
except u.core.UnitConversionError:
return []
# Get local units.
if u.sr not in flux_unit.bases:
locally_defined_flux_units = ['Jy', 'mJy', 'uJy', 'MJy', 'Jy',
'W / (Hz m2)',
'eV / (s m2 Hz)',
'erg / (s cm2)',
'erg / (s cm2 Angstrom)',
'erg / (s cm2 Hz)',
'ph / (s cm2 Angstrom)',
'ph / (s cm2 Hz)']
local_units = [u.Unit(unit) for unit in locally_defined_flux_units]
else:
locally_defined_flux_units = ['Jy / sr', 'mJy / sr', 'uJy / sr', 'MJy / sr', 'Jy / sr',
'W / (Hz sr m2)',
'eV / (s m2 Hz sr)',
'erg / (s cm2 sr)',
'erg / (s cm2 Angstrom sr)',
'erg / (s cm2 Hz sr)',
'ph / (s cm2 Angstrom sr)',
'ph / (s cm2 Hz sr)',
'bol / sr', 'AB / sr', 'ST / sr']
local_units = [u.Unit(unit) for unit in locally_defined_flux_units]
# Remove overlap units.
curr_flux_unit_equivalencies = list(set(curr_flux_unit_equivalencies)
- set(local_units))
# Convert equivalencies into readable versions of the units and sort them alphabetically.
flux_unit_equivalencies_titles = sorted(units_to_strings(curr_flux_unit_equivalencies))
# Concatenate both lists with the local units coming first.
return sorted(units_to_strings(local_units)) + flux_unit_equivalencies_titles
[docs]
def check_if_unit_is_per_solid_angle(unit):
"""
Check if a given u.Unit or unit string (that can be converted to
a u.Unit object) represents some unit per solid angle.
Parameters
----------
unit : str or u.Unit
Unit object or string representation of unit.
Examples
--------
>>> check_if_unit_is_per_solid_angle('erg / (s cm^2 sr)')
True
>>> check_if_unit_is_per_solid_angle('erg / s cm^2')
False
>>> check_if_unit_is_per_solid_angle('Jy * sr^-1')
True
"""
# first, convert string to u.Unit obj.
# this will take care of some formatting consistency like
# turning something like Jy / (degree*degree) to Jy / deg**2
# and erg sr^1 to erg / sr
if isinstance(unit, u.core.Unit) or isinstance(unit, u.core.CompositeUnit):
unit_str = unit.to_string()
elif isinstance(unit, str):
unit = u.Unit(unit)
unit_str = unit.to_string()
else:
raise ValueError('Unit must be u.Unit, or string that can be converted into a u.Unit')
if '/' in unit_str:
# might be comprised of several units in denom.
denom = unit_str.split('/')[-1].split()
# find all combos of one or two units, to catch cases where there are two different
# units of angle in the denom that might comprise a solid angle when multiplied.
for i in [combo for length in (1, 2) for combo in itertools.combinations(denom, length)]:
# turn tuple of 1 or 2 units into a string, and turn that into a u.Unit to check type
new_unit_str = ' '.join(i).translate(str.maketrans('', '', '()'))
new_unit = u.Unit(new_unit_str)
if new_unit.physical_type == 'solid angle':
return True
return False