def lunarDistance(fld, startTime, endTime): """Calculate the distance to the moon at starttime and end time.""" # Position of the target cast into pyeEphem Angle tarRa = pyEphem.hours(fld['ra'].values[0]) tarDec = pyEphem.degrees(fld['dec'].values[0]) # Moon Position moonRa1, moonDec1 = MMTEphem.moonPosition(startTime) moonRa2, moonDec2 = MMTEphem.moonPosition(endTime) dist1 = angSep(moonRa1, moonDec1, tarRa, tarDec) dist2 = angSep(moonRa2, moonDec2, tarRa, tarDec) return (dist1 + dist2) / 2.0
def lunarDistance(fld, startTime, endTime): """Calculate the distance to the moon at starttime and end time.""" # Position of the target cast into pyeEphem Angle tarRa = pyEphem.hours(fld['ra'].values[0]) tarDec = pyEphem.degrees(fld['dec'].values[0]) # Moon Position moonRa1, moonDec1 = MMTEphem.moonPosition(startTime) moonRa2, moonDec2 = MMTEphem.moonPosition(endTime) dist1 = angSep(moonRa1, moonDec1, tarRa, tarDec) dist2 = angSep(moonRa2, moonDec2, tarRa, tarDec) return (dist1+dist2)/2.0
def obsOneNight(fldPar, donePar, date): """Fully Schedules one night.""" # Get the ephemeris for the night mmt = MMTEphem.ephem(date) startTime = mmt.eveningTwilight # Now, start at twilight and add observervations. Each # time increment currentTime by the observation time # If no observations are found, add 5 minutes and check again currentTime = startTime schedule = [] # Will contain scheduled fields allDone = False prevPos = None while (currentTime < mmt.morningTwilight) & (allDone is False): newSched, prevPos = obsUpdateRow(fldPar, donePar, currentTime, mmt, prevPos) # Check to see if something was observed if newSched is None: # Increment time and continue currentTime += datetime.timedelta(minutes=20) else: # Append new entry to schedule, increment currentTime # by exposure time. schedule.append(newSched) currentTime += datetime.timedelta(seconds=newSched[1]) completed = donePar['complete'].values if min(completed) == 1: allDone = True return schedule
def readAllocatedTime(startDay="1900/1/1", endDay="3000/1/1"): """Read a log file to determine how much each PI was allocated.""" filename = "AllocatedTime.dat" f = open(filename, 'r') if type(startDay) == str: startDay = pyEphem.date(startDay).datetime() if type(endDay) == str: endDay = pyEphem.date(endDay).datetime() allocatedTime = {} for line in f.readlines(): if line[0] == '#': # Comment string, skip continue date, PI = line.strip().split() date = pyEphem.date(date).datetime() mmt = MMTEphem.ephem(date) if (abs((date-startDay).total_seconds()) < 24*3600.) | \ (abs((date-endDay).total_seconds()) < 24*3600.): # This night is not in the current run continue nightLength = (mmt.morningTwilight - mmt.eveningTwilight) nightLength = nightLength.total_seconds() / 3600.0 if PI in allocatedTime: allocatedTime[PI] += nightLength else: allocatedTime[PI] = nightLength return allocatedTime
def calcMoonFlag(fld, startTime, endTime, mmt): """Calculate the IGNORE_FLAG based on lunar brightness and position. Inputs: fld -- field parameter entry from obsPars startTime -- datetime formatted starting time endTime -- datetime formatted ending time Output: flag -- 0/1 flag marking if the field is too close to the moon or the moon is brighter than specified. """ moonUp = moonUpDuringObs(startTime, endTime, mmt) moonAge = MMTEphem.moonAge(startTime) # Get the distance to the moon moonDist = lunarDistance(fld, startTime, endTime) # Now do brightness flag moonReq = fld['moon'].values[0] if (moonReq == 'bright') | (moonUp == 0): # Anything works, either we were asked for bright # time or the moon isn't up during # the entirety of the observation illumFlag = 1 elif (moonReq == 'grey') & (abs(moonAge) < 9) & (moonDist < 90): # We were asked for grey time and it's grey time illumFlag = 1 elif (moonReq == 'dark') & (abs(moonAge) < 4.5) & (moonDist > 90.0): # We were asked for dark time and it's dark time illumFlag = 1 else: illumFlag = 0 # This isn't going to work here! # Flag things that are just plain too close to the moon if moonDist < 10: illumFlag = 0 return illumFlag
def obsUpdateRow(fldPar, donePar, startTime, mmt, prevPos=None): """Calculate observing weight for given observation. Input: fldpar : DataFrame for a single observation. Comes from readAllFLDFiles (i.e. not a single dictionary) donepar : Dataframe with stats pertaining to a fields doneness starTime : datetime string for beginning time for observation """ # The idea here is to loop through all of the fields and calculate # the weight for this startTime. weightList = [] # Will store array of dicts with weight info for objID in fldPar["objid"]: # Is this already observed? donefld = donePar[donePar['objid'] == objID] fld = fldPar[fldPar["objid"] == objID] if donefld['complete'].values[0] == 1: continue # Initialize the weight dictionary obsWeight = {} obsWeight['objid'] = objID objEphem = MMTEphem.ObjEphem(fld['ra'].values[0], fld['dec'].values[0], startTime, mmt) fitWeight, endTime, fitVisits = willItFitWeight( fld, startTime, mmt, objEphem, donefld) moonFlag = calcMoonFlag(fld, startTime, endTime, mmt) # Does this observation have one very close by dist_weight = 1 if prevPos is not None: dist = angSep( hms2dec(fld['ra'].values[0]) * 15.0, hms2dec(fld['dec'].values[0]), prevPos[0], prevPos[1]) if dist < 10. / 3600.: dist_weight = 1000 obsWeight['fitWeight'] = fitWeight obsWeight['obsTime'] = (endTime - startTime).total_seconds() obsWeight['moonFlag'] = moonFlag obsWeight['nVisits'] = fitVisits obsWeight['ra'] = fld['ra'].values[0] obsWeight['dec'] = fld['dec'].values[0] # Priority Weight priorFlag = 1.0 / float(fld['priority'])**3 # Now combine the weights weightTAC = 1.0 - 1.0 * donefld['doneTime'].values[0] \ / donefld['totalTime'].values[0] if weightTAC < 0: weightTAC = 0.001 totalWeight = fitWeight * moonFlag * \ (weightTAC) *dist_weight*priorFlag # We need to account for a few extra things. # 1. I want fields that have had previously observed # fields to be the top priority if they are observable. # This modification will weight fields with no observations # at one (1+0) and those partially observed at 10 partCompWeight = int(donefld['doneVisit'].values[0] > 0) #totalWeight = totalWeight * (1+0.5*partCompWeight) # Now account for weighting from preivous iteration of the # code. This should smooth things out totalWeight = totalWeight / donefld['prevWeight'].values[0] obsWeight['totalWeight'] = totalWeight # Append to weight listing weightList.append(obsWeight) obsWeights = pd.DataFrame(weightList) # Doing the O(n) problem here hasMax = [] # Check to see there are actually targets! if len(obsWeights) == 0: return None, None maxWeight = max(obsWeights['totalWeight']) for ii in range(len(obsWeights)): if obsWeights['totalWeight'].values[ii] == maxWeight: hasMax.append(ii) # Now, check there are some with non-zero weight and # Observe a random one if maxWeight == 0: # No targets were done. return None, None else: # This allows for random choice. randIndex = hasMax[randint(0, len(hasMax) - 1)] diffTime = obsWeights['obsTime'].values[randIndex] # Increment the schedule schedule = [] schedule.append(startTime) schedule.append(diffTime) schedule.append(obsWeights['objid'].values[randIndex]) schedule.append(obsWeights['nVisits'].values[randIndex]) outPos = [ hms2dec(obsWeights['ra'].values[randIndex]) * 15.0, hms2dec(obsWeights['dec'].values[randIndex]) ] # Update the done masks index = [i for i, x in enumerate(donePar['objid'] == schedule[2]) if x] # Donetime tracks total time for this PI. We weight by # this, so let's increment all entries in donefld PI = donePar.loc[index, 'PI'].values[0] for ii in range(len(fldPar)): if donePar["PI"].values[ii] == PI: donePar.loc[ii, 'doneTime'] += diffTime / 3600. donePar.loc[ii, 'currentWeight'] = \ donePar.loc[ii, 'doneTime'] / \ donePar.loc[ii, 'totalTime'] donePar.loc[index, 'doneVisit'] += \ obsWeights['nVisits'].values[randIndex] # Check to see if the target is now done requested = int( fldPar[fldPar['objid'] == schedule[2]]["repeats"].values[0]) if int(donePar.loc[index, 'doneVisit']) >= requested: donePar.loc[index, 'complete'] = 1 return schedule, outPos