APSF //---------------------------------------------------------------------------------------------- // Resource name to index converters. // function SiteIndex(siteName as string) as integer dim i as integer for i = 1 to nSites if Site(i).Name = siteName then return i end if next return 1 end function //---------------------------------------------------------------------------------------------- // Classes and routines for disambiguating "nights" and for storing conditions data for each // night. // dim night as double // length of a night in seconds -- observations within this delta night = 60 * 60 * 12 // will be considered to be on the same night function CompareDateTimes(d1 as double, d2 as double) as integer if Abs(d1 - d2) < night then return 0 elseif d1 < d2 then return -1 else return 1 end if end function class conditions dateTime as double seeing as string seeingConflict as boolean trans as string transConflict as boolean end class //---------------------------------------------------------------------------------------------- // Bucketing classes and routines for histogramming data. // class bucket label as string frequency as integer end class //---------------------------------------------------------------------------------------------- // Drop a value into an existing bucket or create a new bucket for it. Buckets are kept // sorted. // sub BucketValue(value as string, buckets() as bucket, byref nBuckets as integer) dim i, j as integer dim b as bucket dim cmp as integer, found as boolean found = false for i = 0 to nBuckets - 1 b = buckets(i) cmp = strcomp(value, b.label, 0) if cmp = 0 then found = true b.frequency = b.frequency + 1 exit elseif cmp < 0 then exit end if next if NOT found then b = new bucket b.label = value b.frequency = 1 redim buckets(nBuckets) for j = nBuckets downto i + 1 buckets(j) = buckets(j - 1) next buckets(i) = b nBuckets = nBuckets + 1 end if end sub //---------------------------------------------------------------------------------------------- // Add label, frequency and bar columns to list for a set of buckets. // sub AddBucketsToList(list as integer, buckets() as bucket, nBuckets as integer, colOffset as integer) dim b as bucket dim maxF as integer, pad as string maxF = 0.0001 // avoid div-by-zero for i = 0 to nBuckets - 1 b = buckets(i) AddToList(list, i + 1, colOffset, b.label) if b.frequency < 10 then pad = " " elseif b.frequency < 100 then pad = " " else pad = "" end if AddToList(list, i + 1, colOffset + 1, pad + Str(b.frequency)) if b.frequency > maxF then maxF = b.frequency end if next // // Generate a poor-man's bar chart // dim factor as double, normalized as integer, j as integer factor = 10 / maxF for i = 0 to nBuckets - 1 b = buckets(i) normalized = Round(b.frequency * factor) pad = "" for j = 1 to normalized pad = pad + chr(187) next AddToList(list, i + 1, colOffset + 2, pad) next end sub //---------------------------------------------------------------------------------------------- // Main script. // try // Be a good citizen // // Throw up a dialog to see what sites the user wants the report generated from. // const reportOnRadioBtns = "Report On:" const sitesCheckList = "For Sites:" dim cancelled as boolean cancelled = false dim current as SiteResource, siteFlags() as integer, i as integer current = CurrentSite if current = nil then current = DefaultSite end if redim siteFlags(nSites - 1) for i = 1 to nSites if current <> nil AND Site(i).Name = current.Name then siteFlags(i - 1) = 1 else siteFlags(i - 1) = 0 end if next SetCheckListParameter(sitesCheckList, siteFlags, Sites) if NOT EditParameters("Conditions Report") then exit end if siteFlags = GetCheckListParameter(sitesCheckList) // // Bucket observations into distinct nights // StartProgress("Collecting Observations...", true, nGlobalObservations) dim records(-1) as conditions dim nRecords as integer nRecords = 0 dim i, k as integer, obs as APGlobalObservation for i = 1 to nGlobalObservations if UpdateProgress(i) then cancelled = true exit end if obs = GlobalObservation(i) dim seeing, trans as string seeing = obs.Seeing trans = NthField(obs.Transparency, " ", 1) if siteFlags(SiteIndex(obs.site) - 1) = 1 then // Check to see if DateTime matches an existing "night" dim upper, lower, middle, cmp as integer dim found as boolean, r as conditions found = false lower = 0 upper = nRecords while NOT found AND upper > lower middle = (lower + upper) / 2 r = records(middle) cmp = CompareDateTimes(obs.DateTime, r.dateTime) if cmp < 0 then upper = middle elseif cmp > 0 then lower = middle + 1 middle = middle + 1 else found = true if r.seeing <> seeing then r.seeingConflict = true end if if r.trans <> trans then r.transConflict = true end if exit end if wend if NOT found then // Enter a new night. Note that records are kept sorted to allow binary // searching (see above). redim records(nRecords) for k = nRecords downto middle + 1 records(k) = records(k - 1) next nRecords = nRecords + 1 r = new conditions r.dateTime = obs.DateTime r.seeing = seeing r.seeingConflict = false r.trans = trans r.transConflict = false records(middle) = r end if end if next StopProgress() if cancelled then exit // // Histogram data // if nRecords > 500 then StartProgress("Generating Histogram...", true, nRecords) end if dim seeingBuckets(-1) as bucket dim nSeeingBuckets as integer dim transBuckets(-1) as bucket dim nTransBuckets as integer nSeeingBuckets = 0 nTransBuckets = 0 for i = 0 to nRecords - 1 if nRecords > 500 AND UpdateProgress(i) then cancelled = true exit end if found = false BucketValue(records(i).seeing, seeingBuckets, nSeeingBuckets) BucketValue(records(i).trans, transBuckets, nTransBuckets) next if nRecords > 500 then StopProgress() if cancelled then exit end if // // Generate Report // // Generate a coma-delimited list of sites for report title dim siteNames as string, first as boolean first = true for i = 1 to nSites if siteFlags(i - 1) = 1 then if NOT first then siteNames = siteNames + ", " end if first = false siteNames = siteNames + Site(i).Name end if next dim list as integer dim reportTitle as string reportTitle = "Conditions Report for " + Str(nRecords + 1) + " Nights at " + siteNames list = NewList(reportTitle) ListHeading(list, 1, "Seeing", 3) ListHeading(list, 2, "Frequency", 2) ListHeading(list, 3, "Graph") ListHeading(list, 4, " ") ListHeading(list, 5, "Transparency", 3) ListHeading(list, 6, "Frequency", 2) ListHeading(list, 7, "Graph") AddBucketsToList(list, seeingBuckets, nSeeingBuckets, 1) AddBucketsToList(list, transBuckets, nTransBuckets, 5) catch StopProgress() // just in case exception was thrown during data collection print "My bad. Seeing Report script generated an exception." end try