Skip to content

Commit

Permalink
Healpix doc
Browse files Browse the repository at this point in the history
fix code markdown

Update app/routes/docs.notices.healpix.mdx

Co-authored-by: Leo Singer <[email protected]>

resolve doi issue
  • Loading branch information
Vidushi-GitHub committed Dec 5, 2024
1 parent d4c4647 commit 30f6292
Showing 1 changed file with 192 additions and 0 deletions.
192 changes: 192 additions & 0 deletions app/routes/docs.client.samples.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ handle:
breadcrumb: Sample Code
---

import { Highlight } from '~/components/Highlight'
import { Tab, Tabs } from '~/components/tabs'

# Sample Code

Here is a collection of functions and example code that may be useful
Expand Down Expand Up @@ -164,3 +167,192 @@ for message in consumer.consume(end[0].offset - start[0].offset, timeout=1):
continue
print(message.value())
```

## HEALPix Sky Maps

HEALPix stands for <b>H</b>ierarchical, <b>E</b>qual <b>A</b>rea, and iso-<b>L</b>atitude <b>Pix</b>elisation is a scheme for indexing positions on the unit sphere.
For localization of events, the multi-messenger community uses the standard [HEALPix](https://healpix.sourceforge.io) format with the file extension `.fits.gz`, as well as multi-resolution HEALPix format with the file extension `.multiorder.fits`. The preferred format is the multi-resolution HEALPix format, that is only format explicitly listed in the GCN.

### Multi-Order Sky Maps

GCN strongly encourages the use of multi-order sky maps. These are a more complex form of healpix sky maps that utilize a variable resolution, with higher probability regions having higher resolution and lower probability regions being encoded with a lower resolution. This is signicantly more efficient than single-resolution healpix sky maps with respect to storage footprint and read speed. However, interpreting these multi-order sky maps can be more complex.

### Working with HEALPix Maps

HEALPix data is distrubuted in standard format with the file extension `.fits.gz`. These files are FITS image files and can be utilized with many common FITS tools. Typically, the data is stored using the HEALPix projection.

#### Reading Sky Maps

Sky maps can be parsed using python; to start, import a handful of packages (note: while this documentation covers the use of `astropy-healpix`, there are several packages that can be used for this purpose; a number of alternatives are listed at the bottom of this page)

```python
import astropy_healpix as ah
import numpy as np

