telescope: Astronomical Observations (FITS, ASDF, WCS, etc)

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

Work with astronomical observations from modern telescopes


[Skip to Readme]

Properties

Versions 0.2.0, 0.3.0, 0.3.0, 0.4.0
Change log None available
Dependencies base (>=4.18 && <5), binary (>=0.8.9 && <0.9), byte-order (>=0.1.3 && <0.2), bytestring (>=0.11 && <0.13), casing (>=0.1.4 && <0.2), conduit (>=1.3 && <1.4), effectful (>=2.3 && <3), exceptions (>=0.10 && <0.11), libyaml (>=0.1.4 && <0.2), massiv (>=1.0 && <1.1), massiv-io (>=1.0 && <1.1), megaparsec (>=9.6 && <9.7), resourcet-effectful (>=1.0.1 && <1.1), scientific (>=0.3 && <0.4), text (>=2.0 && <3), time (>=1.12 && <2) [details]
License BSD-3-Clause
Copyright (c) 2024 Sean Hess
Author Sean Hess
Maintainer Sean Hess <shess@nso.edu>
Category Science, Astronomy
Home page https://github.com/dkistdc/telescope.hs
Uploaded by seanhess at 2025-06-27T16:13:17Z

Modules

[Index] [Quick Jump]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees


Readme for telescope-0.3.0

[back to package description]

Telescope

Hackage Version

Haskell library to work with scientific data files commonly used in astronomy

FITS Example

import Telescope.Fits
import Data.ByteString qualified as BS

main :: IO ()
main = do
  inp <- BS.readFile "hubble.fits"
  fits <- decode inp

FITS files start with a primary Header Data Unit

  print fits.primaryHDU
DataHDU
  Header: 490 records
  data: 0 bytes
  dimensions:
    format: Int8
    axes: []

HDUs may contain both data and a header

  print fits.primaryHDU.header
SIMPLE  =                    T / conforms to FITS standard
BITPIX  =                    8 / array data type
NAXIS   =                    0 / number of array dimensions
EXTEND  =                    T
DATE    = '2009-11-10'         / date this file was written (yyyy-mm-dd)
FILETYPE= 'SCI'                / type of data found in data file

TELESCOP= 'HST'                / telescope used to acquire data
INSTRUME= 'WFPC2'              / identifier for instrument used to acquire data
EQUINOX =               2000.0 / equinox of celestial coord. system
...

The primary HDU is followed by multiple extensions in a similar format

  mapM_ print fits.extensions
Image: DataHDU
  Header: 103 records
  data: 12960000 bytes
  dimensions:
    format: Float
    axes: [1800,1800]

Image: DataHDU
  Header: 124 records
  data: 12960000 bytes
  dimensions:
    format: Float
    axes: [1800,1800]

Image: DataHDU
  Header: 123 records
  data: 12960000 bytes
  dimensions:
    format: Int32
    axes: [1800,1800]

We can use Array from Data.Massiv to parse, manipulate, and display data

  Image img : _ <- pure fits.extensions
  arr <- decodeDataArray @Ix2 @Float img.dataArray
  writeImage "hubble1.png" (heatmap arr)

Hubble Output

Parsing Headers

Parse header keywords into Haskell records

import Telescope.Fits
import Effectful

data HubbleInfo = HubbleInfo
  { telescop :: Text
  , instrume :: Text
  , equinox :: Float
  } deriving (Generic, FromHeader, ToHeader)

main = do
  ...
  let h = fits.primaryHDU.header
  print $ lookupKeyword "INSTRUME" h

  case runPureEff $ runParser $ parseHeader h of
    Left e -> fail $ show e
    Right info -> do
      print info.telescop
      print info.equinox

ASDF Example

ASDF files contain a YAML tree and binary data afterwards. They are readable and the tree is editable in a text editor.

example :: IO ()
example = do
  inp <- BS.readFile "../samples/dkist.asdf"
  dset :: Dataset <- decodeM inp
  print dset.info

data DKISTInfo = DKISTInfo
  { instrumentName :: Text
  , frameCount :: Int
  }
  deriving (Show, Generic, FromAsdf)


data Dataset = Dataset
  { info :: DKISTInfo
  }
instance FromAsdf Dataset where
  -- parse .dataset.meta.inventory into DKISTInfo
  parseValue val =
    case val of
      Object o -> do
        dset <- o .: "dataset"
        meta <- dset .: "meta"
        info <- meta .: "inventory"
        pure $ Dataset info
      k -> expected "Object" k
DKISTInfo {instrumentName = "VISP", frameCount = 1960}

Data can be parsed directly from the YAML tree or from binary-encoded data blocks (an NDArray)

data Example = Example
  { foo :: Int32
  , powers :: Maybe Powers
  , sequence :: [Int64]
  , random :: Array D Ix1 Double
  }
  deriving (Generic, FromAsdf)

example :: IO ()
example = do
  inp <- BS.readFile "../samples/example.asdf"
  ex :: Example <- decodeM inp
  print ex.name
  print ex.items
  print $ take 30 ex.sequence
  print $ take 10 $ M.toList ex.random
"Monty"
["one","two","three","four","five"]
[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29]
[0.7842310832387069,0.2279459557291822,0.9534462812074139,0.5100515929833191,0.6597920763222204,0.8778040169160855,0.8079416746447109,0.5373925949744411,0.5169365152585088,0.436101639340324]

Getting Raw Telescope Data

Attributions

National Solar Observatory

FITS code was developed in collaboration with @krakrjak