1  """ 
   2    * Copyright (C) 2004, 2005 Cristina V. Torres 
   3    * 
   4    *  This program is free software; you can redistribute it and/or modify 
   5    *  it under the terms of the GNU General Public License as published by 
   6    *  the Free Software Foundation; either version 2 of the License, or 
   7    *  (at your option) any later version. 
   8    * 
   9    *  This program is distributed in the hope that it will be useful, 
  10    *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
  11    *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  12    *  GNU General Public License for more details. 
  13    * 
  14    *  You should have received a copy of the GNU General Public License 
  15    *  along with with program; see the file COPYING. If not, write to the 
  16    *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
  17    *  MA  02111-1307  USA 
  18  """ 
  19  __author__ = 'Cristina Torres <cristina.torres@ligo.org>' 
  20   
  21  import os 
  22  import numpy 
  23  import copy 
  24  import sys 
  25  try: 
  26    import sqlite3 as sqlite 
  27  except ImportError: 
  28    import sqlite 
  29  if os.getenv("DISPLAY") == None: 
  30     
  31    try: 
  32        import matplotlib 
  33        matplotlib.use("Agg") 
  34        import pylab 
  35    except Exception, errorInfo:  
  36        disableGraphics=True 
  37        sys.stderr.write("Error trying to import NON-INTERACTIVE pylab!\n") 
  38        sys.stderr.write("Exception Instance :%s\n"%(str(type(errorInfo)))) 
  39        sys.stderr.write("Exception Args     :%s\n"%(str(errorInfo.args))) 
  40        sys.stderr.write("Pylab functionality unavailable!\n") 
  41  else: 
  42     
  43    try: 
  44        import pylab 
  45    except Exception, errorInfo:  
  46        disableGraphics=True 
  47        sys.stderr.write("Error trying to import INTERACTIVE pylab!\n") 
  48        sys.stderr.write("Exception Instance :%s\n"%(str(type(errorInfo)))) 
  49        sys.stderr.write("Exception Args     :%s\n"%(str(errorInfo.args))) 
  50        sys.stderr.write("Pylab functionality unavailable!\n") 
  51   
  52  """ 
  53  This file is intended to provide the autotrack utilities required to 
  54  process the results of the tracksearch hybrid MDGC codes. 
  55  """ 
  56   
  58    """ 
  59    This writes the information in the tgnList to a simple text 
  60    file. Actually we write two files.  filename.TGN and 
  61    filename.AUX.  In the AUX file is information like time stamps, 
  62    and other misc information from the TGNs that are dumped to disk! 
  63    """ 
  64    if tgnList==None: 
  65      return 
  66     
  67    fp0=open(filename+".TGN",'wt') 
  68    fp1=open(filename+".AUX",'wt') 
  69    for tgn in tgnList: 
  70      a,b=tgn.reverseCreateFromString() 
  71      id=tgn.getID() 
  72      count=tgn.getMemberCount() 
  73      vol=tgn.getVolume() 
  74      fp0.write("%s\n%s\n"%(a,b)) 
  75      fp1.write("%s\t%s\t%s\n"%(id,count,vol)) 
  76    fp0.close() 
  77    fp1.close() 
   78     
  79     
  81    """ 
  82    This method opens a text file containing multiple TGNs and creates 
  83    a list of TGN objects.  It is assumed that this list of TGNs was 
  84    created at the same time for each TGN in the file. 
  85    """ 
  86    fp=open(filename,'rt') 
  87    rawData=fp.readlines() 
  88    fp.close() 
  89    linesPerTGN=2 
  90    if rawData.__len__().__mod__(linesPerTGN) != 0: 
  91        raise autotrackError("File appears inconsistent!") 
  92    eCount=rawData.__len__().__div__(linesPerTGN) 
  93    TGNList=list() 
  94    for index in range(0,eCount): 
  95        thisTGN=TGN() 
  96        thisTGN.createFromString(rawData[index*2],rawData[index*2+1]) 
  97        thisTGN.__setBirthDate__(timestamp) 
  98        thisTGN.__setGPS__(int(timestamp)) 
  99        TGNList.append(thisTGN) 
 100    return TGNList 
  101       
 102   
 104    """ 
 105    Method is a complex case statement that selects out given a 
 106    back-end name the properties that the TGN should be capable of 
 107    tracking. Depends on the output formatting of tracksearchMDGCv2.m 
 108    file 
 109    """ 
 110    if backEndName.strip().lower() == "tracksearch": 
 111         
 112        from lalapps.tracksearchutils import candidateListProperties 
 113        tmpProperties=candidateListProperties() 
 114         
 115         
 116         
 117         
 118         
 119         
 120        propertiesToKeep=[ 
 121            ["pp",0], 
 122            ["y",1], 
 123            ["b",2], 
 124            ["d",3], 
 125            ["a",4], 
 126            ["r",5], 
 127            ["rr",6], 
 128            ["w",7], 
 129            ["e",8], 
 130            ["ww",9], 
 131            ["ee",10] 
 132            ] 
 133        propertiesHandDefined=[ 
 134            ["ht","Time symmetry",11], 
 135            ["hf","Freq symmetry",12] 
 136            ] 
 137         
 138        finalPropertyList=[] 
 139        for myRow in propertiesToKeep: 
 140            for thatRow in tmpProperties: 
 141                if thatRow[0].lower().strip() == \ 
 142                        myRow[0].lower().strip(): 
 143                    finalPropertyList.append([myRow[0],thatRow[1],myRow[1]]) 
 144        for myRow in propertiesHandDefined: 
 145            finalPropertyList.append(myRow) 
 146    return finalPropertyList 
  147   
 148   
 150      """ 
 151      Takes an input list of tuples representing start,stop and merges 
 152      them placing them in time order when returning the coalesced list of 
 153      tuples. 
 154      """ 
 155      outputList=list() 
 156      if type(inputList) != type(list()): 
 157        sys.stderr.write("Wrong variable type passed as argument in\ 
 158   autotrackutils.__coalescetuplelist__()\n") 
 159        return None 
 160      if inputList.__len__() < 1: 
 161        return  inputList 
 162      inputList.sort() 
 163      while inputList: 
 164          segA=inputList.pop() 
 165          overlap=True 
 166           
 167          while overlap: 
 168               
 169              if inputList.__len__() > 0: 
 170                  segB=inputList.pop() 
 171              else: 
 172                   
 173                  segB=(-1,-1) 
 174                  overlap=False 
 175               
 176               
 177              if ( 
 178                  (segB[0]<= segA[0] <= segB[1]) 
 179                  and 
 180                  (segA[1] >= segB[1]) 
 181                  ): 
 182                  segA=(segB[0],segA[1]) 
 183               
 184              elif ( 
 185                    (segB[0]<= segA[1] <= segB[1]) 
 186                    and 
 187                    (segA[1] <= segB[0]) 
 188                   ): 
 189                  segA=(segA[0],segB[1]) 
 190               
 191              elif ( 
 192                  (segB[0]<=segA[0]) 
 193                  and 
 194                  (segB[1]>=segA[1]) 
 195                  ): 
 196                  segA=(segB[0],segB[1]) 
 197              else: 
 198                   
 199                  if not((-1,-1)==segB): 
 200                    inputList.append(segB) 
 201                  overlap=False 
 202          outputList.append(segA) 
 203          outputList.sort() 
 204      return outputList 
  205   
 206   
 208    """ 
 209    A simple coalesce feature useful to autotrack to return a list of 
 210    segments which define intervals that the thread was active. 
 211    """ 
 212    tupleList=list() 
 213    for tgn in tgnList: 
 214      start=float(tgn.getBirthDateText()) 
 215      stop=start+tgnSize 
 216      tupleList.append((start,stop)) 
 217    activeListofTuples=coalescetuplelist(tupleList) 
 218    return activeListofTuples 
  219   
 220   
 222    """ 
 223    Generic class raise this flag if we do not have a better 
 224    flag name. 
 225    """ 
  226     
 227   
 229    """ 
 230    Custom error exceptions for these class objects. 
 231    """ 
  232     
 233   
 235    """ 
 236    Custom error handling of mismatched ID 
 237    """ 
  238     
 239   
 240   
 242    """ 
 243    This class is a wrapper for plotting TGNs.  It can plot TGNs on a 
 244    2D plot of requested parameter options. 
 245    """ 
 246 -  def __init__(self,iTGN=None,thread=bool(False)): 
  247      """ 
 248      Ths method should be invoked blind with either a single TGN or 
 249      a list of TGNS.  Invoking without a TGN is still possible.  A 
 250      second argument lets the plotting code know if we are 
 251      comparing different TGNs or plotting a thread of TGNs. 
 252      """ 
 253      self.isThread=thread 
 254      if (iTGN != None and type(iTGN) != type([])): 
 255          raise autotrackError("plotTGN expects a list of TGN objects.") 
 256      self.tgnList=iTGN 
 257       
 258      self.defaultX="d" 
 259      self.defaultY="y" 
 260       
 261      self.memberSteps=100; 
  262     
 263   
 265      """ 
 266      Using the single character string see the output of 
 267      getQualityTable() select the quantity to show on the Xaxis. 
 268      """ 
 269      self.defaultX=newX 
  270     
 271   
 273      """ 
 274      Using the single character string see the output of 
 275      getQualityTable() select the quantity to show on the Yaxis. 
 276      """ 
 277      self.defaultY=newY 
  278     
 279   
 297     
 298   
 336     
 337   
 339      """ 
 340      Returns index and labels for X and Y axis 
 341      """ 
 342      for elem in getQualityTable(): 
 343          if elem[0].strip().lower() == self.defaultX: 
 344              xIndex=elem[2] 
 345              xLabel=elem[1] 
 346          if elem[0].strip().lower() == self.defaultY: 
 347              yIndex=elem[2] 
 348              yLabel=elem[1] 
 349      return [xIndex,xLabel,yIndex,yLabel] 
  350     
 351   
 353      """ 
 354      Is a macro of plotting commands that takes a list of TGNs that 
 355      plots each of these individually as a collection of points. 
 356      Creates a figure plotting the thread of list of TGNs using the 
 357      centroid and an X,Y error bars.  Take a optional boolean to 
 358      make the plot not include a title and legend 
 359      """ 
 360       
 361      xIndex=0 
 362      yIndex=0 
 363      xLabel="NULL" 
 364      yLabel="NULL" 
 365      (xIndex,xLabel,yIndex,yLabel)=self.__getIndexAndLabels__() 
 366      plotValues=list() 
 367      gpsTimesInList=list() 
 368      for thisTGN in self.tgnList: 
 369          label=str(thisTGN.getID()) 
 370           
 371          (xC,xE)=thisTGN.getCentroidErrorViaIndex(xIndex) 
 372          (yC,yE)=thisTGN.getCentroidErrorViaIndex(yIndex) 
 373          plotValues.append([xC,yC,xE,yE,label]) 
 374          gpsTimesInList.append(thisTGN.getGPS()) 
 375      for x,y,ex,ey,txtLabel in plotValues: 
 376          pylab.errorbar(x,y,xerr=ex,yerr=ey,label=txtLabel,marker='o') 
 377      pylab.xlabel(str(xLabel)) 
 378      pylab.ylabel(str(yLabel)) 
 379      if not bare: 
 380        pylab.title("TGNs: %i"%(min(gpsTimesInList))) 
 381        pylab.legend() 
  382     
 383   
 385      """ 
 386      Is a macro of plotting commands that takes a list of TGNs that 
 387      plots each of these individually as a collection of points. 
 388      Creates a figure plotting the thread of list of TGNs using the 
 389      centroid and an X,Y error bars 
 390      """ 
 391       
 392      xIndex=0 
 393      yIndex=0 
 394      xLabel="NULL" 
 395      yLabel="NULL" 
 396      for elem in getQualityTable(): 
 397          if elem[0].strip().lower() == self.defaultX: 
 398              xIndex=elem[2] 
 399              xLabel=elem[1] 
 400          if elem[0].strip().lower() == self.defaultY: 
 401              yIndex=elem[2] 
 402              yLabel=elem[1] 
 403      plotValues=list() 
 404      gpsTimesInList=list() 
 405      for thisTGN in self.tgnList: 
 406          txtLabel=str(thisTGN.getGPS()) 
 407           
 408          (xC,xE)=thisTGN.getCentroidErrorViaIndex(xIndex) 
 409          (yC,yE)=thisTGN.getCentroidErrorViaIndex(yIndex) 
 410          plotValues.append([xC,yC,xE,yE,txtLabel]) 
 411          gpsTimesInList.append(thisTGN.getGPS()) 
 412      xVec=list() 
 413      yVec=list() 
 414      for x,y,ex,ey,txtLabel in plotValues: 
 415          xVec.append(x) 
 416          yVec.append(y) 
 417      pylab.plot(xVec,yVec,label="Time Line") 
 418      for x,y,ex,ey,txtLabel in plotValues: 
 419          pylab.errorbar(x,y,xerr=ex,yerr=ey,label=txtLabel,marker='o') 
 420      pylab.xlabel(str(xLabel)) 
 421      pylab.ylabel(str(yLabel)) 
 422      if not bare: 
 423        pylab.title("TGN Thread %i"%(min(gpsTimesInList))) 
 424        pylab.legend() 
   425     
 426   
 427   
 429    """ 
 430    This class provides the definition of a single defined autotrack 
 431    defined neighborhood.  We use these neighborhoods to track 
 432    how the instrument behavior groups change, appear or disappear. 
 433    """ 
 435        """ This method initializes an empty neighborhood. 
 436        To populate the neightborhood invoke the proper method 
 437        depending on the source of the data, ie ascii mysql etc 
 438        """ 
 439        self.delim=" " 
 440        self.idNum=float(-1) 
 441        self.density=float(0) 
 442        self.memberCount=0 
 443        self.volume=0 
 444        self.colCount=0 
 445        self.birthdate=str("-1") 
 446        self.gpsStamp=int(-1) 
 447        self.discoverer=str() 
 448        self.lastSeen=float(0) 
 449        self.center=None 
 450        self.bound=None 
 451         
 452         
 453         
 454         
 455        self.qualities=getQualityTable("tracksearch") 
  456     
 457   
 459        """ 
 460        Should set the ID numeric field 
 461        """ 
 462        if type(float(0)) != type(inputArg): 
 463            inputArg=float(inputArg) 
 464        self.idNum=inputArg 
  465     
 466   
 468        """ 
 469        Fetches the numeric ID assigned to this TGN instance 
 470        """ 
 471        return self.idNum 
  472     
 473   
 475        """ 
 476        Set a text string which is the GPS birthdate, 
 477        as closely as possible for this neighborhood. 
 478        """ 
 479        if type(str()) != type(bDate): 
 480            bDate=str(bDate) 
 481        self.birthdate=bDate 
  482     
 483   
 485        """ 
 486        Set a text string which is the GPS birthdate, 
 487        as closely as possible for this neighborhood. 
 488        """ 
 489        if type(int()) != type(gps): 
 490            raise autotrackError("GPS time not a INT type.") 
 491        self.gpsStamp=gps 
  492     
 493   
 495        """ 
 496        This retrieves the text string birthdate stored in TGN 
 497        instance. 
 498        """ 
 499        return self.birthdate 
  500     
 501   
 503        """ 
 504        This retrieves the integer GPS birthdate stored in TGN 
 505        instance. 
 506        """ 
 507        return self.gpsStamp 
  508     
 509   
 511        """ 
 512        This input method assumes you've opened a text file container 
 513        and will input the data from text strings.  The assumed 
 514        delimiter is a space but can be set in the method call. 
 515        """ 
 516        self.delim=delim 
 517        if self.delim == " ": 
 518          mData=str(mString).lower().split(None) 
 519          bData=str(bString).lower().split(None) 
 520        else: 
 521          mData=str(mString).lower().split(delim) 
 522          bData=str(bString).lower().split(delim) 
 523        mCol=mData.__len__() 
 524        sCol=bData.__len__() 
 525        if (mData.__len__()) != (bData.__len__()): 
 526            raise autotrackDefineMismatchError("Array lengths %i vs %i"%(mData.__len__(),bData.__len__())) 
 527        self.colCount=mCol 
 528         
 529        mID=mData.pop(0) 
 530        mDensity=mData.pop(0) 
 531        mCount=mData.pop(0) 
 532        mVolume=mData.pop(0) 
 533         
 534        sID=bData.pop(0) 
 535        sDensity=bData.pop(0) 
 536        sCount=bData.pop(0) 
 537        sVolume=bData.pop(0) 
 538         
 539        if mID != sID: 
 540            raise autotrackDefineIdMismatchError("Group labels do not match!") 
 541        if mDensity != sDensity: 
 542            raise autotrackDefineIdMismatchError("Group density values do not match!") 
 543        if mCount != sCount: 
 544            raise autotrackDefineIdMismatchError("Group count values do not match!") 
 545        if mVolume!=sVolume: 
 546            raise autotrackDefineIdMismatchError("Group volume measures do not match! %f \t %f"%(float(mVolume),float(sVolume))) 
 547        self.__setID__(float(mID)) 
 548        self.__setDensity__(float(mDensity)) 
 549        self.__setMemberCount__(float(mCount)) 
 550        self.__setVolume__(float(mVolume)) 
 551        self.center=numpy.array([numpy.float64(j) for j in mData],'float64') 
 552        self.bound=numpy.array([numpy.float64(j) for j in bData],'float64') 
  553     
 554   
 556      """ 
 557      Returns a tuple of two strings, that can be dumped to disk and read 
 558      back into a TGN object with method createFromString() 
 559      """ 
 560      stringA,stringB=self.exportToString().split("\n") 
 561      return (stringA,stringB) 
  562     
 563   
 565        """ 
 566        Sets the tally of members in the group. 
 567        """ 
 568        self.memberCount=mCount 
  569     
 570   
 572        """ 
 573        get the registered members listed for this TGN 
 574        """ 
 575        return self.memberCount 
  576     
 577   
 579        """ 
 580        Sets the volume value of this grouping. 
 581        """ 
 582        self.volume=volume 
  583     
 584   
 586        """ 
 587        Gets the registered volume for a given TGN. 
 588        """ 
 589        return self.volume 
  590     
 591   
 593        """ 
 594        Create a text string that can be directly inserted into the 
 595        text field of the sqlite database table TGN. 
 596        """ 
 597        delimiter=self.delim 
 598        outputString="" 
 599        outputString=outputString+"%s%s"%(delimiter,self.getID()) 
 600        outputString=outputString+"%s%s"%(delimiter,self.getDensity()) 
 601        if self.colCount >= 17: 
 602            outputString=outputString+"%s%s"%(delimiter,self.getMemberCount()) 
 603            outputString=outputString+"%s%s"%(delimiter,self.getVolume()) 
 604        for elem in self.center: 
 605            outputString=outputString+"%s%s"%(delimiter,elem) 
 606        outputString=outputString+"\n" 
 607        outputString=outputString+"%s%s"%(delimiter,self.getID()) 
 608        outputString=outputString+"%s%s"%(delimiter,self.getDensity()) 
 609        if self.colCount >= 17: 
 610            outputString=outputString+"%s%s"%(delimiter,self.getMemberCount()) 
 611            outputString=outputString+"%s%s"%(delimiter,self.getVolume()) 
 612        for elem in self.bound: 
 613            outputString=outputString+"%s%s"%(delimiter,elem) 
 614        return outputString 
  615     
 616   
 618        """ 
 619        Returns the value of TGN density set. 
 620        """ 
 621        return self.density 
  622     
 623   
 625        """ 
 626        Sets the input density value to the TGN instance. 
 627        """ 
 628        if type(float(0)) != type(inputArg): 
 629            inputArg=float(inputArg) 
 630        self.density=inputArg 
  631     
 632   
 634        """ 
 635        Check the defined properties, returns true if they are all 
 636        zeroed out which is NULL according the the matlab generator. 
 637        """ 
 638        isNull=bool(False) 
 639        cV=self.getCenterVector() 
 640        bV=self.getBoundVector() 
 641        if numpy.any(cV==0) and numpy.any(bV==0): 
 642            isNull=bool(True) 
 643        return isNull 
  644     
 645   
 647        """ 
 648        Gets the variance components of this TGN instance. 
 649        """ 
 650        return self.bound 
  651     
 652   
 654        """ 
 655        Gets the center of the neighborhood 
 656        """ 
 657        return self.center 
  658     
 659   
 661        """ 
 662        Given an index select the that index from the Center vector 
 663        and the bound Vector. This will return a tuple (center,bound) 
 664        """ 
 665        centerVec=self.getCenterVector() 
 666        boundVec=self.getBoundVector() 
 667        vectorLength=centerVec.__len__() 
 668        if index >= vectorLength: 
 669            raise autotrackError("Invalid index requested exceeds\ 
 670      elements available. Elements: %i Index Sought: %i"%(vectorLength,index)) 
 671        center=centerVec[index] 
 672        bound=boundVec[index] 
 673        return (center,bound) 
  674     
 675   
 677        """ 
 678        Checks to see if self instance is IDENTICAL to  
 679        TGN instance given as argument! 
 680        """ 
 681        samePoint=bool(False) 
 682        samePoint=self.checkOverlap(TGN,0) 
 683        if samePoint and self.idNum==TGN.idNum and self.density==TGN.density: 
 684            return bool(True) 
 685        return bool(False) 
  686   
 687 -  def checkOverlap(self,TGN,boundSize=0.5,mutual=bool(True)): 
  688        """ 
 689        Check to see if SELF neighborhood overlaps with other input 
 690        TGN class.  We define them as over lapping if they are 
 691        withing boundSize stddevs of the center of SELF compared 
 692        to the center of argument TGN. The last optional argument 
 693        dictates that given the bound vector of both TGNs they should be 
 694        able to 'walk' into each other not just A into B but that B must 
 695        also be able to step into the neighborhood of B. 
 696        """ 
 697        stepVectorSelf=boundSize*numpy.array(self.getBoundVector()).__abs__() 
 698        stepVectorTGN=boundSize*numpy.array(TGN.getBoundVector()).__abs__() 
 699        diffVector=numpy.array( 
 700            self.getCenterVector() 
 701            -TGN.getCenterVector()).__abs__() 
 702        if mutual: 
 703          if numpy.array(diffVector<=stepVectorSelf).all()\ 
 704                           and\ 
 705             numpy.array(diffVector<=stepVectorTGN).all(): 
 706            return bool(True) 
 707          else: 
 708            return bool(False) 
 709        else: 
 710          if numpy.array(diffVector<=stepVectorSelf).all(): 
 711              return bool(True) 
 712          else: 
 713              return bool(False) 
  714         
 715   
 717        """ 
 718        Gets the resultant seperation vectors and normalizes this  
 719        value by the boundVector, then use this to compute a  
 720        normalized magnitude of the vector. 
 721        """  
 722        diffVector=numpy.array( 
 723            self.getCenterVector() 
 724            -TGN.getCenterVector()).__abs__() 
 725        bv=self.getBoundVector() 
 726        sepVector=diffVector.__div__(bv) 
 727        mag=numpy.sqrt(numpy.inner(sepVector,sepVector)) 
 728        return mag 
  729     
 730   
 732      """ 
 733      Return the index returned by getCenterVector for self the spatial 
 734      axis with the smallest difference between self.getCenterVector and 
 735      TGN.getCenterVector  
 736      returns a tuple of two indices {minAxisIndex,maxAxisIndex} 
 737      """ 
 738      diffVector=numpy.array( 
 739        self.getCenterVector() 
 740        -TGN.getCenterVector()).__abs__() 
 741      smallIndex=diffVector.argmin() 
 742      largeIndex=diffVector.argmax() 
 743      return (smallIndex,largeIndex) 
  744     
 745   
 747        """ 
 748        wrapper 
 749        """ 
 750        myN=self.nearestTGN(TGNList,boundSize) 
 751        myID=myN.getID() 
 752        return myID 
  753   
 755        """ 
 756        Takes a list of TGNs and compares it to self 
 757        to determine which is the closest one, this ideally 
 758        is the same group and we can associate the group IDs. If method 
 759        does not find TGN it returns a NONE value. 
 760        """ 
 761        if type(list())!=type(TGNList): 
 762            raise autotrackError("Type of input to method nearestTGNid is wrong!") 
 763        distanceKey=list() 
 764        for index in range(0,TGNList.__len__()): 
 765             
 766            if not TGNList[index].isNULL(): 
 767                if self.checkOverlap(TGNList[index],boundSize): 
 768                    dist=self.getSeparation(TGNList[index]) 
 769                    idVal=TGNList[index].getID() 
 770                    distanceKey.append([dist,idVal]) 
 771        distanceKey.sort() 
 772        try: 
 773            findID=int(distanceKey[0][1]) 
 774        except IndexError: 
 775            findID=-1 
 776        if findID > -1: 
 777            for nhd in TGNList: 
 778                if nhd.getID() == findID: 
 779                    foundTGN=nhd 
 780        else: 
 781            foundTGN=None 
 782        return foundTGN 
   783       
 784   
 785           
 787      """ 
 788      This class is a simple list object with manipulation methods which 
 789      is called a thread that shows how the TNGs are related and it also 
 790      tracks knots (intersections/overlaps) of two different threads. 
 791      Thereby relating them. Three lists are tracked: 
 792      0) The thread serial number for quick ID 
 793      1) A thread name if given(default is thread serial number) 
 794      2) The list of TGN what are related and sorted by time 
 795      3) The list of knots (threads with overlaping TGNs) 
 796      """ 
  801       
 802         
 803   
 805      """ 
 806      This class provides sqlite table creation query deletion etc, 
 807      related funtions for working the the autotrack databases.  This 
 808      """ 
 809 -    def __init__(self,dbName="autotrack_default.sqlite"): 
  810          """ 
 811          Initializes the variables associated with the autotrackSQL 
 812          database manipulations. Setup is {TableName,Bool,{Definition}} 
 813          """ 
 814          self.dbFile="" 
 815          self.dbSocket=None 
 816           
 817          self.tables=dict() 
 818          self.table['active_tgn']={'group_serial_number':'blob', 
 819                                    'group_birthdate'    :'text', 
 820                                    'group_gps'          :'integer', 
 821                                    'discoverer'         :'text', 
 822                                    'group_IFO'          :'text', 
 823                                    'group_label'        :'text', 
 824                                    'group_density'      :'text', 
 825                                    'group_member_count' :'text', 
 826                                    'group_last_seen'    :'text', 
 827                                    'statistics'         :'blob'} 
 828   
 829          self.table['scientist_entry']={'group_serial_number'  :'blob', 
 830                                         'entry_date'           :'text', 
 831                                         'scientist'            :'blob', 
 832                                         'channels_of_interest' :'blob', 
 833                                         'URLs_of_interest'     :'blob', 
 834                                         'description_text'     :'text', 
 835                                         'solution_text'        :'text', 
 836                                         'misc_information'     :'text', 
 837                                         'usefulness_score'     :'text', 
 838                                         'extra_field1'         :'blob', 
 839                                         'extra_field2'         :'blob', 
 840                                         'extra_field3'         :'blob'} 
 841   
 842          self.table['plot_locations']={'group_serial_number' :'blob', 
 843                                         'line_plot'          :'blob', 
 844                                         'aux_plots'          :'blob'} 
 845   
 846          self.table['inactive_tgn']={'group_serial_number' :'blob', 
 847                                        'group_birthdate'     :'text', 
 848                                        'group_gps'          :'integer', 
 849                                        'discoverer'          :'text', 
 850                                        'group_label'         :'text', 
 851                                        'group_density'       :'real', 
 852                                        'group_member_count'  :'integer', 
 853                                        'group_last_seen'     :'text', 
 854                                        'statistics'          :'blob'} 
 855   
 856          self.table['active_threads']={'thread_serial_number' :'blob', 
 857                                        'thread_name'          :'text', 
 858                                        'group_list'           :'blob', 
 859                                        'knot_list'            :'blob'} 
 860   
 861          self.table['inactive_threads']={'thread_serial_number' :'blob', 
 862                                          'thread_name'          :'text', 
 863                                          'group_list'           :'blob', 
 864                                          'knot_list'            :'blob'} 
 865   
 866           
 867           
 868          self.__selectDB__(dbName) 
  869           
 870   
 872          """ 
 873          Selects the specified if it exists is reads the contents 
 874          or if not is issues a warning and tells you the db  
 875          needs to be created. 
 876          """ 
 877           
 878           
 879           
 880          self.dbSocket=sqlite.connect(dbName) 
 881          self.dbFile=dbName 
 882           
 883          try: 
 884              self.dbSocket.execute("select * from %s"%(self.defineTables[0][0])) 
 885          except: 
 886              sys.stdout.write("It appears that we need to create the tables.\n") 
 887              self.createTables() 
  888           
 889   
 891          """ 
 892          Given a string searches the tuple self.defineTables to 
 893          determine the index of that table to various function calls. 
 894          """ 
 895          answer=int(-1) 
 896          for index in range(self.defineTables.__len__()): 
 897              if self.defineTables[index][0].lower() == name.lower(): 
 898                  answer=index 
 899          if not(type(int()) == type(answer)): 
 900              raise autotrackError("getTableIndex type invalid!\n %s"(answer)) 
 901          return answer 
  902       
 903   
 905          """ 
 906          This method will generate a table from the list of tables 
 907          and definitions specified by self.autotrackTableDef or 
 908          self.auxTableDef 
 909          """ 
 910          tableIndex=self.DEPRICATEDgetTableIndex(name) 
 911          thisTable=self.defineTables[tableIndex] 
 912          tableName=thisTable[0] 
 913          required=thisTable[1] 
 914          colDefs=thisTable[2] 
 915          rowString="" 
 916          for col in colDefs: 
 917              rowString=rowString+"%s "%(col) 
 918          commandString="create table %s (%s)"%(tableName,rowString) 
 919          try: 
 920              self.dbSocket.execute(commandString) 
 921          except: 
 922              sys.stderr.write("Error trying to create table.\n") 
 923              self.dbSocket.commit() 
 924              return 
 925          self.dbSocket.commit() 
  926           
 927   
 929          """ 
 930          This method will generate a table from the list of tables 
 931          and definitions specified by self.autotrackTableDef or 
 932          self.auxTableDef 
 933          """ 
 934          if (name == None or tabledef == None): 
 935              return 
 936          tableName=name 
 937          colDefs=tabledef 
 938          rowString="" 
 939          for col in colDefs: 
 940              rowString=rowString+"%s "%(col) 
 941          commandString="create table %s (%s)"%(tableName,rowString) 
 942          try: 
 943              self.dbSocket.execute(commandString) 
 944          except: 
 945              sys.stderr.write("Error trying to create table.\n") 
 946              self.dbSocket.commit() 
 947              return 
 948          self.dbSocket.commit() 
  949           
 950           
 952          """ 
 953          Returns an object which is a raw handle to the dqlite DB. 
 954          This is equivalent to being returned X from 
 955          X=sqlite.connect('dbfilename') 
 956          """ 
 957          return self.dbSocket 
  958           
 959   
 961          """ 
 962          This function call will create the specified sqlite db unless 
 963          there exists one already.  In that case we throw an error 
 964          unless we explicitly want to overwrite that table. 
 965          """ 
 966          for index in self.tables.keys(): 
 967              sys.stdout.write("Creating table %s\n"%(index)) 
 968              self.__createSingleTable__(index,self.tables[index]) 
 969          self.dbSocket.commit() 
  970           
 971   
 973          """ 
 974          This method will fetch the groups defined at time NOW in table 
 975          TGN(default).  It returns these groups as a list of TGN objects. 
 976          """ 
 977           
 978           
 979           
 980           
 981          print "HI" 
  982           
 983   
 985          """ 
 986          This returns only the head of the thread to keep memory 
 987          requirements to a minimum.  The thread object will only 
 988          be loaded if a manipulation to the thread or thread report 
 989          method is called. 
 990          """ 
 991          print "Getting all TGN heads from threads." 
  992           
 993   
 995          """ 
 996          This function will return a thread object (list) for a  
 997          TGN thread that exists in the table specified.  By default 
 998          we search the active threads in table TGN. 
 999          """ 
1000          print "Getting single thread by name" 
 1001           
1002   
1004          """ 
1005          Returns a single TGN object the thread head for quoted 
1006          thread. 
1007          """ 
1008          print "Getting TGN head from thread" 
  1009           
1010   
1011       
1012       
1013       
1014       
1015       
1016