1   
   2   
   3  import os, sys, shutil, time 
   4  import pickle, glob 
   5  import subprocess, commands 
   6  import ConfigParser, optparse 
   7  import itertools 
   8  import urllib 
   9  from datetime import datetime 
  10   
  11  import numpy as np 
  12  import matplotlib 
  13  matplotlib.use('Agg') 
  14   
  15  from glue import segments 
  16  from glue import segmentsUtils 
  17  from glue.ligolw import lsctables 
  18  from glue.ligolw import ligolw 
  19  from glue.ligolw import table 
  20  from glue.ligolw import utils 
  21  from pylal.plotsegments import PlotSegmentsPlot 
  22  from pylal.grbsummary import multi_ifo_compute_offsource_segment as micos 
  23  from pylal import antenna 
  24  from pylal.xlal import date 
  25  from pylal import git_version 
  26   
  27   
  28  cp = None 
  29  maindir = None 
  30   
  31  template_trigger_hipe = "./lalapps_trigger_hipe"\ 
  32    " --number-buffer-left 8 --number-buffer-right 8"\ 
  33    " --verbose --skip-datafind "\ 
  34    " --injection-config injectionsWI.ini" \ 
  35    " --user-tag onoff" 
  36   
  37  template_trigger_hipe_inj = "./lalapps_trigger_hipe"\ 
  38    " --number-buffer-left 8 --number-buffer-right 8" \ 
  39    " --verbose --skip-datafind "\ 
  40    " --user-tag inj "\ 
  41    " --overwrite-dir" 
  42   
  43   
  44  basic_ifolist = ['H1','H2','L1','V1'] 
  45   
  46   
  47  colors = itertools.cycle(['b', 'g', 'r', 'c', 'm', 'y']) 
  48   
  49   
  50   
  51  runtimes = {'A':[931035296,935798487],'B':[937800015,947347215],\ 
  52              'C':[949003215,961545615],'D':[961545615, 971654415] } 
  53   
  54   
  55  offset_gps_to_linux = 315964800  
  56   
  57   
  58  total_summary_prefix = """ 
  59  <body style="color: rgb(0, 0, 0); background-color: rgb(221, 255, 255);" alink="#000099" link="#000099" vlink="#990099"> 
  60   
  61  <h1>Summary of Gamma Ray Burst low-latency results during S6</h1> 
  62   
  63  <span style="font-weight: bold;"><br><br> 
  64  The following table contain a list of Gamma Ray Bursts occured during S6, with information about time, position on the sky, as well as duration and redshift (if available). This table has been automatically created by pylal_exttrig_llmonitor (in pylal_exttrig_llutils.py) to show a summary of the low-latency inspiral analysis of the GRBs during S6. A page describing this search can be found in the <a href="https://www.lsc-group.phys.uwm.edu/ligovirgo/cbcnote/S6Plan/090706044855TriggeredSearchLow_Latency_Exttrig_Search#preview">wiki</a>. The page containing Isabels list of GRB triggers can be found <a href="https://ldas-jobs.ligo.caltech.edu/~xpipeline/S6/grb/online/triggers/S6Agrbs_list.html">here</a> which might differ from this page. <br><br> 
  65   
  66  A detailed explanation of the terms, expressions and used colors can be found <a href="s6_exttrig_info.html">here</a>.<br> 
  67   
  68  Total number of GRB in this list: %d<br> 
  69  Number of GRB with data: %d <br> 
  70  Number of GRB without data: %d<br> 
  71  Number of long GRB: %d (with data %d)<br> 
  72  Number of short GRB: %d (with data %d)<br><br> 
  73  Number of completed GRB: %d (short: %d)<br> 
  74  Number of opened GRB: %d (short: %d)<br><br> 
  75   
  76  Date of last creation: %s<br><br> 
  77   
  78  </span><span style="font-weight: bold;"> 
  79  <br><br> 
  80  </div> 
  81  <table border="1" cellpadding="2" cellspacing="2"> 
  82    <tbody> 
  83    <td style="vertical-align: top; font-weight: bold; font-style: italic; color: rgb(51, 51, 255); background-color: rgb(255, 153, 0);">Nr</td> 
  84    <td style="vertical-align: top; font-weight: bold; font-style: italic; color: rgb(51, 51, 255); background-color: rgb(255, 153, 0);">GRB</td> 
  85    <td style="vertical-align: top; font-weight: bold; font-style: italic; color: rgb(51, 51, 255); background-color: rgb(255, 153, 0);">Status</td> 
  86    <td style="vertical-align: top; font-weight: bold; font-style: italic; color: rgb(51, 51, 255); background-color: rgb(255, 153, 0);">Tag</td> 
  87    <td style="vertical-align: top; font-weight: bold; font-style: italic; color: rgb(51, 51, 255); background-color: rgb(255, 153, 0);">GPS<br> 
  88    <td style="vertical-align: top; font-weight: bold; font-style: italic; color: rgb(51, 51, 255); background-color: rgb(255, 153, 0);">Date<br> 
  89    <td style="vertical-align: top; font-weight: bold; font-style: italic; color: rgb(51, 51, 255); background-color: rgb(255, 153, 0);">redshift<br> 
  90    <td style="vertical-align: top; font-weight: bold; font-style: italic; color: rgb(51, 51, 255); background-color: rgb(255, 153, 0);">duration<br> 
  91    <td style="vertical-align: top; font-weight: bold; font-style: italic; color: rgb(51, 51, 255); background-color: rgb(255, 153, 0);">Coord<br> 
  92    <td style="vertical-align: top; font-weight: bold; font-style: italic; color: rgb(51, 51, 255); background-color: rgb(255, 153, 0);">H1<br> 
  93    <td style="vertical-align: top; font-weight: bold; font-style: italic; color: rgb(51, 51, 255); background-color: rgb(255, 153, 0);">L1<br> 
  94    <td style="vertical-align: top; font-weight: bold; font-style: italic; color: rgb(51, 51, 255); background-color: rgb(255, 153, 0);">V1<br> 
  95    <td style="vertical-align: top; font-weight: bold; font-style: italic; color: rgb(51, 51, 255); background-color: rgb(255, 153, 0);">Sanity<br> 
  96    <td style="vertical-align: top; font-weight: bold; font-style: italic; color: rgb(51, 51, 255); background-color: rgb(255, 153, 0);">Result<br> 
  97    <td style="vertical-align: top; font-weight: bold; font-style: italic; color: rgb(51, 51, 255); background-color: rgb(255, 153, 0);">Box<br> 
  98  """ 
  99   
 100   
 102      """ 
 103      Makes an internal call to the shell (with the 
 104      current set environment), wait for completion 
 105      and returns the output and error of the command. 
 106      @param command: command to be executed internally 
 107      @return: a tuple (status, output, error) 
 108      """ 
 109   
 110       
 111   
 112      p = subprocess.Popen(command, shell=True, \ 
 113                           stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
 114   
 115       
 116       
 117      out, err =  p.communicate() 
 118   
 119       
 120      errorcode = p.poll() 
 121   
 122      return errorcode, out, err 
  123   
 124   
 125 -def system_call(item, command, divert_output_to_log = True): 
  126    """ 
 127    Makes a system call. 
 128    @params item: a text specifying the content of the text 
 129           (e.g. number of the GRB the message is associated with) 
 130           (see also 'info') 
 131    @params command: the command to be executed on the bash 
 132    @params divert_output_to_log: If this flag is set to True the output of the  
 133                                  given command is automatically put into the log-file. 
 134                                  If the output of some command itself is further used, 
 135                                  like science segments, this flag must be set  
 136                                  to False, so that the output is diverted where it should go. 
 137    """ 
 138    l = logfile_name() 
 139   
 140     
 141    info(item, ">>> "+command) 
 142     
 143     
 144    if divert_output_to_log: 
 145      command_actual = command+' >>%s 2>>%s '%(l,l) 
 146    else: 
 147      command_actual = command +' 2>>%s '%l 
 148      
 149     
 150    code, out, err = external_call(command_actual) 
 151   
 152    if code>0 and len(err)>0: 
 153      info(item, "ERROR: " +err) 
  154   
 155   
 157    """ 
 158    Returns the current time in human-readable format 
 159    """ 
 160    return time.asctime(time.gmtime()) 
  161   
 162   
 164    """ 
 165    Computes the correct GPS time from the date and time 
 166    as given in text strings. 
 167    @param date_string: date in a string format, i.e. 090717 
 168    @param time_string: time in a string format, i.e. 19:10:34 
 169    """ 
 170   
 171     
 172     
 173    a = time.strptime(date_string, "%y%m%d") 
 174    time_list = time_string.split('.') 
 175    b = time.strptime(time_list[0], "%H:%M:%S") 
 176    if len(time_list)==2: 
 177      nsecs = time_list[1] 
 178      nsecs += (9-len(nsecs))*'0' 
 179      nano_seconds = int(nsecs)  
 180    else: 
 181      nano_seconds = 0 
 182   
 183     
 184    tm = datetime(a[0], a[1], a[2], b[3], b[4], b[5]).timetuple() 
 185     
 186     
 187    gpstime = date.XLALUTCToGPS(tm) 
 188   
 189    return int(gpstime) 
  190   
 191   
 193    """ 
 194    Returns the main directory of the analysis from the 
 195    cp file. If that does not exist, returns the current directory. 
 196    """ 
 197    if cp is not None: 
 198      main_dir = cp.get('paths','main')+'/' 
 199    elif maindir is not None: 
 200      main_dir = maindir 
 201    else: 
 202      main_dir = './' 
 203    return main_dir 
  204   
 205   
 207    """ 
 208    Returns the file of the logfile; used in 'info' and 'system_call' 
 209    """ 
 210    return get_main_dir()+'llmonitor.log' 
  211   
 212   
 213 -def info(item, text): 
  214    """ 
 215    Prints an info into the log-file. 
 216    @item: a text specifying the content of the text  
 217           (e.g. number of the GRB the message is associated with) 
 218    @text: the text to be logged 
 219    """ 
 220    msg = get_time() + ' ('+item+'): '+text 
 221     
 222    log_file = logfile_name() 
 223    logfile = open(log_file,'a') 
 224    logfile.write(msg+'\n') 
 225    logfile.close() 
 226   
 227    print msg 
  228   
 229   
 230 -def send_mail(subject, msg, email_addresses = None, extra_addresses = None): 
  231    """ 
 232    Function to send an email to a certain adress 
 233    @param subject: Subject line of the email 
 234    @param msg: Message of the email 
 235    @param email_addresses: list of email addresses to which the mail is sent 
 236    @param extra_addresses: Extra adresses to which to send the email 
 237    """ 
 238   
 239     
 240    message = 'Automatic notification from pylal_exttrig_llmonitor at time '+\ 
 241              get_time()+'\n\n'+subject+'\n'+msg 
 242    subject = cp.get('notifications','head') + ': '+subject 
 243       
 244     
 245    tmp_file = '.llmonitor.email' 
 246    f = file(tmp_file,'w') 
 247    f.write(message) 
 248    f.close() 
 249   
 250     
 251    if not email_addresses: 
 252      email_addresses = cp.get('notifications','email').replace(',',' ').split() 
 253   
 254    if extra_addresses: 
 255      email_addresses.extend(extra_addresses) 
 256   
 257     
 258    for address in email_addresses: 
 259      command = "mail -s '%s' %s < %s" % (subject, address, tmp_file) 
 260      system_call('email',command) 
  261    
 262   
 263 -def notify(grb, dag, message): 
  264    """ 
 265    Makes an email notification to all recipients listed 
 266    in the config file. 
 267    @param grb: grb dictionary for obtaining some informations 
 268    @param message: the message of the notification 
 269    """ 
 270   
 271     
 272    subject = 'Status changed for DAG GRB%s: %s' %\ 
 273         (grb.name, message) 
 274   
 275     
 276    email_msg = 'Automatic notification from pylal_exttrig_llutils at time %s\n\n'%\ 
 277                get_time() 
 278    email_msg += subject+'\n' 
 279    email_msg += 'The analysis dir is %s\n' % grb.analysis_dir 
 280    email_msg += ' and the dagfils is %s\n' % dag.get_outname() 
 281   
 282     
 283    send_mail(subject, email_msg) 
 284   
 285     
 286    info("email","  Email notification sent with the following content: "+\ 
 287         email_msg.replace('\n','\n    ')) 
  288   
 289   
 290   
 292    """ 
 293    Returns the name of the lock file 
 294    """ 
 295    return get_main_dir()+'.llmonitor.lock' 
  296   
 297   
 299    """ 
 300    Checks if another instance of this code is running. 
 301    See http://code.activestate.com/recipes/546512/ 
 302    """ 
 303    lockname = get_lockname() 
 304    if os.path.exists(lockname): 
 305      pid=open(lockname, 'r').read().strip() 
 306      pidRunning=commands.getoutput('ls /proc | grep %s' % pid) 
 307      if pidRunning: 
 308        return pid 
 309      else: 
 310        return None 
 311    
 312    return None 
  313   
 314   
 316     """ 
 317     Sets the lock file and writes the PID of this process 
 318     """ 
 319     f = open(get_lockname(),'w') 
 320     f.write(str(os.getpid())) 
 321     f.close() 
  322   
 323   
 325     """ 
 326     Removes the lock file 
 327     """ 
 328     if os.path.exists(get_lockname()): 
 329       os.remove(get_lockname()) 
 330     info('monitor','Program exit normally')    
  331   
 332   
 334    """ 
 335    Gets the dag-name from the ini file. 
 336    This might be non-robust, therefore it is 
 337    coded as a complete function which can be changes easily. 
 338    @param ini_file: the name of the ini-file 
 339    @param return: the common part of any dag name 
 340    """ 
 341    dag_part = ini_file.split('.')[0] 
 342    return dag_part 
  343   
 344   
 346    """ 
 347    Check the existance of a file and that it is non-zero in size 
 348    (which is useful for segment files...) 
 349    @param filename: name of the file to check 
 350    @return: True or False 
 351    """ 
 352   
 353     
 354    if not os.path.exists(filename): 
 355      return False 
 356   
 357     
 358    size = os.path.getsize(filename) 
 359    if size==0: 
 360      return False 
 361    else: 
 362      return True 
  363   
 364   
 366      """ 
 367      Calculate the minimum science segment that 
 368      can be used with the data given in the actual ini-file. 
 369      The procedure below is taken from trigger_hipe. 
 370      @params cp: the config parser instance 
 371      """ 
 372   
 373       
 374      paddata = int(cp.get('data', 'pad-data')) 
 375      if cp.has_option('data', 'segment-length'): 
 376        n = int(cp.get('data', 'segment-length')) 
 377        s = int(cp.get('data', 'number-of-segments')) 
 378        r = int(cp.get('data', 'sample-rate')) 
 379        o = int(cp.get('inspiral', 'segment-overlap')) 
 380        length = ( n * s - ( s - 1 ) * o ) / r 
 381        overlap = o / r 
 382      elif cp.has_option('data','block-duration'): 
 383        length = int(cp.get('data','block-duration')) 
 384        overlap = int(cp.get('data','segment-duration'))/2 
 385      else: 
 386        raise ValueError, "Cannot find segment information in [data] section of ini file." 
 387         
 388      minsciseg = length + 2 * paddata 
 389       
 390       
 391      return minsciseg 
  392   
 393   
 395    """ 
 396    Converts a segment xml file into a segment text file for convenience. 
 397    """ 
 398     
 399    try: 
 400      doc = utils.load_filename(segxmlfile) 
 401    except: 
 402      raise IOError, "Error reading file %s" % segxmlfile 
 403   
 404     
 405    segs = table.get_table(doc, "segment") 
 406    seglist = segments.segmentlist(segments.segment(s.start_time, s.end_time) for s in segs) 
 407     
 408     
 409    segmentsUtils.tosegwizard(file(segtxtfile, 'w'), seglist, header = True) 
  410   
 411   
 413    """ 
 414    Function to read a segment list from a xml segment file 
 415    """ 
 416     
 417    doc = utils.load_filename(xmlsegfile) 
 418    segs = table.get_table(doc, "segment") 
 419    vetolist = segments.segmentlist(segments.segment(s.start_time, s.end_time) for s in segs) 
 420    return vetolist 
  421   
 422   
 424    """ 
 425    Function to download the latest segment lists. 
 426    @param segdict: the names of the segment for each IFO 
 427    @param timerange: the timerange the segments should cover 
 428    @param tag: optional parameter indicating the tag (e.g. 'grb090802') 
 429    @param outputdir: optional parameter indicating the output directory. 
 430    """ 
 431   
 432     
 433    if tag is not None: 
 434      tag = '_'+tag 
 435    else: 
 436      tag = '' 
 437   
 438     
 439    for ifo, seg in segdict.iteritems(): 
 440   
 441       
 442      segxmlfile = "%s/segments%s%s.xml" % (outputdir, ifo, tag) 
 443      segtxtfile = "%s/%s-science%s.txt" % (outputdir, ifo, tag) 
 444       
 445      if not check_file(segxmlfile): 
 446   
 447          cmd = "ligolw_segment_query --database --query-segments --include-segments '%s'"\ 
 448              " --gps-start-time %d --gps-end-time %d > %s" %\ 
 449              (seg, timerange[0], timerange[1], segxmlfile) 
 450   
 451          pas = AnalysisSingleton() 
 452          pas.system(cmd, item = tag[4:], divert_output_to_log = False) 
 453   
 454       
 455      convert_segxml_to_segtxt(segxmlfile, segtxtfile) 
  456       
 457   
 458   
 460      """ 
 461      Function to update the veto files for a given time range 
 462      @veto_definer: Veto definer file to use 
 463      @timerange: Time range to download the vetoes for 
 464      @path: Output path for the segment files [optional] 
 465      @param tag: Tag for the output files [optional] 
 466      """ 
 467       
 468       
 469      if tag is not None: 
 470          tag = '_'+tag 
 471      else: 
 472          tag = '' 
 473   
 474       
 475      pas = AnalysisSingleton() 
 476      cmd = "ligolw_segments_from_cats --database --veto-file=%s --separate-categories "\ 
 477            "--gps-start-time %d  --gps-end-time %d --output-dir=%s --individual-results"\ 
 478            % (veto_definer, timerange[0], timerange[1], path) 
 479      pas.system(cmd, tag[4:]) 
 480   
 481   
 482       
 483      veto_files = glob.glob('%s/*VETOTIME_CAT*%d*xml'% (path, timerange[0])) 
 484      for filename in veto_files: 
 485         
 486        p = filename.split('-') 
 487        newname = "%s-%s%s.xml"%(p[0], p[1], tag) 
 488        shutil.move(filename, newname) 
  489   
 490   
 492    """ 
 493    Returns all vetoes from the file 'xmlsegfile' that overlap with the given 'segment' 
 494    """ 
 495     
 496     
 497    testseg = segments.segment(segment) 
 498    
 499     
 500    list_vetoes = [] 
 501       
 502     
 503    xmldoc = utils.load_filename(xmlsegfile, gz = False) 
 504    segs = lsctables.SegmentTable.get_table(xmldoc) 
 505    segdefs = lsctables.SegmentDefTable.get_table(xmldoc) 
 506       
 507     
 508    defdict = {} 
 509    for segdef in segdefs: 
 510        defdict[segdef.segment_def_id] = segdef.name 
 511   
 512     
 513    for seg in segs: 
 514       
 515       
 516      s = segments.segment(seg.start_time, seg.end_time) 
 517         
 518       
 519       
 520      if testseg.intersects(s): 
 521        id = seg.segment_def_id 
 522        list_vetoes.append([defdict[id], seg.start_time, seg.end_time]) 
 523   
 524    return list_vetoes 
  525   
 526   
 527 -def check_veto_time(used_ifos, list_cat, timerange, path = '.', tag = None): 
  528      """ 
 529      Function to check if the given timerange overlaps with some CAT veto 
 530      @param used_ifos: A list of used ifos for which SCIENCE data is available 
 531      @param list_cat: A list of numbers, specifying the categories that should be checked for 
 532      @param timerange: The range of time that should be checked 
 533      @param path: Output path for the segment files [optional] 
 534      @param tag: Tag for the output files [optional] 
 535      """ 
 536   
 537      pas = AnalysisSingleton() 
 538   
 539       
 540      if tag is not None: 
 541          tag = '_'+tag 
 542      else: 
 543          tag = '' 
 544   
 545       
 546      clear_ifos = [] 
 547      for ifo in used_ifos: 
 548           
 549           
 550          vetoed_ifos = set() 
 551          vetoed_cats = set() 
 552          for cat in list_cat: 
 553   
 554               
 555              xmlsegfile = "%s/%s-VETOTIME_CAT%d%s.xml" % \ 
 556                              (path, ifo, cat, tag) 
 557              vetolist = read_xmlsegfile(xmlsegfile) 
 558              vetolist.coalesce() 
 559   
 560               
 561              list_overlaps =  get_veto_overlaps(timerange, xmlsegfile) 
 562              for name, segstart, segend in list_overlaps: 
 563                pas.info("   - IFO %s vetoed from %d to %d by CAT%d: %s"%\ 
 564                         (ifo, segstart, segend, cat, name), tag[4:]) 
 565              if vetolist.intersects_segment(segments.segment(timerange)): 
 566                  vetoed_ifos.add(ifo) 
 567                  vetoed_cats.add(cat) 
 568   
 569           
 570          if len(vetoed_ifos)==0: 
 571                clear_ifos.append(ifo) 
 572          else: 
 573              pas.info("IFO(s) %s vetoed by CAT(s): %s" %\ 
 574                       (list(vetoed_ifos), list(vetoed_cats)), tag[4:]) 
 575                   
 576   
 577      return clear_ifos 
  578    
 579   
 580 -def get_segment_info(pas,timerange, minsciseg, plot_segments_file = None, path = '.', tag = None, segs1 = False): 
  581      """ 
 582      Function to get the segment info for a timerange 
 583      @param timerange: The range of time the SCIENCE segments should be checked 
 584      @param minsciseg: The minimum time length (in seconds) for an analyzable consecutive segment 
 585      @param plot_segments_file: Name of the output name for the plot [optional] 
 586      @param path: Output path for the segment files (NOT the image) [optional] 
 587      @param tag: Tag for the files [optional] 
 588      @param segscat1: CAT1 veto times to be considered when finding the best segment [optional] 
 589      """ 
 590      pas = AnalysisSingleton() 
 591   
 592       
 593      if tag is not None: 
 594          tag = '_'+tag 
 595      else: 
 596          tag = '' 
 597   
 598       
 599      segdict = segments.segmentlistdict() 
 600   
 601       
 602      for ifo in basic_ifolist: 
 603        if not pas.cp.has_option('segments','%s-segments'%ifo.lower()): 
 604          continue 
 605        ifo_segfile = '%s/%s-science%s.txt' % (path, ifo, tag) 
 606        if ifo_segfile is not None: 
 607          tmplist = segmentsUtils.fromsegwizard(open(ifo_segfile)) 
 608          segdict[ifo] = segments.segmentlist([s for s in tmplist \ 
 609                                               if abs(s) > minsciseg]) 
 610   
 611           
 612           
 613          if segs1: 
 614               
 615               
 616              xmlsegfile = "%s/%s-VETOTIME_CAT1%s.xml" % \ 
 617                           (path, ifo, tag) 
 618              vetoes1 = read_xmlsegfile(xmlsegfile) 
 619              vetoes1.coalesce() 
 620   
 621               
 622              list_overlaps =  get_veto_overlaps(timerange, xmlsegfile) 
 623              for name, segstart, segend in list_overlaps: 
 624                pas.info("   - CAT1 preveto for IFO %s,  vetoed from %d to %d: %s"%\ 
 625                         (ifo, segstart, segend, name), tag[4:]) 
 626   
 627               
 628              segdict[ifo] -= vetoes1 
 629         
 630      ifolist = segdict.keys() 
 631      ifolist.sort() 
 632   
 633       
 634      onSourceSegment = segments.segment(timerange[0], timerange[1]) 
 635   
 636       
 637      pas = AnalysisSingleton() 
 638      padding_time = int(pas.cp.get('exttrig','padding_time')) 
 639      num_trials = int(pas.cp.get('exttrig','num_trials')) 
 640      symmetric = False 
 641      offSourceSegment, grb_ifolist = micos(segdict, onSourceSegment,\ 
 642                           padding_time = padding_time, max_trials = num_trials,\ 
 643                           min_trials = num_trials, symmetric = symmetric) 
 644   
 645      grb_ifolist.sort() 
 646      ifo_times = "".join(grb_ifolist) 
 647   
 648       
 649      if plot_segments_file: 
 650        plot_segment_info(segdict, onSourceSegment, offSourceSegment, timerange[1]-1, plot_segments_file) 
 651   
 652       
 653      return offSourceSegment, grb_ifolist, ifo_times 
  654   
 655   
 656 -def plot_segment_info(segdict, onsource, offsource, centertime, output_filename, plot_offset = 1000, tag = ''): 
  657    """ 
 658    Function to plot the segments around a 'centertime' 
 659    @param segdict: dictionary containing the segments of the science data 
 660    @param onsource: the onsource segment 
 661    @param offsource: the offsource segment 
 662    @param centertime: the time at which the origin is set 
 663    @param output_filename: output filename of the plot 
 664    @param plot_offet: additional times (in second) on either side of the range 
 665    @param tag: full tag denoting e.g. the GRB (with the underscore before) 
 666    """ 
 667   
 668     
 669    pas = AnalysisSingleton() 
 670    num_trials = int(pas.cp.get('exttrig','num_trials')) 
 671   
 672     
 673    length_off_source = num_trials*(abs(onsource)) 
 674    plot_offSourceSegment = segments.segment(onsource[0] - length_off_source, 
 675                                             onsource[1] + length_off_source) 
 676   
 677    effective_window = segments.segmentlist([plot_offSourceSegment]).\ 
 678                           protract(plot_offset) 
 679    effective_segdict = segdict.map(lambda sl: sl & effective_window) 
 680   
 681     
 682    plot = PlotSegmentsPlot(centertime) 
 683    plot.add_contents(effective_segdict) 
 684    if offsource: 
 685      plot.set_window(offsource, plot_offset) 
 686    plot.highlight_segment(onsource) 
 687    plot.finalize() 
 688    plot.ax.set_title('Segments for GRB '+tag[4:]) 
 689    plot.savefig(output_filename) 
 690    plot.close() 
  691   
 692   
 693   
 694 -def get_available_ifos(trigger,  minscilength, path = '.', tag = '', useold = False, offset = 2000, onsource = None): 
  695    """ 
 696    Function for a full scale check how many IFOs are available for a given time 
 697    Requires a CP to be set with the following fileds: 
 698      'data','science_segment_[IFO]' 
 699      'data','veto_definer' 
 700      'analysis','onsource_left' 
 701      'analysis','onsource_right' 
 702    """ 
 703   
 704    trend_ifos = [] 
 705   
 706     
 707    pas = AnalysisSingleton() 
 708   
 709     
 710    trial_length =  int(pas.cp.get('exttrig','onsource_left')) + int(pas.cp.get('exttrig','onsource_right'))  
 711    padding_time = int(pas.cp.get('exttrig','padding_time')) 
 712    num_trials = int(pas.cp.get('exttrig','num_trials')) 
 713    check_scilength = (num_trials+1)*trial_length + 2*padding_time 
 714   
 715    if minscilength != check_scilength: 
 716      raise AssertionError, "Inconsistent science length requirement! "\ 
 717          "Actual requirement is %d seconds, while num_trials=%d suggest %d seconds."%\ 
 718          (minscilength, num_trials, check_scilength) 
 719   
 720     
 721    seg_names = {} 
 722    for ifo in basic_ifolist: 
 723      if pas.cp.has_option('segments','%s-segments'%ifo.lower()): 
 724        seg_names[ifo] = pas.cp.get('segments','%s-segments'%ifo.lower()) 
 725   
 726     
 727    timerange = [ trigger - offset, trigger + offset] 
 728    update_segment_lists(seg_names, timerange, tag = tag, outputdir = path) 
 729   
 730     
 731    if onsource is None: 
 732      onsource = [trigger - int(pas.cp.get('exttrig','onsource_left')), \ 
 733                      trigger + int(pas.cp.get('exttrig','onsource_right'))] 
 734    offsource, ifolist, ifotimes = get_segment_info(pas,onsource, minscilength, tag = tag, path = path) 
 735    trend_ifos.append(ifolist) 
 736   
 737     
 738    if len(ifolist)>1: 
 739   
 740       
 741      deltat = 500 
 742      starttime = offsource[0]-deltat 
 743      endtime   = offsource[1]+deltat 
 744      duration = endtime-starttime 
 745   
 746       
 747      avail = True 
 748      for ifo in ifolist: 
 749        for cat in [1,2,3]: 
 750          xmlsegfile = "%s/%s-VETOTIME_CAT%d_%s.xml" % (path, ifo, cat, tag) 
 751          if not os.path.exists(xmlsegfile): avail = False 
 752   
 753       
 754      if not useold or not avail: 
 755        veto_definer_file_url = pas.cp.get('exttrig','cvs_veto_definer') 
 756        veto_definer_file,headers = urllib.urlretrieve(veto_definer_file_url,os.path.basename(veto_definer_file_url)) 
 757        update_veto_lists(veto_definer_file, [starttime, endtime], \ 
 758                              tag = tag, path = path) 
 759   
 760   
 761       
 762      segsdict = {} 
 763      for ifo in ifolist: 
 764        xmlsegfile = "%s/%s-VETOTIME_CAT1_%s.xml" % (path, ifo,tag) 
 765        segsdict[ifo] = read_xmlsegfile(xmlsegfile) 
 766        segsdict[ifo].coalesce() 
 767   
 768       
 769      outname = 'plot_segments_%s.png' % tag 
 770      offsource, ifolist, ifotimes = get_segment_info(pas,onsource, minscilength, plot_segments_file=outname, \ 
 771           segs1 = True, tag = tag, path = path) 
 772      trend_ifos.append(ifolist) 
 773   
 774       
 775      new_ifos = check_veto_time(ifolist, [2,3], onsource, tag = tag, path = path) 
 776      nifos = "".join(new_ifos) 
 777      trend_ifos.append(new_ifos) 
 778   
 779       
 780      return new_ifos, onsource, offsource, trend_ifos 
 781   
 782    else: 
 783      return ifolist, onsource, offsource, trend_ifos 
  784   
 785   
 786   
 787   
 789    """ 
 790    Reads the adjusted onsource times for GRBs inspected manually. 
 791    Uses the simple file format 
 792    """ 
 793   
 794    grbs = {} 
 795    refdict = {} 
 796     
 797    for linex in file(filename): 
 798   
 799       
 800      line = linex.replace('\n','') 
 801      w = line.split() 
 802   
 803       
 804      if len(linex)<3 or linex[0]=='#': 
 805   
 806         
 807        if 'REF' in linex: 
 808          refdict[int(w[2])] = w[3] 
 809        continue 
 810   
 811       
 812      name = w[0] 
 813      try: 
 814        start = int(w[1]) 
 815        end = int(w[2]) 
 816        used = True 
 817      except: 
 818        used = False 
 819   
 820      comment = " ".join(w[3:]) 
 821   
 822      if used: 
 823          grbs[name] = {'onsource':[start, end], 'used':used,\ 
 824                            'comment':comment} 
 825      else: 
 826          grbs[name] = {'onsource':None, 'used':used, 'comment':comment} 
 827   
 828     
 829    return grbs, refdict 
  830   
 831   
 832   
 833   
 835    """ 
 836    Reads the adjusted onsource times for GRBs inspected manually. 
 837    Uses the Jordi-type of file 
 838    """ 
 839   
 840    grbs = {} 
 841     
 842    for line in file(filename): 
 843      w = line.split() 
 844      if len(w)<7: 
 845        continue 
 846   
 847       
 848      name = w[1] 
 849      try: 
 850        number = int(name[:6]) 
 851      except: 
 852        continue 
 853   
 854      try: 
 855        start = int(w[3]) 
 856        end = int(w[5]) 
 857        used = True 
 858      except: 
 859        used = False 
 860   
 861   
 862      comment = line[40:].replace('\n','').replace('|','').strip() 
 863   
 864      if used: 
 865          grbs[name] = {'onsource':[start, end], 'used':used,\ 
 866                            'comment':comment} 
 867      else: 
 868          grbs[name] = {'onsource':None, 'used':used, 'comment':comment} 
 869               
 870    return grbs 
  871   
 872   
 873 -def parse_trigger_list(trigger_file, processed = [], max_number = None, specific_name = None): 
  874    """ 
 875    This function parses the GRB list provided by Isabel 
 876    and returns a list of new GRBs 
 877    @param trigger_file: The name of the trigger file to parse 
 878    @param processed: List of triggers already processed [optional] 
 879    @param max_number: Returns at maximum this number of new triggers 
 880    @param specific_name: Will return a list with only the trigger information 
 881                          for this specific item, if it is found [optional] 
 882    """ 
 883   
 884     
 885    counter = 0 
 886    new_triggers = {'name':[], 'ra':[], 'de':[], 'box':[],'gps':[],\ 
 887                     'duration':[], 'sat':[]} 
 888   
 889     
 890    for line in file(trigger_file): 
 891   
 892       
 893      if len(line)==0 or line[0]=="#": 
 894        continue 
 895   
 896       
 897       
 898      if max_number: 
 899        if counter>=max_number: 
 900          break 
 901   
 902       
 903      w = line.split() 
 904   
 905       
 906      grb_name = w[0] 
 907   
 908       
 909      if grb_name in processed: 
 910        continue 
 911   
 912       
 913      if specific_name: 
 914        if grb_name!=specific_name: 
 915          continue 
 916   
 917       
 918   
 919       
 920      try: 
 921        grb_duration = float(w[8]) 
 922      except: 
 923        grb_duration = None 
 924   
 925       
 926      try: 
 927        errorbox = float(w[4]) 
 928      except: 
 929        errorbox = None 
 930   
 931       
 932      grb_time = w[6] 
 933      grb_date = grb_name[:6] 
 934      grb_gps_time = get_gps_from_asc(grb_date, grb_time) 
 935   
 936       
 937      new_triggers['name'].append(grb_name) 
 938      new_triggers['ra'].append(float(w[1])) 
 939      new_triggers['de'].append(float(w[2])) 
 940      new_triggers['box'].append(errorbox) 
 941      new_triggers['gps'].append(grb_gps_time) 
 942      new_triggers['duration'].append(grb_duration) 
 943      new_triggers['sat'].append(w[10]) 
 944      counter += 1 
 945   
 946    return new_triggers 
  947   
 948   
 950    """ 
 951    Returns an empty exttrig row  
 952    @return: empty exttrig table row 
 953    """ 
 954    row = lsctables.ExtTriggersTable() 
 955   
 956    row.process_id = None 
 957    row.det_alts = None 
 958    row.det_band = None 
 959    row.det_fluence = None 
 960    row.det_fluence_int = None 
 961    row.det_name = None 
 962    row.det_peak = None 
 963    row.det_peak_int = None 
 964    row.det_snr = '' 
 965    row.email_time = 0 
 966    row.event_dec = 0.0 
 967    row.event_dec_err = 0.0 
 968    row.event_epoch = '' 
 969    row.event_err_type = '' 
 970    row.event_ra = 0.0 
 971    row.event_ra_err = 0.0 
 972    row.start_time = 0 
 973    row.start_time_ns = 0 
 974    row.event_type = '' 
 975    row.event_z = 0.0 
 976    row.event_z_err = 0.0 
 977    row.notice_comments = '' 
 978    row.notice_id = '' 
 979    row.notice_sequence = '' 
 980    row.notice_time = 0 
 981    row.notice_type = '' 
 982    row.notice_url = '' 
 983    row.obs_fov_dec = 0.0 
 984    row.obs_fov_dec_width = 0.0 
 985    row.obs_fov_ra = 0.0 
 986    row.obs_fov_ra_width = 0.0 
 987    row.obs_loc_ele = 0.0 
 988    row.obs_loc_lat = 0.0 
 989    row.obs_loc_long = 0.0 
 990    row.ligo_fave_lho = 0.0 
 991    row.ligo_fave_llo = 0.0 
 992    row.ligo_delay = 0.0 
 993    row.event_number_gcn = 0 
 994    row.event_number_grb = '' 
 995    row.event_status = 0 
 996    return row 
  997   
 998   
1000    """ 
1001    Returns the name of the monitor pickle filename 
1002    @return: name of the monitor pickle file 
1003    """ 
1004    return get_main_dir()+'llmonitor.pickle' 
 1005   
1006   
1008    """ 
1009    Opens the monitor pickle file (usually llmonitor.pickle) 
1010    and return its contents. 
1011    @return: list of GRB instances from the pickle file 
1012    """ 
1013   
1014    monitor_file = get_monitor_filename() 
1015    try: 
1016      monitor_list = pickle.load(file(monitor_file)) 
1017    except IOError: 
1018       
1019      monitor_list = [] 
1020      pickle.dump(monitor_list, file(monitor_file,'w')) 
1021    return monitor_list 
 1022   
1023   
1025    """ 
1026    Writes the monitor list to file 
1027    @param monitor_list: list to be written to file 
1028    """ 
1029    monitor_file = get_monitor_filename() 
1030    pickle.dump(monitor_list, file(monitor_file,'w')) 
 1031   
1032   
1034    """ 
1035    Returns the object associated with the given GRB. 
1036    @params grb_name: name of the GRB without the leading 'GRB' 
1037    """ 
1038    grb_list = read_monitor_list() 
1039    for grb in grb_list: 
1040      if grb.name==grb_name: 
1041        return grb 
1042    return None 
 1043   
1044   
1046    """ 
1047    Copying all relevant files to the working directory, 
1048    usually from CIT from Isabels pwd 
1049    """ 
1050    alert_loc = cp.get('alerts','alert_location') 
1051    main_loc = cp.get('paths','main') 
1052    cmd = 'scp %s %s >> ~/cp.log 2>&1' % (alert_loc, main_loc) 
1053    system_call('monitor', cmd) 
 1054   
1055   
1057    """ 
1058    Reads the local copy of the parsed circular and  
1059    updated any duration information in the monitor_list structure 
1060    @params monitor_list: list of all GRBs and DAGs 
1061    """ 
1062     
1063    circular_file = cp.get('paths','main')+'/'+cp.get('alerts','circular_file') 
1064   
1065     
1066    dict_duration = {} 
1067    for line in file(circular_file): 
1068      parts = line.split() 
1069      grb_name = parts[2] 
1070      duration = float(parts[13]) 
1071   
1072       
1073      if duration>0: 
1074        dict_duration[grb_name]=duration 
1075   
1076     
1077    for grb in monitor_list: 
1078       
1079      if grb.name in dict_duration: 
1080        grb.duration = dict_duration[grb.name] 
 1081   
1082   
1084    """ 
1085    Obtain the result, i.e the smallest p(c|0) 
1086    @param grb: the grb stucture with all the infos in it 
1087    """ 
1088   
1089    tag = grb.code['onoff'].tag 
1090    path_to_result = '%s/GRB%s/postprocessing_%s/OPENBOX/llsummary_onoff_GRB%s.pickle' %\ 
1091       (grb.analysis_dir, grb.name, tag, grb.name) 
1092    if os.path.exists(path_to_result): 
1093      data = pickle.load(file(path_to_result)) 
1094    else: 
1095       info(grb.name, "OPENBOX results file %s does not exist! "\ 
1096            "Maybe this is a rerun and the --force-rerun option have been forgotten? "%path_to_result)   
1097       return -1 
1098   
1099    min_prob = 2.0 
1100    for coinc in data: 
1101      if 'prob' in coinc: 
1102        p = coinc['prob'] 
1103        if p<min_prob: 
1104          min_prob = p 
1105   
1106    return min_prob 
 1107   
1108   
1110    """ 
1111    Generating summary page, with all sanity and/or openbox results 
1112    properly linked. 
1113    @param publish_path: Main path to where to copy the results and files 
1114    @param publish_url: The url identifier of the same path 
1115    """ 
1116   
1117    def add(table, text): 
1118      return table + '<td>' +str(text)+'</td>'  
 1119   
1120    def add_linked_value(table, value, ref): 
1121      if value>0: 
1122        if ref>0: 
1123          table = add(table, '<a href="http://gcn.gsfc.nasa.gov/gcn3/%d.gcn3">%.2f</a>' % (ref, value)) 
1124        else: 
1125          table = add(table, '%.2f' % value) 
1126      else: 
1127        table = add(table, '&mdash') 
1128      return table 
1129   
1130    def create_col(l): 
1131      f = 1.0 
1132      if colsign==1: 
1133        f = 0.95 
1134      return  '%d, %d, %d'%(f*l[0], f*l[1], f*l[2]) 
1135   
1136   
1137    colsign = -1 
1138     
1139    coldict = {'analong':[153, 255, 255],'anashort':[255,200,200],'nolong':[100,150,150],'noshort':[130,130,70]} 
1140   
1141     
1142    monitor_list = read_monitor_list() 
1143   
1144    short_grb_duration = float(cp.get('analysis','max-duration')) 
1145   
1146     
1147    number_short = number_long = number_data = number_nodata = number_long_data = number_short_data = 0 
1148    number_complete_all = number_complete_short = number_opened_all = number_opened_short = 0 
1149    for grb in monitor_list: 
1150      if grb.has_data: 
1151        number_data +=1 
1152        if grb.duration and grb.duration<short_grb_duration: 
1153          number_short += 1 
1154          number_short_data +=1 
1155          if grb.dag['inj'].status == 5: 
1156            number_complete_short += 1 
1157          if grb.openbox: 
1158            number_opened_short += 1 
1159   
1160        else: 
1161          number_long +=1 
1162          number_long_data += 1 
1163   
1164          if grb.dag['onoff'].status==5: 
1165            number_complete_all += 1 
1166          if grb.openbox: 
1167            number_opened_all += 1 
1168   
1169      else: 
1170        number_nodata +=1 
1171        if grb.duration and grb.duration<short_grb_duration: 
1172          number_short += 1 
1173        else: 
1174          number_long +=1 
1175   
1176   
1177   
1178     
1179    time_unsort = [grb.time for grb in monitor_list] 
1180    index = np.argsort(time_unsort) 
1181    num_grb = len(time_unsort) 
1182   
1183    table = total_summary_prefix % ( len(monitor_list), number_data, number_nodata, number_long, \ 
1184                                    number_long_data, number_short, number_short_data, \ 
1185                                    number_complete_all, number_complete_short, \ 
1186                                    number_opened_all, number_opened_short, get_time()) 
1187   
1188     
1189    for number, i in enumerate(index[::-1]): 
1190   
1191      grb = monitor_list[i] 
1192   
1193       
1194      if grb.duration and grb.duration<short_grb_duration: 
1195        if grb.has_data: 
1196          coldef = create_col(coldict['anashort']) 
1197        else: 
1198          coldef = create_col(coldict['noshort']) 
1199      else: 
1200        if grb.has_data: 
1201          coldef = create_col(coldict['analong']) 
1202        else: 
1203          coldef = create_col(coldict['nolong']) 
1204   
1205      colsign = -colsign 
1206      table += '<tr style="background-color: rgb(%s);">' % coldef 
1207      
1208       
1209      if grb.has_data: 
1210        status_onoff = grb.dag['onoff'].get_status() 
1211        status_inj = grb.dag['inj'].get_status() 
1212      else: 
1213        status_onoff = status_inj = 0 
1214      ifos = "".join(grb.ifolist) 
1215   
1216       
1217      table = add(table, num_grb- number) 
1218      table = add(table, '<a href="http://grblog.org/grblog.php?view=burst&GRB=%s">%s</a>'%(grb.name, grb.name))  
1219      status_msg = grb.get_html_status() 
1220      table = add(table, status_msg['onoff']+'<br>'+status_msg['inj']) 
1221      try: 
1222        tag_onoff = grb.code['onoff'].get_tag() 
1223      except: 
1224        tag_onoff = 'None' 
1225      try: 
1226        tag_lik = grb.code['inj'].get_tag() 
1227      except: 
1228        tag_lik = 'None' 
1229      table = add(table, tag_onoff+'<br>'+tag_lik) 
1230      table = add(table, grb.time) 
1231      tm = date.XLALGPSToUTC(LIGOTimeGPS(grb.time)) 
1232      asctime = time.strftime("%d %b %Y\n%H:%M:%S",tm) 
1233      table = add(table, asctime) 
1234      table = add_linked_value(table, grb.redshift, None ) 
1235      table = add_linked_value(table, grb.duration, None) 
1236      table = add(table, '%.2f<br>%.2f' % (grb.ra, grb.de)) 
1237      for ifo in basic_ifolist: 
1238        segplot_link = 'GRB%s/plot_segments_grb%s.png'%(grb.name, grb.name) 
1239         
1240        if ifo in grb.ifos: 
1241          txt = '<b>%.2f</b>'%grb.qvalues[ifo] 
1242        else: 
1243          txt = '%.2f'%grb.qvalues[ifo] 
1244        table = add(table, '<a href="%s">%s</a>'%(segplot_link, txt)) 
1245       
1246      if status_onoff==5: 
1247       
1248         
1249        htmlfile = publish_url+'/GRB%s/pylal_exttrig_llsummary_%s-sanity.html' % (grb.name, grb.name) 
1250        htmlfile_inj = publish_url+'/GRB%s/pylal_exttrig_llsummary_%s-sanity_inj.html' % (grb.name, grb.name) 
1251        if status_inj==5: 
1252          table = add(table, '<a href="%s">onoff</a><br> <a href="%s">inj</a> '%(htmlfile, htmlfile_inj)) 
1253        else:  
1254          table = add(table, '<a href="%s">onoff</a><br> &mdash '%htmlfile) 
1255   
1256         
1257        if grb.openbox: 
1258           
1259          result = obtain_results(grb) 
1260          if result<2: 
1261            table = add(table, '%.2f'%result) 
1262          else:         
1263            table = add(table, 'no cand.') 
1264   
1265           
1266          htmlfile = publish_url+'/GRB%s/OPENBOX/pylal_exttrig_llsummary_%s-OPENBOX.html' % \ 
1267                      (grb.name, grb.name) 
1268          htmlfile_inj = publish_url+'/GRB%s/OPENBOX/%s-pylal_exttrig_llsummary_GRB%s_inj-%s.html' %\ 
1269                      (grb.name, ifos, grb.name, grb.get_time_string()) 
1270          if status_inj==5: 
1271            table = add(table, '<a href="%s">onoff</a><br> <a href="%s">lik</a> '%(htmlfile, htmlfile_inj)) 
1272          else: 
1273            table = add(table, '<a href="%s">onoff</a><br> &mdash '%htmlfile) 
1274   
1275        else: 
1276           
1277          table = add(table,'box closed') 
1278          table = add(table,'box closed') 
1279      else: 
1280         
1281        table = add(table, '&mdash') 
1282        table = add(table, '&mdash') 
1283        table = add(table, '&mdash') 
1284   
1285      table +='</tr>' 
1286   
1287       
1288      filename = publish_path +'/total_summary.html' 
1289      f = open(filename,'w') 
1290      f.write(table) 
1291      f.close() 
1292   
1293   
1294   
1296    """ 
1297    Returns the name of the tag currently stored in an environment variable 
1298    @return: name of the tag 
1299    """ 
1300     
1301    tag = os.getenv('LAL_PYLAL_TAG') 
1302    if not tag: 
1303      del_lock() 
1304      raise EnvironmentError, "Environment variable LAL_PYLAL_TAG is missing, which contains the "\ 
1305                         "tag of the code used, e.g. s6_exttrig_100119b. This should have been set in the "\ 
1306                         "lscsource script, called within runmonitor. Please check" 
1307    return tag 
 1308   
1309   
1310 -def get_env(name, required = False): 
 1311       
1312       
1313      content = os.getenv(name) 
1314       
1315       
1316      if required and not content: 
1317          raise ValueError, "Environment variable '%s' needs to be set!"%name 
1318       
1319      return content 
 1320   
1321   
1322   
1325          if not hasattr(cls, '_instance'): 
1326              orig = super(Singleton, cls) 
1327              cls._instance = orig.__new__(cls, *args, **kw) 
1328          return cls._instance 
  1329   
1330   
1331   
1333     
1334      
1335       
1339   
1340       
1342        self.init = True 
1343   
1344        import socket 
1345   
1346         
1347        self.hostname = socket.gethostname() 
1348        self.publishing_path = get_env('USER_PUB') 
1349        self.publishing_url = get_env('USER_URL') 
1350        self.cvs = get_env('USER_CVS') 
1351        self.condor_log_path = get_env('USER_LOG') 
1352        self.email = get_env('USER_EMAIL') 
 1353   
1354   
1355       
1358           
1359       
1362           
1363       
1365          self.logfile = logfile 
 1366   
1367       
1370   
1371       
1372 -    def info(self, text, item = None, onscreen = True): 
 1373          """ 
1374          Puts some information onto the logfile 
1375          @params text: The information to be put out. 
1376          @params item: optional text specifying the context of the text (e.g. GRB name). 
1377          @params onscreen: optional flag to have the message printed to stdout as well. 
1378          """ 
1379   
1380          if item is None: 
1381              msg = get_time() + ': '+text 
1382          else: 
1383              msg = get_time() + ' ('+item+'): '+text 
1384   
1385       
1386          logfile = open(self.logfile,'a') 
1387          logfile.write(msg+'\n') 
1388          logfile.close() 
1389   
1390           
1391          if onscreen: 
1392              print msg 
 1393       
1394       
1395 -    def system(self, cmd, item = None, divert_output_to_log = True):       
 1396          """ 
1397          Makes a system call. 
1398          @params command: the command to be executed on the bash 
1399          @params item: a text specifying the content of the text 
1400                  (e.g. number of the GRB the message is associated with) 
1401                  (see also 'info') 
1402          @params divert_output_to_log: If this flag is set to True the output of the  
1403              given command is automatically put into the log-file. 
1404              If the output of some command itself is further used, 
1405              like science segments, this flag must be set  
1406              to False, so that the output is diverted where it should go. 
1407          """ 
1408   
1409           
1410          self.info(">>> "+cmd, item) 
1411   
1412           
1413          if divert_output_to_log: 
1414              command = cmd+' >>%s 2>>%s '%(self.logfile, self.logfile) 
1415          else: 
1416              command = cmd +' 2>>%s '%self.logfile 
1417      
1418           
1419          code, out, err = external_call(command) 
1420   
1421           
1422          if code>0 and len(err)>0: 
1423              info("ERROR: " +err, item) 
 1424   
1425       
1427        """ 
1428        Returns the name of the lock file 
1429        """ 
1430        return os.path.expanduser('~/.llmonitor.lock') 
 1431   
1432       
1434        """ 
1435        Checks if another instance of this code is running. 
1436        See http://code.activestate.com/recipes/546512/ 
1437       """ 
1438        lockname = self.get_lockname() 
1439        if os.path.exists(lockname): 
1440          pid=open(lockname, 'r').read().strip() 
1441          pidRunning=commands.getoutput('ls /proc | grep %s' % pid) 
1442          if pidRunning: 
1443            return pid 
1444          else: 
1445            return None 
1446   
1447        return None 
 1448   
1449       
1451        """ 
1452        Sets the lock file and writes the PID of this process 
1453        """ 
1454        if self.check_lock() is not None: 
1455          print "ERROR: Program seems to be running" 
1456          sys.exit(0) 
1457   
1458        f = file(self.get_lockname(),'w') 
1459        f.write(str(os.getpid())) 
1460        f.close() 
 1461   
1462       
1464        """ 
1465        Removes the lock file 
1466        """ 
1467        if os.path.exists(self.get_lockname()): 
1468          os.remove(self.get_lockname()) 
1469        self.info('Program exit normally', 'monitor') 
 1470   
1471   
1472   
1473   
1474   
1475   
1477   
1491   
1493      """ 
1494      Makes a consistency check of the tag used 
1495      """ 
1496      tag_env = get_code_tag() 
1497      if tag_env != self.tag: 
1498        print "WARNING: The tag from git_version is %s"\ 
1499              " while the tag from LAL_PYLAL_TAG is %s."\ 
1500              " Will use the latter one."%(self.tag, tag_env) 
1501   
1502      self.tag = tag_env 
 1503   
1505      if self.tag: return self.tag 
1506      else: return 'None' 
  1507     
1508   
1509   
1510   
1512    """ 
1513    Class to hold and handle an analysis DAG and all 
1514    related information. 
1515    """ 
1516     
1517     
1518 -  def __init__(self, name, type, analysis_dir): 
 1519      """ 
1520      Initializing this class with all the needed information 
1521      @param name: name of the GRB 
1522      @param type: what dag is this? onoff/inj 
1523      #@param stage: stage of the dag, like uberdag or ligolwdag 
1524      #@param inifile: inifile for this DAG 
1525      #@param injfile: injection file for this DAG 
1526      @param analysis_dir: path to the analysis directory 
1527      """ 
1528   
1529       
1530      self.name = name 
1531      self.type = type 
1532      self.analysis_dir = analysis_dir 
1533   
1534      self.dagname = None 
1535   
1536      self.status = 0 
1537      self.status_dict = {1:'inspiral',2:'ligolw',3:'postproc'} 
1538   
1539      self.code_list = [] 
 1540   
1541     
1543      """ 
1544      Sets the current name of the DAG 
1545      @param name: name of the .dag file 
1546      """ 
1547      self.dagname = name 
 1548   
1549     
1551      """ 
1552      Returns the outname of this DAG 
1553      """ 
1554      return self.dagname+'.dagman.out' 
 1555   
1556     
1558      """ 
1559      Returns the name of the DAG file 
1560      """ 
1561      return self.dagname 
 1562    
1563     
1565      """ 
1566      Returns the name of the sh file 
1567      """ 
1568      basename = self.dagname[:-4] 
1569      return basename+'.sh' 
 1570   
1571     
1573      """ 
1574      Start this DAG 
1575      """ 
1576   
1577       
1578      dir = os.path.dirname(self.get_dagname()) 
1579      dagname = os.path.basename(self.get_dagname()) 
1580      cmd = 'export _CONDOR_DAGMAN_LOG_ON_NFS_IS_ERROR=FALSE;' 
1581      cmd += 'cd %s;' % dir 
1582      cmd += 'condor_submit_dag %s' % dagname 
1583      system_call(self.name, cmd) 
1584   
1585       
1586      self.status = 1 
1587   
1588       
1589      time.sleep(10) 
 1590   
1591     
1594   
1595     
1597      if new_status<=0: 
1598        del_lock() 
1599        raise ValueError, "The DAG Status variable can only be set to positive values" 
1600   
1601      self.status = new_status 
 1602   
1603     
1605      """ 
1606      Returns the name of the stage or error of the current DAG. 
1607      """ 
1608      status_dict = {1:'inspiral',2:'ligolw',3:'postproc'} 
1609       
1610      text = '' 
1611      if self.status==0: 
1612        text = 'Not started' 
1613      elif self.status==5: 
1614        text = 'Complete' 
1615      elif self.status==-6: 
1616        text = 'DAGFILE ERROR' 
1617      else: 
1618        text = status_dict[abs(self.status)] 
1619        if self.status<0: 
1620          text += "ERROR" 
1621    
1622      return text 
 1623   
1624     
1626      """ 
1627      Updating the status for this DAG, 
1628      and return the fstat value 
1629      """ 
1630   
1631       
1632      fstat = 0 
1633      try: 
1634         
1635        line = file(self.get_outname()).readlines()[-1] 
1636         
1637         
1638        if "EXITING WITH STATUS" in line: 
1639          if "EXITING WITH STATUS 0" in line: 
1640            fstat = 1 
1641          else: 
1642            fstat = -1 
1643      except IOError: 
1644        fstat = -2 
1645   
1646       
1647      if self.status>0: 
1648       if fstat<0: 
1649          
1650         self.status = -self.status 
1651   
1652         if fstat == -1: 
1653           notify(grb, self, 'DAG exited on error') 
1654         elif fstat==-2: 
1655           notify(grb, self, 'DAG file vanished!?') 
1656       
1657      if fstat>=0 and self.status<0: 
1658        self.status = -self.status 
1659   
1660      return fstat 
  1661   
1662   
1663   
1664   
1665   
1666     
1667   
1668   
1670    """ 
1671    Class holding all the infos for a GRB and for setting up 
1672    a new analysis DAG. 
1673    """ 
1674   
1675     
1676 -  def __init__(self, grb_name=None, grb_ra=None, grb_de=None, grb_time=None, errorbox = None, sat = None): 
 1677      """ 
1678      Initializes the GRB class with a basic set of information 
1679      @param grb_name: the name of the GRB without the term 'GRB' (e.g.: 070201) 
1680      @param grb_ra: right ascension of this GRB given in degrees 
1681      @param grb_de: declination of this GRB given in degrees 
1682      @param grb_time: GPS trigger time of the GRB  
1683      @param errorbox: size of the errorbox as stated in Isabel's list 
1684      @param sat: Name of the satellite providing those data 
1685      """ 
1686      self.name = grb_name  
1687      self.ra = float(grb_ra) 
1688      self.de = float(grb_de) 
1689      self.time = int(grb_time) 
1690   
1691       
1692      self.ifos = '' 
1693      self.errorbox = errorbox 
1694      self.duration = None 
1695      self.redshift = None 
1696      self.sat = sat 
1697      self.starttime = None 
1698      self.endtime = None 
1699      self.openbox = False 
1700      self.openbox_fap = None 
1701       
1702       
1703      self.dag = {'onoff':None, 'inj':None} 
1704   
1705       
1706      self.code = {'inspiral':None, 'onoff':None, 'inj':None} 
1707   
1708       
1709      self.qvalues = {} 
1710      self.offsource_segment = None 
1711      self.onsource_segment = None 
1712      self.ifolist  = [] 
1713   
1714       
1715      self.pas = AnalysisSingleton() 
1716      self.cp = self.pas.get_cp() 
1717   
1718       
1719      self.use_offline_data = True 
1720       
1721      self.type_online = None 
1722      self.type_offline = {'H1':'H1_'+self.cp.get('input','ligo-type'), 'L1':'L1_'+self.cp.get('input','ligo-type'), 'V1':self.cp.get('input','virgo-type')} 
 1723   
1724   
1725     
1726 -  def set_paths(self, input_dir=None, main_dir=None,\ 
1727                  ini_file = None, inj_file = None,\ 
1728                  config_file = None, \ 
1729                  condor_log_path = None, log_file=None): 
 1730      """ 
1731      Set paths for this GRB, like the path to the main directory, and the analysis directory 
1732      @param input_dir: path to the CVS directory 
1733      @param main_dir: main directory for the whole online analysis 
1734      @param ini_file: the name of the ini-file for the inspiral analysis 
1735      @param inj-file: name of the ini-file for the injections 
1736      @param config_file: name of the config file used 
1737      @param condor_log_path: path to the condor log path 
1738      @param log_file: file of the llmonitor log file (usually llmonitor.log) 
1739      """ 
1740      self.input_dir = input_dir 
1741      self.main_dir = main_dir 
1742      self.inifile = ini_file 
1743      self.injfile = inj_file 
1744      self.condor_log_path = condor_log_path 
1745      self.log_file = log_file      
1746      self.config_file = config_file 
1747   
1748       
1749      self.analysis_dir = self.main_dir+'/GRB'+self.name 
 1750   
1751     
1753      return os.getenv('PYLAL_LOCATION') 
 1754   
1755     
1757      return os.getenv('LALAPPS_LOCATION') 
 1758   
1759     
1761      return os.getenv('GLUE_LOCATION') 
 1762   
1763     
1765      """ 
1766      Set adresses for the online notification 
1767      @addresses: list of email addresses to use 
1768      """ 
1769      self.addresses = addresses 
 1770   
1771     
1773      """ 
1774      Construction of the dagname 
1775      @return: name of the dagfile without the '.dag' 
1776      """ 
1777      return  self.analysis_dir+'/'+self.inifile[:-4] 
 1778   
1779     
1781      """ 
1782      Returns the standard suffix used for plots and html files 
1783      containing the GPS starttime and the length of the processed data. 
1784      Example: 935460888-51000 
1785      @return: standard GPS time suffix for file naming 
1786      """ 
1787      timestring = str(self.starttime)+'-'+str(self.endtime-self.starttime) 
1788      return timestring 
 1789   
1790     
1791 -  def make_links(self, sourcedir, destdir, list_exec): 
 1792      """ 
1793      Using a list of executables names to make symbolic links rather 
1794      than copying the files itself.  
1795      @param sourcedir: source directory containing the files 
1796      @param destdir: destination directory in which the links should go 
1797      @param list_exec: list of files to be linked 
1798      """ 
1799       
1800       
1801      cmd = 'cd %s;' % destdir 
1802      for execfile in list_exec: 
1803        cmd += 'ln -s %s/%s .;' % (sourcedir, execfile) 
1804   
1805       
1806      system_call(self.name,cmd) 
 1807   
1808     
1810      """ 
1811      Creates an exttrig xml file with the basic informations 
1812      of the GRB in it. 
1813      Data given in strings or as float 
1814      """ 
1815     
1816       
1817       
1818       
1819       
1820       
1821      xmldoc = ligolw.Document() 
1822      xmldoc.appendChild(ligolw.LIGO_LW()) 
1823      tbl = lsctables.New(lsctables.ExtTriggersTable) 
1824      xmldoc.childNodes[-1].appendChild(tbl) 
1825       
1826       
1827      row = get_empty_exttrig_row() 
1828      row.event_ra = float(self.ra) 
1829      row.event_dec = float(self.de) 
1830      row.start_time = int(self.time) 
1831      row.event_number_gcn = 9999 
1832      row.event_number_grb = self.name 
1833       
1834       
1835      tbl.extend([row]) 
1836       
1837       
1838      self.trigger_file = 'grb%s.xml' % self.name 
1839      utils.write_filename(xmldoc, self.trigger_file) 
 1840   
1841     
1843      """ 
1844      Creates a call to the function 'lalapps_online_datafind' to find 
1845      the data. To be used only for data from the last 2 weeks... 
1846      """ 
1847      executable = self.get_lalapps_dir()+'/bin/lalapps_online_datafind' 
1848   
1849      cmd = "%s --ifo %s --gps-start-time %d --gps-end-time %d --output %s" % \ 
1850              (executable, ifo, starttime, endtime, output_location) 
1851      return cmd 
 1852   
1853   
1854     
1856      """ 
1857      Creates a call to the function 'ligo_data_find' to find 
1858      the data after more than ~2 weeks. Don't ask me... 
1859      """ 
1860      executable = self.get_glue_dir()+'/bin/ligo_data_find --url-type file --lal-cache' 
1861   
1862      cmd = "%s --type %s --observatory %s --gps-start-time %d --gps-end-time %d > %s" %\ 
1863            (executable, self.type_offline[ifo], ifo[0].upper(), starttime, endtime, output_location) 
1864      return cmd 
 1865   
1866     
1868      """ 
1869      Run the datafind command to find the data 
1870      """  
1871       
1872      cache_dir = "%s/GRB%s/datafind/cache" % (self.analysis_dir, self.name) 
1873      cmd = 'mkdir -p '+cache_dir 
1874      system_call(self.name, cmd) 
1875   
1876       
1877      starttime = self.offsource_segment[0] 
1878      endtime = self.offsource_segment[1] 
1879   
1880       
1881       
1882      for ifo in basic_ifolist: 
1883   
1884         
1885        output_location = '%s/%s-DATA-%10d-%10d.cache' % (cache_dir, ifo[0].upper(), starttime, endtime) 
1886   
1887         
1888         
1889        if self.use_offline_data: 
1890          cmd = self.create_call_datafind_offline(starttime, endtime, ifo, output_location) 
1891        else: 
1892          cmd = self.create_call_datafind_online(starttime, endtime, ifo, output_location) 
1893   
1894        system_call(self.name, cmd, False) 
 1895   
1896     
1898      """ 
1899      Checking the difference between now and the requested data 
1900      to indentify if we can use online data or have to use 
1901      offline data 
1902      """  
1903   
1904       
1905      starttime = self.offsource_segment[0] 
1906   
1907       
1908      timediff = time.time() - offset_gps_to_linux - starttime 
1909      self.use_offline_data = False 
1910      if timediff>1000000: 
1911        self.use_offline_data = True 
 1912   
1913     
1915      """ 
1916      Function to conveniently replace some of the parameters 
1917      in the ini-file by specific values. 
1918      """  
1919   
1920       
1921      config_file = '%s/%s' % (self.analysis_dir, self.inifile) 
1922      pc = ConfigParser.ConfigParser() 
1923      pc.read(config_file) 
1924        
1925       
1926      for replacement in list_replacements: 
1927        pc.set(replacement[0], replacement[1], replacement[2]) 
1928   
1929       
1930      cp_file = open(config_file, 'w') 
1931      pc.write(cp_file) 
1932      cp_file.close() 
 1933   
1934     
1936      """ 
1937      Returns the common part for the call to lalapps_trigger_hipe 
1938      """ 
1939        
1940      cmd  = " --h1-segments H1-science_grb%s.txt" % self.name 
1941      cmd += " --l1-segments L1-science_grb%s.txt" % self.name 
1942      cmd += " --v1-segments V1-science_grb%s.txt" % self.name 
1943      cmd += " --list "+self.trigger_file 
1944      cmd += " --grb "+self.name 
1945      cmd += " --onsource-left "+self.cp.get('analysis','onsource_left') 
1946      cmd += " --onsource-right "+self.cp.get('analysis','onsource_right') 
1947      cmd += " --config-file "+self.inifile 
1948      cmd += " --log-path "+self.condor_log_path 
1949      cmd += " --num-trials "+self.cp.get('analysis','num_trials') 
1950      cmd += " --padding-time "+self.cp.get('analysis','padding_time') 
1951      return cmd 
 1952    
1953     
1955      """ 
1956      Main piece to create and prepare the inspiral analysis 
1957      """ 
1958       
1959       
1960       
1961   
1962       
1963      self.check_data_to_use() 
1964       
1965       
1966      if False and os.path.exists(self.analysis_dir): 
1967        del_lock() 
1968        raise IOError, "The directory %s already exists. Please (re)move"\ 
1969              " this directory or choose another name for the "\ 
1970              "analysis directory" % self.analysis_dir 
1971      cmd = 'mkdir %s' % self.analysis_dir 
1972      system_call(self.name, cmd) 
1973   
1974       
1975      files = glob.glob('%s/*.ini' % self.input_dir) 
1976      self.make_cvs_copy(files, self.analysis_dir) 
1977   
1978       
1979       
1980       
1981      cmd = 'cp %s %s/' % (self.trigger_file, self.analysis_dir) 
1982      system_call(self.name, cmd) 
1983   
1984       
1985      list_replacements = [['pipeline', 'user-tag', 'GRB%s'%self.name]] 
1986      if self.use_offline_data: 
1987        list_replacements.append(['input', 'ligo-channel', 'LDAS-STRAIN']) 
1988      self.update_inifile(list_replacements) 
1989   
1990       
1991      cmd = 'cd %s/bin; cp lalapps_coherent_inspiral lalapps_coherentbank \ 
1992        lalapps_coire lalapps_frjoin lalapps_inca lalapps_inspinj lalapps_inspiral \ 
1993        lalapps_inspiral_hipe lalapps_sire lalapps_thinca lalapps_tmpltbank \ 
1994        lalapps_trigbank lalapps_plot_hipe lalapps_trigger_hipe %s' %\ 
1995      (self.get_lalapps_dir(), self.analysis_dir) 
1996      system_call(self.name, cmd) 
1997   
1998       
1999      self.make_links(self.get_glue_dir()+'/bin', self.analysis_dir, ['ligo_data_find','ligolw_add']) 
2000   
2001       
2002      self.code['inspiral'] = CodeTagger() 
2003      self.create_setup_script(self.analysis_dir) 
2004   
2005       
2006      cmd = 'mv %s/*-science_grb%s.txt %s' % (self.main_dir, self.name, self.analysis_dir) 
2007      system_call(self.name, cmd) 
2008   
2009       
2010       
2011       
2012      cmd = 'cd %s;' % self.analysis_dir 
2013      cmd += template_trigger_hipe  
2014      cmd += self.get_hipe_arguments() 
2015      system_call(self.name, cmd) 
2016   
2017       
2018      cmd = 'cd %s/GRB%s; mv GRB%s_onoff.cache GRB%s.cache' % \ 
2019            (self.analysis_dir, self.name, self.name, self.name) 
2020      system_call(self.name, cmd) 
2021   
2022       
2023      self.run_datafind() 
2024   
2025       
2026      self.dag['onoff'] = AnalysisDag(self.name, 'onoff', self.analysis_dir) 
2027      self.dag['inj'] = AnalysisDag(self.name, 'inj', self.analysis_dir) 
2028   
2029      dagfile = self.get_basic_dagname()+'_onoff_uberdag.dag' 
2030      self.dag['onoff'].set_dagname(dagfile) 
2031      dagfile = self.get_basic_dagname()+'_inj_uberdag.dag' 
2032      self.dag['inj'].set_dagname(dagfile) 
 2033   
2034     
2051   
2052   
2053     
2055      """ 
2056      Prepare the onoff directory with all needed files and  
2057      code and prepare the DAG. Don't start DAG here 
2058      @return: name of the DAG file 
2059      """ 
2060    
2061       
2062      tag = get_code_tag() 
2063      pylal_dir = self.get_pylal_dir() 
2064   
2065       
2066      test_dir = self.cp.get('paths','lalsuite')+'/'+tag+'.pylal' 
2067      if os.path.normpath(test_dir)!=os.path.normpath(pylal_dir): 
2068        del_lock() 
2069        raise NameError, "The paths to the pylal directory does not agree. Possible error in the setup scripts. \n"\ 
2070                         "   Name from environment: %s  "\ 
2071                         "   Name from tag: %s" % (pylal_dir, test_dir) 
2072   
2073       
2074      dir_onoff = "%s/GRB%s/postprocessing_%s" % (self.analysis_dir, self.name, tag) 
2075       
2076      if os.path.exists(dir_onoff): 
2077        info(self.name, "    WARNING: The directory %s already exists. Maybe this is a test? " 
2078                        "Then (re)move the directory..." % dir_onoff) 
2079        return None 
2080   
2081      system_call(self.name, 'mkdir -p %s/logs'%dir_onoff) 
2082   
2083       
2084      files = glob.glob('%s/post*'%self.input_dir) 
2085      self.make_cvs_copy(files, dir_onoff) 
2086   
2087       
2088      cmd = 'cd %s; ln -s %s/bin executables' % (dir_onoff, pylal_dir) 
2089      system_call(self.name, cmd) 
2090    
2091       
2092      self.code['onoff'] = CodeTagger() 
2093      self.create_setup_script(dir_onoff) 
2094    
2095       
2096      self.apply_sed_file(dir_onoff, 'postproc.in', 'postproc.dag') 
2097   
2098       
2099      dagfile = "%s/postproc.dag" % dir_onoff 
2100      return dagfile 
 2101   
2102     
2104      """ 
2105      Prepare the likelihood directory with all needed files and 
2106      code and prepare the DAG. Don't start DAG here 
2107      @return: name of the DAG file 
2108      """ 
2109   
2110       
2111      tag = get_code_tag() 
2112   
2113       
2114      dir_lik = "%s/GRB%s/likelihood_%s" % (self.analysis_dir, self.name, tag) 
2115      if os.path.exists(dir_lik): 
2116        info(self.name, "    WARNING: The directory %s already exists. Maybe this is a test? " 
2117                        "Then (re)move the directory..." % dir_lik) 
2118        return None 
2119   
2120      system_call(self.name, 'mkdir -p %s/logs'%dir_lik) 
2121   
2122       
2123      files = glob.glob('%s/likelihood*'%self.input_dir) 
2124      self.make_cvs_copy(files, dir_lik) 
2125   
2126       
2127      cmd = 'cd %s; ln -s %s/bin executables' % (dir_lik, self.get_pylal_dir()) 
2128      system_call(self.name, cmd) 
2129   
2130       
2131      self.code['inj'] = CodeTagger() 
2132      self.create_setup_script(dir_lik) 
2133   
2134       
2135      self.apply_sed_file(dir_lik, 'likelihood.in', 'likelihood.dag') 
2136   
2137       
2138      dagfile = "%s/likelihood.dag" % dir_lik 
2139      return dagfile 
 2140   
2141   
2142     
2144      """ 
2145      Check if the dagman.out file does exist 
2146      after some while for the dag with 'dag_key' 
2147      """ 
2148   
2149      dag = self.dag[dag_key] 
2150   
2151       
2152      for i in range(10): 
2153        time.sleep(10) 
2154        success = os.path.exists(dag.get_outname()) 
2155        if success: 
2156          break 
2157   
2158       
2159      if not success: 
2160         
2161         
2162        subject = 'Problems starting condor DAG'      
2163        email_msg = 'The condor DAG %s was not started.\n' % dag.get_dagname() 
2164        send_mail(subject, email_msg)   
2165   
2166         
2167        if dag.status>0: 
2168          dag.status = -dag.status 
2169         
2170        return -1  
2171      else: 
2172   
2173        return 1 
 2174         
2175   
2176     
2178       """ 
2179       Copies all the files given in the list 'files' to 
2180       dest_dir and creates a file 'cvs_versions.txt' in dest_dir 
2181       containing the actual CVS version of the files 
2182       @param files: list of files to be copied from self.input_dir 
2183       @param dest_dir: destination directory 
2184       """ 
2185   
2186       cvs_rev_file_output = '' 
2187       cmd = 'cp ' 
2188       for name in files: 
2189   
2190          
2191         cmd += name + ' ' 
2192   
2193          
2194         basename = os.path.basename(name) 
2195         cmdtmp = "cd %s; cvs status %s " % (os.path.dirname(name), basename) 
2196         code, output, error = external_call(cmdtmp) 
2197   
2198          
2199         for line in output.split('\n'): 
2200           if 'Working revision:' in line: 
2201             rev_work = line.split()[2] 
2202   
2203          
2204         cvs_rev_file_output+='%s %s\n' % (basename, rev_work) 
2205        
2206        
2207       cmd += dest_dir 
2208       system_call(self.name, cmd) 
2209   
2210        
2211       cvs_rev_file_name = dest_dir+'/cvs_versions.txt' 
2212       f = file(cvs_rev_file_name,'w') 
2213       f.write(cvs_rev_file_output) 
2214       f.close() 
 2215        
2216     
2218      """ 
2219      Returns the status of the DAGs of this instance 
2220      in form of a dictionary. 
2221      """ 
2222   
2223      status_dict = {} 
2224   
2225       
2226      for key, dag in self.dag.iteritems(): 
2227        if self.has_data: 
2228          status = dag.get_status() 
2229          text = dag.get_stage_name() 
2230          if status<0: 
2231            text = '<font color="#FF0000">%s</font>'%text 
2232          if status==5: 
2233            text = '<font color="#00aa00">%s</font>'%text 
2234        else: 
2235          text = 'NoData' 
2236   
2237         
2238        status_dict[key]=text 
2239          
2240      return status_dict 
 2241   
2242     
2250   
2251     
2253      """ 
2254      Applies the sed file to an in file 
2255      """ 
2256   
2257       
2258      sedfile = path+'/sed.file' 
2259      self.create_sed_file(sedfile) 
2260   
2261       
2262      cmd = 'sed -f %s %s/%s > %s/%s' % (sedfile, path, infile, path, outfile) 
2263      system_call(self.name, cmd, False) 
 2264   
2265     
2267      """ 
2268      Creates the replacement sed file that will be used later 
2269      on several in files. 
2270      """ 
2271   
2272       
2273      publishing_path = cp.get('paths','publishing_path') 
2274      html_path = "%s/GRB%s" % (publishing_path, self.name) 
2275   
2276       
2277      f = file(sedfile,'w') 
2278      f.write("# created %s\n"%get_time()) 
2279      f.write("s/@GRBNAME@/GRB%s/g\n"%self.name) 
2280      f.write("s=@ANALYSISPATH@=%s=g\n"%self.analysis_dir) 
2281      f.write("s/@STARTTIME@/%d/g\n"%self.starttime) 
2282      f.write("s/@ENDTIME@/%d/g\n"%self.endtime) 
2283      f.write("s/@IFOS@/%s/g\n"%self.ifos) 
2284      f.write("s=@LOGPATH@=%s=g\n"%self.condor_log_path) 
2285      f.write("s/@TRIGGERTIME@/%d/g\n"%int(self.time)) 
2286      f.write("s/@RIGHTASCENSION@/%f/g\n"%float(self.ra)) 
2287      f.write("s/@DECLINATION@/%f/g\n"%float(self.de)) 
2288      f.write("s=@OUTPUTPATH@=html=g\n") 
2289      f.write("s=@OPENBOXPATH@=OPENBOX=g\n") 
2290      f.write("s=@HTMLOUTPUT@=%s=g\n"%html_path) 
2291      f.write("s/@LOGNAME@/%s/g\n" % os.getenv("LOGNAME")) 
2292      f.write("s/@BOUNDARIESMC@/%s/g\n" % cp.get('analysis','mc_boundaries')) 
2293      f.write("s/@GRBID@/%s/g\n"%self.name) 
2294      f.write("s=@GRBPICKLE@=%s=g\n"%get_monitor_filename()) 
2295      f.write("s=@CONFIGFILE@=%s=g\n"%self.config_file) 
2296      f.write("s/@BOUNDARIESM2@/%s/g\n" % cp.get('analysis','m2_boundaries')) 
2297      vetofiles = '' 
2298      for ifo in self.ifolist: 
2299        vetofiles+=',../../%s-VETOTIME_CAT2_grb%s.txt' %(ifo, self.name) 
2300      f.write("s=@VETOFILES@=%s=g\n" % vetofiles) 
2301      f.write("s/@STATISTIC@/%s/g\n" % cp.get('analysis','statistic'))  
2302      f.close() 
 2303   
2304   
2305     
2307      """ 
2308      Returns the setup script used for the current environment 
2309      @return: path to source file 
2310      """ 
2311   
2312       
2313      tag = get_code_tag() 
2314   
2315       
2316      source_file = cp.get('paths','lalsuite') + '/'+tag+'.pylal.rc' 
2317   
2318      if not os.path.exists(source_file): 
2319        del_lock() 
2320        raise IOError, "Source script does not seem to be present: %s. Please check." % source_file 
2321       
2322      return source_file 
 2323   
2324     
2326      """ 
2327      Create a setup script in the directory 
2328      @param dest_dir: destination directory 
2329      """ 
2330   
2331       
2332      source_file = self.get_code_setup() 
2333   
2334       
2335      cmd = 'cd %s; ln -s %s setup.rc' % (dest_dir, source_file) 
2336      system_call(self.name, cmd) 
 2337   
2338   
2339     
2341      """ 
2342      Cleanup of the temporary files stored in the main dir 
2343      to either put them into the GRB directories 
2344      or into the Auxiliary directory 
2345      @param path: path to where to shift the files 
2346      """ 
2347   
2348      cmd = 'mv %s/*grb%s* %s'%(cp.get('paths','main'), self.name, path) 
2349      system_call(self.name, cmd) 
2350      cmd = 'mv %s/*VETOTIME* %s'%(cp.get('paths','main'), path) 
2351      system_call(self.name, cmd) 
 2352