Source code for drizzlepac.astrodrizzle

"""
``AstroDrizzle`` - Python implementation of ``MultiDrizzle``

``AstroDrizzle`` automates the process of aligning images in an output frame,
identifying cosmic-rays, removing distortion, and then combining the images
after removing the identified cosmic-rays.

This process involves a number of steps, such as:
  *  Processing the input images and input parameters
  *  Creating a static mask
  *  Performing sky subtraction
  *  Drizzling onto separate output images
  *  Creating the median image
  *  Blotting the median image
  *  Identifying and flagging cosmic-rays
  *  Final combination
  *  Cleaning-up of temporary files (when applicable)

A full description of this process can be found
in the `DrizzlePac Handbook <http://drizzlepac.stsci.edu>`_\ .

The primary output from this task is the distortion-corrected,
cosmic-ray cleaned, and combined image as a FITS file.

This task requires numerous user-settable parameters to control the primary
aspects of each of the processing steps.

:Authors: Warren Hack

:License: :doc:`LICENSE`

"""
import os
import sys

from stsci.tools import teal, logutil, textutil

from . import adrizzle
from . import ablot
from . import createMedian
from . import drizCR
from . import processInput
from . import sky
from . import staticMask
from . import util
from . import wcs_functions
from .version import *


__taskname__ = "astrodrizzle"


# Pointer to the included Python class for WCS-based coordinate transformations
PYTHON_WCSMAP = wcs_functions.WCSMap

log = logutil.create_logger(__name__, level=logutil.logging.NOTSET)


