Beispiel #1
0
def readsolascii(solfile, soldict):
    """Read in an ascii file that has the wavelength solution in formation in it.
       The ascii file is expected to be in the same format as the output from
       saltidentify

       return soldict
    """
    # open up the ascii file
    fin = saltsafeio.openascii(solfile, 'r')
    data = fin.read()

    # Each new solution in the file should have WS at the start of it.  We will split
    # the file on ws
    sol_list = data.split('#WS')
    for sol in sol_list[1:]:
        name = findwskeyword('name', sol)
        timeobs = enterdatetime(findwskeyword('time-obs', sol))
        instrume = findwskeyword('instrument', sol)
        grating = findwskeyword('grating', sol)
        graang = float(findwskeyword('gratilt', sol))
        arang = float(findwskeyword('artilt', sol))
        filtername = findwskeyword('filter', sol)
        function = findwskeyword('Function', sol)
        order = int(findwskeyword('Order', sol))
        try:
            slitid = findwskeyword('slitid', sol)
            name = name + '_' + slitid
        except:
            slitid = None
        try:
            domain = findwskeyword('domain', sol)
            domain = [float(x) for x in domain.split(',')]
        except:
            domain = None
        wsrow = []
        wscoef = []
        j = finddata(sol)
        for ws in sol[j:].splitlines():
            if ws.strip():
                ws = ws.split()
                wsrow.append(float(ws[0]))
                wscoef.append(np.array(ws[1:], dtype=float))
        soldict[name] = [
            timeobs,
            instrume,
            grating,
            graang,
            arang,
            filtername,
            slitid,
            function,
            order,
            np.array(wsrow),
            wscoef,
            domain]

    return soldict
Beispiel #2
0
def readsolascii(solfile, soldict):
    """Read in an ascii file that has the wavelength solution in formation in it.
       The ascii file is expected to be in the same format as the output from
       saltidentify

       return soldict
    """
    # open up the ascii file
    fin = saltsafeio.openascii(solfile, 'r')
    data = fin.read()

    # Each new solution in the file should have WS at the start of it.  We will split
    # the file on ws
    sol_list = data.split('#WS')
    for sol in sol_list[1:]:
        name = findwskeyword('name', sol)
        timeobs = enterdatetime(findwskeyword('time-obs', sol))
        instrume = findwskeyword('instrument', sol)
        grating = findwskeyword('grating', sol)
        graang = float(findwskeyword('gratilt', sol))
        arang = float(findwskeyword('artilt', sol))
        filtername = findwskeyword('filter', sol)
        function = findwskeyword('Function', sol)
        order = int(findwskeyword('Order', sol))
        try:
            slitid = findwskeyword('slitid', sol)
            name = name + '_' + slitid
        except:
            slitid = None
        try:
            domain = findwskeyword('domain', sol)
            domain = [float(x) for x in domain.split(',')]
        except:
            domain = None
        wsrow = []
        wscoef = []
        j = finddata(sol)
        for ws in sol[j:].splitlines():
            if ws.strip():
                ws = ws.split()
                wsrow.append(float(ws[0]))
                wscoef.append(np.array(ws[1:], dtype=float))
        soldict[name] = [
            timeobs,
            instrume,
            grating,
            graang,
            arang,
            filtername,
            slitid,
            function,
            order,
            np.array(wsrow),
            wscoef,
            domain]

    return soldict
Beispiel #3
0
def writespectrum(spectra, outfile, error=False, ftype=None):
   """Given a spectrum, write it out to a file"""
   fout=saltio.openascii(outfile, 'w')
   for i in range(spectra.nwave):
       fout.write('%8.6f ' % spectra.wavelength[i])
       fout.write('%8.6e ' % spectra.flux[i])
       if error: fout.write('%8.6e ' % spectra.sigma[i])
       fout.write('\n')
   fout.close()
Beispiel #4
0
def writespectrum(spectra, outfile, error=False, ftype=None):
    """Given a spectrum, write it out to a file"""
    fout = saltio.openascii(outfile, 'w')
    for i in range(spectra.nwave):
        fout.write('%8.6f ' % spectra.wavelength[i])
        fout.write('%8.6e ' % spectra.flux[i])
        if error:
            fout.write('%8.6e ' % spectra.var[i])
        fout.write('\n')
    fout.close()
