Skip to content

Commit

Permalink
Units cleanup (#3204)
Browse files Browse the repository at this point in the history
* defined pix2 unit, define supported units in one place, added test
  • Loading branch information
cshanahan1 authored Sep 30, 2024
1 parent f48bc16 commit f880d55
Show file tree
Hide file tree
Showing 16 changed files with 359 additions and 300 deletions.
37 changes: 11 additions & 26 deletions jdaviz/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@
from jdaviz.utils import (SnackbarQueue, alpha_index, data_has_valid_wcs, layer_is_table_data,
MultiMaskSubsetState, _wcs_only_label, flux_conversion,
spectral_axis_conversion)
from jdaviz.core.validunits import check_if_unit_is_per_solid_angle
from jdaviz.core.validunits import (check_if_unit_is_per_solid_angle,
combine_flux_and_angle_units,
locally_defined_flux_units,
supported_sq_angle_units)

__all__ = ['Application', 'ALL_JDAVIZ_CONFIGS', 'UnitConverterWithSpectral']

Expand All @@ -72,32 +75,14 @@ class UnitConverterWithSpectral:
def equivalent_units(self, data, cid, units):
if cid.label == "flux":
eqv = u.spectral_density(1 * u.m) # Value does not matter here.
list_of_units = set(list(map(str, u.Unit(units).find_equivalent_units(
include_prefix_units=True, equivalencies=eqv)))
+ [
'Jy', 'mJy', 'uJy', 'MJy',
'W / (Hz m2)', 'eV / (Hz s m2)',
'erg / (Hz s cm2)', 'erg / (Angstrom s cm2)',
'ph / (Angstrom s cm2)', 'ph / (Hz s cm2)',
'ct'
]
+ [
'Jy / sr', 'mJy / sr', 'uJy / sr', 'MJy / sr',
'W / (Hz sr m2)', 'eV / (Hz s sr m2)',
'erg / (s sr cm2)', 'erg / (Hz s sr cm2)',
'erg / (Angstrom s sr cm2)',
'ph / (Angstrom s sr cm2)', 'ph / (Hz s sr cm2)',
'ct / sr'
]
+ [
'Jy / pix2', 'mJy / pix2', 'uJy / pix2', 'MJy / pix2',
'W / (Hz m2 pix2)', 'eV / (Hz s m2 pix2)',
'erg / (s cm2 pix2)', 'erg / (Hz s cm2 pix2)',
'erg / (Angstrom s cm2 pix2)',
'ph / (Angstrom s cm2 pix2)', 'ph / (Hz s cm2 pix2)',
'ct / pix2'
]
all_flux_units = locally_defined_flux_units() + ['ct']
angle_units = supported_sq_angle_units()
all_sb_units = combine_flux_and_angle_units(all_flux_units, angle_units)

# list of all possible units for spectral y axis, independent of data loaded
#
list_of_units = set(list(map(str, u.Unit(units).find_equivalent_units(
include_prefix_units=True, equivalencies=eqv))) + all_flux_units + all_sb_units
)
else: # spectral axis
# prefer Hz over Bq and um over micron
Expand Down
9 changes: 5 additions & 4 deletions jdaviz/configs/cubeviz/plugins/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from astropy.wcs import WCS
from specutils import Spectrum1D, SpectralAxis

from jdaviz.core.custom_units import PIX2
from jdaviz.core.registries import data_parser_registry
from jdaviz.core.validunits import check_if_unit_is_per_solid_angle
from jdaviz.utils import standardize_metadata, PRIHDR_KEY, download_uri_to_path
Expand Down Expand Up @@ -195,9 +196,9 @@ def _return_spectrum_with_correct_units(flux, wcs, metadata, data_type=None,
# convert flux and uncertainty to per-pix2 if input is not a surface brightness
if apply_pix2:
if not check_if_unit_is_per_solid_angle(flux.unit):
flux = flux / (u.pix * u.pix)
flux = flux / PIX2
if uncertainty is not None:
uncertainty = uncertainty / (u.pix * u.pix)
uncertainty = uncertainty / PIX2

# handle scale factors when they are included in the unit
if not np.isclose(flux.unit.scale, 1.0, rtol=1e-5):
Expand Down Expand Up @@ -606,14 +607,14 @@ def convert_spectrum1d_from_flux_to_flux_per_pixel(spectrum):

# convert flux, which is always populated
flux = getattr(spectrum, 'flux')
flux = flux / (u.pix * u.pix)
flux = flux / PIX2

# and uncerts, if present
uncerts = getattr(spectrum, 'uncertainty')
if uncerts is not None:
# enforce common uncert type.
uncerts = uncerts.represent_as(StdDevUncertainty)
uncerts = StdDevUncertainty(uncerts.quantity / (u.pix * u.pix))
uncerts = StdDevUncertainty(uncerts.quantity / PIX2)

# create a new spectrum 1d with all the info from the input spectrum 1d,
# and the flux / uncerts converted from flux to SB per square pixel
Expand Down
14 changes: 8 additions & 6 deletions jdaviz/configs/cubeviz/plugins/tests/test_cubeviz_aperphot.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
from numpy.testing import assert_allclose
from regions import RectanglePixelRegion, PixCoord

from jdaviz.core.custom_units import PIX2


def test_cubeviz_aperphot_cube_orig_flux(cubeviz_helper, image_cube_hdu_obj_microns):
cubeviz_helper.load_data(image_cube_hdu_obj_microns, data_label="test")
flux_unit = u.Unit("1E-17 erg*s^-1*cm^-2*Angstrom^-1*pix^-2") # actually a sb
solid_angle_unit = u.pix * u.pix
solid_angle_unit = PIX2

aper = RectanglePixelRegion(center=PixCoord(x=1, y=2), width=3, height=5)
cubeviz_helper.plugins['Subset Tools']._obj.import_region(aper)
Expand Down Expand Up @@ -99,7 +101,7 @@ def test_cubeviz_aperphot_cube_orig_flux(cubeviz_helper, image_cube_hdu_obj_micr
def test_cubeviz_aperphot_generated_3d_gaussian_smooth(cubeviz_helper, image_cube_hdu_obj_microns):
cubeviz_helper.load_data(image_cube_hdu_obj_microns, data_label="test")
flux_unit = u.Unit("1E-17 erg*s^-1*cm^-2*Angstrom^-1*pix^-2") # actually a sb
solid_angle_unit = u.pix * u.pix
solid_angle_unit = PIX2

gauss_plg = cubeviz_helper.plugins["Gaussian Smooth"]._obj
gauss_plg.mode_selected = "Spatial"
Expand Down Expand Up @@ -133,7 +135,7 @@ def test_cubeviz_aperphot_generated_3d_gaussian_smooth(cubeviz_helper, image_cub
assert_quantity_allclose(row["slice_wave"], 4.894499866699333 * u.um)


@pytest.mark.parametrize("cube_unit", [u.MJy / u.sr, u.MJy, u.MJy / (u.pix*u.pix)])
@pytest.mark.parametrize("cube_unit", [u.MJy / u.sr, u.MJy, u.MJy / PIX2])
def test_cubeviz_aperphot_cube_sr_and_pix2(cubeviz_helper,
spectrum1d_cube_custom_fluxunit,
cube_unit):
Expand Down Expand Up @@ -173,7 +175,7 @@ def test_cubeviz_aperphot_cube_sr_and_pix2(cubeviz_helper,
# so we can directly compare. this shouldn't be populated automatically,
# which is checked above
plg.flux_scaling = 0.003631
solid_angle_unit = u.pix * u.pix
solid_angle_unit = PIX2
cube_unit = u.MJy / solid_angle_unit # cube unit in app is now per pix2

plg.vue_do_aper_phot()
Expand All @@ -185,7 +187,7 @@ def test_cubeviz_aperphot_cube_sr_and_pix2(cubeviz_helper,
# (15 - 10) MJy/sr x 1 sr, will always be MJy since solid angle is multiplied out
assert_allclose(row["sum"], 5.0 * u.MJy)

assert_allclose(row["sum_aper_area"], 1 * (u.pix * u.pix))
assert_allclose(row["sum_aper_area"], 1 * PIX2)

# we forced area to be one sr so MJy / sr and MJy / pix2 gave the same result
assert_allclose(row["pixarea_tot"], 1.0 * solid_angle_unit)
Expand Down Expand Up @@ -226,7 +228,7 @@ def test_cubeviz_aperphot_cube_orig_flux_mjysr(cubeviz_helper, spectrum1d_cube_c
assert_allclose(row["xcenter"], 3 * u.pix)
assert_allclose(row["ycenter"], 1 * u.pix)
assert_allclose(row["sum"], 1.1752215e-12 * u.MJy) # (15 - 10) MJy/sr x 2.3504431e-13 sr
assert_allclose(row["sum_aper_area"], 1 * (u.pix * u.pix))
assert_allclose(row["sum_aper_area"], 1 * PIX2)
assert_allclose(row["pixarea_tot"], 2.350443053909789e-13 * u.sr)
assert_allclose(row["aperture_sum_mag"], 23.72476627732448 * u.mag)
assert_allclose(row["mean"], 5 * (u.MJy / u.sr))
Expand Down
Loading

0 comments on commit f880d55

Please sign in to comment.