def EVLAPolnCleanup(uv, Sources, err, \ logfile = "",check=False, debug = False): """ Zap uv data and any calibration images in AIPS Returns 0 on success otherwise failure * uv = UV data with calibration and editing * Sources = List of Source Models as created by EVLACal.EVLACalModel * err = Obit error/message stack * logfile = Log file for task * check = Only check script * debug = Run tasks debug, show input """ ################################################################ mess = "Cleanup, Zap AIPS files, check = "+str(check) printMess(mess, logfile) # Zap data if UV.PIsA(uv): mess = "Zap uv data" printMess(mess, logfile) if not check: uv.Zap(err) # cleanup if err.isErr: mess = "Error Zapping uv file" printMess(mess, logfile) return 1 # Zap calibration images stokes = ["I","Q","U"] for sou in Sources: # Ignore FITS images if sou["CalDataType"]=="FITS": continue for s in stokes: klass = s+sou["CalClass"][1:] # Test if file exists cno = AIPSDir.PTestCNO(sou["CalDisk"], AIPS.userno, \ sou["CalName"][0:12], klass, "MA", sou["CalSeq"], err) if cno>0: img = Image.newPAImage("img", sou["CalName"][0:12], klass, \ sou["CalDisk"], sou["CalSeq"], True, err) if err.isErr: mess = "Error finding "+s+" image for "+sou["Source"] printMess(mess, logfile) return 1 if Image.PIsA(img): mess = "Zap "+sou["Source"].strip()+" "+s+"Pol" printMess(mess, logfile) if not check: img.Zap(err) # cleanup del img if err.isErr: mess = "Error Zapping image" printMess(mess, logfile) return 1 # end if exist # end source/stokes loop return 0
def exists(self): # Do I exist? exists = False if self.uv.FileType == "FITS": exists = FITSDir.PExist(self.uv.FileName, self.uv.Disk, self._err) elif self.uv.FileType == "AIPS": user = OSystem.PGetAIPSuser() test = AIPSDir.PTestCNO(self.uv.Disk, user, self.uv.Aname, self.uv.Aclass, "UV", self.uv.Aseq, self._err) exists = test > 0 return exists
def EVLAPolnFlag (uv, souModels, err, \ flagTab=1, timeAvg=0.0, maxAmp=1.0, \ doCalib=0, gainUse=0, doBand=0, BPVer=0, flagVer=-1, \ doPol=False, PDVer=1, nThreads=1, \ check=False, debug = False, noScrat=[], logfile = ""): """ Subtract a polarization model from a data set and flag by residuals Data flagged using AutoFlag with points larger than maxAmp Returns task error code, 0=OK, else failed * uv = UV data object to calibrate * souModels= List of Source Models as created by EVLACal.EVLACalModel * err = Obit error/message stack * flagTab = Output Flagging table version * timeAvg = Time over which data is vector averaged * maxAmp = maximum allowed residual, single or list per source #* flagSig = Flagging level (sigma) #* alpha = Smoothing parameter #* timeWind = MWF width (min) #* avgTime = pre average time (min) #* avgFreq = Averaging in frequency # 0 = none # 1 = average chAvg channels # 2 = average all channels # 3 = average all channels, IFs * doCalib = Apply calibration table * chAvg = Number of channels to average * gainUse = CL/SN table to apply * doBand = If >0.5 apply bandpass cal. * BPVer = Bandpass table version * doPol = If True apply poln cal * PDVer = AIPS PD polarization cal table to apply * flagVer = Input Flagging table version * check = Only check script, don't execute tasks * debug = Run tasks debug, show input * nThreads = Number of threads to use * noScrat = list of disks to avoid for scratch files * logfile = Log file for task """ if len(souModels)<=0: # Anything to work on? return 0 mess = "Flag residuals from models " printMess(mess, logfile) # Setup UVSub uvsub = ObitTask.ObitTask("UVSub") if not check: setname(uv,uvsub) uvsub.user = AIPS.userno # This gets lost somehow uvsub.taskLog = logfile uvsub.nThreads = nThreads uvsub.noScrat = noScrat uvsub.outDisk = uv.Disk uvsub.flagVer = flagVer uvsub.doCalib = doCalib uvsub.gainUse = gainUse uvsub.doBand = doBand uvsub.BPVer = BPVer if "PDVer" in uvsub.__dict__: uvsub.doPol = doPol uvsub.PDVer = PDVer # setup for flagging #flag = ObitTask.ObitTask("MednFlag") flag = ObitTask.ObitTask("AutoFlag") flag.user = AIPS.userno # This gets lost somehow if not check: setoname(uv,flag) flag.taskLog = logfile flag.nThreads = nThreads flag.flagTab = flagTab flag.timeAvg = timeAvg if type(maxAmp)!=list: flag.IClip = [maxAmp, 0.1] #flag.flagSig = flagSig #flag.alpha = alpha #flag.timeWind = timeWind #flag.avgTime = avgTime #flag.avgFreq = avgFreq #flag.chAvg = chAvg # Loop over sources OK = False i = -1 for model in souModels: i += 1 uvsub.Sources[0]= model["Source"] if "DataType2" in uvsub.__dict__: uvsub.DataType2 = model["CalDataType"] uvsub.in2File = model["CalFile"] uvsub.in2Name = model["CalName"][0:12] uvsub.in2Class = model["CalClass"] uvsub.in2Seq = model["CalSeq"] uvsub.in2Disk = model["CalDisk"] if "nmaps" in uvsub.__dict__: uvsub.nmaps = model["CalNfield"] else: uvsub.nfield = model["CalNfield"] uvsub.CCVer = model["CalCCVer"] uvsub.BComp = model["CalBComp"] uvsub.EComp = model["CalEComp"] uvsub.Cmethod = model["CalCmethod"] uvsub.Cmodel = model["CalCmodel"] uvsub.Flux = model["CalFlux"] if "Alpha" in uvsub.__dict__: uvsub.Alpha = model["CalModelSI"] uvsub.modelFlux = model["CalModelFlux"] uvsub.modelPos = model["CalModelPos"] uvsub.modelParm = model["CalModelParm"] # Setup scratch output file uvsub.outName = model["Source"][0:12] uvsub.outClass = "PolFlg" uvsub.outSeq = 6666 if debug: uvsub.i uvsub.debug = debug # Trap failure try: mess = "Run UVSub on "+uvsub.Sources[0]+", then edit residuals above "+str(maxAmp[i]) printMess(mess, logfile) if not check: uvsub.g except Exception, exception: print exception mess = "UVSub Failed retCode= "+str(uvsub.retCode)+" Source "+uvsub.Sources[0] printMess(mess, logfile) return uvsub.retCode else: OK = True # Now flag cno = AIPSDir.PTestCNO(uvsub.outDisk, AIPS.userno, \ uvsub.outName, uvsub.outClass, "UV", uvsub.outSeq, err) if cno>0: uvscr = UV.newPAUV("zap", uvsub.outName, uvsub.outClass, uvsub.outDisk, uvsub.outSeq, False, err) else: mess = "No subtracted data created for Source "+uvsub.Sources[0] printMess(mess, logfile) return 1 # Flag using scratch writing input FG flag.Sources[0]= uvsub.Sources[0] if type(maxAmp)==list: flag.IClip = [maxAmp[i], 0.1] if not check: setname(uvscr, flag) if debug: flag.i flag.debug = debug # Trap failure try: if not check: flag.g except Exception, exception: print exception mess = "AutoFlag Failed retCode= "+str(flag.retCode)+" Source "+flag.Sources[0] printMess(mess, logfile) return flag.retCode
def EVLAPolnImage(uv, err, Sources=None, FreqID=1, seq=1, sclass="IClean", band="", \ doCalib=-1, gainUse=0, doBand=-1, BPVer=0, flagVer=-1, maxPixel=50000, \ doPol=False, PDVer=-1, minFlux=0.0, BIF=1, EIF=0, \ Stokes="I", FOV=20.0/3600.0, Robust=0, Niter=300, CleanRad=None, \ maxPSCLoop=0, minFluxPSC=0.1, solPInt=20.0/60.,\ solPMode="P", solPType= "L1", Gain=0.1, \ maxASCLoop=0, minFluxASC=0.5, solAInt=2.0, \ solAMode="A&P", solAType= "L1", Beam=[0.0,0.0,0.0], \ avgPol=False, avgIF=False, minSNR = 5.0, refAnt=0, \ do3D=False, BLFact=0.999, BLchAvg=False, doOutlier=None, \ doMB=False, norder=1, maxFBW=0.05, doComRes=False, \ nTaper=0, Tapers=[20.0], dispURL="None", \ nThreads=1, noScrat=[], logfile='', check=False, debug=False): """ Image a list of sources with optional selfcal Uses Imager or MFImage to image a list of sources. Data must be at least approximately calibrated Returns list of source models, None on failure * uv = UV data object * err = Python Obit Error/message stack * Sources = Source name or list of names to use If an empty list all sources in uv are included * seq = sequence number of output * sclass = Image output class * band = project band - appended to name * BIF = First IF * CIF = Highest IF * FreqID = Frequency group identifier * doCalib = Apply calibration table * gainUse = CL/SN table to apply * doBand = If >0.5 apply bandpass cal. * BPVer = Bandpass table version * flagVer = Input Flagging table version * doPol = Apply polarization cal? * PDVer = PD version for pol cal, -1=>use IF * minFlux = minimum flux density for initial CLEAN * Stokes = Stokes parameters to image * FOV = Field of view to image in deg * Robust = Weighting robustness parameter * Niter = max no. iterations * Gain = CLEAN loop gain * maxPixel = Maximum number of residuals in inner CLEAN * CleanRad = CLEAN radius about center or None=autoWin * maxPSCLoop = max. number of phase sc loops * minFluxPSC = Trip level for phase self cal (Jy) * solPInt = Phase solution interval (min) * solPMode = Phase soln mode "P", "DELA" * solPType = Phase soln type * maxASCLoop = max. number of amp&phase sc loops * minFluxASC = Trip level for amp&phase self cal (Jy) * solAInt = Amp&phase solution interval (min) * solAMode = Amp&Phase soln mode "A&P", "P", "DELA" * solAType = Amp&PPhase soln type * Beam = CLEAN restoring beam * avgPol = Average poln in SC? * avgIF = Average IFs in SC? * minSNR = minimum acceptable SNR in SC * refAnt = Reference antenna * do3D = Use 3D imaging? * doComRes = Force common resolution in frequency? (MF) * BLFact = Baseline dependent averaging factor * BLchAvg = If True and BLFact>=1.0 also average channels * doOutlier = Outliers from NVSS? Yes=> 4*FOV, 1 mJy None = Default, Yes if freq<6 GHz * doMB = If True is wideband imaging * norder = order on wideband imaging * maxFBW = max. fractional wideband imaging * nTaper = number of (additional) multi resolution tapers * Tapers = Sizes of additional tapers in pixels * dispURL = Name of image display * nThreads = Max. number of threads to use * noScrat = list of disks to avoid for scratch files * logfile = logfile for messages * check = Only check script, don't execute tasks * debug = show input """ ################################################################ mess = "Image a list of sources " printMess(mess, logfile) # Tolerate missing BP table # Open and close image to sync with disk uv.Open(UV.READONLY, err) uv.Close(err) hiBP = uv.GetHighVer("AIPS BP") if hiBP<=0: doBand = -1 # get reference Freq refFreq = uv.Desc.Dict["crval"][uv.Desc.Dict["jlocf"]] # If list empty get all sources if type(Sources)==list: sl = Sources else: sl = [Sources] if len(sl)<=0: slist = EVLAAllSource(uv,err,logfile=logfile,check=check,debug=debug) else: slist = sl if doMB: imager = ObitTask.ObitTask("MFImage") imager.norder = norder imager.maxFBW = maxFBW imager.prtLv = 2 else: imager = ObitTask.ObitTask("Imager") imager.prtLv = 2 imager.user = AIPS.userno # This gets lost somehow imager.taskLog = logfile if not check: setname(uv,imager) imager.outDisk = imager.inDisk imager.outName = "_"+band imager.out2Name = "_"+band imager.out2Disk = imager.inDisk imager.outSeq = seq imager.out2Seq = seq imager.outClass = sclass imager.BIF = BIF imager.EIF = EIF imager.BLFact = BLFact imager.BLchAvg = BLchAvg imager.flagVer = flagVer imager.doCalib = doCalib imager.gainUse = gainUse imager.doBand = doBand imager.BPVer = BPVer imager.doPol = doPol if "PDVer" in imager.__dict__: imager.PDVer = PDVer imager.Stokes = Stokes imager.FOV = FOV imager.Robust = Robust imager.Niter = Niter imager.Gain = Gain imager.Beam = Beam imager.maxPixel = maxPixel imager.minFlux = minFlux imager.maxPixel = maxPixel imager.maxPSCLoop = maxPSCLoop imager.minFluxPSC = minFluxPSC imager.solPInt = solPInt imager.solPMode = solPMode imager.solPType = solPType imager.maxASCLoop = maxASCLoop imager.minFluxASC = minFluxASC imager.solAInt = solAInt imager.solAMode = solAMode imager.solAType = solAType imager.avgPol = avgPol imager.avgIF = avgIF imager.refAnt = refAnt imager.minSNR = minSNR imager.do3D = do3D imager.dispURL = dispURL imager.nTaper = nTaper imager.Tapers = Tapers if doOutlier or ((doOutlier==None) and refFreq<6.0e9): FWHM = (45.0 /(refFreq*1.0e-9) ) / 60. # FWHM in deg imager.OutlierDist = FWHM*2.0 # Outliers from NVSS for lower frequencies imager.OutlierFlux = 0.01 # Auto window or centered box if CleanRad: imager.CLEANBox=[-1,CleanRad,0,0] else: imager.autoWindow = True if "doComRes" in imager.__dict__: imager.doComRes = doComRes imager.noScrat = noScrat imager.nThreads = nThreads if debug: imager.prtLv = 5 imager.i imager.debug = debug OK = False # Some must work modelList = [] # Init output model list # Loop over slist for sou in slist: imager.Sources[0] = sou mess = "Image "+sou printMess(mess, logfile) # Trap failure try: if not check: imager.g except Exception, exception: print exception mess = "Imager Failed retCode= "+str(imager.retCode) printMess(mess, logfile) #return 1 Allow some failures # Cleanup image mess AllDest(err,Atype="MA",Aname=imager.Sources[0], disk=imager.outDisk, Aseq=imager.outSeq); else: OK = True # delete Imager file if not debug if not debug: out2Name = imager.Sources[0].strip()+"_"+band out2Name = out2Name[0:12] if doMB: out2Class = "MFImage" else: out2Class = "Imager" # Tolerate failures try: # Test if file exists cno = AIPSDir.PTestCNO(imager.out2Disk, AIPS.userno, \ out2Name, out2Class, "UV", imager.out2Seq, err) if cno>0: u = UV.newPAUV("zap", out2Name, out2Class, imager.out2Disk, imager.out2Seq, False, err) if UV.PIsA(u): u.Zap(err) # cleanup if err.isErr: mess = "Error deleting Imager work file" printMess(mess, logfile) #return 1 del u # Create model, add to modelList modelList.append(EVLACal.EVLACalModel(sou, CalName=imager.Sources[0]+imager.outName, \ CalClass=imager.outClass, \ CalSeq=imager.outSeq, \ CalCmethod="DFT", CalDataType="AIPS", \ CalDisk=imager.outDisk, CalNfield=1)) except Exception, exception: print exception mess = "Imager Cleanup Failed source= "+imager.Sources[0].strip()+"_"+band printMess(mess, logfile) OErr.PClear(err) # Clear any message/error #return 1 Allow some failures else: pass
print exception mess = "TabCopy Failed retCode= "+str(taco.retCode) printMess(mess, logfile) return 1 # end loop over tables # Write calibration images stokes = ["I","Q","U"] for sou in Sources: # Ignore FITS images if sou["CalDataType"]=="FITS": continue for s in stokes: klass = s+sou["CalClass"][1:] # Test if file exists cno = AIPSDir.PTestCNO(sou["CalDisk"], AIPS.userno, \ sou["CalName"][0:12], klass, "MA", sou["CalSeq"], err) if cno>0: img = Image.newPAImage("img", sou["CalName"][0:12], klass, \ sou["CalDisk"], sou["CalSeq"], True, err) if err.isErr: mess = "Error finding "+s+" image for "+sou["Source"] printMess(mess, logfile) return 1 imgfile = sou["Source"].strip()+session+s+"Pol.fits" EVLACal. EVLAImFITS (img, imgfile, outDisk, err, logfile=logfile) if err.isErr: OErr.printErrMsg(err, "Error Writing image") return 1 else: mess = "Skip writing "+s+" image for "+sou["Source"] printMess(mess, logfile)
def newPAImage(name, Aname, Aclass, disk, seq, exists, err, verbose=False): """ Create and initialize an AIPS based Image structure Create, set initial access information (full image, plane at a time) and if exists verifies the file. Returns the Python Image object isOK member set to indicate success * name = name desired for object (labeling purposes) * Aname = AIPS name of file * Aclass = AIPS class of file * seq = AIPS sequence number of file * disk = FITS directory number * exists = if true then the file is opened and closed to verify * err = Python Obit Error/message stack * verbose = If true any give error messages, else suppress """ ################################################################ out = ImageMF(name) out.isOK = True # until proven otherwise cno = -1 user = OSystem.PGetAIPSuser() # print "disk, aseq", disk, seq # Does it really previously exist? test = AIPSDir.PTestCNO(disk, user, Aname, Aclass, "MA", seq, err) out.exist = test > 0 if exists: # If user thinks file exists... if out.exist: # If file is defined in catalog -> verify that file exists OErr.PLog(err, OErr.Info, Aname + " image found. Now verifying...") if verbose: OErr.printErr(err) cno = AIPSDir.PFindCNO(disk, user, Aname, Aclass, "MA", seq, err) Obit.ImageMFSetAIPS(out.me, 2, disk, cno, user, blc, trc, err.me) Obit.ImagefullInstantiate(out.cast("ObitImage"), 1, err.me) #print "found",Aname,Aclass,"as",cno else: # If file not defined in catalog -> error OErr.PLog(err, OErr.Error, Aname + " image does not exist") out.isOK = False else: # exists=False # Create new image entry in catalog; if image already defined, this # has no effect OErr.PLog(err, OErr.Info, "Creating new image: " + Aname + ", " + Aclass) if verbose: OErr.printErr(err) cno = AIPSDir.PAlloc(disk, user, Aname, Aclass, "MA", seq, err) Obit.ImageMFSetAIPS(out.me, 2, disk, cno, user, blc, trc, err.me) #print "assigned",Aname,Aclass,"to",cno # show any errors if wanted if verbose and err.isErr: out.isOK = False OErr.printErrMsg(err, "Error creating AIPS Image object") elif err.isErr: out.isOK = False OErr.PClear(err) # Clear unwanted messages else: OErr.PClear(err) # Clear non-error messages # It work? if not out.isOK: return out # Add File info out.FileType = 'AIPS' out.Disk = disk out.Aname = Aname out.Aclass = Aclass out.Aseq = seq out.Otype = "Image" out.Acno = cno return out # seems OK
def VLAUVLoad(filename, inDisk, Aname, Aclass, Adisk, Aseq, err, logfile=''): """ Read FITS uvtab file into AIPS Read a UVTAB FITS UV data file and write an AIPS data set filename = name of FITS file inDisk = FITS directory number Aname = AIPS name of file Aclass = AIPS class of file Aseq = AIPS sequence number of file, 0=> create new Adisk = FITS directory number err = Python Obit Error/message stack logfile = logfile for messages returns AIPS UV data object """ ################################################################ # # Checks if not OErr.OErrIsA(err): raise TypeError, "err MUST be an OErr" # # Get input inUV = UV.newPFUV("FITS UV DATA", filename, inDisk, True, err) if err.isErr: OErr.printErrMsg(err, "Error with FITS data") # Get output, create new if seq=0 if Aseq < 1: OErr.printErr(err) # Print any outstanding messages user = OSystem.PGetAIPSuser() Aseq = AIPSDir.PHiSeq(Adisk, user, Aname, Aclass, "MA", err) # If it already exists, increment seq if AIPSDir.PTestCNO(Adisk, user, Aname, Aclass, "MA", Aseq, err) > 0: Aseq = Aseq + 1 OErr.PClear(err) # Clear any message/error mess = "Creating AIPS UV file " + Aname + "." + Aclass + "." + str( Aseq) + " on disk " + str(Adisk) printMess(mess, logfile) outUV = UV.newPAUV("AIPS UV DATA", Aname, Aclass, Adisk, Aseq, False, err) if err.isErr: OErr.printErrMsg(err, "Error creating AIPS data") # Copy UV.PCopy(inUV, outUV, err) if err.isErr: OErr.printErrMsg(err, "Error copying UV data to AIPS") # Copy History inHistory = History.History("inhistory", inUV.List, err) outHistory = History.History("outhistory", outUV.List, err) History.PCopyHeader(inHistory, outHistory, err) # Add history outHistory.Open(History.READWRITE, err) outHistory.TimeStamp(" Start Obit uvlod", err) outHistory.WriteRec( -1, "uvlod / FITS file " + filename + " disk " + str(inDisk), err) outHistory.Close(err) # # Copy Tables exclude = [ "AIPS HI", "AIPS AN", "AIPS FQ", "AIPS SL", "AIPS PL", "History" ] include = [] UV.PCopyTables(inUV, outUV, exclude, include, err) return outUV # return new object
def EVLAPolnToFITS(uv, outFile, outDisk, Sources, session, err, \ logfile = "",check=False, debug = False): """ Copy new calibration and editing tables from uv to the input FITS file Any SN, CL, BP, PD, CP tables not on outFile are copied from uv uv FG table 1 is copied to outFile table 2 Also writes AIPS calibrator images (I, Q, U) Returns 0 on success otherwise failure * uv = UV data with calibration and editing * outFile = Name of FITS file to write tables to * outDisk = FITS disk for inFile, 0=>cwd * Sources = List of Source Models as created by EVLACal.EVLACalModel * session = Name of session, used for FITS images * err = Obit error/message stack * logfile = Log file for task * check = Only check script * debug = Run tasks debug, show input """ ################################################################ mess = "Save resultant tables, calibration images" printMess(mess, logfile) # Copy tables not on inFile # UV Data for infile outUV = UV.newPFUV("FITS UV DATA", outFile, outDisk, True, err) if err.isErr: OErr.printErrMsg(err, "Error with FITS data") # Use TabCopy taco = ObitTask.ObitTask("TabCopy") taco.user = AIPS.userno # This gets lost somehow setname(uv, taco) taco.taskLog = logfile taco.DataType = "AIPS" taco.outDType = "FITS" taco.outFile = outFile taco.outDisk = outDisk # FG inHi = UV.PGetHighVer(uv, "AIPS FG") outHi = UV.PGetHighVer(outUV, "AIPS FG") if outHi < 2: # copy uv FG table 1 to outUV FG 2 (new table) mess = "Copy FG 1 to FG 2" printMess(mess, logfile) taco.inTab = "AIPS FG" taco.inVer = 1 taco.outVer = 2 # Trap failure try: if not check: taco.g except Exception as exception: print(exception) mess = "TabCopy Failed retCode= " + str(taco.retCode) printMess(mess, logfile) return 1 # Other tables tabs = ["BP", "CL", "SN", "PD", "CP"] for tt in tabs: ttype = "AIPS " + tt inHi = UV.PGetHighVer(uv, ttype) outHi = UV.PGetHighVer(outUV, ttype) mess = "Copy " + tt + " tables " + str(outHi + 1) + " to " + str(inHi) printMess(mess, logfile) for ver in range(outHi + 1, inHi + 1): taco.inTab = ttype taco.inVer = ver taco.outVer = ver # Trap failure try: if not check: taco.g except Exception as exception: print(exception) mess = "TabCopy Failed retCode= " + str(taco.retCode) printMess(mess, logfile) return 1 # end loop over tables # Write calibration images stokes = ["I", "Q", "U"] for sou in Sources: # Ignore FITS images if sou["CalDataType"] == "FITS": continue for s in stokes: klass = s + sou["CalClass"][1:] # Test if file exists cno = AIPSDir.PTestCNO(sou["CalDisk"], AIPS.userno, \ sou["CalName"][0:12], klass, "MA", sou["CalSeq"], err) if cno > 0: img = Image.newPAImage("img", sou["CalName"][0:12], klass, \ sou["CalDisk"], sou["CalSeq"], True, err) if err.isErr: mess = "Error finding " + s + " image for " + sou["Source"] printMess(mess, logfile) return 1 imgfile = sou["Source"].strip() + session + s + "Pol.fits" EVLACal.EVLAImFITS(img, imgfile, outDisk, err, logfile=logfile) if err.isErr: OErr.printErrMsg(err, "Error Writing image") return 1 else: mess = "Skip writing " + s + " image for " + sou["Source"] printMess(mess, logfile) # end if exist # end loops over Stokes and source return 0