Skip to content

Commit

Permalink
Merge 1178482 into d51a777
Browse files Browse the repository at this point in the history
  • Loading branch information
nmearl committed Nov 2, 2018
2 parents d51a777 + 1178482 commit 43abf83
Show file tree
Hide file tree
Showing 15 changed files with 667 additions and 51 deletions.
7 changes: 6 additions & 1 deletion docs/custom_loading.rst
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ ensure that the data file being loaded is compatible with the loader function.
os.path.splitext(args[0].lower())[1] == '.fits')
@data_loader("my-format", identifier=identify_generic_fits)
@data_loader("my-format", identifier=identify_generic_fits,
extensions=['fits'])
def generic_fits(file_name, **kwargs):
name = os.path.basename(file_name.rstrip(os.sep)).rsplit('.', 1)[0]
Expand All @@ -94,6 +95,10 @@ ensure that the data file being loaded is compatible with the loader function.
return Spectrum1D(flux=data, wcs=wcs, uncertainty=uncertainty, meta=meta)
An ``extensions`` keyword can be provided. This allows for basic filename
extension matching in the case that the ``identifier`` function is not
provided.

After placing this python file in the user's ``~/.specutils`` directory, it
can be utilized by referencing its name in the ``read`` method of the
:class:`~specutils.Spectrum1D` class
Expand Down
179 changes: 179 additions & 0 deletions specutils/io/default_loaders/apogee.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
"""
Loader for APOGEE spectrum files: apVisit_, apStar_, aspcapStar_ files.
.. _apVisit: https://data.sdss.org/datamodel/files/APOGEE_REDUX/APRED_VERS/TELESCOPE/PLATE_ID/MJD5/apVisit.html
.. _apStar: https://data.sdss.org/datamodel/files/APOGEE_REDUX/APRED_VERS/APSTAR_VERS/TELESCOPE/LOCATION_ID/apStar.html
.. _aspcapStar: https://data.sdss.org/datamodel/files/APOGEE_REDUX/APRED_VERS/APSTAR_VERS/ASPCAP_VERS/RESULTS_VERS/LOCATION_ID/aspcapStar.html
"""
import os

from astropy.io import fits
from astropy.table import Table
from astropy.wcs import WCS
from astropy.units import Unit, def_unit
from astropy.nddata import StdDevUncertainty

import numpy as np

from specutils.io.registers import data_loader, custom_writer
from specutils import Spectrum1D

__all__ = ['apVisit_identify', 'apStar_identify', 'aspcapStar_identify',
'apVisit_loader', 'apStar_loader', 'aspcapStar_loader']


def apVisit_identify(origin, *args, **kwargs):
"""
Check whether given filename is FITS. This is used for Astropy I/O
Registry.
"""
return (isinstance(args[0], str) and
args[0].lower().split('.')[-1] == 'fits' and
args[0].startswith('apVisit'))


def apStar_identify(origin, *args, **kwargs):
"""
Check whether given filename is FITS. This is used for Astropy I/O
Registry.
"""
return (isinstance(args[0], str) and
args[0].lower().split('.')[-1] == 'fits' and
args[0].startswith('apStar'))


def aspcapStar_identify(origin, *args, **kwargs):
"""
Check whether given filename is FITS. This is used for Astropy I/O
Registry.
"""
return (isinstance(args[0], str) and
args[0].lower().split('.')[-1] == 'fits' and
args[0].startswith('aspcapStar'))


@data_loader(label="APOGEE apVisit", identifier=apVisit_identify, extensions=['fits'])
def apVisit_loader(file_name, **kwargs):
"""
Loader for APOGEE apVisit files.
Parameters
----------
file_name: str
The path to the FITS file
Returns
-------
data: Spectrum1DRef
The data.
"""
name = os.path.basename(file_name.rstrip(os.sep)).rsplit('.', 1)[0]
hdulist = fits.open(file_name, **kwargs)

header = hdulist[0].header
meta = {'header': header}

