diff --git a/CHANGES.rst b/CHANGES.rst index af6e4071..96a6b855 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -13,15 +13,19 @@ New Features ------------ +sbpy.activity +^^^^^^^^^^^^^ +- New `sbpy.activity.CircularAperture.from_coma_equivalent()` to immediately + create a `CircularAperture` from any other `Aperture` given a nominal coma + surface brightness distribution. [#393] + sbpy.utils ^^^^^^^^^^ - - New `required_packages` and `optional_packages` functions to test for the presence of required and optional packages. sbpy.utils.decorators ^^^^^^^^^^^^^^^^^^^^^ - - New `requires` and `optionally_uses` function decorators to simplify testing for required and optional packages. diff --git a/docs/sbpy/activity/index.rst b/docs/sbpy/activity/index.rst index 10080ab1..01a83f57 100644 --- a/docs/sbpy/activity/index.rst +++ b/docs/sbpy/activity/index.rst @@ -16,7 +16,7 @@ Introduction Apertures --------- -Four photometric apertures are defined: +Four photometric aperture classes are defined, primarily for use with cometary comae: * `~sbpy.activity.CircularAperture`: a circle, * `~sbpy.activity.AnnularAperture`: an annulus, @@ -48,6 +48,10 @@ Ideal comae (constant production rate, free-expansion, infinite lifetime) have * >>> sba.CircularAperture(ap.coma_equivalent_radius()) # doctest: +FLOAT_CMP +Through the ``coma_equivalent_radius()`` method, all apertures may be used to initialize a ``CircularAperture`` instance using the :func:`~sbpy.activity.CircularAperture.from_coma_equivalent` method: + + >>> sba.CircularAperture.from_coma_equivalent(ap) + Reference/API ------------- diff --git a/sbpy/activity/core.py b/sbpy/activity/core.py index f03d05c6..e147ddf2 100644 --- a/sbpy/activity/core.py +++ b/sbpy/activity/core.py @@ -134,6 +134,25 @@ def coma_equivalent_radius(self): return self.radius coma_equivalent_radius.__doc__ = Aperture.coma_equivalent_radius.__doc__ + @classmethod + def from_coma_equivalent(cls, aperture): + """Initialize based on coma equivalent radius. + + + Parameters + ---------- + aperture : `Aperture` or `~sbpy.units.Quantity` + Another aperture or a radius. + + """ + + if isinstance(aperture, Aperture): + radius = aperture.coma_equivalent_radius() + else: + radius = u.Quantity(aperture) + + return cls(radius) + class AnnularAperture(Aperture): """Annular aperture projected at the distance of the target. diff --git a/sbpy/activity/dust.py b/sbpy/activity/dust.py index 62a74a64..e017669f 100644 --- a/sbpy/activity/dust.py +++ b/sbpy/activity/dust.py @@ -32,7 +32,7 @@ from .. import data as sbd from .. import units as sbu from ..spectroscopy.sources import SinglePointSpectrumError -from .core import Aperture +from .core import CircularAperture @bib.cite( @@ -337,8 +337,13 @@ def from_fluxd(cls, wfb, fluxd, aper, eph, **kwargs): """ - fluxd1cm = cls(1 * u.cm).to_fluxd(wfb, aper, - eph, unit=fluxd.unit, **kwargs) + fluxd1cm = cls(1 * u.cm).to_fluxd( + wfb, + aper, + eph, + unit=fluxd.unit, + **kwargs, + ) if isinstance(fluxd1cm, u.Magnitude): coma = cls((fluxd - fluxd1cm).physical * u.cm) @@ -380,12 +385,8 @@ def to_fluxd(self, wfb, aper, eph, unit=None, **kwargs): # rho = effective circular aperture radius at the distance of # the comet. Keep track of array dimensionality as Ephem # objects can needlessly increase the number of dimensions. - if isinstance(aper, Aperture): - rho = aper.coma_equivalent_radius() - ndim = np.ndim(rho) - else: - rho = aper - ndim = np.ndim(rho) + rho = CircularAperture.from_coma_equivalent(aper).dim + ndim = np.ndim(rho) rho = rho.to("km", sbu.projected_size(eph)) ndim = max(ndim, np.ndim(self)) diff --git a/sbpy/activity/tests/test_core.py b/sbpy/activity/tests/test_core.py index bab2731e..381ccd3a 100644 --- a/sbpy/activity/tests/test_core.py +++ b/sbpy/activity/tests/test_core.py @@ -35,6 +35,17 @@ def test_as_angle(self): angle = r.to('arcsec', sbu.projected_size(eph)) assert np.isclose(aper.as_angle(eph).dim.value, angle.value) + def test_from_coma_equivalent(self): + # test initialization from another aperture + shape = [1, 2] * u.arcsec + an_aper = AnnularAperture(shape) + circ_aper = CircularAperture.from_coma_equivalent(an_aper) + assert circ_aper.dim == 1 * u.arcsec + + # test initialization from a radius + circ_aper = CircularAperture.from_coma_equivalent(1 * u.arcsec) + assert circ_aper.dim == 1 * u.arcsec + class TestAnnularAperture: def test_str(self):