Beispiel #5
0
def mkheader(file, keyword, value, comment):
    """create keyword with mkheader IRAF tool i.e. without opening the whole file"""

    try:
        tmpfile = saltsafeio.tmpfile('.', False)
        tmp = saltsafeio.openascii(tmpfile, 'w')
        tmp.write('%-8s= \'%-18s\' / %-s\n' % (keyword, value, comment))
        saltsafeio.closeascii(tmp)
        iraf.noao.artdata.mkheader(file, tmpfile, append='y', verbose='n')
        saltsafeio.delete(tmpfile, False)
    except:
        raise SaltIOError('Cannot edit keyword ' + keyword + ' in ' + file)
Beispiel #6
0
def mkheader(file,keyword,value,comment):
    """create keyword with mkheader IRAF tool i.e. without opening the whole file"""

    try:
        tmpfile=saltsafeio.tmpfile('.',False)
        tmp=saltsafeio.openascii(tmpfile,'w')
        tmp.write('%-8s= \'%-18s\' / %-s\n' % (keyword,value,comment))
        saltsafeio.closeascii(tmp)
        iraf.noao.artdata.mkheader(file,tmpfile,append='y',verbose='n')
        saltsafeio.delete(tmpfile,False)
    except:
        raise SaltIOError('Cannot edit keyword '+keyword+' in '+file)
Beispiel #7
0
def maketempreadmefast(pid, sdb, readme):
   """Creates the readme file to send to the PI.  It adds on the observing log for those
      observations
   """
   #read in the readme
   f=saltio.openascii(readme, 'r')
   rstring=f.read()
   saltio.closeascii(f)

   #replace propcode with the actual propcode
   if pid: rstring=rstring.replace('PROPCODE', pid)

   #add in the observing log

   return rstring 
Beispiel #8
0
def saltfpcalring(images,outfile, waves, method=None, thresh=5, minsize=10, niter=3, conv=0.05,  
                  axc=None, ayc=None, 
                  clobber=False,logfile='salt.log',verbose=True):  
   """Fits rings in Fabry-Perot ring images"""
   with logging(logfile,debug) as log:

       # Check the input images 
       infiles = saltio.argunpack ('Input',images)

       # if the outfile exists and not clobber, fail
       saltio.overwrite(outfile,clobber) 

       #open the output file
       fout = saltio.openascii(outfile, 'w')

       #make sure that the list of waves is convertable to a numpy array
       #convert to floats in case the wave is given as a string
       if isinstance(waves, str):  
          waves=[float(x) for x in waves.split(',')]

       try: 
           waves=np.array(waves)
       except:
           raise SaltError('%s is not convertable to a numpy array' % waves)

       #check the value of method
       method=saltio.checkfornone(method)

       #setup the output file
       fout.write('#Comment\n')
       fout.write('# radius   err     xc      yc      z      ut     wave   dn  file\n')

       # open each image and detect the ring
       for img,w  in zip(infiles, waves):

          #open the image
          hdu=saltio.openfits(img)

          #measure the ring in each file
          xc, yc, radius, err, z, ut=make_calring(hdu, method=method, thresh=thresh, niter=niter, conv=conv, minsize=minsize, axc=axc, ayc=ayc)

          #output the results
          outstr=' %7.2f %6.2f %7.2f %7.2f %6.2f %7.4f %8.3f  0 %s\n' % (radius, err, xc, yc, z, ut, w, img)
          fout.write(outstr)
          log.message(outstr.strip(), with_stdout=verbose, with_header=False)

       fout.close()
Beispiel #9
0
def readkeyfile(keyfile, log=None, verbose=True):
   """Read in the keyword file"""
 
   #open the key word file
   kfile = saltio.openascii(keyfile,'r')

   #extract keyword edits
   keyedits={}
   for line in kfile:
       if len(line.strip()) > 0 and not line.startswith('#'):
           try:
               frange, finstr, fstar, fend=getfrange(line)
               #print frange, finstr, fstar, fend
               keyedits[frange]=[finstr, fstar, fend, getitems(line, frange)]
               #print frange, keyedits[frange]
               #print getitems(line, frange)
           except EditKeyError,e :
               message="Could not extract keyword edits for %s because %s" % (line, e)
               log.error(message)
