Source code for pynpoint.readwrite.fitswriting
"""
Module for exporting a dataset from the HDF5 database to a FITS file.
"""
import os
import warnings
from typing import Optional, Tuple
from astropy.io import fits
from typeguard import typechecked
import numpy as np
from pynpoint.core.processing import WritingModule
from pynpoint.util.module import memory_frames
[docs]class FitsWritingModule(WritingModule):
"""
Module for writing a dataset from the central HDF5 database to a FITS file. The static
attributes will be stored as header information. The dataset is selected from the database
by its tag name. :class:`~pynpoint.readwrite.fitswriting.FitsWritingModule` is a
:class:`~pynpoint.core.processing.WritingModule` and uses either the default output directory
of a :class:`~pynpoint.core.pypeline.Pypeline` or a specified location to store the FITS data.
"""
__author__ = 'Markus Bonse, Tomas Stolker'
@typechecked
def __init__(self,
name_in: str,
data_tag: str,
file_name: str,
output_dir: Optional[str] = None,
data_range: Optional[Tuple[int, int]] = None,
overwrite: bool = True,
subset_size: Optional[int] = None) -> None:
"""
Parameters
----------
name_in : str
Unique name of the module instance.
data_tag : str
Tag of the database entry that has to be exported to a FITS file.
file_name : str
Name of the FITS output file. Requires the FITS extension.
output_dir : str, None
Output directory where the FITS file will be stored. If no folder is specified the
Pypeline default is chosen.
data_range : tuple, None
A two element tuple which specifies a begin and end frame of the export. This can be
used to save a subsets of a large dataset. The whole dataset will be exported if set
to None.
overwrite : bool
Overwrite an existing FITS file with an identical filename.
subset_size : int, None
Size of the subsets that are created when storing the data. This can be useful if the
dataset contains a large number of images. An increasing index value is appended to
the FITS file names. All images are written to a single FITS file if set to None.
Returns
-------
NoneType
None
"""
super().__init__(name_in, output_dir=output_dir)
if not file_name.endswith('.fits'):
raise ValueError('Output \'file_name\' requires the FITS extension.')
self.m_file_name = file_name
self.m_data_port = self.add_input_port(data_tag)
self.m_range = data_range
self.m_overwrite = overwrite
self.m_subset_size = subset_size
[docs] @typechecked
def run(self) -> None:
"""
Run method of the module. Creates a FITS file and stores the data and the corresponding
static attributes.
Returns
-------
NoneType
None
"""
out_name = os.path.join(self.m_output_location, self.m_file_name)
print('Writing FITS file...', end='')
if os.path.isfile(out_name) and not self.m_overwrite:
warnings.warn('Filename already present. Use overwrite=True to overwrite an existing '
'FITS file.')
else:
header = fits.Header()
attributes = self.m_data_port.get_all_static_attributes()
for attr in attributes:
if len(attr) > 8:
# Check if the header keyword together with its value is
# too long for the FITS format. If that is the case, raise
# a warning and truncate the value to avoid a ValueError.
key = 'hierarch ' + attr
value = str(attributes[attr])
max_val_len = 75 - len(key)
if len(key + value) > 75:
warnings.warn(f'Key \'{key}\' with value \'{value}\' is too long for '
f'the FITS format. To avoid an error, the value was '
f'truncated to \'{value[:max_val_len]}\'.')
header[key] = value[:max_val_len]
else:
header[attr] = attributes[attr]
if self.m_subset_size is None:
if self.m_range is None:
frames = [0, self.m_data_port.get_shape()[0]]
else:
frames = [self.m_range[0], self.m_range[1]]
else:
if self.m_range is None:
nimages = self.m_data_port.get_shape()[0]
frames = memory_frames(self.m_subset_size, nimages)
else:
nimages = self.m_range[1] - self.m_range[0]
frames = memory_frames(self.m_subset_size, nimages)
frames = np.asarray(frames) + self.m_range[0]
for i, _ in enumerate(frames[:-1]):
data_select = self.m_data_port[frames[i]:frames[i+1], ]
if len(frames) == 2:
fits.writeto(out_name, data_select, header, overwrite=self.m_overwrite)
else:
filename = f'{out_name[:-5]}{i:03d}.fits'
fits.writeto(filename, data_select, header, overwrite=self.m_overwrite)
print(' [DONE]')
self.m_data_port.close_port()