class TransSubSeqProp(Proposal): """ This class is here to describe a Transient Objects case scenario. """ def __init__(self, lsstDB, propConf, propName, propFullName, sky, weather, sessionID, filters, targetList=None, dbTableDict=None, log=False, logfile='./TransSubSeqProp.log', verbose=0, transientConf=DefaultNEAConfigFile): """ Standard initializer. lsstDB LSST DB access object propConf file name containing the instance's configuration data propName proposal name sky: an AsronomycalSky instance. weather: a Weather instance. sessionID: An integer identifying this particular run. filters: a Filters instance targetList: the name (with path) of the TEXT file containing the field list. It is assumed that the target list is a three column list of RA, Dec and field ID. RA and Dec are assumed to be in decimal degrees; filed ID is assumed to be an integer uniquely identifying any give field. dbTableDict: log False if not set, else: log = logging.getLogger("...") logfile Name (and path) of the desired log file. Defaults "./NearEarthProp.log". verbose: Log verbosity: -1=none, 0=minimal, 1=wordy, >1=verbose transientConf: Near Earth Asteroid Configuration file """ super(TransSubSeqProp, self).__init__(lsstDB=lsstDB, propConf=propConf, propName=propName, propFullName=propFullName, sky=sky, weather=weather, sessionID=sessionID, filters=filters, targetList=targetList, dbTableDict=dbTableDict, log=log, logfile=logfile, verbose=verbose) self.lsstDB = lsstDB self.verbose = verbose self.dbTableDict = dbTableDict # DataBase specifics self.dbTable = self.dbTableDict['field'] self.dbRA = 'fieldRA' self.dbDec = 'fieldDec' self.dbID = 'fieldID' self.winners = [] self.loosers = [] self.obsHistory = None # self.seqHistory = None self.sessionID = sessionID # self.targets is a convenience dictionary. Its keys are # fieldIDs, its values are the corresponding RA and Dec. self.targets = {} self.tonightTargets = {} self.sequences = {} self.tonightSubseqsForTarget = {} # Create the ObsHistory instance and cleanup any leftover self.obsHistory = ObsHistory(lsstDB=self.lsstDB, dbTableDict=self.dbTableDict, log=self.log, logfile=self.logfile, verbose=self.verbose) self.obsHistory.cleanupProposal(self.propID, self.sessionID) # Create the SeqHistory instance and cleanup any leftover # self.seqHistory = SeqHistory (lsstDB=self.lsstDB, # dbTableDict=self.dbTableDict, # log=self.log, # logfile=self.logfile, # verbose=self.verbose) # self.seqHistory.cleanupProposal (self.propID, self.sessionID) self.exclusiveBlockNeeded = False self.exclusiveObs = None self.exclusiveField = None self.exclusiveSubseq = None self.SeqCount = 0 return def start(self): """ Activate the TransientProp instance. """ # Removes the subsequences that require 0 events N = len(self.subSeqName) for n in range(N): ix = N - n - 1 if self.subSeqEvents[ix] == 0: self.subSeqName.pop(ix) self.subSeqNested.pop(ix) self.subSeqFilters.pop(ix) self.subSeqExposures.pop(ix) self.subSeqEvents.pop(ix) self.subSeqMaxMissed.pop(ix) self.subSeqInterval.pop(ix) self.subSeqWindowStart.pop(ix) self.subSeqWindowMax.pop(ix) self.subSeqWindowEnd.pop(ix) return def ComplyToFilterChangeBurstConstraint(self, filterBurstNumber, filterBurstTime, visitTime, readoutTime, filterTime): N = len(self.subSeqName) for n in range(N): subFilters = self.subSeqFilters[n].split(',') nfilters = len(subFilters) if nfilters > 1: print self.propConf print self.subSeqName[n] print subFilters subVisits = self.subSeqExposures[n].split(',') print subVisits T = [] for k in range(nfilters): tk = 0 if k > 0: tk += filterTime tk += int(subVisits[k]) * visitTime + (int(subVisits[k]) - 1) * readoutTime T.append(tk) print T numIdxToCheck = nfilters - 1 if numIdxToCheck >= filterBurstNumber: for startIdx in range(0, numIdxToCheck - filterBurstNumber + 1): tt = 0 for idx in range(startIdx, startIdx + filterBurstNumber): tt += T[idx] if tt < filterBurstTime: print "REJECTED %f < %f" % (tt, filterBurstTime) return False return True def startNight(self, dateProfile, moonProfile, startNewLunation, randomizeSequencesSelection, nRun, mountedFiltersList): super(TransSubSeqProp, self).startNight(dateProfile, moonProfile, startNewLunation, mountedFiltersList) (date, mjd, lst_RAD) = dateProfile runProgress = date / YEAR / nRun self.tonightTargets = self.targets.copy() # deletes all sequences that did not start while the fields were # in the region for starting new sequences. notstarted = 0 for fieldID in self.sequences.keys(): if fieldID not in self.targetsNewSeq.keys(): if self.sequences[fieldID].IsIdle(): # self.log.info('%sProp: startNight() deleted sequence field=%d at progress=%.3f%% ' # 'state=%d nevents=%d' % (self.propFullName, fieldID, # 100*self.sequences[fieldID].GetProgress(), # self.sequences[fieldID].state, # self.sequences[fieldID].nAllEvents)) notstarted += 1 del self.sequences[fieldID] # counts the active sequences in the target region currentActiveSequences = 0 coaddedProgress = 0.0 coaddedNumber = 0 for fieldID in self.sequences.keys(): if fieldID in self.tonightTargets.keys(): coaddedProgress += self.sequences[fieldID].GetProgress() coaddedNumber += 1 if (not self.sequences[fieldID].IsLost()) and (not self.sequences[fieldID].IsComplete()): currentActiveSequences += 1 # creates the sequence object for all the new fields in the restricted area newseq = 0 restartedlost = 0 restartedcomplete = 0 keptsequences = 0 #listOfNewFields=self.targetsNewSeq.keys() listOfNewFields = sorted(self.targetsNewSeq.iterkeys()) while (len(listOfNewFields) > 0 and currentActiveSequences < self.maxNumberActiveSequences and (coaddedProgress / max(coaddedNumber, 1) > runProgress or currentActiveSequences < self.minNumberActiveSequences)): if randomizeSequencesSelection: fieldID = random.choice(listOfNewFields) else: fieldID = listOfNewFields[0] listOfNewFields.remove(fieldID) # create a new sequence object if fieldID not in self.sequences.keys(): self.SeqCount += 1 self.sequences[fieldID] = SuperSequence(self.propID, fieldID, self.SeqCount, self.WLtype, self.numGroupedVisits, self.masterSubSequence, self.subSeqName, self.subSeqNested, self.subSeqFilters, self.subSeqExposures, self.subSeqEvents, self.subSeqMaxMissed, self.subSeqInterval, self.subSeqWindowStart, self.subSeqWindowMax, self.subSeqWindowEnd, self.overflowLevel, self.progressToStartBoost, self.maxBoostToComplete) coaddedNumber += 1 newseq += 1 currentActiveSequences += 1 # was sequence lost? elif self.sequences[fieldID].IsLost(): if self.restartLostSequences: self.SeqCount += 1 self.sequences[fieldID].Restart(self.SeqCount) restartedlost += 1 currentActiveSequences += 1 else: # ZZZZ - mm debug 2nd delete of tonightTargets # print "Prop[%d].startNight() while targetsNewSeq: seq lost: delete "\ # "self.tonightTargets[%d] date = %d" % (self.propID, fieldID, date) del self.tonightTargets[fieldID] # was sequence completed? elif self.sequences[fieldID].IsComplete(): if self.restartCompleteSequences and not self.overflow: self.SeqCount += 1 self.sequences[fieldID].Restart(self.SeqCount) restartedcomplete += 1 currentActiveSequences += 1 else: # ZZZZ - mm debug 2nd delete of tonightTargets # print "Prop[%d].startNight() while targetsNewSeq: seq complete: "\ # "delete self.tonightTargets[%d] date = %d" % (self.propID, fieldID, date) del self.tonightTargets[fieldID] #else: # prog = self.sequences[fieldID].GetProgress() # if prog >= 1.0: # print "seqnNum=%i fieldID=%i progress=%f" % (self.sequences[fieldID].seqNum, fieldID, prog, # str(self.sequences[fieldID].allHistory), # self.sequences[fieldID].state) # From the broad target area, just keep the fields # associated to a target that is not lost and not complete self.tonightSubseqsForTarget = {} for fieldID in self.tonightTargets.keys(): if fieldID in self.sequences.keys(): complete_seq = self.sequences[fieldID].IsComplete() and not self.overflow if self.sequences[fieldID].IsLost() or complete_seq: # ZZZZ - mm debug 2nd delete of tonightTargets # print "Prop[%d].startNight() for tonightTargets() in self.sequences: seq is lost or "\ # "complete: delete self.tonightTargets[%d] date = %d" % (self.propID, fieldID, # date) # print "how would we ever get here?" del self.tonightTargets[fieldID] else: keptsequences += 1 self.tonightSubseqsForTarget[fieldID] = list(self.sequences[fieldID].subSeqName) # only pursue targets that are already started sequences else: # ZZZZ - mm debug 2nd delete of tonightTargets # print "TSS.startNight() for tonightTargets() and not in self.sequences: delete "\ # "self.tonightTargets[%d] date = %d" % (fieldID, date) del self.tonightTargets[fieldID] if coaddedNumber > 0: self.globalProgress = coaddedProgress / coaddedNumber else: self.globalProgress = 0.0 if self.log: self.log.info('%sProp: startNight() propID=%d Sequences: new=%i deletedidle=%i ' 'restartedlost=%i restartedcomplete=%i total=%i targetprogress=%.3f%% ' 'runprogress=%.3f%%' % (self.propFullName, self.propID, newseq, notstarted, restartedlost, restartedcomplete, keptsequences, 100 * self.globalProgress, 100 * runProgress)) return def GetProgressPerFilter(self): coaddedNumber = 0 coaddedSubseqProgress = {} progressFilter = {} numsubseFilter = {} # for subseq in self.subSeqName: # coaddedSubseqProgress[subseq] = 0 for fieldID in self.sequences.keys(): if not self.sequences[fieldID].IsLost(): coaddedNumber += 1 for subseq in self.sequences[fieldID].subSeqName: progress = self.sequences[fieldID].GetProgress(subseq) if subseq in coaddedSubseqProgress.keys(): coaddedSubseqProgress[subseq] += progress else: coaddedSubseqProgress[subseq] = progress for filter in self.sequences[fieldID].GetFilterListForSubseq(subseq): if filter in progressFilter.keys(): progressFilter[filter] += progress numsubseFilter[filter] += 1 else: progressFilter[filter] = progress numsubseFilter[filter] = 1 if coaddedNumber > 0: for subseq in coaddedSubseqProgress.keys(): coaddedSubseqProgress[subseq] /= coaddedNumber if self.log: for subseq in coaddedSubseqProgress.keys(): self.log.info('%sProp: GetProgressPerFilter() propID=%d Sub-Sequence progress: %20s = %.3f%%' % (self.propFullName, self.propID, subseq, 100 * coaddedSubseqProgress[subseq])) # progressFilter = {} # numsubseFilter = {} # for ix in range(len(self.subSeqName)): # subseq = self.subSeqName[ix] # for filter in self.subSeqFilters[ix].split(','): # if filter != '': # if filter in progressFilter.keys(): # progressFilter[filter] += coaddedSubseqProgress[subseq] # numsubseFilter[filter] += 1 # else: # progressFilter[filter] = coaddedSubseqProgress[subseq] # numsubseFilter[filter] = 1 for filter in progressFilter.keys(): progressFilter[filter] /= numsubseFilter[filter] if self.log: for filter in progressFilter.keys(): self.log.info('%sProp: GetProgressPerFilter() propID=%d Filter progress: %10s = %.3f%%' % (self.propFullName, self.propID, filter, 100 * progressFilter[filter])) return progressFilter def MissEvent(self, date, mjd, fieldID, subseq, obsHistID): self.sequences[fieldID].MissEvent(date, subseq, obsHistID) if self.log and self.verbose > 0 and not self.sequences[fieldID].IsLost(): t_secs = date % 60 t_mins = (date % 3600) / 60 t_hour = (date % 86400) / 3600 t_days = date / 86400 progress = 100 * self.sequences[fieldID].GetProgress() self.log.info('%sProp: suggestObs() subevent MISSED for propID=%d field=%i subseq=%s ' 't=%dd%02dh%02dm%02ds progress=%i%%' % (self.propFullName, self.propID, fieldID, subseq, t_days, t_hour, t_mins, t_secs, progress)) filter = self.sequences[fieldID].GetNextFilter(subseq) obs = self.obsPool[fieldID][filter] obs.propID = self.propID obs.seqn = self.sequences[fieldID].seqNum obs.subsequence = subseq obs.pairNum = self.sequences[fieldID].GetPairNum(subseq) obs.date = date obs.mjd = mjd super(TransSubSeqProp, self).missObservation(obs) return def suggestObs(self, dateProfile, n=100, exclusiveObservation=None, minDistance2Moon=0.0, rawSeeing=0.0, seeing=0.0, transparency=0.0, sdnight=0, sdtime=0): """ Return the list of (at most) the n (currently) higher ranking observations. Input dateProfile current date profile of: (date,mjd,lst_RAD) where: date simulated time (s) mjd lst_RAD local sidereal time (radians) moonProfile current moon profile of: (moonRA_RAD,moonDec_RAD,moonPhase_PERCENT) moonPhase current moon phase in range [0-100] n number of observations to return. Return An array of the (at most) n highest ranking observations, ordered from the highest ranking obs to the lowest. """ if self.log and self.verbose > 1: self.log.info('%sProp: suggestObs() propID=%d' % (self.propFullName, self.propID)) # Copy the input vars # inFieldID = skyfields # inproximity = proximity # intargetProfiles = targetProfiles (date, mjd, lst_RAD) = dateProfile (moonRA_RAD, moonDec_RAD, moonPhase_PERCENT) = self.schedulingData.moonProfile[sdnight] # Check the start/end of observing cycle. # For NEA the lunation is checked if self.CheckObservingCycle(date): # Create a priority queue to choose the best n obs self.clearSuggestList() # If in an exclusive block, no new observation candidates. If this # proposal originated request, it should re-suggest observation. if exclusiveObservation is not None: # adjust counter for one obs # self.reuseRanking -= 1 if exclusiveObservation.propID == self.propID: # The exclusive block is for this proposal so we just suggest our exclusive observation fieldID = exclusiveObservation.fieldID subseq = self.exclusiveSubseq rank = 1.0 # i = inFieldID.index (fieldID) #airmass = self.schedulingData.airmass[fieldID][sdtime] filter = self.sequences[fieldID].GetNextFilter(subseq) #print filter exclusiveBlockRequired = self.sequences[fieldID].GetExclusiveBlockNeed(subseq) #print "exclusiveBlockRequired = %s" % (exclusiveBlockRequired) recordFieldFilter = self.obsPool[fieldID][filter] recordFieldFilter.propID = self.propID recordFieldFilter.subsequence = subseq recordFieldFilter.seqn = self.sequences[fieldID].seqNum recordFieldFilter.pairNum = self.sequences[fieldID].GetPairNum(subseq) recordFieldFilter.date = date recordFieldFilter.mjd = mjd recordFieldFilter.night = sdnight recordFieldFilter.exposureTime = self.exposureTime recordFieldFilter.propRank = rank recordFieldFilter.maxSeeing = self.exclusiveObs.maxSeeing recordFieldFilter.rawSeeing = self.exclusiveObs.rawSeeing recordFieldFilter.seeing = self.exclusiveObs.seeing recordFieldFilter.transparency = self.exclusiveObs.transparency recordFieldFilter.cloudSeeing = self.exclusiveObs.cloudSeeing recordFieldFilter.airmass = self.exclusiveObs.airmass recordFieldFilter.skyBrightness = self.exclusiveObs.skyBrightness recordFieldFilter.lst = lst_RAD recordFieldFilter.altitude = self.exclusiveObs.altitude recordFieldFilter.azimuth = self.exclusiveObs.azimuth recordFieldFilter.distance2moon = self.exclusiveObs.distance2moon recordFieldFilter.moonRA = self.exclusiveObs.moonRA recordFieldFilter.moonDec = self.exclusiveObs.moonDec recordFieldFilter.moonAlt = self.exclusiveObs.moonAlt recordFieldFilter.moonPhase = self.exclusiveObs.moonPhase recordFieldFilter.exclusiveBlockRequired = exclusiveBlockRequired self.addToSuggestList(recordFieldFilter) return self.getSuggestList(1) else: # The exclusive block is not for this proposal so we don't propose observations # but we must update the ranking and availability of the exclusive observation for # correct serendipity if exclusiveObservation.fieldID in self.tonightTargets.keys(): listOfFieldsToEvaluate = [exclusiveObservation.fieldID] else: listOfFieldsToEvaluate = [] # return [] numberOfObsToPropose = 0 else: # Normal observation block, all proposals competing # If not time to rerank fields, return no suggestions. # if self.reuseRanking > 1: # self.reuseRanking -= 1 # return [] #listOfFieldsToEvaluate = self.tonightTargets.keys() listOfFieldsToEvaluate = sorted(self.tonightTargets.iterkeys()) numberOfObsToPropose = n # ZZZ - This block needs attention. Do we get here? Does it make sense? - mm if self.exclusiveBlockNeeded: # We needed an exclusive block to complete the current event # so we miss this event and evaluate if the sequence is missed or complete fieldID = self.exclusiveField subseq = self.exclusiveSubseq self.exclusiveBlockNeeded = False obsHist = self.lsstDB.addMissedObservation(self.sequences[fieldID].GetNextFilter(subseq), date, mjd, sdnight, lst_RAD, self.sessionID, fieldID) self.MissEvent(date, mjd, fieldID, subseq, obsHist.missedHistID) fields_received = len(listOfFieldsToEvaluate) fields_invisible = 0 fields_moon = 0 events_waiting = 0 events_proposed = 0 events_missed = 0 seq_lost = 0 seq_completed = 0 events_nottonight = 0 events_nofilter = 0 events_noseeing = 0 for fieldID in listOfFieldsToEvaluate: fieldRecordList = [] # ra and dec variables are unused!!!!! #ra = self.tonightTargets[fieldID][0] #dec = self.tonightTargets[fieldID][1] #i = inFieldID.index (fieldID) if fieldID == self.last_observed_fieldID and self.last_observed_wasForThisProposal and \ not self.AcceptConsecutiveObs: continue airmass = self.schedulingData.airmass[sdtime][fieldID] if airmass > self.maxAirmass: if self.log and self.verbose > 2: self.log.info('%sProp: suggestObs() propID=%d field=%i too low:%f' % (self.propFullName, self.propID, fieldID, airmass)) fields_invisible += 1 continue distance2moon = self.schedulingData.dist2moon[sdtime][fieldID] if distance2moon < minDistance2Moon: fields_moon += 1 # remove the target for the rest of the night if it is too close to the moon # ZZZZ - mm debug 2nd delete of tonightTargets # print "Prop[%d].suggestObs():too close to moon - delete self.tonightTargets[%d] date = %d" \ # % (self.propID, fieldID, date) del self.tonightTargets[fieldID] continue # if not self.sequences[fieldID].HasEventsTonight(date): # seq_nottonight += 1 # del self.tonightTargets[fieldID] # continue #............................................................. # Gets the list of possible filters based on the sky brightness skyBrightness = self.schedulingData.brightness[sdtime][fieldID] allowedFilterList = self.allowedFiltersForBrightness(skyBrightness) filterSeeingList = self.filters.computeFilterSeeing(seeing, airmass) #rankForFilters = self.RankFilters(fieldID, filterSeeingList) #............................................................. for subseq in self.tonightSubseqsForTarget[fieldID]: # Prevents that a lost sequence due to a missed event # keeps beeing evaluated for the other subsequences # wasting time and triggering an error when deleting # the already deleted field from the target list. if self.sequences[fieldID].IsLost(): continue allfiltersavailable = True for f in self.sequences[fieldID].GetFilterListForSubseq(subseq): if f not in allowedFilterList: allfiltersavailable = False events_nofilter += 1 elif filterSeeingList[f] > self.FilterMaxSeeing[f]: allfiltersavailable = False events_noseeing += 1 if allfiltersavailable is False: continue # Boost factor according to the remaining observable days on sky if self.DaysLeftToStartBoost > 0.0 and self.rankDaysLeftMax != 0.0: observableDaysLeft = max((self.ha_twilight[fieldID] + self.ha_maxairmass) * 15.0, 0.0) rankDaysLeft = max(1.0 - observableDaysLeft / self.DaysLeftToStartBoost, 0.0) else: rankDaysLeft = 0.0 if self.WLtype or self.sequences[fieldID].IsActive(subseq): (rankTime, timeWindow) = self.sequences[fieldID].RankTimeWindow(subseq, date) rankLossRisk = max(1.0 - 0.5 * self.sequences[fieldID].GetRemainingAllowedMisses(subseq), 0.0) elif self.sequences[fieldID].IsIdle(subseq): rankTime = self.rankIdleSeq / self.rankTimeMax timeWindow = True rankLossRisk = 0.0 else: rankTime = 0.0 timeWindow = False rankLossRisk = 0.0 if rankTime == -0.1: events_nottonight += 1 self.tonightSubseqsForTarget[fieldID].remove(subseq) elif rankTime > 0.0: events_proposed += 1 # print 'ha_twilight=' + str(self.ha_twilight[fieldID]) + ' ha_maxairmass='\ # + str(self.ha_maxairmass) + ' observableDaysLeft=' + str(observableDaysLeft)\ # + ' rankDaysLeft=' + str(rankDaysLeft) if timeWindow: factor = self.rankTimeMax else: if self.globalProgress < 1.0: factor = self.rankIdleSeq / (1.0 - self.globalProgress) elif self.overflowLevel > 0.0: factor = self.rankIdleSeq / (self.overflowLevel / self.globalProgress) rank = rankTime * factor + rankLossRisk * self.rankLossRiskMax \ + rankDaysLeft * self.rankDaysLeftMax filter = self.sequences[fieldID].GetNextFilter(subseq) #print 'fieldID='+str(fieldID)+' subseq='+str(subseq)+' filter='+str(filter) exclusiveBlockRequired = self.sequences[fieldID].GetExclusiveBlockNeed(subseq) # Create the corresponding Observation recordFieldFilter = self.obsPool[fieldID][filter] #recordFieldFilter.sessionID = sessionID recordFieldFilter.propID = self.propID recordFieldFilter.subsequence = subseq #recordFieldFilter.fieldID = fieldID #recordFieldFilter.filter = filter recordFieldFilter.seqn = self.sequences[fieldID].seqNum recordFieldFilter.pairNum = self.sequences[fieldID].GetPairNum(subseq) recordFieldFilter.date = date recordFieldFilter.mjd = mjd recordFieldFilter.night = sdnight recordFieldFilter.exposureTime = self.exposureTime #recordFieldFilter.slewTime = slewTime #recordFieldFilter.rotatorSkyPos = 0.0 #recordFieldFilter.rotatorTelPos = 0.0 recordFieldFilter.propRank = rank #recordFieldFilter.finRank = finRank recordFieldFilter.maxSeeing = self.FilterMaxSeeing[filter] recordFieldFilter.rawSeeing = rawSeeing recordFieldFilter.seeing = filterSeeingList[filter] recordFieldFilter.transparency = transparency #recordFieldFilter.cloudSeeing = intargetProfiles[i][4] recordFieldFilter.airmass = airmass recordFieldFilter.skyBrightness = skyBrightness #recordFieldFilter.ra = ra #recordFieldFilter.dec = dec recordFieldFilter.lst = lst_RAD recordFieldFilter.altitude = self.schedulingData.alt[sdtime][fieldID] recordFieldFilter.azimuth = self.schedulingData.az[sdtime][fieldID] recordFieldFilter.parallactic = self.schedulingData.pa[sdtime][fieldID] recordFieldFilter.distance2moon = distance2moon recordFieldFilter.moonRA = moonRA_RAD recordFieldFilter.moonDec = moonDec_RAD #recordFieldFilter.moonAlt = intargetProfiles[i][8] recordFieldFilter.moonPhase = moonPhase_PERCENT recordFieldFilter.exclusiveBlockRequired = exclusiveBlockRequired fieldRecordList.append(recordFieldFilter) elif rankTime < 0.0: events_missed += 1 oh_filter = self.sequences[fieldID].GetNextFilter(subseq) obsHist = self.lsstDB.addMissedObservation(oh_filter, date, mjd, sdnight, lst_RAD, self.sessionID, fieldID) self.MissEvent(date, mjd, fieldID, subseq, obsHist.missedHistID) if self.sequences[fieldID].IsLost(): if self.log and self.verbose > 0: self.log.info('%sProp: suggestObs() sequence LOST for propID=%d field=%i ' 't=%.0f event missed' % (self.propFullName, self.propID, fieldID, date)) # Update the SeqHistory database seq = self.sequences[fieldID] seqHist = self.lsstDB.addSeqHistory(seq.date, date, seq.seqNum, seq.GetProgress(), seq.GetNumTargetEvents(), seq.GetNumActualEvents(), MAX_MISSED_EVENTS, 0, fieldID, self.sessionID, self.propID) for obsID in seq.GetListObsID(): self.lsstDB.addSeqHistoryObsHistory(seqHist.sequenceID, obsID, self.sessionID) for misID in seq.GetListMisID(): self.lsstDB.addSeqHistoryMissedHistory(seqHist.sequenceID, misID, self.sessionID) seq_lost += 1 # ZZZZ - mm debug 2nd delete of tonightTargets print "Prop[%d].suggestObs() seq lost: delete self.tonightTargets[%d] date = %d"\ % (self.propID, fieldID, date) del self.tonightTargets[fieldID] # Also remove the posible previously considered subsequences # as the whole sequence is now lost they must not be proposed. fieldRecordList = [] # it is also possible that the missed event was the last needed for completing the # sequence in such a case the sequence object determines the completion of the # sequence. elif self.sequences[fieldID].IsComplete(): self.CompleteSequence(fieldID, date) seq_completed += 1 fieldRecordList = [] else: # rankTime==0.0 events_waiting += 1 if self.tonightSubseqsForTarget[fieldID] == []: # ZZZZ - mm debug 2nd delete of tonightTargets # print "Prop[%d].suggestObs() no subseqs for target: delete self.tonightTargets[%d] "\ # "date = %d" % (self.propID, fieldID, date) del self.tonightTargets[fieldID] for record in fieldRecordList: self.addToSuggestList(record) if self.log and self.verbose > 0: self.log.info('%sProp: suggestObs() propID=%d : Fields received=%i invisible=%i moon=%i ' 'Events nottonight=%i waiting=%i nofilter=%i noseeing=%i proposed=%i missed=%i ' 'Sequences lost=%i completed=%i' % (self.propFullName, self.propID, fields_received, fields_invisible, fields_moon, events_nottonight, events_waiting, events_nofilter, events_noseeing, events_proposed, events_missed, seq_lost, seq_completed)) # Choose the n highest ranking observations # self.reuseRanking = self.reuseRankingCount return self.getSuggestList(numberOfObsToPropose) else: # The cycle has ended and next one hasn't started yet (full moon for NEA) return [] def getFieldCoordinates(self, fieldID): """ Given a fieldID, fetch the corresponding values for RA and Dec Input fieldID: a field identifier (long int) Return (ra, dec) in decimal degrees Raise Exception if fieldID is unknown. """ return self.targets[fieldID] def setMaxSeeing(self, seeing): """ Setter method for self.seeing Input seeing: float Return None """ # self.maxSeeing = float(seeing) return def setSlewTime(self, slewTime): """ Setter method for self.maxSlewTime Input slewTime: float Return None """ self.maxSlewTime = float(slewTime) return def closeObservation(self, observation, obsHistID, twilightProfile): """ Registers the fact that the indicated observation took place. This is, the corresponding event in the sequence of the indicated fieldID has been executed, and the sequence can continue. Input obs an Observation instance winslewTime slew time required for the winning observation Return None Raise Exception if Observation History update fails """ if not self.IsObservingCycle(): self.last_observed_wasForThisProposal = False return None # if self.log and self.verbose > 1: # self.log.info('%sProp: closeObservation()' % (self.propFullName)) obs = super(TransSubSeqProp, self).closeObservation(observation, obsHistID, twilightProfile) if obs is not None: self.sequences[obs.fieldID].ObserveEvent(obs.date, obs.subsequence, obsHistID) progress = self.sequences[obs.fieldID].GetProgress() if self.log and self.verbose > 0: t_secs = obs.date % 60 t_mins = (obs.date % 3600) / 60 t_hour = (obs.date % 86400) / 3600 t_days = obs.date / 86400 if self.sequences[obs.fieldID].IsEventInProgress(obs.subsequence): progrmod = '+' else: progrmod = '' self.log.info('%s: closeObservation() propID=%d field=%d filter=%s propRank=%.4f ' 'finRank=%.4f t=%dd%02dh%02dm%02ds progress=%d%s%%' % (self.propConf, self.propID, obs.fieldID, obs.filter, obs.propRank, obs.finRank, t_days, t_hour, t_mins, t_secs, int(100 * progress), progrmod)) if obs.exclusiveBlockRequired: self.exclusiveBlockNeeded = True self.exclusiveObs = copy.copy(obs) self.exclusiveField = obs.fieldID self.exclusiveSubseq = obs.subsequence else: self.exclusiveBlockNeeded = False # if sequence is complete, then deletes target from tonight's list. if progress == 1.0: self.CompleteSequence(obs.fieldID, obs.date) self.exclusiveBlockNeeded = False return obs def CompleteSequence(self, fieldID, date): # Update sequence history DB seq = self.sequences[fieldID] seqHist = self.lsstDB.addSeqHistory(seq.date, date, seq.seqNum, seq.GetProgress(), seq.GetNumTargetEvents(), seq.GetNumActualEvents(), SUCCESS, 0, fieldID, self.sessionID, self.propID) for obsID in seq.GetListObsID(): self.lsstDB.addSeqHistoryObsHistory(seqHist.sequenceID, obsID, self.sessionID) for misID in seq.GetListMisID(): self.lsstDB.addSeqHistoryMissedHistory(seqHist.sequenceID, misID, self.sessionID) if not self.overflow: # ZZZZ - mm debug 2nd delete of tonightTargets # print "Prop[%d].CompleteSequence() delete self.tonightTargets[%d] date = %d" % (self.propID, # fieldID, date) if fieldID in self.tonightTargets.keys(): del self.tonightTargets[fieldID] if self.log and self.verbose > 0: self.log.info('%sProp: CompleteSequence() sequence COMPLETE for propID=%d field=%d' % (self.propFullName, self.propID, fieldID)) return def FinishSequences(self, obsdate): """ Finishes the current sequences. """ if self.log: self.log.info('%sProp: FinishSequences()' % (self.propFullName)) for fieldID in self.sequences.keys(): if (not self.sequences[fieldID].IsComplete()) and (not self.sequences[fieldID].IsLost()): if self.log: self.log.info('%sProp: suggestObs() propID=%d sequence LOST for field=%i end of cycle' % (self.propFullName, self.propID, fieldID)) self.sequences[fieldID].Abort() # Update sequence history DB seq = self.sequences[fieldID] seqHist = self.lsstDB.addSeqHistory(seq.date, obsdate, seq.seqNum, seq.GetProgress(), seq.GetNumTargetEvents(), seq.GetNumActualEvents(), CYCLE_END, 0, fieldID, self.sessionID, self.propID) for obsID in seq.GetListObsID(): self.lsstDB.addSeqHistoryObsHistory(seqHist.sequenceID, obsID, self.sessionID) for misID in seq.GetListMisID(): self.lsstDB.addSeqHistoryMissedHistory(seqHist.sequenceID, misID, self.sessionID) return def closeProposal(self, time): """ Finishes the current sequences. """ if self.log: self.log.info('%sProp: closeProposal()' % (self.propFullName)) for fieldID in self.sequences.keys(): if (not self.sequences[fieldID].IsComplete()) and (not self.sequences[fieldID].IsLost()): if self.log: self.log.info('%sProp: closeProposal() propID=%d sequence LOST for field=%i end of ' 'simulation' % (self.propFullName, self.propID, fieldID)) #self.sequences[fieldID].Abort() # Update sequence history DB seq = self.sequences[fieldID] seqHist = self.lsstDB.addSeqHistory(seq.date, time, seq.seqNum, seq.GetProgress(), seq.GetNumTargetEvents(), seq.GetNumActualEvents(), SIMULATION_END, 0, fieldID, self.sessionID, self.propID) for obsID in seq.GetListObsID(): self.lsstDB.addSeqHistoryObsHistory(seqHist.sequenceID, obsID, self.sessionID) for misID in seq.GetListMisID(): self.lsstDB.addSeqHistoryMissedHistory(seqHist.sequenceID, misID, self.sessionID) # delete OlapField user-defined region table if self.userRegion[0] is not None: overlappingField = "OlapField_%d_%d" % (self.sessionID, self.propID) # Result from below is never used self.lsstDB.dropTable(overlappingField) return def RestartSequences(self): if self.log: self.log.info('%sProp: RestartFinishedSequences() propID=%d' % (self.propFullName, self.propID)) for fieldID in self.sequences.keys(): if self.sequences[fieldID].IsLost() or self.sequences[fieldID].IsComplete(): self.SeqCount += 1 self.sequences[fieldID].Restart(self.SeqCount) if self.log and self.verbose > 0: self.log.info('%sProp: RestartSequences() sequence for propID=%d field=%i restarted' % (self.propFullName, self.propID, fieldID)) return def updateTargetList(self, dateProfile, obsProfile, sky, fov): return
class WeakLensingProp(Proposal): """ This class is here to describe a simple case scenario: a Proposal type of object that only cares about seeing values and slew time. It does not care about particular fields, filters or anythin else, just seeing and slew time. """ def __init__(self, lsstDB, schedulingData, sky, weather, sessionID, filters, fov, weakLensConf=DefaultWLConfigFile, targetList=None, dbTableDict=None, log=True, logfile='./Proposal.log', verbose=0): """ Standard initializer. lsstDB: LSST DB Access object sky: an AsronomycalSky instance. weather: a Weather instance. sessionID: An integer identifying this particular run. filters: ... fov: FoV of the instrument. weakLensConf: Weak Lensing Proposal Configuration file exposureTime: Exposure time in seconds. maxSeeing: Maximum acceptable seeing. targetList: the name (with path) of the TEXT file containing the field list. It is assumed that the target list is a three column list of RA, Dec and field ID. RA and Dec are assumed to be in decimal degrees; filed ID is assumed to be an integer uniquely identifying any give field. dbTableDict: log ... logfile ... verbose: integer specifying the verbosity level (defaults to 0 meaning quite). """ super(WeakLensingProp, self).__init__(lsstDB=lsstDB, propConf=weakLensConf, propName='WL', propFullName='WeakLensing', sky=sky, weather=weather, sessionID=sessionID, filters=filters, targetList=targetList, dbTableDict=dbTableDict, log=log, logfile=logfile, verbose=verbose) self.lsstDB = lsstDB if (self.log and self.verbose > 1): self.log.info('WeakLensingProp: init() propID=%d' % (self.propID)) self.schedulingData = schedulingData self.weakLensConf = weakLensConf self.GoalVisitsFieldFilter = {} self.sky = sky config, pairs = readConfFile(weakLensConf) self.nextNight = 0 try: self.maxAirmass = config['MaxAirmass'] except: pass try: self.exposureTime = config['ExposureTime'] except: pass try: self.goalNVisits = config['NVisits'] except: self.goalNVisits = 30. try: filterVisits = config["Filter_Visits"] except: filterVisits = [] for filter in self.FilterNames: filterVisits.append(self.goalNVisits) # if singleton, make into a list of one if not isinstance(filterVisits, list): filterVisits = [filterVisits] for ix in range(len(self.FilterNames)): self.GoalVisitsFieldFilter[self.FilterNames[ix]] = filterVisits[ix] print 'GoalVisitsFieldFilter for propID=%d %s = %s' % ( self.propID, self.propFullName, str(self.GoalVisitsFieldFilter)) try: self.maxNeedAfterOverflow = config['MaxNeedAfterOverflow'] except: self.maxNeedAfterOverflow = 0.5 try: self.ProgressToStartBoost = config['ProgressToStartBoost'] except: self.ProgressToStartBoost = 1.0 try: self.MaxBoostToComplete = config['MaxBoostToComplete'] except: self.MaxBoostToComplete = 0.0 try: self.scale = config['RankScale'] except: self.scale = 0.1 try: self.taperB = config['taperB'] except: self.taperB = 180. try: self.taperL = config['taperL'] except: self.taperL = 5. try: self.peakL = config['peakL'] except: self.peakL = 25. try: self.deltaLST = config['deltaLST'] except: self.deltaLST = 60. try: self.maxReach = config['maxReach'] except: self.maxReach = 80. try: self.minTransparency = config['minTransparency'] except: self.minTransparency = 9. if (config.has_key('userRegion')): self.userRegion = config["userRegion"] else: self.userRegion = None if (not isinstance(self.userRegion, list)): # turn it into a list with one entry save = self.userRegion self.userRegion = [] self.userRegion.append(save) try: self.maxProximityBonus = config['MaxProximityBonus'] except: self.maxProximityBonus = 1.0 # store config to DB for line in pairs: storeParam(self.lsstDB, self.sessionID, self.propID, 'weakLensing', line['index'], line['key'], line['val']) self.dbField = dbTableDict['field'] if (self.goalNVisits <= 0): self.goalNVisits = 1. # Setup FieldFilter visit history for later ObsHistory DB ingest self.fieldVisits = {} self.lastFieldVisit = {} self.lastFieldFilterVisit = {} self.lastTarget = (0.0, 0.0) # Setup the relative importance of each filter. For # convenience we use a dictionary of the form {filter: N} # where N is the desired fraction of the total number of # observations for that particular filter. If all the filters # were equally desirable, then N would be always equal to # 1. / total_number_of_filters. n = 0. # filterNames now is assigned in the parent class using the # filters' configuration file. # If this proposal wants to observe in a subset of this filter # list, this subset should be specified in the proposal's # configuration file. self.visits = {} self.GoalVisitsField = 0 for filter in (self.FilterNames): if filter in self.GoalVisitsFieldFilter.keys(): self.visits[filter] = {} self.GoalVisitsField += self.GoalVisitsFieldFilter[filter] print('GoalVisitsField = %i' % (self.GoalVisitsField)) # DataBase specifics self.dbTableDict = dbTableDict self.dbField = self.dbTableDict['field'] # If user-defined regions have been defined, build new FieldDB if not (self.userRegion[0] == None): self.dbField = self.buildUserRegionDB(self.userRegion, self.dbField) print "WeakLensingProp:init: dbField: %s" % (self.dbField) self.winners = [] self.obsHistory = None self.sessionID = sessionID # self.targets is a convenience dictionary. Its keys are # fieldIDs, its values are the corresponding RA and Dec. self.targets = {} # Create the ObsHistory instance and cleanup any leftover self.obsHistory = ObsHistory(lsstDB=self.lsstDB, dbTableDict=self.dbTableDict, log=self.log, logfile=self.logfile, verbose=self.verbose) self.obsHistory.cleanupProposal(self.propID, self.sessionID) self.ha_maxairmass = sky.getHAforAirmass(self.maxAirmass) return def start(self): """ Activate the WeakLensingProp instance. """ if (self.log and self.verbose > 1): self.log.info('WeakLensingProp: start() propID=%d' % (self.propID)) # PAUSE yield hold, self return def startNight(self, dateProfile, moonProfile, startNewLunation, randomizeSequencesSelection, nRun, mountedFiltersList): super(WeakLensingProp, self).startNight(dateProfile, moonProfile, startNewLunation, mountedFiltersList) def GetProgressPerFilter(self): coaddedFilterProgress = {} allfields = [] filters = self.visits.keys() for filter in filters: coaddedFilterProgress[filter] = 0 fields = self.visits[filter].keys() allfields += fields for fieldID in fields: coaddedFilterProgress[filter] += self.visits[filter][fieldID] progressFilter = {} for filter in filters: if self.GoalVisitsFieldFilter[filter] > 0: if len(allfields) > 0: progressFilter[filter] = float( coaddedFilterProgress[filter]) / len( allfields) / self.GoalVisitsFieldFilter[filter] else: # no fileds observed for this filter progressFilter[filter] = 0.0 else: # no observations required for this filter progress[filter] = 1.0 if (self.log): for filter in progressFilter.keys(): self.log.info( '%sProp: GetProgressPerFilter() propID=%d Filter progress: %10s = %.3f%%' % (self.propFullName, self.propID, filter, 100 * progressFilter[filter])) return progressFilter def suggestObs(self, dateProfile, moonProfile, n=1, skyfields=None, proximity=None, targetProfiles=None, exclusiveObservation=None, minDistance2Moon=0.0): """ Return the list of (at most) the n (currently) higher ranking observations. Input dateProfile current date profile of: (date,mjd,lst_RAD) where: date simulated time (s) mjd lst_RAD local sidereal time (radians) moonProfile current moon profile of: (moonRA_RAD,moonDec_RAD,moonPhase_PERCENT) moonPhase current moon phase in range [0-100] n number of observations to return. skyfields array of fieldIDs (with index-synced to proximity) proximity array of proximity distance between current telescope position and each entry in skyfields (with index-synced to skyfields) targetProfiles: array of [AirMass, Sky brightness, Filterlist, transparency, cloudSeeing, distance2moon, altitude, rawSeeing, moonAltitude] values (dictionary-keyed to fieldID) Return An array of the (at most) n highest ranking observations, ordered from the highest ranking obs to the lowest. """ if (self.log and self.verbose > 1): self.log.info('WeakLensingProp: suggestObs() propID=%d' % (self.propID)) # If in an exclusive block, no new observation candidates. Return null. # if (exclusiveObservation != None): # adjust counter for one obs # self.reuseRanking -= 1 # return [] # else: # If not time to rerank fields, return no suggestions. # if self.reuseRanking > 1: # self.reuseRanking -= 1 # return [] if (exclusiveObservation != None): if exclusiveObservation.fieldID in self.targets.keys(): listOfFieldsToEvaluate = [exclusiveObservation.fieldID] else: listOfFieldsToEvaluate = [] numberOfObsToPropose = 0 else: listOfFieldsToEvaluate = sorted(self.targets.iterkeys()) numberOfObsToPropose = n # listOfFieldsToEvaluate = self.targets.keys() # listOfFieldsToEvaluate = sorted(self.targets.iterkeys()) # numberOfObsToPropose = n # Create a priority queue to choose the best n obs self.clearSuggestList() # Copy the input vars inFieldID = skyfields inproximity = proximity intargetProfiles = targetProfiles (date, mjd, lst_RAD) = dateProfile (moonRA_RAD, moonDec_RAD, moonPhase_PERCENT) = moonProfile # Get the number of times we observed in each field # The idea here is to make sure that, over one year, we end up # with a balanced set of observations. For the Weak Lensing # proposal, we want to observe each field-filter combo approx. # GOAL times/year. This means that we do not want to observe # each field-filter more than 6 times per lunation or once per # night. # numVisits is a dict of the form {filter: {fieldID: n}} # visits = self.obsHistory.getNVisitsPerFilterField (self.propID, # self.sessionID, fieldID=None) #.................. T o D o ................................. # Compute the normalization constant for SignalToNoise (SNR) ranking #.................. T o D o ................................. fields_received = len(listOfFieldsToEvaluate) fields_invisible = 0 fields_moon = 0 ffilter_allowed = 0 ffilter_badseeing = 0 ffilter_proposed = 0 # Adjust the partial rank so that we end with # self.sumFieldFilterGoal for all field/filter combos # Adjust the scaling needTonight = self.GoalVisitsTonight - self.VisitsTonight if needTonight > 0: GlobalNeedFactor = float(needTonight) / self.GoalVisitsTonight else: GlobalNeedFactor = (self.maxNeedAfterOverflow / (self.VisitsTonight - self.GoalVisitsTonight + 1)) / self.GoalVisitsTonight for fieldID in listOfFieldsToEvaluate: i = inFieldID.index(fieldID) ra = self.targets[fieldID][0] dec = self.targets[fieldID][1] if (fieldID == self.last_observed_fieldID) and ( self.last_observed_wasForThisProposal) and ( not self.AcceptConsecutiveObs): continue #----------------------------------------------------------- # Field cuts #----------------------------------------------------------- # First, discard all the targets which are not visible right now. airmass = intargetProfiles[i][0] if airmass > self.maxAirmass: fields_invisible += 1 if self.log and self.verbose > 1: self.log.info( 'TOSS: propID=%d field=%d WeakLensingProp: suggestObs(): too low:%f' % (self.propID, fieldID, airmass)) #DBGprint "Toss: Field: %d ra:%f dec:%f am:%f > 5 " % (fieldID,ra,dec,airmass) continue distance2moon = intargetProfiles[i][5] if distance2moon < minDistance2Moon: fields_moon += 1 # remove the target for the rest of the night if it is too close to the moon del self.targets[fieldID] continue nVisits = {} progress = {} progress_avg = 0.0 for filter in self.FilterNames: try: nVisits[filter] = self.visits[filter][fieldID] except: nVisits[filter] = 0. progress[filter] = nVisits[ filter] / self.GoalVisitsFieldFilter[filter] progress_avg += min(progress[filter], 1.0) / len( self.FilterNames) FieldNeedFactor = 1.0 - progress_avg if self.ProgressToStartBoost < progress_avg < 1.0: FieldNeedFactor += self.MaxBoostToComplete * ( progress_avg - self.ProgressToStartBoost) / ( 1.0 - self.ProgressToStartBoost) skyBrightness = intargetProfiles[i][1] allowedFilterList = self.allowedFiltersForBrightness(skyBrightness) filterSeeingList = intargetProfiles[i][2] #print ".....field:%d ra:%f dec:%f am:%f phs:%f brite:%f" % (fieldID, ra,dec, airmass, moonPhase, intargetProfiles[i][1]) , filterSeeingList for filter in allowedFilterList: ffilter_allowed += 1 #----------------------------------------------------------- # Field/filter cuts #----------------------------------------------------------- if filterSeeingList[filter] > self.FilterMaxSeeing[filter]: ffilter_badseeing += 1 #DBGprint "TOSS: fld:%d fltr:%s ra:%f dec%f airms:%f phs:%f airAdjSee:%f > maxSee:%f" % (fieldID,filter,ra,dec,airmass,moonPhase,filterSeeingList[filter],self.FilterMaxSeeing[filter]) if self.log and self.verbose > 1: self.log.info( 'TOSS: propID=%d field=%d filter=%s WeakLensingProp: suggestObs(): bad seeing:%f' % (self.propID, fieldID, filter, filterSeeingList[filter])) continue #----------------------------------------------------------- # Ranking #----------------------------------------------------------- # Assign the priority to the fields. The priority/rank is # reflecting the fact that we want to end up observing in # each filter with a given frequency (see above). # The partial rank for this field/filter varies between # 0 and 1. It is 0 if we already have self.filterVisits[filter] # visits. It is 1 if we have no visit... if GlobalNeedFactor > 0.0: if FieldNeedFactor > 0.0: if progress[filter] < 1.0: FilterNeedFactor = 1.0 - progress[filter] rank = self.scale * 0.5 * ( FieldNeedFactor + FilterNeedFactor) / GlobalNeedFactor else: rank = 0.0 else: FilterNeedFactor = ( self.maxNeedAfterOverflow / (nVisits[filter] - self.GoalVisitsFieldFilter[filter] + 1)) / self.GoalVisitsFieldFilter[filter] rank = self.scale * FilterNeedFactor / GlobalNeedFactor else: rank = 0.0 if (rank > 0.0): ffilter_proposed += 1 #print "WeakLensing", intargetProfiles[i] # Edit corresponding Observation instance in self.obsPool recordFieldFilter = self.obsPool[fieldID][filter] #recordFieldFilter.sessionID = sessionID #recordFieldFilter.propID = propID #recordFieldFilter.fieldID = fieldID #recordFieldFilter.filter = filter #recordFieldFilter.seqn = seqn recordFieldFilter.date = date recordFieldFilter.mjd = mjd #recordFieldFilter.exposureTime = exposureTime #recordFieldFilter.slewTime = slewTime #recordFieldFilter.rotatorSkyPos = 0.0 #recordFieldFilter.rotatorTelPos = 0.0 recordFieldFilter.propRank = rank #recordFieldFilter.finRank = finRank recordFieldFilter.maxSeeing = self.FilterMaxSeeing[filter] recordFieldFilter.rawSeeing = intargetProfiles[i][7] recordFieldFilter.seeing = filterSeeingList[filter] recordFieldFilter.transparency = intargetProfiles[i][3] recordFieldFilter.cloudSeeing = intargetProfiles[i][4] recordFieldFilter.airmass = airmass recordFieldFilter.skyBrightness = skyBrightness #recordFieldFilter.ra = ra #recordFieldFilter.dec = dec recordFieldFilter.lst = lst_RAD recordFieldFilter.altitude = intargetProfiles[i][6] recordFieldFilter.azimuth = intargetProfiles[i][9] recordFieldFilter.distance2moon = intargetProfiles[i][5] recordFieldFilter.moonRA = moonRA_RAD recordFieldFilter.moonDec = moonDec_RAD recordFieldFilter.moonAlt = intargetProfiles[i][8] recordFieldFilter.moonPhase = moonPhase_PERCENT self.addToSuggestList(recordFieldFilter, inproximity[i]) #print "WLRANK: f:%d am:%f see:%f brt:%f phs:%f dt:%d flt:%s rnk:%f" % (fieldID, airmass,filterSeeingList[filter],intargetProfiles[i][1],moonPhase, date, filter, rank) if self.log and self.verbose > 0: self.log.info( '%sProp: suggestObs() propID=%d : Fields received=%i invisible=%i moon=%i Field-Filters allowed=%i badseeing=%i proposed=%i' % (self.propFullName, self.propID, fields_received, fields_invisible, fields_moon, ffilter_allowed, ffilter_badseeing, ffilter_proposed)) # Chose the n highest ranking observations # self.reuseRanking = self.reuseRankingCount return self.getSuggestList(numberOfObsToPropose) def closeObservation(self, observation, obsHistID, twilightProfile): if (self.log and self.verbose > 1): self.log.info('WeakLensingProp: closeObservation() propID=%d' % (self.propID)) obs = super(WeakLensingProp, self).closeObservation(observation, obsHistID, twilightProfile) if obs != None: try: self.visits[obs.filter][obs.fieldID] += 1 except: self.visits[obs.filter][obs.fieldID] = 1 self.VisitsTonight += 1 progress = self.visits[obs.filter][ obs.fieldID] / self.GoalVisitsFieldFilter[obs.filter] if (self.log and self.verbose > 0): t_secs = obs.date % 60 t_mins = (obs.date % 3600) / 60 t_hour = (obs.date % 86400) / 3600 t_days = (obs.date) / 86400 self.log.info( 'WeakLensingProp: closeObservation() propID=%d field=%d filter=%s propRank=%.4f finRank=%.4f t=%dd%02dh%02dm%02ds progress=%d%%' % (self.propID, obs.fieldID, obs.filter, obs.propRank, obs.finRank, t_days, t_hour, t_mins, t_secs, int(100 * progress))) #print ('%i %i' % (self.visits[obs.filter][obs.fieldID], self.VisitsTonight)) return obs def updateTargetList(self, dateProfile, obsProfile, sky, fov): """ Update the list of potentially visible fields given a LST and a latitude. The range in coordinates of the selected fields is RA: [LST-60; LST+60] (degrees) Dec: [lat-60; lat+60] (degrees) This version uses Sun.py and computes RA limits at the nautical twilight. Input: dateProfile .... obsProfile .... sky AstronomicalSky instance fov Field of view of the telescope Return fields A dictionary of the form {fieldID: (ra, dec)} """ ## Benchmark memory use - start #m0 = memory() #r0 = resident() #s0 = stacksize() ##self.log.info("WL: updateTargetList entry: mem: %d resMem: %d stack: %d" % (m0, r0, s0)) if (self.log): self.log.info('Proposal:updateTargetList propID=%d' % (self.propID)) dbFov = 'fieldFov' dbRA = 'fieldRA' dbDec = 'fieldDec' #dbL = 'fieldGL' #dbB = 'fieldGB' dbID = 'fieldID' (date, mjd, lst_RAD) = dateProfile (lon_RAD, lat_RAD, elev_M, epoch_MJD, d1, d2, d3) = obsProfile # MJD -> calendar date (yy, mm, dd) = mjd2gre(mjd)[:3] # determine twilight times based on user param: TwilightBoundary s = Sun.Sun() (sunRise, sunSet) = s.__sunriset__(yy, mm, dd, lon_RAD * RAD2DEG, lat_RAD * RAD2DEG, self.twilightBoundary, 0) #(sunRise, sunSet) = s.nauticalTwilight (yy, mm, dd, lon_RAD*RAD2DEG, lat_RAD*RAD2DEG) # RAA following overkill for simulation #if (date >= sunSet): # Beginning of the night # (sunRise, dummy) = s.nauticalTwilight (yy, mm, dd+1, lon_DEG, lat_DEG) #else: # End of the night # (dummy, sunSet) = s.nauticalTwilight (yy, mm, dd-1, lon_DEG, lat_DEG) # Compute RA min (at twilight) date_MJD = int(mjd) + (sunSet / 24.) raMin = ( (slalib.sla_gmst(date_MJD) + lon_RAD) * RAD2DEG) - self.deltaLST # Compute RA max (at twilight) date_MJD = int(mjd) + (sunRise / 24.) raMax = ( (slalib.sla_gmst(date_MJD) + lon_RAD) * RAD2DEG) + self.deltaLST # Make sure that both raMin and raMax are in the [0; 360] range raMin = normalize(angle=raMin, min=0., max=360, degrees=True) raMax = normalize(angle=raMax, min=0., max=360, degrees=True) # self.targets is a convenience dictionary. Its keys are # fieldIDs, its values are the corresponding RA and Dec. fields = {} fovEpsilon1 = fov - .01 fovEpsilon2 = fov + .01 sql = 'SELECT %s, %s, %s from %s ' % (dbRA, dbDec, dbID, self.dbField) sql += 'WHERE %s BETWEEN %f AND %f AND ' % (dbFov, fovEpsilon1, fovEpsilon2) # subtract galactic exclusion zone taperB = self.taperB taperL = self.taperL peakL = self.peakL band = peakL - taperL if ((taperB != 0.) & (taperL != 0.)): sql += '( (fieldGL < 180. AND abs(fieldGB) > (%f - (%f * abs(fieldGL)) / %f) ) OR ' % ( peakL, band, taperB) sql += '(fieldGL > 180. AND abs(fieldGB) > (%f - (%f * abs(fieldGL-360.)) / %f))) AND ' % ( peakL, band, taperB) # subtract un-viewable sky if (raMax > raMin): sql += '%s BETWEEN %f AND %f AND ' % (dbRA, raMin, raMax) elif (raMax < raMin): sql += '(%s BETWEEN %f AND 360.0 OR ' % (dbRA, raMin) sql += '%s BETWEEN 0.0 AND %f) AND ' % (dbRA, raMax) else: sql += '%s BETWEEN 0.0 AND 360.0 AND ' % (dbRA) DecLimit = math.acos(1. / float(self.maxAirmass)) * RAD2DEG sql += '%s BETWEEN %f AND %f and %f < %s < %f order by FieldRA,FieldDec' % ( dbDec, (lat_RAD * RAD2DEG) - DecLimit, (lat_RAD * RAD2DEG) + DecLimit, -abs(self.maxReach), dbDec, abs(self.maxReach)) # Send the query to the DB (n, res) = self.lsstDB.executeSQL(sql) # Build the output dictionary for (ra, dec, fieldID) in res: fields[fieldID] = (ra, dec) self.targets = fields self.computeTargetsHAatTwilight(lst_RAD) self.NumberOfFieldsTonight = len(self.targets) #print('NumberOfFieldsTonight = %i' % (self.NumberOfFieldsTonight)) self.GoalVisitsTonight = self.GoalVisitsField * self.NumberOfFieldsTonight #print('Goal Visits with Tonight targets = %i' % (self.GoalVisitsTonight)) self.VisitsTonight = 0 for filter in self.visits.keys(): #print('visits in %s = %i' % (filter, len(self.visits[filter].keys()))) for field in self.visits[filter].keys(): if self.targets.has_key(field): self.VisitsTonight += self.visits[filter][field] #print field #print('Visits up to Tonight for propID=%d for current targets = %i' % (self.propID,self.VisitsTonight)) print('*** Found %d WL fields for propID=%d ***' % (len(res), self.propID)) ## Benchmark memory use - exit #m1 = memory() #r1 = resident() #s1 = stacksize() ##self.log.info("WL: updateTargetList:(entry:exit) mem: %d:%d resMem: %d:%d stack: %d:%d" % (m0,m1, r0,r1, s0,s1)) #print("WL: updateTargetList:(entry:exit) mem: %d:%d resMem: %d:%d stack: %d:%d" % (m0,m1, r0,r1, s0,s1)) self.schedulingData.updateTargets(fields, self.propID, dateProfile) return (fields) def closeProposal(self, time): # delete OlapField user-defined region table if not (self.userRegion[0] == None): overlappingField = "OlapField_%d_%d" % (self.sessionID, self.propID) result = self.lsstDB.dropTable(overlappingField) return
class WeakLensingProp (Proposal): """ This class is here to describe a simple case scenario: a Proposal type of object that only cares about seeing values and slew time. It does not care about particular fields, filters or anythin else, just seeing and slew time. """ def __init__ (self, lsstDB, schedulingData, sky, weather, sessionID, filters, fov, weakLensConf=DefaultWLConfigFile, targetList=None, dbTableDict=None, log=True, logfile='./Proposal.log', verbose=0): """ Standard initializer. lsstDB: LSST DB Access object sky: an AsronomycalSky instance. weather: a Weather instance. sessionID: An integer identifying this particular run. filters: ... fov: FoV of the instrument. weakLensConf: Weak Lensing Proposal Configuration file exposureTime: Exposure time in seconds. maxSeeing: Maximum acceptable seeing. targetList: the name (with path) of the TEXT file containing the field list. It is assumed that the target list is a three column list of RA, Dec and field ID. RA and Dec are assumed to be in decimal degrees; filed ID is assumed to be an integer uniquely identifying any give field. dbTableDict: log ... logfile ... verbose: integer specifying the verbosity level (defaults to 0 meaning quite). """ super (WeakLensingProp, self).__init__ (lsstDB=lsstDB, propConf=weakLensConf, propName='WL', propFullName='WeakLensing', sky=sky, weather=weather, sessionID=sessionID, filters=filters, targetList=targetList, dbTableDict=dbTableDict, log=log, logfile=logfile, verbose=verbose) self.lsstDB = lsstDB if (self.log and self.verbose > 1): self.log.info('WeakLensingProp: init() propID=%d' %(self.propID)) self.schedulingData = schedulingData self.weakLensConf = weakLensConf self.GoalVisitsFieldFilter = {} self.sky = sky config, pairs = readConfFile (weakLensConf) self.nextNight = 0 try: self.maxAirmass = config['MaxAirmass'] except: pass try: self.exposureTime = config['ExposureTime'] except: pass try: self.goalNVisits = config['NVisits'] except: self.goalNVisits = 30. try: filterVisits = config["Filter_Visits"] except: filterVisits = [] for filter in self.FilterNames: filterVisits.append(self.goalNVisits) # if singleton, make into a list of one if not isinstance (filterVisits, list): filterVisits = [filterVisits] for ix in range(len(self.FilterNames)): self.GoalVisitsFieldFilter[self.FilterNames[ix]] = filterVisits[ix] print 'GoalVisitsFieldFilter for propID=%d %s = %s' % (self.propID, self.propFullName, str(self.GoalVisitsFieldFilter)) try: self.maxNeedAfterOverflow = config['MaxNeedAfterOverflow'] except: self.maxNeedAfterOverflow = 0.5 try: self.ProgressToStartBoost = config['ProgressToStartBoost'] except: self.ProgressToStartBoost = 1.0 try: self.MaxBoostToComplete = config['MaxBoostToComplete'] except: self.MaxBoostToComplete = 0.0 try: self.scale = config['RankScale'] except: self.scale = 0.1 try: self.taperB = config['taperB'] except: self.taperB = 180. try: self.taperL = config['taperL'] except: self.taperL = 5. try: self.peakL = config['peakL'] except: self.peakL = 25. try: self.deltaLST = config['deltaLST'] except: self.deltaLST = 60. try: self.maxReach = config['maxReach'] except: self.maxReach = 80. try: self.minTransparency = config['minTransparency'] except: self.minTransparency = 9. if ( config.has_key ('userRegion')) : self.userRegion = config["userRegion"] else : self.userRegion = None if (not isinstance(self.userRegion,list)): # turn it into a list with one entry save = self.userRegion self.userRegion = [] self.userRegion.append(save) try: self.maxProximityBonus = config['MaxProximityBonus'] except: self.maxProximityBonus = 1.0 # store config to DB for line in pairs: storeParam (self.lsstDB, self.sessionID, self.propID, 'weakLensing', line['index'], line['key'], line['val']) self.dbField = dbTableDict['field'] if (self.goalNVisits <= 0): self.goalNVisits = 1. # Setup FieldFilter visit history for later ObsHistory DB ingest self.fieldVisits = {} self.lastFieldVisit = {} self.lastFieldFilterVisit = {} self.lastTarget = (0.0,0.0) # Setup the relative importance of each filter. For # convenience we use a dictionary of the form {filter: N} # where N is the desired fraction of the total number of # observations for that particular filter. If all the filters # were equally desirable, then N would be always equal to # 1. / total_number_of_filters. n = 0. # filterNames now is assigned in the parent class using the # filters' configuration file. # If this proposal wants to observe in a subset of this filter # list, this subset should be specified in the proposal's # configuration file. self.visits={} self.GoalVisitsField=0 for filter in (self.FilterNames): if filter in self.GoalVisitsFieldFilter.keys(): self.visits[filter]={} self.GoalVisitsField += self.GoalVisitsFieldFilter[filter] print('GoalVisitsField = %i' % (self.GoalVisitsField)) # DataBase specifics self.dbTableDict = dbTableDict self.dbField = self.dbTableDict['field'] # If user-defined regions have been defined, build new FieldDB if not (self.userRegion[0] == None) : self.dbField = self.buildUserRegionDB(self.userRegion,self.dbField) print "WeakLensingProp:init: dbField: %s" % (self.dbField) self.winners = [] self.obsHistory = None self.sessionID = sessionID # self.targets is a convenience dictionary. Its keys are # fieldIDs, its values are the corresponding RA and Dec. self.targets = {} # Create the ObsHistory instance and cleanup any leftover self.obsHistory = ObsHistory (lsstDB=self.lsstDB, dbTableDict=self.dbTableDict, log=self.log, logfile=self.logfile, verbose=self.verbose) self.obsHistory.cleanupProposal (self.propID, self.sessionID) self.ha_maxairmass = sky.getHAforAirmass(self.maxAirmass) return def start (self): """ Activate the WeakLensingProp instance. """ if (self.log and self.verbose > 1): self.log.info('WeakLensingProp: start() propID=%d' %(self.propID)) # PAUSE yield hold, self return def startNight(self,dateProfile,moonProfile,startNewLunation,randomizeSequencesSelection, nRun, mountedFiltersList): super (WeakLensingProp, self).startNight (dateProfile,moonProfile,startNewLunation, mountedFiltersList) def GetProgressPerFilter(self): coaddedFilterProgress = {} allfields = [] filters = self.visits.keys() for filter in filters: coaddedFilterProgress[filter] = 0 fields = self.visits[filter].keys() allfields += fields for fieldID in fields: coaddedFilterProgress[filter] += self.visits[filter][fieldID] progressFilter = {} for filter in filters: if self.GoalVisitsFieldFilter[filter] > 0: if len(allfields) > 0: progressFilter[filter] = float(coaddedFilterProgress[filter])/len(allfields)/self.GoalVisitsFieldFilter[filter] else: # no fileds observed for this filter progressFilter[filter] = 0.0 else: # no observations required for this filter progress[filter] = 1.0 if ( self.log ): for filter in progressFilter.keys(): self.log.info('%sProp: GetProgressPerFilter() propID=%d Filter progress: %10s = %.3f%%' % (self.propFullName, self.propID, filter, 100*progressFilter[filter])) return progressFilter def suggestObs (self, dateProfile, moonProfile, n=1, skyfields=None, proximity=None, targetProfiles=None, exclusiveObservation=None, minDistance2Moon=0.0): """ Return the list of (at most) the n (currently) higher ranking observations. Input dateProfile current date profile of: (date,mjd,lst_RAD) where: date simulated time (s) mjd lst_RAD local sidereal time (radians) moonProfile current moon profile of: (moonRA_RAD,moonDec_RAD,moonPhase_PERCENT) moonPhase current moon phase in range [0-100] n number of observations to return. skyfields array of fieldIDs (with index-synced to proximity) proximity array of proximity distance between current telescope position and each entry in skyfields (with index-synced to skyfields) targetProfiles: array of [AirMass, Sky brightness, Filterlist, transparency, cloudSeeing, distance2moon, altitude, rawSeeing, moonAltitude] values (dictionary-keyed to fieldID) Return An array of the (at most) n highest ranking observations, ordered from the highest ranking obs to the lowest. """ if (self.log and self.verbose > 1): self.log.info('WeakLensingProp: suggestObs() propID=%d' %(self.propID)) # If in an exclusive block, no new observation candidates. Return null. # if (exclusiveObservation != None): # adjust counter for one obs # self.reuseRanking -= 1 # return [] # else: # If not time to rerank fields, return no suggestions. # if self.reuseRanking > 1: # self.reuseRanking -= 1 # return [] if (exclusiveObservation != None): if exclusiveObservation.fieldID in self.targets.keys(): listOfFieldsToEvaluate = [exclusiveObservation.fieldID] else: listOfFieldsToEvaluate = [] numberOfObsToPropose = 0 else: listOfFieldsToEvaluate = sorted(self.targets.iterkeys()) numberOfObsToPropose = n # listOfFieldsToEvaluate = self.targets.keys() # listOfFieldsToEvaluate = sorted(self.targets.iterkeys()) # numberOfObsToPropose = n # Create a priority queue to choose the best n obs self.clearSuggestList() # Copy the input vars inFieldID = skyfields inproximity = proximity intargetProfiles = targetProfiles (date,mjd,lst_RAD) = dateProfile (moonRA_RAD,moonDec_RAD,moonPhase_PERCENT) = moonProfile # Get the number of times we observed in each field # The idea here is to make sure that, over one year, we end up # with a balanced set of observations. For the Weak Lensing # proposal, we want to observe each field-filter combo approx. # GOAL times/year. This means that we do not want to observe # each field-filter more than 6 times per lunation or once per # night. # numVisits is a dict of the form {filter: {fieldID: n}} # visits = self.obsHistory.getNVisitsPerFilterField (self.propID, # self.sessionID, fieldID=None) #.................. T o D o ................................. # Compute the normalization constant for SignalToNoise (SNR) ranking #.................. T o D o ................................. fields_received = len(listOfFieldsToEvaluate) fields_invisible = 0 fields_moon = 0 ffilter_allowed = 0 ffilter_badseeing = 0 ffilter_proposed = 0 # Adjust the partial rank so that we end with # self.sumFieldFilterGoal for all field/filter combos # Adjust the scaling needTonight = self.GoalVisitsTonight - self.VisitsTonight if needTonight > 0: GlobalNeedFactor = float(needTonight) / self.GoalVisitsTonight else: GlobalNeedFactor = (self.maxNeedAfterOverflow/(self.VisitsTonight-self.GoalVisitsTonight+1)) / self.GoalVisitsTonight for fieldID in listOfFieldsToEvaluate: i = inFieldID.index(fieldID) ra = self.targets[fieldID][0] dec = self.targets[fieldID][1] if (fieldID==self.last_observed_fieldID) and (self.last_observed_wasForThisProposal) and (not self.AcceptConsecutiveObs): continue #----------------------------------------------------------- # Field cuts #----------------------------------------------------------- # First, discard all the targets which are not visible right now. airmass = intargetProfiles[i][0] if airmass > self.maxAirmass : fields_invisible += 1 if self.log and self.verbose>1 : self.log.info('TOSS: propID=%d field=%d WeakLensingProp: suggestObs(): too low:%f' % (self.propID,fieldID,airmass)) #DBGprint "Toss: Field: %d ra:%f dec:%f am:%f > 5 " % (fieldID,ra,dec,airmass) continue distance2moon = intargetProfiles[i][5] if distance2moon < minDistance2Moon: fields_moon += 1 # remove the target for the rest of the night if it is too close to the moon del self.targets[fieldID] continue nVisits = {} progress = {} progress_avg = 0.0 for filter in self.FilterNames: try: nVisits[filter] = self.visits[filter][fieldID] except: nVisits[filter] = 0. progress[filter] = nVisits[filter] / self.GoalVisitsFieldFilter[filter] progress_avg += min(progress[filter],1.0)/len(self.FilterNames) FieldNeedFactor = 1.0 - progress_avg if self.ProgressToStartBoost < progress_avg < 1.0: FieldNeedFactor += self.MaxBoostToComplete*(progress_avg-self.ProgressToStartBoost)/(1.0-self.ProgressToStartBoost) skyBrightness = intargetProfiles[i][1] allowedFilterList = self.allowedFiltersForBrightness(skyBrightness) filterSeeingList = intargetProfiles[i][2] #print ".....field:%d ra:%f dec:%f am:%f phs:%f brite:%f" % (fieldID, ra,dec, airmass, moonPhase, intargetProfiles[i][1]) , filterSeeingList for filter in allowedFilterList: ffilter_allowed += 1 #----------------------------------------------------------- # Field/filter cuts #----------------------------------------------------------- if filterSeeingList[filter] > self.FilterMaxSeeing[filter] : ffilter_badseeing += 1 #DBGprint "TOSS: fld:%d fltr:%s ra:%f dec%f airms:%f phs:%f airAdjSee:%f > maxSee:%f" % (fieldID,filter,ra,dec,airmass,moonPhase,filterSeeingList[filter],self.FilterMaxSeeing[filter]) if self.log and self.verbose>1 : self.log.info('TOSS: propID=%d field=%d filter=%s WeakLensingProp: suggestObs(): bad seeing:%f' % (self.propID,fieldID,filter,filterSeeingList[filter])) continue #----------------------------------------------------------- # Ranking #----------------------------------------------------------- # Assign the priority to the fields. The priority/rank is # reflecting the fact that we want to end up observing in # each filter with a given frequency (see above). # The partial rank for this field/filter varies between # 0 and 1. It is 0 if we already have self.filterVisits[filter] # visits. It is 1 if we have no visit... if GlobalNeedFactor > 0.0: if FieldNeedFactor > 0.0: if progress[filter] < 1.0: FilterNeedFactor = 1.0 - progress[filter] rank = self.scale * 0.5*(FieldNeedFactor + FilterNeedFactor) / GlobalNeedFactor else: rank = 0.0 else: FilterNeedFactor = (self.maxNeedAfterOverflow/(nVisits[filter]-self.GoalVisitsFieldFilter[filter]+1)) / self.GoalVisitsFieldFilter[filter] rank = self.scale * FilterNeedFactor / GlobalNeedFactor else: rank = 0.0 if (rank >0.0): ffilter_proposed += 1 #print "WeakLensing", intargetProfiles[i] # Edit corresponding Observation instance in self.obsPool recordFieldFilter = self.obsPool[fieldID][filter] #recordFieldFilter.sessionID = sessionID #recordFieldFilter.propID = propID #recordFieldFilter.fieldID = fieldID #recordFieldFilter.filter = filter #recordFieldFilter.seqn = seqn recordFieldFilter.date = date recordFieldFilter.mjd = mjd #recordFieldFilter.exposureTime = exposureTime #recordFieldFilter.slewTime = slewTime #recordFieldFilter.rotatorSkyPos = 0.0 #recordFieldFilter.rotatorTelPos = 0.0 recordFieldFilter.propRank = rank #recordFieldFilter.finRank = finRank recordFieldFilter.maxSeeing = self.FilterMaxSeeing[filter] recordFieldFilter.rawSeeing = intargetProfiles[i][7] recordFieldFilter.seeing = filterSeeingList[filter] recordFieldFilter.transparency = intargetProfiles[i][3] recordFieldFilter.cloudSeeing = intargetProfiles[i][4] recordFieldFilter.airmass = airmass recordFieldFilter.skyBrightness = skyBrightness #recordFieldFilter.ra = ra #recordFieldFilter.dec = dec recordFieldFilter.lst = lst_RAD recordFieldFilter.altitude = intargetProfiles[i][6] recordFieldFilter.azimuth = intargetProfiles[i][9] recordFieldFilter.distance2moon = intargetProfiles[i][5] recordFieldFilter.moonRA = moonRA_RAD recordFieldFilter.moonDec = moonDec_RAD recordFieldFilter.moonAlt = intargetProfiles[i][8] recordFieldFilter.moonPhase = moonPhase_PERCENT self.addToSuggestList(recordFieldFilter, inproximity[i]) #print "WLRANK: f:%d am:%f see:%f brt:%f phs:%f dt:%d flt:%s rnk:%f" % (fieldID, airmass,filterSeeingList[filter],intargetProfiles[i][1],moonPhase, date, filter, rank) if self.log and self.verbose>0: self.log.info('%sProp: suggestObs() propID=%d : Fields received=%i invisible=%i moon=%i Field-Filters allowed=%i badseeing=%i proposed=%i' % (self.propFullName, self.propID, fields_received, fields_invisible, fields_moon, ffilter_allowed, ffilter_badseeing, ffilter_proposed)) # Chose the n highest ranking observations # self.reuseRanking = self.reuseRankingCount return self.getSuggestList(numberOfObsToPropose) def closeObservation (self, observation, obsHistID, twilightProfile): if (self.log and self.verbose > 1): self.log.info('WeakLensingProp: closeObservation() propID=%d' %(self.propID)) obs = super (WeakLensingProp, self).closeObservation(observation, obsHistID, twilightProfile) if obs != None: try: self.visits[obs.filter][obs.fieldID] += 1 except: self.visits[obs.filter][obs.fieldID] = 1 self.VisitsTonight += 1 progress = self.visits[obs.filter][obs.fieldID]/self.GoalVisitsFieldFilter[obs.filter] if (self.log and self.verbose>0): t_secs = obs.date%60 t_mins = (obs.date%3600)/60 t_hour = (obs.date%86400)/3600 t_days = (obs.date)/86400 self.log.info('WeakLensingProp: closeObservation() propID=%d field=%d filter=%s propRank=%.4f finRank=%.4f t=%dd%02dh%02dm%02ds progress=%d%%' % (self.propID, obs.fieldID, obs.filter, obs.propRank, obs.finRank, t_days, t_hour, t_mins, t_secs, int(100*progress))) #print ('%i %i' % (self.visits[obs.filter][obs.fieldID], self.VisitsTonight)) return obs def updateTargetList (self, dateProfile, obsProfile, sky, fov ): """ Update the list of potentially visible fields given a LST and a latitude. The range in coordinates of the selected fields is RA: [LST-60; LST+60] (degrees) Dec: [lat-60; lat+60] (degrees) This version uses Sun.py and computes RA limits at the nautical twilight. Input: dateProfile .... obsProfile .... sky AstronomicalSky instance fov Field of view of the telescope Return fields A dictionary of the form {fieldID: (ra, dec)} """ ## Benchmark memory use - start #m0 = memory() #r0 = resident() #s0 = stacksize() ##self.log.info("WL: updateTargetList entry: mem: %d resMem: %d stack: %d" % (m0, r0, s0)) if ( self.log): self.log.info ('Proposal:updateTargetList propID=%d' %(self.propID)) dbFov = 'fieldFov' dbRA = 'fieldRA' dbDec = 'fieldDec' #dbL = 'fieldGL' #dbB = 'fieldGB' dbID = 'fieldID' (date,mjd,lst_RAD) = dateProfile (lon_RAD,lat_RAD,elev_M,epoch_MJD,d1,d2,d3) = obsProfile # MJD -> calendar date (yy, mm, dd) = mjd2gre (mjd)[:3] # determine twilight times based on user param: TwilightBoundary s = Sun.Sun () (sunRise, sunSet) = s.__sunriset__ (yy, mm, dd, lon_RAD*RAD2DEG, lat_RAD*RAD2DEG,self.twilightBoundary,0) #(sunRise, sunSet) = s.nauticalTwilight (yy, mm, dd, lon_RAD*RAD2DEG, lat_RAD*RAD2DEG) # RAA following overkill for simulation #if (date >= sunSet): # Beginning of the night # (sunRise, dummy) = s.nauticalTwilight (yy, mm, dd+1, lon_DEG, lat_DEG) #else: # End of the night # (dummy, sunSet) = s.nauticalTwilight (yy, mm, dd-1, lon_DEG, lat_DEG) # Compute RA min (at twilight) date_MJD = int (mjd) + (sunSet / 24.) raMin = ((slalib.sla_gmst(date_MJD) + lon_RAD) * RAD2DEG) - self.deltaLST # Compute RA max (at twilight) date_MJD = int (mjd) + (sunRise / 24.) raMax = ((slalib.sla_gmst(date_MJD) + lon_RAD) * RAD2DEG) + self.deltaLST # Make sure that both raMin and raMax are in the [0; 360] range raMin = normalize (angle=raMin, min=0., max=360, degrees=True) raMax = normalize (angle=raMax, min=0., max=360, degrees=True) # self.targets is a convenience dictionary. Its keys are # fieldIDs, its values are the corresponding RA and Dec. fields = {} fovEpsilon1 = fov - .01 fovEpsilon2 = fov + .01 sql = 'SELECT %s, %s, %s from %s ' % (dbRA, dbDec, dbID, self.dbField) sql += 'WHERE %s BETWEEN %f AND %f AND ' % (dbFov, fovEpsilon1, fovEpsilon2) # subtract galactic exclusion zone taperB = self.taperB taperL = self.taperL peakL = self.peakL band = peakL - taperL if ( (taperB != 0.) & (taperL != 0.) ) : sql += '( (fieldGL < 180. AND abs(fieldGB) > (%f - (%f * abs(fieldGL)) / %f) ) OR ' % (peakL, band, taperB) sql += '(fieldGL > 180. AND abs(fieldGB) > (%f - (%f * abs(fieldGL-360.)) / %f))) AND ' % (peakL, band, taperB) # subtract un-viewable sky if (raMax > raMin): sql += '%s BETWEEN %f AND %f AND ' % (dbRA, raMin, raMax) elif (raMax < raMin): sql += '(%s BETWEEN %f AND 360.0 OR ' % (dbRA, raMin) sql += '%s BETWEEN 0.0 AND %f) AND ' % (dbRA, raMax) else: sql += '%s BETWEEN 0.0 AND 360.0 AND ' % (dbRA) DecLimit = math.acos(1./float(self.maxAirmass)) * RAD2DEG sql += '%s BETWEEN %f AND %f and %f < %s < %f order by FieldRA,FieldDec' % (dbDec, (lat_RAD*RAD2DEG)-DecLimit, (lat_RAD*RAD2DEG)+DecLimit, -abs(self.maxReach),dbDec,abs(self.maxReach)) # Send the query to the DB (n, res) = self.lsstDB.executeSQL (sql) # Build the output dictionary for (ra, dec, fieldID) in res: fields[fieldID] = (ra, dec) self.targets = fields self.computeTargetsHAatTwilight(lst_RAD) self.NumberOfFieldsTonight = len(self.targets) #print('NumberOfFieldsTonight = %i' % (self.NumberOfFieldsTonight)) self.GoalVisitsTonight = self.GoalVisitsField * self.NumberOfFieldsTonight #print('Goal Visits with Tonight targets = %i' % (self.GoalVisitsTonight)) self.VisitsTonight = 0 for filter in self.visits.keys(): #print('visits in %s = %i' % (filter, len(self.visits[filter].keys()))) for field in self.visits[filter].keys(): if self.targets.has_key(field): self.VisitsTonight += self.visits[filter][field] #print field #print('Visits up to Tonight for propID=%d for current targets = %i' % (self.propID,self.VisitsTonight)) print ('*** Found %d WL fields for propID=%d ***' % (len (res),self.propID)) ## Benchmark memory use - exit #m1 = memory() #r1 = resident() #s1 = stacksize() ##self.log.info("WL: updateTargetList:(entry:exit) mem: %d:%d resMem: %d:%d stack: %d:%d" % (m0,m1, r0,r1, s0,s1)) #print("WL: updateTargetList:(entry:exit) mem: %d:%d resMem: %d:%d stack: %d:%d" % (m0,m1, r0,r1, s0,s1)) self.schedulingData.updateTargets(fields, self.propID, dateProfile) return (fields) def closeProposal(self, time): # delete OlapField user-defined region table if not (self.userRegion[0] == None): overlappingField = "OlapField_%d_%d" %(self.sessionID,self.propID) result = self.lsstDB.dropTable(overlappingField) return
class TransientProp (Proposal): """ This class is here to describe a Transient Objects case scenario. """ def __init__ (self, lsstDB, propConf, propName, propFullName, sky, weather, sessionID, filters, targetList=None, dbTableDict=None, log=False, logfile='./TransientProp.log', verbose=0, transientConf=DefaultNEAConfigFile): """ Standard initializer. lsstDB LSST DB access object propConf file name containing the instance's configuration data propName proposal name sky: an AsronomycalSky instance. weather: a Weather instance. sessionID: An integer identifying this particular run. filters: a Filters instance targetList: the name (with path) of the TEXT file containing the field list. It is assumed that the target list is a three column list of RA, Dec and field ID. RA and Dec are assumed to be in decimal degrees; filed ID is assumed to be an integer uniquely identifying any give field. dbTableDict: log False if not set, else: log = logging.getLogger("...") logfile Name (and path) of the desired log file. Defaults "./NearEarthProp.log". verbose: Log verbosity: -1=none, 0=minimal, 1=wordy, >1=verbose transientConf: Near Earth Asteroid Configuration file """ super (TransientProp, self).__init__ (lsstDB=lsstDB, propConf=propConf, propName=propName, propFullName=propFullName, sky=sky, weather=weather, sessionID=sessionID, filters=filters, targetList=targetList, dbTableDict=dbTableDict, log=log, logfile=logfile, verbose=verbose) self.lsstDB = lsstDB self.verbose = verbose self.dbTableDict = dbTableDict # DataBase specifics self.dbTable = self.dbTableDict['field'] self.dbRA = 'fieldRA' self.dbDec = 'fieldDec' self.dbID = 'fieldID' self.winners = [] self.loosers = [] self.obsHistory = None # self.seqHistory = None self.sessionID = sessionID # self.targets is a convenience dictionary. Its keys are # fieldIDs, its values are the corresponding RA and Dec. self.targets = {} self.tonightTargets = {} self.sequences= {} self.blockedTargets = [] # Create the ObsHistory instance and cleanup any leftover self.obsHistory = ObsHistory (lsstDB=self.lsstDB, dbTableDict=self.dbTableDict, log=self.log, logfile=self.logfile, verbose=self.verbose) self.obsHistory.cleanupProposal (self.propID, self.sessionID) # Create the SeqHistory instance and cleanup any leftover # self.seqHistory = SeqHistory (lsstDB=self.lsstDB, # dbTableDict=self.dbTableDict, # log=self.log, # logfile=self.logfile, # verbose=self.verbose) # self.seqHistory.cleanupProposal (self.propID, self.sessionID) self.SeqCount = 0 return def start (self): """ Activate the TransientProp instance. """ # PAUSE # yield hold, self return def startNight(self,dateProfile,moonProfile,startNewLunation,randomizeSequencesSelection,nRun, mountedFiltersList): super (TransientProp, self).startNight (dateProfile,moonProfile,startNewLunation, mountedFiltersList) self.tonightTargets = self.targets.copy() date = 0 duration =self.seqDuration distrib = IvezicDistribution(date, duration, intervals =self.visitIntervals, repeats =self.cycleRepeats, repeatdelay=self.cycleInterval ) filters = self.seqFilters if not isinstance(filters, list): filters = [filters] # deletes all sequences that did not start while the fields were # in the region for starting new sequences. notstarted = 0 for fieldID in self.sequences.keys(): if not fieldID in self.targetsNewSeq.keys(): if self.sequences[fieldID].IsIdle(): notstarted+=1 del self.sequences[fieldID] # counts the active sequences in the target region currentActiveSequences = 0 for fieldID in self.sequences.keys(): if fieldID in self.tonightTargets.keys(): if (not self.sequences[fieldID].IsLost()) and (not self.sequences[fieldID].IsComplete()): currentActiveSequences+=1 # creates the sequence object for all the new fields in the restricted area newseq=0 restartedlost=0 restartedcomplete=0 keptsequences=0 # listOfNewFields=self.targetsNewSeq.keys() listOfNewFields=sorted(self.targetsNewSeq.iterkeys()) while (len(listOfNewFields)>0 and currentActiveSequences<self.maxNumberActiveSequences): if randomizeSequencesSelection: fieldID=random.choice(listOfNewFields) else: fieldID=listOfNewFields[0] listOfNewFields.remove(fieldID) if not fieldID in self.sequences.keys(): self.SeqCount += 1 self.sequences[fieldID]=IvezicSequence(self.propID, fieldID, self.SeqCount, filters, distrib, date, duration, self.maxMissedEvents) newseq+=1 currentActiveSequences+=1 elif self.sequences[fieldID].IsLost(): if self.restartLostSequences: self.SeqCount += 1 self.sequences[fieldID].Restart(self.SeqCount) restartedlost+=1 currentActiveSequences+=1 else: del self.tonightTargets[fieldID] elif self.sequences[fieldID].IsComplete(): if self.restartCompleteSequences and not self.blockCompleteSeqConsecutiveLunations: self.SeqCount += 1 self.sequences[fieldID].Restart(self.SeqCount) restartedcomplete+=1 currentActiveSequences+=1 else: del self.tonightTargets[fieldID] # From the broad target area, just keep the fields # associated to a target that is not lost and not complete for fieldID in self.tonightTargets.keys(): if fieldID in self.sequences.keys(): if self.sequences[fieldID].IsLost() or self.sequences[fieldID].IsComplete(): del self.tonightTargets[fieldID] else: keptsequences+=1 else: del self.tonightTargets[fieldID] if ( self.log ): self.log.info('%sProp: startNight() propID=%d added %i new sequences, deleted %i notstarted, restarted %i lost, restarted %i complete, kept %i' % (self.propFullName, self.propID,newseq, notstarted, restartedlost, restartedcomplete, keptsequences)) return def GetProgressPerFilter(self): coaddedNumber = 0 coaddedProgress = 0 for fieldID in self.sequences.keys(): if not self.sequences[fieldID].IsLost(): coaddedNumber += 1 coaddedProgress += self.sequences[fieldID].GetProgress() if coaddedNumber > 0: coaddedProgress /= coaddedNumber if ( self.log ): self.log.info('%sProp: GetProgressPerFilter() propID=%d Sequence progress: %.3f%%' % (self.propFullName, self.propID, 100*coaddedProgress)) progressFilter = {} for filter in self.seqFilters: progressFilter[filter] = coaddedProgress if ( self.log ): for filter in progressFilter.keys(): self.log.info('%sProp: GetProgressPerFilter() propID=%d Filter progress: %10s = %.3f%%' % (self.propFullName, self.propID, filter, 100*progressFilter[filter])) return progressFilter def RankWindow(self, deltat, scale=300.0): """ Evaluates the priority of an event according to the proximity to the event time. Input deltat: the proximity in seconds to the event (current T - event T) scale: the time scale for the window. Default 5 minutes. """ w_start = self.windowStart*scale w_inflex = self.windowMax *scale w_end = self.windowEnd *scale if deltat <= w_start-DAY: rank = -0.1 elif deltat <= w_start: rank = 0.0 elif deltat <= w_inflex: rank = (deltat-w_start)/(w_inflex-w_start) elif deltat <= w_end: rank = 1.0 else: rank = -1.0 return rank def suggestObs (self, dateProfile, moonProfile, n=100, skyfields=None, proximity=None, targetProfiles=None, exclusiveObservation=None, minDistance2Moon=0.0): """ Return the list of (at most) the n (currently) higher ranking observations. Input dateProfile current date profile of: (date,mjd,lst_RAD) where: date simulated time (s) mjd lst_RAD local sidereal time (radians) moonProfile current moon profile of: (moonRA_RAD,moonDec_RAD,moonPhase_PERCENT) moonPhase current moon phase in range [0-100] n number of observations to return. skyfields array of fieldIDs (with index-synced to proximity) proximity array of proximity distance between current telescope position and each entry in skyfields (with index-synced to skyfields) targetProfiles: array of [AirMass, Sky brightness, Filterlist, transparency, cloudSeeing, distance2moon, altitude, rawSeeing, moonAlt] values (dictionary-keyed to fieldID) Return An array of the (at most) n highest ranking observations, ordered from the highest ranking obs to the lowest. """ if ( self.log and self.verbose > 1 ): self.log.info('%sProp: suggestObs() propID=%d' %(self.TransientType, self.propID)) # do we need to rerank fields? # if self.reuseRanking > 1: # self.reuseRanking -= 1 # return [] # Copy the input vars inFieldID = skyfields inproximity = proximity intargetProfiles = targetProfiles (date,mjd,lst_RAD) = dateProfile (moonRA_RAD,moonDec_RAD,moonPhase_PERCENT) = moonProfile # Create a priority queue to choose the best n obs # before checking observing cycle to assure the clearance # of winners and losers list avoiding wrong serendipity observations. self.clearSuggestList() # Check the start/end of observing cycle. # For NEA the lunation is checked if self.CheckObservingCycle(date): # First of all, discard all the targets which are not visible # right now. fields_received=len(self.tonightTargets) fields_invisible=0 fields_moon=0 fields_nottoday=0 fields_waiting=0 fields_missed=0 fields_lost=0 fields_completed=0 fields_proposed=0 fieldfilter_proposed=0 if (exclusiveObservation != None): if exclusiveObservation.fieldID in self.tonightTargets.keys(): listOfFieldsToEvaluate = [exclusiveObservation.fieldID] else: listOfFieldsToEvaluate = [] numberOfObsToPropose = 0 else: # listOfFieldsToEvaluate = self.tonightTargets.keys() listOfFieldsToEvaluate = sorted(self.tonightTargets.iterkeys()) numberOfObsToPropose = n for fieldID in listOfFieldsToEvaluate: ra = self.tonightTargets[fieldID][0] dec = self.tonightTargets[fieldID][1] i = inFieldID.index (fieldID) #============================================================= # RAA --- To Be Done 04 May 2005 # Factor into ranking the proximity of this target to all fields # check all target fields for this local proposal # # # ? If proximity == 0 then want to set factor to infinite? # # # do something with the telescope's proximity to this Field # ..... inproximity[i] .... #============================================================= if (fieldID==self.last_observed_fieldID) and (self.last_observed_wasForThisProposal) and (not self.AcceptConsecutiveObs): continue airmass = intargetProfiles[i][0] if (airmass > self.maxAirmass): if self.log and self.verbose>2: self.log.info('%sProp: suggestObs() propID=%d field=%i too low:%f' % (self.TransientType, self.propID,fieldID,airmass)) fields_invisible+=1 continue distance2moon = intargetProfiles[i][5] if (distance2moon < minDistance2Moon): fields_moon+=1 # remove the target for the rest of the night if it is too close to the moon del self.tonightTargets[fieldID] continue #............................................................. # Gets the list of possible filters based on the sky brightness skyBrightness = intargetProfiles[i][1] allowedFilterList = self.allowedFiltersForBrightness(skyBrightness) filterSeeingList = intargetProfiles[i][2] #............................................................. # Obtains the time for the next event in the sequence for this field if self.sequences[fieldID].IsActive(): try: nextdate = self.sequences[fieldID].nextDate() except: print 'fieldID = '+str(fieldID) raise(IndexError, 'fieldID') # Obtains the interval between the next event and the previous # to quantify the precision required for next event. nextperiod = self.sequences[fieldID].nextPeriod() # Computes the base ranking based on the proximity of the next # event. deltaT = date - nextdate rankTime = self.RankWindow(deltaT, nextperiod) rankLossRisk = max(1.0-0.5*self.sequences[fieldID].GetRemainingAllowedMisses(), 0.0) else: rankTime = self.rankIdleSeq rankLossRisk = 0.0 if rankTime == -0.1: # if more than one day is needed for next event, then remove # the target from the list, it will be received next night if it # is visible. fields_nottoday+=1 del self.tonightTargets[fieldID] elif rankTime > 0.0: fields_proposed+=1 rankForFilters = self.RankFilters(fieldID, filterSeeingList, allowedFilterList) # Boost factor according to the remaining observable days on sky if self.DaysLeftToStartBoost > 0.0 and self.rankDaysLeftMax != 0.0: observableDaysLeft = max((self.ha_twilight[fieldID]+self.ha_maxairmass) * 15.0, 0.0) rankDaysLeft = max(1.0-observableDaysLeft/self.DaysLeftToStartBoost, 0.0) else: rankDaysLeft = 0.0 # for filter in rankForFilters.keys(): for filter in sorted(rankForFilters.iterkeys()): rank = rankTime*self.rankTimeMax + rankForFilters[filter]*self.rankFilter + rankLossRisk*self.rankLossRiskMax + rankDaysLeft*self.rankDaysLeftMax # Create the corresponding Observation recordFieldFilter = self.obsPool[fieldID][filter] #recordFieldFilter.sessionID = sessionID #recordFieldFilter.propID = propID #recordFieldFilter.fieldID = fieldID #recordFieldFilter.filter = filter recordFieldFilter.seqn = self.sequences[fieldID].seqNum recordFieldFilter.date = date recordFieldFilter.mjd = mjd recordFieldFilter.exposureTime = self.exposureTime #recordFieldFilter.slewTime = slewTime #recordFieldFilter.rotatorSkyPos = 0.0 #recordFieldFilter.rotatorTelPos = 0.0 recordFieldFilter.propRank = rank #recordFieldFilter.finRank = finRank recordFieldFilter.maxSeeing = self.maxSeeing recordFieldFilter.rawSeeing = intargetProfiles[i][7] recordFieldFilter.seeing = filterSeeingList[filter] recordFieldFilter.transparency = intargetProfiles[i][3] recordFieldFilter.cloudSeeing = intargetProfiles[i][4] recordFieldFilter.airmass = airmass recordFieldFilter.skyBrightness = skyBrightness #recordFieldFilter.ra = ra #recordFieldFilter.dec = dec recordFieldFilter.lst = lst_RAD recordFieldFilter.altitude = intargetProfiles[i][6] recordFieldFilter.azimuth = intargetProfiles[i][9] recordFieldFilter.distance2moon = intargetProfiles[i][5] recordFieldFilter.moonRA = moonRA_RAD recordFieldFilter.moonDec = moonDec_RAD recordFieldFilter.moonAlt = intargetProfiles[i][8] recordFieldFilter.moonPhase = moonPhase_PERCENT self.addToSuggestList (recordFieldFilter, inproximity[i]) fieldfilter_proposed+=1 elif rankTime < 0.0: fields_missed+=1 obsHist = self.lsstDB.addMissedObservation(self.sequences[fieldID].GetNextFilter(), date, mjd, 0, lst_RAD, self.sessionID, fieldID) self.sequences[fieldID].missEvent(date, obsHist.obsHistID) if self.log and self.verbose>0 and not self.sequences[fieldID].IsLost(): t_secs = date%60 t_mins = (date%3600)/60 t_hour = (date%86400)/3600 t_days = (date)/86400 self.log.info('%sProp: suggestObs() event MISSED for propID=%d field=%i t=%dd%02dh%02dm%02ds progress=%i%%' % (self.TransientType, self.propID, fieldID, t_days, t_hour, t_mins, t_secs, 100*self.sequences[fieldID].GetProgress())) # now the sequence object determines if the sequence is lost, according to the # number of missed events and the maximum allowed. if self.sequences[fieldID].IsLost(): if self.log and self.verbose>0: self.log.info('%sProp: suggestObs() sequence LOST for propID=%d field=%i t=%.0f event missed' % (self.TransientType, self.propID ,fieldID, date)) # Update the SeqHistory database seq = self.sequences[fieldID] seqHist = self.lsstDB.addSeqHistory(seq.date, date, seq.seqNum, seq.GetProgress(), seq.GetNumTargetEvents(), seq.GetNumActualEvents(), MAX_MISSED_EVENTS, 0, fieldID, self.sessionID, self.propID) for obsID in seq.GetListObsID(): self.lsstDB.addSeqHistoryObsHistory(seqHist.sequenceID, obsID, self.sessionID) for misID in seq.GetListMisID(): self.lsstDB.addSeqHistoryMissedHistory(seqHist.sequenceID, misID, self.sessionID) fields_lost+=1 del self.tonightTargets[fieldID] # it is also possible that the missed event was the last needed for completing the sequence # in such a case the sequence object determines the completion of the sequence. elif self.sequences[fieldID].IsComplete(): self.CompleteSequence(fieldID, date) fields_completed+=1 else: fields_waiting+=1 if self.log and self.verbose>0: self.log.info('%sProp: suggestObs() propID=%d fields count: received=%i invisible=%i moon=%i nottoday=%i waiting=%i proposed=%i missed=%i lost=%i completed=%i fieldfilter=%i' % (self.TransientType, self.propID, fields_received, fields_invisible, fields_moon, fields_nottoday, fields_waiting, fields_proposed, fields_missed, fields_lost, fields_completed, fieldfilter_proposed)) # Choose the n highest ranking observations # self.reuseRanking = self.reuseRankingCount return self.getSuggestList(numberOfObsToPropose) else: # The cycle has ended and next one hasn't started yet (full moon for NEA) return [] def getFieldCoordinates (self, fieldID): """ Given a fieldID, fetch the corresponding values for RA and Dec Input fieldID: a field identifier (long int) Return (ra, dec) in decimal degrees Raise Exception if fieldID is unknown. """ return (self.targets[fieldID]) def setMaxSeeing (self, seeing): """ Setter method for self.seeing Input seeing: float Return None """ self.maxSeeing = float (seeing) return def setSlewTime (self, slewTime): """ Setter method for self.maxSlewTime Input slewTime: float Return None """ self.maxSlewTime = float (slewTime) return def closeObservation (self, observation, twilightProfile, obsHistID): """ Registers the fact that the indicated observation took place. This is, the corresponding event in the sequence of the indicated fieldID has been executed, and the sequence can continue. Input obs an Observation instance winslewTime slew time required for the winning observation Return None Raise Exception if Observation History update fails """ if not self.IsObservingCycle(): self.last_observed_wasForThisProposal = False return None if ( self.log and self.verbose > 1 ): self.log.info('TransientProp: closeObservation()') obs = super (TransientProp, self).closeObservation(observation, twilightProfile, obsHistID) if obs != None: self.sequences[obs.fieldID].closeEvent(obs.date, obs.filter) progress = self.sequences[obs.fieldID].GetProgress() if self.log and self.verbose>0: t_secs = obs.date%60 t_mins = (obs.date%3600)/60 t_hour = (obs.date%86400)/3600 t_days = (obs.date)/86400 self.log.info('%sProp: closeObservation() propID=%d field=%d filter=%s propRank=%.4f finRank=%.4f t=%dd%02dh%02dm%02ds progress=%d%%' % (self.propFullName, self.propID, obs.fieldID, obs.filter, obs.propRank, obs.finRank, t_days, t_hour, t_mins, t_secs, int(100*progress))) # if sequence is complete, then deletes target from tonight's list. if progress == 1.0: self.CompleteSequence(obs.fieldID, obs.date) return obs def CompleteSequence(self, fieldID, date): # Update sequence history DB seq = self.sequences[fieldID] seqHist = self.lsstDB.addSeqHistory(seq.date, date, seq.seqNum, seq.GetProgress(), seq.GetNumTargetEvents(), seq.GetNumActualEvents(), SUCCESS, 0, fieldID, self.sessionID, self.propID) for obsID in seq.GetListObsID(): self.lsstDB.addSeqHistoryObsHistory(seqHist.sequenceID, obsID, self.sessionID) for misID in seq.GetListMisID(): self.lsstDB.addSeqHistoryMissedHistory(seqHist.sequenceID, misID, self.sessionID) del self.tonightTargets[fieldID] if (self.log and self.verbose >0): self.log.info('%sProp: closeObservation() sequence COMPLETE for propID=%d field=%d' % (self.propFullName, self.propID, fieldID)) return def FinishSequences(self, obsdate): """ Finishes the current sequences. """ if ( self.log ): self.log.info ('TransientProp: FinishSequences()') for fieldID in self.sequences.keys(): if self.sequences[fieldID].IsProgressing(): if ( self.log ): self.log.info('%sProp: FinishSequences() propID=%d sequence LOST for field=%i end of cycle' % (self.propFullName, self.propID, fieldID)) self.sequences[fieldID].SetLost() # Update sequence history DB seq = self.sequences[fieldID] seqHist = self.lsstDB.addSeqHistory(seq.date, obsdate, seq.seqNum, seq.GetProgress(), seq.GetNumTargetEvents(), seq.GetNumActualEvents(), CYCLE_END, 0, fieldID, self.sessionID, self.propID) for obsID in seq.GetListObsID(): self.lsstDB.addSeqHistoryObsHistory(seqHist.sequenceID, obsID, self.sessionID) for misID in seq.GetListMisID(): self.lsstDB.addSeqHistoryMissedHistory(seqHist.sequenceID, misID, self.sessionID) return def closeProposal(self, time): """ Finishes the current sequences. """ if ( self.log ): self.log.info ('%sProp: closeProposal()' % (self.propFullName)) for fieldID in self.sequences.keys(): if self.sequences[fieldID].IsProgressing(): if ( self.log ): self.log.info('%sProp: closeProposal() propID=%d sequence LOST for field=%i end of simulation' % (self.propFullName, self.propID, fieldID)) self.sequences[fieldID].SetLost() # Update sequence history DB seq = self.sequences[fieldID] seqHist = self.lsstDB.addSeqHistory(seq.date, time, seq.seqNum, seq.GetProgress(), seq.GetNumTargetEvents(), seq.GetNumActualEvents(), SIMULATION_END, 0, fieldID, self.sessionID, self.propID) for obsID in seq.GetListObsID(): self.lsstDB.addSeqHistoryObsHistory(seqHist.sequenceID, obsID, self.sessionID) for misID in seq.GetListMisID(): self.lsstDB.addSeqHistoryMissedHistory(seqHist.sequenceID, misID, self.sessionID) # delete OlapField user-defined region table if not (self.userRegion[0] == None): overlappingField = "OlapField_%d_%d" %(self.sessionID,self.propID) result = self.lsstDB.dropTable(overlappingField) return def RestartSequences(self): if (self.log): self.log.info('TransientProp: RestartFinishedSequences() propID=%d' %(self.propID)) for fieldID in self.sequences.keys(): if self.sequences[fieldID].IsLost() or (self.sequences[fieldID].IsComplete() and not fieldID in self.blockedTargets): self.SeqCount += 1 self.sequences[fieldID].Restart(self.SeqCount) if self.log and self.verbose>0: self.log.info('TransientProp: RestartSequences() sequence for propID=%d field=%i restarted' % (self.propID,fieldID)) return def updateTargetList (self, dateProfile, obsProfile, sky, fov ): return
class TransientProp(Proposal): """ This class is here to describe a Transient Objects case scenario. """ def __init__(self, lsstDB, propConf, propName, propFullName, sky, weather, sessionID, filters, targetList=None, dbTableDict=None, log=False, logfile='./TransientProp.log', verbose=0, transientConf=DefaultNEAConfigFile): """ Standard initializer. lsstDB LSST DB access object propConf file name containing the instance's configuration data propName proposal name sky: an AsronomycalSky instance. weather: a Weather instance. sessionID: An integer identifying this particular run. filters: a Filters instance targetList: the name (with path) of the TEXT file containing the field list. It is assumed that the target list is a three column list of RA, Dec and field ID. RA and Dec are assumed to be in decimal degrees; filed ID is assumed to be an integer uniquely identifying any give field. dbTableDict: log False if not set, else: log = logging.getLogger("...") logfile Name (and path) of the desired log file. Defaults "./NearEarthProp.log". verbose: Log verbosity: -1=none, 0=minimal, 1=wordy, >1=verbose transientConf: Near Earth Asteroid Configuration file """ super(TransientProp, self).__init__(lsstDB=lsstDB, propConf=propConf, propName=propName, propFullName=propFullName, sky=sky, weather=weather, sessionID=sessionID, filters=filters, targetList=targetList, dbTableDict=dbTableDict, log=log, logfile=logfile, verbose=verbose) self.lsstDB = lsstDB self.verbose = verbose self.dbTableDict = dbTableDict # DataBase specifics self.dbTable = self.dbTableDict['field'] self.dbRA = 'fieldRA' self.dbDec = 'fieldDec' self.dbID = 'fieldID' self.winners = [] self.loosers = [] self.obsHistory = None # self.seqHistory = None self.sessionID = sessionID # self.targets is a convenience dictionary. Its keys are # fieldIDs, its values are the corresponding RA and Dec. self.targets = {} self.tonightTargets = {} self.sequences = {} self.blockedTargets = [] # Create the ObsHistory instance and cleanup any leftover self.obsHistory = ObsHistory(lsstDB=self.lsstDB, dbTableDict=self.dbTableDict, log=self.log, logfile=self.logfile, verbose=self.verbose) self.obsHistory.cleanupProposal(self.propID, self.sessionID) # Create the SeqHistory instance and cleanup any leftover # self.seqHistory = SeqHistory (lsstDB=self.lsstDB, # dbTableDict=self.dbTableDict, # log=self.log, # logfile=self.logfile, # verbose=self.verbose) # self.seqHistory.cleanupProposal (self.propID, self.sessionID) self.SeqCount = 0 return def start(self): """ Activate the TransientProp instance. """ # PAUSE # yield hold, self return def startNight(self, dateProfile, moonProfile, startNewLunation, randomizeSequencesSelection, nRun, mountedFiltersList): super(TransientProp, self).startNight(dateProfile, moonProfile, startNewLunation, mountedFiltersList) self.tonightTargets = self.targets.copy() date = 0 duration = self.seqDuration distrib = IvezicDistribution(date, duration, intervals=self.visitIntervals, repeats=self.cycleRepeats, repeatdelay=self.cycleInterval) filters = self.seqFilters if not isinstance(filters, list): filters = [filters] # deletes all sequences that did not start while the fields were # in the region for starting new sequences. notstarted = 0 for fieldID in self.sequences.keys(): if not fieldID in self.targetsNewSeq.keys(): if self.sequences[fieldID].IsIdle(): notstarted += 1 del self.sequences[fieldID] # counts the active sequences in the target region currentActiveSequences = 0 for fieldID in self.sequences.keys(): if fieldID in self.tonightTargets.keys(): if (not self.sequences[fieldID].IsLost()) and ( not self.sequences[fieldID].IsComplete()): currentActiveSequences += 1 # creates the sequence object for all the new fields in the restricted area newseq = 0 restartedlost = 0 restartedcomplete = 0 keptsequences = 0 # listOfNewFields=self.targetsNewSeq.keys() listOfNewFields = sorted(self.targetsNewSeq.iterkeys()) while (len(listOfNewFields) > 0 and currentActiveSequences < self.maxNumberActiveSequences): if randomizeSequencesSelection: fieldID = random.choice(listOfNewFields) else: fieldID = listOfNewFields[0] listOfNewFields.remove(fieldID) if not fieldID in self.sequences.keys(): self.SeqCount += 1 self.sequences[fieldID] = IvezicSequence( self.propID, fieldID, self.SeqCount, filters, distrib, date, duration, self.maxMissedEvents) newseq += 1 currentActiveSequences += 1 elif self.sequences[fieldID].IsLost(): if self.restartLostSequences: self.SeqCount += 1 self.sequences[fieldID].Restart(self.SeqCount) restartedlost += 1 currentActiveSequences += 1 else: del self.tonightTargets[fieldID] elif self.sequences[fieldID].IsComplete(): if self.restartCompleteSequences and not self.blockCompleteSeqConsecutiveLunations: self.SeqCount += 1 self.sequences[fieldID].Restart(self.SeqCount) restartedcomplete += 1 currentActiveSequences += 1 else: del self.tonightTargets[fieldID] # From the broad target area, just keep the fields # associated to a target that is not lost and not complete for fieldID in self.tonightTargets.keys(): if fieldID in self.sequences.keys(): if self.sequences[fieldID].IsLost( ) or self.sequences[fieldID].IsComplete(): del self.tonightTargets[fieldID] else: keptsequences += 1 else: del self.tonightTargets[fieldID] if (self.log): self.log.info( '%sProp: startNight() propID=%d added %i new sequences, deleted %i notstarted, restarted %i lost, restarted %i complete, kept %i' % (self.propFullName, self.propID, newseq, notstarted, restartedlost, restartedcomplete, keptsequences)) return def GetProgressPerFilter(self): coaddedNumber = 0 coaddedProgress = 0 for fieldID in self.sequences.keys(): if not self.sequences[fieldID].IsLost(): coaddedNumber += 1 coaddedProgress += self.sequences[fieldID].GetProgress() if coaddedNumber > 0: coaddedProgress /= coaddedNumber if (self.log): self.log.info( '%sProp: GetProgressPerFilter() propID=%d Sequence progress: %.3f%%' % (self.propFullName, self.propID, 100 * coaddedProgress)) progressFilter = {} for filter in self.seqFilters: progressFilter[filter] = coaddedProgress if (self.log): for filter in progressFilter.keys(): self.log.info( '%sProp: GetProgressPerFilter() propID=%d Filter progress: %10s = %.3f%%' % (self.propFullName, self.propID, filter, 100 * progressFilter[filter])) return progressFilter def RankWindow(self, deltat, scale=300.0): """ Evaluates the priority of an event according to the proximity to the event time. Input deltat: the proximity in seconds to the event (current T - event T) scale: the time scale for the window. Default 5 minutes. """ w_start = self.windowStart * scale w_inflex = self.windowMax * scale w_end = self.windowEnd * scale if deltat <= w_start - DAY: rank = -0.1 elif deltat <= w_start: rank = 0.0 elif deltat <= w_inflex: rank = (deltat - w_start) / (w_inflex - w_start) elif deltat <= w_end: rank = 1.0 else: rank = -1.0 return rank def suggestObs(self, dateProfile, moonProfile, n=100, skyfields=None, proximity=None, targetProfiles=None, exclusiveObservation=None, minDistance2Moon=0.0): """ Return the list of (at most) the n (currently) higher ranking observations. Input dateProfile current date profile of: (date,mjd,lst_RAD) where: date simulated time (s) mjd lst_RAD local sidereal time (radians) moonProfile current moon profile of: (moonRA_RAD,moonDec_RAD,moonPhase_PERCENT) moonPhase current moon phase in range [0-100] n number of observations to return. skyfields array of fieldIDs (with index-synced to proximity) proximity array of proximity distance between current telescope position and each entry in skyfields (with index-synced to skyfields) targetProfiles: array of [AirMass, Sky brightness, Filterlist, transparency, cloudSeeing, distance2moon, altitude, rawSeeing, moonAlt] values (dictionary-keyed to fieldID) Return An array of the (at most) n highest ranking observations, ordered from the highest ranking obs to the lowest. """ if (self.log and self.verbose > 1): self.log.info('%sProp: suggestObs() propID=%d' % (self.TransientType, self.propID)) # do we need to rerank fields? # if self.reuseRanking > 1: # self.reuseRanking -= 1 # return [] # Copy the input vars inFieldID = skyfields inproximity = proximity intargetProfiles = targetProfiles (date, mjd, lst_RAD) = dateProfile (moonRA_RAD, moonDec_RAD, moonPhase_PERCENT) = moonProfile # Create a priority queue to choose the best n obs # before checking observing cycle to assure the clearance # of winners and losers list avoiding wrong serendipity observations. self.clearSuggestList() # Check the start/end of observing cycle. # For NEA the lunation is checked if self.CheckObservingCycle(date): # First of all, discard all the targets which are not visible # right now. fields_received = len(self.tonightTargets) fields_invisible = 0 fields_moon = 0 fields_nottoday = 0 fields_waiting = 0 fields_missed = 0 fields_lost = 0 fields_completed = 0 fields_proposed = 0 fieldfilter_proposed = 0 if (exclusiveObservation != None): if exclusiveObservation.fieldID in self.tonightTargets.keys(): listOfFieldsToEvaluate = [exclusiveObservation.fieldID] else: listOfFieldsToEvaluate = [] numberOfObsToPropose = 0 else: # listOfFieldsToEvaluate = self.tonightTargets.keys() listOfFieldsToEvaluate = sorted(self.tonightTargets.iterkeys()) numberOfObsToPropose = n for fieldID in listOfFieldsToEvaluate: ra = self.tonightTargets[fieldID][0] dec = self.tonightTargets[fieldID][1] i = inFieldID.index(fieldID) #============================================================= # RAA --- To Be Done 04 May 2005 # Factor into ranking the proximity of this target to all fields # check all target fields for this local proposal # # # ? If proximity == 0 then want to set factor to infinite? # # # do something with the telescope's proximity to this Field # ..... inproximity[i] .... #============================================================= if (fieldID == self.last_observed_fieldID) and ( self.last_observed_wasForThisProposal) and ( not self.AcceptConsecutiveObs): continue airmass = intargetProfiles[i][0] if (airmass > self.maxAirmass): if self.log and self.verbose > 2: self.log.info( '%sProp: suggestObs() propID=%d field=%i too low:%f' % (self.TransientType, self.propID, fieldID, airmass)) fields_invisible += 1 continue distance2moon = intargetProfiles[i][5] if (distance2moon < minDistance2Moon): fields_moon += 1 # remove the target for the rest of the night if it is too close to the moon del self.tonightTargets[fieldID] continue #............................................................. # Gets the list of possible filters based on the sky brightness skyBrightness = intargetProfiles[i][1] allowedFilterList = self.allowedFiltersForBrightness( skyBrightness) filterSeeingList = intargetProfiles[i][2] #............................................................. # Obtains the time for the next event in the sequence for this field if self.sequences[fieldID].IsActive(): try: nextdate = self.sequences[fieldID].nextDate() except: print 'fieldID = ' + str(fieldID) raise (IndexError, 'fieldID') # Obtains the interval between the next event and the previous # to quantify the precision required for next event. nextperiod = self.sequences[fieldID].nextPeriod() # Computes the base ranking based on the proximity of the next # event. deltaT = date - nextdate rankTime = self.RankWindow(deltaT, nextperiod) rankLossRisk = max( 1.0 - 0.5 * self.sequences[fieldID].GetRemainingAllowedMisses(), 0.0) else: rankTime = self.rankIdleSeq rankLossRisk = 0.0 if rankTime == -0.1: # if more than one day is needed for next event, then remove # the target from the list, it will be received next night if it # is visible. fields_nottoday += 1 del self.tonightTargets[fieldID] elif rankTime > 0.0: fields_proposed += 1 rankForFilters = self.RankFilters(fieldID, filterSeeingList, allowedFilterList) # Boost factor according to the remaining observable days on sky if self.DaysLeftToStartBoost > 0.0 and self.rankDaysLeftMax != 0.0: observableDaysLeft = max( (self.ha_twilight[fieldID] + self.ha_maxairmass) * 15.0, 0.0) rankDaysLeft = max( 1.0 - observableDaysLeft / self.DaysLeftToStartBoost, 0.0) else: rankDaysLeft = 0.0 # for filter in rankForFilters.keys(): for filter in sorted(rankForFilters.iterkeys()): rank = rankTime * self.rankTimeMax + rankForFilters[ filter] * self.rankFilter + rankLossRisk * self.rankLossRiskMax + rankDaysLeft * self.rankDaysLeftMax # Create the corresponding Observation recordFieldFilter = self.obsPool[fieldID][filter] #recordFieldFilter.sessionID = sessionID #recordFieldFilter.propID = propID #recordFieldFilter.fieldID = fieldID #recordFieldFilter.filter = filter recordFieldFilter.seqn = self.sequences[fieldID].seqNum recordFieldFilter.date = date recordFieldFilter.mjd = mjd recordFieldFilter.exposureTime = self.exposureTime #recordFieldFilter.slewTime = slewTime #recordFieldFilter.rotatorSkyPos = 0.0 #recordFieldFilter.rotatorTelPos = 0.0 recordFieldFilter.propRank = rank #recordFieldFilter.finRank = finRank recordFieldFilter.maxSeeing = self.maxSeeing recordFieldFilter.rawSeeing = intargetProfiles[i][7] recordFieldFilter.seeing = filterSeeingList[filter] recordFieldFilter.transparency = intargetProfiles[i][3] recordFieldFilter.cloudSeeing = intargetProfiles[i][4] recordFieldFilter.airmass = airmass recordFieldFilter.skyBrightness = skyBrightness #recordFieldFilter.ra = ra #recordFieldFilter.dec = dec recordFieldFilter.lst = lst_RAD recordFieldFilter.altitude = intargetProfiles[i][6] recordFieldFilter.azimuth = intargetProfiles[i][9] recordFieldFilter.distance2moon = intargetProfiles[i][ 5] recordFieldFilter.moonRA = moonRA_RAD recordFieldFilter.moonDec = moonDec_RAD recordFieldFilter.moonAlt = intargetProfiles[i][8] recordFieldFilter.moonPhase = moonPhase_PERCENT self.addToSuggestList(recordFieldFilter, inproximity[i]) fieldfilter_proposed += 1 elif rankTime < 0.0: fields_missed += 1 obsHist = self.lsstDB.addMissedObservation( self.sequences[fieldID].GetNextFilter(), date, mjd, 0, lst_RAD, self.sessionID, fieldID) self.sequences[fieldID].missEvent(date, obsHist.obsHistID) if self.log and self.verbose > 0 and not self.sequences[ fieldID].IsLost(): t_secs = date % 60 t_mins = (date % 3600) / 60 t_hour = (date % 86400) / 3600 t_days = (date) / 86400 self.log.info( '%sProp: suggestObs() event MISSED for propID=%d field=%i t=%dd%02dh%02dm%02ds progress=%i%%' % (self.TransientType, self.propID, fieldID, t_days, t_hour, t_mins, t_secs, 100 * self.sequences[fieldID].GetProgress())) # now the sequence object determines if the sequence is lost, according to the # number of missed events and the maximum allowed. if self.sequences[fieldID].IsLost(): if self.log and self.verbose > 0: self.log.info( '%sProp: suggestObs() sequence LOST for propID=%d field=%i t=%.0f event missed' % (self.TransientType, self.propID, fieldID, date)) # Update the SeqHistory database seq = self.sequences[fieldID] seqHist = self.lsstDB.addSeqHistory( seq.date, date, seq.seqNum, seq.GetProgress(), seq.GetNumTargetEvents(), seq.GetNumActualEvents(), MAX_MISSED_EVENTS, 0, fieldID, self.sessionID, self.propID) for obsID in seq.GetListObsID(): self.lsstDB.addSeqHistoryObsHistory( seqHist.sequenceID, obsID, self.sessionID) for misID in seq.GetListMisID(): self.lsstDB.addSeqHistoryMissedHistory( seqHist.sequenceID, misID, self.sessionID) fields_lost += 1 del self.tonightTargets[fieldID] # it is also possible that the missed event was the last needed for completing the sequence # in such a case the sequence object determines the completion of the sequence. elif self.sequences[fieldID].IsComplete(): self.CompleteSequence(fieldID, date) fields_completed += 1 else: fields_waiting += 1 if self.log and self.verbose > 0: self.log.info( '%sProp: suggestObs() propID=%d fields count: received=%i invisible=%i moon=%i nottoday=%i waiting=%i proposed=%i missed=%i lost=%i completed=%i fieldfilter=%i' % (self.TransientType, self.propID, fields_received, fields_invisible, fields_moon, fields_nottoday, fields_waiting, fields_proposed, fields_missed, fields_lost, fields_completed, fieldfilter_proposed)) # Choose the n highest ranking observations # self.reuseRanking = self.reuseRankingCount return self.getSuggestList(numberOfObsToPropose) else: # The cycle has ended and next one hasn't started yet (full moon for NEA) return [] def getFieldCoordinates(self, fieldID): """ Given a fieldID, fetch the corresponding values for RA and Dec Input fieldID: a field identifier (long int) Return (ra, dec) in decimal degrees Raise Exception if fieldID is unknown. """ return (self.targets[fieldID]) def setMaxSeeing(self, seeing): """ Setter method for self.seeing Input seeing: float Return None """ self.maxSeeing = float(seeing) return def setSlewTime(self, slewTime): """ Setter method for self.maxSlewTime Input slewTime: float Return None """ self.maxSlewTime = float(slewTime) return def closeObservation(self, observation, twilightProfile, obsHistID): """ Registers the fact that the indicated observation took place. This is, the corresponding event in the sequence of the indicated fieldID has been executed, and the sequence can continue. Input obs an Observation instance winslewTime slew time required for the winning observation Return None Raise Exception if Observation History update fails """ if not self.IsObservingCycle(): self.last_observed_wasForThisProposal = False return None if (self.log and self.verbose > 1): self.log.info('TransientProp: closeObservation()') obs = super(TransientProp, self).closeObservation(observation, twilightProfile, obsHistID) if obs != None: self.sequences[obs.fieldID].closeEvent(obs.date, obs.filter) progress = self.sequences[obs.fieldID].GetProgress() if self.log and self.verbose > 0: t_secs = obs.date % 60 t_mins = (obs.date % 3600) / 60 t_hour = (obs.date % 86400) / 3600 t_days = (obs.date) / 86400 self.log.info( '%sProp: closeObservation() propID=%d field=%d filter=%s propRank=%.4f finRank=%.4f t=%dd%02dh%02dm%02ds progress=%d%%' % (self.propFullName, self.propID, obs.fieldID, obs.filter, obs.propRank, obs.finRank, t_days, t_hour, t_mins, t_secs, int(100 * progress))) # if sequence is complete, then deletes target from tonight's list. if progress == 1.0: self.CompleteSequence(obs.fieldID, obs.date) return obs def CompleteSequence(self, fieldID, date): # Update sequence history DB seq = self.sequences[fieldID] seqHist = self.lsstDB.addSeqHistory(seq.date, date, seq.seqNum, seq.GetProgress(), seq.GetNumTargetEvents(), seq.GetNumActualEvents(), SUCCESS, 0, fieldID, self.sessionID, self.propID) for obsID in seq.GetListObsID(): self.lsstDB.addSeqHistoryObsHistory(seqHist.sequenceID, obsID, self.sessionID) for misID in seq.GetListMisID(): self.lsstDB.addSeqHistoryMissedHistory(seqHist.sequenceID, misID, self.sessionID) del self.tonightTargets[fieldID] if (self.log and self.verbose > 0): self.log.info( '%sProp: closeObservation() sequence COMPLETE for propID=%d field=%d' % (self.propFullName, self.propID, fieldID)) return def FinishSequences(self, obsdate): """ Finishes the current sequences. """ if (self.log): self.log.info('TransientProp: FinishSequences()') for fieldID in self.sequences.keys(): if self.sequences[fieldID].IsProgressing(): if (self.log): self.log.info( '%sProp: FinishSequences() propID=%d sequence LOST for field=%i end of cycle' % (self.propFullName, self.propID, fieldID)) self.sequences[fieldID].SetLost() # Update sequence history DB seq = self.sequences[fieldID] seqHist = self.lsstDB.addSeqHistory(seq.date, obsdate, seq.seqNum, seq.GetProgress(), seq.GetNumTargetEvents(), seq.GetNumActualEvents(), CYCLE_END, 0, fieldID, self.sessionID, self.propID) for obsID in seq.GetListObsID(): self.lsstDB.addSeqHistoryObsHistory( seqHist.sequenceID, obsID, self.sessionID) for misID in seq.GetListMisID(): self.lsstDB.addSeqHistoryMissedHistory( seqHist.sequenceID, misID, self.sessionID) return def closeProposal(self, time): """ Finishes the current sequences. """ if (self.log): self.log.info('%sProp: closeProposal()' % (self.propFullName)) for fieldID in self.sequences.keys(): if self.sequences[fieldID].IsProgressing(): if (self.log): self.log.info( '%sProp: closeProposal() propID=%d sequence LOST for field=%i end of simulation' % (self.propFullName, self.propID, fieldID)) self.sequences[fieldID].SetLost() # Update sequence history DB seq = self.sequences[fieldID] seqHist = self.lsstDB.addSeqHistory(seq.date, time, seq.seqNum, seq.GetProgress(), seq.GetNumTargetEvents(), seq.GetNumActualEvents(), SIMULATION_END, 0, fieldID, self.sessionID, self.propID) for obsID in seq.GetListObsID(): self.lsstDB.addSeqHistoryObsHistory( seqHist.sequenceID, obsID, self.sessionID) for misID in seq.GetListMisID(): self.lsstDB.addSeqHistoryMissedHistory( seqHist.sequenceID, misID, self.sessionID) # delete OlapField user-defined region table if not (self.userRegion[0] == None): overlappingField = "OlapField_%d_%d" % (self.sessionID, self.propID) result = self.lsstDB.dropTable(overlappingField) return def RestartSequences(self): if (self.log): self.log.info( 'TransientProp: RestartFinishedSequences() propID=%d' % (self.propID)) for fieldID in self.sequences.keys(): if self.sequences[fieldID].IsLost() or ( self.sequences[fieldID].IsComplete() and not fieldID in self.blockedTargets): self.SeqCount += 1 self.sequences[fieldID].Restart(self.SeqCount) if self.log and self.verbose > 0: self.log.info( 'TransientProp: RestartSequences() sequence for propID=%d field=%i restarted' % (self.propID, fieldID)) return def updateTargetList(self, dateProfile, obsProfile, sky, fov): return
class TransSubSeqProp(Proposal): """ This class is here to describe a Transient Objects case scenario. """ def __init__(self, lsstDB, propConf, propName, propFullName, sky, weather, sessionID, filters, targetList=None, dbTableDict=None, log=False, logfile='./TransSubSeqProp.log', verbose=0, transientConf=DefaultNEAConfigFile): """ Standard initializer. lsstDB LSST DB access object propConf file name containing the instance's configuration data propName proposal name sky: an AsronomycalSky instance. weather: a Weather instance. sessionID: An integer identifying this particular run. filters: a Filters instance targetList: the name (with path) of the TEXT file containing the field list. It is assumed that the target list is a three column list of RA, Dec and field ID. RA and Dec are assumed to be in decimal degrees; filed ID is assumed to be an integer uniquely identifying any give field. dbTableDict: log False if not set, else: log = logging.getLogger("...") logfile Name (and path) of the desired log file. Defaults "./NearEarthProp.log". verbose: Log verbosity: -1=none, 0=minimal, 1=wordy, >1=verbose transientConf: Near Earth Asteroid Configuration file """ super(TransSubSeqProp, self).__init__(lsstDB=lsstDB, propConf=propConf, propName=propName, propFullName=propFullName, sky=sky, weather=weather, sessionID=sessionID, filters=filters, targetList=targetList, dbTableDict=dbTableDict, log=log, logfile=logfile, verbose=verbose) self.lsstDB = lsstDB self.verbose = verbose self.dbTableDict = dbTableDict # DataBase specifics self.dbTable = self.dbTableDict['field'] self.dbRA = 'fieldRA' self.dbDec = 'fieldDec' self.dbID = 'fieldID' self.winners = [] self.loosers = [] self.obsHistory = None # self.seqHistory = None self.sessionID = sessionID # self.targets is a convenience dictionary. Its keys are # fieldIDs, its values are the corresponding RA and Dec. self.targets = {} self.tonightTargets = {} self.sequences = {} self.tonightSubseqsForTarget = {} # Create the ObsHistory instance and cleanup any leftover self.obsHistory = ObsHistory(lsstDB=self.lsstDB, dbTableDict=self.dbTableDict, log=self.log, logfile=self.logfile, verbose=self.verbose) self.obsHistory.cleanupProposal(self.propID, self.sessionID) # Create the SeqHistory instance and cleanup any leftover # self.seqHistory = SeqHistory (lsstDB=self.lsstDB, # dbTableDict=self.dbTableDict, # log=self.log, # logfile=self.logfile, # verbose=self.verbose) # self.seqHistory.cleanupProposal (self.propID, self.sessionID) self.exclusiveBlockNeeded = False self.exclusiveObs = None self.exclusiveField = None self.exclusiveSubseq = None self.SeqCount = 0 return def start(self): """ Activate the TransientProp instance. """ # Removes the subsequences that require 0 events N = len(self.subSeqName) for n in range(N): ix = N - n - 1 if self.subSeqEvents[ix] == 0: self.subSeqName.pop(ix) self.subSeqNested.pop(ix) self.subSeqFilters.pop(ix) self.subSeqExposures.pop(ix) self.subSeqEvents.pop(ix) self.subSeqMaxMissed.pop(ix) self.subSeqInterval.pop(ix) self.subSeqWindowStart.pop(ix) self.subSeqWindowMax.pop(ix) self.subSeqWindowEnd.pop(ix) return def ComplyToFilterChangeBurstConstraint(self, filterBurstNumber, filterBurstTime, visitTime, readoutTime, filterTime): N = len(self.subSeqName) for n in range(N): subFilters = self.subSeqFilters[n].split(',') nfilters = len(subFilters) if nfilters > 1: print self.propConf print self.subSeqName[n] print subFilters subVisits = self.subSeqExposures[n].split(',') print subVisits T = [] for k in range(nfilters): tk = 0 if k > 0: tk += filterTime tk += int(subVisits[k]) * visitTime + (int(subVisits[k]) - 1) * readoutTime T.append(tk) print T numIdxToCheck = nfilters - 1 if numIdxToCheck >= filterBurstNumber: for startIdx in range( 0, numIdxToCheck - filterBurstNumber + 1): tt = 0 for idx in range(startIdx, startIdx + filterBurstNumber): tt += T[idx] if tt < filterBurstTime: print "REJECTED %f < %f" % (tt, filterBurstTime) return False return True def startNight(self, dateProfile, moonProfile, startNewLunation, randomizeSequencesSelection, nRun, mountedFiltersList): super(TransSubSeqProp, self).startNight(dateProfile, moonProfile, startNewLunation, mountedFiltersList) (date, mjd, lst_RAD) = dateProfile runProgress = date / YEAR / nRun self.tonightTargets = self.targets.copy() # deletes all sequences that did not start while the fields were # in the region for starting new sequences. notstarted = 0 for fieldID in self.sequences.keys(): if fieldID not in self.targetsNewSeq.keys(): if self.sequences[fieldID].IsIdle(): # self.log.info('%sProp: startNight() deleted sequence field=%d at progress=%.3f%% ' # 'state=%d nevents=%d' % (self.propFullName, fieldID, # 100*self.sequences[fieldID].GetProgress(), # self.sequences[fieldID].state, # self.sequences[fieldID].nAllEvents)) notstarted += 1 del self.sequences[fieldID] # counts the active sequences in the target region currentActiveSequences = 0 coaddedProgress = 0.0 coaddedNumber = 0 for fieldID in self.sequences.keys(): if fieldID in self.tonightTargets.keys(): coaddedProgress += self.sequences[fieldID].GetProgress() coaddedNumber += 1 if (not self.sequences[fieldID].IsLost()) and ( not self.sequences[fieldID].IsComplete()): currentActiveSequences += 1 # creates the sequence object for all the new fields in the restricted area newseq = 0 restartedlost = 0 restartedcomplete = 0 keptsequences = 0 #listOfNewFields=self.targetsNewSeq.keys() listOfNewFields = sorted(self.targetsNewSeq.iterkeys()) while (len(listOfNewFields) > 0 and currentActiveSequences < self.maxNumberActiveSequences and (coaddedProgress / max(coaddedNumber, 1) > runProgress or currentActiveSequences < self.minNumberActiveSequences)): if randomizeSequencesSelection: fieldID = random.choice(listOfNewFields) else: fieldID = listOfNewFields[0] listOfNewFields.remove(fieldID) # create a new sequence object if fieldID not in self.sequences.keys(): self.SeqCount += 1 self.sequences[fieldID] = SuperSequence( self.propID, fieldID, self.SeqCount, self.WLtype, self.numGroupedVisits, self.masterSubSequence, self.subSeqName, self.subSeqNested, self.subSeqFilters, self.subSeqExposures, self.subSeqEvents, self.subSeqMaxMissed, self.subSeqInterval, self.subSeqWindowStart, self.subSeqWindowMax, self.subSeqWindowEnd, self.overflowLevel, self.progressToStartBoost, self.maxBoostToComplete) coaddedNumber += 1 newseq += 1 currentActiveSequences += 1 # was sequence lost? elif self.sequences[fieldID].IsLost(): if self.restartLostSequences: self.SeqCount += 1 self.sequences[fieldID].Restart(self.SeqCount) restartedlost += 1 currentActiveSequences += 1 else: # ZZZZ - mm debug 2nd delete of tonightTargets # print "Prop[%d].startNight() while targetsNewSeq: seq lost: delete "\ # "self.tonightTargets[%d] date = %d" % (self.propID, fieldID, date) del self.tonightTargets[fieldID] # was sequence completed? elif self.sequences[fieldID].IsComplete(): if self.restartCompleteSequences and not self.overflow: self.SeqCount += 1 self.sequences[fieldID].Restart(self.SeqCount) restartedcomplete += 1 currentActiveSequences += 1 else: # ZZZZ - mm debug 2nd delete of tonightTargets # print "Prop[%d].startNight() while targetsNewSeq: seq complete: "\ # "delete self.tonightTargets[%d] date = %d" % (self.propID, fieldID, date) del self.tonightTargets[fieldID] #else: # prog = self.sequences[fieldID].GetProgress() # if prog >= 1.0: # print "seqnNum=%i fieldID=%i progress=%f" % (self.sequences[fieldID].seqNum, fieldID, prog, # str(self.sequences[fieldID].allHistory), # self.sequences[fieldID].state) # From the broad target area, just keep the fields # associated to a target that is not lost and not complete self.tonightSubseqsForTarget = {} for fieldID in self.tonightTargets.keys(): if fieldID in self.sequences.keys(): complete_seq = self.sequences[fieldID].IsComplete( ) and not self.overflow if self.sequences[fieldID].IsLost() or complete_seq: # ZZZZ - mm debug 2nd delete of tonightTargets # print "Prop[%d].startNight() for tonightTargets() in self.sequences: seq is lost or "\ # "complete: delete self.tonightTargets[%d] date = %d" % (self.propID, fieldID, # date) # print "how would we ever get here?" del self.tonightTargets[fieldID] else: keptsequences += 1 self.tonightSubseqsForTarget[fieldID] = list( self.sequences[fieldID].subSeqName) # only pursue targets that are already started sequences else: # ZZZZ - mm debug 2nd delete of tonightTargets # print "TSS.startNight() for tonightTargets() and not in self.sequences: delete "\ # "self.tonightTargets[%d] date = %d" % (fieldID, date) del self.tonightTargets[fieldID] if coaddedNumber > 0: self.globalProgress = coaddedProgress / coaddedNumber else: self.globalProgress = 0.0 if self.log: self.log.info( '%sProp: startNight() propID=%d Sequences: new=%i deletedidle=%i ' 'restartedlost=%i restartedcomplete=%i total=%i targetprogress=%.3f%% ' 'runprogress=%.3f%%' % (self.propFullName, self.propID, newseq, notstarted, restartedlost, restartedcomplete, keptsequences, 100 * self.globalProgress, 100 * runProgress)) return def GetProgressPerFilter(self): coaddedNumber = 0 coaddedSubseqProgress = {} progressFilter = {} numsubseFilter = {} # for subseq in self.subSeqName: # coaddedSubseqProgress[subseq] = 0 for fieldID in self.sequences.keys(): if not self.sequences[fieldID].IsLost(): coaddedNumber += 1 for subseq in self.sequences[fieldID].subSeqName: progress = self.sequences[fieldID].GetProgress(subseq) if subseq in coaddedSubseqProgress.keys(): coaddedSubseqProgress[subseq] += progress else: coaddedSubseqProgress[subseq] = progress for filter in self.sequences[ fieldID].GetFilterListForSubseq(subseq): if filter in progressFilter.keys(): progressFilter[filter] += progress numsubseFilter[filter] += 1 else: progressFilter[filter] = progress numsubseFilter[filter] = 1 if coaddedNumber > 0: for subseq in coaddedSubseqProgress.keys(): coaddedSubseqProgress[subseq] /= coaddedNumber if self.log: for subseq in coaddedSubseqProgress.keys(): self.log.info( '%sProp: GetProgressPerFilter() propID=%d Sub-Sequence progress: %20s = %.3f%%' % (self.propFullName, self.propID, subseq, 100 * coaddedSubseqProgress[subseq])) # progressFilter = {} # numsubseFilter = {} # for ix in range(len(self.subSeqName)): # subseq = self.subSeqName[ix] # for filter in self.subSeqFilters[ix].split(','): # if filter != '': # if filter in progressFilter.keys(): # progressFilter[filter] += coaddedSubseqProgress[subseq] # numsubseFilter[filter] += 1 # else: # progressFilter[filter] = coaddedSubseqProgress[subseq] # numsubseFilter[filter] = 1 for filter in progressFilter.keys(): progressFilter[filter] /= numsubseFilter[filter] if self.log: for filter in progressFilter.keys(): self.log.info( '%sProp: GetProgressPerFilter() propID=%d Filter progress: %10s = %.3f%%' % (self.propFullName, self.propID, filter, 100 * progressFilter[filter])) return progressFilter def MissEvent(self, date, mjd, fieldID, subseq, obsHistID): self.sequences[fieldID].MissEvent(date, subseq, obsHistID) if self.log and self.verbose > 0 and not self.sequences[ fieldID].IsLost(): t_secs = date % 60 t_mins = (date % 3600) / 60 t_hour = (date % 86400) / 3600 t_days = date / 86400 progress = 100 * self.sequences[fieldID].GetProgress() self.log.info( '%sProp: suggestObs() subevent MISSED for propID=%d field=%i subseq=%s ' 't=%dd%02dh%02dm%02ds progress=%i%%' % (self.propFullName, self.propID, fieldID, subseq, t_days, t_hour, t_mins, t_secs, progress)) filter = self.sequences[fieldID].GetNextFilter(subseq) obs = self.obsPool[fieldID][filter] obs.propID = self.propID obs.seqn = self.sequences[fieldID].seqNum obs.subsequence = subseq obs.pairNum = self.sequences[fieldID].GetPairNum(subseq) obs.date = date obs.mjd = mjd super(TransSubSeqProp, self).missObservation(obs) return def suggestObs(self, dateProfile, n=100, exclusiveObservation=None, minDistance2Moon=0.0, rawSeeing=0.0, seeing=0.0, transparency=0.0, sdnight=0, sdtime=0): """ Return the list of (at most) the n (currently) higher ranking observations. Input dateProfile current date profile of: (date,mjd,lst_RAD) where: date simulated time (s) mjd lst_RAD local sidereal time (radians) moonProfile current moon profile of: (moonRA_RAD,moonDec_RAD,moonPhase_PERCENT) moonPhase current moon phase in range [0-100] n number of observations to return. Return An array of the (at most) n highest ranking observations, ordered from the highest ranking obs to the lowest. """ if self.log and self.verbose > 1: self.log.info('%sProp: suggestObs() propID=%d' % (self.propFullName, self.propID)) # Copy the input vars # inFieldID = skyfields # inproximity = proximity # intargetProfiles = targetProfiles (date, mjd, lst_RAD) = dateProfile (moonRA_RAD, moonDec_RAD, moonPhase_PERCENT) = self.schedulingData.moonProfile[sdnight] # Check the start/end of observing cycle. # For NEA the lunation is checked if self.CheckObservingCycle(date): # Create a priority queue to choose the best n obs self.clearSuggestList() # If in an exclusive block, no new observation candidates. If this # proposal originated request, it should re-suggest observation. if exclusiveObservation is not None: # adjust counter for one obs # self.reuseRanking -= 1 if exclusiveObservation.propID == self.propID: # The exclusive block is for this proposal so we just suggest our exclusive observation fieldID = exclusiveObservation.fieldID subseq = self.exclusiveSubseq rank = 1.0 # i = inFieldID.index (fieldID) #airmass = self.schedulingData.airmass[fieldID][sdtime] filter = self.sequences[fieldID].GetNextFilter(subseq) #print filter exclusiveBlockRequired = self.sequences[ fieldID].GetExclusiveBlockNeed(subseq) #print "exclusiveBlockRequired = %s" % (exclusiveBlockRequired) recordFieldFilter = self.obsPool[fieldID][filter] recordFieldFilter.propID = self.propID recordFieldFilter.subsequence = subseq recordFieldFilter.seqn = self.sequences[fieldID].seqNum recordFieldFilter.pairNum = self.sequences[ fieldID].GetPairNum(subseq) recordFieldFilter.date = date recordFieldFilter.mjd = mjd recordFieldFilter.night = sdnight recordFieldFilter.exposureTime = self.exposureTime recordFieldFilter.propRank = rank recordFieldFilter.maxSeeing = self.exclusiveObs.maxSeeing recordFieldFilter.rawSeeing = self.exclusiveObs.rawSeeing recordFieldFilter.seeing = self.exclusiveObs.seeing recordFieldFilter.transparency = self.exclusiveObs.transparency recordFieldFilter.cloudSeeing = self.exclusiveObs.cloudSeeing recordFieldFilter.airmass = self.exclusiveObs.airmass recordFieldFilter.skyBrightness = self.exclusiveObs.skyBrightness recordFieldFilter.lst = lst_RAD recordFieldFilter.altitude = self.exclusiveObs.altitude recordFieldFilter.azimuth = self.exclusiveObs.azimuth recordFieldFilter.distance2moon = self.exclusiveObs.distance2moon recordFieldFilter.moonRA = self.exclusiveObs.moonRA recordFieldFilter.moonDec = self.exclusiveObs.moonDec recordFieldFilter.moonAlt = self.exclusiveObs.moonAlt recordFieldFilter.moonPhase = self.exclusiveObs.moonPhase recordFieldFilter.exclusiveBlockRequired = exclusiveBlockRequired self.addToSuggestList(recordFieldFilter) return self.getSuggestList(1) else: # The exclusive block is not for this proposal so we don't propose observations # but we must update the ranking and availability of the exclusive observation for # correct serendipity if exclusiveObservation.fieldID in self.tonightTargets.keys( ): listOfFieldsToEvaluate = [exclusiveObservation.fieldID] else: listOfFieldsToEvaluate = [] # return [] numberOfObsToPropose = 0 else: # Normal observation block, all proposals competing # If not time to rerank fields, return no suggestions. # if self.reuseRanking > 1: # self.reuseRanking -= 1 # return [] #listOfFieldsToEvaluate = self.tonightTargets.keys() listOfFieldsToEvaluate = sorted(self.tonightTargets.iterkeys()) numberOfObsToPropose = n # ZZZ - This block needs attention. Do we get here? Does it make sense? - mm if self.exclusiveBlockNeeded: # We needed an exclusive block to complete the current event # so we miss this event and evaluate if the sequence is missed or complete fieldID = self.exclusiveField subseq = self.exclusiveSubseq self.exclusiveBlockNeeded = False obsHist = self.lsstDB.addMissedObservation( self.sequences[fieldID].GetNextFilter(subseq), date, mjd, sdnight, lst_RAD, self.sessionID, fieldID) self.MissEvent(date, mjd, fieldID, subseq, obsHist.missedHistID) fields_received = len(listOfFieldsToEvaluate) fields_invisible = 0 fields_moon = 0 events_waiting = 0 events_proposed = 0 events_missed = 0 seq_lost = 0 seq_completed = 0 events_nottonight = 0 events_nofilter = 0 events_noseeing = 0 for fieldID in listOfFieldsToEvaluate: fieldRecordList = [] # ra and dec variables are unused!!!!! #ra = self.tonightTargets[fieldID][0] #dec = self.tonightTargets[fieldID][1] #i = inFieldID.index (fieldID) if fieldID == self.last_observed_fieldID and self.last_observed_wasForThisProposal and \ not self.AcceptConsecutiveObs: continue airmass = self.schedulingData.airmass[sdtime][fieldID] if airmass > self.maxAirmass: if self.log and self.verbose > 2: self.log.info( '%sProp: suggestObs() propID=%d field=%i too low:%f' % (self.propFullName, self.propID, fieldID, airmass)) fields_invisible += 1 continue distance2moon = self.schedulingData.dist2moon[sdtime][fieldID] if distance2moon < minDistance2Moon: fields_moon += 1 # remove the target for the rest of the night if it is too close to the moon # ZZZZ - mm debug 2nd delete of tonightTargets # print "Prop[%d].suggestObs():too close to moon - delete self.tonightTargets[%d] date = %d" \ # % (self.propID, fieldID, date) del self.tonightTargets[fieldID] continue # if not self.sequences[fieldID].HasEventsTonight(date): # seq_nottonight += 1 # del self.tonightTargets[fieldID] # continue #............................................................. # Gets the list of possible filters based on the sky brightness skyBrightness = self.schedulingData.brightness[sdtime][fieldID] allowedFilterList = self.allowedFiltersForBrightness( skyBrightness) filterSeeingList = self.filters.computeFilterSeeing( seeing, airmass) #rankForFilters = self.RankFilters(fieldID, filterSeeingList) #............................................................. for subseq in self.tonightSubseqsForTarget[fieldID]: # Prevents that a lost sequence due to a missed event # keeps beeing evaluated for the other subsequences # wasting time and triggering an error when deleting # the already deleted field from the target list. if self.sequences[fieldID].IsLost(): continue allfiltersavailable = True for f in self.sequences[fieldID].GetFilterListForSubseq( subseq): if f not in allowedFilterList: allfiltersavailable = False events_nofilter += 1 elif filterSeeingList[f] > self.FilterMaxSeeing[f]: allfiltersavailable = False events_noseeing += 1 if allfiltersavailable is False: continue # Boost factor according to the remaining observable days on sky if self.DaysLeftToStartBoost > 0.0 and self.rankDaysLeftMax != 0.0: observableDaysLeft = max( (self.ha_twilight[fieldID] + self.ha_maxairmass) * 15.0, 0.0) rankDaysLeft = max( 1.0 - observableDaysLeft / self.DaysLeftToStartBoost, 0.0) else: rankDaysLeft = 0.0 if self.WLtype or self.sequences[fieldID].IsActive(subseq): (rankTime, timeWindow) = self.sequences[fieldID].RankTimeWindow( subseq, date) rankLossRisk = max( 1.0 - 0.5 * self.sequences[fieldID]. GetRemainingAllowedMisses(subseq), 0.0) elif self.sequences[fieldID].IsIdle(subseq): rankTime = self.rankIdleSeq / self.rankTimeMax timeWindow = True rankLossRisk = 0.0 else: rankTime = 0.0 timeWindow = False rankLossRisk = 0.0 if rankTime == -0.1: events_nottonight += 1 self.tonightSubseqsForTarget[fieldID].remove(subseq) elif rankTime > 0.0: events_proposed += 1 # print 'ha_twilight=' + str(self.ha_twilight[fieldID]) + ' ha_maxairmass='\ # + str(self.ha_maxairmass) + ' observableDaysLeft=' + str(observableDaysLeft)\ # + ' rankDaysLeft=' + str(rankDaysLeft) if timeWindow: factor = self.rankTimeMax else: if self.globalProgress < 1.0: factor = self.rankIdleSeq / ( 1.0 - self.globalProgress) elif self.overflowLevel > 0.0: factor = self.rankIdleSeq / ( self.overflowLevel / self.globalProgress) rank = rankTime * factor + rankLossRisk * self.rankLossRiskMax \ + rankDaysLeft * self.rankDaysLeftMax filter = self.sequences[fieldID].GetNextFilter(subseq) #print 'fieldID='+str(fieldID)+' subseq='+str(subseq)+' filter='+str(filter) exclusiveBlockRequired = self.sequences[ fieldID].GetExclusiveBlockNeed(subseq) # Create the corresponding Observation recordFieldFilter = self.obsPool[fieldID][filter] #recordFieldFilter.sessionID = sessionID recordFieldFilter.propID = self.propID recordFieldFilter.subsequence = subseq #recordFieldFilter.fieldID = fieldID #recordFieldFilter.filter = filter recordFieldFilter.seqn = self.sequences[fieldID].seqNum recordFieldFilter.pairNum = self.sequences[ fieldID].GetPairNum(subseq) recordFieldFilter.date = date recordFieldFilter.mjd = mjd recordFieldFilter.night = sdnight recordFieldFilter.exposureTime = self.exposureTime #recordFieldFilter.slewTime = slewTime #recordFieldFilter.rotatorSkyPos = 0.0 #recordFieldFilter.rotatorTelPos = 0.0 recordFieldFilter.propRank = rank #recordFieldFilter.finRank = finRank recordFieldFilter.maxSeeing = self.FilterMaxSeeing[ filter] recordFieldFilter.rawSeeing = rawSeeing recordFieldFilter.seeing = filterSeeingList[filter] recordFieldFilter.transparency = transparency #recordFieldFilter.cloudSeeing = intargetProfiles[i][4] recordFieldFilter.airmass = airmass recordFieldFilter.skyBrightness = skyBrightness #recordFieldFilter.ra = ra #recordFieldFilter.dec = dec recordFieldFilter.lst = lst_RAD recordFieldFilter.altitude = self.schedulingData.alt[ sdtime][fieldID] recordFieldFilter.azimuth = self.schedulingData.az[ sdtime][fieldID] recordFieldFilter.parallactic = self.schedulingData.pa[ sdtime][fieldID] recordFieldFilter.distance2moon = distance2moon recordFieldFilter.moonRA = moonRA_RAD recordFieldFilter.moonDec = moonDec_RAD #recordFieldFilter.moonAlt = intargetProfiles[i][8] recordFieldFilter.moonPhase = moonPhase_PERCENT recordFieldFilter.exclusiveBlockRequired = exclusiveBlockRequired fieldRecordList.append(recordFieldFilter) elif rankTime < 0.0: events_missed += 1 oh_filter = self.sequences[fieldID].GetNextFilter( subseq) obsHist = self.lsstDB.addMissedObservation( oh_filter, date, mjd, sdnight, lst_RAD, self.sessionID, fieldID) self.MissEvent(date, mjd, fieldID, subseq, obsHist.missedHistID) if self.sequences[fieldID].IsLost(): if self.log and self.verbose > 0: self.log.info( '%sProp: suggestObs() sequence LOST for propID=%d field=%i ' 't=%.0f event missed' % (self.propFullName, self.propID, fieldID, date)) # Update the SeqHistory database seq = self.sequences[fieldID] seqHist = self.lsstDB.addSeqHistory( seq.date, date, seq.seqNum, seq.GetProgress(), seq.GetNumTargetEvents(), seq.GetNumActualEvents(), MAX_MISSED_EVENTS, 0, fieldID, self.sessionID, self.propID) for obsID in seq.GetListObsID(): self.lsstDB.addSeqHistoryObsHistory( seqHist.sequenceID, obsID, self.sessionID) for misID in seq.GetListMisID(): self.lsstDB.addSeqHistoryMissedHistory( seqHist.sequenceID, misID, self.sessionID) seq_lost += 1 # ZZZZ - mm debug 2nd delete of tonightTargets print "Prop[%d].suggestObs() seq lost: delete self.tonightTargets[%d] date = %d"\ % (self.propID, fieldID, date) del self.tonightTargets[fieldID] # Also remove the posible previously considered subsequences # as the whole sequence is now lost they must not be proposed. fieldRecordList = [] # it is also possible that the missed event was the last needed for completing the # sequence in such a case the sequence object determines the completion of the # sequence. elif self.sequences[fieldID].IsComplete(): self.CompleteSequence(fieldID, date) seq_completed += 1 fieldRecordList = [] else: # rankTime==0.0 events_waiting += 1 if self.tonightSubseqsForTarget[fieldID] == []: # ZZZZ - mm debug 2nd delete of tonightTargets # print "Prop[%d].suggestObs() no subseqs for target: delete self.tonightTargets[%d] "\ # "date = %d" % (self.propID, fieldID, date) del self.tonightTargets[fieldID] for record in fieldRecordList: self.addToSuggestList(record) if self.log and self.verbose > 0: self.log.info( '%sProp: suggestObs() propID=%d : Fields received=%i invisible=%i moon=%i ' 'Events nottonight=%i waiting=%i nofilter=%i noseeing=%i proposed=%i missed=%i ' 'Sequences lost=%i completed=%i' % (self.propFullName, self.propID, fields_received, fields_invisible, fields_moon, events_nottonight, events_waiting, events_nofilter, events_noseeing, events_proposed, events_missed, seq_lost, seq_completed)) # Choose the n highest ranking observations # self.reuseRanking = self.reuseRankingCount return self.getSuggestList(numberOfObsToPropose) else: # The cycle has ended and next one hasn't started yet (full moon for NEA) return [] def getFieldCoordinates(self, fieldID): """ Given a fieldID, fetch the corresponding values for RA and Dec Input fieldID: a field identifier (long int) Return (ra, dec) in decimal degrees Raise Exception if fieldID is unknown. """ return self.targets[fieldID] def setMaxSeeing(self, seeing): """ Setter method for self.seeing Input seeing: float Return None """ # self.maxSeeing = float(seeing) return def setSlewTime(self, slewTime): """ Setter method for self.maxSlewTime Input slewTime: float Return None """ self.maxSlewTime = float(slewTime) return def closeObservation(self, observation, obsHistID, twilightProfile): """ Registers the fact that the indicated observation took place. This is, the corresponding event in the sequence of the indicated fieldID has been executed, and the sequence can continue. Input obs an Observation instance winslewTime slew time required for the winning observation Return None Raise Exception if Observation History update fails """ if not self.IsObservingCycle(): self.last_observed_wasForThisProposal = False return None # if self.log and self.verbose > 1: # self.log.info('%sProp: closeObservation()' % (self.propFullName)) obs = super(TransSubSeqProp, self).closeObservation(observation, obsHistID, twilightProfile) if obs is not None: self.sequences[obs.fieldID].ObserveEvent(obs.date, obs.subsequence, obsHistID) progress = self.sequences[obs.fieldID].GetProgress() if self.log and self.verbose > 0: t_secs = obs.date % 60 t_mins = (obs.date % 3600) / 60 t_hour = (obs.date % 86400) / 3600 t_days = obs.date / 86400 if self.sequences[obs.fieldID].IsEventInProgress( obs.subsequence): progrmod = '+' else: progrmod = '' self.log.info( '%s: closeObservation() propID=%d field=%d filter=%s propRank=%.4f ' 'finRank=%.4f t=%dd%02dh%02dm%02ds progress=%d%s%%' % (self.propConf, self.propID, obs.fieldID, obs.filter, obs.propRank, obs.finRank, t_days, t_hour, t_mins, t_secs, int(100 * progress), progrmod)) if obs.exclusiveBlockRequired: self.exclusiveBlockNeeded = True self.exclusiveObs = copy.copy(obs) self.exclusiveField = obs.fieldID self.exclusiveSubseq = obs.subsequence else: self.exclusiveBlockNeeded = False # if sequence is complete, then deletes target from tonight's list. if progress == 1.0: self.CompleteSequence(obs.fieldID, obs.date) self.exclusiveBlockNeeded = False return obs def CompleteSequence(self, fieldID, date): # Update sequence history DB seq = self.sequences[fieldID] seqHist = self.lsstDB.addSeqHistory(seq.date, date, seq.seqNum, seq.GetProgress(), seq.GetNumTargetEvents(), seq.GetNumActualEvents(), SUCCESS, 0, fieldID, self.sessionID, self.propID) for obsID in seq.GetListObsID(): self.lsstDB.addSeqHistoryObsHistory(seqHist.sequenceID, obsID, self.sessionID) for misID in seq.GetListMisID(): self.lsstDB.addSeqHistoryMissedHistory(seqHist.sequenceID, misID, self.sessionID) if not self.overflow: # ZZZZ - mm debug 2nd delete of tonightTargets # print "Prop[%d].CompleteSequence() delete self.tonightTargets[%d] date = %d" % (self.propID, # fieldID, date) if fieldID in self.tonightTargets.keys(): del self.tonightTargets[fieldID] if self.log and self.verbose > 0: self.log.info( '%sProp: CompleteSequence() sequence COMPLETE for propID=%d field=%d' % (self.propFullName, self.propID, fieldID)) return def FinishSequences(self, obsdate): """ Finishes the current sequences. """ if self.log: self.log.info('%sProp: FinishSequences()' % (self.propFullName)) for fieldID in self.sequences.keys(): if (not self.sequences[fieldID].IsComplete()) and ( not self.sequences[fieldID].IsLost()): if self.log: self.log.info( '%sProp: suggestObs() propID=%d sequence LOST for field=%i end of cycle' % (self.propFullName, self.propID, fieldID)) self.sequences[fieldID].Abort() # Update sequence history DB seq = self.sequences[fieldID] seqHist = self.lsstDB.addSeqHistory(seq.date, obsdate, seq.seqNum, seq.GetProgress(), seq.GetNumTargetEvents(), seq.GetNumActualEvents(), CYCLE_END, 0, fieldID, self.sessionID, self.propID) for obsID in seq.GetListObsID(): self.lsstDB.addSeqHistoryObsHistory( seqHist.sequenceID, obsID, self.sessionID) for misID in seq.GetListMisID(): self.lsstDB.addSeqHistoryMissedHistory( seqHist.sequenceID, misID, self.sessionID) return def closeProposal(self, time): """ Finishes the current sequences. """ if self.log: self.log.info('%sProp: closeProposal()' % (self.propFullName)) for fieldID in self.sequences.keys(): if (not self.sequences[fieldID].IsComplete()) and ( not self.sequences[fieldID].IsLost()): if self.log: self.log.info( '%sProp: closeProposal() propID=%d sequence LOST for field=%i end of ' 'simulation' % (self.propFullName, self.propID, fieldID)) #self.sequences[fieldID].Abort() # Update sequence history DB seq = self.sequences[fieldID] seqHist = self.lsstDB.addSeqHistory(seq.date, time, seq.seqNum, seq.GetProgress(), seq.GetNumTargetEvents(), seq.GetNumActualEvents(), SIMULATION_END, 0, fieldID, self.sessionID, self.propID) for obsID in seq.GetListObsID(): self.lsstDB.addSeqHistoryObsHistory( seqHist.sequenceID, obsID, self.sessionID) for misID in seq.GetListMisID(): self.lsstDB.addSeqHistoryMissedHistory( seqHist.sequenceID, misID, self.sessionID) # delete OlapField user-defined region table if self.userRegion[0] is not None: overlappingField = "OlapField_%d_%d" % (self.sessionID, self.propID) # Result from below is never used self.lsstDB.dropTable(overlappingField) return def RestartSequences(self): if self.log: self.log.info('%sProp: RestartFinishedSequences() propID=%d' % (self.propFullName, self.propID)) for fieldID in self.sequences.keys(): if self.sequences[fieldID].IsLost( ) or self.sequences[fieldID].IsComplete(): self.SeqCount += 1 self.sequences[fieldID].Restart(self.SeqCount) if self.log and self.verbose > 0: self.log.info( '%sProp: RestartSequences() sequence for propID=%d field=%i restarted' % (self.propFullName, self.propID, fieldID)) return def updateTargetList(self, dateProfile, obsProfile, sky, fov): return