Beispiel #10
0
def checkfordata(rawpath, prefix, obsdate, log):
   """Check to see if the data have downloaded correctly"""
   lastnum=1
   saltio.fileexists(rawpath+'disk.file')
   content = saltio.openascii(rawpath+'disk.file','r')
   for line in content:
       lastnum = saltstring.filenumber(line)
   saltio.closeascii(content)
   lastfile = saltstring.filename(prefix,obsdate,lastnum-1)

   if lastnum==1: return lastnum

   #check to see that the data are present
   if (os.path.isfile(rawpath+lastfile) or os.path.isfile(rawpath+lastfile.replace('fits','bin'))):
       message  = 'Data download complete for %s\n' % rawpath
       log.message(message)
   else:
       message  = 'Data download incomplete to %s' % rawpath
       log.error(message)

   return lastnum
Beispiel #11
0
def write_extract_text(ofile, ap_list, clobber=False):
    """Write out the extracted spectrum to a text file.  If the file already
       exists, this will not overwrite it.  The first

       For each spectrum in ap_list, it will add a columns onto the output file
       so that the first column is always wavelength, the second column is
       flux, and the third column is sigma, and then repeat the flux and sigma
       columns

       ofile: Output file to write

       ap_list:  List of extracted spectrum

       clobber: delete ofile if it already exists


    """
    if os.path.isfile(ofile) and not clobber:
        return

    # open the file
    dout = saltio.openascii(ofile, 'w')

    # first extract warr, assume it is the same for all frames
    warr = ap_list[0].wave

    # write out the spectrum
    for i in range(len(warr)):
        outstr = '%7.3f ' % warr[i]
        for ap in ap_list:
            flux = ap.ldata[i]
            try:
                fvar = abs(ap.lvar[i])**0.5
            except:
                fvar = 1
            outstr += "%7.3f %7.3f " % (flux, fvar)
        outstr += '\n'
        dout.write(outstr)
    dout.close()
    return
Beispiel #12
0
def write_extract_text(ofile, ap_list, clobber=False):
    """Write out the extracted spectrum to a text file.  If the file already
       exists, this will not overwrite it.  The first

       For each spectrum in ap_list, it will add a columns onto the output file
       so that the first column is always wavelength, the second column is
       flux, and the third column is sigma, and then repeat the flux and sigma
       columns

       ofile: Output file to write

       ap_list:  List of extracted spectrum

       clobber: delete ofile if it already exists


    """
    if os.path.isfile(ofile) and not clobber:
        return

    # open the file
    dout = saltio.openascii(ofile, "w")

    # first extract warr, assume it is the same for all frames
    warr = ap_list[0].wave

    # write out the spectrum
    for i in range(len(warr)):
        outstr = "%7.3f " % warr[i]
        for ap in ap_list:
            flux = ap.ldata[i]
            try:
                fvar = abs(ap.lvar[i]) ** 0.5
            except:
                fvar = 1
            outstr += "%7.3f %7.3f " % (flux, fvar)
        outstr += "\n"
        dout.write(outstr)
    dout.close()
    return
Beispiel #13
0
def fitsconfig(config):
   """reads in the configuration file and calculates the appropriate parameters
       for the sections

       returns dictiionary
   """

   condict={}
   #open and read the config file
   construct=saltio.openascii(config,'r')
   try:
       condata = construct.read().split('\n')
   except:
       message = 'ERROR: VID2BIN.FITSCONFIG -- cannot read in ' + file
       raise SaltError(message)


   for conline in condata:
       ckey,cval=processline(conline)
       if ckey and cval: condict[ckey]=cval

   return condict
