import logging
from collections import OrderedDict
import numpy as np
from .. import datamodels
from . import gwcs_drizzle
from . import resample_utils
from ..model_blender import blendmeta
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
__all__ = ["ResampleData"]
[docs]class ResampleData:
"""
This is the controlling routine for the resampling process.
It loads and sets the various input data and parameters needed by
the drizzle function and then calls the C-based cdriz.tdriz function
to do the actual resampling.
Notes
-----
This routine performs the following operations::
1. Extracts parameter settings from input model, such as pixfrac,
weight type, exposure time (if relevant), and kernel, and merges
them with any user-provided values.
2. Creates output WCS based on input images and define mapping function
between all input arrays and the output array.
3. Initializes all output arrays, including WHT and CTX arrays.
4. Passes all information for each input chip to drizzle function.
5. Updates output data model with output arrays from drizzle, including
(eventually) a record of metadata from all input models.
"""
def __init__(self, input_models, output=None, **pars):
"""
Parameters
----------
input_models : list of objects
list of data models, one for each input image
output : str
filename for output
"""
self.input_models = input_models
self.drizpars = pars
if output is None:
output = input_models.meta.resample.output
self.output_filename = output
# Define output WCS based on all inputs, including a reference WCS
self.output_wcs = resample_utils.make_output_wcs(self.input_models)
log.debug('Output mosaic size: {}'.format(self.output_wcs.data_size))
self.blank_output = datamodels.DrizProductModel(self.output_wcs.data_size)
# update meta data and wcs
self.blank_output.update(input_models[0])
self.blank_output.meta.wcs = self.output_wcs
self.output_models = datamodels.ModelContainer()
[docs] def update_driz_outputs(self):
""" Define output arrays for use with drizzle operations.
"""
numchips = len(self.input_models)
numplanes = (numchips // 32) + 1
# Replace CONTEXT array with full set of planes needed for all inputs
outcon = np.zeros((numplanes, self.output_wcs.data_size[0],
self.output_wcs.data_size[1]), dtype=np.int32)
self.blank_output.con = outcon
[docs] def do_drizzle(self):
""" Perform drizzling operation on input images's to create a new output
"""
# Set up information about what outputs we need to create: single or final
# Key: value from metadata for output/observation name
# Value: full filename for output file
driz_outputs = OrderedDict()
# Look for input configuration parameter telling the code to run
# in single-drizzle mode (mosaic all detectors in a single observation)
if self.drizpars['single']:
driz_outputs = self.input_models.group_names
exposures = self.input_models.models_grouped
group_exptime = []
for exposure in exposures:
group_exptime.append(exposure[0].meta.exposure.exposure_time)
else:
driz_outputs = [self.output_filename]
exposures = [self.input_models]
total_exposure_time = 0.0
for exposure in exposures:
total_exposure_time += exposure[0].meta.exposure.exposure_time
group_exptime = [total_exposure_time]
pointings = len(self.input_models.group_names)
for obs_product, exposure, texptime in zip(driz_outputs, exposures,
group_exptime):
output_model = self.blank_output.copy()
output_model.meta.filename = obs_product
saved_model_type = output_model.meta.model_type
if self.drizpars['blendheaders']:
self.blend_output_metadata(output_model)
output_model.meta.model_type = saved_model_type
exposure_times = {'start': [], 'end': []}
# Initialize the output with the wcs
driz = gwcs_drizzle.GWCSDrizzle(output_model,
single=self.drizpars['single'],
pixfrac=self.drizpars['pixfrac'],
kernel=self.drizpars['kernel'],
fillval=self.drizpars['fillval'])
for n, img in enumerate(exposure):
exposure_times['start'].append(img.meta.exposure.start_time)
exposure_times['end'].append(img.meta.exposure.end_time)
# apply sky subtraction
blevel = img.meta.background.level
if not img.meta.background.subtracted and blevel is not None:
img.data -= blevel
outwcs_pscale = output_model.meta.wcsinfo.cdelt1
wcslin_pscale = img.meta.wcsinfo.cdelt1
inwht = resample_utils.build_driz_weight(img,
weight_type=self.drizpars['weight_type'],
good_bits=self.drizpars['good_bits'])
driz.add_image(img.data, img.meta.wcs, inwht=inwht,
expin=img.meta.exposure.exposure_time,
pscale_ratio=outwcs_pscale / wcslin_pscale)
# Update some basic exposure time values based on all the inputs
output_model.meta.exposure.exposure_time = texptime
output_model.meta.exposure.start_time = min(exposure_times['start'])
output_model.meta.exposure.end_time = max(exposure_times['end'])
output_model.meta.resample.product_exposure_time = texptime
output_model.meta.resample.weight_type = self.drizpars['weight_type']
output_model.meta.resample.pointings = pointings
self.update_fits_wcs(output_model)
self.output_models.append(output_model)
[docs] def update_fits_wcs(self, model):
"""
Update FITS WCS keywords of the resampled image.
"""
transform = model.meta.wcs.forward_transform
model.meta.wcsinfo.crpix1 = -transform[0].offset.value + 1
model.meta.wcsinfo.crpix2 = -transform[1].offset.value + 1
model.meta.wcsinfo.cdelt1 = transform[3].factor.value
model.meta.wcsinfo.cdelt2 = transform[4].factor.value
model.meta.wcsinfo.ra_ref = transform[6].lon.value
model.meta.wcsinfo.dec_ref = transform[6].lat.value
model.meta.wcsinfo.crval1 = model.meta.wcsinfo.ra_ref
model.meta.wcsinfo.crval2 = model.meta.wcsinfo.dec_ref
model.meta.wcsinfo.pc1_1 = transform[2].matrix.value[0][0]
model.meta.wcsinfo.pc1_2 = transform[2].matrix.value[0][1]
model.meta.wcsinfo.pc2_1 = transform[2].matrix.value[1][0]
model.meta.wcsinfo.pc2_2 = transform[2].matrix.value[1][1]