casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables
task_sdstat.py
Go to the documentation of this file.
00001 import os
00002 import sys
00003 from taskinit import *
00004 from get_user import get_user
00005 
00006 import asap as sd
00007 from asap import _to_list
00008 from asap.scantable import is_scantable
00009 import pylab as pl
00010 import sdutil
00011 
00012 def sdstat(infile, antenna, fluxunit, telescopeparm, specunit, restfreq, frame, doppler, scanlist, field, iflist, pollist, masklist, invertmask, interactive, outfile, format, overwrite):
00013 
00014     casalog.origin('sdstat')
00015     
00016     ###
00017     ### Now the actual task code
00018     ###
00019     try:
00020         worker = sdstat_worker(**locals())
00021         worker.initialize()
00022         worker.execute()
00023         worker.finalize()
00024         
00025         return  worker.statistics
00026         
00027     except Exception, instance:
00028         sdutil.process_exception(instance)
00029         raise Exception, instance
00030 
00031 class sdstat_worker(sdutil.sdtask_template):
00032     def __init__(self, **kwargs):
00033         super(sdstat_worker,self).__init__(**kwargs)
00034 
00035     def __del__(self):
00036         # restore scantable when the instance is deleted
00037         self.cleanup()
00038 
00039     def parameter_check(self):
00040         # If outfile is set, sd.rcParams['verbose'] must be True
00041         self.verbose_saved = sd.rcParams['verbose']
00042         if ( len(self.outfile) > 0 ):
00043             if ( not os.path.exists(sdutil.get_abspath(self.outfile)) \
00044                  or self.overwrite ):
00045                 sd.rcParams['verbose']=True
00046 
00047 
00048     def initialize_scan(self):
00049         #load the data without averaging
00050         sorg = sd.scantable(self.infile,average=False,antenna=self.antenna)
00051 
00052         # collect data to restore
00053         self.restorer = sdutil.scantable_restore_factory(sorg,
00054                                                          self.infile,
00055                                                          self.fluxunit,
00056                                                          self.specunit,
00057                                                          self.frame,
00058                                                          self.doppler,
00059                                                          self.restfreq)
00060         
00061         # scantable selection
00062         sorg.set_selection(self.get_selector())
00063 
00064 
00065         # this is bit tricky
00066         # set fluxunit here instead of self.set_to_scan
00067         # and remove fluxunit attribute to disable additional
00068         # call of set_fluxunit in self.set_to_scan
00069         self.scan = sdutil.set_fluxunit(sorg, self.fluxunit, self.telescopeparm, False)
00070         self.fluxunit_saved = self.fluxunit
00071         del self.fluxunit
00072 
00073         if self.scan:
00074             # Restore flux unit in original table before deleting
00075             self.restorer.restore()
00076             del self.restorer
00077             self.restorer = None
00078         else:
00079             self.scan = sorg
00080 
00081     def execute(self):
00082         self.set_to_scan()
00083 
00084         # restore self.fluxunit
00085         self.fluxunit = self.fluxunit_saved
00086         del self.fluxunit_saved
00087 
00088         self.calc_statistics()
00089 
00090     def calc_statistics(self):
00091         # Warning for multi-IF data
00092         if len(self.scan.getifnos()) > 1:
00093             casalog.post( 'The scantable contains multiple IF data.', priority='WARN' )
00094             casalog.post( 'Note the same mask(s) are applied to all IFs based on CHANNELS.', priority='WARN' )
00095             casalog.post( 'Baseline ranges may be incorrect for all but IF=%d.\n' % (self.scan.getif(0)), priority='WARN' )
00096 
00097         # set mask
00098         self.__set_mask()
00099 
00100         # set formatter
00101         self.__set_formatter()
00102 
00103         # set unit labels
00104         self.__set_unit_labels()
00105 
00106         # calculate statistics
00107         #statsdict = get_stats(s, msk, formstr)
00108         self.__calc_stats()
00109 
00110         # reshape statsdict for return
00111         for k in ['min','max']:
00112             self.statistics['%s_abscissa'%(k)] = qa.quantity(self.statistics.pop('%s_abc'%(k)),self.xunit)
00113         for (k,u) in [('eqw',self.xunit),('totint',self.intunit)]:
00114             self.statistics[k] = qa.quantity(self.statistics[k],u)
00115 
00116     def save(self):
00117         if ( len(self.outfile) > 0 ):
00118             if ( not os.path.exists(sdutil.get_abspath(self.outfile)) \
00119                  or self.overwrite ):
00120                 f=open(self.outfile,'w')
00121                 f.write(self.resultstats)
00122                 f.close()
00123             else:
00124                 casalog.post( 'File '+self.outfile+' already exists.\nStatistics results are not written into the file.', priority = 'WARN' )
00125 
00126     def cleanup(self):
00127         # restore sd.rcParams
00128         sd.rcParams['verbose'] = self.verbose_saved
00129 
00130         # restore original scantable
00131         if self.restorer is not None:
00132             self.restorer.restore()
00133 
00134     def __calc_stats(self):
00135         usr = get_user()
00136         tmpfile = '/tmp/tmp_'+usr+'_casapy_asap_scantable_stats'
00137         self.resultstats = ''
00138         self.statistics = {}
00139 
00140         # calculate regular statistics
00141         statsname = ['max', 'min', 'max_abc', 'min_abc',
00142                      'sum', 'mean', 'median', 'rms',
00143                      'stddev']
00144         for name in statsname:
00145             v = self.scan.stats(name,self.msk,self.format_string)
00146             self.statistics[name] = list(v) if len(v) > 1 else v[0]
00147             if sd.rcParams['verbose']:
00148                 self.resultstats += get_text_from_file(tmpfile)
00149 
00150         # calculate additional statistics (eqw and integrated intensity)
00151         self.__calc_eqw_and_integf()
00152 
00153         if sd.rcParams['verbose']:
00154             # Print equivalent width
00155             out = self.__get_statstext('eqw', self.abclbl, 'eqw')
00156             self.resultstats += out
00157 
00158             # Print integrated flux
00159             outp = self.__get_statstext('Integrated intensity', self.intlbl, 'totint')
00160             self.resultstats += outp
00161 
00162             # to logger
00163             casalog.post(out[:-2]+outp)
00164 
00165     def __calc_eqw_and_integf(self):
00166         eqw = None
00167         integratef = None
00168         if isinstance(self.statistics['max'],list):
00169             # User selected multiple scans,ifs
00170             ns = len(self.statistics['max'])
00171             eqw=[]
00172             integratef=[]
00173             for i in range(ns):
00174                 #Get bin width
00175                 abcissa, lbl = self.scan.get_abcissa(rowno=i)
00176                 dabc=abs(abcissa[-1] - abcissa[0])/float(len(abcissa)-1)
00177                 # Construct equivalent width (=sum/max)
00178                 eqw = eqw + [get_eqw(self.statistics['max'][i],
00179                                      self.statistics['min'][i],
00180                                      self.statistics['sum'][i],
00181                                      dabc)]
00182                 # Construct integrated flux
00183                 integratef = integratef + [get_integf(self.statistics['sum'][i], dabc)]
00184         else:
00185             # Single scantable only
00186             abcissa, lbl = self.scan.get_abcissa(rowno=0)
00187             dabc=abs(abcissa[-1] - abcissa[0])/float(len(abcissa)-1)
00188         
00189             # Construct equivalent width (=sum/max)
00190             eqw = get_eqw(self.statistics['max'],
00191                           self.statistics['min'],
00192                           self.statistics['sum'],
00193                           dabc)
00194 
00195             # Construct integrated flux
00196             integratef = get_integf(self.statistics['sum'], dabc)
00197         self.statistics['eqw'] = eqw
00198         self.statistics['totint'] = integratef
00199 
00200     def __set_mask(self):
00201         self.msk = None
00202         if self.interactive:
00203             # Interactive masking
00204             self.msk = sdutil.interactive_mask(self.scan,
00205                                                self.masklist,
00206                                                False,
00207                                                purpose='to calculate statistics')
00208             msks = self.scan.get_masklist(self.msk)
00209             if len(msks) < 1:
00210                 raise Exception, 'No channel is selected. Exit without calculation.'
00211             lbl=self.scan.get_unit()
00212             casalog.post( 'final mask list ('+lbl+') = '+str(msks) )
00213 
00214             del msks
00215 
00216         # set the mask region
00217         elif ( len(self.masklist) > 0):
00218             self.msk=self.scan.create_mask(self.masklist,invert=self.invertmask)
00219             msks=self.scan.get_masklist(self.msk)
00220             if len(msks) < 1:
00221                 del self.msk, msks
00222                 raise Exception, 'Selected mask lists are out of range. Exit without calculation.'
00223             del msks
00224         else:
00225             # Full region
00226             casalog.post( 'Using full region' )
00227         
00228     def __set_formatter(self):
00229         self.format_string=self.format.replace(' ','')
00230         if len(self.format_string)==0:
00231             casalog.post("Invalid format string. Using the default 3.3f.")
00232             self.format_string='3.3f'
00233 
00234     def __set_unit_labels(self):
00235         if self.specunit != '': self.abclbl = self.specunit
00236         else: self.abclbl = self.scan.get_unit()
00237         if self.fluxunit != '': ordlbl = self.fluxunit
00238         else: ordlbl = self.scan.get_fluxunit()
00239         self.intlbl = ordlbl+' * '+self.abclbl
00240 
00241         # Check units
00242         if self.abclbl == 'channel' and not qa.check(self.abclbl):
00243             qa.define('channel','1 _')
00244 
00245         self.xunit = check_unit(self.abclbl,self.abclbl,'_')
00246         self.intunit = check_unit(ordlbl,ordlbl+'.'+self.abclbl,'_.'+self.abclbl)
00247 
00248     def __get_statstext(self, title, label, key):
00249         sep = "--------------------------------------------------"
00250         head = string.join([sep,string.join([" ","%s ["%(title),label,"]"]," "),sep],'\n')
00251         tail = ''
00252         out = head + '\n'
00253         val = self.statistics[key]
00254         if isinstance(val,list):
00255             ns = len(val)
00256             for i in xrange(ns):
00257                 out += self.__get_statstr(i, val[i], sep)
00258         else:
00259             out += self.__get_statstr(0, val, sep)
00260         out += '\n%s'%(tail)
00261         return out
00262 
00263     def __get_statstr(self, irow, val, separator):
00264         out = ''
00265         out += 'Scan[%d] (%s) ' % (self.scan.getscan(irow), self.scan._getsourcename(irow))
00266         out += 'Time[%s]:\n' % (self.scan._gettime(irow))
00267         if self.scan.nbeam(-1) > 1: out +=  ' Beam[%d] ' % (self.scan.getbeam(irow))
00268         if self.scan.nif(-1) > 1: out +=  ' IF[%d] ' % (self.scan.getif(irow))
00269         if self.scan.npol(-1) > 1: out +=  ' Pol[%d] ' % (self.scan.getpol(irow))
00270         out += ('= %'+self.format_string) % (val) + '\n'
00271         out +=  "%s\n "%(separator)
00272         return out 
00273 
00274 def check_unit(unit_in,valid_unit=None,default_unit=None):
00275     if qa.check(unit_in):
00276         return valid_unit
00277     else:
00278         casalog.post('Undefined unit: \'%s\'...ignored'%(unit_in), priority='WARN')
00279         return default_unit
00280 
00281 def get_eqw(maxl, minl, suml, dabc):
00282     eqw = 0.0
00283     if ( maxl != 0.0 or minl != 0.0 ):
00284         if ( abs(maxl) >= abs(minl) ):
00285             eqw = suml/maxl*dabc
00286         else:
00287             eqw = suml/minl*dabc
00288     return eqw
00289     
00290 def get_integf(suml, dabc):
00291     return suml * dabc
00292 
00293 def get_text_from_file(filename):
00294     f = open(filename,'r')
00295     rlines = f.readlines()
00296     f.close()
00297     return string.join(rlines,'')
00298