;+ ; NAME: ; CALCAREA ; ; PURPOSE: ; Compute the moment, area, and convex hull of a series of RA/DEC points ; ; CALLING SEQUENCE: ; FLAG = CALCAREA( ALERTID, SITEFILE ) ; ; INPUT: ; ALERTID - String - Alert identifiant ; SITEFILE - String - Name of the file with all the observer sites listed ; FOV - Float - Size of the Observer's Field of View (ARCSEC) ; ; OUTPUT: ; FLAG - Boolean- Indicate success or failure ; 0: Success ; 1: Error -- Demo Mode ; 11: Error -- No Cuts configuration ; 12: Error -- No Site File ; 13: Error -- Geo- and Topo-center both sets ; 14: Error -- No Alert Directory ; 15: Error -- No CSV found ; 16: Error -- Bad CSV Data ; ; FILE written on disk: [alert-footprint.csv] ; epoch (JD & ISO) ; medianRA meanRA stdevRA skewRA minRA maxRA ; medianDEC meanDEC stdevDEC skewDEC minDEC maxDEC ; delaunayTrianglesTotal skySearchAreaTotal delaunayTrianglesCut skySearchAreaCut ; IndexOfMedianOrbit (line #) ; mainFootprint(Polygon J2000 RA DEC RA DEC RA DEC.....) ; isolatedPointsFootprints(Polygon J2000 RA DEC RA DEC RA DEC.....) ; ; KEYWORD PARAMETERS: ; geocenter - Bool - Run the code for Geocenter only ; topocenter - Bool - Run the code for ALL observers but Geocenter ; ; CREATION ; 2013-Jul-09: B.Carry (IMCCE, Observatoire de Paris) ; ; EXTERNAL ROUTINE NEEDED: ; date_conv, readcol ; ; HISTORY ; 2013-Sep-18: B. Carry (IMCCE) - FOV added as input // Median orbital solution extracted ; 2013-Sep-17: H. Devillepoix (IMCCE) - Added output of the index of the median point of the dataset ; 2013-Sep-17: H. Devillepoix (IMCCE) - Added documentation for I/O ; 2014-Jan-30: B. Carry (IMCCE) - Flags commented -- Bug file path corrected ; 2017 Nov : B. Carry (OCA) - idl2 ; 2017 Dec : B. Carry (OCA) - Added velocity computation ; ;- function calcarea, alertID, siteFile, FOV=FOV, geocenter=geocenter, topocenter=topocenter COMPILE_OPT hidden, idl2 ;-----------------------------------------------------------------------------------------------; ;-----------------------------------------------------------------------------------------------; ;--- TAG --- I -- Initialization And Input Verification -----------------------; ;-----------------------------------------------------------------------------------------------; ;-----------------------------------------------------------------------------------------------; ;--I.1-- Directory Architecture --------------------------------------------------------------; ;--I.1.1-- Script and root directories dirSCRIPT = file_dirName(routine_filePath( 'calcarea', /Is_Function ))+'/' root = strMid( dirSCRIPT, 0, strLen(dirSCRIPT)-strLen('scripts/') ) ;--I.1.2-- Data directories dirDATA = root+'data/' dirOUT = dirDATA+'output/' ;--I.1.3-- Configuration, Logs Directories dirLOG = root+'logs/'+alertID+'/' dirCONF = root+'conf/' ;------ XXX - TO BE REMOVED later: now used for test while integrating ; the motion ; root='/home/bcarry/work/gaia/' ; dirOUT=root ; dirLOG=root ; dirCONF=root ;--I.1.4-- Useful files cutsINI = 'cuts.ini' if keyword_set( GEOCENTER ) then begin logFILE = dirLOG+'scp_1-4.log' endif else begin logFILE = dirLOG+'scp_2-3.log' endelse errFILE = dirLOG+'errors.err' ;--I.2-- IDL in DEMO or NORMAL mode ----------------------------------------------------------; idlMode = lmgr(/DEMO) if (idlMode gt 0) then begin jdBug = SYSTIME( /JULIAN , /UTC ) spawn, 'echo "[ERROR] '+strMid(date_conv(jdBug,'FITS'),11,8)+' ----- IDL in Demo mode - Aborting " > '+logFile spawn, 'echo " '+strMid(date_conv(jdBug,'FITS'),0,19)+' - CALCAREA - IDL in Demo mode - Aborting " >> '+errFile return, 1 endif else begin jdBeg = SYSTIME( /JULIAN , /UTC ) spawn, 'echo "'+strMid(date_conv(jdBeg,'FITS'),0,19)+' -- I-- Code initialization " > '+logFile endelse ;--I.3-- Read Configuration File -------------------------------------------------------------; if not file_test(dirCONF+cutsINI,/READ) then begin jdBug = SYSTIME( /JULIAN , /UTC ) spawn, 'echo "[ERROR] '+strMid(date_conv(jdBug,'FITS'),11,8)+' -- I-- Cannot find the Cuts Configuration file: '+$ cutsINI+' " >> '+logFile spawn, 'echo " '+strMid(date_conv(jdBug,'FITS'),0,19)+' - CALCAREA - Cuts Configuration File not Found " >> '+errFile return, 11 endif else begin ;--I.3.1-- Open the Configuration File & Declare cutAREA openr, idInput, dirCONF+cutsINI, /Get_Lun line = ' ' section = ' ' cutAREA = {total: 10, triangle: 0.25} ;--I.3.2-- Analyse the Configuration File while ~EOF(idInput) do begin readf, idInput, line split = strSplit(line, '=', /EXTRACT ) CASE split[0] OF 'maxSearchArea' : cutAREA.total = float(split[1]) 'maxTriangleArea' : cutAREA.triangle = float(split[1]) ELSE: ENDCASE endwhile free_lun, idInput ;--I.3.3-- Log Insertion jdNow = SYSTIME( /JULIAN , /UTC ) spawn, 'echo " '+strMid(date_conv(jdNow,'FITS'),11,8)+' -- I-- Cuts configuration read" >> '+logFile endelse ;--I.4-- Read the Observing Sites List -------------------------------------------------------; ;--I.4.1-- Geocentric Observations if keyword_set( GEOCENTER ) then begin siteIAU =[500] siteLon =[0] siteLat =[0] siteName=["Geocenter"] ;--I.4.2-- Topocentric Observations endif else begin ;--I.4.2/A-- No observer File Found if not file_test( root+siteFile,/Read ) then begin jdBug = SYSTIME( /JULIAN , /UTC ) spawn, 'echo "[ERROR] '+strMid(date_conv(jdBug,'FITS'),11,8)+' -- I-- Cannot find the Observing Sites file: '+$ root+siteFile+' " >> '+logFile spawn, 'echo " '+strMid(date_conv(jdBug,'FITS'),0,19)+' - CALCAREA - Observing Site File not Found: '+$ root+siteFile+' " >> '+errFile return, 12 ;--I.4.2/B-- Read the Observers File endif else begin readcol, root+siteFile, $ siteIAU, siteLon, siteLat, siteName, $ format='(A,F,F,A)', delim=',', /SILENT nbSite = n_elements( siteIAU ) jdNow = SYSTIME( /JULIAN , /UTC ) spawn, 'echo " '+strMid(date_conv(jdNow,'FITS'),11,8)+' -- I-- Observing Sites read -- '+$ strTrim(string(nbSite,format='(I)'),2)+' sites found" >> '+logFile endelse endelse ;--I.4.3-- Observer's Field of View if keyword_set( FOV ) then fovSize = FOV $ else fovSize = 5 ; Arcseconds ;--I.5-- Geocenter only or All Observers -----------------------------------------------------; ;--I.5.1-- Only ONE Choice Allowed if keyword_set( GEOCENTER ) and keyword_set( TOPOCENTER ) then begin jdBug = SYSTIME( /JULIAN , /UTC ) spawn, 'echo "[ERROR] '+strMid(date_conv(jdBug,'FITS'),11,8)+$ ' -- I-- Cannot choose GEOCENTER *and* ALL observers " >> '+logFile spawn, 'echo " CALCAREA - '+strMid(date_conv(jdBug,'FITS'),0,19)+' - Cannot run Geocenter and Topocenter together " >> '+errFile return, 13 endif ;--I.5.2-- Choose GEOCENTER as Default if not keyword_set( GEOCENTER ) and not keyword_set( TOPOCENTER ) then begin GEOCENTER=500 ;--I.4.2-- Log Insertion jdNow = SYSTIME( /JULIAN , /UTC ) spawn, 'echo "[WARNING] '+strMid(date_conv(jdNow,'FITS'),11,8)+$ ' -- I-- Observer not specified - Set to geocenter by default" >> '+logFile endif ;--I.5.3-- Setup Directories and Loop if keyword_set( GEOCENTER ) then begin kSiteS=0 ;-Start ID kSiteE=kSiteS+1 ;-End ID endif else begin kSiteS=0 ;-Start ID kSiteE=nbSite ;-End ID endelse for kSite=kSiteS, kSiteE-1 do begin stringOBS = strTrim(siteIAU[kSite], 1) stringOBS = strTrim(stringOBS) dirALERT= dirOUT+alertID+'/'+stringOBS+'/' endfor ;--I.5.4-- Loop over Observing Sites for kSite=kSiteS, kSiteE-1 do begin ;--I.5.5-- Working Directory stringOBS = strTrim(siteIAU[kSite], 1) stringOBS = strTrim(stringOBS) dirALERT= dirOUT+alertID+'/'+stringOBS+'/' ;--I.5.6-- Log Insertion if not file_test( dirALERT, /DIR ) then begin jdBug = SYSTIME( /JULIAN , /UTC ) spawn, 'echo "[ERROR] '+strMid(date_conv(jdBug,'FITS'),11,8)+$ ' : Alert directory not found: '+dirALERT+' " >> '+logFile spawn, 'echo " '+strMid(date_conv(jdBug,'FITS'),0,19)+' - CALCAREA - Alert Directory not Found: '+$ dirALERT+' " >> '+errFile return, 14 endif else begin sLen = strTrim(string( strLen(strTrim(string(kSiteE,format='(I)'),2)),format='(I)'),2) jdNow = SYSTIME( /JULIAN , /UTC ) spawn, 'echo " '+strMid(date_conv(jdNow,'FITS'),11,8)+$ ' -- II-- Observer '+$ string(kSite+1,format='(I'+sLen+')')+'/'+$ string(kSiteE ,format='(I'+sLen+')')+' - '+stringOBS+'" >> '+logFile endelse ;-----------------------------------------------------------------------------------------------; ;-----------------------------------------------------------------------------------------------; ;--- TAG --- II -- Analysis of the Alert Directory -----------------------; ;-----------------------------------------------------------------------------------------------; ;-----------------------------------------------------------------------------------------------; ;--II.1--List CSV files in Alert Directory -------------------------------------------------; spawn, 'ls -1 '+dirALERT+'*csv', listd nbDate = n_elements( listd ) if nbDate eq 0 then begin jdBug = SYSTIME( /JULIAN , /UTC ) spawn, 'echo "[ERROR] '+strMid(date_conv(jdBug,'FITS'),11,8)+' -- II-- No CSV files in alert directory: '+$ dirALERT+' " >> '+logFile spawn, 'echo " '+strMid(date_conv(jdBug,'FITS'),0,19)+' - CALCAREA - No CSV File in alert directory: '+$ dirALERT+' " >> '+errFile return, 15 endif ;--II.2-- Declaration of Ouput Arrays ------------------------------------------------------; jdArr = dblarr( nbDate ) ;--Date of each Ephemeris Step -- Julian days isoArr = strarr( nbDate ) ;--Date of each Ephemeris Step -- ISO format coordArr = fltarr( 2, nbDate ) ;--Average RA/DEC areaArr = fltarr( 2, 3, nbDate ) ;--Cloud area || id1: RA or RA+180 numArr = lonarr( 2, 3, nbDate ) ;--Number of Triangle || id2: ALL, SMALL, or LARGE triangles rateArr = fltarr( 2, 3, nbDate ) ;--Apparent rate || id1: mean stddev || id2: ra,dec,all orientArr= fltarr( 2, nbDate ) ;--Direction of motion || id1: mean stddev ;--II.3-- Read each Date & Basic Computation -----------------------------------------------; fullLoop=0 for kDate=0, nbDate-1 do begin ;--II.3.1-- Read the CSV file ;--II.3.1/A-- Blind read ra=-99 readcol, listd[kDate], $ jd, $ ;-Julian Day (d) ra, dec, $ ;-RA/Dec coordinates (deg) geoDist, $ ;-Geocentric distance (AU) muRA, muDEC, $ ;-RA/Dec apparent motion (deg/d) muGeo, $ ;-Geocentric distance rate (AU/d) orbWeight, $ ;-Solution Weight (DU456) (--) format='(D,F,F,F,F,F,F,I)', delim=',', /SILENT ;--II.3.1/B-- Create List Versin of Variables jdl=list(jd,/extract) ral=list(ra, /extract) decl=list(dec,/extract) geoDistl=list(geoDist,/extract) muRal=list(muRa,/extract) muDecl=list(muDec,/extract) muGeol=list(muGeo,/extract) orbWeightl=list(orbWeight,/extract) i_nan=where(~finite(ra), /null) ;--II.3.1/C-- Remove NaN items if i_nan ne !NULL then begin jdl.remove,i_nan ral.remove,i_nan decl.remove,i_nan geoDistl.remove,i_nan muRal.remove,i_nan muDecl.remove,i_nan muGeol.remove,i_nan orbWeightl.remove,i_nan jdl=jdl.toArray() ra=ral.toArray() dec=decl.toArray() geoDist=geoDistl.toArray() muRa=muRal.toArray() muDec=muDecl.toArray() meGeo=muGeol.toArray() orbWeight=orbWeightl.toArray() endif ;--II.3.2-- Number of Orbits to Consider nbOrb = n_elements( ra ) if nbOrb eq 1 and ra[0] eq -99 then begin jdBug = SYSTIME( /JULIAN , /UTC ) spawn, 'echo "[ERROR] '+strMid(date_conv(jdBug,'FITS'),11,8)+' -- II-- Bad data in the CSV file: '+$ listd[kDate]+' " >> '+logFile spawn, 'echo " '+strMid(date_conv(jdBug,'FITS'),0,19)+' - CALCAREA - Bad data in CSV File: '+$ listd[kDate]+' " >> '+errFile return, 16 endif ;--II.3.3-- Look-up Table for Small/Large Triangle largeTriFlag = intarr(2,nbOrb) ;--II.3.4-- Median Orbit pMedian = where( ra eq median(ra) ) pMedian = pMedian[0] ;--II.3.5-- Moments of the Orbit Projections: median, mean, variance, skew, kurtosis mmtRA = [ra[pMedian], moment(ra) ] mmtDEC = [dec[pMedian], moment(dec) ] coordArr[*,kDate] = [ mmtRA[0], mmtDEC[0] ] ;--II.3.6-- Time arrays jdArr[kDate] = median( jd ) isoArr[kDate] = date_conv( jdArr[kDate], 'FITS' ) ;--II.3.7-- Motion arrays muRa *= 3600./(24.*60.) muDec *= 3600./(24.*60.) motion = sqrt( muRa^2. + muDec^2. ) rateArr[0,0,kDate] = mean(muRa) rateArr[1,0,kDate] = stddev(muRa) rateArr[0,1,kDate] = mean(muDec) rateArr[1,1,kDate] = stddev(muDec) rateArr[0,2,kDate] = mean(motion) rateArr[1,2,kDate] = stddev(motion) angle = 90. - atan( muDec, muRa )/!DTOR orientArr[0,kDate] = mean(angle) orientArr[1,kDate] = stddev(angle) ;-----------------------------------------------------------------------------------------------; ;-----------------------------------------------------------------------------------------------; ;--- TAG --- III -- Area and Convex Hull Computation -----------------------; ;-----------------------------------------------------------------------------------------------; ;-----------------------------------------------------------------------------------------------; ; ; If ra~0 or 360 then shift -> hull -> shift ; else hull ; ; ;-----------------------------------------------------------------------------------------------; ;-------------------------------------------------------------------- ;--III.1-- Using Native RA/DEC step=0 ;--III.1.1-- Delaunay Triangulation ;-- options: SPHERE: Coordinates on a sphere and not a plane ;-- DEGREE: Coordinates in degrees and not radians ;debug; area=poly_area(ra,dec) ;debug; print, '' ;debug; print, kSite, kDate, ' ', isoArr[kDate] ;debug; plot, ra, dec, /iso, psym=3, $ ;debug; xtitle='Right Ascencion (!Uo!N)', $ ;debug; ytitle='Declination (!Uo!N)' ;print, 'start of step 1 ', Error_Status, kDate print, '0 - Error_status = step = ',step,' kDate = ',kDate CATCH, Error_status IF Error_status NE 0 then kDate-- print, '1 - Error_status = ',Error_status,' step = ',step,' kDate = ',kDate print, ' alert id is ',alertID IF Error_status NE 0 and step eq 2 then begin catch, /cancel goto, j2Shifted endif step=1 IF Error_status NE 0 THEN BEGIN print, '--> rerun on plane for alert id ',alertID,' - Error_status = ',Error_status,' step = ',step,' kDate = ',kDate message, /info, 'Error catched in first step, rerun on plane' triangulate, ra, dec, triangle, /DEGREE print,'Error_status = ',Error_status Error_status=0 catch, /cancel endif else begin triangulate, ra, dec, triangle, sphere=sphere, /DEGREE endelse print, '2 - Error_status = ',Error_status,' step = ',step,' kDate = ',kDate ;--III.1.2-- Number of Triangles nbTri = n_elements( triangle ) /3. triArea = fltarr( nbTri ) ;-Area of Individual Triangles numArr[ 0,0,kDate] = nbTri ;-Total Number of Triangles print, '3 - Error_status = ',Error_status,' nbTri = ',nbTri,' step = ',step,' kDate = ',kDate ;--III.1.3-- Individual Triangle Area and Sorting for kTri=0, nbTri-1 do begin ;--III.1.3.1-- Current Triangle: Area & Total Area triArea[kTri] = poly_area( ra[triangle[*,kTri]], dec[triangle[*,kTri]] ) areaArr[0,0,kDate] += triArea[kTri] ; color=255 ; if triArea[kTri] ge cutAREA.triangle then color=80 ; for kSid=0,2 do begin ; oplot, [ra(triangle( [kSid, (kSid+1) mod 2],kTri))], $ ; [dec(triangle([kSid, (kSid+1) mod 2],kTri))], color=color ; endfor ;--III.1.3.2-- IF Small Triangle: Number & Total Area if triArea[kTri] le cutAREA.triangle then begin numArr[ 0,1,kDate] ++ areaArr[0,1,kDate] += triArea[kTri] ;--III.1.3.3-- IF Large Triangle: Number & Total Area & Flag endif else begin numArr[ 0,2,kDate] ++ areaArr[0,2,kDate] += triArea[kTri] ;-Keep Marked each Vertex of the Large Triangle largeTriFlag[0, triangle[*,kTri] ] = 1 endelse endfor ;-------------------------------------------------------------------- ;--III.2-- Using RA/DEC Shifted by 180 deg. in RA j2Shifted: raS = (ra+180.) mod 360. raArr = transpose([ [ra], [(ra+180.) mod 360.] ]) ;--III.2.1-- Delaunay Triangulation ;-- options: SPHERE: Coordinates on a sphere and not a plane ;-- DEGREE: Coordinates in degrees and not radians step=2 print, '4 - Error_status = ',Error_status,' step = ',step IF Error_status NE 0 THEN BEGIN triangulate, raS, dec, triangle, /DEGREE Error_status=0 catch, /cancel endif else begin triangulate, raS, dec, triangle, sphere=sphere, /DEGREE endelse print,"III.2.1-- Delaunay Triangulation" ;--III.2.2-- Number of Triangles nbTri = n_elements( triangle ) /3. triArea = fltarr( nbTri ) ;-Area of Individual Triangles numArr[ 1,0,kDate] = nbTri ;-Total Number of Triangles ;--III.2.3-- Individual Triangle Area and Sorting print,"III.2.3" for kTri=0, nbTri-1 do begin ;--III.2.3.1-- Current Triangle: Area & Total Area triArea[kTri] = poly_area( raS[triangle[*,kTri]], dec[triangle[*,kTri]] ) areaArr[1,0,kDate] += triArea[kTri] ;--III.2.3.2-- IF Small Triangle: Number & Total Area if triArea[kTri] le cutAREA.triangle then begin numArr[ 1,1,kDate] ++ areaArr[1,1,kDate] += triArea[kTri] ;--III.2.3.3-- IF Large Triangle: Number & Total Area & Flag endif else begin numArr[ 1,2,kDate] ++ areaArr[1,2,kDate] += triArea[kTri] ;-Keep Marked each Vertex of the Large Triangle largeTriFlag[1, triangle[*,kTri] ] = 1 endelse endfor ;-------------------------------------------------------------------- ;--III.3-- Selection of Native or Shifted Version print,"--III.3-- Selection of Native or Shifted Version" if areaArr[0,0,kDate] le areaArr[1,0,kDate] then selSol = 0 $ else selSol = 1 ;-------------------------------------------------------------------- ;--III.4-- Convex Hull for Small Triangles Only ;--III.4.1-- Identify Vertices & Compute Convex Hull smallZone = where( largeTriFlag[selSol,*] eq 0, nbSZ, comp=largeZone, ncom=nbLZ ) ;--III.4.2-- Sort Convex Hull Sides if nbSZ gt 3 then begin qhull, raArr[selSol,smallZone], dec[smallZone], connect ;--III.4.2.1-- Sides of the Convex Hull nbSide = n_elements( connect )/2. side = connect[*,0] ;--III.4.2.2-- Footprint String for Output footprint = 'Polygon J2000 ' for kSide=1, nbSide-1 do begin ;--III.4.2.2/a-- Identify Adjacent Side p=where( connect[0,*] eq side[1,kSide-1] ) side=[[side],[connect[*,p[0]]]] ;--III.4.2.2/b-- Complete Footprint String for Output footprint += string( ra[smallZone[connect[0,p[0]]]],format='(F8.4)' )+' '+$ string( dec[smallZone[connect[0,p[0]]]],format='(F8.4)' )+' ' endfor endif print,"--III.4.2-- Sort Convex Hull Sides" ;-------------------------------------------------------------------- ;--III.5-- Excecution Optimization: Stop Loop when Area is too Big if areaArr[selSol,1,kDate] gt cutAREA.total then begin print,"--III.5-- Excecution Optimization: Stop Loop when Area is too Big" fullLoop=0 goto, j2ExitDate endif ;-----------------------------------------------------------------------------------------------; ;-----------------------------------------------------------------------------------------------; ;--- TAG --- IV -- Generation of Output Files -----------------------; ;-----------------------------------------------------------------------------------------------; ;-----------------------------------------------------------------------------------------------; ;--IV.1-- Open the output file openw, 1, strMid(listd[kDate],0,strLen(listd[kDate])-4)+'-footprint.dat' ;--IV.2-- Basic Statistics on the Cloud printf, 1, jdArr[kDate], isoArr[kDate], format='(D16.8,1x,A-25)' printf, 1, mmtRA[0], mmtRA[1], sqrt(mmtRA[2]), mmtRA[3], min(ra), max(ra), format='(6(F8.4,1x))' printf, 1, mmtDEC[0], mmtDEC[1], sqrt(mmtDEC[2]), mmtDEC[3], min(dec), max(dec), format='(6(F8.4,1x))' ;--XXX CHANGE: added a line with apparent motion rate printf, 1, rateArr[0,2,kDate], rateArr[1,2,kDate], orientArr[0,kDate], orientArr[1,kDate], $ format='(2(F7.2,2x),2(F6.1,2x))' printf, 1, numArr[selSol,0,kDate], areaArr[selSol,0,kDate], $ numArr[selSol,1,kDate], areaArr[selSol,1,kDate], $ format='(2(I6,1x,F12.5))' printf, 1, strTrim(string(pMedian, format='(I)'),2) ;--IV.3-- Alert Footprint on Sky ;--IV.3.1-- Large Footprint from the Sum of All the Small Triangles if nbSZ gt 3 then printf, 1, footprint ;--IV.3.2-- Remaining Isolated Points (from Large Triangles) if nbLZ ge 1 then begin fovRA = [-1, 1, 1,-1]*fovSize/3600. fovDEC= [-1,-1, 1, 1]*fovSize/3600. for kLZ=0, nbLZ-1 do begin footprint = 'Polygon J2000 ' for kF=0,3 do footprint += string( ra[largeZone[kLZ]]+fovRA [kF],format='(F8.4)' )+' '+$ string( dec[largeZone[kLZ]]+fovDEC[kF],format='(F8.4)' )+' ' printf, 1, footprint endfor endif ;--IV.4-- Close the Output File close, 1 j2NextDate: endfor ;--End of loop over Dates j2ExitDate: ;--IV.5-- Close the Log jdNow = SYSTIME( /JULIAN , /UTC ) if fullLoop eq 0 then begin spawn, 'echo " '+strMid(date_conv(jdNow,'FITS'),11,8)+' -- II---- '+$ ' Loop Aborted at step '+strTrim(string(kDate-1,format='(I)'),2)+': '+isoArr[kDate-1]+' " >> '+logFile endif spawn, 'echo " '+strMid(date_conv(jdNow,'FITS'),11,8)+' -- II---- '+$ ' Observer '+siteName[kSite]+' completed " >> '+logFile endfor ;--End of loop over Observer Sites ;--V-- Close the Log jdNow = SYSTIME( /JULIAN , /UTC ) spawn, 'echo " '+strMid(date_conv(jdNow,'FITS'),11,8)+' -- V-- '+$ 'Success -- Runtime '+$ strTrim( string( (jdNow-jdBeg)*24.D*3600, format='(F12.1)'),2)+'s " >> '+logFile return, 0 end