# spectrum is stored in three rows (for three chips)
data = np.concatenate([hdulist[1].data[0, :],
hdulist[1].data[1, :],
hdulist[1].data[2, :]])
unit = Unit('1e-17 erg / (Angstrom cm2 s)')

stdev = np.concatenate([hdulist[2].data[0, :],
hdulist[2].data[1, :],
hdulist[2].data[2, :]])
uncertainty = StdDevUncertainty(stdev * unit)

# Dispersion is not a simple function in these files. There's a
# look-up table instead.
dispersion = np.concatenate([hdulist[4].data[0, :],
hdulist[4].data[1, :],
hdulist[4].data[2, :]])
dispersion_unit = Unit('Angstrom')
hdulist.close()

return Spectrum1D(data=data * unit,
uncertainty=uncertainty,
dispersion=dispersion * dispersion_unit,
meta=meta)


@data_loader(label="APOGEE apStar", identifier=apStar_identify, extensions=['fits'])
def apStar_loader(file_name, **kwargs):
"""
Loader for APOGEE apStar files.
Parameters
----------
file_name: str
The path to the FITS file
Returns
-------
data: Spectrum1DRef
The data.
"""
name = os.path.basename(file_name.rstrip(os.sep)).rsplit('.', 1)[0]
hdulist = fits.open(file_name, **kwargs)

header = hdulist[0].header
meta = {'header': header}
wcs = WCS(hdulist[1].header)

data = hdulist[1].data[0, :] # spectrum in the first row of the first extension
unit = Unit('1e-17 erg / (Angstrom cm2 s)')

uncertainty = StdDevUncertainty(hdulist[2].data[0, :])

# dispersion from the WCS but convert out of logspace
# dispersion = 10**wcs.all_pix2world(np.arange(data.shape[0]), 0)[0]
dispersion = 10**wcs.all_pix2world(np.vstack((np.arange(data.shape[0]),
np.zeros((data.shape[0],)))).T,
0)[:, 0]
dispersion_unit = Unit('Angstrom')
hdulist.close()

return Spectrum1D(data=data * unit,
uncertainty=uncertainty,
dispersion=dispersion * dispersion_unit,
meta=meta,
wcs=wcs)


@data_loader(label="APOGEE aspcapStar", identifier=aspcapStar_identify, extensions=['fits'])
def aspcapStar_loader(file_name, **kwargs):
"""
Loader for APOGEE aspcapStar files.
Parameters
----------
file_name: str
The path to the FITS file
Returns
-------
data: Spectrum1DRef
The data.
"""
name = os.path.basename(file_name.rstrip(os.sep)).rsplit('.', 1)[0]
hdulist = fits.open(file_name, **kwargs)

header = hdulist[0].header
meta = {'header': header}
wcs = WCS(hdulist[1].header)

data = hdulist[1].data # spectrum in the first extension
unit = def_unit('arbitrary units')

uncertainty = StdDevUncertainty(hdulist[2].data)

# dispersion from the WCS but convert out of logspace
dispersion = 10**wcs.all_pix2world(np.arange(data.shape[0]), 0)[0]
dispersion_unit = Unit('Angstrom')
hdulist.close()

return Spectrum1D(data=data * unit,
uncertainty=uncertainty,
dispersion=dispersion * dispersion_unit,
meta=meta,
wcs=wcs)
114 changes: 114 additions & 0 deletions specutils/io/default_loaders/ascii.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import os

import astropy.units as u
from astropy.nddata import StdDevUncertainty
from astropy.table import Table

from specutils import Spectrum1D
from specutils.io.registers import data_loader

__all__ = ['ascii_identify', 'ascii_loader', 'ipac_identify', 'ipac_loader']


def ascii_identify(origin, *args, **kwargs):
"""Check if it's an ASCII file."""
name = os.path.basename(args[0])

if name.lower().split('.')[-1] in ['txt', 'ascii']:
return True

return False