from astropy import units as u
from astropy.table import QTable
```

A given sky map can then be read in as

```python
skymap = QTable.read('skymap.multiofits)
```

#### Most Probable Sky Location

The index of the highest probability point can be found by doing the following

```python
hp_index = np.argmax(skymap['PROBDENSITY'])
uniq = skymap[hq_index]['UNIQ']

level, ipix = ah.uniq_to_level_ipix(uniq)
nside = ah.level_to_nside(level)

ra, dec = ah.healpix_to_lonlat(ipix, nside, order='nested')
```

#### Probability Density at a Known Position

Similarly, one can calculate the probability density at a known position

```python
ra, dec = 197.450341598 * u.deg, -23.3814675445 * u.deg

level, ipix = ah.uniq_to_level_ipix(skymap['UNIQ'])
nside = ah.level_to_nside(level)

match_ipix = ad.lonlat_to_healpix(ra, dec, nside, order='nested')

match_index = np.flatnonzero(ipix == match_ipix)[0]

prob_density = skymap[match_index]['PROBDENSITY'].to_value(u.deg**-2)
```

#### Find the 90% Probability Region

The estimation of a 90% probability region, involves sorting the pixel, calculating the area of each pixel, and then proceeding by the probability of each pixel.

```python
#Sort the pixels by decending probability density
skymap.sort('PROBDENSITY', reverse=True)

#Area of each pixel
level, ipix = ah.uniq_to_level_ipix(skymap['UNIQ'])
pixel_area = ah.nside_to_pixel_area(ah.level_to_nside(level))

#Pixel area times the probability
prob = pixel_area * skymap['PROBDENSITY']

#Cummulative sum of probability
cumprob = np.cumsum(prob)

#Pixels for which cummulative is 0.9
i = cumprob.searchsorted(0.9)

#Sum of the areas of the pixels up to that one
area_90 = pixel_area[:i].sum()
area_90.to_value(u.deg**2)

```

#### Flat Resolution HEALPix Sky maps

Let's say you have a sky map fits file, read in Python with Healpy:

```python
import healpy as hp
import numpy as np

# Read both the HEALPix image data and the FITS header
hpx, header = hp.read_map('*.fits.gz,0', h=True)

# Plotting a Mollweide-projection all-sky map
np.mollview(hpx)
```

Most Probable Sky Location

```python
# Find the highest probability pixel
ipix_max = np.argmax(hpx)

# Probability density per square degree at that position
hpx[ipix_max] / hp.nside2pixarea(nside, degrees=True)

# Highest probability pixel on the sky
theta, phi = hp.pix2ang(nside, ipix_max)
ra = np.rad2deg(phi)
dec = np.rad2deg(0.5 * np.pi - theta)
ra, dec
```

#### Integrated probability in a Circle

We call hp.query_disc to obtain an array of indices for the pixels inside the circle.

```python
# First define the Cartesian coordinates of the center of the Circle
ra = 180.0
dec = -45.0
radius = 2.5

# We convert to spherical polar coordinates
theta = 0.5 * np.pi - np.deg2rad(dec)
phi = np.deg2rad(ra)
radius = np.deg2rad(radius)

# Calculate Cartesian coordinates of the center of the Circle
xyz = hp.ang2vec(theta, phi)

# Obtain an array of indices for the pixels inside the circle
ipix_disc = hp.query_disc(nside, xyz, radius)

# Sum the probability in all of the matching pixels:
hpx[ipix_disc].sum()

```

#### Integrated probability in a Polygon

We can use the `hp.query_polygon` function to find the pixels inside a polygon and compute the probability that the source is inside the polygon by adding up the pixel values.

```python
# Indices of the pixels within a polygon (defined by the Cartesian coordinates of its vertices)

xyz = [[-0.5, -0.4, -0.5],
[-0.4, -0.4, -0.6],
[-0.6, -0.3, -0.6],
[-0.7 , -0.4, -0.5]]
ipix_poly = hp.query_polygon(nside, xyz)
hpx[ipix_poly].sum()
```

##### Further documentation

Additional information can be found on the [LIGO website](https://emfollow.docs.ligo.org/userguide/tutorial/multiorder_sky maps.html)

[healpy](https://healpy.readthedocs.io/en/latest/): Official python library for handling the pixlated data on sphere

[astropy-healpix](https://pypi.org/project/astropy-healpix/): Integrates HEALPix with Astropy for data manipulation and analysis

[mhealpy](https://mhealpy.readthedocs.io/en/latest/): Object-oriented wrapper of healpy for handling the multi-resolution maps

[MOCpy](https://cds-astro.github.io/mocpy/): Python library allowing easy creation, parsing and manipulation of Multi-Order Coverage maps.

## Papers

(1) Calabretta, M. R., & Roukema, B. F. 2007, Mon. Notices Royal Astron. Soc., 381, 865. [doi: 10.1111/j.1365-2966.2007.12297.x](https://doi.org/10.1111/j.1365-2966.2007.12297.x)

(2) Górski, K.M., Hivon, E., Banday, A.J., et al. 2005, Astrophys. J., 622, 759. [doi: 10.1086/427976](https://doi.org/10.1086/427976)

(3) Górski, K. M., Wandelt, B. D., et al. 1999. [doi: 10.48550/arXiv.astro-ph/9905275](https://doi.org/10.48550/arXiv.astro-ph/9905275)

(4) Fernique, P., Allen, et al. 2015, Astron. Astrophys., 578, A114. [doi: 10.1051/0004-6361/201526075](https://doi.org/10.1051/0004-6361/201526075)

(5) Fernique, P., Boch, T., et al. 2014, IVOA Recommendation. [doi: 10.48550/arXiv.1505.02937](https://doi.org/10.48550/arXiv.1505.02937)

(6) Martinez-Castellanos, I., Singer, L. P., et al. 2022, Astrophys. J., 163, 259. [doi: 10.3847/1538-3881/ac6260](https://doi.org/10.3847/1538-3881/ac6260)

(7) Singer, L. P., & Price, L. R. 2016, Phys. Rev. D, 93, 024013. [doi: 10.1103/PhysRevD.93.024013](https://doi.org/10.1103/PhysRevD.93.024013)

0 comments on commit 30f6292

Please sign in to comment.