1 """
2 MultiDrizzle combines astronomical images while removing
3 distortion and cosmic-rays. The Python syntax for using
4 MultiDrizzle relies on initializing a MultiDrizzle object,
5 building up the parameters necessary for combining the images,
6 then performing the actual processing necessary to generate
7 the final product. The process starts with the input of the
8 image names to initialize the MultiDrizzle object:
9
10 >>> import multidrizzle
11 >>> md = multidrizzle.MultiDrizzle(input,'other parameters')
12 >>> md.build()
13 >>> md.run()
14
15 MultiDrizzle defines default values for all inputs, and only
16 those values which need to be over-ridden should be entered.
17
18 Further help can be obtained interactively using:
19 >>> md.help()
20
21 :author: Warren Hack, Christopher Hanley, Ivo Busko, and David Grumm
22
23 """
24 from __future__ import division
25
26
27
28
29
30
31
32
33
34 import os, shutil, sys, string
35 import numpy as np
36 from pydrizzle import pydrizzle, process_input
37 from pydrizzle import drutil
38 import pyfits
39 from pytools import fileutil
40 import mdzhandler
41 import manager
42 from manager import ImageManager
43 import mdrizpars
44 from procstep import ProcSteps, timestamp
45
46 from pytools import parseinput
47 from pytools.parseinput import parseinput
48
49
50
51
52
53 __version__ = '3.3.8'
54 __vdate__ = '08-Jul-2010'
55
56
57 try:
58 import svn_version
59 __svn_version__ = svn_version.__svn_version__
60 except ImportError:
61 __svn_version__ = 'Unable to determine SVN revision'
62
64 """
65 The MultiDrizzle object manages the processing of the images. All
66 input parameters, including the input, have default values, so only
67 those parameters which need to be changed should be specified. The
68 processing requires the following steps to be performed in order:
69 - input all parameters and convert all input images to
70 multi-extension FITS (MEF) files
71
72 >>> md = multidrizzle.MultiDrizzle (input, output=None,
73 editpars=no,**input_dict)
74
75 where editpars turns on/off the GUI parameter editor
76 input_dict contains all parameters which have non-default values
77
78 - (optionally) edit all input parameter values with Traits-based GUI
79
80 >>> md.editpars()
81
82 - build parameters necessary for combining the images
83
84 >>> md.build()
85
86 - process the images through the steps which were turned on
87
88 >>> md.run( static = None, skysub = None,
89 driz_separate = None, median = None,
90 blot = None, driz_cr = None,
91 driz_combine = None, timing = None):
92
93 where each parameter controls whether a processing step gets performed.
94
95 A full list of the parameters can be obtained from the MultiDrizzle
96 help file.
97
98
99 """
100 init_keys = ['mdriztab','runfile','workinplace',
101 'context','clean','shiftfile','staticfile',
102 'static_sig','coeffs']
103
104 driz_keys = ['refimage','group','ra','dec','build']
105
106 instr_keys = ['gain','gnkeyword','rdnoise','rnkeyword',
107 'exptime', 'expkeyword','crbit']
108 sky_keys = ['skywidth','skystat', 'skylower','skyupper',
109 'skyclip','skylsigma','skyusigma','skyuser']
110
111 median_keys = ['median_newmasks','combine_type','combine_nsigma',
112 'combine_nlow', 'combine_nhigh','combine_lthresh',
113 'combine_hthresh','combine_grow','combine_maskpt','nsigma1','nsigma2' ]
114
115 drizcr_keys = ['driz_cr_snr','driz_cr_scale', 'driz_cr_corr',
116 'driz_cr_grow','driz_cr_ctegrow']
117
118 blot_keys = ['blot_interp','blot_sinscl']
119
120 - def __init__(self,
121 input = '*flt.fits',
122 output = None,
123 editpars = False,
124 shiftfile = None,
125 updatewcs = True,
126 **input_dict):
127
128 timestamp()
129 print 'Running MultiDrizzle ',__version__
130
131
132 self.versions = versioninfo()
133
134 self.shiftfile = shiftfile
135 self.updatewcs = updatewcs
136 if input_dict.has_key('proc_unit'):
137 self.proc_unit = input_dict['proc_unit']
138 else:
139 self.proc_unit = "native"
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190 self.errorstate = False
191
192
193 self.input = input
194 asndict, ivmfiles, output = process_input.process_input(input, output=output, updatewcs=self.updatewcs, shiftfile=shiftfile)
195 self.asndict = asndict
196 self.ivmlist = ivmfiles
197 self.output = output
198 if not self.asndict:
199 self.errorstate = True
200 return
201
202
203 self.files = [fileutil.buildRootname(f) for f in self.asndict['order']]
204
205 self.printInputFiles()
206
207
208
209
210
211
212
213
214
215
216
217
218 self.pars = mdrizpars.MDrizPars(self.input, self.output,
219 dict=input_dict,files=self.files)
220
221
222
223 self.steps = None
224 self.skypars = {}
225 self.medianpars = {}
226 self.drizcrpars = {}
227 self.blotpars = {}
228 self.driz_sep_pars = {}
229 self.driz_final_pars = {}
230 self.instrpars = {}
231
232 self.image_manager = None
233
234
235
236
237 self.traits_edited = False
238 if editpars:
239 self.editpars()
240
242 """ Run Python GUI parameter editor to set parameter values. """
243 self.pars.edit_traits()
244 self.traits_edited = True
245
246
248 """ Parses parameter list into dictionaries for use by
249 each processing step, builds the PyDrizzle input
250 association table, builds the PyDrizzle object and
251 uses that to build the InputImage instances needed
252 for MultiDrizzle processing.
253 """
254
255 if self.errorstate == True:
256
257
258
259
260
261
262
263
264
265
266
267 return
268
269
270
271 if self.traits_edited:
272 self.pars.updateMasterPars()
273
274
275
276 for kw in self.init_keys:
277 self.__dict__[kw] = self.pars.master_pars[kw]
278
279
280 self.runfile = str(self.runfile)
281
282
283
284
285 self.steps = self.pars.steps
286 self.steps.doStep(ProcSteps.doInitialize)
287
288 self.skypars = self.pars.getParList(self.sky_keys)
289 self.medianpars = self.pars.getParList(self.median_keys,prefix='combine_')
290 self.drizcrpars = self.pars.getParList(self.drizcr_keys)
291 self.blotpars = self.pars.getParList(self.blot_keys, prefix='blot_')
292
293
294
295 self.driz_sep_pars = self.pars.getDrizPars(prefix='driz_sep',keylist=self.driz_keys)
296 self.driz_final_pars = self.pars.getDrizPars(prefix='driz_final',keylist=self.driz_keys)
297 self.instrpars = self.pars.getParList(self.instr_keys)
298
299
300
301 self.setMedianPars()
302
303
304
305
306
307
308
309 if (len(self.files) == 1):
310 if self.pars.switches['median'] == True:
311 errorstr = "####################################\n"
312 errorstr += "# #\n"
313 errorstr += "# WARNING: #\n"
314 errorstr += "# Step 4: CREATE MEDIAN IMAGE has #\n"
315 errorstr += "# been turned off because only #\n"
316 errorstr += "# one file was provided as input. #\n"
317 errorstr += "# #\n"
318 errorstr += "####################################\n\n"
319 print errorstr
320 self.pars.switches['median'] = False
321 if self.pars.switches['blot'] == True:
322 errorstr = "############################################\n"
323 errorstr += "# #\n"
324 errorstr += "# WARNING: #\n"
325 errorstr += "# Step 5: BLOT BACK THE MEDIAN IMAGE has #\n"
326 errorstr += "# been turned off because only one file #\n"
327 errorstr += "# was provided as input. #\n"
328 errorstr += "# #\n"
329 errorstr += "############################################\n\n"
330 print errorstr
331 self.pars.switches['blot'] = False
332 if self.pars.switches['driz_cr'] == True:
333 errorstr = "#######################################################\n"
334 errorstr += "# #\n"
335 errorstr += "# WARNING: #\n"
336 errorstr += "# Step 6: REMOVE COSMIC RAYS WITH DERIV, DRIZ_CR has #\n"
337 errorstr += "# been turned off because only one file was provided #\n"
338 errorstr += "# as input. #\n"
339 errorstr += "# #\n"
340 errorstr += "#######################################################\n\n"
341 print errorstr
342 self.pars.switches['driz_cr'] = False
343
344
345
346
347 wht_type = self.pars.master_pars['driz_final_wht_type']
348
349 if ( wht_type != None and wht_type.upper() == 'ERR'):
350 for file in self.files:
351 if not fileutil.findFile(file+"[err,1]"):
352 raise ValueError,"! final_wht_type = ERR, no ERR array found for %s"%(file)
353
354 if (self.staticfile != None):
355 self._checkStaticFile(self.staticfile)
356
357
358
359 if not self.workinplace:
360 self._createInputCopies(self.files)
361 else:
362 print "\n\n********************"
363 print "WARNING: Sky will be subtracted from sci extensions"
364 print "WARNING: Units of sci extensions will be electrons"
365 print "WARNING: Value of MDRIZSKY is in units of input data sci extensions."
366 print "********************\n\n"
367
368
369 self.driz_sep_bits = self.pars.master_pars['driz_sep_bits']
370 self.final_bits = self.pars.master_pars['driz_final_bits']
371 self.final_units = self.pars.master_pars['driz_final_units']
372
373
374
375
376
377
378
379
380
381 assoc = pydrizzle._PyDrizzle(self.asndict, output=self.output,
382 idckey=self.coeffs,
383 section=self.driz_sep_pars['group'],
384 bits_single=self.driz_sep_bits,
385 bits_final=self.final_bits,
386 )
387
388
389 if self.clean:
390 assoc.clean()
391
392 print 'Initial parameters: '
393 assoc.printPars(format=1)
394
395
396 for plist in assoc.parlist:
397 fname,extname = fileutil.parseFilename(plist['data'])
398 ivmname = None
399 if len(self.ivmlist) > 0:
400 for index in xrange(len(self.ivmlist)):
401 if self.files[index] == fname:
402 ivmname = self.ivmlist[index]
403 plist['ivmname'] = ivmname
404
405
406
407
408 self.image_manager = ImageManager(assoc, self.context, self.instrpars, self.workinplace, self.staticfile, self.proc_unit)
409
410
411 self.steps.markStepDone(ProcSteps.doInitialize)
412
413
430
431
440
441
537 """
538 def __pav3errmsg(self,filename):
539 msgstr = "\n*******************************************\n"
540 msgstr += "* *\n"
541 msgstr += "* Primary header keyword PA_V3 not found! *\n"
542 msgstr += "* World Coordinate keywords cannot be *\n"
543 msgstr += "* recomputed without a valid PA_V3 value. *\n"
544 msgstr += "* Please insure that PA_V3 is populated *\n"
545 msgstr += "* in the primary header of *\n"
546 msgstr += " %s \n"%(filename)
547 msgstr += "* This keyword is generated by versions *\n"
548 msgstr += "* of OPUS 15.7 or later. If the data were *\n"
549 msgstr += "* obtained from an earlier version of *\n"
550 msgstr += "* OPUS, please re-retrieve the data from *\n"
551 msgstr += "* the archive after OPUS 15.7 has been *\n"
552 msgstr += "* installed, or manually add the keyword *\n"
553 msgstr += "* with the proper value to the header (it *\n"
554 msgstr += "* may be found in the SPT file header) *\n"
555 msgstr += "* *\n"
556 msgstr += "*******************************************\n"
557
558 print msgstr
559
560 """
562
563 """ Checks input files before they are required later. """
564
565
566
567 if (static_file != None):
568 _err_str = "Cannot find static mask file: " + static_file
569 try:
570
571 _exist = fileutil.checkFileExists(static_file)
572 if not _exist:
573 raise ValueError, _err_str
574 except IOError:
575 raise ValueError, _err_str
576
577
578
579
580 try:
581
582 sciimg = pyfits.open(self.files[0])
583 scicount = 0
584 for extension in sciimg:
585 if extension.header.has_key('extname'):
586 if (extension.header['extname'].upper() == 'SCI'):
587 scicount += 1
588
589 maskimg = pyfits.open(static_file)
590 maskcount = 0
591 for extension in maskimg:
592 if extension.header.has_key('extname'):
593 if (extension.header['extname'].upper() == 'MASK'):
594 maskcount += 1
595
596 if (scicount != maskcount):
597 raise ValueError
598 except ValueError:
599
600 errorstr = "\n############################################\n"
601 errorstr += "# #\n"
602 errorstr += "# ERROR: #\n"
603 errorstr += "# The user supplied static mask file #\n"
604 errorstr += " " + str(static_file) + "\n"
605 errorstr += "# does not contain enough MASK #\n"
606 errorstr += "# extensions. There needs to be 1 #\n"
607 errorstr += "# MASK extension for every SCI #\n"
608 errorstr += "# extension. #\n"
609 errorstr += "# #\n"
610 errorstr += "############################################\n"
611 raise ValueError, errorstr
612 except:
613 errorstr = "\n############################################\n"
614 errorstr += "# #\n"
615 errorstr += "# Error: #\n"
616 errorstr += "# Unable to verify the user supplied #\n"
617 errorstr += "# static mask file is in the correct #\n"
618 errorstr += "# format. Test could not complete. #\n"
619 errorstr += "# #\n"
620 errorstr += "############################################\n"
621 raise IOError, errorstr
622
623
624
652
653
670
671 - def run(self,
672 static = None,
673 skysub = None,
674 driz_separate = None,
675 median = None,
676 blot = None,
677 driz_cr = None,
678 driz_combine = None,
679 timing = None):
680
681 if self.errorstate == True:
682
683
684
685
686
687
688
689
690
691
692
693 return
694
695
696
697
698 self.pars.setProcSteps(static=static,
699 skysub=skysub,
700 driz_separate = driz_separate,
701 median = median,
702 blot = blot,
703 driz_cr = driz_cr,
704 driz_combine = driz_combine,
705 timing = timing)
706
707
708
709 self.image_manager._setOutputFrame(self.driz_sep_pars)
710
711 self._preMedian(skysub)
712 if self.steps.doStep(ProcSteps.doMedian):
713 self.image_manager.createMedian(self.medianpars)
714 self.steps.markStepDone(ProcSteps.doMedian)
715
716 self._postMedian(self.blotpars, self.drizcrpars, self.skypars)
717
718 if self.steps.doStep(ProcSteps.doFinalDriz):
719 self.driz_final_pars['runfile'] = self.runfile
720 self.image_manager.doFinalDriz(self.driz_final_pars)
721 self.runfile = self.driz_final_pars['runfile']
722 self.image_manager.updateMdrizVerHistory(self.driz_final_pars['build'],self.versions)
723 self.steps.markStepDone(ProcSteps.doFinalDriz)
724
725
726
727
728
729 if not self.workinplace:
730 self.image_manager.removeInputCopies()
731
732
733 if self.clean:
734
735 if os.path.exists(self.runfile):
736 os.remove(self.runfile)
737
738
739 self.image_manager.removeMDrizProducts()
740
741 if self.pars.switches['timing']:
742 self.steps.reportTimes()
743
745 """
746
747 Purpose
748 =======
749 Help function on Multidrizzle Class that
750 prints __doc__ string.
751
752 """
753
754 print 'MultiDrizzle Version ',__version__
755 print self.__doc__
756
757
759 """
760
761 Purpose
762 =======
763 This is a help function that is used to split up the "combine_nsigma"
764 string. If a second value is specified, then this will be used later
765 in "minmed" where a second-iteration rejection is done. Typically
766 the second value should be around 3 sigma, while the first
767 can be much higher.
768
769 """
770 _sig = s.split(" ")
771 _nsigma1 = float(_sig[0])
772 _nsigma2 = float(_sig[0])
773 if len(_sig) > 1:
774 _nsigma2 = float(_sig[1])
775 return (_nsigma1, _nsigma2)
776
777
779 """
780
781 Purpose
782 =======
783 Function prints help information for MultiDrizzle.
784
785 """
786
787
788 help_str = "MultiDrizzle combines astronomical images while removing \n"
789 help_str += "distortion and cosmic-rays. The Python syntax for using \n"
790 help_str += "MultiDrizzle relies on initializing a MultiDrizzle object, \n"
791 help_str += "building up the parameters necessary for combining the images, \n"
792 help_str += "then performing the actual processing necessary to generate \n"
793 help_str += "the final product. The process starts with the input of the \n"
794 help_str += "image names to initialize the MultiDrizzle object: \n"
795 help_str += " \n"
796 help_str += ">>> import multidrizzle \n"
797 help_str += ">>> md = multidrizzle.MultiDrizzle(input,args,...) \n"
798 help_str += ">>> md.build() \n"
799 help_str += ">>> md.run() \n"
800 help_str += " \n"
801 help_str += "MultiDrizzle defines default values for all inputs, and only \n"
802 help_str += "those values which need to be over-ridden should be entered. \n"
803 help_str += " \n"
804 print 'MultiDrizzle Version ',__version__
805 print help_str
806
807
809 """
810
811 Purpose
812 =======
813 Function prints version information for packages used by Multidrizzle
814
815 """
816
817
818 version_dict = {}
819
820
821 mdrizzle_key = " MultiDrizzle "
822 array_key = " NUMPY Version "
823 pydrizzle_key = " PyDrizzle Version "
824 pyfits_key = " PyFITS Version "
825 python_key = " Python Version: "
826
827 version_dict[mdrizzle_key] = __version__
828 version_dict[array_key]= np.__version__
829 version_dict[pydrizzle_key]= pydrizzle.__version__
830 version_dict[pyfits_key] = pyfits.__version__
831
832 _sys_version_list = sys.version.split("\n")
833 _sys_version = " # "
834 for _sys_str in _sys_version_list:
835 _sys_version += _sys_str+"\n # "
836 version_dict[python_key] = '\n'+_sys_version
837
838
839 print "\n"
840 print " Version Information for MultiDrizzle "+version_dict[mdrizzle_key]
841 print "-------------------------------------------- "
842 print array_key + version_dict[array_key]
843 print pyfits_key + version_dict[pyfits_key]
844 print pydrizzle_key + version_dict[pydrizzle_key]
845 print python_key + version_dict[python_key]
846 print "\n"
847
848 return version_dict
849