[docs]def AstroDrizzle(input=None, mdriztab=False, editpars=False, configobj=None, wcsmap=None, **input_dict): """ AstroDrizzle command-line interface """ # Support input of filenames from command-line without a parameter name # then copy this into input_dict for merging with TEAL ConfigObj # parameters. # Load any user-specified configobj if isinstance(configobj, (str, bytes)): if configobj == 'defaults': # load "TEAL"-defaults (from ~/.teal/): configobj = teal.load(__taskname__) else: if not os.path.exists(configobj): raise RuntimeError('Cannot find .cfg file: '+configobj) configobj = teal.load(configobj, strict=False) elif configobj is None: # load 'astrodrizzle' parameter defaults as described in the docs: configobj = teal.load(__taskname__, defaults=True) if input and not util.is_blank(input): input_dict['input'] = input elif configobj is None: raise TypeError("AstroDrizzle() needs either 'input' or " "'configobj' arguments") if 'updatewcs' in input_dict: # user trying to explicitly turn on updatewcs configobj['updatewcs'] = input_dict['updatewcs'] del input_dict['updatewcs'] # If called from interactive user-interface, configObj will not be # defined yet, so get defaults using EPAR/TEAL. # # Also insure that the input_dict (user-specified values) are folded in # with a fully populated configObj instance. try: configObj = util.getDefaultConfigObj(__taskname__, configobj, input_dict, loadOnly=(not editpars)) log.debug('') log.debug("INPUT_DICT:") util.print_cfg(input_dict, log.debug) log.debug('') # If user specifies optional parameter for final_wcs specification in input_dict, # insure that the final_wcs step gets turned on util.applyUserPars_steps(configObj, input_dict, step='3a') util.applyUserPars_steps(configObj, input_dict, step='7a') except ValueError: print("Problem with input parameters. Quitting...", file=sys.stderr) return if not configObj: return configObj['mdriztab'] = mdriztab # If 'editpars' was set to True, util.getDefaultConfigObj() will have # already called 'run()'. if not editpars: run(configObj, wcsmap=wcsmap)
############################## ## Interfaces used by TEAL ## ############################## @util.with_logging def run(configobj, wcsmap=None): """ Initial example by Nadia ran MD with configobj EPAR using: It can be run in one of two ways: from stsci.tools import teal 1. Passing a config object to teal teal.teal('drizzlepac/pars/astrodrizzle.cfg') 2. Passing a task name: teal.teal('astrodrizzle') The example config files are in drizzlepac/pars """ # turn on logging, redirecting stdout/stderr messages to a log file # while also printing them out to stdout as well # also, initialize timing of processing steps # # We need to define a default logfile name from the user's parameters input_list, output, ivmlist, odict = \ processInput.processFilenames(configobj['input']) if output is not None: def_logname = output elif len(input_list) > 0: def_logname = input_list[0] else: print(textutil.textbox( "ERROR:\nNo valid input files found! Please restart the task " "and check the value for the 'input' parameter."), file=sys.stderr) def_logname = None return clean = configobj['STATE OF INPUT FILES']['clean'] procSteps = util.ProcSteps() print("AstroDrizzle Version {:s} ({:s}) started at: {:s}\n" .format(__version__, __version_date__, util._ptime()[0])) util.print_pkg_versions(log=log) log.debug('') log.debug( "==== AstroDrizzle was invoked with the following parameters: ====" ) log.debug('') util.print_cfg(configobj, log.debug) try: # Define list of imageObject instances and output WCSObject instance # based on input paramters imgObjList = None procSteps.addStep('Initialization') imgObjList, outwcs = processInput.setCommonInput(configobj) procSteps.endStep('Initialization') if imgObjList is None or not imgObjList: errmsg = "No valid images found for processing!\n" errmsg += "Check log file for full details.\n" errmsg += "Exiting AstroDrizzle now..." print(textutil.textbox(errmsg, width=65)) print(textutil.textbox( 'ERROR:\nAstroDrizzle Version {:s} encountered a problem! ' 'Processing terminated at {:s}.' .format(__version__, util._ptime()[0])), file=sys.stderr) return log.info("USER INPUT PARAMETERS common to all Processing Steps:") util.printParams(configobj, log=log) # Call rest of MD steps... #create static masks for each image staticMask.createStaticMask(imgObjList, configobj, procSteps=procSteps) #subtract the sky sky.subtractSky(imgObjList, configobj, procSteps=procSteps) # _dbg_dump_virtual_outputs(imgObjList) #drizzle to separate images adrizzle.drizSeparate(imgObjList, outwcs, configobj, wcsmap=wcsmap, procSteps=procSteps) # _dbg_dump_virtual_outputs(imgObjList) #create the median images from the driz sep images createMedian.createMedian(imgObjList, configobj, procSteps=procSteps) #blot the images back to the original reference frame ablot.runBlot(imgObjList, outwcs, configobj, wcsmap=wcsmap, procSteps=procSteps) #look for cosmic rays drizCR.rundrizCR(imgObjList, configobj, procSteps=procSteps) #Make your final drizzled image adrizzle.drizFinal(imgObjList, outwcs, configobj, wcsmap=wcsmap, procSteps=procSteps) print() print("AstroDrizzle Version {:s} is finished processing at {:s}.\n" .format(__version__, util._ptime()[0])) except: clean = False print(textutil.textbox( "ERROR:\nAstroDrizzle Version {:s} encountered a problem! " "Processing terminated at {:s}." .format(__version__, util._ptime()[0])), file=sys.stderr) raise finally: procSteps.reportTimes() if imgObjList: for image in imgObjList: if clean: image.clean() image.close() del imgObjList del outwcs def help(file=None): """ Print out syntax help for running astrodrizzle Parameters ---------- file : str (Default = None) If given, write out help to the filename specified by this parameter Any previously existing file with this name will be deleted before writing out the help. """ helpstr = getHelpAsString(docstring=True, show_ver = True) if file is None: print(helpstr) else: if os.path.exists(file): os.remove(file) f = open(file, mode = 'w') f.write(helpstr) f.close() def getHelpAsString(docstring = False, show_ver = True): """ return useful help from a file in the script directory called __taskname__.help """ install_dir = os.path.dirname(__file__) taskname = util.base_taskname(__taskname__, '') htmlfile = os.path.join(install_dir, 'htmlhelp', taskname + '.html') helpfile = os.path.join(install_dir, taskname + '.help') if docstring or (not docstring and not os.path.exists(htmlfile)): if show_ver: helpString = os.linesep + \ ' '.join([__taskname__, 'Version', __version__, ' updated on ', __version_date__]) + 2*os.linesep else: helpString = '' if os.path.exists(helpfile): helpString += teal.getHelpFileAsString(taskname, __file__) else: if __doc__ is not None: helpString += __doc__ + os.linesep else: helpString = 'file://' + htmlfile return helpString _fidx = 0 def _dbg_dump_virtual_outputs(imgObjList): """ dump some helpful information. strictly for debugging """ global _fidx tag = 'virtual' log.info((tag+' ')*7) for iii in imgObjList: log.info('-'*80) log.info(tag+' orig nm: '+iii._original_file_name) log.info(tag+' names.data: '+str(iii.outputNames["data"])) log.info(tag+' names.orig: '+str(iii.outputNames["origFilename"])) log.info(tag+' id: '+str(id(iii))) log.info(tag+' in.mem: '+str(iii.inmemory)) log.info(tag+' vo items...') for vok in sorted(iii.virtualOutputs.keys()): FITSOBJ = iii.virtualOutputs[vok] log.info(tag+': '+str(vok)+' = '+str(FITSOBJ)) if vok.endswith('.fits'): if not hasattr(FITSOBJ, 'data'): FITSOBJ = FITSOBJ[0] # list of PrimaryHDU ? if not hasattr(FITSOBJ, 'data'): FITSOBJ = FITSOBJ[0] # was list of HDUList ? dbgname = 'DEBUG_%02d_'%(_fidx,) dbgname+=os.path.basename(vok) _fidx+=1 FITSOBJ.writeto(dbgname) log.info(tag+' wrote: '+dbgname) log.info('\n'+vok) if hasattr(FITSOBJ, 'data'): log.info(str(FITSOBJ._summary())) log.info('min and max are: '+str( (FITSOBJ.data.min(), FITSOBJ.data.max()) )) log.info('avg and sum are: '+str( (FITSOBJ.data.mean(), FITSOBJ.data.sum()) )) # log.info(str(FITSOBJ.data)[:75]) else: log.info(vok+' has no .data attr') log.info(str(type(FITSOBJ))) log.info(vok+'\n') log.info('-'*80) AstroDrizzle.__doc__ = getHelpAsString(docstring = True, show_ver = False)