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