""" Line/vector/area/holo scan of multiple spectral regions save this script into your script/user folder before editing! usage: 1. uncomment one of the MOTORS lines. add another line if necessary. 2. uncomment one of the scan blocks and adjust the parameters. add another block if necessary. 3. declare the regions. 4. add the regions to the REGIONS list. 5. run the script. revisions 230912 DFS30 analyser with peakAnalyser EPICS layer """ # dummy scan (time series) #MOTORS = [dummy] # photon energy scan (do not include 'ephot' in regions in this case!) #MOTORS = [Eph] # phi scan #MOTORS = [ManipulatorPhi] # holo scan MOTORS = (ManipulatorPhi, ManipulatorTheta) # 2D YZ scan #MOTORS = [ManipulatorY, ManipulatorZ] # line scan [start, stop, step] #POSITIONS = [0., 5., 0.5] #SCAN = 'lscan' # vector scan [pos1, pos2, pos3, ...] #POSITIONS = [200., 300., 400., 500.] #SCAN = 'vscan' # area scan [(start1, start2), (stop1, stop2), (step1, step2)] # corresponding to (positioner1, positioner2) #POSITIONS = [(-1., 114.), (+1., 116.), (20, 20)] #ZIGZAG = True #SCAN = 'ascan' # holo scan PHI_RANGE = (-45, 45) # (tuple (min, max)) THETA_RANGE = (-11.0, 55.0) # (tuple (min, max)) STEPS = (15.0, 1) # (tuple (phi, theta)) ZIGZAG = True POSITIONS = [(PHI_RANGE[0], THETA_RANGE[0]), (PHI_RANGE[1], THETA_RANGE[1]), STEPS] SCAN = 'ascan' # seconds to wait between positioning command and triggering the detector LATENCY = 0.0 # region setup # # for each region, define a python dictionary with the following items. # optional items can be left unspecified and will default to the indicated values. # for swept mode, include 'elo', 'ehi', 'estep', 'iter' values, but do not include 'efix'. # for fixed mode, include 'efix' value, but do not include 'elo', 'ehi', 'estep', 'iter'. # # 'name': user-specific name of the region (for graph title and RegionName attribute in data file) # 'elo': lower kinetic energy boundary of the spectrum # 'ehi': upper kinetic energy boundary of the spectrum # 'estep': energy step size # 'efix': center kinetic energy in fixed mode # 'epass': pass energy # 'ephot': photon energy (default: unchanged) # 'tstep': dwell time in seconds # 'iter': number of iterations/sweeps (default 1) # 'cis': True = constant initial state (photoemission line), False = constant final state (Auger peak), (default False) # 'slit': exit slit (default: unchanged) REGION1 = {'name': 'Peak 1', 'elo': 164.50, 'ehi': 166.20, 'estep': 0.05, 'epass': 50., 'tstep': 0.12, 'iter': 1} REGION2 = {'name': 'multiplet 1', 'elo': 167.50, 'ehi': 171.01, 'estep': 0.03, 'epass': 50., 'tstep': 0.12, 'iter': 1} REGION3 = {'name': 'multiplet 2', 'elo': 173.5, 'ehi': 176.8, 'estep': 0.03, 'epass': 50., 'tstep': 0.12, 'iter': 1} # list of region dictionaries to execute at each scan position REGIONS = [REGION1, REGION2, REGION3] # close beam shutter and turn off analyser at the end of the scan CLOSE_SHUTTER_AT_END = True # --- DO NOT EDIT BELOW THIS LINE! --- set_exec_pars(keep=False) set_exec_pars(compression=True) def check_region(region): """ check region dictionary items and apply defaults where necessary """ region['fixed'] = 'efix' in region if region['fixed']: region['elo'] = region['efix'] region['ehi'] = region['efix'] if 'iter' not in region: region['iter'] = 1 print("region {0}: setting default iter = {1}".format(region['name'], region['iter'])) if 'cis' not in region: region['cis'] = False print("region {0}: setting default cis = {1}".format(region['name'], region['cis'])) class SpectrumReader(ReadonlyRegisterBase, ReadonlyRegisterArray): """ pseudo-device class to acquire and read out a Scienta spectrum per region. this devices starts the spectrum acquisition and organises the data file. """ def initialize(self): #super(SpectrumReader, self).initialize() self.scan_index = -1 def create_datasets(self): path = get_exec_pars().scanPath + self.region_name + "/" self.channel_begin_dataset_name = path + "ScientaChannelBegin" self.channel_end_dataset_name = path + "ScientaChannelEnd" create_dataset(self.channel_begin_dataset_name, 'd') create_dataset(self.channel_end_dataset_name, 'd') if self.region['fixed']: self.channel_center_dataset_name = path + "ScientaChannelCenter" create_dataset(self.channel_center_dataset_name, 'd') else: self.step_energy_dataset_name = path + "ScientaStepEnergy" create_dataset(self.step_energy_dataset_name, 'd') if 'epass' in self.region: self.pass_energy_dataset_name = path + "ScientaPassEnergy" create_dataset(self.pass_energy_dataset_name, 'd') if 'tstep' in self.region: self.step_time_dataset_name = path + "ScientaStepTime" create_dataset(self.step_time_dataset_name, 'd') if 'iter' in self.region: self.iterations_dataset_name = path + "ScientaIterations" create_dataset(self.iterations_dataset_name, 'd') if 'slit' in self.region: self.slit_dataset_name = path + "ExitSlit" create_dataset(self.slit_dataset_name, 'd') def setup(self): # print("spectrum.setup") if self.scan_index != get_exec_pars().index: self.scan_index = get_exec_pars().index self.create_datasets() print "scan {0}, region {1} ({2})".format(self.scan_index, self.region_index, self.region['name']) edelta = 0.0 try: ephot = self.region['ephot'] Eph.move(ephot) except KeyError: ephot = Eph.take(100) if isinstance(ephot, float) and ephot > 0.: try: if self.region['cis']: edelta = ephot - self.ephot_start except AttributeError: self.ephot_start = ephot elo = self.region['elo'] + edelta ehi = self.region['ehi'] + edelta if self.region['fixed']: Scienta.setAcquisitionMode("Fixed") Scienta.centerEnergy.write(elo) append_dataset(self.channel_center_dataset_name, elo) else: Scienta.setAcquisitionMode("Sweep Energy") Scienta.lowEnergy.write(elo) Scienta.highEnergy.write(ehi) Scienta.stepSize.write(self.region['estep']) append_dataset(self.step_energy_dataset_name, self.region['estep']) try: Scienta.setPassEnergy(int(self.region['epass'])) append_dataset(self.pass_energy_dataset_name, self.region['epass']) except KeyError: pass try: Scienta.stepTime.write(self.region['tstep']) append_dataset(self.step_time_dataset_name, self.region['tstep']) except KeyError: pass try: Scienta.setIterations(self.region['iter']) append_dataset(self.iterations_dataset_name, self.region['iter']) except KeyError: pass try: ExitSlit.write(self.region['slit']) append_dataset(self.slit_dataset_name, self.region['slit']) time.sleep(0.5) ExitSlitY.waitReady(5000) except KeyError: pass Scienta.update() def read(self): # print("spectrum.read") global current_region_index current_region_index = self.region_index self.setup() # print("Acquiring region {0}.".format(self.region['name'])) trig_scienta() time.sleep(0.1) sp = Scienta.getSpectrum().read() append_dataset(self.channel_begin_dataset_name, Scienta.getChannelBegin().getValue()) append_dataset(self.channel_end_dataset_name, Scienta.getChannelEnd().getValue()) return sp def getSize(self): # this is called before the scan starts - we have to predict the spectrum size # wrong values don't seem to affect the data files, however if self.region['fixed']: nx = 1066 else: nx = int((self.region['ehi'] - self.region['elo']) / self.region['estep']) + 1 return nx class ImageReader(ReadonlyRegisterBase, ReadonlyRegisterMatrix): """ pseudo-device class to read out the Scienta image per region. this device just reads out the Scienta image that has been acquired by SpectrumReader. """ def read(self): # print("image.read") return Scienta.getDataMatrix().read() def getWidth(self): # this is called before the scan starts - we have to predict the spectrum size # wrong values don't seem to affect the data files, however if self.region['fixed']: nx = 1066 else: nx = int((self.region['ehi'] - self.region['elo']) / self.region['estep']) + 1 return nx def getHeight(self): # this is called before the scan starts - the number of slices is an independent parameter ny = Scienta.slices.read() return ny class SimpleDeviceReader(Readable): """ pseudo-device class to read out another device once per region. the device must be set assigned to the source attribute. """ def read(self): return self.source.read() def setup_live_plots(regions): global live_plots global current_region_index names = [region['name'] for region in regions] live_plots = plot(None, names, title="Live Spectra") current_region_index = 0 def update_live_plots(): global live_plots global current_region_index try: while get_context().state.running: y = Scienta.spectrum.take(100) x = Scienta.spectrumX try: series = live_plots[current_region_index].getSeries(0) series.setData(x, y) except IndexError: pass time.sleep(1.0) finally: print "Stopping live spectra" def do_scan(scan, motors, positions, regions, latency): """ set up detectors and run the scan for each region we have to add a SpectrumReader and an ImageReader pseudo-device to the SENSORS list. the order SpectrumReader, ImageReader is important because the SpectrumReader triggers the Scienta, whereafter the ImageReader reads the image. """ global SENSORS SENSORS = [] for (index, region) in enumerate(regions): check_region(region) reader = SpectrumReader() reader.region_index = index reader.region_name = "region{0}".format(index + 1) reader.region = region reader.initialize() set_device_alias(reader, reader.region_name + "/ScientaSpectrum") SENSORS.append(reader) image = ImageReader() image.region_index = index image.region = region image.initialize() set_device_alias(image, reader.region_name + "/ScientaImage") SENSORS.append(image) dev = SimpleDeviceReader() dev.source = SampleCurrent set_device_alias(dev, reader.region_name + "/SampleCurrent") SENSORS.append(dev) dev = SimpleDeviceReader() dev.source = RefCurrent set_device_alias(dev, reader.region_name + "/RefCurrent") SENSORS.append(dev) adjust_sensors() set_adc_averaging() if scan == 'ascan': ascan(motors, SENSORS, positions[0], positions[1], positions[2], latency, False, zigzag = True, before_read=wait_beam, after_read = after_readout) elif scan == 'lscan': lscan(motors, SENSORS, positions[0], positions[1], positions[2], latency, False, before_read=wait_beam, after_read = after_readout) elif scan == 'vscan': vscan(motors, SENSORS, positions, True, latency,False, before_read=wait_beam, after_read = after_readout) else: print('unknown scan mode {}'.format(scan)) for (index, region) in enumerate(regions): set_attribute(get_exec_pars().scanPath + "region{0}/ScientaSpectrum".format(index + 1), "RegionName", region['name']) set_attribute(get_exec_pars().scanPath + "region{0}/ScientaImage".format(index + 1), "RegionName", region['name']) set_attribute(get_exec_pars().scanPath, "Regions", [region['name'] for region in regions]) try: setup_live_plots(REGIONS) task = fork(update_live_plots) do_scan(SCAN, MOTORS, POSITIONS, REGIONS, LATENCY) finally: if CLOSE_SHUTTER_AT_END: after_scan()