casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables
task_simobserve.py
Go to the documentation of this file.
00001 from taskinit import *
00002 from simutil import *
00003 import os
00004 import re
00005 import pylab as pl
00006 import pdb
00007 
00008 def simobserve(
00009     project=None, 
00010     skymodel=None, inbright=None, indirection=None, incell=None, 
00011     incenter=None, inwidth=None, # innchan=None,
00012     complist=None, compwidth=None,
00013     setpointings=None,
00014     ptgfile=None, integration=None, direction=None, mapsize=None, 
00015     maptype=None, pointingspacing=None, caldirection=None, calflux=None, 
00016     # observe=None,
00017     obsmode=None, 
00018     refdate=None, hourangle=None, 
00019     totaltime=None, antennalist=None, 
00020     sdantlist=None,
00021     sdant=None,
00022     thermalnoise=None,
00023     user_pwv=None, t_ground=None, t_sky=None, tau0=None, seed=None,
00024     leakage=None,
00025     graphics=None,
00026     verbose=None, 
00027     overwrite=None,
00028     async=False):
00029 
00030     # Collect a list of parameter values to save inputs
00031     in_params =  locals()
00032 
00033     import re
00034 
00035     try:
00036 
00037         # RI TODO for inbright=unchanged, need to scale input image to jy/pix
00038         # according to actual units in the input image
00039 
00040         casalog.origin('simobserve')
00041         if verbose: casalog.filter(level="DEBUG2")
00042 
00043         a = inspect.stack()
00044         stacklevel = 0
00045         for k in range(len(a)):
00046             if (string.find(a[k][1], 'ipython console') > 0):
00047                 stacklevel = k
00048         myf = sys._getframe(stacklevel).f_globals
00049 
00050         # create the utility object:
00051         util = simutil(direction)  # this is the dir of the observation - could be ""
00052         if verbose: util.verbose = True
00053         msg = util.msg
00054 
00055         # it was requested to make the user interface "observe" for what 
00056         # is sm.observe and sm.predict.
00057         # interally the code is clearer if we stick with predict so
00058         predict = obsmode.startswith('i') or obsmode.startswith('s')
00059         if predict:
00060             uvmode = obsmode.startswith('i')
00061             if not uvmode: antennalist = sdantlist
00062         elif sdantlist != "":
00063             if antennalist == "":
00064                 uvmode = False
00065                 antennalist = sdantlist
00066             else:
00067                 #uvmode = True
00068                 #msg("Both antennalist and sdantlist are defined. sdantlist will be ignored",priority="warn")
00069                 msg("Both antennalist and sdantlist are defined. Define one of them.",priority="error")
00070                 return False
00071         else:
00072             uvmode = True
00073         #    uvmode = (sdant < 0) #when flexible default values come available
00074 
00075 
00076         # put output in directory called "project"
00077         fileroot = project
00078         if not os.path.exists(fileroot):
00079             os.mkdir(fileroot)
00080 
00081 
00082         # filename parsing of cfg file here so that the project filenames 
00083         # can contain the cfg
00084         repodir = os.getenv("CASAPATH").split(' ')[0] + "/data/alma/simmos/"
00085 
00086         # convert "alma;0.4arcsec" to an actual configuration
00087         # can only be done after reading skymodel, so here, we just string parse
00088         if str.upper(antennalist[0:4]) == "ALMA":
00089             foo=antennalist.replace(';','_')
00090         elif len(antennalist) > 0:
00091             foo=antennalist
00092         else:
00093             msg("The name of antenna list (antennalist/sdantlist) is not specified",priority="error")
00094 
00095         if foo:
00096             foo=foo.replace(".cfg","")
00097             sfoo=foo.split('/')
00098             if len(sfoo)>1:
00099                 foo=sfoo[-1]
00100             project=project+"."+foo
00101 
00102 
00103         if not overwrite:
00104             if (predict and uvmode and os.path.exists(fileroot+"/"+project+".ms")):
00105                 msg(fileroot+"/"+project+".ms exists but overwrite=F",priority="error")
00106                 return False
00107             if (predict and (not uvmode) and os.path.exists(fileroot+"/"+project+".sd.ms")):
00108                 msg(fileroot+"/"+project+".sd.ms exists but overwrite=F",priority="error")
00109                 return False
00110 
00111 
00112         saveinputs = myf['saveinputs']
00113         saveinputs('simobserve',fileroot+"/"+project+".simobserve.last",
00114                    myparams=in_params)
00115 
00116 
00117 
00118         # some hardcoded variables that may be reintroduced in future development
00119         relmargin = .5  # number of PB between edge of model and pointing centers
00120         scanlength = 1  # number of integrations per scan
00121 
00122         if type(skymodel) == type([]):
00123             skymodel = skymodel[0]
00124         skymodel = skymodel.replace('$project',project)
00125 
00126         if type(complist) == type([]):
00127             complist = complist[0]
00128 
00129         if((not os.path.exists(skymodel)) and (not os.path.exists(complist))):
00130             msg("No sky input found.  At least one of skymodel or complist must be set.",priority="error")
00131             return False
00132 
00133 
00134         grscreen = False
00135         grfile = False
00136         if graphics == "both":
00137             grscreen = True
00138             grfile = True
00139         if graphics == "screen":
00140             grscreen = True
00141         if graphics == "file":
00142             grfile = True
00143 
00144         ##################################################################
00145         # set up skymodel image
00146 
00147         if os.path.exists(skymodel):
00148             components_only = False
00149             # create a new skymodel called skymodel, or if its already there, called newmodel
00150             default_model = project + ".skymodel"
00151             if skymodel == default_model:
00152                 newmodel = fileroot + "/" + project + ".newmodel"
00153             else:
00154                 newmodel = fileroot + "/" + default_model
00155             if os.path.exists(newmodel):
00156                 if overwrite:
00157                     shutil.rmtree(newmodel)
00158                 else:
00159                     msg(newmodel+" exists -- please delete it, change skymodel, or set overwrite=T",priority="error")
00160                     return False
00161 
00162             # modifymodel just collects info if skymodel==newmodel
00163             innchan = -1
00164             returnpars = util.modifymodel(skymodel,newmodel,
00165                                           inbright,indirection,incell,
00166                                           incenter,inwidth,innchan,
00167                                           flatimage=False)
00168             if not returnpars:
00169                 return False
00170 
00171             (model_refdir,model_cell,model_size,
00172              model_nchan,model_center,model_width,
00173              model_stokes) = returnpars
00174 
00175             modelflat = fileroot + "/" + project + ".skymodel.flat"
00176             if os.path.exists(modelflat) and (not predict):
00177                 # if we're not predicting, then we want to use the previously
00178                 # created modelflat, because it may have components added 
00179                 msg("flat sky model "+modelflat+" exists, predict not requested",priority="warn")
00180                 msg(" working from existing model image - please delete it if you wish to overwrite.",priority="warn")
00181             else:
00182                 # create and add components into modelflat with util.flatimage()
00183                 util.flatimage(newmodel,complist=complist,verbose=verbose)
00184                 # we want the skymodel.flat image to be called that no matter what 
00185                 # the skymodel image is called, since that's what used in analysis
00186                 if modelflat != newmodel+".flat":
00187                     if os.path.exists(modelflat):
00188                         shutil.rmtree(modelflat)
00189                     shutil.move(newmodel+".flat",modelflat)
00190 
00191             casalog.origin('simobserve')
00192 
00193             # set startfeq and bandwidth in util object after modifymodel
00194             bandwidth = qa.mul(qa.quantity(model_nchan),qa.quantity(model_width))
00195             util.bandwidth = bandwidth
00196 
00197         else:
00198             components_only = True
00199             # calculate model parameters from the component list:
00200 
00201             compdirs = []
00202             cl.done()
00203             cl.open(complist)
00204 
00205             for i in range(cl.length()):
00206                 compdirs.append(util.dir_m2s(cl.getrefdir(i)))
00207 
00208             model_refdir, coffs = util.average_direction(compdirs)
00209             model_center = cl.getspectrum(0)['frequency']['m0']
00210             # components don't yet support spectrum
00211             if util.isquantity(compwidth,halt=False):
00212                 model_width = compwidth
00213             else:
00214                 model_width = "2GHz"
00215                 msg("component-only simulation, compwidth unset: setting bandwidth to 2GHz",priority="warn")
00216 
00217             model_nchan = 1
00218             model_stokes = "I"
00219 
00220             cmax = 0.0014 # ~5 arcsec
00221             for i in range(coffs.shape[1]):
00222                 xc = pl.absolute(coffs[0,i])  # offsets in deg
00223                 yc = pl.absolute(coffs[1,i])
00224                 if xc > cmax:
00225                     cmax = xc
00226                 if yc > cmax:
00227                     cmax = yc
00228 
00229             model_size = ["%fdeg" % (3*cmax), "%fdeg" % (3*cmax)]
00230 
00231 
00232         # for cases either if there is a skymodel or if there are only components,
00233         # if the user has not input a map size (for setpointings), then use model_size
00234         if len(mapsize) == 0:
00235             mapsize = model_size
00236             if verbose: msg("setting map size to "+str(model_size))
00237         else:
00238              if type(mapsize) == type([]):
00239                  if len(mapsize[0]) == 0:
00240                      mapsize = model_size
00241                      if verbose: msg("setting map size to "+str(model_size))
00242 
00243         if components_only:
00244             if type(mapsize) == type([]):
00245                 map_asec = qa.convert(mapsize[0],"arcsec")['value']
00246             else:
00247                 map_asec = qa.convert(mapsize,"arcsec")['value']
00248             if type(model_size) == type([]):
00249                 mod_asec = qa.convert(model_size[0],"arcsec")['value']
00250             else:
00251                 mod_asec = qa.convert(model_size,"arcsec")['value']
00252             if map_asec>mod_asec:
00253                 model_size=["%farcsec" % map_asec,"%farcsec" % map_asec]
00254 
00255 
00256 
00257 
00258         ##################################################################
00259         # read antenna file here to get Primary Beam, and estimate maxbase and psfsize
00260         aveant = -1
00261         stnx = []  # for later, to know if we read an array in or not
00262         pb = 0. # primary beam
00263 
00264         # convert "alma;0.4arcsec" to an actual configuration
00265         if str.upper(antennalist[0:4]) == "ALMA":
00266 
00267             # test for cycle 1
00268             q = re.compile('.*CYCLE.?1.?;(.*)')
00269             qq = q.match(antennalist.upper())
00270             if qq:
00271                 z = qq.groups()
00272                 tail=z[0]
00273                 tail=tail.lower()
00274                 if util.isquantity(tail,halt=False):
00275                     resl = qa.convert(tail,"arcsec")['value']
00276                     if os.path.exists(repodir):
00277                         confnum = (1.044-6.733*pl.log10(resl*qa.convert(model_center,"GHz")['value']/345.))
00278                         confnum = max(1,min(6,confnum))
00279                         conf = str(int(round(confnum)))
00280                         antennalist = repodir + "alma_cycle1_" + conf + ".cfg"
00281                         msg("converted resolution to antennalist "+antennalist)
00282                     else:
00283                         msg("failed to find antenna configuration repository at "+repodir,priority="warn")
00284 
00285             else: # assume FS
00286                 tail = antennalist[5:]
00287                 if util.isquantity(tail,halt=False):
00288                     resl = qa.convert(tail,"arcsec")['value']
00289                     if os.path.exists(repodir):
00290                         confnum = (2.867-pl.log10(resl*1000*qa.convert(model_center,"GHz")['value']/672.))/0.0721
00291                         confnum = max(1,min(28,confnum))
00292                         conf = str(int(round(confnum)))
00293                         if len(conf) < 2: conf = '0' + conf
00294                         antennalist = repodir + "alma.out" + conf + ".cfg"
00295                         msg("converted resolution to antennalist "+antennalist)
00296                     else:
00297                         msg("failed to find antenna configuration repository at "+repodir,priority="warn")
00298 
00299 
00300         # Search order is fileroot/ -> specified path -> repository
00301         if len(antennalist) > 0:
00302             if os.path.exists(fileroot+"/"+antennalist):
00303                 antennalist = fileroot + "/" + antennalist
00304             elif not os.path.exists(antennalist) and \
00305                      os.path.exists(repodir+antennalist):
00306                 antennalist = repodir + antennalist
00307             # Now make sure the antennalist exists
00308             if not os.path.exists(antennalist):
00309                 util.msg("Couldn't find antennalist: %s" % antennalist, priority="error")
00310                 return False
00311         elif predict or components_only:
00312             # antennalist is required when predicting or components only
00313             util.msg("Must specify antennalist", priority="error")
00314 
00315         # Read antennalist
00316         if os.path.exists(antennalist):
00317             stnx, stny, stnz, stnd, padnames, nant, telescopename = util.readantenna(antennalist)
00318             if len(stnx) == 1:
00319                 if predict and uvmode:
00320                     # observe="int" but antennalist is SD
00321                     util.msg("antennalist contains only 1 antenna", priority="error")
00322                 uvmode = False
00323             antnames = []
00324             if not uvmode: #Single-dish
00325                 # KS TODO: what if not predicting but SD with multi-Ants
00326                 # in antennalist (e.g., aca.tp)? In that case, PB on plots and
00327                 # pointingspacing="??PB" will not be correct for heterogeneous list.
00328                 if sdant > nant-1 or sdant < -nant:
00329                     msg("antenna index %d is out of range. setting sdant=0"%sdant,priority="warn")
00330                     sdant = 0
00331                 stnx = [stnx[sdant]]
00332                 stny = [stny[sdant]]
00333                 stnz = [stnz[sdant]]
00334                 stnd = pl.array(stnd[sdant])
00335                 padnames = [padnames[sdant]]
00336                 nant = 1
00337 
00338             for k in xrange(0,nant): antnames.append('A%02d'%k)
00339             aveant = stnd.mean()
00340             # TODO use max ant = min PB instead?
00341             # (set back to simdata - there must be an automatic way to do this)
00342             casalog.origin('simobserve')
00343             pb = 1.2*0.29979/qa.convert(qa.quantity(model_center),'GHz')['value']/aveant*3600.*180/pl.pi # arcsec
00344 
00345             # PSF size
00346             if uvmode:
00347                 # approx max baseline, to compare with model_cell:
00348                 cx=pl.mean(stnx)
00349                 cy=pl.mean(stny)
00350                 cz=pl.mean(stnz)
00351                 lat,lon = util.itrf2loc(stnx,stny,stnz,cx,cy,cz)
00352                 maxbase=max(lat)-min(lat) # in meters
00353                 maxbase2=max(lon)-min(lon)
00354                 if maxbase2>maxbase:
00355                     maxbase=maxbase2
00356                 # estimate the psf size from the minimum spatial scale
00357                 psfsize = 0.3/qa.convert(qa.quantity(model_center),'GHz')['value']/maxbase*3600.*180/pl.pi # lambda/b converted to arcsec
00358                 del cx, cy, cz, lat, lon, maxbase, maxbase2
00359             else: # Single-dish
00360                 psfsize = pb
00361                 # check for model size
00362                 if not components_only:
00363                     minsize = min(qa.convert(model_size[0],'arcsec')['value'],\
00364                                   qa.convert(model_size[1],'arcsec')['value'])
00365                     if minsize < 2*pb:
00366                         msg("skymodel should be larger than 2*primary beam. Your skymodel: %.3f arcsec < %.3f arcsec: 2*primary beam" % (minsize, 2*pb),priority="error")
00367                     del minsize
00368         else:
00369             msg("Can't find antennalist",priority="error")
00370             return False
00371 
00372 
00373         # now we have an estimate of the psf from the antenna configuration, 
00374         # so we can guess a model_cell for the case of component-only 
00375         # simulation, 
00376         if components_only:
00377             # first set based on psfsize:
00378             # needs high subsampling because small shifts in placement of 
00379             # components lead to large changes in the difference image.
00380             model_cell = [ str(psfsize/20)+"arcsec", str(psfsize/20)+"arcsec" ]
00381             
00382             # XXX if the user has set direction should we center the compskymodel there?
00383             # if len(direction)>0: model_refdir = direction
00384 
00385         # and can create a compskymodel image (tmp) and 
00386         # skymodel.flat which is what is needed for analysis.
00387 
00388         if components_only:
00389             newmodel = fileroot + "/" + project + ".compskymodel"
00390             needmodel=True
00391 
00392             modimsize=int((qa.convert(model_size[0],"arcsec")['value'])/(qa.convert(model_cell[0],"arcsec")['value']))
00393 #            modimsize=max([modimsize,32])
00394             newepoch,newlat,newlon = util.direction_splitter(model_refdir)
00395 
00396             if os.path.exists(newmodel):
00397                 if overwrite:
00398                     shutil.rmtree(newmodel)
00399                 else:
00400                     needmodel=False
00401                     ia.open(newmodel)
00402                     oldshape=ia.shape()
00403                     if len(oldshape) != 2:
00404                         needmodel=True
00405                     else:
00406                         if oldshape[0] != modimsize or oldshape[1]==modimsize:
00407                             needmodel=True
00408                     oldcs=ia.coordsys()
00409                     ia.done()
00410                     olddir = (oldcs.referencevalue())['numeric']
00411                     if ( olddir[0] != qa.convert(newlat,oldcs.units()[0])['value'] or
00412                          olddir[1] != qa.convert(newlon,oldcs.units()[1])['value'] or
00413                          newepoch != oldcs.referencecode() ):
00414                         needmodel=True
00415                     oldcs.done()
00416                     del oldcs, olddir
00417                     if needmodel:
00418                         msg(newmodel+" exists and is inconsistent with required size="+str(modimsize)+" and direction. Please set overwrite=True",priority="error")
00419                         return False
00420 
00421             if needmodel:
00422                 csmodel = ia.newimagefromshape(newmodel,[modimsize,modimsize,1,1])
00423                 modelcsys = csmodel.coordsys()
00424                 modelshape = csmodel.shape()
00425                 cell0_rad=qa.convert(model_cell[0],'rad')['value']
00426                 cell1_rad=qa.convert(model_cell[1],'rad')['value']
00427                 modelcsys.setdirection(refpix=[modimsize/2,modimsize/2],
00428                                        refval=[qa.tos(newlat),qa.tos(newlon)],
00429                                        refcode=newepoch)
00430                 modelcsys.setincrement([-cell0_rad,cell1_rad],'direction')
00431                 modelcsys.setreferencevalue(type="spectral",value=qa.tos(model_center))
00432                 modelcsys.setrestfrequency(qa.tos(model_center))
00433                 modelcsys.setincrement(type="spectral",value=compwidth)
00434                 csmodel.setcoordsys(modelcsys.torecord())
00435                 modelcsys.done()
00436                 cl.open(complist)
00437                 csmodel.setbrightnessunit("Jy/pixel")
00438                 csmodel.modify(cl.torecord(),subtract=False)
00439                 cl.done()
00440                 csmodel.done()
00441                 # as noted, compskymodel doesn't need to exist, only skymodel.flat
00442                 # flatimage adds in components if complist!=None
00443                 #util.flatimage(newmodel,complist=complist,verbose=verbose)
00444                 util.flatimage(newmodel,verbose=verbose)
00445                 modelflat = fileroot + "/" + project + ".compskymodel.flat"
00446 #                modelflat = fileroot + "/" + project + ".skymodel.flat"
00447 #                if modelflat != newmodel+".flat":
00448 #                    if os.path.exists(modelflat):
00449 #                        shutil.rmtree(modelflat)
00450 #                    shutil.move(newmodel+".flat",modelflat)
00451 
00452 
00453         # and finally, with model_cell set either from an actual skymodel,
00454         # or from the antenna configuration in components_only case,
00455         # we can check for the user that the psf is likely to be sampled enough:
00456         cell_asec=qa.convert(model_cell[0],'arcsec')['value']
00457         if psfsize < cell_asec:
00458             msg("Sky model cell of "+str(cell_asec)+" asec is very large compared to highest resolution "+str(psfsize)+" asec - this will lead to blank or erroneous output. (Did you set incell?)",priority="error")
00459             shutil.rmtree(modelflat)
00460             return False
00461         if psfsize < 2*cell_asec:
00462             msg("Sky model cell of "+str(cell_asec)+" asec is large compared to highest resolution "+str(psfsize)+" asec. (Did you set incell?)",priority="warn")
00463 
00464         # set this for future minimum image size
00465         minimsize = 8* int(psfsize/cell_asec)
00466 
00467 
00468 
00469         ##################################################################
00470         # set up pointings
00471         dir = model_refdir
00472         dir0 = dir
00473         if type(direction) == type([]):
00474             if len(direction) > 0:
00475                 if util.isdirection(direction[0],halt=False):
00476                     dir = direction
00477                     dir0 = direction[0]
00478         else:
00479             if util.isdirection(direction,halt=False):
00480                 dir = direction
00481                 dir0 = dir
00482         util.direction = dir0
00483 
00484         # if the integration time is a real time quantity
00485         # test for weird units
00486         if not util.isquantity(integration):
00487             msg("integration time "+integration+" does not appear to represent a time interval (use 's','min'; not 'sec','m')",priority="error")
00488             return False
00489 
00490         if qa.quantity(integration)['unit'] != '':
00491             if not qa.compare(integration,"1s"):
00492                 msg("integration time "+integration+" does not appear to represent a time interval ('s','min'; not 'sec','m')",priority="error")
00493                 return False
00494             intsec = qa.convert(qa.quantity(integration),"s")['value']
00495         else:
00496             if len(integration)>0:
00497                 intsec = float(integration)
00498                 msg("interpreting integration time parameter as "+str(intsec)+"s",priority="warn")
00499             else:
00500                 intsec = 0
00501         integration="%fs" %intsec
00502 
00503 
00504         if setpointings:
00505             if verbose: util.msg("calculating map pointings centered at "+str(dir0))
00506 
00507             if len(pointingspacing) < 1:
00508                 pointingspacing = "Nyquist"
00509             if str.upper(pointingspacing)=="NYQUIST":
00510                 pointingspacing="0.48113PB"
00511             q = re.compile('(\d+.?\d+)\s*PB')
00512             qq = q.match(pointingspacing.upper())
00513             if qq:
00514                 z = qq.groups()
00515                 if pb <= 0:
00516                     util.msg("Can't calculate pointingspacing in terms of primary beam because antennalist is not specified",priority="error")
00517                     return False
00518                 pointingspacing = "%farcsec" % (float(z[0])*pb)
00519                 # todo make more robust to nonconforming z[0] strings
00520             if verbose:
00521                 msg("pointing spacing in mosaic = "+pointingspacing)
00522             pointings = util.calc_pointings2(pointingspacing,mapsize,maptype=maptype, direction=dir, beam=pb)
00523             nfld=len(pointings)
00524             etime = qa.convert(qa.mul(qa.quantity(integration),scanlength),"s")['value']
00525             # etime is an array of scan lengths - here they're all the same.
00526             etime = etime + pl.zeros(nfld)
00527             # totaltime might not allow all fields to be observed, or it might
00528             # repeat
00529             ptgfile = fileroot + "/" + project + ".ptg.txt"
00530         else:
00531             if type(ptgfile) == type([]):
00532                 ptgfile = ptgfile[0]
00533             ptgfile = ptgfile.replace('$project',project)
00534             # precedence to ptg file outside the project dir
00535             if os.path.exists(ptgfile):
00536                 shutil.copyfile(ptgfile,fileroot+"/"+project + ".ptg.txt")
00537                 ptgfile = fileroot + "/" + project + ".ptg.txt"
00538             else:
00539                 if os.path.exists(fileroot+"/"+ptgfile):
00540                     ptgfile = fileroot + "/" + ptgfile
00541                 else:
00542                     util.msg("Can't find pointing file "+ptgfile,priority="error")
00543                     return False
00544 
00545             nfld, pointings, etime = util.read_pointings(ptgfile)
00546             if max(etime) <= 0:
00547                 # integration is a string in input params
00548                 etime = intsec
00549                 # make etime into an array
00550                 etime = etime + pl.zeros(nfld)
00551             # etimes determine stop/start i.e. the scan
00552             # if a longer etime is in the file, it'll do multiple integrations
00553             # per scan
00554             # expects that the cal is separate, and this is just one round of the mosaic
00555             # furthermore, the cal will use _integration_ from the inputs, and that
00556             # needs to be less than the min etime:
00557             if min(etime) < intsec:
00558                 integration = str(min(etime))+"s"
00559                 msg("Setting integration to "+integration+" to match the shortest time in the pointing file.",priority="warn")
00560                 intsec = min(etime)
00561 
00562 
00563         # find imcenter - phase center
00564         imcenter , offsets = util.median_direction(pointings)     
00565         epoch, ra, dec = util.direction_splitter(imcenter)
00566 
00567         # model is centered at model_refdir, and has model_size;
00568         mepoch, mra, mdec = util.direction_splitter(model_refdir)
00569         # ra/mra should be in degrees, but just in case
00570         ra=qa.convert(ra,'deg')
00571         mra=qa.convert(mra,'deg')
00572         dec=qa.convert(dec,'deg')
00573         mdec=qa.convert(mdec,'deg')
00574 
00575         # observation near ra=0:
00576         if abs(mra['value'])<10 or abs(mra['value']-360.)<10 or abs(ra['value'])<10 or abs(mra['value']-360.)<10:
00577             nearzero=True
00578         else:
00579             nearzero=False
00580 
00581         # fix wraps
00582         if nearzero: # put break at 180
00583            if ra['value'] >= 180.:
00584                ra['value'] = ra['value'] - 360.
00585            if mra['value'] >= 180.:
00586                mra['value'] = mra['value'] - 360.
00587         else:
00588            if ra['value'] >= 360.:
00589                ra['value'] = ra['value'] - 360.
00590            if mra['value'] >= 360.:
00591                mra['value'] = mra['value'] - 360.
00592 
00593         # shift is the offset from the model to imcenter
00594         shift = [ (qa.convert(ra,'deg')['value'] -
00595                    qa.convert(mra,'deg')['value'])*pl.cos(qa.convert(dec,'rad')['value'] ),
00596                   (qa.convert(dec,'deg')['value'] - qa.convert(mdec,'deg')['value']) ]
00597         if verbose: 
00598             msg("pointings are shifted relative to the model by %g,%g arcsec" % (shift[0]*3600,shift[1]*3600))
00599 
00600         xmax = qa.convert(model_size[0],'deg')['value']*0.5
00601         ymax = qa.convert(model_size[1],'deg')['value']*0.5
00602         overlap = False
00603         # wrapang in median_direction should make offsets always small, not >360
00604         for i in xrange(offsets.shape[1]):
00605             xc = pl.absolute(offsets[0,i]+shift[0])  # offsets and shift are in degrees
00606             yc = pl.absolute(offsets[1,i]+shift[1])
00607             if xc < xmax and yc < ymax:
00608                 overlap = True
00609                 break
00610 
00611         if setpointings:
00612             if os.path.exists(ptgfile):
00613                 if overwrite:
00614                     os.remove(ptgfile)
00615                 else:
00616                     util.msg("pointing file "+ptgfile+" already exists and user does not want to overwrite",priority="error")
00617                     return False
00618             util.write_pointings(ptgfile,pointings,etime.tolist())
00619 
00620         msg("center = "+imcenter)
00621         if nfld > 1 and verbose:
00622             for idir in range(min(len(pointings),20)):
00623                 msg("   "+pointings[idir])
00624             if nfld >= 20:
00625                 msg("   (printing only first 20 - see pointing file for full list)")
00626 
00627         if not overlap:
00628             msg("No overlap between model and pointings",priority="error")
00629             return False
00630 
00631 
00632 
00633         ##################################################################
00634         # calibrator is not explicitly contained in the pointing file
00635         # but interleaved with etime=intergration
00636         util.isquantity(calflux)
00637         calfluxjy = qa.convert(calflux,'Jy')['value']
00638         # XML returns a list even for a string:
00639         if type(caldirection) == type([]): caldirection = caldirection[0]
00640         if len(caldirection) < 4: caldirection = ""
00641         if calfluxjy > 0 and caldirection != "" and uvmode:
00642             docalibrator = True
00643             if os.path.exists(fileroot+"/"+project+'.cal.cclist'):
00644                 shutil.rmtree(fileroot+"/"+project+'.cal.cclist')
00645             util.isdirection(caldirection)
00646             cl.done()
00647             cl.addcomponent(flux=calfluxjy,dir=caldirection,label="phase calibrator")
00648             # set reference freq to center freq of model
00649             cl.rename(fileroot+"/"+project+'.cal.cclist')
00650             cl.done()
00651         else:
00652             docalibrator = False
00653 
00654 
00655 
00656 
00657 
00658         ##################################################################
00659         # create one figure for model and pointings - need antenna diam 
00660         # to determine primary beam
00661         if grfile:
00662             file = fileroot + "/" + project + ".skymodel.png"
00663         else:
00664             file = ""
00665     
00666         if grscreen or grfile:
00667             util.newfig(show=grscreen)
00668 
00669 # remove after we fix the scaling algorithm for the images
00670             if components_only:
00671                 pl.plot()
00672                 # TODO add symbols at locations of components
00673                 pl.plot(coffs[0,]*3600,coffs[1,]*3600,'o',c="#dddd66")
00674                 pl.axis("equal")
00675             else:
00676                 discard = util.statim(modelflat,plot=True,incell=model_cell)
00677             
00678             lims = pl.xlim(),pl.ylim()
00679             if pb <= 0 and verbose:
00680                 msg("unknown primary beam size for plot",priority="warn")
00681             if max(max(lims)) > pb and not components_only:
00682                 plotcolor = 'w'
00683             else:
00684                 plotcolor = 'k'
00685 
00686             #if offsets.shape[1] > 16 or pb <= 0 or pb > pl.absolute(max(max(lims))):
00687             if offsets.shape[1] > 19 or pb <= 0:
00688                 lims = pl.xlim(),pl.ylim()
00689                 pl.plot((offsets[0]+shift[0])*3600.,(offsets[1]+shift[1])*3600.,
00690                         plotcolor+'+',markeredgewidth=1)
00691                 #if pb > 0 and pl.absolute(lims[0][0]) > pb:
00692                 if pb > 0:
00693                     plotpb(pb,pl.gca(),lims=lims,color=plotcolor)
00694             else:
00695                 from matplotlib.patches import Circle
00696                 for i in xrange(offsets.shape[1]):
00697                     pl.gca().add_artist(Circle(
00698                         ((offsets[0,i]+shift[0])*3600,
00699                          (offsets[1,i]+shift[1])*3600),
00700                         radius=pb/2.,edgecolor=plotcolor,fill=False,
00701                         label='beam',transform=pl.gca().transData,clip_on=True))
00702 
00703             xlim = max(abs(pl.array(lims[0])))
00704             ylim = max(abs(pl.array(lims[1])))
00705             # show entire pb: (statim doesn't by default)
00706             pl.xlim([max([xlim,pb/2]),min([-xlim,-pb/2])])
00707             pl.ylim([min([-ylim,-pb/2]),max([ylim,pb/2])])         
00708             pl.xlabel("resized model sky",fontsize="x-small")
00709             util.endfig(show=grscreen,filename=file)
00710 
00711 
00712 
00713 
00714 
00715 
00716 
00717 
00718         ##################################################################
00719         # set up observatory, feeds, etc
00720         quickpsf_current = False
00721 
00722         if uvmode:
00723             msfile = fileroot + "/" + project + '.ms'
00724         else:
00725             msfile = fileroot + "/" + project + '.sd.ms'
00726 
00727         if predict:
00728             # TODO check for frequency overlap here - if zero stop
00729             # position overlap already checked above in pointing section
00730 
00731             message = "preparing empty measurement set"
00732             if verbose:
00733                 msg(message,origin="simobserve",priority="warn")
00734             else:
00735                 msg(message,origin="simobserve")
00736 
00737             nbands = 1;
00738             fband  = util.bandname(qa.convert(model_center, 'GHz')['value'])
00739 
00740             ############################################
00741             # predict observation
00742 
00743             # if someone has the old style refdate with the included, discard
00744             q = re.compile('(\d*/\d+/\d+)([/:\d]*)')
00745             qq = q.match(refdate)
00746             if not qq:
00747                 msg("Invalid reference date "+refdate,priority="error")
00748                 return False
00749             else:
00750                 z = qq.groups()
00751                 refdate=z[0]
00752                 if len(z)>1:
00753                     msg("Discarding time part of refdate, "+z[1]+", in favor of hourangle parameter = "+hourangle)
00754 
00755             if hourangle=="transit":
00756                 haoffset=0.0
00757             else:
00758                 haoffset=qa.convert(qa.quantity(hourangle),'s')['value']
00759 
00760             refdate=refdate+"/00:00:00"
00761             usehourangle=True
00762 
00763 
00764             intsec = qa.convert(qa.quantity(integration),"s")['value']
00765 
00766             # totaltime as an integer for # times through the mosaic:
00767             if not util.isquantity(totaltime):
00768                 msg("total time "+totaltime+" does not appear to represent a time interval (use 's','min','h'; not 'sec','m','hr')",priority="error")
00769                 return False
00770 
00771             if qa.quantity(totaltime)['value'] < 0.:
00772                 # casapy crashes for negative totaltime
00773                 msg("Negative totaltime is not allowed.",priority="error")
00774                 return False
00775             if qa.quantity(totaltime)['unit'] == '':
00776                 # assume it means number of maps, or # repetitions.
00777                 totalsec = sum(etime)
00778                 if docalibrator:
00779                     totalsec = totalsec + intsec # cal gets one int-time
00780                 totalsec = float(totaltime) * totalsec
00781                 msg("Total observing time = "+str(totalsec)+"s.",priority="warn")
00782             else:
00783                 if not qa.compare(totaltime,"1s"):
00784                     msg("total time "+totaltime+" does not appear to represent a time interval (use 's','min','h'; not 'sec','m','hr')",priority="error")
00785                     return False
00786                 totalsec = qa.convert(qa.quantity(totaltime),'s')['value']
00787 
00788             if os.path.exists(msfile) and not overwrite: #redundant check?
00789                 util.msg("measurement set "+msfile+" already exists and user does not wish to overwrite",priority="error")
00790                 return False
00791             sm.open(msfile)
00792             posobs = me.observatory(telescopename)
00793             diam = stnd;
00794             # WARNING: sm.setspwindow is not consistent with clean::center
00795             #model_start=qa.sub(model_center,qa.mul(model_width,0.5*model_nchan))
00796             # but the "start" is the center of the first channel:
00797             model_start = qa.sub(model_center,qa.mul(model_width,0.5*(model_nchan-1)))
00798 
00799             mounttype = 'alt-az'
00800             if telescopename in ['DRAO', 'WSRT']:
00801                 mounttype = 'EQUATORIAL'
00802             # Should ASKAP be BIZARRE or something else?  It may be effectively equatorial.
00803 
00804             sm.setconfig(telescopename=telescopename, x=stnx, y=stny, z=stnz,
00805                          dishdiameter=diam.tolist(),
00806                          mount=[mounttype], antname=antnames, padname=padnames, 
00807                          coordsystem='global', referencelocation=posobs)
00808             if str.upper(telescopename).find('VLA') > 0:
00809                 sm.setspwindow(spwname=fband, freq=qa.tos(model_start),
00810                                deltafreq=qa.tos(model_width),
00811                                freqresolution=qa.tos(model_width),
00812                                nchannels=model_nchan, refcode="LSRK",
00813                                stokes='RR LL')
00814                 sm.setfeed(mode='perfect R L',pol=[''])
00815             else:
00816                 sm.setspwindow(spwname=fband, freq=qa.tos(model_start),
00817                                deltafreq=qa.tos(model_width),
00818                                freqresolution=qa.tos(model_width), 
00819                                nchannels=model_nchan, refcode="LSRK",
00820                                stokes='XX YY')
00821                 sm.setfeed(mode='perfect X Y',pol=[''])
00822 
00823             if verbose: msg(" spectral window set at %s" % qa.tos(model_center))
00824             sm.setlimits(shadowlimit=0.01, elevationlimit='10deg')
00825             if uvmode:
00826                 sm.setauto(0.0)
00827             else: #Single-dish
00828                 # auto-correlation should be unity for single dish obs.
00829                 sm.setauto(1.0)
00830 
00831             for k in xrange(0,nfld):
00832                 src = project + '_%d' % k
00833                 sm.setfield(sourcename=src, sourcedirection=pointings[k],
00834                             calcode="OBJ", distance='0m')
00835                 if k == 0:
00836                     sourcefieldlist = src
00837                 else:
00838                     sourcefieldlist = sourcefieldlist + ',' + src
00839             if docalibrator:
00840                 sm.setfield(sourcename="phase calibrator", 
00841                             sourcedirection=caldirection,calcode='C',
00842                             distance='0m')
00843 
00844             mereftime = me.epoch('TAI', refdate)
00845             # integration is a scalar quantity, etime is a vector of seconds
00846             sm.settimes(integrationtime=integration, usehourangle=usehourangle, 
00847                         referencetime=mereftime)
00848 
00849             # time required to observe all planned scanes in etime array:
00850             totalscansec = sum(etime)
00851             kfld = 0
00852 
00853             if totalsec < totalscansec:
00854                 msg("Not all pointings in the mosaic will be observed - check mosaic setup and exposure time parameters!",priority="warn")
00855                 ###
00856                 #print "you need at least %16.12e sec but you have %16.12e sec (%f < %f = %s)" % (totalscansec, totalsec, totalsec, totalscansec, str(totalsec<totalscansec))
00857                 ###
00858 
00859             # sm.observemany
00860             srces = []
00861             starttimes = []
00862             stoptimes = []
00863             dirs = []
00864 
00865             if usehourangle:
00866                 sttime = -totalsec/2.0
00867             else:
00868                 sttime = 0. # leave start at the reftime
00869             sttime=sttime+haoffset
00870             scanstart=sttime
00871 
00872             # can before sources
00873             if docalibrator:
00874                 endtime = sttime + qa.convert(integration,'s')['value']
00875                 sm.observe(sourcename="phase calibrator", spwname=fband,
00876                            starttime=qa.quantity(sttime, "s"),
00877                            stoptime=qa.quantity(endtime, "s"),
00878                            state_obs_mode="CALIBRATE_PHASE.ON_SOURCE",state_sig=True,
00879                            project=project);
00880                 sttime = endtime
00881 
00882             while (sttime-scanstart) < totalsec: # the last scan could exceed totaltime
00883                 endtime = sttime + etime[kfld]
00884                 src = project + '_%d' % kfld
00885                 srces.append(src)
00886                 starttimes.append(str(sttime)+"s")
00887                 stoptimes.append(str(endtime)+"s")
00888                 dirs.append(pointings[kfld])
00889                 kfld = kfld + 1
00890                 # advance start time - XX someday slew goes here
00891                 sttime = endtime
00892 
00893                 if kfld == nfld:
00894                     if docalibrator:
00895                         endtime = sttime + qa.convert(integration,'s')['value'] 
00896 
00897                         # need to observe cal singly to get new row in obs table, so 
00898                         # first observemany the on-source pointing(s)
00899                         sm.observemany(sourcenames=srces,spwname=fband,starttimes=starttimes,stoptimes=stoptimes,project=project)
00900                         # and clear the list
00901                         srces = []
00902                         starttimes = []
00903                         stoptimes = []
00904                         dirs = []
00905                         sm.observe(sourcename="phase calibrator", spwname=fband,
00906                                    starttime=qa.quantity(sttime, "s"),
00907                                    stoptime=qa.quantity(endtime, "s"),
00908                                    state_obs_mode="CALIBRATE_PHASE.ON_SOURCE",state_sig=True,
00909                                    project=project);
00910                     kfld = kfld + 1
00911                     sttime = endtime
00912 #                 if kfld > nfld: kfld = 0
00913                 if kfld > nfld-1: kfld = 0
00914             # if directions is unset, NewMSSimulator::observemany
00915 
00916             # looks up the direction in the field table.
00917             if not docalibrator:
00918                 sm.observemany(sourcenames=srces,spwname=fband,starttimes=starttimes,stoptimes=stoptimes,project=project)
00919 
00920             sm.setdata(fieldid=range(0,nfld))
00921             sm.setvp()
00922 
00923             msg("done setting up observations (blank visibilities)")
00924             if verbose: sm.summary()
00925 
00926             # do actual calculation of visibilities:
00927 
00928             if not uvmode: #Single-dish
00929                 sm.setoptions(gridfunction='pb', ftmachine="sd", location=posobs)
00930 
00931             if not components_only:
00932                 if docalibrator:
00933                     if len(complist) <=0:
00934                         complist=fileroot+"/"+project+'.cal.cclist'
00935                     else:
00936                         # XXX will 2 cl work?
00937                         complist=complist+","+fileroot+"/"+project+'.cal.cclist'
00938 
00939                 if len(complist) > 1:
00940                     message = "predicting from "+newmodel+" and "+complist
00941                     if verbose:
00942                         msg(message,priority="warn",origin="simobserve")
00943                     else:
00944                         msg(message,origin="simobserve")
00945                 else:
00946                     message = "predicting from "+newmodel
00947                     if verbose:
00948                         msg(message,priority="warn",origin="simobserve")
00949                     else:
00950                         msg(message,origin="simobserve")
00951                 sm.predict(imagename=newmodel,complist=complist)
00952             else:   # if we're doing only components
00953                 # XXX will 2 cl work?
00954                 if docalibrator:
00955                     complist=complist+","+fileroot+"/"+project+'.cal.cclist'
00956                 if verbose:
00957                     msg("predicting from "+complist,priority="warn",origin="simobserve")
00958                 else:
00959                     msg("predicting from "+complist,origin="simobserve")
00960                 sm.predict(complist=complist)
00961 
00962             sm.done()
00963             msg('generation of measurement set '+msfile+' complete',origin="simobserve")
00964 
00965 
00966             ############################################
00967             # create figure 
00968             if grfile:
00969                 file = fileroot + "/" + project + ".observe.png"
00970             else:
00971                 file = ""
00972 
00973             # update psfsize using uv coverage instead of maxbase above
00974             if os.path.exists(msfile):
00975                 # psfsize was set from the antenna posns before, but uv is better
00976                 tb.open(msfile)
00977                 rawdata = tb.getcol("UVW")
00978                 tb.done()
00979                 maxbase = max([max(rawdata[0,]),max(rawdata[1,])])  # in m
00980                 if maxbase > 0.:
00981                     psfsize = 0.3/qa.convert(qa.quantity(model_center),'GHz')['value']/maxbase*3600.*180/pl.pi # lambda/b converted to arcsec
00982                     if not uvmode:
00983                         msg("An single observation is requested but CROSS-correlation in "+msfile,priority="error")
00984                 else: #Single-dish (zero-spacing)
00985                     psfsize = pb
00986                     if uvmode:
00987                         msg("An interferometer observation is requested but only AUTO-correlation in "+msfile,priority="error")
00988                 minimsize = 8* int(psfsize/cell_asec)
00989             else:
00990                 msg("Couldn't find "+msfile,priority="error")
00991 
00992             if uvmode:
00993                 multi = [2,2,1]
00994             else:
00995                 multi = 0
00996 
00997 
00998             if (grscreen or grfile):
00999                 util.newfig(multi=multi,show=grscreen)
01000                 util.ephemeris(refdate,direction=util.direction,telescope=telescopename,ms=msfile,usehourangle=usehourangle)
01001                 casalog.origin('simobserve')
01002                 if uvmode:
01003                     util.nextfig()
01004                     util.plotants(stnx, stny, stnz, stnd, padnames)
01005 
01006                     # uv coverage
01007                     util.nextfig()
01008                     klam_m = 300/qa.convert(model_center,'GHz')['value']
01009                     pl.box()
01010                     pl.plot(rawdata[0,]/klam_m,rawdata[1,]/klam_m,'b,')
01011                     pl.plot(-rawdata[0,]/klam_m,-rawdata[1,]/klam_m,'b,')
01012                     ax = pl.gca()
01013                     ax.yaxis.LABELPAD = -4
01014                     pl.xlabel('u[klambda]',fontsize='x-small')
01015                     pl.ylabel('v[klambda]',fontsize='x-small')
01016                     pl.axis('equal')
01017 
01018                     # show dirty beam from observed uv coverage
01019                     util.nextfig()
01020                     im.open(msfile)
01021                     # TODO spectral parms
01022                     msg("using default model cell "+qa.tos(model_cell[0])+" for PSF calculation",priority="warn")
01023                     im.defineimage(cellx=qa.tos(model_cell[0]),nx=int(max([minimsize,128])))
01024                     if os.path.exists(fileroot+"/"+project+".quick.psf"):
01025                         shutil.rmtree(fileroot+"/"+project+".quick.psf")
01026                     im.approximatepsf(psf=fileroot+"/"+project+".quick.psf")
01027                     quickpsf_current = True
01028                     beam = im.fitpsf(psf=fileroot+"/"+project+".quick.psf")
01029                     im.done()
01030                     ia.open(fileroot+"/"+project+".quick.psf")
01031                     beamcs = ia.coordsys()
01032                     beam_array = ia.getchunk(axes=[beamcs.findcoordinate("spectral")[1][0],beamcs.findcoordinate("stokes")[1][0]],dropdeg=True)
01033                     nn = beam_array.shape
01034                     xextent = nn[0]*cell_asec*0.5
01035                     xextent = [xextent,-xextent]
01036                     yextent = nn[1]*cell_asec*0.5
01037                     yextent = [-yextent,yextent]
01038                     flipped_array = beam_array.transpose()
01039                     ttrans_array = flipped_array.tolist()
01040                     ttrans_array.reverse()
01041                     pl.imshow(ttrans_array,interpolation='bilinear',cmap=pl.cm.jet,extent=xextent+yextent,origin="bottom")
01042                     pl.title(project+".quick.psf",fontsize="x-small")
01043                     b = qa.convert(beam[1],'arcsec')['value']
01044                     pl.xlim([-3*b,3*b])
01045                     pl.ylim([-3*b,3*b])
01046                     ax = pl.gca()
01047                     pl.text(0.05,0.95,"bmaj=%7.1e\nbmin=%7.1e" % (beam[1]['value'],beam[2]['value']),transform = ax.transAxes,bbox=dict(facecolor='white', alpha=0.7),size="x-small",verticalalignment="top")
01048                     ia.done()
01049                 util.endfig(show=grscreen,filename=file)
01050 
01051             elif thermalnoise != "" or leakage > 0:
01052                 # Not predicting this time but corrupting. Get obsmode from ms.
01053                 if not os.path.exists(msfile):
01054                     msg("Couldn't find "+msfile,priority="error")
01055                 uvmode = (not util.ismstp(msfile,halt=False))
01056 
01057 
01058         ######################################################################
01059         # noisify
01060 
01061         noise_any = False
01062         msroot = fileroot + "/" + project  # if leakage, can just copy from this project
01063 
01064         if thermalnoise != "":
01065             knowntelescopes = ["ALMA", "ACA", "SMA", "EVLA", "VLA"]
01066 
01067             noise_any = True
01068 
01069             noisymsroot = msroot + ".noisy"
01070             if not uvmode: #Single-dish
01071                 msroot += ".sd"
01072                 noisymsroot += ".sd"
01073  
01074             # Cosmic background radiation temperature in K.
01075             t_cmb = 2.725
01076 
01077 
01078             # check for interferometric ms:
01079             if not os.path.exists(msroot+".ms"):
01080                 msg("Couldn't find "+msroot+".ms",priority="error")
01081 
01082             # MS exists
01083             message = 'copying '+msroot+'.ms to ' + \
01084                       noisymsroot+'.ms and adding thermal noise'
01085             if verbose:
01086                 msg(message,origin="noise",priority="warn")
01087             else:
01088                 msg(message,origin="noise")
01089 
01090             if os.path.exists(noisymsroot+".ms"):
01091                 shutil.rmtree(noisymsroot+".ms")
01092             shutil.copytree(msfile,noisymsroot+".ms")
01093             if sm.name() != '':
01094                 msg("table persistence error on %s" % sm.name(),priority="error")
01095                 return False
01096 
01097             # if not predicted this time, get telescopename from ms
01098             if not predict:
01099                 tb.open(noisymsroot+".ms/OBSERVATION")
01100                 n = tb.getcol("TELESCOPE_NAME")
01101                 telescopename = n[0]
01102                 # todo add check that entire column is the same
01103                 tb.done()
01104                 msg("telescopename read from "+noisymsroot+".ms: "+telescopename)
01105 
01106             if telescopename not in knowntelescopes:
01107                 msg("thermal noise only works properly for ALMA/ACA or EVLA",origin="noise",priority="warn")
01108             eta_p, eta_s, eta_b, eta_t, eta_q, t_rx = util.noisetemp(telescope=telescopename,freq=model_center)
01109 
01110             # antenna efficiency
01111             eta_a = eta_p * eta_s * eta_b * eta_t
01112             if verbose: 
01113                 msg('antenna efficiency    = '+str(eta_a), origin="noise")
01114                 msg('spillover efficiency  = '+str(eta_s), origin="noise")
01115                 msg('correlator efficiency = '+str(eta_q), origin="noise")
01116             # sensitivity constant
01117             scoeff = -1  #Force setting the default value, 1./sqrt(2.0)
01118             if not uvmode: #Single-dish
01119                 scoeff = 1.0
01120                 if verbose: msg('sensitivity constant = '+str(scoeff), origin="noise")
01121 
01122             sm.openfromms(noisymsroot+".ms")    # an existing MS
01123             sm.setdata(fieldid=[]) # force to get all fields
01124             sm.setseed(seed)
01125             if thermalnoise == "tsys-manual":
01126                 if verbose:
01127                     message = "sm.setnoise(spillefficiency="+str(eta_s)+\
01128                               ",correfficiency="+str(eta_q)+\
01129                               ",antefficiency="+str(eta_a)+\
01130                               ",trx="+str(t_rx)+",tau="+str(tau0)+\
01131                               ",tatmos="+str(t_sky)+",tground="+str(t_ground)+\
01132                               ",tcmb="+str(t_cmb)
01133                     if not uvmode: message += ",senscoeff="+str(scoeff)
01134                     message += ",mode='tsys-manual')"
01135                     msg(message);
01136                     msg("** this may be slow if your MS is finely sampled in time ** ",priority="warn")
01137                 sm.setnoise(spillefficiency=eta_s,correfficiency=eta_q,
01138                             antefficiency=eta_a,trx=t_rx,
01139                             tau=tau0,tatmos=t_sky,tground=t_ground,tcmb=t_cmb,
01140                             mode="tsys-manual",senscoeff=scoeff)
01141             else:
01142                 if verbose:
01143                     message = "sm.setnoise(spillefficiency="+str(eta_s)+\
01144                               ",correfficiency="+str(eta_q)+\
01145                               ",antefficiency="+str(eta_a)+\
01146                               ",trx="+str(t_rx)+",tground="+str(t_ground)+\
01147                               ",tcmb="+str(t_cmb)
01148                     if not uvmode: message += ",senscoeff="+str(scoeff)
01149                     message += ",mode='tsys-atm'"+\
01150                                ",pground='560mbar',altitude='5000m'"+\
01151                                ",waterheight='2km',relhum=20,pwv="+str(user_pwv)+"mm)"
01152                     msg(message);
01153                     msg("** this may be slow if your MS is finely sampled in time ** ",priority="warn")
01154                 sm.setnoise(spillefficiency=eta_s,correfficiency=eta_q,
01155                             antefficiency=eta_a,trx=t_rx,
01156                             tground=t_ground,tcmb=t_cmb,pwv=str(user_pwv)+"mm",
01157                             mode="tsys-atm",table=noisymsroot,senscoeff=scoeff)
01158                 # don't set table, that way it won't save to disk
01159                 #                        mode="calculate",table=noisymsroot)
01160 
01161             sm.corrupt();
01162             sm.done();
01163 
01164 
01165             msroot = noisymsroot
01166             if verbose: msg("done corrupting with thermal noise",origin="noise")
01167 
01168 
01169         if leakage > 0:
01170             noise_any = True
01171             # TODO: need to handle SD name when leakage is available
01172             if msroot == fileroot+"/"+project:
01173                 noisymsroot = fileroot + "/" + project + ".noisy"
01174             else:
01175                 noisymsroot = fileroot + "/" + project + ".noisier"
01176             if not uvmode: #Single-dish
01177                 msg("Can't corrupt SD data with polarization leakage",priority="warn")
01178             if os.path.exists(msfile):
01179                 msg('copying '+msfile+' to ' + 
01180                     noisymsroot+'.ms and adding polarization leakage',
01181                     origin="noise",priority="warn")
01182                 if os.path.exists(noisymsroot+".ms"):
01183                     shutil.rmtree(noisymsroot+".ms")
01184                 shutil.copytree(msfile,noisymsroot+".ms")
01185                 if sm.name() != '':
01186                     msg("table persistence error on %s" % sm.name(),priority="error")
01187                     return False
01188 
01189                 sm.openfromms(noisymsroot+".ms")    # an existing MS
01190                 sm.setdata(fieldid=[]) # force to get all fields
01191                 sm.setleakage(amplitude=leakage,table=noisymsroot+".cal")
01192                 sm.corrupt();
01193                 sm.done();
01194 
01195 
01196 
01197         # cleanup - delete newmodel, newmodel.flat etc
01198 #        if os.path.exists(modelflat):
01199 #            shutil.rmtree(modelflat)
01200         if os.path.exists(modelflat+".regrid"):
01201             shutil.rmtree(modelflat+".regrid")
01202         if os.path.exists(fileroot+"/"+project+".noisy.T.cal"):
01203             shutil.rmtree(fileroot+"/"+project+".noisy.T.cal")
01204         if os.path.exists(fileroot+"/"+project+".noisy.sd.T.cal"):
01205             shutil.rmtree(fileroot+"/"+project+".noisy.sd.T.cal")
01206 
01207     except TypeError, e:
01208         finalize_tools()
01209         #msg("simobserve -- TypeError: %s" % e, priority="error")
01210         casalog.post("simobserve -- TypeError: %s" % e, priority="ERROR")
01211         raise TypeError, e
01212         return False
01213     except ValueError, e:
01214         finalize_tools()
01215         #print "task_simobserve -- OptionError: ", e
01216         #msg("simobserve -- OptionError: %s" % e, priority="error")
01217         casalog.post("simobserve -- OptionError: %s" % e, priority="ERROR")
01218         raise ValueError, e
01219         return False
01220     except Exception, instance:
01221         finalize_tools()
01222         #print '***Error***',instance
01223         #msg("simobserve -- Exception: %s" % instance, priority="error")
01224         casalog.post("simobserve -- Exception: %s" % instance, priority="ERROR")
01225         raise Exception, instance
01226         return False
01227     return True
01228 
01229 ##### Helper functions to plot primary beam
01230 def plotpb(pb,axes,lims=None,color='k'):
01231     # This beam is automatically scaled when you zoom in/out but
01232     # not anchored in plot area. We'll wait for Matplotlib 0.99
01233     # for that function.
01234     #major=major
01235     #minor=minor
01236     #rangle=rangle
01237     #bwidth=max(major*pl.cos(rangle),minor*pl.sin(rangle))*1.1
01238     #bheight=max(major*pl.sin(rangle),minor*pl.cos(rangle))*1.1
01239     from matplotlib.patches import Rectangle, Circle #,Ellipse
01240     try:
01241         from matplotlib.offsetbox import AnchoredOffsetbox, AuxTransformBox
01242         box = AuxTransformBox(axes.transData)
01243         box.set_alpha(0.7)
01244         circ = Circle((pb,pb),radius=pb/2.,color=color,fill=False,\
01245                       label='primary beam',linewidth=2.0)
01246         box.add_artist(circ)
01247         pblegend = AnchoredOffsetbox(loc=3,pad=0.2,borderpad=0.,\
01248                                      child=box,prop=None,frameon=False)#,frameon=True)
01249         pblegend.set_alpha(0.7)
01250         axes.add_artist(pblegend)
01251     except:
01252         print "Using old matplotlib substituting with circle"
01253         # work around for old matplotlib
01254         boxsize = pb*1.1
01255         if not lims: lims = axes.get_xlim(),axes.get_ylim()
01256         incx = 1
01257         incy = 1
01258         if axes.xaxis_inverted(): incx = -1
01259         if axes.yaxis_inverted(): incy = -1
01260         #ecx = lims[0][0] + bwidth/2.*incx
01261         #ecy = lims[1][0] + bheight/2.*incy
01262         ccx = lims[0][0] + boxsize/2.*incx
01263         ccy = lims[1][0] + boxsize/2.*incy
01264     
01265         #box = Rectangle((lims[0][0],lims[1][0]),incx*bwidth,incy*bheight,
01266         box = Rectangle((lims[0][0],lims[1][0]),incx*boxsize,incy*boxsize,
01267                         alpha=0.7,facecolor='w',
01268                         transform=axes.transData) #Axes
01269         #beam = Ellipse((ecx,ecy),major,minor,angle=rangle,
01270         beam = Circle((ccx,ccy), radius=pb/2.,
01271                       edgecolor='k',fill=False,
01272                       label='beam',transform=axes.transData)
01273         #props = {'pad': 3, 'edgecolor': 'k', 'linewidth':2, 'facecolor': 'w', 'alpha': 0.5}
01274         #pl.matplotlib.patches.bbox_artist(beam,axes.figure.canvas.get_renderer(),props=props)
01275         axes.add_artist(box)
01276         axes.add_artist(beam)
01277 
01278 def finalize_tools():
01279     if ia.isopen(): ia.close()
01280     sm.close()
01281     #cl.close()   # crashes casa