def calibrate(self, script, time): s_calibrate = os.path.join(ScriptDir,"calibrate") if self.test: print "Test Mode: calibrate %s %s." % (script, time) APFTask.waitFor(self.task, True, timeout=10) return True if time == 'pre' or 'post': try: APFLib.write("apfmot.DEWARFOCRAW",ktl.read("apftask","FOCUSINSTR_LASTFOCUS",binary=True)) except: apflog("Cannot read the last best fitting focus value or write the dewar focus value", level='error') if self.dewarfoc > 8600 or self.dewarfoc < 8400: apflog("Warning: The dewar focus is currently %d. This is outside the typical range of acceptable values." % (self.dewarfoc), level = "error", echo=True) return False apflog("Running calibrate %s %s" % (script, time), level = 'info') owner = self.apfschedule('OWNRHINT').read() self.apfschedule('OWNRHINT').write('public') cmd = '%s %s %s' % (s_calibrate,script, time) result, code = cmdexec(cmd,debug=True,cwd=os.getcwd()) if not result: apflog("%s %s failed with return code %d" % (s_calibrate, script, code),echo=True) expression="($apftask.CALIBRATE_STATUS != 0) and ($apftask.CALIBRATE_STATUS != 1) " if not APFTask.waitFor(self.task,True,expression=expression,timeout=30): apflog("%s %s failed to exit" % (s_calibrate,script),echo=True) self.apfschedule('OWNRHINT').write(owner) return result else: print "Couldn't understand argument %s, nothing was done." % time
def getTarget(): APFLib.write(self.apf.ucam["RECORD"], "Yes") # safe / sorry if self.apf.nerase != 2: self.apf.nerase.write(2, binary=True) if self.checkObsFinished(): apflog( "getTarget(): Scriptobs phase is input, determining next target.", echo=True) else: apflog("getTarget(): Not at end of block but out of targets.", echo=True) try: self.obsBstar = ktl.read("apftask", "MASTER_OBSBSTAR", binary=True) apflog("getTarget(): Setting obsBstar to %s" % (str(self.obsBstar)), echo=True) except Exception, e: apflog("getTarget(): Cannot read apftask.MASTER_OBSBSTAR: %s" % (e), level='error', echo=True) self.obsBstar = True
def DMZero(self): try: if self.checkapf['DMTIME'].read(binary=True) < 1: APFLib.write(self.checkapf['DMTIME'], -1,timeout=10) except Exception, e: ostr = "Error: cannot touch DM Timer: %s " %( e) apflog(ostr,level='error',echo=True)
def openat(self, sunset=False): """Function to ready the APF for observing. Calls either openatsunset or openatnight. This function will attempt to open successfully twice. If both attempts fail, then it will return false, allowing the master to register the error and behave accodingly. Otherwise it will return True. """ # If this is a test run, just return True if self.test: return True if not self.ok2open: # This should really never happen. In case of a temporary condition, we give # a short waitfor rather than immediatly exiting. chk_open = "$checkapf.OPEN_OK == true" result = APFLib.waitFor(self.task, False, chk_open, timeout=30) if not result: apflog("Tried calling openat with OPEN_OK = False. Can't open.", echo=True) apflog(self.checkapf["OPREASON"].read(), echo=True) return False if float(self.sunel) > SUNEL_HOR: apflog("Sun is still up. Current sunel = %4.2f. Can't open." % self.sunel, echo=True) return False if self.mv_perm.binary == False: apflog("Waiting for permission to move...", echo=True) chk_move = "$checkapf.MOVE_PERM == true" result = APFTask.waitFor(self.task, False, chk_move, timeout=600) if not result: apflog("Can't open. No move permission.",echo=True) return False if self.states_set(): apflog("An unusal emergency state is set.", level="error",echo=True) return False # Everything seems acceptable, so lets try opening if sunset: cmd = '/usr/local/lick/bin/robot/openatsunset' else: cmd = '/usr/local/lick/bin/robot/openatnight' # Make two tries at opening. If they both fail return False so the caller can act # accordingly. result, code = cmdexec(cmd) if not result: apflog("First openup attempt has failed. Exit code = %d. After a pause, will make one more attempt." % code,echo=True) APFTask.waitFor(self.task, True, timeout=10) result, code = cmdexec(cmd) if not result: apflog("Second openup attempt also failed. Exit code %d. Giving up." % code,echo=True) return False rv = self.checkhome() if rv == False: return False try: APFLib.write("eostele.FOCUS",ktl.read("apftask","FOCUSTEL_LASTFOCUS",binary=True)) except: apflog("Cannot move secondary focus.",level="error") return False return True
def updateLastObs(self,obsnum): """ If the last observation was a success, this function updates the file storing the last observation number and the hit_list which is required by the dynamic scheduler.""" if obsnum['populated']: if self.ucam('OUTFILE').read() == 'ucsc': APFLib.write(self.robot["MASTER_LAST_OBS_UCSC"], obsnum) # else: # apflog("UCAM Observer name is not ucsc, so the lastObs value will not be updated.") # apflog("Number of last observation is %s" % self.obsnum.read()) return
def DMReset(self): try: APFLib.write(self.checkapf['ROBOSTATE'], "master operating",timeout=10) except Exception, e: try: ukind = self.checkapf['USERKIND'].read() except: ukind = "Unknown" ostr = "Error: Cannot write to ROBOSTATE, USERKIND = %s, reason: %s" % (ukind,e) apflog(ostr,level='error',echo=True)
def killRobot(self, now=False): """ In case during an exposure there is a need to stop the robot and close up.""" apflog("Terminating Robot.csh") if now: apflog("Abort exposure, terminating robot now.") else: if not ucam['EVENT_STR'].read() == "ControllerReady": apflog("Waiting for current exposure to finish.") ucam['EVENT_STR'].waitfor(" = ReadoutBegin", timout=1200) apflog("Killing Robot.") ripd, running = self.findRobot() if running: APFLib.write(self.robot['scriptobs_control'], "abort")
def startRobot(self): """Start an instance of scriptobs. Returns the result from subprocess.Popen().""" # For running in test mode if self.test: apflog("Would be taking observation in starlist %s" % observation) APFTask.waitFor(self.task, True, timeout=300) return # Make sure the telescope autofocus is enabled APFLib.write(self.autofoc, "robot_autofocus_enable") chk_foc = '$apftask.SCRIPTOBS_AUTOFOC == robot_autofocus_enable' result = APFTask.waitFor(self.task, False, chk_foc, timeout=60) if not result: apflog("Error setting scriptobs_autofoc", echo=True) return # Make sure APFTEQ is in night mode for observations if self.teqmode.read() != 'Night': self.setTeqMode('Night') # Check the instrument focus for a reasonable value if self.dewarfoc > DEWARMAX or self.dewarfoc < DEWARMIN: lastfit_dewarfoc = ktl.read("apftask","FOCUSINSTR_LASTFOCUS",binary=True) apflog("Warning: The dewar focus is currently %d. This is outside the typical range of acceptable values. Resetting to last derived value %d" % (self.dewarfoc,lastfit_dewarfoc), level = "error", echo=True) APFLib.write("apfmot.DEWARFOCRAW",lastfit_dewarfoc) robotdir = "/usr/local/lick/bin/robot/" telstate = tel['TELSTATE'].read() if telstate == 'Disabled': rv, retc = cmdexec(os.path.join(robotdir,"slew --hold")) if not rv: return rv rv, retc = cmdexec(os.path.join(robotdir,"prep-obs")) if not rv: return rv # Start scriptobs outfile = open("robot.log", 'a') args = ['/usr/local/lick/bin/robot/scriptobs', '-dir', os.getcwd()] p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=outfile, stderr=outfile) return p
def updateWindshield(self, state): """Checks the current windshielding mode, and depending on the input and wind speed measurements makes sure it is set properly.""" currState = self.robot["SCRIPTOBS_WINDSHIELD"].read().strip().lower() if state == 'on': if currState != 'enable': APFLib.write(self.robot["SCRIPTOBS_WINDSHIELD"], "Enable") elif state == 'off': if currState != 'disable': APFLib.write(self.robot["SCRIPTOBS_WINDSHIELD"], "Disable") else: # State must be auto, so check wind if currState == 'enable' and self.wvel <= WINDSHIELD_LIMIT: APFLib.write(self.robot["SCRIPTOBS_WINDSHIELD"], "Disable") if currState == 'disable' and self.wvel > WINDSHIELD_LIMIT: APFLib.write(self.robot["SCRIPTOBS_WINDSHIELD"], "Enable")
def observe(self, observation,skip=False): """ Currently: Takes a string which is the filename of a properly formatted star list. """ if self.test: apflog("Would be taking observation in starlist %s" % observation) APFTask.waitFor(self.task, True, timeout=300) return # Make sure the telescope autofocus is enabled APFLib.write(self.autofoc, "robot_autofocus_enable") APFLib.write(self.ucam["RECORD"], "Yes") chk_foc = '$apftask.SCRIPTOBS_AUTOFOC == robot_autofocus_enable' result = APFTask.waitFor(self.task, False, chk_foc, timeout=60) if not result: apflog("Error setting scriptobs_autofoc", echo=True) return # Make sure APFTEQ is in night mode for observations if self.teqmode.read() != 'Night': self.setTeqMode('Night') # Check the instrument focus for a reasonable value if self.dewarfoc > 8600 or self.dewarfoc < 8400: lastfit_dewarfoc = ktl.read("apftask","FOCUSINSTR_LASTFOCUS",binary=True) apflog("Error: The dewar focus is currently %d. This is outside the typical range of acceptable values. Resetting to last derived value %d" % (self.dewarfoc,lastfit_dewarfoc), level = "error", echo=True) APFLib.write("apfmot.DEWARFOCRAW",lastfit_dewarfoc) # Check Telescope M2 Focus robotdir = "/usr/local/lick/bin/robot/" infile = open(observation,'r') outfile = open("robot.log", 'a') if skip: args = ['/usr/local/lick/bin/robot/scriptobs', '-dir', os.getcwd(),'-skip'] else: args = ['/usr/local/lick/bin/robot/scriptobs', '-dir', os.getcwd()] p = subprocess.Popen(args,stdin=infile, stdout=outfile,stderr = subprocess.PIPE, cwd=robotdir)
# If a command line phase was specified, use that. if opt.phase != None: APFTask.phase(parent, opt.phase) phase.poll() # If the phase isn't a valid option, (say the watchdog was run last) # then assume we are starting a fresh night and start from setting the observer information. apflog("Phase at start is: %s" % phase, echo=True) if str(phase).strip() not in possible_phases: apflog("Starting phase is not valid. Phase being set to ObsInfo", echo=True) APFTask.phase(parent, "ObsInfo") # Make sure that the command line arguments are respected. # Regardless of phase, if a name, obsnum, or reset was commanded, make sure we perform these operations. apflog("Setting scriptobs_lines_done=0") APFLib.write(apf.robot["SCRIPTOBS_LINES_DONE"], 0) if opt.fixed: if not os.path.exists(opt.fixed): errmsg = "starlist %s does not exist" % (opt.fixed) apflog(errmsg,level="error",echo=True) sys.exit(errmsg) if not debug: APFTask.set(parent,"STARLIST",opt.fixed) else: if not debug: APFTask.set(parent,"STARLIST","") if str(phase).strip() != "ObsInfo": if opt.name: apflog("option -n specified. Setting UCAM Observer to %s." % opt.name) APFLib.write(apf.ucam["OBSERVER"], opt.name)
# If a command line phase was specified, use that. if opt.phase != None: APFTask.phase(parent, opt.phase) phase.poll() # If the phase isn't a valid option, (say the watchdog was run last) # then assume we are starting a fresh night and start from setting the observer information. apflog("Phase at start is: %s" % phase, echo=True) if str(phase).strip() not in possible_phases: apflog("Starting phase is not valid. Phase being set to ObsInfo", echo=True) APFTask.phase(parent, "ObsInfo") # Make sure that the command line arguments are respected. # Regardless of phase, if a name, obsnum, or reset was commanded, make sure we perform these operations. if opt.restart: APFLib.write(apf.robot["SCRIPTOBS_LINES_DONE"], 0) if str(phase).strip() != "ObsInfo": if opt.obsnum: APFLib.write(apf.ucam["OBSNUM"], int(opt.obsnum)) # Start the actual operations # Goes through 5 steps: # 1) Set the observer information # 2) Run focuscube # 3) Run calibrate ucsc pre # 4) Start the main watcher # 5) Run calibrate ucsc post # Specifying a phase jumps straight to that point, and continues from there. # 1) Setting the observer information.
def checkClouds(self, target): """ This function will take a test exposure of a B-Star. By using scriptobs to take this exposure, the avg_fwhm and countrate keywords will be updated. The resulting file will be stored as Heimdallr1.fits? :return: """ apflog("checkClouds(): starting transparency check", echo=True) # Things to reset after this apflog("checkClouds(): Storing current UCAM keywords for later...", echo=True) # UCAM outfile obs_file = self.ucam["OUTFILE"].read() # UCAM Obsnumber obs_num = self.ucam["OBSNUM"].read() robot['MASTER_VAR_2'].write(obs_num) # scriptobs_lines_done lines_done = int(self.robot["SCRIPTOBS_LINES_DONE"]) APFLib.write(self.autofoc, "robot_autofocus_enable") apflog("checkClouds(): File name=%s - Number=%d - Lines Done=%d" % (obs_file, int(obs_num), lines_done) ) APFLib.write(self.ucam["OUTFILE"], "heimdallr") APFLib.write(self.ucam["OBSNUM"], self.cloudObsNum) APFLib.write(self.ucam["RECORD"], "No") cmdexec('/usr/local/lick/bin/robot/prep-obs') args = ['/usr/local/lick/bin/robot/scriptobs', '-dir', os.path.join(self.cwd,'checkClouds/')] apflog("checkClouds(): Observing %s as a test star to check the clouds/seeing/transparency" % target["NAME"], echo=True) outfile = open('robot.log', 'a') p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=outfile, stderr=outfile) foo, bar = p.communicate(target["SCRIPTOBS"]) outfile.close() ret = p.returncode if ret != 0: apflog("checkClouds(): The cloud cover test exposure has failed.", echo=True) else: apflog("checkClouds(): Cloud check was successful", echo=True) self.cloudObsNum += 2 apflog("checkClouds(): Resetting UCAM keywords to previous values.", echo=True) APFLib.write(self.ucam["RECORD"], "Yes") APFLib.write(self.ucam["OUTFILE"], obs_file) APFLib.write(self.ucam["OBSNUM"], obs_num) APFLib.write(self.robot["SCRIPTOBS_LINES_DONE"], lines_done) APFTask.waitFor(self.task, True, timeout=5) apflog("checkClouds(): Keywords successfully written.", echo=True) apflog("checkClouds(): New values") apflog("checkClouds(): File=%s - Num=%d - LinesDone=%d" % (self.ucam["OUTFILE"].read(), int(self.ucam["OBSNUM"].read()), int(self.robot["SCRIPTOBS_LINES_DONE"].read()) ) ) return
def calcSlowdown(): if self.blank: return self.apf.robot["MASTER_SLOWDOWN"].read() if self.BV is None: apflog( "Warning!: Ended up in getTarget() with no B Magnitude value, slowdown can't be computed.", echo=True) self.BV = 0.6 # use a default average if self.VMAG is None: apflog( "Warning!: Ended up in getTarget() with no V Magnitude value, slowdown can't be computed.", echo=True) return 5 if self.apf.avg_fwhm < 1.0: apflog( "Warning!: AVG_FWHM = %4.2f. By Odin's beard that seems low." % self.apf.avg_fwhm, echo=True) return SchedulerConsts.SLOWDOWN_MAX slowdown = 1 apflog("Calculating expected counts") apflog( "self.VMAG [%4.2f] - self.BV [%4.2f] - self.apf.ael [%4.2f]" % (self.VMAG, self.BV, self.apf.ael)) exp_cnts_sec = ExposureCalculations.getEXPMeter_Rate( self.VMAG, self.BV, self.apf.ael, self.apf.avg_fwhm, self.decker) try: if self.apf.countrate <= 0: try: self.apf.countrate = self.apf.ccountrate except: self.apf.countrate = -1.0 if self.apf.countrate * 10 < self.apf.ccountrate: self.apf.countrate = self.apf.ccountrate slowdown = exp_cnts_sec / self.apf.countrate if slowdown < 0: slowdown = 1 apflog("Countrate non-sensical %g" % (self.apf.countrate), echo=True, level='warn') self.apf.counts.monitor(start=False) self.apf.counts.monitor(start=True) self.apf.counts.callback(APFControl.countmon) # yes this happened. if slowdown < SchedulerConsts.SLOWDOWN_MIN: slowdown = SchedulerConsts.SLOWDOWN_MIN apflog("slowdown too low, countrate= %g" % (self.apf.countrate), echo=True, level='debug') # yes this happened. if slowdown > SchedulerConsts.SLOWDOWN_MAX: slowdown = SchedulerConsts.SLOWDOWN_MAX apflog("slowdown too high, countrate= %g" % (self.apf.countrate), echo=True, level='debug') except ZeroDivisionError: apflog("Current countrate was 0. Slowdown will be set to 1.", echo=True) slowdown = 1 apflog("countrate = %.2f, ccountrate = %.2f" % (self.apf.countrate, self.apf.ccountrate)) apflog("slowdown factor = %4.2f" % slowdown, echo=True) APFLib.write(self.apf.robot["MASTER_SLOWDOWN"], slowdown) return slowdown
def startScriptobs(): # Update the last obs file and hitlist if needed APFTask.set(self.task, suffix="LAST_OBS_UCSC", value=self.apf.ucam["OBSNUM"].read()) self.apf.updateWindshield(self.windshield_mode) ripd, running = self.apf.findRobot() if running: apflog( "Scriptobs is already running yet startScriptobs was called", level="warn", echo=True) return rv = self.checkScriptobsMessages() if rv is False: return expr = "$checkapf.MOVE_PERM = True and $checkapf.INSTR_PERM = True" perms = APFTask.waitFor(self.task, True, expression=expr, timeout=1200) if perms is False: apflog( "Cannot start an instance of scriptobs because do not have permission", echo=True, level='error') return apflog("Starting an instance of scriptobs", echo=True) if self.fixedList is not None and self.shouldStartList(): # We wish to observe a fixed target list, in it's original order if not os.path.exists(self.fixedList): apflog("Error: starlist %s does not exist" % (self.fixedList), level="error") self.fixedList = None self.starttime = None APFLib.write(self.apf.robot["MASTER_STARLIST"], "") APFLib.write(self.apf.robot["MASTER_UTSTARTLIST"], "") # this reads in the list and appends it to self.target tot = readStarlistFile() if self.apf.ldone == tot: APFLib.write(self.apf.robot["MASTER_STARLIST"], "") APFLib.write(self.apf.robot["MASTER_UTSTARTLIST"], "") self.fixedList = None self.starttime = None self.target = None if not self.apf.test: APFTask.set(self.task, suffix="STARLIST", value="") apflog( "Finished fixed list on line %d, will start dynamic scheduler" % int(self.apf.ldone), echo=True) else: apflog("Found Fixed list %s" % self.fixedList, echo=True) apflog("Starting fixed list on line %d" % int(self.apf.ldone), echo=True) self.fixedList = None else: if self.BV is None: apflog("No B-V value at the moment", echo=True) #self.BV = 0.028 if self.VMAG is None: apflog("No VMag value at the moment", echo=True) #self.VMAG = None # We wish to observe with the dynamic scheduler ripd, running = self.apf.findRobot() if running is False: apflog( "Starting an instance of scriptobs for dynamic observing.", echo=True) self.scriptobs = self.apf.startRobot() # Don't let the watcher run over the robot starting up APFTask.waitFor(self.task, True, timeout=10) return
def run(self): """ Observe.run() - runs the observing """ def calcSlowdown(): if self.blank: return self.apf.robot["MASTER_SLOWDOWN"].read() if self.BV is None: apflog( "Warning!: Ended up in getTarget() with no B Magnitude value, slowdown can't be computed.", echo=True) self.BV = 0.6 # use a default average if self.VMAG is None: apflog( "Warning!: Ended up in getTarget() with no V Magnitude value, slowdown can't be computed.", echo=True) return 5 if self.apf.avg_fwhm < 1.0: apflog( "Warning!: AVG_FWHM = %4.2f. By Odin's beard that seems low." % self.apf.avg_fwhm, echo=True) return SchedulerConsts.SLOWDOWN_MAX slowdown = 1 apflog("Calculating expected counts") apflog( "self.VMAG [%4.2f] - self.BV [%4.2f] - self.apf.ael [%4.2f]" % (self.VMAG, self.BV, self.apf.ael)) exp_cnts_sec = ExposureCalculations.getEXPMeter_Rate( self.VMAG, self.BV, self.apf.ael, self.apf.avg_fwhm, self.decker) try: if self.apf.countrate <= 0: try: self.apf.countrate = self.apf.ccountrate except: self.apf.countrate = -1.0 if self.apf.countrate * 10 < self.apf.ccountrate: self.apf.countrate = self.apf.ccountrate slowdown = exp_cnts_sec / self.apf.countrate if slowdown < 0: slowdown = 1 apflog("Countrate non-sensical %g" % (self.apf.countrate), echo=True, level='warn') self.apf.counts.monitor(start=False) self.apf.counts.monitor(start=True) self.apf.counts.callback(APFControl.countmon) # yes this happened. if slowdown < SchedulerConsts.SLOWDOWN_MIN: slowdown = SchedulerConsts.SLOWDOWN_MIN apflog("slowdown too low, countrate= %g" % (self.apf.countrate), echo=True, level='debug') # yes this happened. if slowdown > SchedulerConsts.SLOWDOWN_MAX: slowdown = SchedulerConsts.SLOWDOWN_MAX apflog("slowdown too high, countrate= %g" % (self.apf.countrate), echo=True, level='debug') except ZeroDivisionError: apflog("Current countrate was 0. Slowdown will be set to 1.", echo=True) slowdown = 1 apflog("countrate = %.2f, ccountrate = %.2f" % (self.apf.countrate, self.apf.ccountrate)) apflog("slowdown factor = %4.2f" % slowdown, echo=True) APFLib.write(self.apf.robot["MASTER_SLOWDOWN"], slowdown) return slowdown def popNext(): curstr = None if self.target is not None and 'SCRIPTOBS' in self.target.keys(): tlist = self.target["SCRIPTOBS"] if len(tlist) > 0: apflog( "getTarget(): Going through remaining target queue.", echo=True) curstr = tlist.pop() + '\n' return curstr if self.fixedtarget is not None and 'SCRIPTOBS' in self.fixedtarget.keys( ): tlist = self.fixedtarget["SCRIPTOBS"] if len(tlist) > 0: apflog("getTarget(): Going through fixed starlist.", echo=True) curstr = tlist.pop() + '\n' else: apflog("getTarget(): Finished fixed starlist.", echo=True) self.fixedtarget = None return curstr # This is called when an observation finishes, and selects the next target def getTarget(): APFLib.write(self.apf.ucam["RECORD"], "Yes") # safe / sorry if self.apf.nerase != 2: self.apf.nerase.write(2, binary=True) if self.checkObsFinished(): apflog( "getTarget(): Scriptobs phase is input, determining next target.", echo=True) else: apflog("getTarget(): Not at end of block but out of targets.", echo=True) try: self.obsBstar = ktl.read("apftask", "MASTER_OBSBSTAR", binary=True) apflog("getTarget(): Setting obsBstar to %s" % (str(self.obsBstar)), echo=True) except Exception, e: apflog("getTarget(): Cannot read apftask.MASTER_OBSBSTAR: %s" % (e), level='error', echo=True) self.obsBstar = True if self.scriptobs is None: apflog( "Called getTarget, but there is not instance of scriptobs associated with %s. This is an error condition." % (self.name), level='error', echo=True) ripd, running = self.apf.findRobot() if running: apflog("Attempting to kill the existing robot, %d" % (ripd), level='error', echo=True) self.apf.killRobot() return # setup a B star observation if needed # if not B star observation, look at current stack of observations and see if anything is left if self.obsBstar: self.apf.autofoc.write("robot_autofocus_enable") else: curstr = popNext() if curstr: self.scriptobs.stdin.write(curstr) return # Calculate the slowdown factor. slowdown = calcSlowdown() # Check for a valid seeing measurment. If there isn't one, use a default if self.apf.avg_fwhm == 0.: apflog( "getTarget(): Warning AVG_FWHM is 0. A default value of 15 will be used in its place.", echo=True) seeing = 15 else: seeing = float(self.apf.avg_fwhm) apflog("getTarget(): Current AVG_FWHM = %4.2f" % seeing) self.apf.initGuideCam() self.apf.updateWindshield(self.windshield_mode) self.focval = self.apf.setAutofocVal() self.target = ds.getNext(time.time(), seeing, slowdown, bstar=self.obsBstar, sheetns=self.sheetn, owner=self.owner, template=self.doTemp, focval=self.focval, rank_sheetn=self.rank_tablen, frac_sheet=self.frac_tablen) if self.target is None: apflog( "No acceptable target was found. Since there does not seem to be anything to observe, %s will now shut down." % (self.name), echo=True) # Send scriptobs EOF to finish execution - wouldn't want to leave a zombie scriptobs running self.scriptobs.stdin.close() self.apf.close() if self.fixedList is None: APFLib.write(self.apf.ldone, 0) self.apf.countrate = -1.0 # sleep for a half hour to see if the clouds blow by APFTask.waitfor(self.task, True, timeout=60 * 30) return else: apflog("Observing target: %s" % self.target['NAME'], echo=True) APFTask.set(self.task, suffix="MESSAGE", value="Observing target: %s" % self.target['NAME'], wait=False) try: self.scriptobs.stdin.write(self.target["SCRIPTOBS"].pop() + '\n') except IOError as e: apflog("Cannot observe target %s: IOError: %s" % (self.target['NAME'], e), echo=True, level='error') return # Set the Vmag and B-V mag of the latest target self.VMAG = self.target["VMAG"] self.BV = self.target["BV"] self.decker = self.target["DECKER"] istemp = str(self.target['isTemp']) if self.target["mode"] == 'B' or self.target["mode"] == 'A': self.blank = True else: self.blank = False apflog("getTarget(): V=%.2f B-V=%.2f Pri=%.2f " % (self.VMAG, self.BV, self.target["PRI"])) apflog("getTarget(): FWHM=%.2f Slowdown=%.2f Countrate=%.2f" % (self.apf.avg_fwhm, slowdown, self.apf.countrate)) apflog("getTarget(): Target= %s Temp=%s" % (self.target["NAME"], istemp)) apflog("getTarget(): Counts=%.2f EXPTime=%.2f Nexp=%d" % (self.target["COUNTS"], self.target["EXP_TIME"], self.target["NEXP"])) if self.target['isTemp']: self.nTemps += 1 if self.nTemps >= self.totTemps: self.doTemp = False return
def run(self): """ Master.run() - runs the observing """ APF = self.APF # This is called when an observation finishes, and selects the next target def getTarget(): apflog("getTarget(): Scriptobs phase is input, determining next target.",echo=True) APFLib.write(APF.ucam["RECORD"], "Yes") # safe / sorry try: self.obsBstar = bool(ktl.read("apftask","master_var_3")) except: self.obsBstar = True if self.scriptobs is None: apflog("Called getTarget, but there is not instance of scriptobs associated with Heimdallr. This is an error condition.", echo=True) return None # Calculate the slowdown factor. if self.BV is None: apflog("Warning!: Ended up in getTarget() with no B Magnitude value, slowdown can't be computed.", echo=True) self.BV = 0.6 # use a default average if self.VMAG is None: apflog("Warning!: Ended up in getTarget() with no V Magnitude value, slowdown can't be computed.", echo=True) slowdown = 5 elif APF.avg_fwhm < 1.0: apflog("Warning!: AVG_FWHM = %4.2f. By Odin's beard that seems low." % APF.avg_fwhm, echo=True) slowdown = 5 else: apflog("Calculating expected counts") apflog("self.VMAG [%4.2f] - self.BV [%4.2f] - APF.ael [%4.2f]" % (self.VMAG, self.BV, APF.ael)) exp_cnts_sec = ExposureCalculations.getEXPMeter_Rate(self.VMAG, self.BV, APF.ael,APF.avg_fwhm, self.decker) try: if APF.countrate <= 0: try: APF.countrate = APF.ccountrate except: APF.countrate = -1.0 slowdown = exp_cnts_sec / APF.countrate if APF.countrate*10 < APF.ccountrate: APF.countrate = APF.ccountrate if slowdown < 0: slowdown = 1 apflog("Countrate non-sensical %g" % (APF.countrate), echo=True, level='warn') APF.counts.monitor(start=False) APF.counts.monitor(start=True) APF.counts.callback(ad.countmon) # yes this happened. if slowdown < SchedulerConsts.SLOWDOWN_MIN: slowdown = SchedulerConsts.SLOWDOWN_MIN apflog("slowdown too low, countrate= %g" % (APF.countrate), echo=True, level='debug') # yes this happened. if slowdown > SchedulerConsts.SLOWDOWN_MAX: slowdown = SchedulerConsts.SLOWDOWN_MAX apflog("slowdown too high, countrate= %g" % (APF.countrate), echo=True, level='debug') except ZeroDivisionError: apflog("Current countrate was 0. Slowdown will be set to 1.", echo=True) slowdown = 1 apflog("getTarget(): slowdown factor = %4.2f" % slowdown, echo=True) APFLib.write(apf.robot["MASTER_VAR_1"], slowdown) apflog("getTarget(): countrate = %.2f, ccountrate = %.2f" % (APF.countrate,APF.ccountrate)) # Check for a valid seeing measurment. If there isn't one, use a default if APF.avg_fwhm == 0.: apflog("getTarget(): Warning AVG_FWHM is 0. A default value of 15 will be used in its place.",echo=True) seeing = 15 else: seeing = float(APF.avg_fwhm) apflog("getTarget(): Current AVG_FWHM = %4.2f" % seeing) target = ds.getNext(time.time(), seeing, slowdown, bstar=self.obsBstar, verbose=True, sheetns=self.sheetn, owner=self.owner) self.set_autofocval() if target is None: apflog("No acceptable target was found. Since there does not seem to be anything to observe, Heimdallr will now shut down.", echo=True) # Send scriptobs EOF to finish execution - wouldn't want to leave a zombie scriptobs running self.scriptobs.stdin.close() APF.close() apf.countrate = -1.0 # sleep for a half hour to see if the clouds blow by APFTask.waitfor(self.task, True, timeout=60*45) return else: apflog("Observing target: %s" % target['NAME'], echo=True) self.scriptobs.stdin.write(target["SCRIPTOBS"] + '\n') # Set the Vmag and B-V mag of the latest target self.VMAG = target["VMAG"] self.BV = target["BV"] self.decker = target["DECKER"] apflog("getTarget(): V=%.2f B-V=%.2f Pri=%.2f " % (self.VMAG, self.BV, target["PRI"])) apflog("getTarget(): FWHM=%.2f Slowdown=%.2f Countrate=%.2f" % (APF.avg_fwhm, slowdown, APF.countrate)) apflog("getTarget(): Target= %s" % target["NAME"]) apflog("getTarget(): Counts=%.2f EXPTime=%.2f Nexp=%d" % (target["COUNTS"], target["EXP_TIME"], target["NEXP"])) # opens the dome & telescope, if sunset is True calls open at sunset, else open at night def opening(sunel,sunset=False): when = "night" if sunset: when = "sunset" apflog("Running open at %s as sunel = %4.2f" % (when, float(sunel))) (apfopen,what) =APF.isOpen() if apfopen: APF.DMReset() else: APF.DMZero() result = APF.openat(sunset=sunset) apflog("openatsunset completed with result %s" % (result), echo=True) if result == False: apflog("openatsunset hasn't successfully opened. Current sunel = %4.2f" % ( float(sunel)), level='warn', echo=True) if ( float(sunel) < SUNEL_ENDLIM): result = APF.openat(sunset=sunset) if not result: apflog("Error: openatsunset has failed twice.", level='error', echo=True) APF.close() if datetime.now().strftime("%p") == 'PM': setting = True else: setting = False APF.DMReset() if setting and sunset: rv = APF.evening_star() if not rv: apflog("evening star targeting and telescope focus did not work",level='warn', echo=True) chk_done = "$eostele.SUNEL < %f" % (SUNEL_STARTLIM*np.pi/180.0) result = False while float(sunel.read()) > SUNEL_STARTLIM and setting: outstr = "Sun setting is %s and sun at elevation of %.3f" % (setting, float(sunel.read())) apflog(outstr,level='info', echo=True) result = APFTask.waitFor(self.task, True, expression=chk_done, timeout=60) APF.DMReset() return # closing def closing(): if running: APF.killRobot(now=True) APF.close() if apf.ucam['OUTFILE'].read() == 'ucsc': APFTask.set(parent,suffix="LAST_OBS_UCSC", value=apf.ucam["OBSNUM"].read()) return # starts an instance of scriptobs def startScriptobs(): # Update the last obs file and hitlist if needed if apf.ucam['OUTFILE'].read() == 'ucsc' and apf.test == False: APFTask.set(parent,suffix="LAST_OBS_UCSC", value=apf.ucam["OBSNUM"].read()) APF.updateWindshield(self.windshield) apflog("Starting an instance of scriptobs",echo=True) ripd, running = APF.findRobot() if running: apflog("Scriptobs is already running yet startScriptobs was called",level="warn",echo=True) return if self.fixedList is not None and self.shouldStartList(): # We wish to observe a fixed target list, in it's original order if not os.path.exists(self.fixedList): apflog("Error: starlist %s does not exist" % (self.fixedList), level="error") self.fixedList=None return tot = getTotalLines(self.fixedList) apflog("%d total starlist lines and %d lines done." % (tot, APF.ldone)) if APF.ldone == tot and APF.user != "ucsc": APF.close() if apf.ucam['OUTFILE'].read() == 'ucsc': APFTask.set(parent,suffix="LAST_OBS_UCSC", value=apf.ucam["OBSNUM"].read()) self.exitMessage = "Fixed list is finished. Exiting the watcher." self.stop() # The fixed list has been completely observed so nothing left to do elif APF.ldone == tot and APF.user == "ucsc": self.fixedList = None self.starttime = None if not APF.test: APFTask.set(self.task,suffix="STARLIST",value="") ripd, running = APF.findRobot() if running: APF.killRobot(now=True) apflog("Finished fixed list on line %d, will start dynamic scheduler" % int(APF.ldone), echo=True) expression="($apftask.SCRIPTOBS_STATUS != 0) and ($apftask.SCRIPTOBS_STATUS != 1) " if APFTask.waitFor(self.task,True,expression=expression,timeout=30): apflog("Starting an instance of scriptobs for dynamic observing.",echo=True) self.scriptobs = APF.startRobot() else: apflog("Found Fixed list %s" % self.fixedList, echo=True) apflog("Starting fixed list on line %d" % int(APF.ldone), echo=True) APF.observe(str(self.fixedList),skip=True) APFTask.waitFor(self.task, True, timeout=10) else: if self.BV is None: apflog("No B-V value at the moment", echo=True) #self.BV = 0.028 if self.VMAG is None: apflog("No VMag value at the moment", echo=True) #self.VMAG = None # We wish to observe either a starlist with intelligent ordering, or the dynamic scheduler apflog("Starting an instance of scriptobs for dynamic observing.",echo=True) self.scriptobs = APF.startRobot() # Don't let the watcher run over the robot starting up APFTask.waitFor(self.task, True, timeout=10) return ############################### # Actual Watching loop apflog("Beginning observing process....",echo=True) APF.DMZero() haveobserved = False failstart = 0 while self.signal: # Check on everything if datetime.now().strftime("%p") == 'AM': rising = True sunel_lim = SUNEL_ENDLIM else: rising = False sunel_lim = sunel_startlim() wind_vel = APF.wvel ripd, running = APF.findRobot() sunel = APF.sunel sunel.monitor() # if paused: # apflog("Pausing because of apftask request",level='warn',echo=True) # APFTask.waitfor(self.task, True, timeout=60) # Check and close for weather if APF.isOpen()[0] and not APF.openOK: closetime = datetime.now() APFTask.set(parent,suffix="MESSAGE",value="Closing for weather",wait=False) apflog("No longer ok to open.", echo=True) apflog("OPREASON: " + APF.checkapf["OPREASON"].read(), echo=True) apflog("WEATHER: " + APF.checkapf['WEATHER'].read(), echo=True) closing() # Check the slowdown factor to close for clouds if self.VMAG is not None and self.BV is not None and False: exp_cntrate = ExposureCalculations.getEXPMeter_Rate(self.VMAG, self.BV, APF.ael,APF.avg_fwhm) try: slow = exp_cntrate / APF.countrate if slow < 0: slow = 5 apflog("Countrate non-sensical %g" % APF.countrate, echo=True) except ZeroDivisionError: apflog("No current countrate", echo=True) slow = 5 APFTask.set(parent,suffix="MESSAGE",value="FWHM = %.2f and slowdown %.2f" % (APF.avg_fwhm,slow),wait=False) if slow > 16: # The slowdown is too high, we should close up and wait. APFTask.set(parent,suffix="MESSAGE",value="Closing for clouds",wait=False) apflog("Slowdown factor of %.2f is too high. Waiting 30 min to check again." % slow, echo=True) closing() APFTask.waitfor(self.task, True, timeout=60*30) self.VMAG=None self.BV=None APF.countrate = 0 # If scriptobs is running and waiting for input, give it a target if running == True and float(sunel) < sunel_lim and APF.sop.read().strip() == 'Input': if self.fixedList is None or self.shouldStartList() == False: self.lastObsSuccess = self.checkObsSuccess() self.obsBstar = self.checkBstar(haveobserved) APFTask.set(parent,suffix="MESSAGE",value="Calling getTarget",wait=False) apflog("Scriptobs phase is input ( dynamic scheduler ), calling getTarget.") getTarget() apflog("Observing target") APFTask.set(parent,suffix="MESSAGE",value="Observing Target",wait=False) APFTask.waitfor(self.task, True, timeout=15) haveobserved = True elif self.starttime != None and self.shouldStartList() : APF.killRobot() # check last telescope focus if running and float(sunel) <= sunel_lim : self.set_autofocval() # If the sun is rising and we are finishing an observation # Send scriptobs EOF. This will shut it down after the observation if float(sunel) >= sunel_lim and running == True: APFTask.set(parent,suffix="MESSAGE",value="Last call",wait=False) if self.scriptobs is None: apflog("Robot claims to be running, but no self.scriptobs instance can be found. Instead calling killRobot().", echo=True) APF.killRobot() else: self.scriptobs.stdin.close() APF.killRobot() # If the sun is rising and scriptobs has stopped, run closeup if float(sunel) > sunel_lim and running == False and rising == True: apflog("Closing due to sun elevation. Sunel = % 4.2f" % float(sunel), echo=True) APFTask.set(parent,suffix="MESSAGE",value="Closing, sun is rising",wait=False) if APF.isOpen()[0]: msg = "APF is open, closing due to sun elevation = %4.2f" % float(sunel) closing() else: msg = "Telescope was already closed when sun got to %4.2f" % float(sunel) if APF.isOpen()[0]: apflog("Error: Closeup did not succeed", level='error', echo=True) self.exitMessage = msg self.stop() # If we can open, try to set stuff up so the vent doors can be controlled by apfteq if APF.openOK and not rising and not APF.isOpen()[0]: APFTask.set(parent,suffix="MESSAGE",value="Powering up for APFTeq",wait=False) if APF.clearestop(): try: APFLib.write(APF.dome['AZENABLE'],'enable',timeout=10) except: apflog("Error: Cannot enable AZ drive, exiting",level="error") return apf.setTeqMode('Evening') else: apflog("Error: Cannot clear emergency stop, sleeping for 600 seconds",level="error") APFTask.waitFor(parent,True,timeout=600) # Open if not APF.isReadyForObserving()[0] and float(sunel) < SUNEL_HOR and APF.openOK : if float(sunel) > sunel_lim and not rising : APFTask.set(parent,suffix="MESSAGE",value="Open at sunset",wait=False) success = opening( sunel, sunset=True) elif not rising or (rising and float(sunel) < (sunel_lim - 5)): APFTask.set(parent,suffix="MESSAGE",value="Open at night",wait=False) success = opening( sunel) else: success = True if success == False: apflog("Error: Cannot open the dome",echo=True,level='error') APF.close() os._exit() # Check for servo errors if APF.isOpen()[0] and APF.slew_allowed == False: APFTask.set(parent,suffix="MESSAGE",value="Servo failure.",wait=False) apflog("Error: APF is open, and slew_allowed is false. Likely an amplifier fault.", level="error", echo=True) # apflog("Forcing checkapf to close the dome. Heimdallr will then exit.", echo=True) chk_done = "$checkapf.MOVE_PERM == true" # APFLib.write(APF.dmtimer, 0) result = APFTask.waitFor(self.task, True, expression=chk_done, timeout=600) if not result and "DomeShutter" in APF.isOpen()[1]: apflog("Error: After 10 min move permission did not return, and the dome is still open.", level='error', echo=True) APF.close(force=True) if not APF.power_down_telescope(): apflog("Error: Cannot reset telescope after servo failure",level="error", echo=True) os._exit(1) # If we are open and scriptobs isn't running, start it up if APF.isReadyForObserving()[0] and not running and float(sunel) <= sunel_lim: APFTask.set(parent,suffix="MESSAGE",value="Starting scriptobs",wait=False) startScriptobs() if not APFTask.waitFor(self.task,True,expression="$apftask.SCRIPTOBS_STATUS == 'Running'",timeout=10): if failstart % 11 == 0 and failstart > 0: lvl = "error" else: lvl = "warn" apflog("scriptobs is not running just after being started!", level=lvl, echo=True) APFTask.set(parent,suffix="MESSAGE",value="scriptobs is not running just after being started!",wait=False) # Keep an eye on the deadman timer if we are open if APF.isOpen()[0] and APF.dmtime <= DMLIM: APFTask.set(parent,suffix="MESSAGE",value="Reseting DM timer",wait=False) APF.DMReset() # apflog("The APF is open, the DM timer is clicking down, and scriptobs is %s." % ( str(running)),level="debug") if not APF.isOpen()[0] and not rising: APFTask.set(parent,suffix="MESSAGE",value="Waiting for sunset",wait=False) APFTask.waitFor(self.task, True, timeout=5) if APF.isOpen()[0] and float(sunel) > sunel_lim: APFTask.set(parent,suffix="MESSAGE",value="Waiting for the end of twilight",wait=False) APFTask.waitFor(self.task, True, timeout=5)
def DMReset(self): APFLib.write(self.checkapf['ROBOSTATE'], "master operating")
def getTarget(): apflog("getTarget(): Scriptobs phase is input, determining next target.",echo=True) APFLib.write(APF.ucam["RECORD"], "Yes") # safe / sorry try: self.obsBstar = bool(ktl.read("apftask","master_var_3")) except: self.obsBstar = True if self.scriptobs is None: apflog("Called getTarget, but there is not instance of scriptobs associated with Heimdallr. This is an error condition.", echo=True) return None # Calculate the slowdown factor. if self.BV is None: apflog("Warning!: Ended up in getTarget() with no B Magnitude value, slowdown can't be computed.", echo=True) self.BV = 0.6 # use a default average if self.VMAG is None: apflog("Warning!: Ended up in getTarget() with no V Magnitude value, slowdown can't be computed.", echo=True) slowdown = 5 elif APF.avg_fwhm < 1.0: apflog("Warning!: AVG_FWHM = %4.2f. By Odin's beard that seems low." % APF.avg_fwhm, echo=True) slowdown = 5 else: apflog("Calculating expected counts") apflog("self.VMAG [%4.2f] - self.BV [%4.2f] - APF.ael [%4.2f]" % (self.VMAG, self.BV, APF.ael)) exp_cnts_sec = ExposureCalculations.getEXPMeter_Rate(self.VMAG, self.BV, APF.ael,APF.avg_fwhm, self.decker) try: if APF.countrate <= 0: try: APF.countrate = APF.ccountrate except: APF.countrate = -1.0 slowdown = exp_cnts_sec / APF.countrate if APF.countrate*10 < APF.ccountrate: APF.countrate = APF.ccountrate if slowdown < 0: slowdown = 1 apflog("Countrate non-sensical %g" % (APF.countrate), echo=True, level='warn') APF.counts.monitor(start=False) APF.counts.monitor(start=True) APF.counts.callback(ad.countmon) # yes this happened. if slowdown < SchedulerConsts.SLOWDOWN_MIN: slowdown = SchedulerConsts.SLOWDOWN_MIN apflog("slowdown too low, countrate= %g" % (APF.countrate), echo=True, level='debug') # yes this happened. if slowdown > SchedulerConsts.SLOWDOWN_MAX: slowdown = SchedulerConsts.SLOWDOWN_MAX apflog("slowdown too high, countrate= %g" % (APF.countrate), echo=True, level='debug') except ZeroDivisionError: apflog("Current countrate was 0. Slowdown will be set to 1.", echo=True) slowdown = 1 apflog("getTarget(): slowdown factor = %4.2f" % slowdown, echo=True) APFLib.write(apf.robot["MASTER_VAR_1"], slowdown) apflog("getTarget(): countrate = %.2f, ccountrate = %.2f" % (APF.countrate,APF.ccountrate)) # Check for a valid seeing measurment. If there isn't one, use a default if APF.avg_fwhm == 0.: apflog("getTarget(): Warning AVG_FWHM is 0. A default value of 15 will be used in its place.",echo=True) seeing = 15 else: seeing = float(APF.avg_fwhm) apflog("getTarget(): Current AVG_FWHM = %4.2f" % seeing) target = ds.getNext(time.time(), seeing, slowdown, bstar=self.obsBstar, verbose=True, sheetns=self.sheetn, owner=self.owner) self.set_autofocval() if target is None: apflog("No acceptable target was found. Since there does not seem to be anything to observe, Heimdallr will now shut down.", echo=True) # Send scriptobs EOF to finish execution - wouldn't want to leave a zombie scriptobs running self.scriptobs.stdin.close() APF.close() apf.countrate = -1.0 # sleep for a half hour to see if the clouds blow by APFTask.waitfor(self.task, True, timeout=60*45) return else: apflog("Observing target: %s" % target['NAME'], echo=True) self.scriptobs.stdin.write(target["SCRIPTOBS"] + '\n') # Set the Vmag and B-V mag of the latest target self.VMAG = target["VMAG"] self.BV = target["BV"] self.decker = target["DECKER"] apflog("getTarget(): V=%.2f B-V=%.2f Pri=%.2f " % (self.VMAG, self.BV, target["PRI"])) apflog("getTarget(): FWHM=%.2f Slowdown=%.2f Countrate=%.2f" % (APF.avg_fwhm, slowdown, APF.countrate)) apflog("getTarget(): Target= %s" % target["NAME"]) apflog("getTarget(): Counts=%.2f EXPTime=%.2f Nexp=%d" % (target["COUNTS"], target["EXP_TIME"], target["NEXP"]))
level='error') else: apflog("Error: Lost permission during opening", echo=True) # If we can open, try to set stuff up so the vent doors can be controlled by apfteq if not rising and not self.apf.isOpen()[0] and float( cursunel) > SchedulerConsts.SUNEL_HOR: APFTask.set(self.task, suffix="MESSAGE", value="Powering up for APFTeq", wait=False) if self.apf.clearestop(): try: APFLib.write(self.apf.dome['AZENABLE'], 'enable', timeout=10) except: apflog("Error: Cannot enable AZ drive", level="error") self.apf.setTeqMode('Evening') vent_open = "$eosdome.VD4STATE = VENT_OPENED" result = APFTask.waitfor(self.task, True, expression=vent_open, timeout=180) if result: try: Apflib.write(self.apf.dome['AZENABLE'], 'disable',