From 541feeaf919ed263fab0cb84d0191b9ce1f5d184 Mon Sep 17 00:00:00 2001 From: "FR@29iduser" <rodolakis@anl.gov> Date: Mon, 12 Sep 2022 13:04:20 -0500 Subject: [PATCH] add octupole --- iexcode/instruments/IEX_BL_config.py | 10 +- iexcode/instruments/Octupole.py | 507 +++++++++++++++++++++++++++ iexcode/instruments/scalers.py | 14 + 3 files changed, 526 insertions(+), 5 deletions(-) create mode 100644 iexcode/instruments/Octupole.py diff --git a/iexcode/instruments/IEX_BL_config.py b/iexcode/instruments/IEX_BL_config.py index 7117b9d..07026ce 100644 --- a/iexcode/instruments/IEX_BL_config.py +++ b/iexcode/instruments/IEX_BL_config.py @@ -13,14 +13,14 @@ init kwargs to see which defaults you can change. """ #For new endstation modify here: -endstations_list = ['ARPES','Kappa'] +endstations_list = ['ARPES','kappa','Octupole'] class Beamline_Config: """ used for defining which endstation in which you are running for short names and ioc info BL = Endstation('ARPES') - BL.endstation_name: name of endstation ("ARPES" / "Kappa" / "Octupole") + BL.endstation_name: name of endstation ("ARPES" / "kappa" / "Octupole") BL.ioc: string of scan ioc ('29idb:', '29idTest:') BL.mda: scanRecord object of ioc specified by .ioc @@ -50,7 +50,7 @@ class Beamline_Config: BL.folder => 'b','c','d' BL.prefix => 'ARPES_','Kappa_' BL.ioc => previously: BL_ioc() - BL.Motors => motor calls + BL.Motors => motor calls#For new endstation modify here: BL.safe_state => function to put endstation in a 'safe state' BL.endstation_get => function to return endstation status BL.log => log class @@ -96,8 +96,8 @@ class Beamline_Config: self.folder = 'd' self.prefix = 'Kappa_' self.branch = 'd' - #elif endstation_name == 'Octupole': - #self.folder = 'e' + elif endstation_name == 'Octupole': + self.folder = 'd' self.branch = 'd' else: print('folder and prefix not set') diff --git a/iexcode/instruments/Octupole.py b/iexcode/instruments/Octupole.py new file mode 100644 index 0000000..6ff8d9b --- /dev/null +++ b/iexcode/instruments/Octupole.py @@ -0,0 +1,507 @@ +import numpy as np +from time import sleep +from math import floor + +from epics import caget, caput,PV + +import iexcode.instruments.cfg as iex +from iexcode.instruments.IEX_endstations import Endstation +from iexcode.instruments.cameras import _enable_endstation_cameras + +from iexcode.instruments.staff import staff_detector_dictionary +from iexcode.instruments.files_and_folders import check_run,make_user_folders,folder_mda +from iexcode.instruments.staff import staff_detector_dictionary +from iexcode.instruments.xrays import _xrays_detector_dictionary,_xrays_reset,xrays_get_all + +from iexcode.instruments.conversions_constants import * +from iexcode.instruments.utilities import * +from iexcode.instruments.userCalcs import userStringSeq_clear, userStringSeq_pvs, userCalcOut_clear + +from iexcode.instruments.Motors import Motors +from iexcode.instruments.current_amplifiers import SRS, ca_reset_all, Keithley_pv +from iexcode.instruments.valves import branch_valve_close +from iexcode.instruments.shutters import branch_shutter_close + +#branch specific +from iexcode.instruments.slits import slit3D_get +#endstation specific +from iexcode.instruments.scalers import scaler_cts +from iexcode.instruments.spec_stuff import folders_spec + +default_ioc = '29ide:' +############################################################################# +def Octupole_init(*userName,**kwargs): + """ + used to intialize the Endstation class which carries scanRecord, logging ... parameters + returns global detectors relavent to this endstation (tey,d3,d4,mesh,Kappa_scaler_pv,tth_pv,tthdet) + + *userName is an optional parameter, will be prompted if set_folders=True + + **kwargs: + set_folders: sets the mda and EA folders (default => True) + reset: to reset the detectors in the IOC, etc (default => True) + xrays: sets global variable and detectors for x-ray (default => True) + mode: used sets the detectors 'user ' / 'staff' (default => 'user' ) + """ + kwargs.setdefault('scan_ioc',default_ioc) + kwargs.setdefault('xrays',True) + kwargs.setdefault('mode','user') + kwargs.setdefault('set_folders',True) + kwargs.setdefault('reset',True) + + #motors + physical_motors = ['x','y','z','th','tth'] + pseudo_motors = [''] + global Octupole_Motors + Octupole_Motors = Motors('Octupole',_Octupole_motor_dictionary(),physical_motors,pseudo_motors) + + #endstation + iex.BL = Endstation('Kappa',kwargs['scan_ioc'],kwargs['xrays'],kwargs['mode'],Octupole_Motors) + + #setting folders + if kwargs['set_folders']: + if iex.BL.mode == 'staff': + user_name = 'staff' + else: + if len(userName)==0: + user_name = input('user name: ') + else: + user_name = userName[0] + print(user_name) + folders_Octupole(user_name,**kwargs) + + #update for default scanRecord advanced parameters + iex.BL.mda.log('Octupole',user_name,_Octupole_log_header(),_Octupole_log_entries) + + #global detectors + global tey,tfy,pd,mesh,diag,kbh,kbv, Octupole_scaler_pv + mesh = SRS("29ide:scaler1.S2", '29idd:A4') + diag = SRS("29ide:scaler1.S6", '29ide:SR570_1') + kbh = SRS("29ide:scaler1.S7", '29ide:SR570_2') + kbv = SRS("29ide:scaler1.S8", '29ide:SR570_3') + tey = SRS("29ide:scaler1.S3", '29ide:SR570_4') + tfy = Scaler("29ide:scaler1.S4") + pd = SRS("29idMZ0:scaler1.S5", '29ide:SR570_5') + Octupole_scaler_pv = '29ide:scaler1.CNT' + + #resetting everything + if kwargs['reset']: + Octupole_reset(**kwargs) + + print ('Octupole initalized') + #return any detectors or other parameters that you want access to from jupyter + return tey,tfy,pd,mesh,diag,kbh,kbv, Octupole_scaler_pv +############################################################################################################## +############################## detectors and motors ############################## +############################################################################################################## +def _Octupole_detector_list(): + """ + list of detectors to trigger + + Previously: part of Detector_List + """ + ca_list=[] + return ca_list + + +def _Octupole_detector_dictionary(**kwargs): + """ + returns a dictionary of the default detectors + + **kwargs + add_vortex: to specifiy to add the vortex detectors to the dictionary (True/False) + + Previously: Detector_Default + """ + kwargs.setdefault('add_vortex',False) + det_dict={} + vortex={ + 15:"", + 16:"", + 17:"", + } + sample_temp={ + 23:"29idd:LS340_1:TC1:SampleA", + } + m3r={ + 25:"29id_ps6:Stats1:CentroidX_RBV", + 26:"29id_ps6:Stats1:SigmaX_RBV", + 27:"29id_ps6:Stats1:CentroidTotal_RBV", + } + scalers={ + 31:"29ide:scaler1.S2", + 32:"29ide:scaler1.S3", + 33:"29ide:scaler1.S4", + 34:"29ide:scaler1.S5", + 35:"29ide:scaler1.S6", + 36:"29ide:scaler1_calc1.B", + 37:"29ide:scaler1_calc1.C", + 38:"29ide:scaler1_calc1.D", + 39:"29ide:scaler1_calc1.E", + 40:"29ide:scaler1.S7", + 41:"29ide:scaler1.S8", + } + motors={ + 51:"29ide:m11.RBV", + 52:"29ide:m12.RBV", + 53:"29ide:m13.RBV", + 54:"29ide:m14.RBV", + 55:"29ide:m15.RBV", + } + #hkl are listed just a place holders, they are filled in by thier scanning functions + det_dict.update(sample_temp) + det_dict.update(scalers) + det_dict.update(motors) + if kwargs['add_vortex']: + det_dict.update(vortex) + + #add detectors related to beamline + if iex.BL.xrays: + det_dict.update(_xrays_detector_dictionary()) + + return det_dict + + +def _Octupole_motor_dictionary(name): + """ + motor_dictionary = {name:[rbv,val,spmg,pv]} for physical and psuedo/Euler motors + usage: + KappaS_PVmotor('x') => ['29idKappa:m2.RBV', '29idKappa:m2.VAL', '29idKapp:m2.SPMG','29idKappa:m2'] + """ + motor_nums={ + 'x':11, + 'y':12, + 'z':13, + 'th':14, + 'tth':15, + } + motor_dictionary = {} + for name in motor_nums.keys(): + pv = '29ide:m'+str(motor_nums[name]) + motor_dictionary.update({name:[pv+'.VAL',pv+'.SPMG',pv]}) + + return motor_dictionary + +def Octupole_extra_pvs(): + """ + used to get the PV associated with a given pnuemonic + + """ + d={ + "TA":"29idd:LS340_1:TC1:Control", + } + return d + + + +############################################################################################################# +############################## setting folder ############################## +############################################################################################################## +def folders_Octupole(user_name,**kwargs): + """ + Create and sets (if create_only=False) all the folders the current run and ARPES user + Sets the FileName for logging to be "UserName/YYYYMMDD_log.txt using logname_Set()" + + **kwargs: + set_folders = True (default); set the mda and EA scanRecords + = False; only makes the folders (was create_only) + run: run cycle e.g. 2022_1 (default => check_run() ) + ftp = True / False (default); print what needs to be added to the ftps crontab and create additional ftp folders + mda_ioc: will overwrite the default ioc for mda scans + debug + """ + kwargs.setdefault('set_folders',False) + kwargs.setdefault('run',check_run()) + kwargs.setdefault('ftp',False) + kwargs.setdefault('debug',False) + + run = kwargs['run'] + + if kwargs['debug']: + print("run,folder,user_name,ioc,ftp: ",run,iex.BL.folder,user_name,iex.BL.ioc,kwargs['ftp']) + + # Create User Folder: + make_user_folders(run,iex.BL.folder,user_name,iex.BL.endstation,ftp=kwargs['ftp']) + sleep(5) + + if kwargs["set_folders"]: + # Set up MDA folder: + folder_mda(run,iex.BL.folder,user_name,iex.BL.prefix,iex.BL.ioc) + + #resetting + if 'reset': + Octupole_reset() + +def Octupole_reset(): + """ + resets scanRecord, current amplifiers, mono limits and lakeshore + """ + #writing default parameters to iex.BL.mda + if iex.BL.mode=='staff': + iex.BL.mda.detector_dictionary = staff_detector_dictionary() + else: + iex.BL.mda.detector_dictionary = _Octupole_detector_dictionary() + iex.BL.mda.trigger_dictionary = _Octupole_trigger_dictionary() + iex.BL.mda.scan_before_sequence = _Octupole_scan_before_sequence() + iex.BL.mda.scan_after_sequence = _Octupole_scan_after_sequence() + + #resetting the scanRecord + print("resetting the scanRecord - "+iex.BL.ioc) + iex.BL.mda.reset_all() + + #resetting the current amplifiers + if iex.BL.xray: + ca_reset_all() + + #resetting mono and anyother beamline stuff + if iex.BL.xrays: + _xrays_reset() + + #resetting mono and other beamline stuff + if iex.BL.xrays: + _xrays_reset() + + +############################################################################################################## +############################## get all ############################## +############################################################################################################## +def Octupole_get_all(verbose=True): + """ + returns a dictionary with the current status of the Kappa endstation and exit slit + """ + vals = {} + + #sample postion + motor_dictionary = _Octupole_motor_dictionary() + for motor in motor_dictionary.keys(): + vals[motor]=Octupole_Motors.get(motor,verbose=False) + + #endstation/branch pvs + extra_pvs = Octupole_extra_pvs() + for key in extra_pvs.keys(): + vals.update(key,caget(extra_pvs[key])) + if iex.BL.xrays: + vals.update('exit_slit',slit3D_get()) + + #beamline info + if iex.BL.xray: + beamline_info = xrays_get_all() + vals.update(beamline_info) + + mesh.get() + vals.update({'mesh':mesh.current}) + + if verbose: + print("-----------------------------------------------------------") + for key in vals: + print(key+" = "+vals[key]) + print("-----------------------------------------------------------") + return vals + +############################################################################################################## +############################## logging ############################## +############################################################################################################## +def _Octupole_log_header(): + """ + header for the log file + """ + h = "scan,motor,start,stop,step,x,y,z,th,tth,TA" + h += "hv,exit_slit,GRT,ID_SP,ID_RBV,ID_Mode,ID_QP,TEY,mesh,det_name,mpa_HV,m3r_centroid,time,comment" + header_list = {'Octupole':h} + return header_list + +def _Octupole_log_entries(): + """ + enstation info for log file + + Previously: scanlog + """ + vals = Kappa_get_all(verbose=False) + x = vals['x'] + y = vals['y'] + z = vals['z'] + th = vals['th'] + tth = vals['tth'] + + + TA = vals['TA'] + mesh.get() + tey_current = tey.current + mesh_current = mesh.current + + #m3r_centroid = vals['kphi'] ???? + + entry_list = ["x","y","z","tth","kth","kap","kphi","TA","TB","TEY","mesh","det_name","mpa_HV","m3r_centroid"] + pv_list = [ x, y, z, tth, kth, kap,kphi, TA, TB,tey_current,mesh_current,det_name,mpa_HV,m3r_centroid] + format_list = [".2f",".2f",".2f",".2f",".2f",".2f",".2f",".2f",".2f","1.2e","1.2e","s",".0f",".0f"] + + return entry_list,pv_list,format_list + +############################################################################################################## +############################## Octupole scanRecord ############################## +############################################################################################################## +def _Octupole_scan_before_sequence(scan_ioc,scan_dim,**kwargs): + """ + writes the user string sequence to happen at the beginning of a scan + returns before_scan_pv = pv for userStringSeq for before scan + + **kwargs + seq_num: userStringSeq number in ioc => 9 (default) + + Previously: BeforeScan_StrSeq + """ + kwargs.setdefault('seq_num',9) + seq_num=kwargs['seq_num'] + + before_scan_pv,before_scan_proc = userStringSeq_pvs(scan_ioc, seq_num) + + #clear and write the before scan user sequence + userStringSeq_clear(scan_ioc,seq_num) + caput(before_scan_pv+".DESC","Before Scan") + + #This is where you'd do something if need (CA -> 'Passive', etc) + pv='' + cmd='' + caput(before_scan_pv+".LNK" +str(1),pv) + caput(before_scan_pv+".STR" +str(1),cmd) + + return before_scan_proc + +def _Octupole_scan_after_sequence(scan_ioc,scan_dim,**kwargs): + """ + writes the user string sequence to happen at the end of a scan + returns after_scan_pv = pv for userStringSeq for after scan + + **kwargs + seq_num: userStringSeq number in ioc => 10 (default) + snake: for snake scanning => False (default) + + Previously: AfterScan_StrSeq + """ + kwargs.setdefault('seq_num',10) + kwargs.setdefault('snake',False) + seq_num=kwargs['seq_num'] + + if 'scan_ioc' in kwargs: + scan_ioc = kwargs['scan_ioc'] + try: + iex.BL.ioc = kwargs['scan_ioc'] + except: + error = 'undefined' + else: + scan_ioc = iex.BL.ioc + + after_scan_pv,after_scan_proc = userStringSeq_pvs(scan_ioc, seq_num) + + #clear and write the after scan user sequence + userStringSeq_clear(scan_ioc,seq_num) + caput(after_scan_pv+".DESC","After Scan") + + scan_pv = iex.BL.ioc+"scan"+str(scan_dim) + ## Put scan record back in absolute mode + caput(after_scan_pv+".LNK2",scan_pv+".P1AR") + caput(after_scan_pv+".STR2","ABSOLUTE") + + ## Put Positionner Settling time to 0.1s + caput(after_scan_pv+".LNK3",scan_pv+".PDLY NPP NMS") + caput(after_scan_pv+".DO3",0.1) + + ## Clear DetTriggers 2 to 4: + caput(after_scan_pv+".LNK4",scan_pv+".T2PV NPP NMS") #remove trigger 2 (used for EA) after scan + + if kwargs['snake']: + snake_dim = scan_dim - 1 + #snake_proc= Kappa_snake_pv(snake_dim,enable=True) + #caput(after_scan_pv+".LNK10",Kappa_snake_pv()+"PP NMS") + #caput(after_scan_pv+".D10",1) + + return after_scan_proc + +def _Octupole_detector_triggers_sequence(scan_ioc,scan_dim,**kwargs): # do we need to add 29idb:ca5 ??? + """ + + """ + + kwargs.setdefault(seq_num,8) + seq_num=kwargs['seq_num'] + + detector_triggers_pv,detector_triggers_proc = userStringSeq_pvs(iex.BL.ioc, seq_num) + + #clear the userStringSeq + userStringSeq_clear(scan_ioc,seq_num=kwargs['seq_num']) + caput(detector_triggers_pv+".DESC","Octupole_Trigger1") + + scaler_pv = Octupole_scaler_pv() + + caput(detector_triggers_pv+".LNK" +str(1),scaler_pv) + caput(detector_triggers_pv+".WAIT"+str(1),"After"+str(last)) + + ca_list = _Octupole_detector_list() + last = len(ca_list) + for i,ca in enumerate(ca_list): + ca_pv = Keithley_pv(ca[0], ca[1])+':read.PROC CA NMS' + caput(detector_triggers_pv+".LNK" +str(i+2),ca_pv) + caput(detector_triggers_pv+".WAIT"+str(i+2),"After"+str(last)) + + return detector_triggers_proc + +def _Octupole_trigger_dictionary(scan_ioc,scan_dim,**kwargs): + """ + need to do something + """ + trigger_dictionary = { + 1:_Octupole_detector_triggers_sequence(scan_ioc,scan_dim,**kwargs), + } + return trigger_dictionary + + + + +############################################################################################################## +############################## Octupole Motor Scan Set Up ############################## +############################################################################################################## + + + + + +############################################################################################################## +############################## Octupole light ############################## +############################################################################################################## +def Octupole_light(ON_OFF): + """ + Previously:light + """ + light_pv = '29ide:Unidig1Bo0' + if ON_OFF.lower() == 'on': + light=0 + elif ON_OFF.lower() == 'off': + light=1 + caput(light_pv,light) + print(("Turning light "+ON_OFF+".")) + + + + + +############################################################################################################## +############################## Octupole safestate ############################## +############################################################################################################## +def Octupole_safe_state(**kwargs): + """ + puts the C-branch in a safe state, + **kwargs + shutter_close = True; closes the D-shutter + valve_close = True; closes the D-valve + """ + kwargs.setdefault("shutter_close",True) + kwargs.setdefault("valve_close",True) + + if kwargs['shutter_close']: + branch_shutter_close() + + if kwargs['valve_close']: + branch_valve_close() + + + \ No newline at end of file diff --git a/iexcode/instruments/scalers.py b/iexcode/instruments/scalers.py index c3cef3b..7face9f 100644 --- a/iexcode/instruments/scalers.py +++ b/iexcode/instruments/scalers.py @@ -30,6 +30,20 @@ def Kappa_scaler(time_seconds=0.1,verbose=True): if verbose: print("Integration time set to:", str(time_seconds)) + +def Octupole_scaler(time_seconds=0.1,verbose=True): + """ + Sets the integration time for the scalers in the Kappa chamber + and mpa filter num if mpa is running + """ + scaler_pv="29ideMZ0:scaler1.TP" + + caput(pv,time_seconds) + + if verbose: + print("Integration time set to:", str(time_seconds)) + + class Scaler: def __inti__(self, pv): """ -- GitLab