casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables
task_setjy.py
Go to the documentation of this file.
00001 from glob import glob
00002 import os
00003 import sys
00004 import shutil
00005 from setjy_helper import * 
00006 from taskinit import *
00007 from parallel.parallel_task_helper import ParallelTaskHelper
00008 
00009 def setjy(vis=None, field=None, spw=None,
00010           selectdata=None, timerange=None, scan=None, observation=None,
00011           modimage=None, listmodels=None,
00012           scalebychan=None, fluxdensity=None, spix=None, reffreq=None,
00013           standard=None, useephemdir=None, usescratch=None):
00014   """Fills the model column for flux density calibrators."""
00015 
00016   casalog.origin('setjy')
00017   # Take care of the trivial parallelization
00018   if ( not listmodels and ParallelTaskHelper.isParallelMS(vis)):
00019     # jagonzal: We actually operate in parallel when usescratch=True because only
00020     # in this case there is a good trade-off between the parallelization overhead
00021     # and speed up due to the load involved with MODEL_DATA column creation
00022     if (usescratch):
00023       helper = ParallelTaskHelper('setjy', locals())
00024       retval = helper.go()
00025     # jagonzal: When usescratch=False, we operate sequentially, but it is necessary
00026     # to iterate trough the list of individual sub-MSs, because each one has its own
00027     # set of keywords (where the visibility model header is set)
00028     else:
00029       myms = mstool()
00030       myms.open(vis)
00031       subMS_list = myms.getreferencedtables()
00032       myms.close()
00033       retval = True
00034       for subMS in subMS_list:
00035           retval_i = setjy_core(subMS, field, spw, selectdata, timerange, 
00036                                 scan, observation, modimage, listmodels, scalebychan, 
00037                                 fluxdensity, spix, reffreq, standard, useephemdir, usescratch)
00038           if not retval_i:
00039               retval = False
00040               casalog.post("setjy failed for sub-MS %s" % (subMS),'WARNING')
00041            
00042       # jagonzal: Gather the models from the keywords of each individual sub-MS
00043       mytb = tbtool()
00044       keywords_MMS = {}
00045       for subMS in subMS_list:
00046           mytb.open(subMS)
00047           keywords_subMS = mytb.getkeywords()
00048           for key in keywords_subMS:
00049               if key.count("model"):
00050                   keywords_MMS[key] = keywords_subMS[key]
00051           mytb.close()
00052           
00053       # jagonzal: Copy the models to the keywords of each individual sub-MS
00054       for subMS in subMS_list:
00055           mytb.open(subMS,nomodify=False)
00056           for key in keywords_MMS:
00057               mytb.putkeyword(key,keywords_MMS[key])
00058           mytb.close()
00059           
00060           
00061   else:
00062     retval = setjy_core(vis, field, spw, selectdata, timerange, 
00063                         scan, observation, modimage, listmodels, scalebychan, 
00064                         fluxdensity, spix, reffreq, standard, useephemdir, usescratch)
00065 
00066   return retval
00067 
00068 
00069 def setjy_core(vis=None, field=None, spw=None,
00070                selectdata=None, timerange=None, scan=None, observation=None,
00071                modimage=None, listmodels=None,
00072                scalebychan=None, fluxdensity=None, spix=None, reffreq=None,
00073                standard=None, useephemdir=None, usescratch=None):
00074   """Fills the model column for flux density calibrators."""
00075 
00076   retval = True
00077   clnamelist=[]
00078   try:
00079     # Here we only list the models available, but don't perform any operation
00080     if listmodels:
00081       casalog.post("Listing model candidates (listmodels == True).")
00082       if vis:
00083         casalog.post("%s is NOT being modified." % vis)
00084 
00085       if standard=='Butler-JPL-Horizons 2012':
00086         ssmoddirs = findCalModels(target='SolarSystemModels',
00087                   roots=[casa['dirs']['data']],
00088                   exts=['.im','.ms','tab'])
00089         if ssmoddirs==set([]):
00090           casalog.post("No models were found. Missing SolarSystemModels in the CASA data directory","WARN")           
00091         for d in ssmoddirs:
00092           lsmodims(d,modpat='*Tb.dat', header='Tb models of solar system objects available for %s' % standard) 
00093       elif standard=='Butler-JPL-Horizons 2010':
00094         availmodellist=['Venus', 'Mars', 'Jupiter', 'Uranus', 'Neptune', 'Pluto',
00095                         'Io', 'Europa', 'Ganymede', 'Callisto', 'Titan','Triton',
00096                         'Ceres', 'Pallas', 'Vesta', 'Juno', 'Victoria', 'Davida']
00097         print "Solar system objects recognized by %s:" % standard
00098         print availmodellist 
00099       else:
00100         lsmodims('.', modpat='*.im* *.mod*')
00101         calmoddirs = findCalModels()
00102         ssmoddirs=None
00103         for d in calmoddirs:
00104           lsmodims(d)
00105 
00106     # Actual operation, when either the MODEL_DATA column or visibility model header are set
00107     else:
00108       if not os.path.isdir(vis):
00109         #casalog.post(vis + " must be a valid MS unless listmodels is True.",
00110         #             "SEVERE")
00111         raise Exception, "%s is not a valid MS" % vis 
00112         #return False
00113 
00114       myms = mstool()
00115       myim = imtool()
00116 
00117       if type(vis) == str and os.path.isdir(vis):
00118         n_selected_rows = nselrows(vis, field, spw, observation, timerange, scan)
00119 
00120         # jagonzal: When  usescratch=True, creating the MODEL column only on a sub-set of
00121         # Sub-MSs causes problems because ms::open requires all the tables in ConCatTable 
00122         # to have the same description (MODEL data column must exist in all Sub-MSs)
00123         #
00124         # This is a bit of an over-doing but it is necessary for the sake of transparency
00125         #
00126         # Besides, this is also the same behavior as when running setjy vs a normal MS
00127         #
00128         # Finally, This does not affect the normal MS case because nselrows throws an
00129         # exception when the user enters an invalid data selection, but it works for the 
00130         # MMS case because every sub-Ms contains a copy of the entire MMS sub-tables
00131         if ((not n_selected_rows) and (not usescratch)):
00132           # jagonzal: Turn this SEVERE into WARNING, as explained above
00133           casalog.post("No rows were selected.", "WARNING")
00134           return True
00135         else:
00136           myim.open(vis, usescratch=usescratch)
00137 
00138       else:
00139         raise Exception, 'Visibility data set not found - please verify the name'
00140 
00141       # If modimage is not an absolute path, see if we can find exactly 1 match in the likely places.
00142       if modimage and modimage[0] != '/':
00143         cwd = os.path.abspath('.')
00144         calmoddirs = [cwd]
00145         calmoddirs += findCalModels(roots=[cwd,
00146                                            casa['dirs']['data']])
00147         candidates = []
00148         for calmoddir in calmoddirs:
00149           cand = calmoddir + '/' + modimage
00150           if os.path.isdir(cand):
00151             candidates.append(cand)
00152         if not candidates:
00153           casalog.post("%s was not found for modimage in %s." %(modimage,
00154                                                                   ', '.join(calmoddirs)),
00155                        'SEVERE')
00156           return False
00157         elif len(candidates) > 1:
00158           casalog.post("More than 1 candidate for modimage was found:",
00159                        'SEVERE')
00160           for c in candidates:
00161             casalog.post("\t" + c, 'SEVERE')
00162             casalog.post("Please pick 1 and use the absolute path (starting with /).",
00163                          'SEVERE')
00164             return False
00165         else:
00166           modimage = candidates[0]
00167           casalog.post("Using %s for modimage." % modimage, 'INFO')
00168 
00169       # Write the parameters to HISTORY before the tool writes anything.
00170       try:
00171         param_names = setjy.func_code.co_varnames[:setjy.func_code.co_argcount]
00172         param_vals = [eval(p) for p in param_names]   
00173         retval &= write_history(myms, vis, 'setjy', param_names,
00174                                 param_vals, casalog)
00175       except Exception, instance:
00176         casalog.post("*** Error \'%s\' updating HISTORY" % (instance),
00177                      'WARN')
00178 
00179       # Split the process for solar system objects
00180       # To maintain the behavior of SetJy such that if a flux density is specified
00181       # we use it rather than the model, we need to check the state of the 
00182       # input fluxdensity  JSK 10/25/2012
00183       userFluxDensity = fluxdensity is not None
00184       if userFluxDensity and isinstance(fluxdensity, list):
00185         userFluxDensity = fluxdensity[0] > 0.0
00186       elif userFluxDensity:
00187         userFluxDensity = fluxdensity > 0.0
00188 
00189       if standard=="Butler-JPL-Horizons 2012" and not userFluxDensity:
00190         casalog.post("Using Butler-JPL-Horizons 2012")
00191         ssmoddirs = findCalModels(target='SolarSystemModels',
00192                   roots=[casa['dirs']['data']],
00193                   exts=['.im','.ms','tab'])
00194         if ssmoddirs==set([]):
00195           raise Exception, "Missing Tb models in the data directory"
00196 
00197         setjyutil=ss_setjy_helper(myim,vis,casalog)
00198         setjyutil.setSolarObjectJy(field=field,spw=spw,scalebychan=scalebychan,
00199                          timerange=timerange,observation=str(observation), scan=scan, useephemdir=useephemdir)
00200         clnamelist=setjyutil.getclnamelist()
00201       else:
00202         myim.setjy(field=field, spw=spw, modimage=modimage,
00203                  fluxdensity=fluxdensity, spix=spix, reffreq=reffreq,
00204                  standard=standard, scalebychan=scalebychan, time=timerange,
00205                  observation=str(observation), scan=scan)
00206       myim.close()
00207 
00208   # This block should catch errors mainly from the actual operation mode 
00209   except Exception, instance:
00210     casalog.post('%s' % instance,'SEVERE')
00211     retval=False
00212     raise instance
00213 
00214   finally:
00215     if standard=='Butler-JPL-Horizons 2012':
00216         for cln in clnamelist:
00217             if os.path.isdir(cln):
00218                 shutil.rmtree(cln) 
00219 
00220 
00221   return retval
00222 
00223 
00224 def better_glob(pats):
00225   """
00226   Unlike ls, glob.glob('pat1 pat2') does not return  
00227   the union of matches to pat1 and pat2.  This does.
00228   """
00229   retset = set([])
00230   patlist = pats.split()
00231   for p in patlist:
00232     retset.update(glob(p))
00233   return retset
00234   
00235 
00236 def lsmodims(path, modpat='*', header='Candidate modimages'):
00237   """
00238   Does an ls -d of files or directories in path matching modpat.
00239   
00240   Header describes what is being listed.
00241   """
00242   if os.path.isdir(path):
00243     if better_glob(path + '/' + modpat):
00244       print "\n%s (%s) in %s:" % (header, modpat, path)
00245       sys.stdout.flush()
00246       os.system('cd ' + path + ';ls -d ' + modpat)
00247     else:
00248       print "\nNo %s matching '%s' found in %s" % (header.lower(),
00249                                                    modpat, path)
00250 
00251 
00252 def findCalModels(target='CalModels',
00253                   roots=['.', casa['dirs']['data']],
00254                   permexcludes = ['.svn', 'regression', 'ephemerides',
00255                                   'geodetic', 'gui'],
00256                   exts=['.ms', '.im', '.tab']):
00257   """
00258   Returns a set of directories ending in target that are in the trees of roots.
00259   
00260   Because casa['dirs']['data'] can contain a lot, and CASA tables are
00261   directories, branches matching permexcludes or exts are excluded for speed.
00262   """
00263   retset = set([])
00264   for root in roots:
00265     # Do a walk to find target directories in root.
00266     # 7/5/2011: glob('/export/data_1/casa/gnuactive/data/*/CalModels/*') doesn't work.
00267     for path, dirs, fnames in os.walk(root, followlinks=True):
00268       excludes = permexcludes[:]
00269       for ext in exts:
00270         excludes += [d for d in dirs if ext in d]
00271       for d in excludes:
00272         if d in dirs:
00273           dirs.remove(d)
00274       if path.split('/')[-1] == target:
00275         retset.add(path)
00276   return retset             
00277 
00278 
00279 def nselrows(vis, field='', spw='', obs='', timerange='', scan=''):
00280 
00281   retval = 0
00282   myms = mstool()
00283 
00284   msselargs = {'vis': vis}
00285   if field:
00286     msselargs['field'] = field
00287   if spw:
00288     msselargs['spw'] = spw
00289   if obs:
00290     msselargs['observation'] = obs
00291   if timerange:
00292     msselargs['time'] = timerange
00293   if scan:
00294     msselargs['scan'] = scan
00295       
00296   # ms.msseltoindex only goes by the subtables - it does NOT check
00297   # whether the main table has any rows matching the selection.
00298   try:
00299     selindices = myms.msseltoindex(**msselargs)
00300   except Exception, instance:
00301     casalog.post('nselrowscore exception: %s' % instance,'SEVERE')
00302     raise instance
00303 
00304   query = []
00305   if field:
00306     query.append("FIELD_ID in " + str(selindices['field'].tolist()))
00307   if spw:
00308     query.append("DATA_DESC_ID in " + str(selindices['spw'].tolist()))
00309   if obs:
00310     query.append("OBSERVATION_ID in " + str(selindices['obsids'].tolist()))
00311 
00312   # I don't know why ms.msseltoindex takes a time argument 
00313   # - It doesn't seem to appear in the output.
00314     
00315   if scan:
00316     query.append("SCAN_NUMBER in " + str(selindices['scan'].tolist()))
00317 
00318   mytb = tbtool()
00319   mytb.open(vis)
00320 
00321   if (len(query)>0):
00322     retval = mytb.nrows()
00323     mytb.close()
00324   else:
00325     try:
00326       st = mytb.query(' and '.join(query),style='python')  # Does style matter here?
00327       retval = st.nrows()
00328       mytb.close()
00329     except Exception, instance:
00330       casalog.post('nselrowscore exception: %s' % instance,'SEVERE')
00331       mytb.close()
00332       raise Exception, instance
00333 
00334   return retval