astropy / regions

Astropy package for region handling
https://astropy-regions.readthedocs.io
BSD 3-Clause "New" or "Revised" License
61 stars 55 forks source link

Introduce SkyRegion.solid_angle #434

Open adonath opened 2 years ago

adonath commented 2 years ago

The PixelRegion already defines an .area property. It would be nice to see the equivalent SkyRegion.solid_angle property.

adonath commented 2 years ago

I guess technically this might not be simple to achieve. While of course for some regions once can rely on analytical expressions, one would still need a numerical approximations in other situations. In any case https://mathworld.wolfram.com/LHuiliersTheorem.html is useful...

larrybradley commented 2 years ago

I'm not sure how this would work because the sky-based regions are simple representations that preserve the shape. They aren't shapes in spherical coordinates, but more like cartesian shapes in a tangent plane (a circle in pixel coordinates converts to a circle in sky coordinates based only on the pixel scale). Does a solid angle make sense for non-spherical coordinates?

adonath commented 2 years ago

Thanks for the feedback @larrybradley! Yes, I now remember that methods like SkyRegion.contains() actually require a wcs to handle the projection to the plane. However I think .solid_angle() could be maybe supported in a similar way?

def solid_angle(self, wcs, mode): """Solid angle enclosed by the region (astropy.units.Quantity)""" region_pix = self.to_pix(wcs=wcs) mask = region_pix.to_mask(mode="exact")

solid_angle_array = compute_solid_angle_array_from_wcs(wcs, shape=mask.data.shape)

return np.sum(mask.data * solid_angle_array)
tjgalvin commented 2 years ago

I would be very curious to see how this progresses. Is there a currently utility to compute the area of a pixel for some arbitary position anywhere? I know of something in astropy wcs, but that performs this at the reference pixel exclusively. I'd would try to help out but not really sure where to start.

adonath commented 2 years ago

@tjgalvin We have something like this in gammapy.maps:

from gammapy.maps import WcsGeom
from astropy import units as u
from astropy.coordinates import SkyCoord

center = SkyCoord("0d", "0d", frame="galactic")

geom = WcsGeom.create(
    skydir=center,
    binsz=0.1,
    width=[10, 8] * u.deg
)
geom.solid_angle()

Which returns an array of solid angle per pixel, computed using L'Huilllers theorem.