Beispiel #14
0
def slotview(newfits,indata , fileout, srcfile, fps=10.0, phottype='square', sigdet=5, contpix=10, \
    driftlimit=10, clobber=True,logfile='slotview.log',verbose=True):

    #set up the variables
    status = 0
    entries = []
    vig_lo = {}
    vig_hi = {}
    hour = 0
    min = 0
    sec = 0.
    time0 = 0.
    nframes = 0
    sleep = 0

    with logging(logfile, debug) as log:

        #enter in the input data
        saltio.fileexists(newfits)

        #set the sleep parameter
        if fps > 0: sleep = 1.0 / (fps)

        # read in the data file
        id, time, ratio, rerr, tx, ty, tflux, terr, cx, cy, cflux, cerr = st.readlcfile(
            indata)

        # read extraction region defintion file
        amp, x, y, x_o, y_o, r, br1, br2 = st.readsrcfile(srcfile)

        #determine the size of the data arrays
        struct = saltio.openfits(newfits)
        naxis1 = saltkey.get('NAXIS1', struct[1])
        naxis2 = saltkey.get('NAXIS2', struct[1])

        # Plot all of the data and the first image
        # Create GUI
        App = QtGui.QApplication([])
        aw=SlotViewWindow(struct, id, tflux, cflux, ratio, time, phottype, sleep,   \
                     tx, ty, cx, cy, r, br1, br2, naxis1, naxis2, sigdet, contpix, driftlimit)
        aw.show()

        # Start application event loop
        app_exit = App.exec_()

        # Check if GUI was executed succesfully
        if app_exit != 0:
            raise SALTError('InterIdentify GUI has unexpected exit status ' +
                            str(exit))

        ratio, tflux, cflux, gframe, newphot = aw.ratio, aw.tflux, aw.cflux, aw.goodframes, aw.newphot

        #close the input file
        saltio.closefits(struct)

        # Update the indata file if necessary
        lc = saltio.openascii(fileout, 'w')

        for i in range(len(ratio)):
            x['target'] = tx[i]
            x['comparison'] = cx[i]
            y['target'] = ty[i]
            y['comparison'] = cy[i]
            reltime = False
            if gframe[i]:
                st.writedataout(lc, id[i], time[i], x, y, tflux[i], terr[i], \
                    cflux[i], cerr[i], ratio[i], rerr[i], time[0], reltime)

        saltio.closeascii(lc)
Beispiel #15
0
def slotview(newfits,indata , fileout, srcfile, fps=10.0, phottype='square', sigdet=5, contpix=10, \
    driftlimit=10, clobber=True,logfile='slotview.log',verbose=True):

    
#set up the variables
    status = 0
    entries = []
    vig_lo = {}
    vig_hi = {}
    hour = 0
    min = 0
    sec = 0.
    time0 = 0.
    nframes = 0
    sleep=0

    with logging(logfile,debug) as log:

        #enter in the input data
        saltio.fileexists(newfits)

        #set the sleep parameter
        if fps>0: sleep=1.0/(fps)

        # read in the data file
        id, time, ratio, rerr, tx, ty, tflux, terr, cx, cy, cflux, cerr=st.readlcfile(indata)

        # read extraction region defintion file
        amp, x, y, x_o, y_o, r, br1, br2=st.readsrcfile(srcfile)



        #determine the size of the data arrays
        struct = saltio.openfits(newfits)
        naxis1 = saltkey.get('NAXIS1',struct[1])
        naxis2 = saltkey.get('NAXIS2',struct[1])

        # Plot all of the data and the first image
        # Create GUI
        App = QtGui.QApplication([])
        aw=SlotViewWindow(struct, id, tflux, cflux, ratio, time, phottype, sleep,   \
                     tx, ty, cx, cy, r, br1, br2, naxis1, naxis2, sigdet, contpix, driftlimit)
        aw.show()

        # Start application event loop
        app_exit=App.exec_()
        
        # Check if GUI was executed succesfully
        if app_exit!=0:
             raise SALTError('InterIdentify GUI has unexpected exit status '+str(exit))

        ratio, tflux, cflux, gframe, newphot=aw.ratio, aw.tflux, aw.cflux, aw.goodframes, aw.newphot

        #close the input file
        saltio.closefits(struct)

        # Update the indata file if necessary
        lc=saltio.openascii(fileout,'w')

        for i in range(len(ratio)):
            x['target']=tx[i]
            x['comparison']=cx[i]
            y['target']=ty[i]
            y['comparison']=cy[i]
            reltime=False
            if gframe[i]:
                st.writedataout(lc, id[i], time[i], x, y, tflux[i], terr[i], \
                    cflux[i], cerr[i], ratio[i], rerr[i], time[0], reltime)

        saltio.closeascii(lc)
Beispiel #16
0
       print pids, propids
       try:
           pids=saltio.cleanpropcode(pids, propids)
           pids=saltio.removebadpids(pids)
           pids=saltio.removeengineeringpids(pids)
       except SaltIOError:
           msg="No notifications necessary for %s" % obsdate
           log.warning
           return

       #loop through each of the pids and send the email
       for pid in pids:
         propinfo=findpropinfo(pid, sdb)
         if propinfo:
           for pi, email in zip(propinfo[pid][0], propinfo[pid][1]):
               letter=saltio.openascii(readme,'r')
               msg=letter.read()
               msg=msg.replace('yourname',pi)
               msg=msg.replace('YYYY-INST-PID',pid.upper())
               msg=msg.replace('yyyymmdd',obsdate)
               saltio.closeascii(letter)

               #set up the message to be sent
               recip = []
               #uncomment the following lines if you just want to send the email
               #to yourself
               #email='*****@*****.**'
               #bcclist=[]
               recip.append(email)
               for bccobj in bcclist:
                   recip.append(bccobj)