@data_loader(label="ASCII", identifier=ascii_identify, extensions=['txt', 'ascii'])
def ascii_loader(file_name, **kwargs):
"""
Load spectrum from ASCII file
Parameters
----------
file_name: str
The path to the ASCII file
Returns
-------
data: Spectrum1D
The data.
"""
table = Table.read(file_name, format='ascii')

flux = None
dispersion = None
uncertainty = None

# If there are more than two columns, assume that the first is wavelength,
# and the second is flux
if len(table.columns) > 1:
disp_unit = u.Unit("Angstrom")
dispersion = table.columns[0] * disp_unit

unit = u.Unit("Jy")
flux = table.columns[1] * unit

# If there are more than two columns, assume the third is uncertainty
if len(table.columns) >= 2:
uncertainty = StdDevUncertainty(table.columns[2] * unit)
# If there is only one column, assume it's just flux.
elif len(table.columns) == 1:
unit = u.Unit("Jy")
flux = table.columns[0] * unit

return Spectrum1D(flux=flux,
spectral_axis=dispersion,
meta=table.meta,
uncertainty=uncertainty)


def ipac_identify(*args, **kwargs):
"""Check if it's an ASCII file."""
name = os.path.basename(args[0])

if name.lower().split('.')[-1] in ['txt', 'dat']:
return True

return False


@data_loader(label="IPAC", identifier=ipac_identify, extensions=['txt', 'dat'])
def ipac_loader(file_name, **kwargs):
"""
Load spectrum from ASCII file
Parameters
----------
file_name: str
The path to the ASCII file
Returns
-------
data: Spectrum1D
The data.
"""
table = Table.read(file_name, format='ascii.ipac')

flux = None
dispersion = None
uncertainty = None

# If there are more than two columns, assume that the first is wavelength,
# and the second is flux
if len(table.columns) > 1:
dispersion = u.Quantity(table.columns[0])
flux = u.Quantity(table.columns[1])

# If there are more than two columns, assume the third is uncertainty
if len(table.columns) >= 2:
uncertainty = StdDevUncertainty(u.Quantity(table.columns[2]))
# If there is only one column, assume it's just flux.
elif len(table.columns) == 1:
flux = u.Quantity(table.columns[0])

return Spectrum1D(flux=flux,
spectral_axis=dispersion,
meta=table.meta,
uncertainty=uncertainty)
2 changes: 1 addition & 1 deletion specutils/io/default_loaders/cube_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def identify_generic_fits(origin, *args, **kwargs):
fits.getheader(args[0])['NAXIS'] == 3)


@data_loader("cubetest1", identifier=identify_generic_fits)
@data_loader("cubetest1", identifier=identify_generic_fits, extensions=['fits'])
def generic_fits(file_name, **kwargs):
name = os.path.basename(file_name.rstrip(os.sep)).rsplit('.', 1)[0]

Expand Down
45 changes: 45 additions & 0 deletions specutils/io/default_loaders/ecsv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import os

from astropy.table import Table

from specutils.io.registers import data_loader, custom_writer
from specutils import Spectrum1D

__all__ = ['ecsv_identify', 'ecsv_spectrum_loader']


def ecsv_identify(origin, *args, **kwargs):
"""Check if it's an ECSV file."""
name = os.path.basename(args[0])

if name.lower().split('.')[-1] == 'ecsv':
return True

return False


@data_loader(label="Spectrum ECSV", identifier=ecsv_identify, extensions=['ecsv'])
def ecsv_spectrum_loader(file_name, **kwargs):
"""
Load spectrum from ECSV file
Parameters
----------
file_name: str
The path to the ECSV file
Returns
-------
data: Spectrum1D
The data.
"""
table = Table.read(file_name, format='ascii.ecsv')

unit = table['Intensity'].unit
disp_unit = table['Wavelength'].unit
flux = table['Intensity'] * unit
dispersion = table['Wavelength'] * disp_unit

return Spectrum1D(flux=flux,
spectral_axis=dispersion,
meta=table.meta)
Loading

0 comments on commit 43abf83

Please sign in to comment.