source: trunk/python/scantable.py @ 497

Last change on this file since 497 was 497, checked in by kil064, 19 years ago

document ascii output format better

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