source: trunk/python/scantable.py @ 489

Last change on this file since 489 was 489, checked in by mar637, 19 years ago
  • added history to all functions, which modify the data
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.4 KB
Line 
1from asap._asap import sdtable
2from asap import rcParams
3from numarray import ones,zeros
4import sys
5
6class scantable(sdtable):
7    """
8        The ASAP container for scans
9    """
10   
11    def __init__(self, filename, average=None, unit=None):
12        """
13        Create a scantable from a saved one or make a reference
14        Parameters:
15            filename:    the name of an asap table on disk
16                         or
17                         the name of a rpfits/sdfits/ms file
18                         (integrations within scans are auto averaged
19                         and the whole file is read)
20                         or
21                         [advanced] a reference to an existing
22                         scantable
23            average:     average all integrations withinb a scan on read.
24                         The default (True) is taken from .asaprc.
25            unit:         brightness unit; must be consistent with K or Jy.
26                         Over-rides the default selected by the reader
27                         (input rpfits/sdfits/ms) or replaces the value
28                         in existing scantables
29        """       
30        if average is None or type(average) is not bool:
31            average = rcParams['scantable.autoaverage']           
32
33        varlist = vars()
34        self._vb = rcParams['verbose']
35        self._p = None
36
37        if isinstance(filename,sdtable):
38            sdtable.__init__(self, filename)           
39            if unit is not None:
40                self.set_fluxunit(unit)                       
41        else:
42            import os.path
43            if not os.path.exists(filename):
44                print "File '%s' not found." % (filename)
45                return
46            filename = os.path.expandvars(filename)
47            if os.path.isdir(filename):
48                # crude check if asap table
49                if os.path.exists(filename+'/table.info'):
50                    sdtable.__init__(self, filename)
51                    if unit is not None:
52                        self.set_fluxunit(unit)                       
53                else:
54                    print "The given file '%s'is not a valid asap table." % (filename)
55                    return
56            else:           
57                from asap._asap import sdreader
58                ifSel = -1
59                beamSel = -1
60                r = sdreader(filename,ifSel,beamSel)
61                print 'Importing data...'
62                r._read([-1])
63                tbl = r._getdata()
64                if unit is not None:
65                    tbl.set_fluxunit(unit)
66                if average:
67                    from asap._asap import average as _av
68                    tmp = tuple([tbl])
69                    print 'Auto averaging integrations...'
70                    tbl2 = _av(tmp,(),True,'none')
71                    sdtable.__init__(self,tbl2)
72                    del r,tbl
73                else:
74                    sdtable.__init__(self,tbl)
75                self._add_history("scantable", varlist)
76
77    def save(self, name=None, format=None, stokes=False, overwrite=False):
78        """
79        Store the scantable on disk. This can be an asap (aips++) Table, SDFITS,
80        Image FITS or MS2 format.
81        Parameters:
82            name:        the name of the outputfile. For format="FITS" this
83                         is the directory file name into which all the files
84                         will be written (default is 'asap_FITS')
85            format:      an optional file format. Default is ASAP.
86                         Allowed are - 'ASAP' (save as ASAP [aips++] Table),
87                                       'SDFITS' (save as SDFITS file)
88                                       'FITS' (saves each row as a FITS Image)
89                                       'ASCII' (saves as ascii text file)
90                                       'MS2' (saves as an aips++
91                                              MeasurementSet V2)
92            stokes:      Convert to Stokes parameters (only available
93                         currently with FITS and ASCII formats.
94                         Default is False.
95            overwrite:   If the file should be overwritten if it exists.
96                         The default False is to return with warning
97                         without writing the output. USE WITH CARE.
98        Example:
99            scan.save('myscan.asap')
100            scan.save('myscan.sdfits','SDFITS')
101        """
102        from os import path
103        if format is None: format = rcParams['scantable.save']
104        suffix = '.'+format.lower()
105        if name is None or name =="":
106            name = 'scantable'+suffix
107            print "No filename given. Using default name %s..." % name
108        name = path.expandvars(name)
109        if path.isfile(name) or path.isdir(name):
110            if not overwrite:
111                print "File %s already exists." % name
112                return
113        format2 = format.upper()
114        if format2 == 'ASAP':
115            self._save(name)
116        else:
117            from asap._asap import sdwriter as _sw
118            w = _sw(format2)
119            w.write(self, name, stokes)
120        return
121
122    def copy(self):
123        """
124        Return a copy of this scantable.
125        Parameters:
126            none
127        Example:
128            copiedscan = scan.copy()
129        """
130        sd = scantable(sdtable._copy(self))
131        return sd
132
133    def get_scan(self, scanid=None):
134        """
135        Return a specific scan (by scanno) or collection of scans (by
136        source name) in a new scantable.
137        Parameters:
138            scanid:    a scanno or a source name
139        Example:
140            scan.get_scan('323p459')
141            # gets all scans containing the source '323p459'
142        """
143        if scanid is None:
144            print "Please specify a scan no or name to retrieve from the scantable"
145        try:
146            if type(scanid) is str:
147                s = sdtable._getsource(self,scanid)
148                return scantable(s)
149            elif type(scanid) is int:
150                s = sdtable._getscan(self,[scanid])
151                return scantable(s)
152            elif type(scanid) is list:
153                s = sdtable._getscan(self,scanid)
154                return scantable(s)
155            else:
156                print "Illegal scanid type, use 'int' or 'list' if ints."
157        except RuntimeError:
158            print "Couldn't find any match."
159
160    def __str__(self):
161        return sdtable._summary(self,True)
162
163    def summary(self,filename=None, verbose=None):
164        """
165        Print a summary of the contents of this scantable.
166        Parameters:
167            filename:    the name of a file to write the putput to
168                         Default - no file output
169            verbose:     print extra info such as the frequency table
170                         The default (False) is taken from .asaprc
171        """
172        info = sdtable._summary(self, verbose)
173        if verbose is None: verbose = rcParams['scantable.verbosesummary']
174        if filename is not None:
175            if filename is "":
176                filename = 'scantable_summary.txt'
177            from os.path import expandvars, isdir
178            filename = expandvars(filename)
179            if not isdir(filename):
180                data = open(filename, 'w')
181                data.write(info)
182                data.close()
183            else:
184                print "Illegal file name '%s'." % (filename)
185        print info
186           
187    def set_cursor(self, thebeam=0,theif=0,thepol=0):
188        """
189        Set the spectrum for individual operations.
190        Parameters:
191            thebeam,theif,thepol:    a number
192        Example:
193            scan.set_cursor(0,0,1)
194            pol1sig = scan.stats(all=False) # returns std dev for beam=0
195                                            # if=0, pol=1
196        """
197        varlist = vars()
198        self.setbeam(thebeam)
199        self.setpol(thepol)
200        self.setif(theif)
201        self._add_history("set_cursor",varlist)
202        return
203
204    def get_cursor(self):
205        """
206        Return/print a the current 'cursor' into the Beam/IF/Pol cube.
207        Parameters:
208            none
209        Returns:
210            a list of values (currentBeam,currentIF,currentPol)
211        Example:
212            none
213        """
214        i = self.getbeam()
215        j = self.getif()
216        k = self.getpol()
217        if self._vb:
218            print "--------------------------------------------------"
219            print " Cursor position"
220            print "--------------------------------------------------"
221            out = 'Beam=%d IF=%d Pol=%d ' % (i,j,k)
222            print out
223        return i,j,k
224
225    def stats(self, stat='stddev', mask=None, allaxes=None):
226        """
227        Determine the specified statistic of the current beam/if/pol
228        Takes a 'mask' as an optional parameter to specify which
229        channels should be excluded.
230        Parameters:
231            stat:    'min', 'max', 'sumsq', 'sum', 'mean'
232                     'var', 'stddev', 'avdev', 'rms', 'median'
233            mask:    an optional mask specifying where the statistic
234                     should be determined.
235            allaxes: if True apply to all spectra. Otherwise
236                     apply only to the selected (beam/pol/if)spectra only.
237                     The default is taken from .asaprc (True if none)
238        Example:
239            scan.set_unit('channel')
240            msk = scan.create_mask([100,200],[500,600])
241            scan.stats(stat='mean', mask=m)
242        """
243        if allaxes is None: allaxes = rcParams['scantable.allaxes']
244        from asap._asap import stats as _stats
245        from numarray import array,zeros,Float
246        if mask == None:
247            mask = ones(self.nchan())
248        axes = ['Beam','IF','Pol','Time']
249
250        beamSel,IFSel,polSel = (self.getbeam(),self.getif(),self.getpol())
251        if allaxes:
252            n = self.nbeam()*self.nif()*self.npol()*self.nrow()
253            shp = [self.nbeam(),self.nif(),self.npol(),self.nrow()]
254            arr = array(zeros(n),shape=shp,type=Float)
255
256            for i in range(self.nbeam()):
257                self.setbeam(i)
258                for j in range(self.nif()):
259                    self.setif(j)
260                    for k in range(self.npol()):
261                        self.setpol(k)
262                        arr[i,j,k,:] = _stats(self,mask,stat,-1)
263            retval = {'axes': axes, 'data': arr, 'cursor':None}
264            tm = [self._gettime(val) for val in range(self.nrow())]
265            if self._vb:
266                self._print_values(retval,stat,tm)
267            self.setbeam(beamSel)
268            self.setif(IFSel)
269            self.setpol(polSel)
270            return retval
271
272        else:
273            statval = _stats(self,mask,stat,-1)
274            out = ''
275            for l in range(self.nrow()):
276                tm = self._gettime(l)
277                out += 'Time[%s]:\n' % (tm)
278                if self.nbeam() > 1: out +=  ' Beam[%d] ' % (beamSel)
279                if self.nif() > 1: out +=  ' IF[%d] ' % (IFSel)
280                if self.npol() > 1: out +=  ' Pol[%d] ' % (polSel)
281                out += '= %3.3f\n' % (statval[l])
282                out +=  "--------------------------------------------------\n"
283
284            if self._vb:
285                print "--------------------------------------------------"
286                print " ",stat
287                print "--------------------------------------------------"
288                print out
289            retval = {'axes': axes, 'data': array(statval), 'cursor':(i,j,k)}
290            return retval
291
292    def stddev(self,mask=None, allaxes=None):
293        """
294        Determine the standard deviation of the current beam/if/pol
295        Takes a 'mask' as an optional parameter to specify which
296        channels should be excluded.
297        Parameters:
298            mask:    an optional mask specifying where the standard
299                     deviation should be determined.
300            allaxes: optional flag to show all or a cursor selected
301                     spectrum of Beam/IF/Pol. Default is all or taken
302                     from .asaprc
303
304        Example:
305            scan.set_unit('channel')
306            msk = scan.create_mask([100,200],[500,600])
307            scan.stddev(mask=m)
308        """
309        if allaxes is None: allaxes = rcParams['scantable.allaxes']
310        return self.stats(stat='stddev',mask=mask, allaxes=allaxes);
311
312    def get_tsys(self, allaxes=None):
313        """
314        Return the System temperatures.
315        Parameters:
316           allaxes:     if True apply to all spectra. Otherwise
317                        apply only to the selected (beam/pol/if)spectra only.
318                        The default is taken from .asaprc (True if none)
319        Returns:
320            a list of Tsys values.
321        """
322        if allaxes is None: allaxes = rcParams['scantable.allaxes']
323        from numarray import array,zeros,Float
324        axes = ['Beam','IF','Pol','Time']
325
326        if allaxes:
327            n = self.nbeam()*self.nif()*self.npol()*self.nrow()
328            shp = [self.nbeam(),self.nif(),self.npol(),self.nrow()]
329            arr = array(zeros(n),shape=shp,type=Float)
330
331            for i in range(self.nbeam()):
332                self.setbeam(i)
333                for j in range(self.nif()):
334                    self.setif(j)
335                    for k in range(self.npol()):
336                        self.setpol(k)
337                        arr[i,j,k,:] = self._gettsys()
338            retval = {'axes': axes, 'data': arr, 'cursor':None}
339            tm = [self._gettime(val) for val in range(self.nrow())]
340            if self._vb:
341                self._print_values(retval,'Tsys',tm)
342            return retval
343
344        else:
345            i,j,k = (self.getbeam(),self.getif(),self.getpol())
346            statval = self._gettsys()
347            out = ''
348            for l in range(self.nrow()):
349                tm = self._gettime(l)
350                out += 'Time[%s]:\n' % (tm)
351                if self.nbeam() > 1: out +=  ' Beam[%d] ' % (i)
352                if self.nif() > 1: out +=  ' IF[%d] ' % (j)
353                if self.npol() > 1: out +=  ' Pol[%d] ' % (k)
354                out += '= %3.3f\n' % (statval[l])
355                out +=  "--------------------------------------------------\n"
356
357            if self._vb:
358                print "--------------------------------------------------"
359                print " TSys"
360                print "--------------------------------------------------"
361                print out
362            retval = {'axes': axes, 'data': array(statval), 'cursor':(i,j,k)}
363            return retval
364       
365    def get_time(self, row=-1):
366        """
367        Get a list of time stamps for the observations.
368        Return a string for each integration in the scantable.
369        Parameters:
370            row:    row no of integration. Default -1 return all rows
371        Example:
372            none
373        """
374        out = []
375        if row == -1:
376            for i in range(self.nrow()):
377                out.append(self._gettime(i))
378            return out
379        else:
380            if row < self.nrow():
381                return self._gettime(row)
382
383    def set_unit(self, unit='channel'):
384        """
385        Set the unit for all following operations on this scantable
386        Parameters:
387            unit:    optional unit, default is 'channel'
388                     one of '*Hz','km/s','channel', ''
389        """
390        varlist = vars()
391        if unit in ['','pixel', 'channel']:
392            unit = ''
393        inf = list(self._getcoordinfo())
394        inf[0] = unit
395        self._setcoordinfo(inf)
396        if self._p: self.plot()
397        self._add_history("set_unit",varlist)
398
399    def set_instrument(self, instr):
400        """
401        Set the instrument for subsequent processing
402        Parameters:
403            instr:    Select from 'ATPKSMB', 'ATPKSHOH', 'ATMOPRA',
404                      'DSS-43' (Tid), 'CEDUNA', and 'HOBART'
405        """
406        self._setInstrument(instr)
407        self._add_history("set_instument",vars())
408
409    def set_doppler(self, doppler='RADIO'):
410        """
411        Set the doppler for all following operations on this scantable.
412        Parameters:
413            doppler:    One of 'RADIO', 'OPTICAL', 'Z', 'BETA', 'GAMMA'
414        """
415        varlist = vars()
416        inf = list(self._getcoordinfo())
417        inf[2] = doppler
418        self._setcoordinfo(inf)
419        if self._p: self.plot()
420        self._add_history("set_doppler",vars())
421 
422    def set_freqframe(self, frame=None):
423        """
424        Set the frame type of the Spectral Axis.
425        Parameters:
426            frame:   an optional frame type, default 'LSRK'.
427        Examples:
428            scan.set_freqframe('BARY')
429        """
430        if frame is None: frame = rcParams['scantable.freqframe']
431        varlist = vars()
432        valid = ['REST','TOPO','LSRD','LSRK','BARY', \
433                   'GEO','GALACTO','LGROUP','CMB']
434        if frame in valid:
435            inf = list(self._getcoordinfo())
436            inf[1] = frame
437            self._setcoordinfo(inf)
438            self._add_history("set_freqframe",varlist)
439        else:
440            print "Please specify a valid freq type. Valid types are:\n",valid
441           
442    def get_unit(self):
443        """
444        Get the default unit set in this scantable
445        Parameters:
446        Returns:
447            A unit string
448        """
449        inf = self._getcoordinfo()
450        unit = inf[0]
451        if unit == '': unit = 'channel'
452        return unit
453
454    def get_abcissa(self, rowno=0):
455        """
456        Get the abcissa in the current coordinate setup for the currently
457        selected Beam/IF/Pol
458        Parameters:
459            rowno:    an optional row number in the scantable. Default is the
460                      first row, i.e. rowno=0
461        Returns:
462            The abcissa values and it's format string (as a dictionary)
463        """
464        abc = self._getabcissa(rowno)
465        lbl = self._getabcissalabel(rowno)       
466        return abc, lbl
467        #return {'abcissa':abc,'label':lbl}
468
469    def create_mask(self, *args, **kwargs):
470        """
471        Compute and return a mask based on [min,max] windows.
472        The specified windows are to be INCLUDED, when the mask is
473        applied.
474        Parameters:
475            [min,max],[min2,max2],...
476                Pairs of start/end points specifying the regions
477                to be masked
478            invert:     optional argument. If specified as True,
479                        return an inverted mask, i.e. the regions
480                        specified are EXCLUDED
481        Example:
482            scan.set_unit('channel')
483
484            a)
485            msk = scan.set_mask([400,500],[800,900])
486            # masks everything outside 400 and 500
487            # and 800 and 900 in the unit 'channel'
488
489            b)
490            msk = scan.set_mask([400,500],[800,900], invert=True)
491            # masks the regions between 400 and 500
492            # and 800 and 900 in the unit 'channel'
493           
494        """
495        varlist = vars()
496        u = self._getcoordinfo()[0]
497        if self._vb:
498            if u == "": u = "channel"
499            print "The current mask window unit is", u
500        n = self.nchan()
501        data = self._getabcissa()
502        msk = zeros(n)
503        for window in args:
504            if (len(window) != 2 or window[0] > window[1] ):
505                print "A window needs to be defined as [min,max]"
506                return
507            for i in range(n):
508                if data[i] >= window[0] and data[i] < window[1]:
509                    msk[i] = 1
510        if kwargs.has_key('invert'):
511            if kwargs.get('invert'):
512                from numarray import logical_not
513                msk = logical_not(msk)
514        self._add_history("create_mask", varlist)
515        return msk
516   
517    def get_restfreqs(self):
518        """
519        Get the restfrequency(s) stored in this scantable.
520        The return value(s) are always of unit 'Hz'
521        Parameters:
522            none
523        Returns:
524            a list of doubles
525        """
526        return list(self._getrestfreqs())
527
528    def lines(self):
529        """
530        Print the list of known spectral lines
531        """
532        sdtable._lines(self)
533
534    def set_restfreqs(self, freqs=None, unit='Hz', lines=None, source=None,
535                      theif=None):
536        """
537        Select the restfrequency for the specified source and IF OR
538        replace for all IFs.  If the 'freqs' argument holds a scalar,
539        then that rest frequency will be applied to the selected
540        data (and added to the list of available rest frequencies).
541        In this way, you can set a rest frequency for each
542        source and IF combination.   If the 'freqs' argument holds
543        a vector, then it MUST be of length the number of IFs
544        (and the available restfrequencies will be replaced by
545        this vector).  In this case, *all* data ('source' and
546        'theif' are ignored) have the restfrequency set per IF according
547        to the corresponding value you give in the 'freqs' vector. 
548        E.g. 'freqs=[1e9,2e9]'  would mean IF 0 gets restfreq 1e9 and
549        IF 1 gets restfreq 2e9.
550
551        You can also specify the frequencies via known line names
552        in the argument 'lines'.  Use 'freqs' or 'lines'.  'freqs'
553        takes precedence. See the list of known names via function
554        scantable.lines()
555        Parameters:
556            freqs:   list of rest frequencies
557            unit:    unit for rest frequency (default 'Hz')
558            lines:   list of known spectral lines names (alternative to freqs).
559                     See possible list via scantable.lines()
560            source:  Source name (blank means all)
561            theif:   IF (-1 means all)
562        Example:
563            scan.set_restfreqs(freqs=1.4e9, source='NGC253', theif=2)
564            scan.set_restfreqs(freqs=[1.4e9,1.67e9])
565        """
566        varlist = vars()
567        if source is None:
568            source = ""
569        if theif is None:
570            theif = -1
571        t = type(freqs)
572        if t is int or t is float:
573           freqs = [freqs]
574        if freqs is None:
575           freqs = []
576        t = type(lines)
577        if t is str:
578           lines = [lines]
579        if lines is None:
580           lines = []
581        sdtable._setrestfreqs(self, freqs, unit, lines, source, theif)
582        self._add_history("set_restfreqs", varlist)
583       
584
585
586    def flag_spectrum(self, thebeam, theif, thepol):
587        """
588        This flags a selected spectrum in the scan 'for good'.
589        USE WITH CARE - not reversible.
590        Use masks for non-permanent exclusion of channels.
591        Parameters:
592            thebeam,theif,thepol:    all have to be explicitly
593                                     specified
594        Example:
595            scan.flag_spectrum(0,0,1)
596            flags the spectrum for Beam=0, IF=0, Pol=1
597        """
598        if (thebeam < self.nbeam() and
599            theif < self.nif() and
600            thepol < self.npol()):
601            sdtable.setbeam(self, thebeam)
602            sdtable.setif(self, theif)
603            sdtable.setpol(self, thepol)
604            sdtable._flag(self)
605            self._add_history("flag_spectrum", vars())
606        else:
607            print "Please specify a valid (Beam/IF/Pol)"
608        return
609
610    def plot(self, what='spectrum',col='Pol', panel=None):
611        """
612        Plot the spectra contained in the scan. Alternatively you can also
613        Plot Tsys vs Time
614        Parameters:
615            what:     a choice of 'spectrum' (default) or 'tsys'
616            col:      which out of Beams/IFs/Pols should be colour stacked
617            panel:    set up multiple panels, currently not working.
618        """
619        print "Warning! Not fully functional. Use plotter.plot() instead"
620       
621        validcol = {'Beam':self.nbeam(),'IF':self.nif(),'Pol':self.npol()}
622
623        validyax = ['spectrum','tsys']
624        from asap.asaplot import ASAPlot
625        if not self._p:
626            self._p = ASAPlot()
627            #print "Plotting not enabled"
628            #return
629        if self._p.is_dead:
630            del self._p
631            self._p = ASAPlot()
632        npan = 1
633        x = None
634        if what == 'tsys':
635            n = self.nrow()
636            if n < 2:
637                print "Only one integration. Can't plot."
638                return
639        self._p.hold()
640        self._p.clear()
641        if panel == 'Time':
642            npan = self.nrow()
643            self._p.set_panels(rows=npan)
644        xlab,ylab,tlab = None,None,None
645        self._vb = False
646        sel = self.get_cursor()       
647        for i in range(npan):
648            if npan > 1:
649                self._p.subplot(i)
650            for j in range(validcol[col]):
651                x = None
652                y = None
653                m = None
654                tlab = self._getsourcename(i)
655                import re
656                tlab = re.sub('_S','',tlab)
657                if col == 'Beam':
658                    self.setbeam(j)
659                elif col == 'IF':
660                    self.setif(j)
661                elif col == 'Pol':
662                    self.setpol(j)
663                if what == 'tsys':
664                    x = range(self.nrow())
665                    xlab = 'Time [pixel]'
666                    m = list(ones(len(x)))
667                    y = []
668                    ylab = r'$T_{sys}$'
669                    for k in range(len(x)):
670                        y.append(self._gettsys(k))
671                else:
672                    x,xlab = self.get_abcissa(i)
673                    y = self._getspectrum(i)
674                    ylab = r'Flux'
675                    m = self._getmask(i)
676                llab = col+' '+str(j)
677                self._p.set_line(label=llab)
678                self._p.plot(x,y,m)
679            self._p.set_axes('xlabel',xlab)
680            self._p.set_axes('ylabel',ylab)
681            self._p.set_axes('title',tlab)
682        self._p.release()
683        self.set_cursor(sel[0],sel[1],sel[2])
684        self._vb = rcParams['verbose']
685        return
686
687        print out
688
689    def _print_values(self, dat, label='', timestamps=[]):
690        d = dat['data']
691        a = dat['axes']
692        shp = d.getshape()
693        out = ''
694        for i in range(shp[3]):
695            out += '%s [%s]:\n' % (a[3],timestamps[i])
696            t = d[:,:,:,i]
697            for j in range(shp[0]):
698                if shp[0] > 1: out +=  ' %s[%d] ' % (a[0],j)
699                for k in range(shp[1]):
700                    if shp[1] > 1: out +=  ' %s[%d] ' % (a[1],k)
701                    for l in range(shp[2]):
702                        if shp[2] > 1: out +=  ' %s[%d] ' % (a[2],l)
703                        out += '= %3.3f\n' % (t[j,k,l])
704            out += "-"*80
705            out += "\n"
706        print "-"*80
707        print " ", label
708        print "-"*80
709        print out
710
711    def history(self):
712        hist = list(self._gethistory())
713        print "-"*80
714        for h in hist:
715            if h.startswith("---"):
716                print h
717            else:
718                items = h.split("##")
719                date = items[0]
720                func = items[1]
721                items = items[2:]
722                print date           
723                print "Function: %s\n  Parameters:" % (func)
724                for i in items:
725                    s = i.split("=")
726                    print "   %s = %s" % (s[0],s[1])
727                print "-"*80
728        return
729
730    def _add_history(self, funcname, parameters):
731        # create date
732        sep = "##"
733        from datetime import datetime
734        dstr = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
735        hist = dstr+sep
736        hist += funcname+sep#cdate+sep
737        if parameters.has_key('self'): del parameters['self']
738        for k,v in parameters.iteritems():
739            if type(v) is dict:
740                for k2,v2 in v.iteritems():
741                    hist += k2
742                    hist += "="
743                    if isinstance(v2,scantable):
744                        hist += 'scantable'
745                    elif k2 == 'mask':
746                        hist += str(self._zip_mask(v2))
747                    else:
748                        hist += str(v2)                   
749            else:
750                hist += k
751                hist += "="
752                if isinstance(v,scantable):
753                    hist += 'scantable'
754                elif k == 'mask':
755                    hist += str(self._zip_mask(v))
756                else:
757                    hist += str(v)
758            hist += sep
759        hist = hist[:-2] # remove trailing '##'
760        self._addhistory(hist)
761       
762
763    def _zip_mask(self, mask):
764        mask = list(mask)
765        i = 0
766        segments = []
767        while mask[i:].count(1):
768            i += mask[i:].index(1)
769            if mask[i:].count(0):
770                j = i + mask[i:].index(0)
771            else:
772                j = len(mask)               
773            segments.append([i,j])
774            i = j
775        return segments
Note: See TracBrowser for help on using the repository browser.