Beispiel #17
0
def saltquery(selection, logic, startdate, enddate, outfile=None, sdbhost='sdb.saao', sdbname='sdb', \
              sdbuser='', password='', clobber=False, logfile='saltlog.log', verbose=True):
    """Query the salt database for FITS files

    """

    with logging(logfile,debug) as log:

       #check the outfiles
       if not saltio.checkfornone(outfile):
          outfile=None
          
       #check that the output file can be deleted
       if outfile:
           saltio.overwrite(outfile, clobber)

       #open outfile
       if outfile:
          fout=saltio.openascii(outfile, 'w')


       #connect to the database
       sdb=saltmysql.connectdb(sdbhost,sdbname,sdbuser,password)

       #Create a list of the selection and then unpack it
       selection_list = saltio.argunpack('Selection', selection)
       selection=','.join(selection_list)

       #write out the header for the outfile
       outstr='#'+' '.join(['%s' % x for x in selection_list]) 
       if outfile:
          fout.write(outstr+'\n')
       else:
          print outstr


       #set up the table
       rsstable=''' FileData 
  left join FitsHeaderImage using (FileData_Id) 
  inner join FitsHeaderRss using (FileData_Id) 
'''
       #set up the table
       scamtable=''' FileData 
  left join FitsHeaderImage using (FileData_Id) 
  inner join FitsHeaderSalticam using (FileData_Id) 
'''

       #set up the logic
       logic=makelogic(logic, startdate, enddate)

       for tab in [rsstable, scamtable]:

          msg='''
Mysql querying data is:

  SELECT %s
  FROM   %s
  WHERE  %s
'''  % (selection, tab, logic)
          log.message(msg, with_stdout=verbose)


          record=saltmysql.select(sdb, selection, tab, logic)

          print record
  
          for r in record:
             outstr=' '.join(['%s' % x for x in r]) 
             if outfile:
                 fout.write(outstr+'\n')
             else:
                 print outstr

       #close outfile
       if outfile: fout.close()
