Skip to content

Commit

Permalink
.
Browse files Browse the repository at this point in the history
  • Loading branch information
cshanahan1 committed Nov 15, 2023
1 parent c08d270 commit a980b55
Showing 1 changed file with 87 additions and 82 deletions.
169 changes: 87 additions & 82 deletions specutils/io/default_loaders/mef_tabular_fits.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,85 +7,90 @@
import numpy as np
from astropy.table import Table

def mef_tabular_fits_writer(spectrum, file_name, hdu=0, update_header=False, **kwargs):

# no matter what the dimensionality of 'flux', there will always be a primary header and
# a single BinTableHDU extension. the `hdu` arg controls where `meta.header` is dumped.
hdulist = [fits.PrimaryHDU(), None]

if hdu > 1:
raise ValueError('`hdu`, which controls which extension `meta.header` is written to, must either be 0 or 1')

# we expect anything that should be written out to the file header to be in `meta.header`
# This should be a `fits.header.Header` object, so convert to if meta.header is a dictionary
header = spectrum.meta.get('header', fits.header.Header()) # if no meta.header, create empty `fits.header.Header`
if not isinstance(header, fits.header.Header):
if isinstance(header, dict):
header = fits.header.Header(header)
else:
raise ValueError('`Spectrum1d.meta.header must be `fits.header.Header` or dictionary.')

if update_header:
hdr_types = (str, int, float, complex, bool,
np.floating, np.integer, np.complexfloating, np.bool_)
header.update([keyword for keyword in spectrum.meta.items() if
isinstance(keyword[1], hdr_types)])

# Strip header of FITS reserved keywords
for keyword in ['NAXIS', 'NAXIS1', 'NAXIS2']:
header.remove(keyword, ignore_missing=True)

# Add dispersion array and unit
wtype = kwargs.pop('wtype', spectrum.spectral_axis.dtype)
wunit = u.Unit(kwargs.pop('wunit', spectrum.spectral_axis.unit))

disp = spectrum.spectral_axis.to(wunit, equivalencies=u.spectral())

# Mapping of spectral_axis types to header TTYPE1 (no "torque/work" types!)
dispname = str(wunit.physical_type)
if dispname == "length":
dispname = "wavelength"
elif "energy" in dispname:
dispname = "energy"

# Add flux array and unit
ftype = kwargs.pop('ftype', spectrum.flux.dtype)
funit = u.Unit(kwargs.pop('funit', spectrum.flux.unit))
flux = spectrum.flux.to(funit, equivalencies=u.spectral_density(disp))

columns = [disp.astype(wtype), flux.astype(ftype)]
colnames = [dispname, "flux"]

# Include uncertainty - units to be inferred from spectrum.flux
if spectrum.uncertainty is not None:
try:
unc = (
spectrum
.uncertainty
.represent_as(StdDevUncertainty)
.quantity
.to(funit, equivalencies=u.spectral_density(disp))
)
columns.append(unc.astype(ftype))
colnames.append("uncertainty")
except RuntimeWarning:
raise ValueError("Could not convert uncertainty to StdDevUncertainty due"
" to divide-by-zero error.")

# For > 1D data transpose from row-major format
for c in range(1, len(columns)):
if columns[c].ndim > 1:
columns[c] = columns[c].T

tab = Table(columns, names=colnames, meta=header)
hdulist[1] = fits.BinTableHDU(tab)

# now figure out where meta.header (and if specified, addl meta keys) should go
if hdu==0:
hdulist[0].header = header
else: # must otherwise be 1, we already checked this
hdulist[1].header = header

hdulist = fits.HDUList(hdulist)

hdulist.writeto(file_name)
def mef_tabular_fits_writer(spectrum, file_name='my_func_output.fits', hdu=0, update_header=False, **kwargs):

# no matter what the dimensionality of 'flux', there will always be a primary header and
# a single BinTableHDU extension. the `hdu` arg controls where `meta.header` is dumped.
hdulist = [fits.PrimaryHDU(), None]
pri_header_initial = hdulist[0].header

Check warning on line 15 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L14-L15

Added lines #L14 - L15 were not covered by tests

if hdu > 1:
raise ValueError('`hdu`, which controls which extension `meta.header` is written to, must either be 0 or 1')

Check warning on line 18 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L17-L18

Added lines #L17 - L18 were not covered by tests

# we expect anything that should be written out to the file header to be in `meta.header`
# This should be a `fits.header.Header` object, so convert to if meta.header is a dictionary
header = spectrum.meta.get('header', fits.header.Header()) # if no meta.header, create empty `fits.header.Header`

