def run(self): log.info("Starting scheduler machine") self.state(State.OFF) # inject instruments on handlers self.executor.__start__() while self.state() != State.SHUTDOWN: if self.state() == State.OFF: log.debug("[off] will just sleep..") self.sleep() if self.state() == State.START: log.debug("[start] database changed, rescheduling...") self.scheduler.reschedule(self) self.state(State.IDLE) if self.state() == State.IDLE: log.debug("[idle] looking for something to do...") # find something to do program = self.scheduler.next() if program: log.debug("[idle] there is something to do, processing...") log.debug("[idle] program slew start %s",program.slewAt) log.debug("[idle] program exposure start %s",program.exposeAt) self.state(State.BUSY) self.currentProgram = program self._process(program) continue # should'nt get here if any task was executed log.debug("[idle] there is nothing to do, going offline...") self.currentProgram = None self.state(State.OFF) elif self.state() == State.BUSY: log.debug("[busy] waiting tasks to finish..") self.sleep() elif self.state() == State.STOP: log.debug("[stop] trying to stop current program") self.executor.stop() self.state(State.OFF) elif self.state() == State.SHUTDOWN: log.debug("[shutdown] trying to stop current program") self.executor.stop() log.debug("[shutdown] should die soon.") break log.debug('[shutdown] thread ending...')
def start(self, location): """ Start the object pointed by 'location'. @param location: The object to start. @type location: Location or str @raises ObjectNotFoundException: When te request object or the Manager was not found. @raises ChimeraObjectException: Internal error on managed (user) object. @return: retuns True if sucessfull. False otherwise. @rtype: bool """ if location not in self.resources: raise ObjectNotFoundException("Location %s was not found." % location) log.info("Starting %s." % location) resource = self.resources.get(location) if resource.instance.getState() == State.RUNNING: return True try: resource.instance.__start__() except Exception: log.exception("Error running %s __start__ method." % location) raise ChimeraObjectException("Error running %s __start__ method." % location) try: # FIXME: thread exception handling # ok, now schedule object main in a new thread log.info("Running %s. __main___." % location) loop = threading.Thread(target=resource.instance.__main__) loop.setName(str(resource.location) + ".__main__") loop.setDaemon(True) loop.start() resource.instance.__setstate__(State.RUNNING) resource.created = time.time() resource.loop = loop return True except Exception, e: log.exception("Error running %s __main__ method." % location) resource.instance.__setstate__(State.STOPPED) raise ChimeraObjectException("Error running %s __main__ method." % location)
def beginExposure (self, manager): self._fetchPreHeaders(manager) if self["wait_dome"]: try: dome = manager.getProxy("/Dome/0") dome.syncWithTel() log.debug("Dome slit position synchronized with telescope position.") except ObjectNotFoundException: log.info("No dome present, taking exposure without dome sync.")
def beginExposure(self, manager): self._fetchPreHeaders(manager) if self["wait_dome"]: try: dome = manager.getProxy("/Dome/0") dome.syncWithTel() log.debug( "Dome slit position synchronized with telescope position.") except ObjectNotFoundException: log.info("No dome present, taking exposure without dome sync.")
def startup(self): if self.options.daemon: # detach log.info("FIXME: Daemon...") # system config try: self.config = SystemConfig.fromFile(self.options.config_file) except (InvalidLocationException, IOError), e: log.exception(e) log.error("There was a problem reading your configuration file. (%s)" % e) sys.exit(1)
def selectScienceTargets(self): ''' Based on configuration parameters select a good set of targets to run scheduler on a specified Julian Day. ''' session = Session() # [To be done] Reject objects that are close to the moon for tbin, time in enumerate(self.obsTimeBins): if self.obsTimeMask[tbin] < 1.0: # Select objects from database that where not observed and where not scheduled yet # In the future may include targets that where observed a number of nights ago. # This is still incomplete. We should also consider the distance from the previous pointing to the next! # Since a target can have a higher airmass but be farther away from a neaby target that will take less time # to point. # one way of selecting targets that are close together and have good airmass is to select regions that are close # to the current location. it can start as searching an area with r1 ~ 10 x the FoV and, if there are no regions # to to x2 that and then x4 that. If still there are no targets, than search for the higher in the sky. targets = session.query(Targets).filter( Targets.observed == False).filter( Targets.scheduled == False).filter( Targets.type == self.sciFlag) lst = _skysub.lst(time, self.sitelong) #*360./24. alt = np.array([ _skysub.altit(target.targetDec, lst - target.targetRa, self.sitelat)[0] for target in targets ]) stg = alt.argmax() log.info('Selecting %s' % (targets[stg])) # Marking target as schedule tst = session.query(Targets).filter( Targets.id == targets[stg].id) for t in tst: t.scheduled = True session.commit() self.addObservation(t, time) self.obsTimeMask[tbin] = 1.0 else: log.debug( 'Bin %3i @mjd=%.3f already filled up with observations. Skipping...' % (tbin, time - 2400000.5)) #print i return 0 #targets
def start (self, location): """ Start the object pointed by 'location'. @param location: The object to start. @type location: Location or str @raises ObjectNotFoundException: When te request object or the Manager was not found. @raises ChimeraObjectException: Internal error on managed (user) object. @return: retuns True if sucessfull. False otherwise. @rtype: bool """ if location not in self.resources: raise ObjectNotFoundException ("Location %s was not found." % location) log.info("Starting %s." % location) resource = self.resources.get(location) if resource.instance.getState() == State.RUNNING: return True try: resource.instance.__start__() except Exception: log.exception ("Error running %s __start__ method." % location) raise ChimeraObjectException("Error running %s __start__ method." % location) try: # FIXME: thread exception handling # ok, now schedule object main in a new thread log.info("Running %s. __main___." % location) loop = threading.Thread(target=resource.instance.__main__) loop.setName(str(resource.location) + ".__main__") loop.setDaemon(True) loop.start() resource.instance.__setstate__(State.RUNNING) resource.created = time.time() resource.loop = loop return True except Exception, e: log.exception("Error running %s __main__ method." % location) resource.instance.__setstate__(State.STOPPED) raise ChimeraObjectException("Error running %s __main__ method." % location)
def startup(self): if self.options.daemon: # detach log.info("FIXME: Daemon...") # system config try: self.config = SystemConfig.fromFile(self.options.config_file) except (InvalidLocationException, IOError), e: log.exception(e) log.error( "There was a problem reading your configuration file. (%s)" % e) sys.exit(1)
def __init__(self, host=None, port=None, local=False): RemoteObject.__init__(self) log.info("Starting manager.") self.resources = ResourcesManager() self.classLoader = ClassLoader() # identity self.setGUID(MANAGER_LOCATION) # shutdown event self.died = threading.Event() if not local: try: ManagerLocator.locate() raise ChimeraException("Chimera is already running" " on this system. Use chimera-admin" " to manage it.") except ManagerNotFoundException: # ok, we are alone. pass # our daemon server self.adapter = ManagerAdapter(self, host, port) self.adapterThread = threading.Thread(target=self.adapter.requestLoop) self.adapterThread.setDaemon(True) self.adapterThread.start() # finder beacon if not local: self.beacon = ManagerBeacon(self) self.beaconThread = threading.Thread(target=self.beacon.run) self.beaconThread.setDaemon(True) self.beaconThread.start() else: self.beacon = None # register ourself self.resources.add(MANAGER_LOCATION, self, getManagerURI(self.getHostname(), self.getPort())) # signals signal.signal(signal.SIGTERM, self._sighandler) signal.signal(signal.SIGINT, self._sighandler) atexit.register(self._sighandler)
def stop(self, location): """ Stop the object pointed by 'location'. @param location: The object to stop. @type location: Location or str @raises ObjectNotFoundException: When the requested object or the Manager was not found. @raises ChimeraObjectException: Internal error on managed (user) object. @return: retuns True if sucessfull. False otherwise. @rtype: bool """ if location not in self.resources: raise ObjectNotFoundException("Location %s was not found." % location) log.info("Stopping %s." % location) resource = self.resources.get(location) try: # stop control loop if resource.loop and resource.loop.isAlive(): resource.instance.__abort_loop__() try: resource.loop.join() except KeyboardInterrupt: # ignore Ctrl+C on shutdown pass if resource.instance.getState() != State.STOPPED: resource.instance.__stop__() resource.instance.__setstate__(State.STOPPED) return True except Exception, e: log.exception( "Error running %s __stop__ method. Exception follows..." % location) raise ChimeraObjectException("Error running %s __stop__ method." % location)
def shutdown(self): """ Ask the system to shutdown. Closing all sockets and stopping all threads. @return: Nothing @rtype: None """ # die, but only if we are alive ;) if not self.died.isSet(): log.info("Shuting down manager.") # stop objects # damm 2.4, on 2.5 try/except/finally works try: try: elderly_first = sorted( list(self.resources.values()), cmp=lambda x, y: cmp(x.created, y.created), reverse=True) for resource in elderly_first: # except Manager if resource.location == MANAGER_LOCATION: continue # stop object self.stop(resource.location) except ChimeraException: pass finally: # kill our adapter self.adapter.shutdown(disconnect=True) if self.beacon: self.beacon.shutdown() self.beaconThread.join() # die! self.died.set() log.info("Manager finished.")
def run(self): log.info("Starting scheduler machine") self.state(State.DIRTY) while self.state() != State.SHUTDOWN: if self.state() == State.OFF: log.debug("[off] will just sleep..") pass if self.state() == State.DIRTY: log.debug("[dirty] database changed, rescheduling...") self.scheduler.reschedule(self) self.state(State.IDLE) continue if self.state() == State.IDLE: log.debug("[idle] looking for something to do...") # find something to do exposure = self.scheduler.next() if exposure: log.debug("[idle] there is something to do, processing...") self.state(State.BUSY) self._process(exposure) continue # should'nt get here if any task was executed log.debug("[idle] there is nothing to do, sleeping...") elif self.state() == State.BUSY: log.debug("[busy] waiting tasks to finish..") pass elif self.state() == State.SHUTDOWN: log.debug("[shutdown] should die soon.") break # Rest In Pieces/Let Sleeping Dogs Lie self.sleep() log.debug('[shutdown] thread ending...')
def selectScienceTargets(self): ''' Based on configuration parameters select a good set of targets to run scheduler on a specified Julian Day. ''' session = Session() # [To be done] Reject objects that are close to the moon for tbin,time in enumerate(self.obsTimeBins): if self.obsTimeMask[tbin] < 1.0: # Select objects from database that where not observed and where not scheduled yet # In the future may include targets that where observed a number of nights ago. # This is still incomplete. We should also consider the distance from the previous pointing to the next! # Since a target can have a higher airmass but be farther away from a neaby target that will take less time # to point. # one way of selecting targets that are close together and have good airmass is to select regions that are close # to the current location. it can start as searching an area with r1 ~ 10 x the FoV and, if there are no regions # to to x2 that and then x4 that. If still there are no targets, than search for the higher in the sky. targets = session.query(Targets).filter(Targets.observed == False).filter(Targets.scheduled == False).filter(Targets.type == self.sciFlag) lst = _skysub.lst(time,self.sitelong) #*360./24. alt = np.array([_skysub.altit(target.targetDec,lst - target.targetRa,self.sitelat)[0] for target in targets]) stg = alt.argmax() log.info('Selecting %s'%(targets[stg])) # Marking target as schedule tst = session.query(Targets).filter(Targets.id == targets[stg].id) for t in tst: t.scheduled = True session.commit() self.addObservation(t,time) self.obsTimeMask[tbin] = 1.0 else: log.debug('Bin %3i @mjd=%.3f already filled up with observations. Skipping...'%(tbin,time-2400000.5)) #print i return 0 #targets
def stop (self, location): """ Stop the object pointed by 'location'. @param location: The object to stop. @type location: Location or str @raises ObjectNotFoundException: When the requested object or the Manager was not found. @raises ChimeraObjectException: Internal error on managed (user) object. @return: retuns True if sucessfull. False otherwise. @rtype: bool """ if location not in self.resources: raise ObjectNotFoundException ("Location %s was not found." % location) log.info("Stopping %s." % location) resource = self.resources.get(location) try: # stop control loop if resource.loop and resource.loop.isAlive(): resource.instance.__abort_loop__() try: resource.loop.join() except KeyboardInterrupt: # ignore Ctrl+C on shutdown pass if resource.instance.getState() != State.STOPPED: resource.instance.__stop__ () resource.instance.__setstate__(State.STOPPED) return True except Exception, e: log.exception("Error running %s __stop__ method. Exception follows..." % location) raise ChimeraObjectException("Error running %s __stop__ method." % location)
def shutdown(self): """ Ask the system to shutdown. Closing all sockets and stopping all threads. @return: Nothing @rtype: None """ # die, but only if we are alive ;) if not self.died.isSet(): log.info("Shuting down manager.") # stop objects # damm 2.4, on 2.5 try/except/finally works try: try: elderly_first = sorted( list(self.resources.values()), cmp=lambda x, y: cmp(x.created, y.created), reverse=True ) for resource in elderly_first: # except Manager if resource.location == MANAGER_LOCATION: continue # stop object self.stop(resource.location) except ChimeraException: pass finally: # kill our adapter self.adapter.shutdown(disconnect=True) # die! self.died.set() log.info("Manager finished.")
def __init__(self, host = None, port = None): RemoteObject.__init__ (self) log.info("Starting manager.") self.resources = ResourcesManager() self.classLoader = ClassLoader() # identity self.setGUID(MANAGER_LOCATION) # shutdown event self.died = threading.Event() # our daemon server self.adapter = ManagerAdapter (self, host, port) self.adapterThread = threading.Thread(target=self.adapter.requestLoop) self.adapterThread.setDaemon(True) self.adapterThread.start() # register ourselves self.resources.add(MANAGER_LOCATION, self, getManagerURI(self.getHostname(), self.getPort()))
def __init__(self, host=None, port=None): RemoteObject.__init__(self) log.info("Starting manager.") self.resources = ResourcesManager() self.classLoader = ClassLoader() # identity self.setGUID(MANAGER_LOCATION) # shutdown event self.died = threading.Event() # our daemon server self.adapter = ManagerAdapter(self, host, port) self.adapterThread = threading.Thread(target=self.adapter.requestLoop) self.adapterThread.setDaemon(True) self.adapterThread.start() # register ourself self.resources.add(MANAGER_LOCATION, self, getManagerURI(self.getHostname(), self.getPort()))
self.manager = Manager(**self.config.chimera) except ChimeraException, e: log.error("Chimera is already running on this machine. Use chimera-admin to manage it.") sys.exit(1) log.info("Chimera: running on "+ self.manager.getHostname() + ":" + str(self.manager.getPort())) log.info("Chimera: reading configuration from %s" % os.path.realpath(self.options.config_file)) # add site object if not self.options.dry: for site in self.config.sites: self.manager.addClass(Site, site.name, site.config, True) # search paths log.info("Setting objects include path from command line parameters...") for _dir in self.options.inst_dir: self.paths["instruments"].append(_dir) for _dir in self.options.ctrl_dir: self.paths["controllers"].append(_dir) # init from config log.info("Trying to start instruments...") for inst in self.config.instruments + self.options.instruments: if self.options.dry: print inst else: self._add(inst, path=self.paths["instruments"], start=True)
def addObservation(self,target,obstime): session = Session() lineRe = re.compile('(?P<coord>(?P<ra>[\d:-]+)\s+(?P<dec>\+?[\d:-]+)\s+(?P<epoch>[\dnowNOWJjBb\.]+)\s+)?(?P<imagetype>[\w]+)' '\s+(?P<objname>\'([^\\n\'\\\\]|\\\\.)*\'|"([^\\n"\\\\]|\\\\.)*"|([^ \\n"\\\\]|\\\\.)*)\s+(?P<exposures>[\w\d\s:\*\(\),]*)') programs = [] entryFormat = '%(ra)s %(dec)s %(epoch)s %(obstype)s %(name)s %(exposures)s' p = Position.fromRaDec(target.targetRa,target.targetDec) ra = p.ra.HMS dec = p.dec.DMS filterExpt = self.sciExpTime if target.type == self.stdFlag: filterExpt = self.stdExpTime exposures = '1*(' for i in range(self.nfilters): exposures = exposures+'%s:%.0f, '%(self.filters[i],filterExpt[i]) exposures = exposures[:-2] exposures += ')' infos = { 'ra' : '%02.0f:%02.0f:%02.0f'%(ra[1],ra[2],ra[3]), 'dec': '%+03.0f:%02.0f:%02.0f'%(dec[0]*dec[1],dec[2],dec[3]), 'epoch' : 'J%.0f'%target.targetEpoch, 'obstype' : 'OBJECT', 'name' :target.name, 'exposures' : exposures } i = 0 line = entryFormat%infos matchs = lineRe.search(line) params = matchs.groupdict() position = None objname = None if params.get("coord", None): position = Position.fromRaDec(str(params['ra']), str(params['dec']), params['epoch']) imagetype = params['imagetype'].upper() objname = params['objname'].replace("\"", "") multiplier, exps = params['exposures'].split("*") try: multiplier = int(multiplier) except ValueError: multiplier = 1 exps = exps.replace("(", "").replace(")", "").strip().split(",") mjd = obstime - 2400000.5 for i in range(multiplier): program = Program(tid = target.id ,name="%s-%03d" % (objname.replace(" ", ""), i), slewAt=mjd,exposeAt=mjd+1./60./24.) log.info("# program: %s" % program.name) if imagetype == "OBJECT": if position: program.actions.append(Point(targetRaDec=position)) else: program.actions.append(Point(targetName=objname)) if imagetype == "FLAT": site = self._remoteManager.getProxy("/Site/0") flatPosition = Position.fromAltAz(site['flat_alt'], site['flat_az']) program.actions.append(Point(targetAltAz=flatPosition)) #if i == 0: # program.actions.append(AutoFocus(start=1500, end=3000, step=250, filter="R", exptime=10)) # program.actions.append(PointVerify(here=True)) for exp in exps: if exp.count(":") > 1: filter, exptime, frames = exp.strip().split(":") else: filter, exptime = exp.strip().split(":") frames = 1 if imagetype in ("OBJECT", "FLAT"): shutter = "OPEN" else: shutter = "CLOSE" if imagetype == "BIAS": exptime = 0 if imagetype in ("BIAS", "DARK"): filter = None log.info("%s %s %s filter=%s exptime=%s frames=%s" % (imagetype, objname, str(position), filter, exptime, frames)) program.actions.append(Expose(shutter=shutter, filename="%s-$DATE-$TIME" % objname.replace(" ", ""), filter=filter, frames=frames, exptime=exptime, imageType=imagetype, objectName=objname)) log.info("") programs.append(program) session.add_all(programs) session.commit()
) sys.exit(1) log.info("Chimera: running on " + self.manager.getHostname() + ":" + str(self.manager.getPort())) log.info("Chimera: reading configuration from %s" % os.path.realpath(self.options.config_file)) # add site object if not self.options.dry: for site in self.config.sites: self.manager.addClass(Site, site.name, site.config, True) # search paths log.info( "Setting objects include path from command line parameters...") for _dir in self.options.inst_dir: self.paths["instruments"].append(_dir) for _dir in self.options.ctrl_dir: self.paths["controllers"].append(_dir) # init from config log.info("Trying to start instruments...") for inst in self.config.instruments + self.options.instruments: if self.options.dry: print inst else: self._add(inst, path=self.paths["instruments"], start=True)
def startup(self): if self.options.daemon: # detach log.info("FIXME: Daemon...") # system config try: self.config = SystemConfig.fromFile(self.options.config_file) except (InvalidLocationException, IOError) as e: log.exception(e) log.error( "There was a problem reading your configuration file. (%s)" % e) sys.exit(1) # manager if not self.options.dry: log.info("Starting system.") log.info("Chimera: %s" % _chimera_version_) log.info("Chimera prefix: %s" % ChimeraPath().root()) log.info("Python: %s" % platform.python_version()) log.info("System: %s" % ' '.join(platform.uname())) try: self.manager = Manager(**self.config.chimera) except ChimeraException as e: log.error( "Chimera is already running on this machine. Use chimera-admin to manage it." ) sys.exit(1) log.info("Chimera: running on " + self.manager.getHostname() + ":" + str(self.manager.getPort())) log.info("Chimera: reading configuration from %s" % os.path.realpath(self.options.config_file)) # add site object if not self.options.dry: for site in self.config.sites: self.manager.addClass(Site, site.name, site.config, True) # search paths log.info( "Setting objects include path from command line parameters...") for _dir in self.options.inst_dir: self.paths["instruments"].append(_dir) for _dir in self.options.ctrl_dir: self.paths["controllers"].append(_dir) # init from config log.info("Trying to start instruments...") for inst in self.config.instruments + self.options.instruments: if self.options.dry: print(inst) else: self._add(inst, path=self.paths["instruments"], start=True) log.info("Trying to start controllers...") for ctrl in self.config.controllers + self.options.controllers: if self.options.dry: print(ctrl) else: self._add(ctrl, path=self.paths["controllers"], start=True) log.info("System up and running.") # ok, let's wait manager work if self.wait and not self.options.dry: self.manager.wait()
def shutdown(self): log.info("Shutting down system.") self.manager.shutdown()
def selectStandardTargets(self, nstars=3, nairmass=3): ''' Based on configuration parameters, select 'nstars' standard stars to run scheduler on a specified Julian Day. Ideally you will select standard stars before your science targets so not to have a full queue. Usually standard stars are observed more than once a night at different airmasses. The user can control this parameter with nairmass and the script will try to take care of the rest. ''' session = Session() # First of all, standard stars can be obsered multiple times in sucessive nights. I will mark all # stars an unscheduled. targets = session.query(Targets).filter( Targets.scheduled == True).filter(Targets.type == self.stdFlag) for target in targets: target.scheduled = False session.commit() # [To be done] Reject objects that are close to the moon # Selecting standard stars is not only searching for the higher in that time but select stars than can be observed at 3 # or more (nairmass) different airmasses. It is also important to select stars with different colors (but this will be # taken care in the future). if nairmass * nstars > len(self.obsTimeBins): log.warning( 'Requesting more stars/observations than it will be possible to schedule. Decreasing number of requests to fit in the night.' ) nstars = len(self.obsTimeBins) / nairmass obsStandars = np.zeros(len( self.obsTimeBins)) - 1 # first selection of observable standards for tbin, time in enumerate(self.obsTimeBins): if self.obsTimeMask[tbin] < 1.0: # 1 - Select objects from database that where not scheduled yet (standard stars may be repited) # that fits our observing night targets = session.query(Targets).filter( Targets.scheduled == 0).filter( Targets.type == self.stdFlag) lst = _skysub.lst(time, self.sitelong) #*360./24. alt = np.array([ _skysub.altit(target.targetDec, lst - target.targetRa, self.sitelat)[0] for target in targets ]) stg = alt.argmax() log.info('Selecting %s' % (targets[stg])) # Marking target as schedule tst = session.query(Targets).filter( Targets.id == targets[stg].id) for t in tst: t.scheduled = True session.commit() obsStandars[tbin] = t.id else: log.info( 'Bin already filled up with observations. Skipping...') if len(obsStandars[obsStandars >= 0]) < nstars: log.warning( 'Could not find %i suitable standard stars in catalog. Only %i where found.' % (nstars, len(obsStandars[obsStandars >= 0]))) # # Unmarking potential targets as scheduled # for id in obsStandars[obsStandars >= 0]: target = session.query(Targets).filter(Targets.id == id) for t in target: t.scheduled = False session.commit() tbin += 1 # # Preparing a grid of altitudes for each target for each observing window # amGrid = np.zeros(len(obsStandars) * len(obsStandars)).reshape( len(obsStandars), len(obsStandars)) for i in np.arange(len(obsStandars))[obsStandars >= 0]: target = session.query(Targets).filter( Targets.id == obsStandars[i])[0] for j in range(len(obsStandars)): lst = _skysub.lst(self.obsTimeBins[j], self.sitelong) amGrid[i][j] = _skysub.true_airmass( _skysub.secant_z( _skysub.altit(target.targetDec, lst - target.targetRa, self.sitelat)[0])) if amGrid[i][j] < 0: amGrid[i][j] = 99. # # Build a grid mask that specifies the position in time each target should be observed. This means that, when # selecting a single target we ocuppy more than one, non consecutive, position in the night. This grid shows where are these # positions. # obsMask = np.zeros(len(obsStandars) * len(obsStandars), dtype=np.bool).reshape(len(obsStandars), len(obsStandars)) for i in np.arange(len(obsStandars))[obsStandars >= 0]: amObs = np.linspace(amGrid[i].min(), self.stdMaxAirmass, nairmass) # requested aimasses dam = np.mean( np.abs(amGrid[i][amGrid[i] < self.stdMaxAirmass][1:] - amGrid[i][amGrid[i] < self.stdMaxAirmass][:-1]) ) # how much airmass changes in average for j, am in enumerate(amObs): # Mark positions where target is at specified airmass if j == 0: obsMask[i] = np.bitwise_or(obsMask[i], amGrid[i] == am) else: obsMask[i] = np.bitwise_or( obsMask[i], np.bitwise_and(amGrid[i] > am - dam, amGrid[i] < am + dam)) #print amGrid[i][np.where(obsMask[i])] # # Now it is time to actually select the targets. It will start with the first target and then try the others # until it find enough standard stars, as specified by the user. # # Para cada bin em tempo, varro o bin em massa de ar por coisas observaveis. Se acho um, vejo se posso agendar # os outros bins. Se sim, marco o alvo para observacao, se nao, passo para o proximo. Repito ate completar a # lista de alvos # obsMaskTimeGrid = np.zeros(len(obsStandars), dtype=np.bool) nrequests = 0 reqId = np.zeros(nstars, dtype=np.int) - 1 for tbin, time in enumerate(self.obsTimeBins[:-1]): # Evaluates if time slots are all available. If yes, mark orbservation and ocuppy slots. if ((not obsMaskTimeGrid[obsMask[tbin]].any()) and (len(amGrid[tbin][obsMask[tbin]]) >= nairmass)): obsMaskTimeGrid = np.bitwise_or(obsMaskTimeGrid, obsMask[tbin]) reqId[nrequests] = tbin nrequests += 1 if nrequests >= nstars: break # Finally, requesting observations for id in reqId[reqId >= 0]: target = session.query(Targets).filter( Targets.id == obsStandars[id])[0] secz = amGrid[id][obsMask[id]] seczreq = np.zeros(nairmass, dtype=np.bool) amObs = np.linspace(amGrid[id].min(), self.stdMaxAirmass, nairmass) # requested aimasses for i, obstime in enumerate(self.obsTimeBins[obsMask[id]]): sindex = np.abs(amObs - secz[i]).argmin() if not seczreq[sindex]: log.info( 'Requesting observations of %s @airmass=%4.2f @mjd=%.3f...' % (target.name, secz[i], obstime - 2400000.5)) seczreq[sindex] = True target.scheduled = True session.commit() self.addObservation(target, obstime) self.obsTimeMask[obsMask[id]] = 1.0 #print self.obsTimeBins[obsMask[id]] #print #print i return 0 #targets
def selectStandardTargets(self,nstars=3,nairmass=3): ''' Based on configuration parameters, select 'nstars' standard stars to run scheduler on a specified Julian Day. Ideally you will select standard stars before your science targets so not to have a full queue. Usually standard stars are observed more than once a night at different airmasses. The user can control this parameter with nairmass and the script will try to take care of the rest. ''' session = Session() # First of all, standard stars can be obsered multiple times in sucessive nights. I will mark all # stars an unscheduled. targets = session.query(Targets).filter(Targets.scheduled == True).filter(Targets.type == self.stdFlag) for target in targets: target.scheduled = False session.commit() # [To be done] Reject objects that are close to the moon # Selecting standard stars is not only searching for the higher in that time but select stars than can be observed at 3 # or more (nairmass) different airmasses. It is also important to select stars with different colors (but this will be # taken care in the future). if nairmass*nstars > len(self.obsTimeBins): log.warning('Requesting more stars/observations than it will be possible to schedule. Decreasing number of requests to fit in the night.') nstars = len(self.obsTimeBins)/nairmass obsStandars = np.zeros(len(self.obsTimeBins))-1 # first selection of observable standards for tbin,time in enumerate(self.obsTimeBins): if self.obsTimeMask[tbin] < 1.0: # 1 - Select objects from database that where not scheduled yet (standard stars may be repited) # that fits our observing night targets = session.query(Targets).filter(Targets.scheduled == 0).filter(Targets.type == self.stdFlag) lst = _skysub.lst(time,self.sitelong) #*360./24. alt = np.array([_skysub.altit(target.targetDec,lst - target.targetRa,self.sitelat)[0] for target in targets]) stg = alt.argmax() log.info('Selecting %s'%(targets[stg])) # Marking target as schedule tst = session.query(Targets).filter(Targets.id == targets[stg].id) for t in tst: t.scheduled = True session.commit() obsStandars[tbin] = t.id else: log.info('Bin already filled up with observations. Skipping...') if len(obsStandars[obsStandars >= 0]) < nstars: log.warning('Could not find %i suitable standard stars in catalog. Only %i where found.'%(nstars,len(obsStandars[obsStandars >= 0]))) # # Unmarking potential targets as scheduled # for id in obsStandars[obsStandars >= 0]: target = session.query(Targets).filter(Targets.id == id) for t in target: t.scheduled = False session.commit() tbin+=1 # # Preparing a grid of altitudes for each target for each observing window # amGrid = np.zeros(len(obsStandars)*len(obsStandars)).reshape(len(obsStandars),len(obsStandars)) for i in np.arange(len(obsStandars))[obsStandars >= 0]: target = session.query(Targets).filter(Targets.id == obsStandars[i])[0] for j in range(len(obsStandars)): lst = _skysub.lst(self.obsTimeBins[j],self.sitelong) amGrid[i][j] = _skysub.true_airmass(_skysub.secant_z(_skysub.altit(target.targetDec,lst - target.targetRa,self.sitelat)[0])) if amGrid[i][j] < 0: amGrid [i][j] = 99. # # Build a grid mask that specifies the position in time each target should be observed. This means that, when # selecting a single target we ocuppy more than one, non consecutive, position in the night. This grid shows where are these # positions. # obsMask = np.zeros(len(obsStandars)*len(obsStandars),dtype=np.bool).reshape(len(obsStandars),len(obsStandars)) for i in np.arange(len(obsStandars))[obsStandars >= 0]: amObs = np.linspace(amGrid[i].min(),self.stdMaxAirmass,nairmass) # requested aimasses dam = np.mean(np.abs(amGrid[i][amGrid[i]<self.stdMaxAirmass][1:] - amGrid[i][amGrid[i]<self.stdMaxAirmass][:-1])) # how much airmass changes in average for j,am in enumerate(amObs): # Mark positions where target is at specified airmass if j == 0: obsMask[i] = np.bitwise_or(obsMask[i],amGrid[i] == am) else: obsMask[i] = np.bitwise_or(obsMask[i],np.bitwise_and(amGrid[i]>am-dam,amGrid[i]<am+dam)) #print amGrid[i][np.where(obsMask[i])] # # Now it is time to actually select the targets. It will start with the first target and then try the others # until it find enough standard stars, as specified by the user. # # Para cada bin em tempo, varro o bin em massa de ar por coisas observaveis. Se acho um, vejo se posso agendar # os outros bins. Se sim, marco o alvo para observacao, se nao, passo para o proximo. Repito ate completar a # lista de alvos # obsMaskTimeGrid = np.zeros(len(obsStandars),dtype=np.bool) nrequests = 0 reqId = np.zeros(nstars,dtype=np.int)-1 for tbin,time in enumerate(self.obsTimeBins[:-1]): # Evaluates if time slots are all available. If yes, mark orbservation and ocuppy slots. if ( (not obsMaskTimeGrid[obsMask[tbin]].any()) and (len(amGrid[tbin][obsMask[tbin]])>=nairmass) ): obsMaskTimeGrid = np.bitwise_or(obsMaskTimeGrid,obsMask[tbin]) reqId[nrequests] = tbin nrequests += 1 if nrequests >= nstars: break # Finally, requesting observations for id in reqId[reqId >= 0]: target = session.query(Targets).filter(Targets.id == obsStandars[id])[0] secz = amGrid[id][obsMask[id]] seczreq = np.zeros(nairmass,dtype=np.bool) amObs = np.linspace(amGrid[id].min(),self.stdMaxAirmass,nairmass) # requested aimasses for i,obstime in enumerate(self.obsTimeBins[obsMask[id]]): sindex = np.abs(amObs-secz[i]).argmin() if not seczreq[sindex]: log.info('Requesting observations of %s @airmass=%4.2f @mjd=%.3f...'%(target.name,secz[i],obstime-2400000.5)) seczreq[sindex] = True target.scheduled = True session.commit() self.addObservation(target,obstime) self.obsTimeMask[obsMask[id]] = 1.0 #print self.obsTimeBins[obsMask[id]] #print #print i return 0 #targets
class SiteController(object): def __init__(self, args=[], wait=True): self.wait = wait self.options, self.args = self.parseArgs(args) if self.options.verbose == 1: chimera.core.log.setConsoleLevel(logging.INFO) if self.options.verbose > 1: chimera.core.log.setConsoleLevel(logging.DEBUG) self.manager = None self.paths = {"instruments": [], "controllers": [], "drivers": []} # add system path self.paths["instruments"].append(ChimeraPath.instruments()) self.paths["controllers"].append(ChimeraPath.controllers()) self.paths["drivers"].append(ChimeraPath.drivers()) def parseArgs(self, args): def check_location(option, opt_str, value, parser): try: l = Location(value) except InvalidLocationException: raise optparse.OptionValueError("%s isnt't a valid location." % value) eval('parser.values.%s.append ("%s")' % (option.dest, value)) def check_includepath(option, opt_str, value, parser): if not value or not os.path.isdir(os.path.abspath(value)): raise optparse.OptionValueError( "Couldn't found %s include path." % value) eval('parser.values.%s.append ("%s")' % (option.dest, value)) parser = optparse.OptionParser( prog="chimera", version=find_dev_version() or _chimera_version_, description=_chimera_description_, usage="chimera --help for more information") manag_group = optparse.OptionGroup(parser, "Basic options") manag_group.add_option( "-H", "--host", action="store", dest="pyro_host", type="string", help="Host name/IP address to run as; [default=%default]", metavar="HOST") manag_group.add_option( "-P", "--port", action="store", dest="pyro_port", type="string", help="Port on which to listen for requests; [default=%default]", metavar="PORT") config_group = optparse.OptionGroup(parser, "Configuration") config_group.add_option( "--config", dest="config_file", help="Start Chimera using configuration from FILE.", metavar="FILE") config_group.add_option("--skip-global", action="store_false", dest="use_global", help="Don't use global coniguration file.") config_group.add_option( "--daemon", action="store_true", dest='daemon', help= "Run Chimera in Daemon mode (will detach from current terminal).") misc_group = optparse.OptionGroup(parser, "General") misc_group.add_option( "--dry-run", action="store_true", dest="dry", help= "Only list all configured objects (from command line and configuration files) without starting the system." ) misc_group.add_option( "-v", "--verbose", action="count", dest='verbose', help="Increase log level (multiple v's to increase even more).") inst_group = optparse.OptionGroup( parser, "Instruments, Controllers and Drivers Management") inst_group.add_option( "-i", "--instrument", action="callback", callback=check_location, dest="instruments", type="string", help="Load the instrument defined by LOCATION." "This option could be setted many times to load multiple instruments.", metavar="LOCATION") inst_group.add_option( "-c", "--controller", action="callback", callback=check_location, dest="controllers", type="string", help="Load the controller defined by LOCATION." "This option could be setted many times to load multiple controllers.", metavar="LOCATION") inst_group.add_option( "-d", "--driver", action="callback", callback=check_location, dest="drivers", type="string", help="Load the driver defined by LOCATION." "This option could be setted many times to load multiple drivers.", metavar="LOCATION") inst_group.add_option("-I", "--instruments-dir", action="callback", callback=check_includepath, dest="inst_dir", type="string", help="Append PATH to instruments load path.", metavar="PATH") inst_group.add_option("-C", "--controllers-dir", action="callback", callback=check_includepath, dest="ctrl_dir", type="string", help="Append PATH to controllers load path.", metavar="PATH") inst_group.add_option("-D", "--drivers-dir", action="callback", callback=check_includepath, dest="drv_dir", type="string", help="Append PATH to drivers load path.", metavar="PATH") parser.add_option_group(manag_group) parser.add_option_group(config_group) parser.add_option_group(misc_group) parser.add_option_group(inst_group) parser.set_defaults(instruments=[], controllers=[], drivers=[], config_file=SYSTEM_CONFIG_DEFAULT_FILENAME, inst_dir=[], ctrl_dir=[], drv_dir=[], dry=False, use_global=True, verbose=0, daemon=False, pyro_host=MANAGER_DEFAULT_HOST, pyro_port=MANAGER_DEFAULT_PORT) return parser.parse_args(args) def startup(self): if self.options.daemon: # detach log.info("FIXME: Daemon...") # system config self.config = SystemConfig.fromFile(self.options.config_file, self.options.use_global) # manager if not self.options.dry: log.info("Starting system.") log.info("Chimera version: %s" % find_dev_version() or _chimera_version_) log.info("Chimera prefix: %s" % ChimeraPath.root()) try: self.manager = Manager(**self.config.chimera) except ChimeraException, e: log.error( "Chimera is already running on this machine. Use chimera-admin to manage it." ) sys.exit(1) log.info("Chimera: running on " + self.manager.getHostname() + ":" + str(self.manager.getPort())) if self.options.use_global: log.info("Chimera: reading configuration from %s" % SYSTEM_CONFIG_DEFAULT_GLOBAL) log.info("Chimera: reading configuration from %s" % os.path.realpath(self.options.config_file)) # add site object if not self.options.dry: for site in self.config.sites: self.manager.addClass(Site, site.name, site.config, True) # search paths log.info( "Setting objects include path from command line parameters...") for _dir in self.options.inst_dir: self.paths["instruments"].append(_dir) for _dir in self.options.ctrl_dir: self.paths["controllers"].append(_dir) for _dir in self.options.drv_dir: self.paths["drivers"].append(_dir) # init from config log.info("Trying to start drivers...") for drv in self.config.drivers + self.options.drivers: if self.options.dry: print drv else: self._add(drv, path=self.paths["drivers"], start=True) log.info("Trying to start instruments...") for inst in self.config.instruments + self.options.instruments: if self.options.dry: print inst else: self._add(inst, path=self.paths["instruments"], start=True) log.info("Trying to start controllers...") for ctrl in self.config.controllers + self.options.controllers: if self.options.dry: print ctrl else: self._add(ctrl, path=self.paths["controllers"], start=True) log.info("System up and running.") # ok, let's wait manager work if self.wait and not self.options.dry: self.manager.wait()
def startup(self): if self.options.daemon: # detach log.info("FIXME: Daemon...") # system config self.config = SystemConfig.fromFile(self.options.config_file, self.options.use_global) # manager if not self.options.dry: log.info("Starting system.") log.info("Chimera version: %s" % find_dev_version() or _chimera_version_) log.info("Chimera prefix: %s" % ChimeraPath.root()) try: self.manager = Manager(**self.config.chimera) except ChimeraException, e: log.error( "Chimera is already running on this machine. Use chimera-admin to manage it." ) sys.exit(1) log.info("Chimera: running on " + self.manager.getHostname() + ":" + str(self.manager.getPort())) if self.options.use_global: log.info("Chimera: reading configuration from %s" % SYSTEM_CONFIG_DEFAULT_GLOBAL) log.info("Chimera: reading configuration from %s" % os.path.realpath(self.options.config_file))
class SiteController(object): def __init__(self, args=[], wait=True): self.wait = wait self.options, self.args = self.parseArgs(args) if self.options.verbose == 1: chimera.core.log.setConsoleLevel(logging.INFO) #log.setConsoleLevel(logging.INFO) if self.options.verbose > 1: chimera.core.log.setConsoleLevel(logging.DEBUG) #log.setConsoleLevel(logging.DEBUG) self.manager = None self.paths = {"instruments": [], "controllers": []} # add system and plugins paths Path = ChimeraPath() self.paths["instruments"].extend(Path.instruments) self.paths["controllers"].extend(Path.controllers) def parseArgs(self, args): def check_location(option, opt_str, value, parser): try: l = Location(value) except InvalidLocationException: raise optparse.OptionValueError("%s isnt't a valid location." % value) eval('parser.values.%s.append ("%s")' % (option.dest, value)) def check_includepath(option, opt_str, value, parser): if not value or not os.path.isdir(os.path.abspath(value)): raise optparse.OptionValueError( "Couldn't found %s include path." % value) eval('parser.values.%s.append ("%s")' % (option.dest, value)) parser = optparse.OptionParser( prog="chimera", version=_chimera_version_, description=_chimera_description_, usage="chimera --help for more information") manag_group = optparse.OptionGroup(parser, "Basic options") manag_group.add_option( "-H", "--host", action="store", dest="pyro_host", type="string", help="Host name/IP address to run as; [default=%default]", metavar="HOST") manag_group.add_option( "-P", "--port", action="store", dest="pyro_port", type="string", help="Port on which to listen for requests; [default=%default]", metavar="PORT") config_group = optparse.OptionGroup(parser, "Configuration") config_group.add_option( "--config", dest="config_file", help="Start Chimera using configuration from FILE.", metavar="FILE") config_group.add_option( "--daemon", action="store_true", dest='daemon', help= "Run Chimera in Daemon mode (will detach from current terminal).") misc_group = optparse.OptionGroup(parser, "General") misc_group.add_option( "--dry-run", action="store_true", dest="dry", help= "Only list all configured objects (from command line and configuration files) without starting the system." ) misc_group.add_option( "-v", "--verbose", action="count", dest='verbose', help="Increase log level (multiple v's to increase even more).") inst_group = optparse.OptionGroup( parser, "Instruments and Controllers Management") inst_group.add_option( "-i", "--instrument", action="callback", callback=check_location, dest="instruments", type="string", help="Load the instrument defined by LOCATION." "This option could be set many times to load multiple instruments.", metavar="LOCATION") inst_group.add_option( "-c", "--controller", action="callback", callback=check_location, dest="controllers", type="string", help="Load the controller defined by LOCATION." "This option could be set many times to load multiple controllers.", metavar="LOCATION") inst_group.add_option("-I", "--instruments-dir", action="callback", callback=check_includepath, dest="inst_dir", type="string", help="Append PATH to instruments load path.", metavar="PATH") inst_group.add_option("-C", "--controllers-dir", action="callback", callback=check_includepath, dest="ctrl_dir", type="string", help="Append PATH to controllers load path.", metavar="PATH") parser.add_option_group(manag_group) parser.add_option_group(config_group) parser.add_option_group(misc_group) parser.add_option_group(inst_group) parser.set_defaults(instruments=[], controllers=[], config_file=SYSTEM_CONFIG_DEFAULT_FILENAME, inst_dir=[], ctrl_dir=[], drv_dir=[], dry=False, verbose=0, daemon=False, pyro_host=MANAGER_DEFAULT_HOST, pyro_port=MANAGER_DEFAULT_PORT) return parser.parse_args(args) def startup(self): if self.options.daemon: # detach log.info("FIXME: Daemon...") # system config try: self.config = SystemConfig.fromFile(self.options.config_file) except (InvalidLocationException, IOError), e: log.exception(e) log.error( "There was a problem reading your configuration file. (%s)" % e) sys.exit(1) # manager if not self.options.dry: log.info("Starting system.") log.info("Chimera: %s" % _chimera_version_) log.info("Chimera prefix: %s" % ChimeraPath().root()) log.info("Python: %s" % platform.python_version()) log.info("System: %s" % ' '.join(platform.uname())) try: self.manager = Manager(**self.config.chimera) except ChimeraException, e: log.error( "Chimera is already running on this machine. Use chimera-admin to manage it." ) sys.exit(1) log.info("Chimera: running on " + self.manager.getHostname() + ":" + str(self.manager.getPort())) log.info("Chimera: reading configuration from %s" % os.path.realpath(self.options.config_file))
def addObservation(self, target, obstime): session = Session() lineRe = re.compile( '(?P<coord>(?P<ra>[\d:-]+)\s+(?P<dec>\+?[\d:-]+)\s+(?P<epoch>[\dnowNOWJjBb\.]+)\s+)?(?P<imagetype>[\w]+)' '\s+(?P<objname>\'([^\\n\'\\\\]|\\\\.)*\'|"([^\\n"\\\\]|\\\\.)*"|([^ \\n"\\\\]|\\\\.)*)\s+(?P<exposures>[\w\d\s:\*\(\),]*)' ) programs = [] entryFormat = '%(ra)s %(dec)s %(epoch)s %(obstype)s %(name)s %(exposures)s' p = Position.fromRaDec(target.targetRa, target.targetDec) ra = p.ra.HMS dec = p.dec.DMS filterExpt = self.sciExpTime if target.type == self.stdFlag: filterExpt = self.stdExpTime exposures = '1*(' for i in range(self.nfilters): exposures = exposures + '%s:%.0f, ' % (self.filters[i], filterExpt[i]) exposures = exposures[:-2] exposures += ')' infos = { 'ra': '%02.0f:%02.0f:%02.0f' % (ra[1], ra[2], ra[3]), 'dec': '%+03.0f:%02.0f:%02.0f' % (dec[0] * dec[1], dec[2], dec[3]), 'epoch': 'J%.0f' % target.targetEpoch, 'obstype': 'OBJECT', 'name': target.name, 'exposures': exposures } i = 0 line = entryFormat % infos matchs = lineRe.search(line) params = matchs.groupdict() position = None objname = None if params.get("coord", None): position = Position.fromRaDec(str(params['ra']), str(params['dec']), params['epoch']) imagetype = params['imagetype'].upper() objname = params['objname'].replace("\"", "") multiplier, exps = params['exposures'].split("*") try: multiplier = int(multiplier) except ValueError: multiplier = 1 exps = exps.replace("(", "").replace(")", "").strip().split(",") mjd = obstime - 2400000.5 for i in range(multiplier): program = Program(tid=target.id, name="%s-%03d" % (objname.replace(" ", ""), i), slewAt=mjd, exposeAt=mjd + 1. / 60. / 24.) log.info("# program: %s" % program.name) if imagetype == "OBJECT": if position: program.actions.append(Point(targetRaDec=position)) else: program.actions.append(Point(targetName=objname)) if imagetype == "FLAT": site = self._remoteManager.getProxy("/Site/0") flatPosition = Position.fromAltAz(site['flat_alt'], site['flat_az']) program.actions.append(Point(targetAltAz=flatPosition)) #if i == 0: # program.actions.append(AutoFocus(start=1500, end=3000, step=250, filter="R", exptime=10)) # program.actions.append(PointVerify(here=True)) for exp in exps: if exp.count(":") > 1: filter, exptime, frames = exp.strip().split(":") else: filter, exptime = exp.strip().split(":") frames = 1 if imagetype in ("OBJECT", "FLAT"): shutter = "OPEN" else: shutter = "CLOSE" if imagetype == "BIAS": exptime = 0 if imagetype in ("BIAS", "DARK"): filter = None log.info("%s %s %s filter=%s exptime=%s frames=%s" % (imagetype, objname, str(position), filter, exptime, frames)) program.actions.append( Expose(shutter=shutter, filename="%s-$DATE-$TIME" % objname.replace(" ", ""), filter=filter, frames=frames, exptime=exptime, imageType=imagetype, objectName=objname)) log.info("") programs.append(program) session.add_all(programs) session.commit()