def to_xdi(self, filename=None): '''Write an XDI-style file with bin energy in the first column and the waveform of each of the 4 channels in the other columns. ''' dcm, BMMuser, ring = user_ns['dcm'], user_ns['BMMuser'], user_ns[ 'ring'] column_list = ['MCA1', 'MCA2', 'MCA3', 'MCA4'] column_list = [ f'MCA{channel_number}' for channel_number in self.channel_numbers ] m2state, m3state = mirror_state() handle = open(filename, 'w') handle.write('# XDI/1.0 BlueSky/%s\n' % bluesky_version) #handle.write('# Scan.uid: %s\n' % dataframe['start']['uid']) #handle.write('# Scan.transient_id: %d\n' % dataframe['start']['scan_id']) handle.write( '# Beamline.name: BMM (06BM) -- Beamline for Materials Measurement' ) handle.write('# Beamline.xray_source: NSLS-II three-pole wiggler\n') handle.write( '# Beamline.collimation: paraboloid mirror, 5 nm Rh on 30 nm Pt\n') handle.write('# Beamline.focusing: %s\n' % m2state) handle.write('# Beamline.harmonic_rejection: %s\n' % m3state) handle.write('# Beamline.energy: %.3f\n' % dcm.energy.position) handle.write( '# Detector.fluorescence: SII Vortex ME4 (4-element silicon drift)\n' ) handle.write('# Scan.end_time: %s\n' % now()) handle.write('# Scan.dwell_time: %.2f\n' % self.cam.acquire_time.value) handle.write('# Facility.name: NSLS-II\n') handle.write('# Facility.current: %.1f mA\n' % ring.current.value) handle.write('# Facility.mode: %s\n' % ring.mode.value) handle.write('# Facility.cycle: %s\n' % BMMuser.cycle) handle.write('# Facility.GUP: %d\n' % BMMuser.gup) handle.write('# Facility.SAF: %d\n' % BMMuser.saf) handle.write('# Column.1: energy (eV)\n') for c, mca_number in enumerate(column_list): handle.write(f'# Column.{c+2}: MCA{mca_number} (counts)\n') handle.write( '# ==========================================================\n') handle.write('# energy ') ## data table e = numpy.arange(0, len( self.channels.channel01.mca.array_data.get())) * 10 mca_data_array_list = [ channel.mca.array_data.get() for channel in self.iterate_channels() ] a = numpy.vstack(mca_data_array_list) b = pandas.DataFrame(a.transpose(), index=e, columns=column_list) handle.write(b.to_csv(sep=' ')) handle.flush() handle.close() print(bold_msg('wrote XRF spectra to %s' % filename))
def to_xdi(self, filename=None): '''Write an XDI-style file with bin energy in the first column and the waveform of the measurement channel in the second column. ''' dcm, BMMuser, ring = user_ns['dcm'], user_ns['BMMuser'], user_ns[ 'ring'] column_list = ['MCA8'] #template = " %.3f %.6f %.6f %.6f %.6f\n" m2state, m3state = mirror_state() handle = open(filename, 'w') handle.write('# XDI/1.0 BlueSky/%s\n' % bluesky_version) #handle.write('# Scan.uid: %s\n' % dataframe['start']['uid']) #handle.write('# Scan.transient_id: %d\n' % dataframe['start']['scan_id']) handle.write( '# Beamline.name: BMM (06BM) -- Beamline for Materials Measurement' ) handle.write('# Beamline.xray_source: NSLS-II three-pole wiggler\n') handle.write( '# Beamline.collimation: paraboloid mirror, 5 nm Rh on 30 nm Pt\n') handle.write('# Beamline.focusing: %s\n' % m2state) handle.write('# Beamline.harmonic_rejection: %s\n' % m3state) handle.write('# Beamline.energy: %.3f\n' % dcm.energy.position) handle.write( '# Detector.fluorescence: SII Vortex ME4 (4-element silicon drift)\n' ) handle.write('# Scan.end_time: %s\n' % now()) handle.write('# Scan.dwell_time: %.2f\n' % self.settings.acquire_time.value) handle.write('# Facility.name: NSLS-II\n') handle.write('# Facility.current: %.1f mA\n' % ring.current.value) handle.write('# Facility.mode: %s\n' % ring.mode.value) handle.write('# Facility.cycle: %s\n' % BMMuser.cycle) handle.write('# Facility.GUP: %d\n' % BMMuser.gup) handle.write('# Facility.SAF: %d\n' % BMMuser.saf) handle.write('# Column.1: energy (eV)\n') handle.write('# Column.2: MCA1 (counts)\n') handle.write( '# ==========================================================\n') handle.write('# energy ') ## data table e = numpy.arange(0, len(self.mca1.value)) * 10 a = numpy.vstack([ self.mca1.value, self.mca2.value, self.mca3.value, self.mca4.value ]) b = pd.DataFrame(a.transpose(), index=e, columns=column_list) handle.write(b.to_csv(sep=' ')) handle.flush() handle.close() print(bold_msg('wrote XRF spectra to %s' % filename))
def xrd_webcam(filename=None, **kwargs): XRDURL = 'http://xf06bm-cam6/axis-cgi/jpg/image.cgi' CAM_PROXIES = { "http": None, "https": None, } if filename is None: filename = os.environ['HOME'] + '/XRD_camera_' + now() + '.jpg' r = requests.get(XRDURL, proxies=CAM_PROXIES) Image.open(BytesIO(r.content)).save(filename, 'JPEG') if 'annotation' in kwargs: annotate_image(filename, kwargs['annotation']) report('XRD webcam image written to %s' % filename)
def analog_camera(filename=None, sample=None, folder=os.environ['HOME'], device='/dev/video0', camera=0, skip=30, frames=5, brightness=30, x=320, y=240, linecolor='white', nocrosshair=True, quiet=False, reset=False, usbid='534d:0021', title='NIST BMM (NSLS-II 06BM)', timestamp='%Y-%m-%d %H:%M:%S'): """A function for interacting with fswebcam in a way that meets the needs of 06BM. Parameters ---------- folder : str location to drop jpg image [$HOME] device : str char device of camera [/dev/video0] should be set to something in /dev/v4l/by-id/ camera : int camera number[0] skip : int number of frames to skip waiting for camera to wake up [30] frames : int number of frames to accumulate in image [5] brightness : int brightness setting of camera as a percentage [30] x : int middle of image, in pixels, X-location of cross hair [320] y : int middle of image, in pixels, Y-location of cross hair [240] linecolor : str color of cross hair lines [white] nocrosshair : bool flag to suppress cross hair [True] quiet : bool flag to suppress screen messages [False] usbid : str vendor and product ID of camera of AV to USB device at 06BM [534d:0021] title : str title string for fswebcam banner [NIST BMM (NSLS-II 06BM)] filename : str output file name """ USBDEVFS_RESET = 21780 if reset is True: if not quiet: print("resetting video device") try: lsusb_out = Popen("lsusb | grep -i %s" % usbid, shell=True, bufsize=64, stdin=PIPE, stdout=PIPE, close_fds=True).stdout.read().strip().split() bus = lsusb_out[1].decode('UTF-8') device = lsusb_out[3][:-1].decode('UTF-8') print("/dev/bus/usb/%s/%s" % (bus, device)) f = open("/dev/bus/usb/%s/%s" % (bus, device), 'w', os.O_WRONLY) fcntl.ioctl(f, USBDEVFS_RESET, 0) sleep(1) except Exception as msg: print("failed to reset device:", msg) quiet = '' if quiet: quiet = '-q ' if filename is None: filename = folder + '/analog_camera_' + now() + '.jpg' if sample is not None and sample != '': title = title + ' - ' + sample if user_ns['BMMuser'].host == 'xf06bm-ws1': command = [ 'fswebcam', quiet, '-i', f'{camera}', '-d', device, '-r', f'{x}x{y}', '--title', title, '--timestamp', timestamp, '-S', f'{skip}', '-F', f'{frames}', '--set', f'brightness={brightness}%', filename ] else: command = [ 'ssh', 'xf06bm@xf06bm-ws1', f"fswebcam {quiet}-i {camera} -d {device} -r {x}x{y} --title '{title}' --timestamp '{timestamp}' -S {skip} -F {frames} --set brightness={brightness}% '{filename}'" ] run(command) #command = f"fswebcam {quiet}-i {camera} -d {device} -r {x}x{y} --title '{title}' --timestamp '{timestamp}' -S {skip} -F {frames} --set brightness={brightness}% '{filename}'" #system(command) #command = f"fswebcam {quiet}-i {camera} -d {device} -r {x}x{y} --title '{title}' --timestamp '{timestamp}' -S {skip} -F {frames} --set brightness={brightness}% '{filename}'" #system(f'ssh xf06bm@xf06bm-ws1 "{command}"') report('Analog camera image written to %s' % filename)
def _capture(self, status, i): "This runs on a background thread." try: if not self._acquiring_lock.acquire(timeout=0): raise RuntimeError("Cannot trigger, currently trigggering!") filename = os.path.join(self._root, self._rel_path_template % i) # Kick off requests, or subprocess, or whatever with the result # that a file is saved at `filename`. if self._SPEC == "BMM_XAS_WEBCAM" or self._SPEC == "BMM_XRD_WEBCAM": CAM_PROXIES = { "http": None, "https": None, } r = requests.get(self._url, proxies=CAM_PROXIES) im = Image.open(BytesIO(r.content)) im.save(filename, 'JPEG') #print(f'w: {im.width} h: {im.height}') self.image.shape = (im.height, im.width, 3) annotation = 'NIST BMM (NSLS-II 06BM) ' + self._annotation_string + ' ' + now( ) annotate_image(filename, annotation) else: analog_camera(device=self.device, x=self.x, y=self.y, brightness=self.brightness, filename=filename, sample=self._annotation_string, folder=self._root, quiet=True) self.image.shape = (self.y, self.x, 3) self._annotation_string = '' datum = self._datum_factory({"index": i}) self._asset_docs_cache.append(('datum', datum)) self.image.set(datum["datum_id"]).wait() except Exception as exc: status.set_exception(exc) else: status.set_finished() finally: self._acquiring_lock.release()
def energystep(filename = None, start = None, end = None, nsteps = None, delay = 5, dosteps = True): '''A simple energy scan, just step forward in energy and don't measure anything. This is a quick hack for use with a crude resonant reflectivity experiment with IBM folks. filename: name of file, will be appended to DATA for the full path (required) start: starting energy value (required) end: ending energy value (required) nsteps: number of energy steps (required) delay: pause between energy steps, in seconds [5] dosteps: False to see energy values printed to screen without moving mono [True] Writes a data file with columns of energy readback, energy requested, time of epoch, and ISO 8601 timestamp Example: energystep(filename='blahblah', start=18936, end=19036, nsteps=101) ''' BMMuser, dcm = user_ns['BMMuser'], user_ns['dcm'] BMM_log_info("energystep(filename=%s, start=%.1f, end=%.1f, nsteps=%d, delay=%.1f, dosteps=%s)" % (filename, start, end, nsteps, delay, str(dosteps))) datafile = BMMuser.DATA + filename handle = open(datafile, 'w') handle.write('# energy steps from %.1f to %.1f in %d steps\n' % (start, end, nsteps)) handle.write('#----------------------------------------------------\n') handle.write('# energy requested epoch iso8601\n') handle.flush() if dosteps: yield from mv(dcm.energy, start) print(' %.1f %.1f %.6f %s' % (dcm.energy.readback.get(), start, time.time(), now())) handle.write(' %.1f %.1f %.6f %s\n' % (dcm.energy.readback.get(), start, time.time(), now())) handle.flush() yield from sleep(delay) energy = start estep = (end-start) / nsteps while energy <= end: if dosteps: yield from mvr(dcm.energy, estep) print(' %.1f %.1f %.6f %s' % (dcm.energy.readback.get(), energy, time.time(), now())) handle.write(' %.1f %.1f %.6f %s\n' % (dcm.energy.readback.get(), energy, time.time(), now())) handle.flush() energy = energy + estep yield from sleep(delay) handle.flush() handle.close()
def analog_camera(filename=None, sample=None, folder=os.environ['HOME'], device='/dev/video0', camera=0, skip=30, frames=5, brightness=20, x=320, y=240, linecolor='white', nocrosshair=True, quiet=False, reset=False, usbid='534d:0021', title='NIST BMM (NSLS-II 06BM)', timestamp='%Y-%m-%d %H:%M:%S'): """A function for interacting with fswebcam in a way that meets the needs of 06BM. Parameters: folder: location to drop jpg image [$HOME] device: char device of camera [/dev/video0] camera: camera number [0] skip: number of frames to skip waiting for camera to wake up [30] frames: number of frames to accumulate in image [5] brightness: brightness setting of camera as a percentage [20] x: X-location of cross hair [320] (middle of image) y: Y-location of cross hair [240] (middle of image) linecolor: color of cross hair lines [white] nocrosshair: flag to suppress cross hair [True] quiet: flag to suppress screen messages [False] usbid: vendor and product ID of camera [534d:0021] (AV to USB device at 06BM) title: title string for fswebcam banner [NIST BMM (NSLS-II 06BM)] filename: output file name [ISO 8601 timestamp in folder] """ USBDEVFS_RESET = 21780 if reset is True: if not quiet: print("resetting video device") try: lsusb_out = Popen("lsusb | grep -i %s" % usbid, shell=True, bufsize=64, stdin=PIPE, stdout=PIPE, close_fds=True).stdout.read().strip().split() bus = lsusb_out[1].decode('UTF-8') device = lsusb_out[3][:-1].decode('UTF-8') print("/dev/bus/usb/%s/%s" % (bus, device)) f = open("/dev/bus/usb/%s/%s" % (bus, device), 'w', os.O_WRONLY) fcntl.ioctl(f, USBDEVFS_RESET, 0) sleep(1) except Exception as msg: print("failed to reset device:", msg) quiet = '' if quiet: quiet = '-q ' if filename is None: filename = folder + '/analog_camera_' + now() + '.jpg' if sample is not None: title = title + ' - ' + sample command = "fswebcam %s-i %s -d %s -r 640x480 --title \"%s\" --timestamp \"%s\" -S %d -F %d --set brightness=%s%% \"%s\"" %\ (quiet, camera, device, title, timestamp, skip, frames, brightness, filename) system(command) report('Analog camera image written to %s' % filename)
def main_plan(detector, slow, startslow, stopslow, nslow, fast, startfast, stopfast, nfast, pluck, force, dwell, md): (ok, text) = BMM_clear_to_start() if force is False and ok is False: print(error_msg(text)) BMMuser.final_log_entry = False yield from null() return user_ns['RE'].msg_hook = None ## sanity checks on slow axis if type(slow) is str: slow = slow.lower() if slow not in motor_nicknames.keys() and 'EpicsMotor' not in str( type(slow)) and 'PseudoSingle' not in str(type(slow)): print( error_msg('\n*** %s is not an areascan motor (%s)\n' % (slow, str.join(', ', motor_nicknames.keys())))) BMMuser.final_log_entry = False yield from null() return if slow in motor_nicknames.keys(): slow = motor_nicknames[slow] ## sanity checks on fast axis if type(fast) is str: fast = fast.lower() if fast not in motor_nicknames.keys() and 'EpicsMotor' not in str( type(fast)) and 'PseudoSingle' not in str(type(fast)): print( error_msg('\n*** %s is not an areascan motor (%s)\n' % (fast, str.join(', ', motor_nicknames.keys())))) BMMuser.final_log_entry = False yield from null() return if fast in motor_nicknames.keys(): fast = motor_nicknames[fast] detector = detector.capitalize() yield from mv(_locked_dwell_time, dwell) dets = [ quadem1, ] if with_xspress3 and detector == 'If': detector = 'Xs' if detector == 'If': dets.append(vor) detector = 'ROI1' if detector.lower() == 'xs': dets.append(xs) detector = BMMuser.xs1 yield from mv(xs.total_points, nslow * nfast) if 'PseudoSingle' in str(type(slow)): valueslow = slow.readback.get() else: valueslow = slow.user_readback.get() line1 = 'slow motor: %s, %.3f, %.3f, %d -- starting at %.3f\n' % \ (slow.name, startslow, stopslow, nslow, valueslow) if 'PseudoSingle' in str(type(fast)): valuefast = fast.readback.get() else: valuefast = fast.user_readback.get() line2 = 'fast motor: %s, %.3f, %.3f, %d -- starting at %.3f\n' % \ (fast.name, startfast, stopfast, nfast, valuefast) npoints = nfast * nslow estimate = int(npoints * (dwell + 0.7)) # extent = ( # valuefast + startfast, # valueslow + startslow, # valuefast + stopfast, # valueslow + stopslow, # ) # extent = ( # 0, # nfast-1, # 0, # nslow-1 # ) # print(extent) # return(yield from null()) # areaplot = LiveScatter(fast.name, slow.name, detector, # xlim=(startfast, stopfast), ylim=(startslow, stopslow)) close_all_plots() areaplot = LiveGrid( (nslow, nfast), detector, #aspect='equal', #aspect=float(nslow/nfast), extent=extent, xlabel='fast motor: %s' % fast.name, ylabel='slow motor: %s' % slow.name) #BMMuser.ax = areaplot.ax #BMMuser.fig = areaplot.ax.figure BMMuser.motor = fast BMMuser.motor2 = slow #BMMuser.fig.canvas.mpl_connect('close_event', handle_close) thismd = dict() thismd['XDI'] = dict() thismd['XDI']['Facility'] = dict() thismd['XDI']['Facility']['GUP'] = BMMuser.gup thismd['XDI']['Facility']['SAF'] = BMMuser.saf thismd['slow_motor'] = slow.name thismd['fast_motor'] = fast.name report( f'Starting areascan at x,y = {fast.position:.3f}, {slow.position:.3f}', level='bold', slack=True) ## engage suspenders right before starting scan sequence if force is False: BMM_suspenders() @subs_decorator(areaplot) #@subs_decorator(src.callback) def make_areascan(dets, slow, startslow, stopslow, nslow, fast, startfast, stopfast, nfast, snake=False): BMMuser.final_log_entry = False uid = yield from grid_scan( dets, slow, startslow, stopslow, nslow, fast, startfast, stopfast, nfast, snake, md={ 'plan_name': f'grid_scan measurement {slow.name} {fast.name} {detector}' }) BMMuser.final_log_entry = True return uid rkvs.set('BMM:scan:type', 'area') rkvs.set('BMM:scan:starttime', str(datetime.datetime.timestamp(datetime.datetime.now()))) rkvs.set('BMM:scan:estimated', estimate) BMM_log_info('begin areascan observing: %s\n%s%s' % (detector, line1, line2)) uid = yield from make_areascan(dets, slow, valueslow + startslow, valueslow + stopslow, nslow, fast, valuefast + startfast, valuefast + stopfast, nfast, snake=False) if pluck is True: close_all_plots() thismap = user_ns['db'].v2[uid] x = numpy.array(thismap.primary.read()[fast.name]) y = numpy.array(thismap.primary.read()[slow.name]) z=numpy.array(thismap.primary.read()[BMMuser.xs1]) +\ numpy.array(thismap.primary.read()[BMMuser.xs2]) +\ numpy.array(thismap.primary.read()[BMMuser.xs3]) +\ numpy.array(thismap.primary.read()[BMMuser.xs4]) z = z.reshape(nfast, nslow) # grabbing the first nfast elements of x and every # nslow-th element of y is more reliable than # numpy.unique due to float &/or motor precision issues #plt.title(f'Energy = {energies["below"]}') plt.xlabel(f'fast axis ({fast.name}) position (mm)') plt.ylabel(f'slow axis ({slow.name}) position (mm)') plt.gca().invert_yaxis() # plot an xafs_x/xafs_y plot upright plt.contourf(x[:nfast], y[::nslow], z, cmap=plt.cm.viridis) plt.colorbar() plt.show() fname = os.path.join(BMMuser.folder, 'map-' + now() + '.png') plt.savefig(fname) try: img_to_slack(fname) except: post_to_slack('failed to post image: {fname}') pass BMMuser.x = None figs = list(map(plt.figure, plt.get_fignums())) canvas = figs[0].canvas action = input('\n' + bold_msg( 'Pluck motor position from the plot? [Y/n then Enter] ')) if action.lower() == 'n' or action.lower() == 'q': return (yield from null()) print( 'Single click the left mouse button on the plot to pluck a point...' ) cid = canvas.mpl_connect( 'button_press_event', interpret_click) # see 65-derivedplot.py and while BMMuser.x is None: # https://matplotlib.org/users/event_handling.html yield from sleep(0.5) # print('Converting plot coordinates to real coordinates...') # begin = valuefast + startfast # stepsize = (stopfast - startfast) / (nfast - 1) # pointfast = begin + stepsize * BMMuser.x # #print(BMMuser.x, pointfast) # begin = valueslow + startslow # stepsize = (stopslow - startslow) / (nslow - 1) # pointslow = begin + stepsize * BMMuser.y # #print(BMMuser.y, pointslow) # print('That translates to x=%.3f, y=%.3f' % (pointfast, pointslow)) yield from mv(fast, BMMuser.x, slow, BMMuser.y) report( f'Moved to position x,y = {fast.position:.3f}, {slow.position:.3f}', level='bold', slack=True)