class AD_Integrator(object): """1D integrator""" def __init__(self, suffix='h5', mask=None, **kws): from epicsscan.scandb import ScanDB self.scandb = ScanDB() self.folder = '' self.label = '' self.mask = mask self.suffix = suffix self.sleep_time = 1.0 self.set_state('idle') def set_state(self, state): self.scandb.set_info('xrd_1dint_status', state.lower()) def get_state(self): return self.scandb.get_info('xrd_1dint_status').lower() def read_config(self): calfile = self.scandb.get_info('xrd_calibration') self.label = self.scandb.get_info('xrd_1dint_label') self.folder = self.scandb.get_info('map_folder') if self.folder.endswith('/'): self.folder = self.folder[:-1] calib = json.loads(self.scandb.get_detectorconfig(calfile).text) print("Read Integration configuration: ", calfile) if HAS_PYFAI: self.integrator = AzimuthalIntegrator(**calib) def save_1dint(self, h5file, outfile): t0 = time.time() if not HAS_PYFAI: return try: xrdfile = h5py.File(h5file, 'r') except IOError: time.sleep(2.0 * self.sleep_time) return data = xrdfile['/entry/data/data'] if self.mask is not None: data = data * self.mask if data.shape[1] > data.shape[2]: data = data[:, 3:-3, 1:-1] else: data = data[:, 1:-1, 3:-3] nframes, nx, ny = data.shape xrdfile.close() integrate = self.integrator.integrate1d opts = dict(method='csr', unit='q_A^-1', correctSolidAngle=True, polarization_factor=0.999) dat = [] for i in range(nframes): img = data[i, :, :] img[np.where(img > MAXVAL)] = 0 q, x = integrate(img[::-1, :], 2048, **opts) if i == 0: dat.append(q) dat.append(x) dat = np.array(dat) _path, fname = os.path.split(outfile) print("writing 1D data: %s, %.2f sec" % (fname, time.time() - t0)) np.save(outfile, dat) def integrate(self): if len(self.folder) < 0: self.read_config() fname = '%s*.%s' % (self.label, self.suffix) xrdfiles = glob.glob(os.path.join(self.folder, fname)) for xfile in sorted(xrdfiles): outfile = xfile.replace(self.suffix, 'npy') if not os.path.exists(outfile): self.save_1dint(xfile, outfile) def run(self): while True: time.sleep(self.sleep_time) state = self.get_state() # print(state, self.folder) if state.startswith('starting'): self.read_config() self.set_state('running') elif state.startswith('running'): self.integrate() elif state.startswith('finishing'): self.integrate() self.set_state('idle') self.folder = '' elif state.startswith('idle'): time.sleep(5 * self.sleep_time) elif state.startswith('quit'): return
class QXAFS_ScanWatcher(object): def __init__(self, **conn_kws): self.scandb = ScanDB(**conn_kws) self.state = 0 self.last = self.pulse = -1 self.last_move_time = 0 self.set_state(0) self.config = None self.dead_time = 1.1 self.connect() def connect(self): self.config = json.loads(self.scandb.get_config('qxafs').notes) pulse_channel = "%sCurrentChannel" % self.config['mcs_prefix'] self.pulse_pv = PV(pulse_channel, callback=self.onPulse) self.idarray_pv = PV(self.config['id_array_pv']) self.iddrive_pv = PV(self.config['id_drive_pv']) self.idbusy_pv = PV(self.config['id_busy_pv']) self.pulsecount_pv = PV(PULSECOUNT_PVNAME) self.heartbeat_pv = PV(HEARTBEAT_PVNAME) def qxafs_prep(self): self.idarray = self.idarray_pv.get() self.dtime = float(self.get_info(key='qxafs_dwelltime', default=0.5)) self.pulse = 0 self.last_move_time = 0 self.counters = [] for c in self.scandb.get_scandata(): pv = get_pv(c.pvname) time.sleep(0.05) for c in self.scandb.get_scandata(): pv = get_pv(c.pvname) pv.connect() self.counters.append((c.name, pv, pv.nelm)) def qxafs_finish(self): nidarr = len(self.idarray) self.idarray_pv.put(np.zeros(nidarr)) self.set_state(0) self.dtime = 0.0 self.last, self.pulse = 0, 0 self.last_move_time = 0 self.counters = [] def onPulse(self, pvname, value=0, **kws): self.pulse = value def monitor_qxafs(self): self.qxafs_prep() print("Monitor QXAFS begin") msg_counter = 0 last_pulse = 0 self.pulse = 0 while True: if self.get_state() == 0: print("Break : state=0") break npts = int(self.get_info(key='scan_total_points', default=0)) time.sleep(0.05) now = time.time() self.pulsecount_pv.put("%i" % self.pulse) if self.pulse > last_pulse: self.heartbeat_pv.put("%i" % int(time.time())) val = self.idarray[self.pulse] if (self.iddrive_pv.write_access and (self.idbusy_pv.get() == 0) and ((now- self.last_move_time) > self.dead_time) and (val > MIN_ID_ENERGY) and (val < MAX_ID_ENERGY)): try: self.iddrive_pv.put(val) self.last_move_time = time.time() except: pass last_pulse = self.pulse cpt = int(self.pulse) time_left = (npts-cpt)*self.dtime self.scandb.set_info('scan_time_estimate', time_left) time_est = hms(time_left) msg = 'Point %i/%i, time left: %s' % (cpt, npts, time_est) if cpt >= 10*msg_counter: self.scandb.set_info('scan_progress', msg) msg_counter += 1 print(msg) for name, pv, nelm in self.counters: try: if nelm > 1: self.scandb.set_scandata(name, pv.get()) else: buff = pv.get() self.scandb.append_scandata(name, pv.get()) except: print "Could not set scandata for %s: %i, %s" % (name, nelm, pv) self.scandb.commit() print("Monitor QXAFS done") last_pulse = self.pulse = 0 self.qxafs_finish() def get_info(self, *args, **kws): return self.scandb.get_info(*args, **kws) def set_state(self, val): return self.scandb.set_info('qxafs_running', val) def get_state(self): return int(self.scandb.get_info(key='qxafs_running', default=0)) def mainloop(self): while True: if 1 == self.get_state(): self.monitor_qxafs() time.sleep(1.0) self.heartbeat_pv.put("%i"%int(time.time()))
class QXAFS_ScanWatcher(object): def __init__(self, verbose=False, pidfile=None, heartbeat_pvname=None, pulsecount_pvname=None, **kws): self.verbose = verbose self.scandb = ScanDB() try: self.set_state(0) except: raise RuntimeError("Cannot connect to ScanDB") self.state = 0 self.last = self.pulse = -1 self.last_move_time = 0 self.config = None self.dead_time = 0.5 self.id_lookahead = 2 self.with_id = False self.counters = [] self.pidfile = pidfile or DEFAULT_PIDFILE self.pulsecount_pv = None self.heartbeat_pv = None if pulsecount_pvname is not None: self.pulsecount_pv = PV(pulsecount_pvname) if heartbeat_pvname is not None: self.heartbeat_pv = PV(heartbeat_pvname) self.connected = False self.connect() def connect(self): self.config = json.loads(self.scandb.get_config('qxafs').notes) self.with_id = ('id_array_pv' in self.config and 'id_drive_pv' in self.config) pulse_channel = "%sCurrentChannel" % self.config['mcs_prefix'] self.pulse_pv = PV(pulse_channel, callback=self.onPulse) if self.with_id: self.idarray_pv = PV(self.config['id_array_pv']) self.iddrive_pv = PV(self.config['id_drive_pv']) self.idbusy_pv = PV(self.config['id_busy_pv']) pvroot = self.config['id_busy_pv'].replace('Busy', '') self.idstop_pv = PV("%sStop" % pvroot) self.idgapsym_pv = PV('%sGapSymmetry' % pvroot) self.idtaper_pv = PV('%sTaperEnergy' % pvroot) self.idtaperset_pv = PV('%sTaperEnergySet' % pvroot) self.xps = NewportXPS(self.config['host']) time.sleep(0.1) self.connected = True def qxafs_connect_counters(self): self.counters = [] time.sleep(0.1) pvs = [] for c in self.scandb.get_scandata(): pv = get_pv(c.pvname) pvs.append((c.name, pv)) time.sleep(0.1) for cname, pv in pvs: pv.connect() self.counters.append((cname, pv)) if self.verbose: self.write("QXAFS_connect_counters %i counters" % (len(self.counters))) def qxafs_finish(self): nidarr = len(self.idarray) # self.idarray_pv.put(np.zeros(nidarr)) self.set_state(0) self.dtime = 0.0 self.last, self.pulse = 0, 0 self.last_move_time = 0 self.counters = [] def onPulse(self, pvname, value=0, **kws): self.pulse = value def monitor_qxafs(self): msg_counter = 0 last_pulse = 0 self.pulse = 0 self.last_move_time = 0 if self.with_id: self.idarray = self.idarray_pv.get() else: self.idarray = np.zeros(1) self.dtime = float(self.scandb.get_info(key='qxafs_dwelltime', default=0.5)) if self.verbose: self.write("Monitor QXAFS begin %i ID Points" % len(self.idarray)) self.qxafs_connect_counters() while True: if self.get_state() == 0: print("Break : state=0") break npts = int(self.scandb.get_info(key='scan_total_points', default=0)) if self.scandb.get_info(key='request_abort', as_bool=True): self.write("QXAFS scan aborted") self.xps.abort_group() time.sleep(1.0) self.qxafs_finish() break time.sleep(0.05) now = time.time() # look for and prevent out-of-ordinary values for Taper (50 eV) # or for Gap Symmetry if self.with_id: gapsym = self.idgapsym_pv.get() taper = self.idtaper_pv.get() if abs(gapsym) > 0.050 or abs(taper) > 0.050: self.idtaperset_pv.put(0, wait=True) time.sleep(0.250) val = self.idarray[last_pulse + self.id_lookahead] try: self.iddrive_pv.put(val, wait=True, timeout=5.0) except CASeverityException: pass time.sleep(0.250) if self.pulse > last_pulse: if self.pulsecount_pv is not None: self.pulsecount_pv.put("%i" % self.pulse) self.scandb.set_info('scan_current_point', self.pulse) if self.heartbeat_pv is not None: self.heartbeat_pv.put("%i" % int(time.time())) # if the ID has been moving for more than 0.75 sec, stop it if self.with_id: if ((self.pulse > 2) and (self.idbusy_pv.get() == 1) and (now > self.last_move_time + 0.75)): self.idstop_pv.put(1) time.sleep(0.1) val = self.idarray[self.pulse + self.id_lookahead] if self.verbose and self.pulse % 25 == 0: self.write("QXAFS: %d/%d ID Energy=%.3f " % (self.pulse, npts, val)) if ((self.idbusy_pv.get() == 0) and (now > self.last_move_time + self.dead_time) and (val > MIN_ID_ENERGY) and (val < MAX_ID_ENERGY)): try: self.iddrive_pv.put(val, wait=False) except CASeverityException: pass time.sleep(0.1) self.last_move_time = time.time() else: if self.verbose and self.pulse % 25 == 0: self.write("QXAFS: %d/%d " % (self.pulse, npts)) last_pulse = self.pulse cpt = int(self.pulse) time_left = (npts-cpt)*self.dtime self.scandb.set_info('scan_time_estimate', time_left) time_est = hms(time_left) msg = 'Point %i/%i, time left: %s' % (cpt, npts, time_est) if cpt >= msg_counter: self.scandb.set_info('scan_progress', msg) self.scandb.set_info('heartbeat', tstamp()) msg_counter += 1 for name, pv in self.counters: try: value = pv.get() if pv.nelm > 1: self.scandb.set_scandata(name, value) else: self.scandb.append_scandata(name, value) except: self.write( "Could not set scandata for %s: %i, %s" % (name, pv)) self.scandb.commit() if self.pulsecount_pv is not None: self.pulsecount_pv.put("%i" % self.pulse) self.scandb.set_info('scan_current_point', self.pulse) self.write("Monitor QXAFS scan complete, finishing") last_pulse = self.pulse = 0 self.qxafs_finish() def set_state(self, val): return self.scandb.set_info('qxafs_running', val) def get_state(self): val = self.scandb.get_info(key='qxafs_running', default=0) return int(val) def get_lastupdate(self): if self.heartbeat_pv is not None: return int(self.heartbeat_pv.get(as_string=True)) return -1 def kill_old_process(self): print("kill old ", self.heartbeat_pv) if self.heartbeat_pv is not None: self.heartbeat_pv.put("-1") pid = None with open(self.pidfile) as fh: pid = int(fh.readlines()[0][:-1]) if pid is not None: self.write('killing pid=', pid, ' at ', time.ctime()) os.system("kill -9 %d" % pid) time.sleep(1.0) def save_pid(self): with open(self.pidfile, 'w') as fh: fh.write("%d\n" % os.getpid() ) fh.close() def write(self, msg): sys.stdout.write("%s\n" % msg) sys.stdout.flush() def mainloop(self): if not self.connected: self.connect() self.save_pid() self.qxafs_connect_counters() while True: state = self.get_state() if 2 == int(state): self.monitor_qxafs() else: if self.scandb.get_info(key='request_abort', as_bool=True): self.xps.abort_group() time.sleep(1.0) time.sleep(1.0) if self.heartbeat_pv is not None: self.heartbeat_pv.put("%i"%int(time.time())) self.write("QXAFS monitor mainloop done ")