Check warning on line 22 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L22

Added line #L22 was not covered by tests

if hdu == 0:
header.update(pri_header_initial) # update with initial values created from primary header

Check warning on line 25 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L24-L25

Added lines #L24 - L25 were not covered by tests

if not isinstance(header, fits.header.Header):
if isinstance(header, dict):
header = fits.header.Header(header)

Check warning on line 29 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L27-L29

Added lines #L27 - L29 were not covered by tests
else:
raise ValueError('`Spectrum1d.meta.header must be `fits.header.Header` or dictionary.')

Check warning on line 31 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L31

Added line #L31 was not covered by tests

if update_header:
hdr_types = (str, int, float, complex, bool,

Check warning on line 34 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L33-L34

Added lines #L33 - L34 were not covered by tests
np.floating, np.integer, np.complexfloating, np.bool_)
header.update([keyword for keyword in spectrum.meta.items() if

Check warning on line 36 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L36

Added line #L36 was not covered by tests
isinstance(keyword[1], hdr_types)])

# Strip header of FITS reserved keywords
for keyword in ['NAXIS', 'NAXIS1', 'NAXIS2']:
header.remove(keyword, ignore_missing=True)

Check warning on line 41 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L40-L41

Added lines #L40 - L41 were not covered by tests

# Add dispersion array and unit
wtype = kwargs.pop('wtype', spectrum.spectral_axis.dtype)
wunit = u.Unit(kwargs.pop('wunit', spectrum.spectral_axis.unit))

Check warning on line 45 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L44-L45

Added lines #L44 - L45 were not covered by tests

disp = spectrum.spectral_axis.to(wunit, equivalencies=u.spectral())

Check warning on line 47 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L47

Added line #L47 was not covered by tests

# Mapping of spectral_axis types to header TTYPE1 (no "torque/work" types!)
dispname = str(wunit.physical_type)
if dispname == "length":
dispname = "wavelength"
elif "energy" in dispname:
dispname = "energy"

Check warning on line 54 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L50-L54

Added lines #L50 - L54 were not covered by tests

# Add flux array and unit
ftype = kwargs.pop('ftype', spectrum.flux.dtype)
funit = u.Unit(kwargs.pop('funit', spectrum.flux.unit))
flux = spectrum.flux.to(funit, equivalencies=u.spectral_density(disp))

Check warning on line 59 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L57-L59

Added lines #L57 - L59 were not covered by tests

columns = [disp.astype(wtype), flux.astype(ftype)]
colnames = [dispname, "flux"]

Check warning on line 62 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L61-L62

Added lines #L61 - L62 were not covered by tests

# Include uncertainty - units to be inferred from spectrum.flux
if spectrum.uncertainty is not None:
try:
unc = (

Check warning on line 67 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L65-L67

Added lines #L65 - L67 were not covered by tests
spectrum
.uncertainty
.represent_as(StdDevUncertainty)
.quantity
.to(funit, equivalencies=u.spectral_density(disp))
)
columns.append(unc.astype(ftype))
colnames.append("uncertainty")
except RuntimeWarning:
raise ValueError("Could not convert uncertainty to StdDevUncertainty due"

Check warning on line 77 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L74-L77

Added lines #L74 - L77 were not covered by tests
" to divide-by-zero error.")

# For > 1D data transpose from row-major format
for c in range(1, len(columns)):
if columns[c].ndim > 1:
columns[c] = columns[c].T

Check warning on line 83 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L81-L83

Added lines #L81 - L83 were not covered by tests

tab = Table(columns, names=colnames, meta=header)
hdulist[1] = fits.BinTableHDU(tab)

Check warning on line 86 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L85-L86

Added lines #L85 - L86 were not covered by tests

# now figure out where meta.header (and if specified, addl meta keys) should go
if hdu==0:
hdulist[0].header = header

Check warning on line 90 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L89-L90

Added lines #L89 - L90 were not covered by tests
else: # must otherwise be 1, we already checked this
hdulist[1].header = header

Check warning on line 92 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L92

Added line #L92 was not covered by tests

hdulist = fits.HDUList(hdulist)

Check warning on line 94 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L94

Added line #L94 was not covered by tests

hdulist.writeto(file_name)

Check warning on line 96 in specutils/io/default_loaders/mef_tabular_fits.py

View check run for this annotation

Codecov / codecov/patch

specutils/io/default_loaders/mef_tabular_fits.py#L96

Added line #L96 was not covered by tests

0 comments on commit a980b55

Please sign in to comment.