Beispiel #18
0
def makenightstats(els, sdb, outfile, obsdate, clobber=False):
   """Retrieve data for a given observation during an observation date for 
      a proposal
   """
   fout=saltio.openascii(outfile, 'w')
 

   headerstr="""<html>
<head><title>SALT Night Report for %s</title></head>
<body bgcolor="white" text="black" link="blue" vlink="blue">

<center><h1>
SALT Night Report for %s<br>
</h1></center>
"""  % (obsdate, obsdate)
   fout.write(headerstr)


   #set up the Observing Statistics
   fout.write('<h2> A. Observing Information </h2>\n')
   nid=saltmysql.getnightinfoid(sdb, obsdate)
   print nid
   #get duty information
   selcmd='sa.Surname,  so.Surname,  ct.surname' 
   tabcmd='NightInfo join SaltOperator as so on (SO1_Id=SO_Id) join Investigator as sa on (SA_Id=sa.Investigator_Id) join Investigator as ct on (CTDuty_Id=ct.Investigator_Id)'
   record=saltmysql.select(sdb, selcmd, tabcmd, 'NightInfo_Id=%i' % nid)
   try:
      sa,so,ct=record[0]
      dutystr='SA: %s <br>\nSO: %s <br> \nCT: %s <br>\n<br>' % (sa, so,ct)
   except:
      dutystr='SA: %s <br>\n SO: %s <br> \n CT: %s <br>\n<br>' % ('', '', '')
   fout.write(dutystr)

   #get night time information
   selcmd='SunSet, SunRise, MoonSet, MoonRise, MoonPhase_Percent, EveningTwilightEnd, MorningTwilightStart' 
   record=saltmysql.select(sdb, selcmd, 'NightInfo', 'NightInfo_Id=%i' % nid)[0]
   statlist=['Sun Set', 'Sun Rise', 'Moon Set', 'Moon Rise', 'Moon Phase', 'Evening Twilight', 'Morning Twilight'] 

   statstr='<table border=1><tr><th colspan=2>Nighttime Statistics </th></tr>\n'
   for s,r in zip (statlist, record):
       statstr+='<tr><td>%20s</td><td> %s </td></tr>\n' % (s, r)
   statstr+='</table><br>\n'
   fout.write(statstr)
   mintime=record[0]-datetime.timedelta(seconds=1*3600)
   maxtime=record[1]+datetime.timedelta(seconds=1*3600)
   
   obsstatlist=['Science Time', 'Engineering Time', 'Lost to Weather', 'Lost to Problems']
   selcmd='ScienceTime, EngineeringTime, TimeLostToWeather, TimeLostToProblems'
   record=saltmysql.select(sdb, selcmd, 'NightInfo', 'NightInfo_Id=%i' % nid)[0]
   obsstatstr='<table border=1><tr><th colspan=2>Observing Statistics </th></tr>\n'
   for s,r in zip (obsstatlist, record):
       obsstatstr+='<tr><td>%20s</td><td> %s </td></tr>\n' % (s, r)
   obsstatstr+='</table><br>\n'
   fout.write(obsstatstr)

   #Set up the Envirnmental Statistics
   fout.write('<h2> B. Environmental Statistics </h2>\n')

   #create the tables
   print mintime, maxtime
   #guihdu=guidertable(els, mintime, maxtime)

   #temperature plot
   fout.write('<table>')
   weahdu=weathertable(els, mintime, maxtime)
   tempplot=temperatureplot(weahdu, mintime, maxtime, obsdate)
   fout.write('<tr><td><img width=700 height=200 src=%s></td></tr>\n' % os.path.basename(tempplot))
   windfile=windplot(weahdu, mintime, maxtime, obsdate)
   fout.write('<tr><td><img width=700 height=200 src=%s></td></tr>\n' % os.path.basename(windfile))

   #seeing plot
   seeplot=makeseeingplot(sdb, mintime, maxtime, obsdate)
   fout.write('<tr><td><img width=700 height=200 src=%s><br></td></tr>\n' % os.path.basename(seeplot))

   fout.write('</table>\n')


   #Set up the Pipeline Statistics
   fout.write('<h2> C. Pipeline Statistics </h2>\n')

   fout.write('<table>\n')
   record=saltmysql.select(sdb, 'PipelineStatus, RawSize, ReducedSize, PipelineRunTime', 'PipelineStatistics join PipelineStatus using (PipelineStatus_Id)', 'NightInfo_Id=%i' % nid)[0]
   print record
   print record[1]/3600.0
   pipelinestatus='Completed'
   fout.write('<tr><td>Pipeline Status:</td><td>%s</td></tr>' % record[0])
   fout.write('<tr><td>Raw Data:</td><td>%3.2f Gb</td></tr>' % (record[1]/1e9))
   fout.write('<tr><td>Reduced Data:</td><td>%3.2f Gb</td></tr>' % (record[2]/1e9))
   fout.write('<tr><td>Run Time:</td><td>%3.2f min</td></tr>' % (record[3]/60.0))
   fout.write('</table>\n')

   #Set up the Proposal/Block Statistics
   fout.write('<h2> D. Proposal Statistics </h2>\n')
   selcmd='Proposal_Code, Block_Name, Accepted, ObsTime, BlockRejectedReason_Id, BlockVisit_Id' 
   tabcmd='Block join BlockVisit as bv using (Block_Id) join Proposal using (Proposal_Id) join ProposalCode using (ProposalCode_Id)'
   logcmd='NightInfo_Id=%i' % nid
   record=saltmysql.select(sdb, selcmd, tabcmd, logcmd)
   print record
   fout.write('<table border=1>\n')
   fout.write('<tr><th>Proposal</th><th>Block</th><th>Obs Time</th><th>Accepted?</th><th>Rejected Reason</th></tr>\n')
   for r in record:
       if r[2]>=1: 
          accept='Yes'
          reason=''
       else:
          accept='No'
          print r
          reason=saltmysql.select(sdb, 'RejectedReason', 'BlockRejectedReason', 'BlockRejectedReason_Id=%i' % int(r[4]))[0][0]
       bstr='<tr><td><a href="https://www.salt.ac.za/wm/proposal/%s/">%s</a></td><td>%s</td><td>%3.2f</td><td>%s</td><td>%s</td></tr>\n' % (r[0], r[0], r[1], float(r[3])/3600.0, accept, reason)
       fout.write(bstr)
   fout.write('</table>\n')

   #Set up the Data Quality Statistics
   fout.write('<h2> E. Data Quality </h2>\n')


   fout.write('</body> \n</hmtl>')
   fout.close()