Source code for sofia_redux.instruments.hawc.steps.stepcalibrate
# Licensed under a 3-clause BSD style license - see LICENSE.rst
"""Flux calibration pipeline step."""
from astropy import log
from sofia_redux.calibration.pipecal_util \
import apply_fluxcal, get_fluxcal_factor
from sofia_redux.calibration.pipecal_config import pipecal_config
from sofia_redux.instruments.hawc.stepparent import StepParent
__all__ = ['StepCalibrate']
[docs]
class StepCalibrate(StepParent):
"""
Flux calibrate Stokes images.
This step multiplies the flux in each image by a calibration
factor to convert to Jy/pixel units.
It is assumed that the input data have been opacity-corrected
to a reference altitude and zenith angle, and that the factors were
derived from flux standards that were similarly corrected. This
step should be run after the
`sofia_redux.instruments.hawc.steps.StepOpacity` pipeline step.
Calibration factors are tracked and applied by configuration files and
algorithms in the `sofia_redux.calibration` package:
- `sofia_redux.calibration.pipecal_config`: `pipecal_config`
- `sofia_redux.calibration.pipecal_util`:
`get_fluxcal_factor`, `apply_fluxcal`
"""
[docs]
def setup(self):
"""
Set parameters and metadata for the pipeline step.
Output files have PRODTYPE = 'calibrate', and are named with
the step abbreviation 'CAL'.
No parameters are currently defined for this step.
"""
# Name of the pipeline reduction step
self.name = 'calibrate'
self.description = 'Calibrate Flux'
# Shortcut for pipeline reduction step and identifier for
# saved file names.
self.procname = 'cal'
# Clear Parameter list
self.paramlist = []
[docs]
def run(self):
"""
Run the data reduction algorithm.
Because this step is single-in, single-out (SISO),
self.datain must be a DataFits object. The output
is also a DataFits object, stored in self.dataout.
The process is:
1. Retrieve a calibration factor from configuration files
stored in the `sofia_redux.calibration` package.
2. Multiply flux and error images by the calibration factor.
Multiply covariance images by the calibration factor squared.
3. Set the BUNIT keyword in each extension accordingly (to
'Jy/pixel' or 'Jy2/pixel2' for covariances).
"""
# copy input to output
self.dataout = self.datain.copy()
header = self.dataout.header
# check obstype -- if standard, just continue
try:
obstype = header['OBSTYPE']
except KeyError:
obstype = 'UNKNOWN'
if str(obstype).strip().upper() == 'STANDARD_FLUX':
log.info('Flux standard; not applying calibration.')
return
# Get pipecal config
cal_conf = pipecal_config(self.dataout.header)
# Assemble extensions to correct
imgnames = self.dataout.imgnames
if 'PRIMARY IMAGE' in imgnames and 'NOISE' in imgnames:
# for scan products
extnames = ['PRIMARY IMAGE', 'NOISE']
else:
nhwp = self.dataout.getheadval('nhwp')
if nhwp == 1:
stokes = ['I']
else:
stokes = ['I', 'Q', 'U']
# flux, error, pixel covariances
extnames = []
for var in stokes:
extnames.append('STOKES %s' % var)
extnames.append('ERROR %s' % var)
# stokes covariances
if nhwp > 1:
stokes = ['Q I', 'U I', 'Q U']
for var in stokes:
extnames.append('COVAR %s' % var)
# Correct each extension
header = self.dataout.header
corrfac = None
for i, extname in enumerate(extnames):
data = self.dataout.imageget(extname)
hdr = self.dataout.getheader(extname)
if i == 0:
# correct data and write values to primary header
corrdata = apply_fluxcal(data, header, cal_conf)
corrfac, _ = get_fluxcal_factor(header, cal_conf)
if corrfac is None:
log.warning('No calibration factor found; '
'not calibrating data.')
else:
log.info('Flux calibration factor: '
'{:.4f}'.format(corrfac))
else:
if corrfac is None:
break
if 'VAR' in extname:
corrdata = data / corrfac ** 2
hdr['BUNIT'] = ('Jy2/pixel2', 'Data units')
else:
corrdata = data / corrfac
hdr['BUNIT'] = ('Jy/pixel', 'Data units')
self.dataout.imageset(corrdata, extname)