diff --git a/build/lib/iexcode/__init__.py b/build/lib/iexcode/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/build/lib/iexcode/__init__.py @@ -0,0 +1 @@ + diff --git a/iexcode/instruments/AD_utilites.py b/build/lib/iexcode/instruments/AD_utilites.py similarity index 98% rename from iexcode/instruments/AD_utilites.py rename to build/lib/iexcode/instruments/AD_utilites.py index 19de0238d000b53210e7f0264f01da7dc3c54ec9..f8d43d23aed84bf5a1ee86d46cefdbb81f5d1ffa 100644 --- a/iexcode/instruments/AD_utilites.py +++ b/build/lib/iexcode/instruments/AD_utilites.py @@ -13,8 +13,8 @@ from os.path import join, isfile, exists, dirname from time import sleep from epics import caget, caput -from .IEX_endstations import * -from .files_and_folders import get_next_fileNumber +from iexcode.instruments.IEX_endstations import * +from iexcode.instruments.files_and_folders import get_next_fileNumber def AD_CurrentDirectory(ADplugin): diff --git a/build/lib/iexcode/instruments/AD_utilities.py b/build/lib/iexcode/instruments/AD_utilities.py new file mode 100644 index 0000000000000000000000000000000000000000..f8d43d23aed84bf5a1ee86d46cefdbb81f5d1ffa --- /dev/null +++ b/build/lib/iexcode/instruments/AD_utilities.py @@ -0,0 +1,347 @@ +""" +General functions for dealing with Area Detectors and Cameras at 29ID + +work in progress need to redo +""" +############################################################################################################## +############################## General Area Detector ############################## +############################################################################################################## +import datetime +import re +from os import listdir,mkdir,chown,system,chmod +from os.path import join, isfile, exists, dirname +from time import sleep + +from epics import caget, caput +from iexcode.instruments.IEX_endstations import * +from iexcode.instruments.files_and_folders import get_next_fileNumber + + +def AD_CurrentDirectory(ADplugin): + """ + returns the current directory for area detector SavePlugin + handles both Winodws and linux IOCs + ADplugin = "29idc_ps1:TIFF1:"; $(P)$(SavePlugin) + """ + SubDir=caget(ADplugin+"FilePath",as_string=True) + if SubDir[0] == 'X': + Dir='/net/s29data/export/data_29idb/' + SubDir=SubDir.split('\\')[1:] + elif SubDir[0] == 'Y': + Dir='/net/s29data/export/data_29idc/' + SubDir=SubDir.split('\\')[1:] + elif SubDir[0] == 'Z': + Dir='/net/s29data/export/data_29idd/' + SubDir=SubDir.split('\\')[1:] + else: + Dir = SubDir + SubDir=[] + FilePath=join(Dir,*SubDir,'') + return FilePath + +def AD_prefix(ADplugin): + """ + returns the prefix for AreaDetector plugin based on ADplugin + """ + prefix = caget(ADplugin+"FileName_RBV",as_string=True) + return prefix + +def AD_EnableStats(ADplugin): + """ + Enabling the statistics in an AreaDector + ADplugin = "29idc_ps1:Stats1:"; (ADplugin=$(P)$(StatsPlugin)) + """ + caput(ADplugin+"EnableCallbacks","Enable") + caput(ADplugin+"ComputeStatistics","Yes") + caput(ADplugin+"ComputeCentroid","Yes") + + +def AD_SaveFileSetup(ADplugin,mda,**kwargs): + """ + ADplugin = "29id_ps1:TIFF1:" which IOC and which filesaving plugin + (ADplugin=$(P)$(SavePlugin)) + uses to get the current MDA directory and then set the path to one up + /dtype + MDA_CurrentDirectory(scanIOC=None) + + **kwargs (defaults) + scanIOC = BL_ioc() + userpath = extracted from ScanRecord unless specified + subfolder = taken from ADplugin unless specified + filepath = userpath/subfolder + + prefix = default same as subfolder + ext = file extension is extracted for ADplugin unless specified + (TIFF -> tif, HDF -> h5, ...) + FileTemplate="%s%s_%4.4d."+ext; format for filename first %s = filepath, second %s = prefix + + """ + kwargs.setdefault("userpath",dirname(dirname(mda.filepath))) + kwargs.setdefault("subfolder",ADplugin.split(":")[-2][:-1]) + + kwargs.setdefault("prefix",ADplugin.split(":")[-2][:-1]) + extDict={"TIFF":".tif","HDF":"h5"} + kwargs.setdefault("ext",ADplugin.split(":")[-2][:-1]) + kwargs.setdefault("FileTemplate","%s%s_%4.4d."+kwargs["ext"]) + + kwargs.setdefault("debug",False) + + if kwargs['debug']: + print("kwargs: ",kwargs) + + fpath=join(kwargs['userpath'],kwargs['subfolder'],'') + print("\nFolder: " + fpath) + if not (exists(fpath)): + fileNumber=1 + else: + fileNumber=get_next_fileNumber(fpath,kwargs["prefix"]) + print("NextFile: "+str(fileNumber)) + caput(ADplugin+"CreateDirectory",-1) #allows IOC to create directories + caput(ADplugin+"FilePath",fpath) + caput(ADplugin+"FileName",kwargs["prefix"]) + caput(ADplugin+"FileNumber",fileNumber) + + #setup AD + caput(ADplugin+"FileTemplate",kwargs["FileTemplate"]) + caput(ADplugin+"AutoIncrement","Yes") + caput(ADplugin+"AutoSave","Yes") + +def AD_CurrentPrefix(ADplugin): + """ + returns the prefix (without _) for area detector SavePlugin + ADplugin = "29id_ps1:TIFF1:"; $(P)$(SavePlugin) + """ + Prefix=caget(ADplugin+'FileName',as_string=True) + return Prefix + +def AD_CurrentRun(ADplugin): + """ + returns the curent run specified in the filepath for area detector SavePlugin + ADplugin = "29id_ps1:TIFF1:"; $(P)$(SavePlugin) + """ + fpath=caget(ADplugin+"FilePath",as_string=True) + current_run=re.findall("\d\d\d\d_\d", fpath)[0] + return current_run + +def AD_CurrentUser(ADplugin): + """ + returns the curent user specified in the filepath for area detector SavePlugin + ADplugin = "29id_ps1:TIFF1:"; $(P)$(SavePlugin) + """ + folder_name = ADplugin.split(":")[1] + folder_name[:-1] + SubDir=caget(ADplugin+":FilePath",as_string=True) + if SubDir[0] == 'X': + current_user='Staff' + elif SubDir[0] == 'Y': + m=SubDir.find(AD_CurrentRun(ADplugin)) + n=SubDir.find(folder_name) + current_user=SubDir[m+7:n] + else: current_user=None + return current_user + +def AD_DoneSingleSave(ADplugin,**kwargs): + """ + sets and AD up ready to save images + Acquire -> Done + ImageMode -> Single + Save -> Enable + e.g. ADplugin="29id_ps2:TIFF1:" + + **kwargs: + P=first part of ADplugin if not specified + R="cam1:"; other AD have "det1:" + """ + kwargs.setdefault("P",ADplugin.split(":")[0]+":") + kwargs.setdefault("R","cam1:") + caput(kwargs["P"]+kwargs["R"]+"Acquire","Done",wait=True,timeout=5*60);sleep(.1) + caput(kwargs["P"]+kwargs["R"]+"ImageMode","Single");sleep(.5) + caput(ADplugin+"EnableCallbacks","Enable");sleep(.1) + +def AD_FreeRun(ADplugin,**kwargs): + """ + sets and AD to disable saving and free run + Saving -> Disable + Acquire -> Done + ImageMode -> Single + + e.g. ADplugin="29id_ps2:TIFF1:" + + **kwargs: + P=first part of ADplugin if not specified + R="cam1:"; other AD have "det1:" + """ + kwargs.setdefault("P",ADplugin.split(":")[0]+":") + kwargs.setdefault("R","cam1:") + caput(kwargs["P"]+kwargs["R"]+"Acquire","Done",wait=True,timeout=5*60) + caput(ADplugin+"EnableCallbacks","Disable");sleep(.1) + caput(kwargs["P"]+kwargs["R"]+"ImageMode","Continuous");sleep(.1) + caput(kwargs["P"]+kwargs["R"]+"Acquire","Acquire");sleep(.1) + + +def AD_snap(ADplugin,**kwargs): + """ + takes an image and save the image for ADplugin + e.g. ADplugin="29id_ps2:TIFF1:" + + use AD_SaveFileSetup to set filepath, prefix etc. + use AD_CurrentDirectory to see current directory + use AD_prefix to see current prefix + + **kwargs: + P=first part of ADplugin if not specified + R="cam1:"; other AD have "det1:" + + ExposureTime: changes both the exposure time and the acquire time for the snapshot + resets after acquisition + FreeRun: True => disable setting and go back to continuous acquision + False => leave saving enabled and camera in single acquision + """ + kwargs.setdefault("P",ADplugin.split(":")[0]+":") + kwargs.setdefault("R","cam1:") + kwargs.setdefault("FreeRun",True) + + expT=caget(kwargs["P"]+kwargs["R"]+"AcquireTime_RBV") + acqT=caget(kwargs["P"]+kwargs["R"]+"AcquirePeriod_RBV") + + AD_DoneSingleSave(ADplugin,**kwargs) + + if "ExposureTime" in kwargs: + caput(kwargs["P"]+kwargs["R"]+"AcquireTime",kwargs["ExposureTime"]) + caput(kwargs["P"]+kwargs["R"]+"AcquireTime",kwargs["ExposureTime"]+.01) + + caput(kwargs["P"]+kwargs["R"]+"Acquire","Acquire",wait=True,timeout=5*60) + + if "ExposureTime" in kwargs: + caput(kwargs["P"]+kwargs["R"]+"AcquireTime",expT) + caput(kwargs["P"]+kwargs["R"]+"AcquireTime",acqT) + + if kwargs["FreeRun"]: + sleep(.1) + AD_FreeRun(ADplugin,**kwargs) + + + +def AD_ScanTrigger(ADplugin,mda,**kwargs): + """ + Add Triggering of AreaDetector to scanIOC + ADplugin = "29idc_ps1:TIFF1:" (ADplugin=$(P)$(SavePlugin)) + + **kwargs + scanIOC = "29id"+BL_ioc() if not specified + scanDIM = 1 + P=first part of ADplugin if not specified + R="cam1:"; other AD have "det1" + detTrig = 2; detectorTrigger number + """ + kwargs.setdefault("scanDIM",1) + kwargs.setdefault("P",ADplugin.split(":")[0]+":") + kwargs.setdefault("R","cam1:") + kwargs.setdefault("detTrig",2) + + scanPV=mda.ioc+"scan"+str(kwargs["scanDIM"]) + trigger=".T"+str(kwargs["detTrig"])+"PV" + caput(scanPV+trigger,kwargs["P"]+kwargs["R"]+"Acquire",wait=True,timeout=5*60) + +def ADplugin_ScanSetup(ADplugin,mda, **kwargs): + """ + stop the acquisition, puts in ImageMode=Single + enables saving + add to detector trigger + Does not press go + + ADplugin = "29idc_ps1:TIFF1:"; (ADplugin=$(P)$(SavePlugin)) + **kwargs + # AD_ScanTrigger + scanIOC = "29id"+BL_ioc() if not specified + scanDIM = 1 + P=first part of ADplugin if not specified + R="cam1:"; other AD have "det1:" + detTrig = 2; detectorTrigger number + + # AD_SaveFileSetup + filepath=userpath (from BL_ioc scanRecord)+"/dtype" + (e.g. filepath="/net/s29data/export/data_29id"+folder+"/"+run+"/"+userName+"/"+df) + dtype = taken from ADplugin + FileTemplate="%s%s_%4.4d."+dtype; format for filename first %s = filepath, second %s = prefix + prefix = dtype by default + + """ + #from AD_ScanTrigger + kwargs.setdefault("P",ADplugin.split(":")[0]+":") + kwargs.setdefault("R","cam1:") + + AD_DoneSingleSave(ADplugin,**kwargs) + + AD_SaveFileSetup(ADplugin,**kwargs) + AD_ScanTrigger(ADplugin, **kwargs) + trigger=".T"+str(kwargs["detTrig"])+"PV" + scanPV=mda.ioc+"scan"+str(kwargs["scanDIM"]) + print("WARNING: you need to need to disable saving and clear the trigger by hand after the scan") + print("\tAD_FreeRun("+ADplugin+"); caput("+scanPV+trigger+",'')") + +def AD_ROI_setup(AD,ROInum,xcenter=500,ycenter=500,xsize=50,ysize=50,binX=1,binY=1): + """ + AD = "29id_ps4" + AD = "29iddMPA" + """ + # roiNUM=1 MPA_ROI_SetUp(535,539,50,50) center of MCP + + ADplugin=AD+':ROI'+str(ROInum)+':' + xstart=xcenter-xsize/2.0 + ystart=ycenter-ysize/2.0 + caput(ADplugin+'MinX',xstart) + caput(ADplugin+'MinY',ystart) + caput(ADplugin+'SizeX',xsize) + caput(ADplugin+'SizeY',ysize) + caput(ADplugin+'BinX',binX) + caput(ADplugin+'BinY',binY) + caput(ADplugin+'EnableCallbacks','Enable') + print(ADplugin+' - '+caget(ADplugin+'EnableCallbacks_RBV',as_string=True)) + #MPA_ROI_Stats(roiNUM) + +def AD_OVER_SetUp(AD,ROInum,OVERnum,linewidth=5,shape='Rectangle'): + """ + AD = "29id_ps4" + AD = "29iddMPA" + shape= 'Cross', 'Rectangle', 'Ellipse','Text' + """ + OVER1=AD+":Over1:"+str(OVERnum)+":" + ROI=AD+":ROI"+str(ROInum)+":" + + caput(ROI+'EnableCallbacks','Enable') + caput(OVER1+"Name","ROI"+str(ROInum)) + caput(OVER1+"Shape",shape) + caput(OVER1+"Red",0) + caput(OVER1+"Green",255) + caput(OVER1+"Blue",0) + caput(OVER1+'WidthX',linewidth) + caput(OVER1+'WidthY',linewidth) + + caput(OVER1+"PositionXLink.DOL",ROI+"MinX_RBV CP") + caput(OVER1+"SizeXLink.DOL",ROI+"SizeX_RBV CP") + caput(OVER1+"PositionYLink.DOL",ROI+"MinY_RBV CP") + caput(OVER1+"SizeYLink.DOL",ROI+"SizeY_RBV CP") + + caput(OVER1+"Use","Yes") + + +def AD_OverLayCenter(x,y,AD,OverLay=1,Num=1): + """ + Sets CenterX and CenterY for AD:Over(OverLay):Num: + eg. 29id_ps2:Over1:1: AD='29id_ps2',Overlay=1, Num=1 + """ + caput(AD+":Over"+str(OverLay)+":"+str(Num)+":CenterX",x) + caput(AD+":Over"+str(OverLay)+":"+str(Num)+":CenterY",y) + +def AD_OverLayCenter_get(AD,OverLay=1,Num=1): + """ + Sets CenterX and CenterY for AD:Over(OverLay):Num: + eg. 29id_ps2:Over1:1: AD='29id_ps2',Overlay=1, Num=1 + """ + print('x = '+str(caget(AD+":Over"+str(OverLay)+":"+str(Num)+":CenterX"))) + print('y = '+str(caget(AD+":Over"+str(OverLay)+":"+str(Num)+":CenterY"))) + + + + + diff --git a/build/lib/iexcode/instruments/ARPES.py b/build/lib/iexcode/instruments/ARPES.py new file mode 100644 index 0000000000000000000000000000000000000000..90f825f9fa07a93d36c82263dbf7404f0ea79efd --- /dev/null +++ b/build/lib/iexcode/instruments/ARPES.py @@ -0,0 +1,769 @@ +import numpy as np +from time import sleep + +from epics import caget,caput,PV + +from iexcode.instruments.IEX_endstations import * +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.logfile import logfile_name_set,logfile_header + +from iexcode.instruments.conversions_constants import * +from iexcode.instruments.utilities import * +from iexcode.instruments.userCalcs import userStringSeq_clear, userStringSeq_pvs + +from iexcode.instruments.scanRecord import * +from iexcode.instruments.Motors import * +from iexcode.instruments.xrays import * +from iexcode.instruments.current_amplifiers import * +from iexcode.instruments.gate_valves import valve_close, branch_valves +from iexcode.instruments.shutters import branch_shutter_close +from iexcode.instruments.slits import slit3C_get + +from iexcode.instruments.Lakeshore_335 import Lakeshore_reset +from iexcode.instruments.electron_analyzer import folders_EA,EA + + +############################################################################# +def ARPES_init(set_folders=True,reset=True,**kwargs): + """ + kwargs: + set_folders: sets the mda and EA folders; default => False + xrays: sets global variable; default => True + """ + kwargs.setdefault('scan_ioc','29idARPES:') + kwargs.setdefault('xrays',True) + kwargs.setdefault('BL_mode','user') + + #scan + if kwargs['BL_mode']=='staff': + detector_dictionary = staff_detector_dictionary() + else: + detector_dictionary = ARPES_detector_dictionary() + mda_scanRecord = ScanRecord(kwargs['scan_ioc'],detector_dictionary, + ARPES_trigger_dictionary(),ARPES_scan_before_sequence(),ARPES_scan_after_sequence()) + + #endstation + global BL + BL=Endstation('ARPES',kwargs['scan_ioc'],kwargs['xrays'],kwargs['BL_mode'],mda_scanRecord) + + #EA + try: + EA.get() + except: + print("\n\n NOTE: Scienta IOC is not running - start IOC and %run Macros_29id/ScanFunctions_EA.py\n\n") + + #global detectors + global tey,ca15 + tey = Keithley('c',1) + ca15 = Keithley('b',15) + + #setting folders + if 'set_folders': + if BL.mode == 'staff': + user_name = 'staff' + else: + user_name = input('user name: ') + folders_ARPES(user_name,**kwargs) + + #resetting + if 'reset': + ARPES_reset() + + #motors + global ARPES_Motors + physical_motors = ['x','y','z','th','chi','phi'] + psuedo_motors = ['focus'] + ARPES_Motors = Motors('ARPES',ARPES_motor_dictionary(),physical_motors,psuedo_motors) + + print ('ARPES_init') +############################################################################################################## +############################## ARPES detectors and motors ############################## +############################################################################################################## +def ARPES_detector_list(): + """ + list of detectors to trigger + + Previously: part of Detector_List + """ + ca_list=[["c",1],["b",15],["b",4],["b",13]] + return ca_list + +def ARPES_detector_dictionary(xrays=True): + """ + returns a dictionary of the default detectors for the scan record + + Previously: Detector_Default + """ + det_dict={ + 14:"29idc:ca2:read", + 16:"29idc:ca1:read", + 17:EA._statsPlugin+"Total_RBV", + 18:"29idARPES:LS335:TC1:IN1", + 19:"29idARPES:LS335:TC1:IN2", + } + if xrays: + det_dict.update(xrays_detector_dictionary()) + return det_dict + +def ARPES_motor_dictionary(): + """ + returns a dictionary with {name:[rbv,val,spmg,pv]} + """ + + motor_nums = {'x': 1, + 'y':2, + 'z':3, + 'th':4, + 'chi':5, + 'phi':6, + } + + motor_dictionary={} + for name in motor_nums.keys(): + pv = '29idc:m'+str(motor_nums[name]) + motor_dictionary.update({name:[pv+'.RBV',pv+'.VAL',pv+'.SPMG',pv]}) + + return motor_dictionary + +def ARPES_extra_pvs(): + """ + used to get the PV associated with a given pnuemonic + + """ + d={ + "SES_slit":"29idc:m8.RBV", + "TA":"29idARPES:LS335:TC1:IN1", + "TB":"29idARPES:LS335:TC1:IN2", + "tey1":"29idc:ca1:read", + "tey2":"29idc:ca2:read", + } + return d + +############################################################################################################## +############################## setting folder ############################## +############################################################################################################## +def folders_ARPES(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',True) + 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,BL.folder,user_name,BL.ioc,kwargs['ftp']) + + # Create User Folder: + make_user_folders(run,BL.folder,user_name,BL.endstation,ftp=kwargs['ftp']) + sleep(5) + + if kwargs["set_folders"]: + # Set up MDA folder: + folder_mda(run,BL.folder,user_name,BL.prefix,BL.ioc) + logfile_name_set(BL.endstation) + logfile_header(BL.endstation,BL.ioc,ARPES_log_header()) + + + #Set up Scienta folders: + try: + userPath = "/net/s29data/export/data_29id"+BL.folder+"/"+run+"/"+user_name+"/" + folders_EA(userPath,filePrefix="EA") + except: + print_warning_message("EA ioc is not running, cannot set folder") + +def ARPES_reset(): + """ + resets scanRecord, current amplifiers, mono limits and lakeshore + """ + #resetting the scanRecord + BL.mda.reset() + + #resetting the current amplifiers + if BL.xray: + ca_reset_all() + else: + tey.reset() + + #resetting mono and anyother beamline stuff + if BL.xrays: + xrays_reset() + + #reseting the ARPES Lakeshore + pv = "29idARPES:LS335:" + LS_355_defaults = { + "TC1:read.SCAN":".5 second", + "TC1:OUT1:Cntrl":"A", + "TC1:OUT2:Cntrl":"B", + "TC1:OUT1:Mode":"Closed Loop" + } + Lakeshore_reset(pv,LS_355_defaults) + +############################################################################################################## +############################## get all ############################## +############################################################################################################## +def ARPES_get_all(verbose=True): + """ + returns a dictionary with the current status of the ARPES endstation and exit slit + """ + vals={} + + #sample position + motor_dictionary = ARPES_motor_dictionary() + for motor in motor_dictionary.keys(): + vals[motor]=ARPES_Motors.get(motor,verbose=False) + + #endstation pvs + extra_pvs = ARPES_extra_pvs() + for key in extra_pvs.keys(): + vals.update(key,caget(extra_pvs[key])) + vals.update('exit_slit',slit3C_get()) + + #beamline info + if BL.xray: + beamline_info = xrays_get_all() + vals.update(beamline_info) + + if verbose: + for key in vals: + print(key+" = "+vals[key]) + return vals + + + +############################################################################################################## +############################## logging ############################## +############################################################################################################## +def ARPES_log_header(): + header_list={ + 'EA': "scan,x,y,z,th,chi,phi,T,scan_mode,E1,E2,step,i,f,PE,lens_mode,SES slit #,hv,exit_slit,GRT,ID_SP,ID_RBV,ID_Mode,ID_QP,TEY1,TEY2,time,comment", + 'ARPES':"scan,motor,start,stop,step,x,y,z,th,chi,phi,T,hv,exit_slit,GRT,ID_SP,ID_RBV,ID_Mode,ID_QP,TEY_1,TEY_2,time,comment" + } + return header_list + +def ARPES_log_entries(): + """ + endstation info for log file + + Previously: scanlog + """ + vals = ARPES_get_all(verbose=False) + x = vals['x'] + y = vals['y'] + z = vals['z'] + th = vals['th'] + chi = chi['chi'] + phi = vals['phi'] + TA = vals['TA'] + TB = vals['TB'] + tey1 = vals['tey1'] + tey2 = vals['tey2'] + + entry_list = ["x","y","z","th","chi","phi","TA","TB","tey1","tey2"] + pv_list = [ x, y, z, th, chi, phi, TA, TB, tey1,tey2] + format_list = [".2f",".2f",".2f",".2f",".2f",".2f",".2f",".2f","1.2e","1.2e"] + + return entry_list,pv_list,format_list + +############################################################################################################## +############################## ARPES scanRecord ############################## +############################################################################################################## +def ARPES_scan_before_sequence(**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(BL.ioc, seq_num) + + #clear and write the before scan user sequence + userStringSeq_clear(BL.ioc,seq_num) + caput(before_scan_pv+".DESC","Before Scan") + + #sequence put CAs in passive + ca_list = ARPES_detector_list() + for (i,ca) in enumerate(ca_list): + ca_pv = Keithley_pv(ca[0], ca[1])+':read.SCAN PP NMS' + caput(before_scan_pv+".LNK" +str(i+1),ca_pv) + caput(before_scan_pv+".STR" +str(i+1),"Passive") + + return before_scan_proc + +def ARPES_ca_live_sequence(**kwargs): + """ + """ + kwargs.setdefault('seq_num',7) + ca_live_sequence_proc = ca_live_sequence(BL.ioc,kwargs['seq_num'],ARPES_detector_list()) + return ca_live_sequence_proc + +def ARPES_scan_after_sequence(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'] + + after_scan_pv,after_scan_proc = userStringSeq_pvs(BL.ioc, seq_num) + + #clear and write the after scan user sequence + userStringSeq_clear(BL.ioc,seq_num) + caput(after_scan_pv+".DESC","After Scan") + + ## Put All relevant CA back in live mode + ca_live_sequence_proc = ARPES_ca_live_sequence(**kwargs) + caput(after_scan_pv+".LNK1",ca_live_sequence_proc+" PP NMS") + caput(after_scan_pv+".DO1",1) + + scan_pv = 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: + 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= ARPES_snake_pv(snake_dim,enable=True) + #caput(after_scan_pv+".LNK10",ARPES_snake_pv()+"PP NMS") + #caput(after_scan_pv+".D10",1) + + return after_scan_proc + + +def ARPES_detector_triggers_sequence(**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(BL.ioc, seq_num) + + #clear the userStringSeq + userStringSeq_clear(BL.ioc,seq_num=kwargs['seq_num']) + caput(detector_triggers_pv+".DESC","ARPES_Trigger1") + + ca_list = ARPES_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+1),ca_pv) + caput(detector_triggers_pv+".WAIT"+str(i+1),"After"+str(last)) + + return detector_triggers_proc + +def ARPES_trigger_dictionary(): + """ + need to do something + """ + trigger_dictionary = { + 1:ARPES_detector_triggers_sequence(), + } + return trigger_dictionary + + +############################################################################################################## +############################## ARPES Motor Scan Set Up ############################## +############################################################################################################## +def ARPES_motor_encoder_sync(): + ioc = "29idc:" + for motor in [1,2,3,4]: + pv = ioc+"m"+str(motor)+".SYNC" + caput(pv,1) + print("synch encoder: "+pv) + + + + +#################################################################################################### +################ ARPES Positions (LEED,transfer, measure) ##################################### +##################################################################################################### +def _ARPES_DefaultPosition(destination): + """ + Default ARPES positions in DIAL units + """ + DefaultPosition={ + 'measure':(0.0,0.0,-13.5,0.0,0.0,0.0), + 'LEED':(-0.0, 0.0, -141.5, 89.5, 0.0, 0.0), + 'transfer':(-0,0.0,-141.5,180.0,0.0,0.0), + } + if destination in DefaultPosition: + pos=DefaultPosition[destination] + else: + pos=(None,None,None,None,None,None) + return pos + +def _ARPES_MoveSequence(destination): + """ + Moves the ARPES manipulator x,y,z,th to a given destination (does not change chi or phi) + Resets the limits to help protect from crashes + such as: phi/chi motor body into the strong back, manipulator into the LEED, manipulator into the wobble stick + + DO NOT MAKE BIG MOVE WITH OUT WATCHING THE MANIPULATOR!!!! + if the theta encoder stops reading the manipulator will CRASH!!!! + """ + (x,y,z,th,chi,phi)=_ARPES_DefaultPosition(destination) + motor_dictionary = ARPES_motor_dictionary() + if x is None: + print("Not a valid destination") + else: + #reset limits to default values + _ARPES_limits_set(None) + #print destination + print(("Moving to "+destination+": "+str(round(x,1))+","+str(round(y,1))+","+str(round(z,1))+","+str(round(th,1)))+' Time:'+time.strftime("%H:%M")) + # move x and y to zero for all moves (helps protect the motors from crashing into the strong back) + caput(motor_dictionary['x'][3]+".DVAL",0,wait=True,timeout=18000) + caput(motor_dictionary['y'][3]+".DVAL",0,wait=True,timeout=18000) + # moves z and th simultaneously and monitors the .DMOV + caput(motor_dictionary['z'][3]+".DVAL",z,wait=False,timeout=18000) + caput(motor_dictionary['th'][3]+".DVAL",th,wait=False,timeout=18000) + while True: + sleep(5) + Test=caget(motor_dictionary['z'][3]+".DMOV")*caget(motor_dictionary['th'][3]+".DMOV") + if(Test==1): + break + # move x and y to final position + caput(motor_dictionary['x'][3]+".DVAL",x,wait=True,timeout=18000) + caput(motor_dictionary['y'][3]+".DVAL",y,wait=True,timeout=18000) + print(("Arrived at "+destination+": "+str(round(x,1))+","+str(round(y,1))+","+str(round(z,1))+","+str(round(th,1)))+' Time:'+time.strftime("%H:%M")) + #set the limits for this position + _ARPES_limits_set(destination) + +def _ARPES_limits_set(destination): + """ + Resets the ARPES motor limits in Dial cooridinates(remember that z is negative) + destination: 'measures' or 'LEED', + else: sets to the full range + ARPES_MoveSequence(destination) minimizes that chance of a crash and sets limits + + Previously: ARPES_LimitsSet + """ + motor_dictionary = ARPES_motor_dictionary() + if destination == 'measure': + (x,y,z,th,chi,phi)=_ARPES_DefaultPosition("measure") + limits={'x':[5.5,-7],'y':[7,-5],'z':[-6,-310],'th':[th+35,th-25],'chi':[45,-15],'phi':[120,-120]} + elif destination == 'LEED': + (x,y,z,th,chi,phi)=_ARPES_DefaultPosition("LEED") + limits={'x':[5.5,-7],'y':[6,-1],'z':[z+5,z-5],'th':[th+2,th-2],'chi':[45,-15],'phi':[120,-120]} + else: + limits={'x':[5.5,-7],'y':[7,-5],'z':[-6,-310],'th':[240,-70],'chi':[45,-15],'phi':[120,-120]} + #setting the limits for each motor in Dial + for m in limits: + caput(motor_dictionary[m][3]+'.DHLM',limits[m][0]) + caput(motor_dictionary[m][3]+'.DLLM',limits[m][1]) + if destination is not None: + print("Limits have been reset for "+destination+" position") + else: + print("Limits have been reset for full range") +#################################################################################################### +def ARPES_transfer(chi=0,phi=0,**kwargs): + """ + Moves the ARPES manipulator to the default transfer position + kwargs: + EA_HV_Off=True; Turns off the EA HV + Close_CBranch=True; closes the C-shutter and the C-valve (main chamber to BL) + """ + ARPESgo2("transfer",**kwargs) + +def ARPES_measure(**kwargs): + """ + Moves to ARPES motors x,y,z,th to the default measurement position + kwargs + chi=None # specify a value to move chi + phi=None # specifiy a value to move phi + """ + ARPESgo2("measure",**kwargs) + +def ARPES_LEED(**kwargs): + """ + Moves to ARPES motors x,y,z,th to the default LEED position + kwargs: + EA_HV_Off=True; Turns off the EA HV + Close_CBranch=True; closes the C-shutter and the C-valve (main chamber to BL) + + chi=None # specify a value to move chi + phi=None # specifiy a value to move phi + """ + ARPESgo2("LEED",**kwargs) +#################################################################################################### +def ARPESgo2(destination,**kwargs): + """ + Moves the ARPES manipulator to the default position: + destination: "transfer", "measure", "LEED" + + kwargs: + EA_off = True; turns off EA HV + shutter_close = True; closes the C-shutter + valve_close = True; closes the C-valve + + chi=None => doesn't move, otherwise specify a value to move chi + phi=None => doesn't move, otherwise specifiy a value to move phi + + """ + + + kwargs.setdefault("EA_off",True) + kwargs.setdefault("shutter_close",True) + kwargs.setdefault("valve_close",True) + + kwargs.setdefault("chi",None) + kwargs.setdefault("phi",None) + + ARPES_safe_state(**kwargs) + + #Move x,y,z,th + _ARPES_MoveSequence(destination) + #Move chi and phi back to 0 + motor_dictionary = ARPES_motor_dictionary() + if kwargs["chi"] is not None: + caput(motor_dictionary['chi'][1],kwargs["chi"]) + if kwargs["phi"] is not None: + caput(motor_dictionary['phi'][1],kwargs["phi"]) + + +############################################################################################################## +############################## ARPES pvs for GUIs (caQtDM) ############################## +############################################################################################################## +def ARPES_StringCalc_trigger2_active(): + """ + setup a string calc to be used by caQtDM to indicate that the trigger 2 is filled + """ + ioc="29idARPES:" + pv=ioc+"userStringCalc2" + caput(pv+".DESC","scan1 trigger2 calc") + caput(pv+".INAA",ioc+"scan1.T2PV CP NMS") + caput(pv+".CALC$","AA") + + caput(ioc+"userStringCalcEnable.VAL","Enable") + + + +############################################################################################################## +############################## ARPES safestate ############################## +############################################################################################################## +def ARPES_safe_state(**kwargs): + """ + puts the C-branch in a safe state, + **kwargs + EA_off = True; turns off EA HV + shutter_close = True; closes the C-shutter + valve_close = True; closes the C-valve + """ + kwargs.setdefault("EA_off",True) + kwargs.setdefault("shutter_close",True) + kwargs.setdefault("valve_close",True) + + if kwargs["EA_off"]: + try: + EA.off(quiet=False) + except: + print('EA is not running, visually confirm HV is off') + + if kwargs['valve_close']: + valve_close(branch_valves('c'), verbose=True) + + if kwargs['shutter_close']: + branch_shutter_close('c') + +############################################################################################################## +############################## ARPES motors ############################## +############################################################################################################## +### x ### +def mvx(val,**kwargs): + """ moves x motor in the endstation""" + ARPES_Motors.move('x',val,**kwargs) + +def dmvx(val): + """ relative x motor in the endstation""" + ARPES_Motors.move('x',val,relative=True) + +def scanx(start,stop,step,**kwargs): + """ scans the x motor in the endstation""" + ARPES_Motors.scan("x",start,stop,step,**kwargs) + +def dscanx(start,stop,step): + """relative scans of the x motor in the endstation """ + ARPES_Motors.scan("x",start,stop,step,relative=True) + +### y ### +def mvy(val,**kwargs): + """ moves y motor in the endstation""" + ARPES_Motors.move('y',val,**kwargs) + +def dmvy(val): + """ relative y motor in the endstation""" + ARPES_Motors.move('y',val,relative=True) + +def scany(start,stop,step,**kwargs): + """ scans the y motor in the endstation""" + ARPES_Motors.scan("y",start,stop,step,**kwargs) + +def dscany(start,stop,step): + """relative scans of the y motor in the endstation """ + ARPES_Motors.scan("y",start,stop,step,relative=True) + +### z ### +def mvz(val,**kwargs): + """ moves z motor in the endstation""" + ARPES_Motors.move('z',val,**kwargs) + +def dmvz(val): + """ relative z motor in the endstation""" + ARPES_Motors.move('z',val,relative=True) + +def scanz(start,stop,step,**kwargs): + """ scans the z motor in the endstation""" + ARPES_Motors.scan("z",start,stop,step,**kwargs) + +def dscanz(start,stop,step): + """relative scans of the z motor in the endstation """ + ARPES_Motors.scan("z",start,stop,step,relative=True) + +### th ### +def mvth(val,**kwargs): + """ moves th motor in the endstation""" + ARPES_Motors.move('th',val,**kwargs) + +def dmvth(val): + """ relative th motor in the endstation""" + ARPES_Motors.move('th',val,relative=True) + +def scanth(start,stop,step,**kwargs): + """ scans the th motor in the endstation""" + ARPES_Motors.scan("th",start,stop,step,**kwargs) + +def dscanth(start,stop,step): + """relative scans of the th motor in the endstation """ + ARPES_Motors.scan("th",start,stop,step,relative=True) + +### chi ### +def mvchi(val,**kwargs): + """ moves chi motor in the endstation""" + ARPES_Motors.move('chi',val,**kwargs) + +def dmvchi(val): + """ relative chi motor in the endstation""" + ARPES_Motors.move('chi',val,relative=True) + +def scanchi(start,stop,step,**kwargs): + """ scans the chi motor in the endstation""" + ARPES_Motors.scan("chi",start,stop,step,**kwargs) + +def dscanchi(start,stop,step): + """relative scans of the chi motor in the endstation """ + ARPES_Motors.scan("chi",start,stop,step,relative=True) + +### phi ### +def mvphi(val,**kwargs): + """ moves phi motor in the endstation""" + ARPES_Motors.move('phi',val,**kwargs) + +def dmvphi(val): + """ relative phi motor in the endstation""" + ARPES_Motors.move('phi',val,relative=True) + +def scanphi(start,stop,step,**kwargs): + """ scans the phi motor in the endstation""" + ARPES_Motors.scan("phi",start,stop,step,**kwargs) + +def dscanphi(start,stop,step): + """relative scans of the phi motor in the endstation """ + ARPES_Motors.scan("phi",start,stop,step,relative=True) + + +def mvfocus(x_val): + """ + Moves APPES x and compensates y motor so that the beam stays in the same sample position but the focus is moved + """ + x_delta = x_val - ARPES_Motors.get('x') + y_delta = x_delta * np.tan(55/180*np.pi) + y_val = ARPES_Motors.get('y') + y_delta + + ARPES_Motors.move("x",x_val) + ARPES_Motors.move("y",y_val) + + return x_val,y_val + +def mvy_fixed_focus(y_val): + """ + Moves APPES x and compensates y motor so that the beam stays in the same sample position but the focus is moved + """ + y_delta = y_val - ARPES_Motors.get('y') + x_delta = y_delta / np.tan(55/180*np.pi) + x_val = ARPES_Motors.get('x') + x_delta + + ARPES_Motors.move("x",x_val) + ARPES_Motors.move("y",y_val) + return x_val,y_val + +def scanfocus(x_start,x_stop,x_step,**kwargs): + """ + Scans APPES x and compensates y motor so that the beam stays in the same sample position + y=x*tan(55) + + kwargs: + execute: True/False to start the scan => True (default) + """ + kwargs.setdefault('execute',True) + + + +def ARPES_sample_map2D(step_y=0.5,step_z=0.5): + """ + 2D map of sample area in ARPES chamber + + Previously: Map_ARPES_Sample + """ + print("Scan_ARPES_2Dmotor(\"y\",0,4,"+str(step_y)+",\"z\",12,16,"+str(step_z)+")") + ARPES_Motors.scan2D(["y",0,4,step_y],["z",12,16,step_z]) + + +######## mprint and mvsample ################### +def mprint(): + """ + prints current position of the physical motors + """ + ARPES_Motors.mprint() + +def mvsample(position_list): + """ + moves the sample to the position sepcified by position_list + position_list = ['description',x,y,z,th,chi,phi] + + Previously: sample + """ + ARPES_Motors.mvsample(position_list) + diff --git a/build/lib/iexcode/instruments/FMB_mirrors.py b/build/lib/iexcode/instruments/FMB_mirrors.py new file mode 100644 index 0000000000000000000000000000000000000000..888d9b9425b99a75ac9d39dcac6447fafe0680f7 --- /dev/null +++ b/build/lib/iexcode/instruments/FMB_mirrors.py @@ -0,0 +1,174 @@ +from time import sleep + +from epics import caget, caput + +from iexcode.instruments.IEX_endstations import * +from iexcode.instruments.utilities import read_dict, print_warning_message +from iexcode.instruments.m3r import m3r_branch + +M0M1_fpath="/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/Dict_IDCal.txt" + + +def FMB_mirror_ioc(mirror_num): + """ + returns the ioc name for the given mirror number: + miror_num = 0 / 1 / 3 for M0 / M1 /M3R respectively + """ + ioc = '29id_'+['M0','M1','','M3R'][mirror_num]+":" + return ioc + +def FMB_mirror_status(mirror_num): + """ + returns the ioc name for the given mirror number: + miror_num = 0 / 1 / 3 for M0 / M1 /M3R respectively + + status =1 when positioned + """ + ioc = '29id_'+['M0','M1','','M3R'][mirror_num]+":" + pv = FMB_mirror_ioc(mirror_num) + status=caget(pv+'SYSTEM_STS') + + return status + +def FMB_mirror_axis_position(mirror_num,axis, verbose=True): + """ + returns the readback and set point of an FMB mirror + """ + pv = FMB_mirror_ioc(mirror_num) + + rbv = round(caget(pv+axis+"_MON"),3) + sp = round(caget(pv+axis+"_POS_SP"),3) + + if verbose: + print (pv+axis+": "+str(rbv)) + + return rbv,sp + +def FMB_mirror_get(mirror_num,verbose=True): + """ + get and returns the current mirror position + """ + axis_labels=['Tx','Ty','Tz','Rx','Ry','Rz'] + vals=[] + message = "\nM"+str(mirror_num)+" @ " + for axis in axis_labels: + rbv,sp = FMB_mirror_axis_position(mirror_num,axis, verbose=False) + vals.append(rbv) + message =+ "%.3f"+"/" % rbv + if verbose: + print(message) + if mirror_num == 3: + mirror_branch = m3r_branch() + print(" => In "+mirror_branch+" branch") + return vals + +def FMB_mirror_move(mirror_num,axis,val,verbose=True): + """ + miror_num = 0 / 1 / 3 for M0 / M1 /M3R respectively + and axis: + TX = lateral RX = Roll + TY = vertical RY = Pitch + TZ = longitudinal RZ = Yaw + + "Previously: Move_M0M1 + """ + pv = FMB_mirror_ioc(mirror_num) + axes = ['TX','TY','TZ','RX','RY','RZ'] + if axis in axes: + caput(pv+axis+"_SP.PREC",3) + caput(pv+axis+"_POS_SP") + caput(pv+"MOVE_CMD.PROC",1,wait=True,timeout=18000) + while True: + if FMB_mirror_status != 1: + sleep(.5) + else: + break + FMB_mirror_axis_position(mirror_num,axis,verbose=verbose) + + else: + print_warning_message(axis+' is not a valid axis chose '+axes) + +def FMB_mirror_move_all(mirror_num,position_list,verbose=True): + """ + miror_num = 0 / 1 / 3 for M0 / M1 /M3R respectively + position_list = [TX,TY,TZ,RX,RY,RZ] + + "Previously: Move_M0M1 + """ + pv = FMB_mirror_ioc(mirror_num) + for axis in ['TX','TY','TZ','RX','RY','RZ']: + caput(pv+axis+"_SP.PREC",3) + caput(pv+axis+"_POS_SP") + caput(pv+"MOVE_CMD.PROC",1,wait=True,timeout=18000) + while True: + if FMB_mirror_status != 1: + sleep(.5) + else: + break + FMB_mirror_axis_position(mirror_num,axis,verbose=verbose) + + +def FMB_mirror_tweak(mirror_num,axis,val,verbose=False): + """ + miror_num = 0 / 1 / 3 for M0 / M1 /M3R respectively + and axis: + TX = lateral RX = Roll + TY = vertical RY = Pitch + TZ = longitudinal RZ = Yaw + + "Previously: Move_M0M1 + """ + pv = FMB_mirror_ioc(mirror_num) + previous_position = FMB_mirror_axis_position(mirror_num,axis,verbose=False) + new_position = previous_position[0] + val + FMB_mirror_move(mirror_num,axis,new_position,verbose=False) + + if verbose: + print(pv+" "+str(previous_position[0])+" -> "+str(new_position[0])) + + +def FMB_mirror_scan(mirror_num,start,stop,step): + """ + e.g. Scan_FMB_mirror("m1:TX",-5,5,.25) + + TX = lateral RX = Yaw + TY = vertical RY = Pitch + TZ = longitudinal RZ = Roll + """ + pv = FMB_mirror_ioc(mirror_num) + + # database sets .PREC==0. We want more digits than that. + caput(pv+"_SP.PREC",3) + mda.fillin(pv+"_SP",pv+"_MON",start,stop,step) + + + + +def M0M1_table(run,mirror): + """ + Prints the positions TX / TY / TZ / RX / RY / RZ for either Mirror = 0 or 1 (M0 or M1) for the specified Run + Run='default' give a reasonable starting position after homing + M0M1_SP() will put those values as the set points, you will need to push the Move button + """ + M0M1_Pos=read_dict(M0M1_fpath) + return M0M1_Pos[run][mirror[-1]] + +def M0M1_SP(run,mirror,Go=False): + """ + Gets the values from the mirror position from a previous run and + put values as defined by M0M1_Table as the set points + Go = True / False (default); True to moves to that position + """ + mirror_pos=M0M1_table(run,mirror).split('/') + motor=['TX','TY','TZ','RX','RY','RZ'] + mirror=mirror[-1] + for i in range(len(motor)): + PV="29id_m"+str(mirror)+":"+motor[i]+"_POS_SP" + Val=mirror_pos[i] #float(MirrorPos[i]) + print(PV+" = "+Val) + caput(PV,Val) + sleep(0.5) + if Go: + caput('29id_m'+str(mirror)+':MOVE_CMD.PROC',0,wait=True,timeout=18000) + else: + print(" caput(\'29id_m"+str(mirror)+":MOVE_CMD.PROC\',0)") diff --git a/build/lib/iexcode/instruments/IEX_VPU.py b/build/lib/iexcode/instruments/IEX_VPU.py new file mode 100644 index 0000000000000000000000000000000000000000..6678eb16903a7372b42583b5b4cfae682fa56a56 --- /dev/null +++ b/build/lib/iexcode/instruments/IEX_VPU.py @@ -0,0 +1,528 @@ + + +from math import * +from time import sleep +import numpy.polynomial.polynomial as poly + +from epics import caget, caput + +from iexcode.instruments.utilities import dateandtime, print_warning_message, read_dict +from iexcode.instruments.shutters import main_shutter_check_open +from iexcode.instruments.VLS_PGM import mono_grating_get +from iexcode.instruments.userCalcs import userCalcOut_clear + +IDcal_fpath="/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/Dict_IDCal.txt" + +############################################################################################################## +################################ ID limits and calibration ############################## +############################################################################################################## + +def ID_calc_SP(mono_grating,ID_mode,hv_eV): # Mode = state (0=RCP,1=LCP,2=V,3=H) + """Calculate the ID SP for a given polarization mode and energy; + with Mode = 0 (RCP),1 (LCP), 2 (V), 3 (H) + + Previously: ID_Calc + """ + + + if type(ID_mode)== str: + ID_state=ID_state_mode()[ID_mode] + try: + K=ID_Coef(mono_grating,ID_mode,hv_eV) + ID=poly.polyval(hv_eV,K) + except KeyError: + message_string='Not a valid ID mode!'+"\nValid Modes: "+str(ID_mode_list) + print_warning_message(message_string) + ID=caget("ID29:EnergySeteV") + return round(ID,1) + +############################################################################################################## +################################ ID Functions ############################## +############################################################################################################## + + +def ID_wait_for_permission(): + """ + Monitors the ID permissions and waits for the ID to be in User Mode and then breaks + Checks the status every 30 seconds + + Previously: WaitForPermission + """ + while True: + ID_Access=caget("ID29:AccessSecurity.VAL") + if (ID_Access!=0): + print("Checking ID permission, please wait..."+dateandtime()) + sleep(30) + else: + print("ID now in user mode -"+dateandtime()) + break + +############################################################################################################## +def ID_get_all(verbose=False): + """ + returns dictionart with: ID_Mode, ID_QP_ratio, ID_SP, ID_RBV + + Previously: Get_energy + """ + vals={ + "ID_mode":ID_mode_get(verbose=False), + "ID_QP_ratio":ID_QP_ratio_get(verbose=False), + "ID_sp":ID_SP_get_eV(verbose=False), + "ID_rbv":ID_rbv_get_eV(verbose=False) + } + + if verbose: + print(" ID SP : "+"%.2f" % vals["ID_sp"] , "eV ID mode : "+vals["ID_mode"]) + print(" ID RBV : "+"%.2f" % vals['ID_rbv'], "eV QP mode : "+str(vals['ID_QP_ratio']) +" %") + return vals + +def ID_energy_range(ID_mode=None): + """ + Returns the ID_min_SP, ID_max_SP for a given ID mode + + Previously: ID_Range + """ + if ID_mode == None: + ID_state=caget("ID29:ActualMode") + else: + ID_state = ID_state_mode(ID_mode) + # RCP,LCP, V , H , HN + ID_min_SP = [400,400,440,250,250] + ID_max_SP = 3800 + #hv_min=[390,390,430,245,245] + + return ID_min_SP[ID_state],ID_max_SP + +def ID_mode_list(): + """ + returns the ID_mode_List + current mode = + """ + return ["RCP", "LCP", "V", "H", "HN"] + + +def ID_state_mode(ID_mode): + """ + Returns the state number if mode is a string + Returns the mode string if mode is an int or float + + Previously: ID_State2Mode(which,mode) + """ + try: + ID_mode = ID_mode.upper() + ID_state =ID_mode_list()[ID_mode].index(ID_mode) + return ID_state + + except: + message_string='Not a valid ID mode!'+"\nValid Modes: "+str(ID_mode_list) + print_warning_message(message_string) + +def ID_state_get(): + """ + Returns the current ID state + """ + ID_state = caget("ID29:ActualMode") + +def ID_mode_get(verbose=True): + """ + Returns the current ID mode + """ + ID_state = caget("ID29:ActualMode") + ID_mode = ID_mode_list()[ID_state] + + if verbose: + print('ID mode: '+ID_mode) + return ID_mode + +def ID_mode_set(ID_mode): + """ + writes the desired mode to the correct ID pv + """ + caput("ID29:DesiredMode.VAL",ID_mode,wait=True,timeout=18000) # RCP + + +def ID_ready(verbose=True): + """ + check both the read and busy pv every 2 seconds + + Previously: ID_Ready + """ + while True: + RBV=caget("ID29:Energy.VAL") + checkready=caget("ID29:feedback.VAL") + checkbusy=caget("ID29:BusyRecord") + if (checkready!="Ready") or (RBV < 3.7): + sleep(2) + elif ((checkready=="Ready") and (RBV > 3.7)) and (checkbusy=="Busy"): + caput("ID29:Busy.VAL",0) + else: + break + if verbose: + print("ID Ready") + +def ID_stop(verbose=True): + """ + waits for the ID to be in user mode and then turns it off + + Previously: ID_Stop + """ + ID_wait_for_permission() + caput("ID29:Main_on_off.VAL",1,wait=True,timeout=18000) + + sleep(5) + if verbose: + print("ID is now off") + + +def ID_off(): + """ + calls ID_stop + """ + ID_stop() + + +def ID_start(ID_mode='RCP'): + """ + waits for ID permission and then + starts ID with a specific polarization + mode = \"H\", \"V\", \"RCP\" or \"LCP\" + + """ + + ID_wait_for_permission() + #turning on the ID; default mode = RCP + print("Starting ID - "+dateandtime()) + caput("ID29:EnergySet.VAL",3.8) + caput("ID29:Main_on_off.VAL",0,wait=True,timeout=18000) + ID_ready() + ID_mode_set(ID_mode) + + ID_wait_for_permission() + main_shutter_check_open() + + print('ID is now on, please set your energy') + +def ID_switch_mode(ID_mode): + """ + Change ID polarization; which = 'H', 'V', 'RCP' or 'LCP' + if ID_mode = current mode then does nothing + + WARNING: Does not set the energy + + Previously Switch_IDMode + """ + ID_wait_for_permission() + main_shutter_check_open() + ID_state = ID_state_get() + + try: + if ID_state_mode(ID_mode) != ID_state: + print("Turning ID off...") + ID_stop(verbose=True) + sleep(10) + + print("Switching ID mode, please wait...") + ID_mode_set(ID_mode) + ID_ready() + print("ID Mode:",ID_mode) + except: + print_warning_message("Not a valid ID mode") + +def ID_SP_get(verbose=False): + """ + returns the ID setpoint in keV + """ + ID_SP = caget("ID29:EnergyScanSet.VAL") + if verbose: + print("ID_SP: ", ID_SP) + return ID_SP + +def ID_SP_get_eV(verbose=False): + """ + returns the ID setpoint in eV + """ + ID_SP = ID_SP_get(verbose=False) + if verbose: + print("ID_SP: ", ID_SP) + return ID_SP + +def ID_rbv_get(verbose=False): + """ + returns the readback value for the + """ + ID_RBV = caget("ID29:EnergyRBV") + if verbose: + print("ID_RBV: ", ID_RBV) + return ID_RBV + +def ID_rbv_get_eV(verbose=False): + """ + returns the readback value for the + """ + ID_RBV = ID_rbv_get(verbose=False) + if verbose: + print("ID_RBV: ", ID_RBV) + return ID_RBV + +def ID_restart(): + """ + turns off the ID and turns it back on with the same set point + + Previously: ID_Restart + """ + ID_mode=ID_mode_list[ID_state_get()] + hv=ID_SP_get_eV(verbose=False) + + print("Restarting ID", dateandtime()) + ID_stop(verbose=False) + ID_ready(verbose=False) + + ID_start(verbose=False) + + print("ID is back ON", dateandtime()) + ID_SP_set(hv) + +def ID_SP_set(hv_eV,verbose=True): + """ + "Sets the ID set point to a specific value (hv(eV)) which will not likely be optimum" + + Previously: SetID_Raw + """ + ID_wait_for_permission() + main_shutter_check_open() + + ID_max,ID_min = ID_energy_range() + ID_SP=min(max(hv_eV,ID_min),ID_max)*1.0 + + if hv_eV < ID_min or hv_eV > ID_max: + message_string="Set point out of BL energy range \nPlease select a different energy." + print_warning_message(message_string) + else: + ID_SP_RBV=round(caget("ID29:EnergySet.VAL"),3)*1000 + if ID_SP == ID_SP_RBV: # checks if ID is already at the SP energy + ID_RBV=caget("ID29:EnergyRBV") + if verbose: + print("ID SET : "+"%.1f" % ID_SP, "eV") + print("ID RBV : "+"%.1f" % ID_RBV, "eV") + print(caget('ID29:TableDirection',as_string=True)) + else: + caput("ID29:EnergyScanSet.VAL",ID_SP/1000,wait=True,timeout=18000) + sleep(0.5) + caput("ID29:EnergyScanSet.VAL",(ID_SP+0.001)/1000,wait=True,timeout=18000) + caput('ID29:StartRamp.VAL',1) + + sleep(5) + ID_ready(verbose=False) + + ID_RBV=caget("ID29:EnergyRBV") + print("\nID SET : "+"%.1f" % ID_SP, "eV") + print("ID RBV : "+"%.1f" % ID_RBV, "eV") + print(caget('ID29:TableDirection',as_string=True)) + + ID_diff = abs(ID_RBV-ID_SP) + ID_bw = ID_SP*0.095 + if ID_diff > ID_bw: + sleep(20) + ID_RBV=caget("ID29:EnergyRBV") + ID_diff = abs(ID_RBV-ID_SP) + print("\nID RBV : "+"%.1f" % ID_RBV, "eV") + if ID_diff > ID_bw: + ID_restart + +def ID_energy_set(hv_eV): + """ + Sets optimum ID set point for hv(eV) (max intensity) + and opens the main shutter + + Note that QP is generally not calibrated + + Previously: SetID + """ + ID_mode = ID_mode_list[ID_state_get()] + mono_grating = mono_grating_get() + ID_SP = ID_calc_SP(mono_grating,ID_mode,hv_eV) + + ID_SP(hv_eV) + + +def ID_QP_ratio_get(verbose=True): + """ + gets the read back for the QP ratio + calculate the QP ratio + + + """ + Byq=caget("ID29:ByqRdbk") + Vcoil=caget("ID29:ByRdbk.VAL") + ratio_calc=Byq/Vcoil + ratio_RBV=caget("ID29:QuasiRatio.RVAL") + if verbose: + print("QP ratio =", round(ratio_RBV,3)*100,"%") + print("QP RBV =", ratio_RBV,"%") + + if abs(ratio_RBV-ratio_calc)>1: + message_string="QP RBV and QP calc do not agree \nCheck Interlocks" + print_warning_message(message_string) + return ratio_RBV, ratio_calc + +def ID_QP_mode_set(ID_mode,QP_ratio): + """ + switched to QP mode, if not currently in + sets the QP ratio (QP ration min is 70) and polarization (ID mode) + + does not set the energy, need to use ID_SP + + Previously: Switch_IDQP + """ + QP_min = 70 + if QP_ratio < QP_min: + message_string="QP ratio is too small, setting it to minimum allowed value ("+str(QP_min)+")" + print_warning_message(message_string) + QP_ratio=max(70,QP_ratio) + + ratio_RBV, ratio_calc=ID_QP_ratio_get() + if ratio_RBV != QP_ratio: + ID_stop() + caput("ID29:QuasiRatioIn.C",QP_ratio) + + ID_start(ID_mode) + sleep(15) + + Byq=caget("ID29:ByqRdbk") + Vcoil=caget("ID29:ByRdbk.VAL") + ratio=Byq/Vcoil + ratio_RBV=caget("ID29:QuasiRatio.RVAL") + print("QP ratio =", round(ratio,3)*100,"%") + print("QP RBV =", ratio_RBV,"%") + sleep(15) + +def ID_Coef(grt,ID_mode,hv_eV): # Mode = state (0=RCP,1=LCP,2=V,3=H); + + """Return the ID coeff for a given polarization mode and energy; + with Mode = 0 (RCP),1 (LCP), 2 (V), 3 (H). + Current coefficient dictionary: + /home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/Dict_IDCal.txt + + Previously: ID_Coef + """ + + def ListRange(grt,ID_mode,IDdict): # extract the list of break pts for a given mode/grt + tmp_list=[] + for item in (IDdict[grt][ID_mode]): + tmp_list.append(item[0]) + return tmp_list + + + def FindRange(hv_eV,range_list): # returns the index for the corresponding range + B = [x - hv_eV for x in range_list] + #print(B) + index = [i for (i, x) in enumerate(B) if x > 0] + #print(index) + return(index[0]) + + try: + ID_function=read_dict(IDcal_fpath) + + except KeyError: + print("Unable to read dictionary") + + try: + Lrange = ListRange(grt,ID_mode,ID_function) + Erange = FindRange(hv_eV,Lrange) + K = ID_function[grt][ID_mode][Erange][1] + return K + + except KeyError: + print("WARNING: PLease select one of the following:") + print(" mode 0 = RCP") + print(" mode 1 = LCP") + print(" mode 2 = V") + print(" mode 3 = H") + +def ID_scan_pvs(): + """ + returns the rbv and val for scanning + """ + val_pv="ID29:EnergyScanSeteV" + rbv_pv="ID29:EnergySetRBV" + return val_pv, rbv_pv + +def ID_scan_fillin(mda,scan_dim,start,stop,step,**kwargs): + """ + fills in the scanRecord for scanning the ID set point + + **kwargs => scanRecord.fillin kwargs + """ + #Setting up the ScanRecord for ID in Table mode + val_pv, rbv_pv = ID_scan_pvs() + mda.fillin(scan_dim,val_pv,rbv_pv,start,stop,step,**kwargs) + + +def ID_scan_fillin_table(mda,scan_dim,ID_array,**kwargs): + """ + fills in the scanRecord for scanning the ID set point + + **kwargs => scanRecord.fillin kwargs + """ + #Setting up the ScanRecord for ID in Table mode + val_pv, rbv_pv = ID_scan_pvs() + mda.fillin.table(scan_dim,val_pv,rbv_pv,ID_array,**kwargs) + +############################################################################################################## +############################## ID direction table ############################## +############################################################################################################## + +def ID_Table(): + """ + + Previously: ID_Table + """ + table = caget("ID29:TableDirection") # up = 1 , down = 0 + By = caget("ID29:ByPolaritySet") # pos = 1, neg = 0 + + mode = ID_mode_get() + + if By > 0: + print("\nBy > 0") + if table == 1: # By=1, table = 1 => -1 => A=B + print("table = up") + ID_direction = -1 + elif table == 0: # By=1, table = 0 => +1 => A#B + print("table = down") + ID_direction = 1 + elif By <= 0: + print("\nBy < 0") + if table == 1: # By=0, table = 1 => +1 => A=B + print("table = up") + ID_direction = 1 + elif table == 0: # By=0, table = 0 => -1 => A#B + print("table = down") + ID_direction = -1 + + + if mode == "H" and mode == "RCP": + if By > 0 and table == 0: + print_warning_message("will do a long hysteresis if decreasing energy !!!") +# if Mode == "HN" and Mode == "LCP": +# if By = 0 and table == 1: +# print "WARNING: will do a long hysteresis if decreasing energy !!!" + print("ID direction", ID_direction) + return ID_direction + +def ID_table_userCalcOut(): + """ + # Work in progress + + Previously:ID_Table_CalcOut + """ + n=4 + userCalcOut_clear("b",n) + pvstr="29idb:userCalcOut"+str(n) + caput(pvstr+".DESC","ID_Table") + table="ID29:TableDirection" # up = 1 , down = 0 + By="ID29:ByPolaritySet" # pos = 1, neg = 0 + caput(pvstr+".INPA",table+" CP NMS") + caput(pvstr+".INPB",By+" CP NMS") + caput(pvstr+".CALC$","A#B") + caput(pvstr+".OOPT","On Change") + caput(pvstr+".DOPT","Use CALC") \ No newline at end of file diff --git a/build/lib/iexcode/instruments/IEX_endstations.py b/build/lib/iexcode/instruments/IEX_endstations.py new file mode 100644 index 0000000000000000000000000000000000000000..94ee6e1eb9ce4b609d49ca490ac53f24acb5cf32 --- /dev/null +++ b/build/lib/iexcode/instruments/IEX_endstations.py @@ -0,0 +1,131 @@ +from math import floor +import time + +from epics import caput +""" +Endstation class is used to contain information about ioc, branch, mode + +it makes the default stuff work + +this will prompt for the endstation and will set the default parameters, look at the +init kwargs to see which defaults you can change. +""" +global BL +BL = None + +class Endstation: + """ + used for defining which endstation in which you are running + for short names and ioc info + + BL = endstation('ARPES') + BL.ioc = "ARPES" / "Kappa" / "Test" + BL.mode = "User" / "Staff" / "No Xray" + BL.branch = 'c' / 'd' + BL.mda => mda scanRecord + + """ + + def __init__(self,endstation_name,scan_ioc,xrays,BL_mode,mda_scanRecord): + """ + intializes the several beamline variables + + endstation_name = 'ARPES' / 'Kappa' + + BL = Endstation() + BL.endstation => endstation_name + BL.xrays => True/False + BL.mode => previously: BL_Mode_Set + BL.folder => 'b','c','d' + BL.prefix => 'ARPES_','Kappa_' + BL.ioc => previously: BL_ioc() + BL.mda_filepath + + """ + global BL + endstations_list = ['ARPES','Kappa'] + BL_mode_list = ['user','staff'] + + if self.endstation_name in endstations_list: + self.endstation=endstation_name + else: + print('Not a valid Endstation choice') + print('Endstations: '+endstations_list) + return + + if BL_mode in BL_mode_list: + self.mode = BL_mode + if BL_mode.lower == 'user': + if endstation_name == 'ARPES': + self.folder = 'c' + self.prefix = 'ARPES_' + elif endstation_name == 'Kappa': + self.folder = 'd' + self.prefix = 'Kappa_' + #elif endstation_name == 'Octupole': + #self.folder = 'e' + elif BL_mode.lower == 'staff': + self.folder = 'b' #overwrite folder for staff mode + else: + print('Not a valid BL_mode choice') + print('BL_modes: '+BL_mode_list) + return + + self.xrays = xrays + self.ioc = scan_ioc + self.mda = mda_scanRecord + + + def set_logfile_path(): + """ + sets the default logfile path + """ + +############################################################################################################## +############################## BL commands ############################## +############################################################################################################## +def BL_ioc(): + """ + returns the branch from the Endstation instance + """ + return BL.ioc + +def BL_mode(): + """ + returns the beamline mode, User / Staff / No_Xray + """ + return BL.ioc + +def BL_mda_prefix(): + """ + returns the mda file prefix + """ + return BL.prefix + +def BL_mda_filepath(): + """ + returns the mda file prefix + """ + return BL.filepath + +def scalar_cts(self,integration_time=0.1,verbose=True,**kwargs): + """ + Sets the integration time for the scalers + kwargs: + mcp = True/False to sum mpa + Previously: cts, Kappa counts + """ + + if BL.endstation == 'ARPES': + pass + elif BL.endstation == 'Kappa': + Kappa_scalar_pv = "29idMZ0:scaler1.TP" + mpa_Proc1_pv = "29iddMPA:Proc1:" + + caput(Kappa_scalar_pv,integration_time) + + if kwargs["mpa"]: + caput(mpa_Proc1_pv+'NumFilter',floor(time)) + + if verbose: + print("Integration time set to:", str(time)) \ No newline at end of file diff --git a/build/lib/iexcode/instruments/Kappa.py b/build/lib/iexcode/instruments/Kappa.py new file mode 100644 index 0000000000000000000000000000000000000000..18c98109e657face5c89a1a35b50e2ae272c9966 --- /dev/null +++ b/build/lib/iexcode/instruments/Kappa.py @@ -0,0 +1,1127 @@ +import numpy as np +from time import sleep +from math import floor + +from epics import caget, caput,PV + +from iexcode.instruments.IEX_endstations import * +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.logfile import logfile_name_set,logfile_header + +from iexcode.instruments.conversions_constants import * +from iexcode.instruments.utilities import * +from iexcode.instruments.userCalcs import userStringSeq_clear, userStringSeq_pvs + +from iexcode.instruments.scanRecord import * +from iexcode.instruments.Motors import * +from iexcode.instruments.xrays import * +from iexcode.instruments.current_amplifiers import * +from iexcode.instruments.gate_valves import valve_close, branch_valves +from iexcode.instruments.shutters import branch_shutter_close +from iexcode.instruments.slits import slit3D_get + +from iexcode.instruments.Kappa_det import * +from iexcode.instruments.spec_stuff import folders_spec + + + +############################################################################# +def Kappa_init(set_folders=False,reset=False,**kwargs): + """ + + set_folders: sets the mda and EA folders; default => False + reset: resets the scanRecord (detectors,triggers...) + **kwargs: + xrays: sets global variable; default => True + BL_mode: 'user' / 'staff' => used for saving, detectors... + """ + kwargs.setdefault('scan_ioc','29idKappa:') + kwargs.setdefault('xrays',True) + kwargs.setdefault('BL_mode','user') + + #scan + if kwargs['BL_mode']=='staff': + detector_dictionary = staff_detector_dictionary() + else: + detector_dictionary = Kappa_detector_dictionary() + + mda_scanRecord = ScanRecord(kwargs['scan_ioc'],detector_dictionary, + Kappa_trigger_dictionary(),Kappa_scan_before_sequence(),Kappa_scan_after_sequence()) + + #endstation + global BL + BL=Endstation('Kappa',kwargs['scan_ioc'],kwargs['xrays'],kwargs['BL_mode'],mda_scanRecord) + + #global detectors + global tey, d3, d4, mesh, Kappa_scaler_pv + tey = SRS("29idMZ0:scaler1.S2", '29idd:A1') + d3 = SRS("29idMZ0:scaler1.S3", '29idd:A2') + d4 = SRS("29idMZ0:scaler1.S4", '29idd:A3') + mesh = SRS("29idMZ0:scaler1.S14", '29idd:A4') + Kappa_scaler_pv = '29idMZ0:scaler1.CNT' + + global tthdet + tthdet = Kappa_Detector() + + #setting folders + if 'set_folders': + if BL.mode == 'staff': + user_name = 'staff' + else: + user_name = input('user name: ') + folders_Kappa(user_name,**kwargs) + + #resetting + if 'reset': + Kappa_reset() + + #motors + global Kappa_Motors + physical_motors = ['x','y','z','tth','kth','kap','kphi'] + psuedo_motors = ['th','chi','phi'] + Kappa_Motors = Motors('Kappa',Kappa_motor_dictionary(),physical_motors,psuedo_motors) + +############################################################################################################## +############################## detectors and motors ############################## +############################################################################################################## +def Kappa_detector_list(): + """ + list of detectors to trigger + + Previously: part of Detector_List + """ + ca_list=[] + return ca_list + + +def Kappa_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:LS331:TC1:SampleA", + 24:"29idd:LS331:TC1:SampleB", + } + m3r={ + 25:"29id_ps6:Stats1:CentroidX_RBV", + 26:"29id_ps6:Stats1:SigmaX_RBV", + 27:"29id_ps6:Stats1:CentroidTotal_RBV", + } + scalers={ + 31:"29idMZ0:scaler1.S14", + 32:"29idMZ0:scaler1.S2", + 33:"29idMZ0:scaler1.S3", + 34:"29idMZ0:scaler1.S4", + 35:"29idMZ0:scaler1.S5", + 36:"29idMZ0:scaler1_calc1.B", + 37:"29idMZ0:scaler1_calc1.C", + 38:"29idMZ0:scaler1_calc1.D", + 39:"29idMZ0:scaler1_calc1.E", + } + mpa={ + 30:"29iddMPA:det1:TotalRate_RBV", + 41:"29iddMPA:Stats1:Total_RBV", + 42:"29iddMPA:Stats2:Total_RBV", + 43:"29iddMPA:Stats3:Total_RBV", + 44:"29iddMPA:Stats4:Total_RBV", + 45:"29iddMPA:Stats5:Total_RBV", + } + hkl={ + 46:'<H>', + 47:'<K>', + 48:'<L>' + } + motors={ + 51:"29idKappa:m8.RBV", + 52:"29idKappa:m7.RBV", + 53:"29idKappa:m1.RBV", + 54:"29idKappa:m9.RBV", + 55:"29idKappa:Euler_ThetaRBV", + 56:"29idKappa:Euler_ChiRBV", + 57:"29idKappa:Euler_PhiRBV", + } + #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(mpa) + det_dict.update(motors) + if kwargs['add_vortex']: + det_dict.update(vortex) + + return det_dict + + +def Kappa_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':2, + 'y':3, + 'z':4, + 'tth':9, + 'kth':8, + 'kap':7, + 'kphi':1, + } + Euler_motors={ + 'th':'29idKappa:Euler_Theta', + 'chi':'29idKappa:Euler_Chi', + 'phi':'29idKappa:Euler_Phi' + } + motor_dictionary = {} + for name in motor_nums.keys(): + pv = '29idKappa:m'+str(motor_nums[name]) + motor_dictionary.update({name:[pv+'.VAL',pv+'.SPMG',pv]}) + + for name in Euler_motors.keys(): + pv = Euler_motors[name] + motor_dictionary.update({name:[pv+'RBV',pv,'',pv]}) + + return motor_dictionary + +def Kappa_extra_pvs(): + """ + used to get the PV associated with a given pnuemonic + + """ + d={ + "TA":"29idd:LS331:TC1:Control", + "TB":"29idd:LS331:TC1:SampleB", + "det_nam":'29idKappa:userStringSeq6.STR1', + "HV":'29idKappa:userCalcOut10.OVAL', + "centroid":'29id_ps6:Stats1:CentroidX_RBV' + } + return d + +def Kappa_kth_offset_get(): + caget("29idKappa:userCalcOut1.G") + +def Kappa_kth_offset_set(val): + caput("29idKappa:userCalcOut1.G",val) + + +############################################################################################################# +############################## setting folder ############################## +############################################################################################################## +def folders_Kappa(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,BL.folder,user_name,BL.ioc,kwargs['ftp']) + + # Create User Folder: + make_user_folders(run,BL.folder,user_name,BL.endstation,ftp=kwargs['ftp']) + sleep(5) + + if kwargs["set_folders"]: + # Set up MDA folder: + folder_mda(run,BL.folder,user_name,BL.prefix,BL.ioc) + logfile_name_set(BL.endstation) + logfile_header(BL.endstation,BL.ioc,Kappa_log_header()) + + + # Set up SPEC folder: + folders_spec(run,BL.folder,user_name) + + # Set up MPA folder: + #Folder_MPA(run,BL.folder,user_name) + + #resetting + if 'reset': + Kappa_reset() + +def Kappa_reset(): + """ + resets scanRecord, current amplifiers, mono limits and lakeshore + """ + #resetting the scanRecord + BL.mda.reset() + + #resetting the current amplifiers + if BL.xray: + ca_reset_all() + + #resetting mono and anyother beamline stuff + if BL.xrays: + xrays_reset() + + #reseting the Kappa Lakeshore + + #motors home and sync + SmarAct_motors_home() + PI_motors_sync() + Euler_motors_sync() + +def Kappa_reminder_list(ioc): + """ + resets scanRecord, current amplifiers, mono limits and synchs motors + """ + mda.reset() + if BL.xray: + ca_reset_all() + + + + + +############################################################################################################## +############################## get all ############################## +############################################################################################################## +def Kappa_get_all(verbose=True): + """ + returns a dictionary with the current status of the Kappa endstation and exit slit + """ + vals = {} + + #sample postion + motor_dictionary = Kappa_motor_dictionary() + for motor in motor_dictionary.keys(): + vals[motor]=Kappa_Motors.get(motor,verbose=False) + + #endstation pvs + extra_pvs = Kappa_extra_pvs() + for key in extra_pvs.keys(): + vals.update(key,caget(extra_pvs[key])) + + #beamline info + if BL.xray: + beamline_info = xrays_get_all() + vals.update(beamline_info) + + mesh.get() + vals.update({'mesh':mesh.current}) + + if verbose: + for key in vals: + print(key+" = "+vals[key]) + return vals + +############################################################################################################## +############################## logging ############################## +############################################################################################################## +def Kappa_log_header(): + """ + header for the log file + """ + h = "scan,motor,start,stop,step,x,y,z,tth,kth,kap,kphi,TA,TB," + 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 = {'Kappa':h} + return header_list + +def Kappa_log_entries(): + """ + enstation info for log file + + Previously: scanlog + """ + vals = Kappa_get_all(verbose=False) + x = vals['x'] + y = vals['y'] + z = vals['z'] + tth = vals['tth'] + kth = vals['kth'] + kap = vals['kap'] + kphi = vals['kphi'] + + TA = vals['TA'] + TB = vals['TB'] + mesh.get() + tey_current = tey.current + mesh_current = mesh.current + det_name = tthdet.name + mpa_HV = mpa_HV_get() + 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 + +############################################################################################################## +############################## Kappa scanRecord ############################## +############################################################################################################## +def Kappa_scan_before_sequence(**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(BL.ioc, seq_num) + + #clear and write the before scan user sequence + userStringSeq_clear(BL.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 Kappa_scan_after_sequence(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'] + + after_scan_pv,after_scan_proc = userStringSeq_pvs(BL.ioc, seq_num) + + #clear and write the after scan user sequence + userStringSeq_clear(BL.ioc,seq_num) + caput(after_scan_pv+".DESC","After Scan") + + scan_pv = 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 Kappa_detector_triggers_sequence(**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(BL.ioc, seq_num) + + #clear the userStringSeq + userStringSeq_clear(BL.ioc,seq_num=kwargs['seq_num']) + caput(detector_triggers_pv+".DESC","Kappa_Trigger1") + + scaler_pv = Kappa_scaler_pv + + caput(detector_triggers_pv+".LNK" +str(1),scaler_pv) + caput(detector_triggers_pv+".WAIT"+str(1),"After"+str(last)) + + ca_list = Kappa_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 Kappa_trigger_dictionary(): + """ + need to do something + """ + trigger_dictionary = { + 1:Kappa_detector_triggers_sequence(), + } + return trigger_dictionary + + + + +############################################################################################################## +############################## Kappa Motor Scan Set Up ############################## +############################################################################################################## + + +def Kappa_sample_Euler_list(): + """ + returns list of motor names used by mvsample + """ + motor_list = ['th','chi','phi'] + return motor_list + + +def Kappa_4c_mprint(): + """ + returns the dictionary of the current sample position in 4c units + + motors=['th','chi','phi'] + + Previously: diffracto? + """ + positions={} + motors=Kappa_sample_Euler_list() + for motor in motors: + positions.update(motor,Kappa_motor_dictionary()(motor)[0]) + return positions + +def Kappa_4c_move(th_chi_phi_list): + """ + moves the sample in 4c (Euler) units + Previously: mv4C + """ + motor_list=Kappa_sample_Euler_list() + for motor,i in enumerate(motor_list): + Kappa_Motors.move(motor,motor_list[i],wait=True,verbose=False) + + for motor,i in enumerate(motor_list): + Kappa_Motors.get(motor,verbose=True) + + + +def SmarAct_motor_list(): + """ + returns a list of the motor names for the SmarAct motors in the Kappa + """ + return ['x','y','z'] + +def SmarAct_motors_home(): + """ + Homes the piezo (x,y,z). Home position is middle of travel + + Previously: Home_SmarAct_Motor + """ + motor_dictionary = Kappa_motor_dictionary() + for motor in SmarAct_motor_list(): + pv = motor_dictionary[motor][3] + caput(pv+'.HOMF',1) + sleep(10) + print('SamrAct motors VAL homed') + +def SmarAct_enable(): + motor_dictionary = Kappa_motor_dictionary() + for motor in SmarAct_motor_list(): + spmg = motor_dictionary[motor][2] + caput(spmg,3) # 3=Go + +def SmarAct_disable(): + motor_dictionary = Kappa_motor_dictionary() + for motor in SmarAct_motor_list(): + spmg = motor_dictionary[motor][2] + caput(spmg,0) # 1=Stop + +def PI_motor_list(): + """ + returns a list of the motor names for the SmarAct motors in the Kappa + """ + return ['kap','kth','tth'] + +def PI_motors_sync(): + motor_dictionary = Kappa_motor_dictionary() + for motor in PI_motor_list(): + val_pv = motor_dictionary[motor][1] + rbv_pv = motor_dictionary[motor][0] + current_rbv=caget(rbv_pv) + caput(val_pv,current_rbv) + print('PI motors VAL synced to RBV') + +def Euler_motors_sync(): + """ + Syncs the Euler motores + + Previously: Sync_Euler_Motor + """ + caput('29idKappa:Kappa_sync.PROC',1) + sleep(1) + caput('29idKappa:Kappa_sync.PROC',1) + print('Euler motors VAL/RBV synced to physical motors') + +def Kappa_kphi_reset_zero(val): + """ + resets the zero for the kphi motor + + """ + kphi_pv = Kappa_motor_dictionary()['kphi'][3] + caput(kphi_pv+".SET",1) # 1 = Set + sleep(0.5) + caput("kphi_pv.VAL",val) + sleep(0.5) + caput(kphi_pv+".SET",0) # 0 = Use + print("\nkphi has been reset to " +str(val)) + +def Kappa_tth_reset_zero(): + """ + resets the zero for the tth motor + """ + tthdet.tth0_set() + + + +def Kappa_th2th_scan_sensitivity(th_table,gain_num_table,gain_unit_table,detector=tey,**kwargs): + """ + Scans th2th with variable gain on SRS# (srs_num). + Gain is specified for a given th2th range by building tables as follow: + + th_table = np.array([]) + gain_num_table = np.array([]) + gain_unit_table = np.array([]) + + Example: + for i in RangeUp(10,20,0.5): + th_table = np.append(th_table, i) + gn_table = np.append(gn_table, gain_dict(2)) + gu_table = np.append(gu_table, unit_dict('mA')) + for i in RangeUp(20.5,40,0.5): + th_table = np.append(th_table, i) + gn_table = np.append(gn_table, gain_dict(1)) + gu_table = np.append(gu_table, unit_dict('uA')) + for i in RangeUp(40.5,60,0.5): + th_table = np.append(th_table, i) + gn_table = np.append(gn_table, gain_dict(10)) + gu_table = np.append(gu_table, unit_dict('pA')) + + kwargs: + scan_dim: 1 (default) + cts: integration time for scalers and mpa/mcp => 0.1 (default) + execute: True/False to start the scan => True (default) + + Previoulsy: Scan_th2th_sensitivity + """ + kwargs.setdefault('cts',0.1) + kwargs.setdefault('execute',True) + + kth_offset = Kappa_kth_offset_get() + + motor_dictionary = Kappa_motor_dictionary() + kth_val,kth_rbv,kth_spmg,kth_pv = motor_dictionary['kth'] + tth_val,tth_rbv,tth_spmg,tth_pv = motor_dictionary['tth'] + + detector_pv = detector._srs_pv + gain_num_pv = detector_pv + "sens_num.VAL" + gain_unit_pv= detector_pv + "sens_unit.VAL" + + kth_table = th_table + kth_offset + tth_table = 2*th_table + + kwargs.update("positioner_num",1) + mda.fillin_table(kth_val,kth_rbv,kth_table,**kwargs) + + kwargs.update("positioner_num",2) + mda.fillin_table(tth_val,tth_rbv,tth_table,**kwargs) + + kwargs.update("positioner_num",3) + mda.fillin_table(gain_num_pv,"",gain_num_table,**kwargs) + + kwargs.update("positioner_num",4) + mda.fillin_table(gain_unit_pv,"",gain_unit_table,**kwargs) + + print("\nDon't forget to clear extra positionners at the end of the scan if you were to abort the script using the function:") + print(" Clear_Scan_Positioners('Kappa',1)") + + scaler_cts(kwargs['cts'],verbose=False) + if kwargs['execute']: + mda.go(**kwargs) + + #clean up after scan + mda.table_reset_after(**kwargs) + scaler_cts(verbose=False) + +def Kappa_scan_th2th(tth_start,tth_stop,tth_step,th_offset,**kwargs): + """ + Used for a linear (not table) scan where th = tth /2 + th_offset + **kwargs + scan_dim: 1 (default) + cts: integration time for scalers and mpa/mcp => 0.1 (default) + execute: True/False to start the scan => True (default) + + Previously: scanth2th + """ + kwargs.setdefault('scan_dim',1) + kwargs.setdefault('cts',0.1) + kwargs.setdefault('execute',True) + + th_start = (tth_start)/2+th_offset + th_stop = (tth_stop)/2+th_offset + th_step = int(tth_step/2) + + print('tth: '+str(tth_start)+"/"+str(tth_stop)+"/"+str(tth_step)) + print('th: '+str(th_start)+"/"+str(th_stop)+"/"+str(tth_step/2.0)) + + #write to the scanRecord + th_val,th_rbv,th_spmg,th_pv = Kappa_motor_dictionary['th'] + tth_val,tth_rbv,tth_spmg,tth_pv = Kappa_motor_dictionary['tth'] + + kwargs.update("positioner_num",2) + BL.mda.fillin(th_val,th_rbv,th_start,th_stop,th_step,**kwargs) + + kwargs.update("positioner_num",1) + BL.mda.fillin(tth_val,tth_rbv,tth_start,tth_stop,tth_step,**kwargs) + + scaler_cts(kwargs['cts'],verbose=False) + if kwargs['execute']: + BL.mda.go(**kwargs) + + #clean up after scan + scaler_cts(verbose=False) + + +def scan_th2th_table(tth_table,th0,**kwargs): + """ + Create a table for tth, e.g.: + mytable_tth=[] + for q in range(2,41,1): + mytable_tth.append(q) + print(mytable_tth) + + th0 = th value at grazing incidence + cts = counting time (default is 1s) + + **kwargs + scan_dim: 1 (default) + cts: integration time for scalers and mpa/mcp => 0.1 (default) + execute: True/False to start the scan => True (default) + + Previously: scanth2th_table + + """ + kwargs.setdefault('cts',0.1) + kwargs.setdefault('execute',True) + + tth_table=np.asarray(tth_table) + th_table=tth_table/2.0+th0 + + th_val,th_rbv,th_spmg,th_pv = Kappa_motor_dictionary['th'] + tth_val,tth_rbv,tth_spmg,tth_pv = Kappa_motor_dictionary['tth'] + + #write to the scanRecord + kwargs.update("positioner_num",1) + BL.mda.fillin_table(tth_val,tth_rbv,tth_table,**kwargs) + + kwargs.update("positioner_num",2) + BL.mda.fillin_table(th_val,th_rbv,th_table,**kwargs) + BL.mda.positioner_after_scan(after="STAY") + + + scaler_cts(kwargs['cts'],verbose=False,**kwargs) + if kwargs['execute']: + BL.mda.go(**kwargs) + + #clean up after scan + BL.mda.table_reset_after() + scaler_cts(verbose=False) + BL.mda.positioner_after_scan(after="PRIOR POS",**kwargs) + + + + +############################################################################################################# +############################## Preset Positions ############################## +############################################################################################################## +def KappaTransfer_StrSeq(): + #User= [ DESC, x, y, z, tth, kth, kap, kphi] + User = ["Kappa Transfer",0, -2650, -650, 0, 57, 0, -88] + n=4 + KappaPreset_StrSeq(n,User) + + +def KappaGrazing_StrSeq(): #Need to determine positions and then add to the Kappa graphic + #Dial= [ DESC, x, y, z, tth, kth, kap, kphi] + User = ["Kappa Grazing",0, 0, 0, 0, 57.045, 134.76,57.045] + n=3 + KappaPreset_StrSeq(n,User) + +def Kappa_ResetPreset(): + KappaGrazing_StrSeq() + KappaTransfer_StrSeq() + + + + + + + + + + +############################################################################################################## +############################## Kappa light ############################## +############################################################################################################## +def Kappa_light(ON_OFF): + """ + Previously:light + """ + light_pv = '29idd:Unidig1Bo0' + if ON_OFF.lower() == 'on': + light=0 + elif ON_OFF.lower() == 'off': + light=1 + caput(light_pv,light) + print(("Turning light "+ON_OFF+".")) + + + + +def Kappa_detector_triggers_strSeq(**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(BL.ioc, seq_num) + + #clear the userStringSeq + userStringSeq_clear(BL.ioc,seq_num=kwargs['seq_num']) + caput(detector_triggers_pv+".DESC","Kappa_Trigger1") + + #no triggers see ARPES_detector_triggers_sequence for example + + return detector_triggers_proc + + + + + + +def KappaPreset_StrSeq(n,User): + scanIOC="Kappa" + motorIOC="29idKappa:" + motor = ["m2","m3","m4","m9","m8","m7","m1"] + strSeq_pv = userStringSeq_clear(mda,n) + + if User[0] == "Kappa Grazing": phi0= 0 + if User[0] == "Kappa Transfer": phi0= 57 + caput(strSeq_pv+".DESC",User[0]) + caput(strSeq_pv+".LNK1", "29idKappa:userCalcOut9.A CA NMS") # MPA HV pV + caput(strSeq_pv+".DO1",0) # MPA HV = 0 + caput(strSeq_pv+".WAIT1","Wait") # Wait for completion + caput(strSeq_pv+".LNK2", "29idKappa:m1.VAL CA NMS") # phi = phi0 + caput(strSeq_pv+".DO2",phi0) + caput(strSeq_pv+".WAIT2","Wait") # Wait for completion + for i in range(3,10): + caput(strSeq_pv+".LNK"+str(i),motorIOC+motor[i-3]+".VAL CA NMS") + caput(strSeq_pv+".DO"+str(i),User[i-2]) + if i < 9: + caput(strSeq_pv+".WAIT"+str(i),"After8") + + + + + + + + +def Bragg_Angle_CalcOut(d,eV,l): + n=7 + userCalcOut_pv = userCalcOut_clear(mda,n) + + h=4.135667516e-15 + c=299792458 + f=h*c*1e9*10 + caput(userCalcOut_pv+"DESC","Bragg_Angle") + caput(userCalcOut_pv+"A",d) + caput(userCalcOut_pv+"B",l) + caput(userCalcOut_pv+"C",eV) + caput(userCalcOut_pv+"D",np.pi) + caput(userCalcOut_pv+"E",f) + caput(userCalcOut_pv+".CALC$","ASIN(B*E/(C*"+str(2)+"*A))*"+str(180)+"/D") + +############################################################################################################## +######################## Scan Temp and Pressure ############################## +############################################################################################################## +def Kappa_temperature_pressure_scan(scan_dim=1): + """ + starts scan to monitor temperature and pressure in the kappa chamber + + Previously: Kappa_ScanTempPres + """ + + pv="29id"+BL.mda.ioc+":scan"+str(scan_dim) + #Clear all scan pvs + caput(pv+".CMND",6) + #Set detectors + caput(pv+".D01PV","29idd:tc1:getVal_A.VAL") + caput(pv+".D02PV","29idd:tc1:getVal_B.VAL") + caput(pv+".D03PV","29idb:VS11D.VAL") + #time scan + BL.mda.time_go() + + + +############################################################################################################## +############################## Kappa safestate ############################## +############################################################################################################## +def Kappa_safe_state(**kwargs): + """ + puts the C-branch in a safe state, + **kwargs + MPA_off = True; turns off EA HV + shutter_close = True; closes the D-shutter + valve_close = True; closes the D-valve + """ + kwargs.setdefault("MPA_off",True) + kwargs.setdefault("shutter_close",True) + kwargs.setdefault("valve_close",True) + + if kwargs["EA_off"]: + try: + mpa_HV_off() + except: + print('MPA is not running') + + if kwargs['valve_close']: + valve_close(branch_valves('d'), verbose=True) + + if kwargs['shutter_close']: + branch_shutter_close('d') + +############################################################################################################## +############################## Kappa motors ############################## +############################################################################################################## +### x ### +def mvx(val,**kwargs): + """ moves x motor in the endstation""" + Kappa_Motors.move('x',val,**kwargs) + +def dmvx(val): + """ relative x motor in the endstation""" + Kappa_Motors.move('x',val,relative=True) + +def scanx(start,stop,step,**kwargs): + """ scans the x motor in the endstation""" + Kappa_Motors.scan("x",start,stop,step,**kwargs) + +def dscanx(start,stop,step): + """relative scans of the x motor in the endstation """ + Kappa_Motors.scan("x",start,stop,step,relative=True) + +### y ### +def mvy(val,**kwargs): + """ moves y motor in the endstation""" + Kappa_Motors.move('y',val,**kwargs) + +def dmvy(val): + """ relative y motor in the endstation""" + Kappa_Motors.move('y',val,relative=True) + +def scany(start,stop,step,**kwargs): + """ scans the y motor in the endstation""" + Kappa_Motors.scan("y",start,stop,step,**kwargs) + +def dscany(start,stop,step): + """relative scans of the y motor in the endstation """ + Kappa_Motors.scan("y",start,stop,step,relative=True) + +### z ### +def mvz(val,**kwargs): + """ moves z motor in the endstation""" + Kappa_Motors.move('z',val,**kwargs) + +def dmvz(val): + """ relative z motor in the endstation""" + Kappa_Motors.move('z',val,relative=True) + +def scanz(start,stop,step,**kwargs): + """ scans the z motor in the endstation""" + Kappa_Motors.scan("z",start,stop,step,**kwargs) + +def dscanz(start,stop,step): + """relative scans of the z motor in the endstation """ + Kappa_Motors.scan("z",start,stop,step,relative=True) + +### kth ### +def mvkth(val,**kwargs): + """ moves kth motor in the endstation""" + Kappa_Motors.move('kth',val,**kwargs) + +def dmvkth(val): + """ relative kth motor in the endstation""" + Kappa_Motors.move('kth',val,relative=True) + +def scankth(start,stop,step,**kwargs): + """ scans the kth motor in the endstation""" + Kappa_Motors.scan("kth",start,stop,step,**kwargs) + +def dscankth(start,stop,step): + """relative scans of the kth motor in the endstation """ + Kappa_Motors.scan("kth",start,stop,step,relative=True) + +### kphi ### +def mvkphi(val,**kwargs): + """ moves kphi motor in the endstation""" + Kappa_Motors.move('kphi',val,**kwargs) + +def dmvkphi(val): + """ relative kphi motor in the endstation""" + Kappa_Motors.move('kphi',val,relative=True) + +def scankphi(start,stop,step,**kwargs): + """ scans the kphi motor in the endstation""" + Kappa_Motors.scan("kphi",start,stop,step,**kwargs) + +def dscankphi(start,stop,step): + """relative scans of the kphi motor in the endstation """ + Kappa_Motors.scan("kphi",start,stop,step,relative=True) + +### kap ### +def mvkap(val,**kwargs): + """ moves kap motor in the endstation""" + Kappa_Motors.move('kap',val,**kwargs) + +def dmvkap(val): + """ relative kap motor in the endstation""" + Kappa_Motors.move('kap',val,relative=True) + +def scankap(start,stop,step,**kwargs): + """ scans the kap motor in the endstation""" + Kappa_Motors.scan("kap",start,stop,step,**kwargs) + +def dscankap(start,stop,step): + """relative scans of the kap motor in the endstation """ + Kappa_Motors.scan("kap",start,stop,step,relative=True) + +### tth ### +def mvtth(val,**kwargs): + """ moves tth motor in the endstation""" + Kappa_Motors.move('tth',val,**kwargs) + +def dmvtth(val): + """ relative tth motor in the endstation""" + Kappa_Motors.move('tth',val,relative=True) + +def scantth(start,stop,step,**kwargs): + """ scans the tth motor in the endstation""" + Kappa_Motors.scan("tth",start,stop,step,**kwargs) + +def dscantth(start,stop,step): + """relative scans of the tth motor in the endstation """ + Kappa_Motors.scan("tth",start,stop,step,relative=True) + +### th ### +def mvth(val,**kwargs): + """ moves th motor in the endstation""" + Kappa_Motors.move('th',val,**kwargs) + +def dmvth(val): + """ relative th motor in the endstation""" + Kappa_Motors.move('th',val,relative=True) + +def scanth(start,stop,step,**kwargs): + """ scans the th motor in the endstation""" + Kappa_Motors.scan("th",start,stop,step,**kwargs) + +def dscanth(start,stop,step): + """relative scans of the th motor in the endstation """ + Kappa_Motors.scan("th",start,stop,step,relative=True) + +### chi ### +def mvchi(val,**kwargs): + """ moves chi motor in the endstation""" + Kappa_Motors.move('chi',val,**kwargs) + +def dmvchi(val): + """ relative chi motor in the endstation""" + Kappa_Motors.move('chi',val,relative=True) + +def scanchi(start,stop,step,**kwargs): + """ scans the chi motor in the endstation""" + Kappa_Motors.scan("chi",start,stop,step,**kwargs) + +def dscanchi(start,stop,step): + """relative scans of the chi motor in the endstation """ + Kappa_Motors.scan("chi",start,stop,step,relative=True) + +### phi ### +def mvphi(val,**kwargs): + """ moves phi motor in the endstation""" + Kappa_Motors.move('phi',val,**kwargs) + +def dmvphi(val): + """ relative phi motor in the endstation""" + Kappa_Motors.move('phi',val,relative=True) + +def scanphi(start,stop,step,**kwargs): + """ scans the phi motor in the endstation""" + Kappa_Motors.scan("phi",start,stop,step,**kwargs) + +def dscanphi(start,stop,step): + """relative scans of the phi motor in the endstation """ + Kappa_Motors.scan("phi",start,stop,step,relative=True) + +### uan moves tth and th simultaneously +def uan(tth,th): + """ Moves tth and th motors simultaneously in the in the Kappa chamber + """ + #move tth and th + mvth(th,wait=False) + mvtth(tth,wait=False) + sleep(0.2) + + while True: + status = Kappa_Motors.status() + if status == 0: + sleep(0.2) + else: + tth_RBV=round(Kappa_Motors.get('tth',verbose=False),3) + th_RBV=round(Kappa_Motors.get('th',verbose=False),3) + print('tth='+str(tth_RBV)+' th='+str(th_RBV)) + break + +######## mprint and mvsample ################### +def mprint(): + """ + prints current position of the physical motors + """ + Kappa_Motors.mprint() + +def mvsample(position_list): + """ + moves the sample to the position sepcified by position_list + position_list = ['description',x,y,z,th,chi,phi] + + Previously: sample + """ + Kappa_Motors.mvsample(position_list) \ No newline at end of file diff --git a/build/lib/iexcode/instruments/Kappa_Euler.py b/build/lib/iexcode/instruments/Kappa_Euler.py new file mode 100644 index 0000000000000000000000000000000000000000..42dfe2f1bac9ec223a1c6a78a4d20ab9f32720bf --- /dev/null +++ b/build/lib/iexcode/instruments/Kappa_Euler.py @@ -0,0 +1,120 @@ +import numpy as np +from epics import caget, caput + +from iexcode.instruments.userCalcs import userCalcOut_clear +from iexcode.instruments.IEX_endstations import mda +from iexcode.instruments.userCalcs import userCalcOut_clear + +#### Obsolete? + +def Bragg_Index_CalcOut(d,eV,th): + n=8 + userCalcOut_pv = userCalcOut_clear(mda,n) + + h=4.135667516e-15 + c=299792458 + f=h*c*1e9*10 + + caput(userCalcOut_pv+".DESC","Bragg_Index") + caput(userCalcOut_pv+".A",d) + caput(userCalcOut_pv+".B",th) + caput(userCalcOut_pv+".C",eV) + caput(userCalcOut_pv+".D",np.pi) + caput(userCalcOut_pv+".E",f) + caput(userCalcOut_pv+".CALC$","SIN(B*D/"+str(180)+")*"+str(2)+"*A*C/E") + + + +def KtoE_th_CalcOut(): + n=1 + userCalcOut_pv = userCalcOut_clear(mda,n) + + caput(userCalcOut_pv+".DESC","KtoE_th") + caput(userCalcOut_pv+".INPA","29idKappa:m8.RBV CP NMS") #A=kth + caput(userCalcOut_pv+".INPB","29idKappa:m7.RBV CP NMS") #B=kap + caput(userCalcOut_pv+".INPC","29idKappa:m1.RBV CP NMS") #C=kphi + caput(userCalcOut_pv+".D",3.141592653589793) + caput(userCalcOut_pv+".E",180) + caput(userCalcOut_pv+".F",50) + caput(userCalcOut_pv+".H",57.045) + caput(userCalcOut_pv+".CALC$","((A-(G-H))*D/E-ATAN(TAN(B*D/E/2.0)*COS(F*D/E)))*E/D") + caput(userCalcOut_pv+".DOPT",0) # Use CAL + +def KtoE_chi_CalcOut(): + n=2 + userCalcOut_pv = userCalcOut_clear(mda,n) + + caput(userCalcOut_pv+".DESC","KtoE_chi") + caput(userCalcOut_pv+".INPA","29idKappa:m8.RBV CP NMS") #A=kth + caput(userCalcOut_pv+".INPB","29idKappa:m7.RBV CP NMS") #B=kap + caput(userCalcOut_pv+".INPC","29idKappa:m1.RBV CP NMS") #C=kphi + caput(userCalcOut_pv+".D",3.141592653589793) + caput(userCalcOut_pv+".E",180) + caput(userCalcOut_pv+".F",50) + caput(userCalcOut_pv+".CALC$","(2*ASIN(SIN(B*D/E/2.0) * SIN(F*D/E)))*E/D") + caput(userCalcOut_pv+".DOPT",0) # Use CAL + +def KtoE_phi_CalcOut(): + n=3 + userCalcOut_pv = userCalcOut_clear(mda,n) + + caput(userCalcOut_pv+".DESC","KtoE_phi") + caput(userCalcOut_pv+".INPA","29idKappa:m8.RBV CP NMS") #A=kth + caput(userCalcOut_pv+".INPB","29idKappa:m7.RBV CP NMS") #B=kap + caput(userCalcOut_pv+".INPC","29idKappa:m1.RBV CP NMS") #C=kphi + caput(userCalcOut_pv+".D",3.141592653589793) + caput(userCalcOut_pv+".E",180) + caput(userCalcOut_pv+".F",50) + caput(userCalcOut_pv+".CALC$","(C*D/E-ATAN(TAN(B*D/E/2.0)*COS(F*D/E)))*E/D") + caput(userCalcOut_pv+".DOPT",0) # Use CAL + + + + +def EtoK_kth_CalcOut(): + n=4 + userCalcOut_pv = userCalcOut_clear(mda,n) + + caput(userCalcOut_pv+".DESC","EtoK_kth") + caput(userCalcOut_pv+".INPA","29idKappa:userCalcOut1.VAL CP NMS") #A=th + caput(userCalcOut_pv+".INPB","29idKappa:userCalcOut2.VAL CP NMS") #B=chi + caput(userCalcOut_pv+".INPC","29idKappa:userCalcOut3.VAL CP NMS") #C=phi + caput(userCalcOut_pv+".D",3.141592653589793) + caput(userCalcOut_pv+".E",180) + caput(userCalcOut_pv+".F",50) + caput(userCalcOut_pv+".CALC$","(A*D/E-ASIN(-TAN(B*D/E/2.0)/TAN(F*D/E)))*E/D") + caput(userCalcOut_pv+".DOPT",0) # Use CAL + +def EtoK_kap_CalcOut(): + n=5 + userCalcOut_pv = userCalcOut_clear(mda,n) + + caput(userCalcOut_pv+".DESC","EtoK_kap") + caput(userCalcOut_pv+".INPA","29idKappa:userCalcOut1.VAL CP NMS") #A=th + caput(userCalcOut_pv+".INPB","29idKappa:userCalcOut2.VAL CP NMS") #B=chi + caput(userCalcOut_pv+".INPC","29idKappa:userCalcOut3.VAL CP NMS") #C=phi + caput(userCalcOut_pv+".D",3.141592653589793) + caput(userCalcOut_pv+".E",180) + caput(userCalcOut_pv+".F",50) + caput(userCalcOut_pv+".CALC$","((2*ASIN(SIN(B*D/E/2.0) / SIN(F*D/E))))*E/D") + caput(userCalcOut_pv+".DOPT",0) # Use CAL + +def EtoK_kphi_CalcOut(): + n=6 + userCalcOut_pv = userCalcOut_clear(mda,n) + + caput(userCalcOut_pv+".DESC","EtoK_kphi") + caput(userCalcOut_pv+".INPA","29idKappa:userCalcOut1.VAL CP NMS") #A=th + caput(userCalcOut_pv+".INPB","29idKappa:userCalcOut2.VAL CP NMS") #B=chi + caput(userCalcOut_pv+".INPC","29idKappa:userCalcOut3.VAL CP NMS") #C=phi + caput(userCalcOut_pv+".D",3.141592653589793) + caput(userCalcOut_pv+".E",180) + caput(userCalcOut_pv+".F",50) + caput(userCalcOut_pv+".CALC$","(C*D/E-ASIN(-TAN(B*D/E/2.0)/TAN(F*D/E)))*E/D") + caput(userCalcOut_pv+".DOPT",0) # Use CAL + + + + + + diff --git a/build/lib/iexcode/instruments/Kappa_det.py b/build/lib/iexcode/instruments/Kappa_det.py new file mode 100644 index 0000000000000000000000000000000000000000..9a1a19071153d757e6dd4897cf40339b8fd4a73f --- /dev/null +++ b/build/lib/iexcode/instruments/Kappa_det.py @@ -0,0 +1,77 @@ +from time import sleep +from epics import caget, caput + +from iexcode.instruments.IEX_endstations import Motors + + +############################################################################################################## +################################ Kappa detector class ############################## +############################################################################################################## +det_set_pv = '29idKappa:det:set' +det_list = 'd3', 'd4', 'mcp', 'apd', 'yag' + +class Kappa_Detector: + """ + class for Kappa detector + """ + + def __init__(self): + self.get() + + def get(self): + """ + gets the current det_name and position + + det_name, tth_val + """ + #det_name = caget('29idKappa:userStringSeq6.STR1') + det_name = caget(det_set_pv) + self.name = det_name + tth_val = Motors.get('tth') + return self.name, tth_val + + def set(self,det_name,move=True): + """ + sets the tth detector + and moves the motor to tth value for the new detecotr + + det_names + d3: large diode + d4: small diode + mcp: for the mpa + apd: avalanche photodiode (not currently installed) + yag: yag 'fluorescence screen' + """ + #get current value for tth + tth_val = Motors.get('tth') + + #change det + if det_name in det_list: + caput(det_set_pv,det_name) + if move: + Motors.move('tth',tth_val,wait=True,verbose=False) + + def tth0_set(move): + """ + resetting the tth motor zero to correspond to direct beam + + only works with d4 + """ + current_det=caget(det_set_pv,as_string=True) + tth_pv = Motors._motor_dictionary['th'][3] + + if current_det != 'd4': + print('tth0 can only be redefined with d4') + else: + foo=input('Are you sure you want to reset tth0 (y or n)? >') + if foo == 'Y' or foo == 'y' or foo == 'yes'or foo == 'YES': + caput(tth_pv+'.SET','Set') + sleep(0.5) + caput(tth_pv+'.VAL',0) + caput(tth_pv+'.DVAL',0) + sleep(0.5) + caput(tth_pv+'.SET','Use') + print("tth position reset to 0") + else: + print("That's ok, everybody can get cold feet in tough situation...") + diff --git a/build/lib/iexcode/instruments/Lakeshore_335.py b/build/lib/iexcode/instruments/Lakeshore_335.py new file mode 100644 index 0000000000000000000000000000000000000000..5acc6b95dd8ba5c3da389836f2b159966a62fd99 --- /dev/null +++ b/build/lib/iexcode/instruments/Lakeshore_335.py @@ -0,0 +1,448 @@ +""" +work in progress need to redo +""" +from time import sleep, strftime, localtime + +import numpy as np +from epics import caget, caput + + +from iexcode.instruments.IEX_endstations import * +from iexcode.instruments.utilities import read_dict + +def Lakeshore_reset(pv,d): + """ + resets the lake short to the default paramters defind in the dictionary d + """ + for key in d.keys(): + caput(pv+key,d[key]) + + +############################################################################################################# +############################## Lakeshore 335 Diode Curves ############################## +############################################################################################################## +#---Settings as of 12/04/2018--- +#DiodeCurve_Write(22,"SI435") +#DiodeCurve_SetInput("A",22,400) +#DiodeCurve_Write(23,"SI410") +#DiodeCurve_SetInput("B",23,450) + + + +# ============================================================================= +# def DiodeCurves(DiodeModel): +# DiodeCalibration={} +# DiodeCalibration["SI435"]=[0.00000,1.66751,1.64531,1.61210,1.57373,1.53247,1.49094,1.45196,1.41723,1.38705,1.36089,1.33785,1.31699,1.29756,1.27912,1.26154,1.24489,1.22917,1.21406,1.19855,1.18193,1.16246,1.13841,1.12425,1.11828,1.11480,1.11217,1.10996,1.10828,1.10643,1.10465,1.10295,1.10124,1.09952,1.09791,1.09629,1.09468,1.09306,1.09145,1.08983,1.08821,1.08659,1.08497,1.08334,1.08171,1.08008,1.07844,1.07681,1.07517,1.07353,1.07188,1.07023,1.06858,1.06693,1.06528,1.06362,1.06196,1.06029,1.05863,1.05696,1.05528,1.05360,1.05192,1.05024,1.04856,1.04687,1.04518,1.04349,1.04179,1.04010,1.03839,1.03669,1.03498,1.03327,1.03156,1.02985,1.02814,1.02642,1.02471,1.02299,1.02127,1.01957,1.01785,1.01612,1.01439,1.01267,1.01093,1.00918,1.00744,1.00569,1.00393,1.00218,1.00042,0.99865,0.99687,0.99510,0.99332,0.99153,0.98975,0.98795,0.98615,0.98434,0.98254,0.98073,0.97891,0.97710,0.97527,0.97344,0.97161,0.96978,0.96794,0.96609,0.96424,0.96239,0.96053,0.95867,0.95680,0.95492,0.95304,0.95116,0.94927,0.94738,0.94549,0.94358,0.94167,0.93976,0.93785,0.93592,0.93398,0.93203,0.93008,0.92812,0.92616,0.92418,0.92221,0.92022,0.91823,0.91623,0.91423,0.91222,0.91021,0.90819,0.90617,0.90414,0.90212,0.90008,0.89805,0.89601,0.89397,0.89293,0.88988,0.88783,0.88578,0.88372,0.88166,0.87959,0.87752,0.87545,0.87337,0.87129,0.86921,0.86712,0.86503,0.86294,0.86084,0.85874,0.85664,0.85453,0.85242,0.85030,0.84818,0.84606,0.84393,0.84180,0.83967,0.83754,0.83540,0.83325,0.83111,0.82896,0.82680,0.82465,0.82249,0.82032,0.81816,0.81599,0.81381,0.81163,0.80945,0.80727,0.80508,0.80290,0.80071,0.79851,0.79632,0.79412,0.79192,0.78972,0.78752,0.78532,0.78311,0.78090,0.77869,0.77648,0.77426,0.77205,0.76983,0.76761,0.76539,0.76317,0.76094,0.75871,0.75648,0.75425,0.75202,0.74978,0.74755,0.74532,0.74308,0.74085,0.73861,0.73638,0.73414,0.73191,0.72967,0.72743,0.72520,0.72296,0.72072,0.71848,0.71624,0.71400,0.71176,0.70951,0.70727,0.70503,0.70278,0.70054,0.69829,0.69604,0.69379,0.69154,0.68929,0.68704,0.68479,0.68253,0.68028,0.67802,0.67576,0.67351,0.67124,0.66898,0.66672,0.66445,0.66219,0.65992,0.65765,0.65538,0.65310,0.65083,0.64855,0.64628,0.64400,0.64172,0.63944,0.63716,0.63487,0.63259,0.63030,0.62802,0.62573,0.62344,0.62115,0.61885,0.61656,0.61427,0.61197,0.60968,0.60738,0.60509,0.60279,0.60050,0.59820,0.59590,0.59360,0.59131,0.58901,0.58671,0.58441,0.58211,0.57980,0.57750,0.57520,0.57289,0.57059,0.56828,0.56598,0.56367,0.56136,0.55905,0.55674,0.55443,0.55211,0.54980,0.54748,0.54516,0.54285,0.54053,0.53820,0.53588,0.53356,0.53123,0.52891,0.52658,0.52425,0.52192,0.51958,0.51725,0.51492,0.51258,0.51024,0.50790,0.50556,0.50322,0.50088,0.49854,0.49620,0.49385,0.49151,0.48916,0.48681,0.48446,0.48212,0.47977,0.47741,0.47506,0.47271,0.47036,0.46801,0.46565,0.46330,0.46095,0.45860,0.45624,0.45389,0.45154,0.44918,0.44683,0.44447,0.44212,0.43976,0.43741,0.43505,0.43270,0.43034,0.42799,0.42563,0.42327,0.42092,0.41856,0.41620,0.41384,0.41149,0.40913,0.40677,0.40442,0.40206,0.39970,0.39735,0.39499,0.39263,0.39027,0.38792,0.38556,0.38320,0.38085,0.37849,0.37613,0.37378,0.37142,0.36906,0.36670,0.36435,0.36199,0.35963,0.35728,0.35492,0.35256,0.35021,0.34785,0.34549,0.34313,0.34078,0.33842,0.33606,0.33371,0.33135,0.32899,0.32667,0.32428,0.32192] +# DiodeCalibration["SI410"]=[0.0000,1.7191,1.7086,1.6852,1.6530,1.6124,1.5659,1.5179,1.4723,1.4309,1.3956,1.3656,1.3385,1.3142,1.2918,1.2712,1.2517,1.2333,1.2151,1.1963,1.1759,1.1524,1.1293,1.1192,1.1146,1.1114,1.1090,1.1069,1.1049,1.1031,1.1014,1.0997,1.0980,1.0964,1.0949,1.0933,1.0917,1.0902,1.0886,1.0871,1.0855,1.0839,1.0824,1.0808,1.0792,1.0776,1.0760,1.0744,1.0728,1.0712,1.0696,1.0679,1.0663,1.0646,1.0630,1.0613,1.0597,1.0580,1.0563,1.0547,1.0530,1.0513,1.0497,1.0480,1.0463,1.0446,1.0429,1.0412,1.0395,1.0378,1.0361,1.0344,1.0327,1.0310,1.0293,1.0276,1.0259,1.0242,1.0224,1.0207,1.0190,1.0172,1.0155,1.0137,1.0120,1.0102,1.0085,1.0067,1.0049,1.0032,1.0014,0.9996,0.9978,0.9960,0.9942,0.9924,0.9905,0.9887,0.9869,0.9851,0.9832,0.9814,0.9795,0.9777,0.9758,0.9740,0.9721,0.9703,0.9684,0.9665,0.9646,0.9628,0.9609,0.9590,0.9571,0.9552,0.9533,0.9514,0.9495,0.9476,0.9457,0.9437,0.9418,0.9398,0.9379,0.9359,0.9340,0.9320,0.9300,0.9281,0.9261,0.9241,0.9222,0.9202,0.9182,0.9162,0.9142,0.9122,0.9102,0.9082,0.9062,0.9042,0.9022,0.9002,0.8982,0.8962,0.8942,0.8921,0.8901,0.8881,0.8860,0.8840,0.8820,0.8799,0.8779,0.8758,0.8738,0.8717,0.8696,0.8676,0.8655,0.8634,0.8613,0.8593,0.8572,0.8551,0.8530,0.8509,0.8488,0.8467,0.8446,0.8425,0.8404,0.8383,0.8362,0.8341,0.8320,0.8299,0.8278,0.8257,0.8235,0.8214,0.8193,0.8171,0.8150,0.8129,0.8107,0.8086,0.8064,0.8043,0.8021,0.8000,0.7979,0.7957,0.7935,0.7914,0.7892,0.7871,0.7849,0.7828,0.7806,0.7784,0.7763,0.7741,0.7719,0.7698,0.7676,0.7654,0.7632,0.7610,0.7589,0.7567,0.7545,0.7523,0.7501,0.7479,0.7457,0.7435,0.7413,0.7391,0.7369,0.7347,0.7325,0.7303,0.7281,0.7259,0.7237,0.7215,0.7193,0.7170,0.7148,0.7126,0.7104,0.7082,0.7060,0.7037,0.7015,0.6993,0.6971,0.6948,0.6926,0.6904,0.6881,0.6859,0.6837,0.6814,0.6792,0.6770,0.6747,0.6725,0.6702,0.6680,0.6657,0.6635,0.6612,0.6590,0.6567,0.6545,0.6522,0.6500,0.6477,0.6455,0.6432,0.6410,0.6387,0.6365,0.6342,0.6319,0.6297,0.6274,0.6251,0.6229,0.6206,0.6183,0.6161,0.6138,0.6115,0.6092,0.6070,0.6047,0.6024,0.6001,0.5979,0.5956,0.5933,0.5910,0.5887,0.5865,0.5842,0.5819,0.5796,0.5773,0.5750,0.5727,0.5705,0.5682,0.5659,0.5636,0.5613,0.5590,0.5567,0.5544,0.5521,0.5498,0.5475,0.5452,0.5429,0.5406,0.5383,0.5360,0.5337,0.5314,0.5291,0.5268,0.5245,0.5222,0.5199,0.5176,0.5153,0.5130,0.5107,0.5084,0.5061,0.5038,0.5015,0.4992,0.4968,0.4945,0.4922,0.4899,0.4876,0.4853,0.4830,0.4806,0.4783,0.4760,0.4737,0.4714,0.4690,0.4667,0.4644,0.4621,0.4597,0.4574,0.4551,0.4528,0.4504,0.4481,0.4458,0.4435,0.4411,0.4388,0.4365,0.4341,0.4318,0.4295,0.4271,0.4248,0.4225,0.4201,0.4178,0.4154,0.4131,0.4108,0.4084,0.4061,0.4037,0.4014,0.3991,0.3967,0.3944,0.4154,0.4131,0.4108,0.4084,0.4061,0.4037,0.4014,0.3991,0.3967,0.3709,0.3685,0.3662,0.3638,0.3615,0.3591,0.3567,0.3544,0.3520,0.3497,0.3473,0.3449,0.3426,0.3402,0.3379,0.3355,0.3331,0.3308,0.3284,0.3260,0.3237,0.3213,0.3189,0.3165,0.3142,0.3118,0.3094,0.3071,0.3047,0.3023,0.2999,0.2976,0.2952,0.2928,0.2904,0.2880,0.2857,0.2833,0.2809,0.2785,0.2761,0.2738,0.2714,0.2690,0.2666,0.2642,0.2618,0.2594,0.2570,0.2547,0.2523,0.2499,0.2475,0.2451,0.2427,0.2403,0.2379,0.2355,0.2331,0.2307,0.2283,0.2259,0.2235,0.2211,0.2187,0.2163,0.2139,0.2115,0.2091,0.2067,0.2043] +# return DiodeModel,DiodeCalibration[DiodeModel] +# ============================================================================= + +def DiodeCurve_Write_backup(CRVNum,DiodeModel): + """ + Writes a Diode curve to the Lakeshore 335 temperature controller + Diode curves are saved in the fname=Dict_TempDiode.txt + usage: DiodeCurve_Write(22,"SI435") to write to curve 22 the dictionary entry "SI435" + DiodeCurve_SetInput("A",22,400) + """ + fname="Dict_TempDiode.txt" + PV="29idARPES:LS335:TC1:serial.AOUT" + + t=1 + index=1 + #Curve Header + DiodeDict=read_dict(fname) + CRVHDR,CRVList=DiodeModel,DiodeDict[DiodeModel] + + cmd="CRVHDR "+str(CRVNum)+","+CRVHDR+",SN,2,"+str(len(CRVList)-1)+",1" + print(cmd) + caput(PV,cmd,wait=True,timeout=1800) + while t <len(CRVList): + if(t>=0 and t<30): + countby=1 + elif(t>=30 and t<230): + countby=2 + elif(t>=230): + countby=5 + cmd="CRVPT "+str(CRVNum)+","+str(index)+","+str(CRVList[t])+","+str(t) + #print cmd + caput(PV,cmd,wait=True,timeout=1800) + #sleep(1) + t=t+countby + index+=1 + #write 0,0 to indicate list is done + cmd="CRVPT "+str(CRVNum)+","+str(index)+","+str(CRVList[0])+","+str(0) + caput(PV,cmd,wait=True,timeout=1800) + print("last point = "+str(index)) + +def DiodeCurve_Write(CRVNum,DiodeModel,run=True): #reversing order since it seems that the curve needs to go from high to low based on the built-in + """ + Writes a Diode curve to the Lakeshore 335 temperature controller + Diode curves are saved in the fname=Dict_TempDiode.txt + + run=True to write to the Lakeshoe + run=False to print only + + usage: DiodeCurve_Write(22,"SI435") to write to curve 22 the dictionary entry "SI435" + DiodeCurve_SetInput("A",22,400) + """ + fname="Dict_TempDiode.txt" + PV="29idARPES:LS335:TC1:serial.AOUT" + + + #Curve Header + CRVList=read_dict(fname)[DiodeModel] + cmd="CRVHDR "+str(CRVNum)+","+DiodeModel+",SN,2,"+str(len(CRVList)-1)+",1" + if run == True: + caput(PV,cmd,wait=True,timeout=1800) + else: + print(cmd) + + #Writing the individual terms (model 335 only supports index:1-200) + T1=50 + T2=230 + T3=len(CRVList) + + T=np.arange(0,T1,1) + V=np.array(CRVList[0:T1]) + + T=np.append(T,np.arange(T1,T2,2)) + V=np.append(V,np.array(CRVList[T1:T2:2])) + + T=np.append(T,np.arange(T2,T3,5)) + V=np.append(V,np.array(CRVList[T2:T3:5])) + + #reverse order + T=T[::-1] + V=V[::-1] + + for i,t in enumerate(T): + cmd="CRVPT "+str(CRVNum)+","+str(i+1)+","+str(V[i])+","+str(t) + #cmd="index,v,t"+str(i+1)#+","+str(V[i])+","+str(t) + if run == True: + caput(PV,cmd,wait=True,timeout=1800) + else: + print(cmd) + +def DiodeCurve_SetInput(Channel,Curve,Tmax): + """ + Sets the diode curve for a given channel on the Lakeshore 335 temperature controller + DiodeCurve_SetInput("A",22,400) + Channel: A or B + Curve: set by DiodeCurve_Write(22,"SI435") + Tmax: max temperature for that diode + (pg 118 of manual) + """ + + PV="29idARPES:LS335:TC1:serial.AOUT" + #Set curve info + cmd="INTYPE "+Channel+","+"1,0,0,0,1" + caput(PV,cmd,wait=True,timeout=1800) + #Select curve + cmd="INCRV "+Channel+","+str(Curve) + caput(PV,cmd,wait=True,timeout=1800) + #Set temperature Limit + cmd="TLIMIT "+Channel+","+str(Tmax) + caput(PV,cmd,wait=True,timeout=1800) + +############################################################################################################## +############################## PID Settings ############################## +############################################################################################################## + + +#Setting the PID +# Set P=10, I=0, D=0; Set T and range, +# if T oscilate above setpoint, P/=2 +# if T doesn't reach setpoint, P*=2 +# if T swings above setpoint but then settle below use this P +# Set I=10; smaller I, more reactive (approximately time(sec) for one full oscillation period +# Set D=I/4 +#Lakeshore 355 I = time in seconds for one oscilation / 1000; D=50-100 for starters + + +def PID_dict(which,T): #Dictionary of PID setting to try for the ARPES chamber + """Dictionary for common PID setting for the ARPES system. + Since the PID is dependent on the cooling power, this will change with the cryogen and the flow rate: + - Flow = "LHe,LN" => LHe = needle valve = "on" and flow = 70 + """ + PID={} +# PID[which,T]=[P,I,D,Range] Range=HIGH,MEDIUM,LOW,OFF + PID['RT', 378.0]=[200.0,0.0,0.0,'MEDIUM'] + PID['RT', 375.0]=[200.0,0.0,0.0,'MEDIUM'] + PID['RT', 338.0]=[100.0,0.0,0.0,'MEDIUM'] + PID['RT', 298.0]=[20.0,0.0,0.0,'LOW'] + PID['GHe', 378.0]=[210.0,0.0,0.0,'MEDIUM'] + PID['GHe', 375.0]=[210.0,0.0,0.0,'MEDIUM'] + PID['GHe', 338.0]=[130.0,0.0,0.0,'MEDIUM'] + PID['GHe', 298.0]=[60.0,0.0,0.0,'MEDIUM'] + PID['GHe', 250.0]=[10.0,0.0,0.0,'LOW'] + PID['LHe',298.0]=[20.0,5.0,1.0,'HIGH'] # +/- 1.1 deg, over 10 min, heater power 53% + PID['LHe',200.0]=[10.0,5.0,1.0,'HIGH'] # +/- 1.1 deg, over 10 min, heater power 53% + PID['LHe',150.0]=[200.0,0.1,0,'HIGH'] # Stablized at 153, heater power 43% + PID['LHe',180.0]=[200.0,0.1,0,'HIGH'] + PID['LHe',230.0]=[200.0,0.1,0,'HIGH'] + PID['LHe',300.0]=[200.0,0.1,0,'HIGH'] + PID['LHe',40.0]=[200.0,0.1,0,'HIGH'] # + PID['LN2',230]=[10.0,0.6,100,'HIGH'] #stable 237.83, needle valve=ON; flow 6 half turns from max) + PID['LN2',180]=[50.0,4,100,'MEDIUM'] + return PID[which,T] + +def PID_set(which,T,heater='ON'): + """ + Uses preset PID settings as defined in PID_dict() + To cool down: heater='OFF' + + """ + P,I,D,Range=PID_dict(which,T) + caput("29idARPES:LS335:TC1:P1",P) + caput("29idARPES:LS335:TC1:I1",I) + caput("29idARPES:LS335:TC1:D1",D) + if heater == 'ON': + caput("29idARPES:LS335:TC1:HTR1:Range",Range) + elif heater == 'OFF': + caput("29idARPES:LS335:TC1:HTR1:Range",'OFF') + print('\nP = ',PID_dict(which,T)[0]) + print('I = ',PID_dict(which,T)[1]) + print('D = ',PID_dict(which,T)[2]) + print('Range = ',PID_dict(which,T)[3]) + + +def SetT_Sample(which,T,precision=5,minutes=15,offset=6): + """ + Sets PID settings for a given set point as defined in PID_dict(). + Available set points: + which = 'RT' : T = 298, 338, 375 + which = 'LHe': T = 150, 200 + which = 'GHe': T = 250, 298, 338, 370 + which = 'LN2': T = 230, 180 + precision is temperature in K + """ + current_T=caget("29idARPES:LS335:TC1:IN1") + print('\nSet T to '+ str(T)+' K @ '+ dateandtime()) + if T>current_T: + PID_set(which,T,'ON') + Range=PID_dict(which,T)[3] + SetT_Up(T,offset,Range,precision,minutes) + else: + PID_set(which,T,'OFF') + Range=PID_dict(which,T)[3] + SetT_Down(T,offset,Range,precision,minutes) + caput("29idARPES:LS335:TC1:OUT1:SP",T) + + +def SetT_Up(T,offset,Range,precision=5,minutes=15): + if Range=='LOW': Range=1 + if Range=='MEDIUM': Range=2 + if Range=='HIGH': Range=3 + t=15 + u=0 + caput('29idARPES:LS335:TC1:OUT1:SP',T) # set the set point to T + while True: # while TA < T + TA=caget('29idARPES:LS335:TC1:IN1') # get current temperature at the sample + TB=caget('29idARPES:LS335:TC1:IN2') # get current temperature (B=cold finger) + if TA<T-precision: # if it hasn't reach SP + caput("29idARPES:LS335:TC1:HTR1:Range",min(Range,3)) # increase heater range to Range +1 + while True: # while TB < T+offset: + TB=caget('29idARPES:LS335:TC1:IN2') # get current temperature at the cold finger + if (t%120)==0: + print('\nTA = ',TA,' TB = ',TB, ' @ ',dateandtime()) + if TB<(T+offset) and t<=minutes*60: #if it hasn't reach the SP+offser + sleep(15) + t+=15 + #print t, TA, TB + elif TB<(T+offset) and t>minutes*60: + heater_power=caget('29idARPES:LS335:TC1:HTR1') + heater_range=caget('29idARPES:LS335:TC1:HTR1:Range') + if heater_power > 90: + caput("29idARPES:LS335:TC1:HTR1:Range",min(heater_range+1,3)) + print('Change Range to',caget('29idARPES:LS335:TC1:HTR1:Range'),' @ ',dateandtime()) + elif heater_range==3 or heater_power<=90: + P=caget("29idARPES:LS335:TC1:P1") + caput("29idARPES:LS335:TC1:P1",P*1.5) + print('Change P to',caget("29idARPES:LS335:TC1:P1"),' @ ',dateandtime()) + t=0 + + else: #else + break # break + caput("29idARPES:LS335:TC1:HTR1:Range",'OFF') # turn off the heater + elif TA>T-precision: # if it has reach the set point + break # break + print('TA = ',TA,' TB = ',TB, ' @ ',dateandtime()) # print temperatures + caput("29idARPES:LS335:TC1:HTR1:Range",Range) # set the heater range to preset value + + + + + + +def SetT_Down(T,offset,Range,precision=5,minutes=15): + t=0 + caput('29idARPES:LS335:TC1:OUT1:SP',T) # set the set point to T + while True: # while TA < T + TA=caget('29idARPES:LS335:TC1:IN1') + TB=caget('29idARPES:LS335:TC1:IN2') + if (t%120)==0: + print('\nTA = ',TA,' TB = ',TB, ' @ ',dateandtime()) + if TA>T+precision: + sleep(15) + t+=15 + elif t>minutes*60: + P=caget("29idARPES:LS335:TC1:P1") + caput("29idARPES:LS335:TC1:P1",P/1.5) + t=0 + else: + break + caput("29idARPES:LS335:TC1:HTR1:Range",Range) + print('TA = ',TA,' TB = ',TB, ' @ ',dateandtime()) + + +def Get_PID(which='LHe'): + T=caget("29idARPES:LS335:TC1:IN1") + SP=caget("29idARPES:LS335:TC1:OUT1:SP") + P=caget("29idARPES:LS335:TC1:P1") + I=caget("29idARPES:LS335:TC1:I1") + D=caget("29idARPES:LS335:TC1:D1") + Range=caget("29idARPES:LS335:TC1:HTR1:Range",as_string=True) +# print SP,P,I,D,Range + print("Current T:", T,'K') + print("PID[\'"+which+"\',"+str(SP)+"]=["+str(P)+","+str(I)+","+str(D)+",\'"+Range+"\']") + + + +############################################################################################################## +############################## SI9700 Kludge ############################## + +############################################################################################################## +def ResetPID(): + caput('29idd:tc1:SetPID_1.INPA','') + caput('29idd:tc1:SetPID_1.INPB','') + caput('29idd:tc1:SetPID_1.INPC','') + +def GetCurrentPID(): + T=caget('29idd:tc1:getVal_A.VAL') + P=caget('29idd:tc1:SetPID_1.A') + I=caget('29idd:tc1:SetPID_1.B') + D=caget('29idd:tc1:SetPID_1.C') + return T,P,I,D + +def SetTempSetting(T,P,I,D): + #Change the sample temperature T with the specified PID values + caput('29idd:tc1:getVal_A.VAL',T) + caput('29idd:tc1:SetPID_1.A',P) + caput('29idd:tc1:SetPID_1.B',I) + caput('29idd:tc1:SetPID_1.C',D) + +# GetCurrentPID => (60.0121, 8.0, 50.0, 12.0) ## Temperature overshoots no more than 5.5 degrees +#it takes about 3 min to stablize at any temp +#cooling is about 10 degrees/min + + +#functions use from ScanFunctions_IEX import BL_ioc +def PVLakeshores(which): + """ + which = RSXS / ARPES /Hydra / DetPool + usage: P, Sample, ColdFinger, SetPoint = PVLakeshores[which] + """ + # key: + + d={"Kappa":("29idd:LS331:TC1:","SampleA","SampleB","wr_SP"), + "ARPES":("29idARPES:LS335:TC1:","IN1","IN2","OUT1:SP"), + "Hydra":("29idc:LS340:TC2:","Sample","Control","wr_SP1"), + "DetPool":("29idc:LS340:TC1:","Sample","Control","wr_SP1") + } + return d[which] + +def dateandtime(): + return strftime("%a %d %b %Y %H:%M:%S",localtime()) + +def tempr(which=None): + """ + reads the temperature in the current branch unless otherwise specificed + """ + if which == None: + which=BL_ioc() + PVs=PVLakeshores(which) + sample=PVs[0]+PVs[1] + print(which+" Sample Temperature: {} K".format(caget(sample))) + +def temps(tempset,which=None): + """ + Set sthe sample temperature set point and waits for it to stablelize for the current branch + unless specified by which = Kappa / ARPES /Hydra set by PVLakeshores + """ + if which == None: + which=BL_ioc() + + P, Sample, ColdFinger, SetPoint = PVLakeshores(which) + + print("Initial Sample Temperature:",caget(P+Sample)," K",dateandtime()) + caput(P+SetPoint,1.0*tempset) + stop_var=0 + b=0 + sleep(0) + while b == 0: + delta=abs(caget(P+Sample)-1.0*tempset) + if abs(delta) < 1: + c=0 + while c < 10: + sleep(1) + delta=delta+(caget(P+Sample)-1.0*tempset) + c=c+1 + if abs(delta/10) < 1: + print("Stable Sample Temperature:",caget(P+Sample)," K",dateandtime()) + b=1 + else: + temp1=caget(P+Sample) + sleep(10) + temp2=caget(P+Sample) + if abs(temp1-temp2) < 0.1: + sleep(30) + temp2=caget(P+Sample) + if abs(temp1-temp2) < .5: + print("UNABLE TO STABLIZE TEMPERATURE! Stopped at T=:",caget(P+Sample)," K",dateandtime()) + b=1 + +def ARPES_warming(Tmax,PowerMax=50,Tdiff=10): + """ + Ramps the temperature up for ARPES using open loop and manual power at PowerMax with + the heater on High until Tmax - Tdif is reached and then switches to + closed loop with the heater on Medium + + PowerMax=50,Tdiff=10 + PowerMax=55,Tdiff=25 + """ + + P="29idARPES:LS335:TC1:" + #Needs modified in controller changed + Tsample=P+"IN1" + Tcontrol=P+"IN2" + Tsetpoint=P+"OUT1:SP" + HeaterRange=P+"HTR1:Range" + ControlMode=P+"OUT1:Mode" + ManualPower=P+"OUT1:MOUT" + + caput(Tsetpoint,Tmax) + caput(ManualPower,PowerMax) + caput(ControlMode,"Open Loop") + caput(HeaterRange,'HIGH') + + print("T", caget(Tsample)) + print("Started warming:", dateandtime()) + + while True: + TA=caget(Tsample) + TB=caget(Tsample) + if TB >= Tmax: + print ("Control is to high",TB) + break + if TA < Tmax - Tdiff: + sleep(60) + else: + break + print("T", caget(Tsample)) + print("Switch to closed loop", dateandtime()) + + caput(HeaterRange,'MEDIUM');sleep(1) + caput(ControlMode,"Closed Loop");sleep(1) + caput(HeaterRange,'OFF');sleep(1) + caput(HeaterRange,'MEDIUM');sleep(1) + temps(Tmax,which='ARPES') diff --git a/build/lib/iexcode/instruments/Motors.py b/build/lib/iexcode/instruments/Motors.py new file mode 100644 index 0000000000000000000000000000000000000000..119b51bb725c0a065f3f6eb245b342d17eb3dad4 --- /dev/null +++ b/build/lib/iexcode/instruments/Motors.py @@ -0,0 +1,232 @@ +import time +from math import floor + +from epics import caget, caput + +from iexcode.instruments.IEX_endstations import * + + +class Motors: + """ + short hand to move motors in endstation + usage motors = Motor('ARPES','ARPES_motor_dictionary') + """ + + def __init__(self,endstation_name,motor_dictionary,physical_motors, + psuedo_motors): + self.endstation_name = endstation_name + self._motor_dictionary = motor_dictionary + self.physical_motors = physical_motors + self.pseudo_motors = psuedo_motors + + def info(self): + print("physical motors:",self.physical_motors) + print("pseudo motors:",self.pseudo_motors) + + def get(self,name,verbose=False): + """ + get current position of motor name = "x","y"... + """ + + try: + rbv = caget(self._motor_dictionary(name)[0]) + if verbose: + print('current position: '+name+" = "+str(rbv)) + return rbv + except: + print("Not a valid motor name") + + def reset(self,name): + """ + Reset motor if stuck in 'moving' + """ + pv=self._motor_dictionary(name)[2] + caput(pv,'Stop') + time.sleep(1) + caput(pv,'Go') + + def status(self): + """ + if status == 0 then moving + """ + status = 0 + for motor in self._motor_dictionary.keys(): + status *= caget(self._motor_dictionary[motor][3]+".DMOV") + return status + + def move(self,name,val,**kwargs): + """ + Moves a motor in the endstation based on common name, not PV name + + name: motor name => 'x','y','z','th','chi','phi' ... + val: absolute position if relative=False, delta if relative=True + + **kwargs: + relative: move mode => True/False; default = False (absolute) + wait: wait for move completion before moving on => True/False; default=True + verbose: print old and new motor position => True/False; default=False + + + Previously: Move_ARPES_Motor or Move_ARPES_Motor or motor_move_vs_Branch + """ + kwargs.setdefault('relative',False) + kwargs.setdefault('wait',True) + kwargs.setdefault('verbose',False) + + try: + rbv_pv,val_pv,sgm_pv,pv = self._motor_dictionary[name] + old_position = caget(rbv_pv) + if kwargs['relative']: + val = old_position + val + + caput(val_pv,val,wait=kwargs['wait'],timeout=18000) + + new_position = caget(rbv_pv) + if kwargs['verbose']: + print('old: '+name+" = "+str(old_position)) + print('new: '+name+" = "+str(new_position)) + except: + print(name+" is not a valid motor name") + + + + def dmove(self,name,val,**kwargs): + """ + relative move of a motor in the endstation based on common name, not PV name + name = x,y,z,th,chi,phi ... + + **kwargs: + wait: wait for move completion before moving on => True/False; default=True + verbose: print old and new motor position => True/False; default=False + + Previously: motor_umove_vs_Branch + """ + kwargs.setdefault('wait',True) + kwargs.setdefault('verbose',False) + + self.move(name,val,relative=True,wait=kwargs['wait'],verbose=kwargs['verbose']) + + def mprint(self): + """ + prints current position of the physical motors + """ + position_list = [] + for motor in self.physical_motors(): + position_list.append(self.get(motor,verbose=False)) + return position_list + + def mvsample(self,position_list,verbose=True): + """ + moves the sample to the position sepcified by position_list + position_list = ['description',x,y,z,th,chi,phi] + + Previously: sample + """ + if not isinstance(position_list[0],str): + sample_name = '' + else: + sample_name = position_list[0] + position_list = position_list[1:] + + motor_list = self.physical_motors() + for motor,i in enumerate(motor_list): + self.move(motor,position_list[i]) + + if verbose: + print("Sample now @ "+sample_name) + + def scan(self,name,start,stop,step, **kwargs): + """ + scans a motor + + **kwargs: + relative: move mode => True/False; default = False (absolute) + scan_dim: 1 (default) + execute: True/False to start the scan => True (default) + + for Kappa only: + cts: scaler integration time in seconds (default = 0.1 s) + mpa: True/False to sum mpa acquisitions + + Previously Scan_ARPES_motor / Scan_Kappa_motor + """ + kwargs.setdefault('relative',False) + kwargs.setdefault('scan_dim',1) + kwargs.setdefault('execute',True) + #for kappa only + kwargs.setdefault('cts',0.1) + kwargs.setdefault('mpa',False) + + rbv_pv,val_pv,sgm_pv,pv =self._motor_dictionary()[name] + + if kwargs['mode'] == "relative": + current_value = caget(rbv_pv) + abs_start = round(current_value + start,3) + abs_stop = round(current_value + stop,3) + print("start, stop, step = "+str(abs_start)+", "+str(abs_stop) + +", "+str(step)) + else: + abs_start = start + abs_stop = stop + + self._scalar_cts(kwargs['cts'],verbose=True,**kwargs) + BL.mda.fillin(val_pv,rbv_pv,abs_start,abs_stop,step,**kwargs) + + if kwargs['execute']: + BL.mda.go(**kwargs) + + + def scan_2D(self,inner_loop_list,outer_loop_list,**kwargs): + """ + Fills in a the Scan Record for a 2D scan (Mesh), does NOT press go + InnerMotorList=[name1,start1,stop1,step1] #scanDIM=2 + OuterMotorList=[name2,start2,stop2,step2] #scanDIM=3 + name = 'x'/'y'/'z'/'th'... + + **kwargs: + relative: scab => True/False; default = False (absolute) + outer_scan_dim: 2 (default) + execute: True/False to start the scan => True (default) + Snake; coming soon + + + for Kappa only: + cts: scaler integration time in seconds (default = 0.1 s) + mpa: True/False to sum mpa acquisitions + + """ + kwargs.setdefault('mode','absolute') + kwargs.setdefault('outer_scan_dim',2) + kwargs.setdefault('snake',False) + kwargs.setdefault('execute',True) + #for kappa only + kwargs.setdefault('cts',0.1) + kwargs.setdefault('mpa',False) + + rbv_pv,val_pv,sgm_pv,pv = self._motor_dictionary()[inner_loop_list[0]] + inner_loop_list.insert(0,rbv_pv) + inner_loop_list.insert(0,val_pv) + + rbv_pv,val_pv,sgm_pv,pv = self._motor_dictionary()[outer_loop_list[0]] + outer_loop_list.insert(0,rbv_pv) + outer_loop_list.insert(0,val_pv) + + if kwargs["mode"] == "relative": + current_value1 = caget(inner_loop_list[1]) + inner_loop_list[2]=round(current_value1+inner_loop_list[2],3) + inner_loop_list[3]=round(current_value1+inner_loop_list[3],3) + + current_value2 = caget(outer_loop_list[1]) + outer_loop_list[2]=round(current_value1+outer_loop_list[2],3) + outer_loop_list[3]=round(current_value1+outer_loop_list[3],3) + + scalar_cts(kwargs['cts'],verbose=True,**kwargs) + BL.mda.fillin_2D(inner_loop_list,outer_loop_list, + outer_scan_dim=kwargs['outer_scan_dim'],**kwargs) + + if kwargs['execute']: + BL.mda.go(**kwargs) + + + + diff --git a/build/lib/iexcode/instruments/Scienta.py b/build/lib/iexcode/instruments/Scienta.py new file mode 100644 index 0000000000000000000000000000000000000000..f493664c17207aa84874be71aee4433e459c25f8 --- /dev/null +++ b/build/lib/iexcode/instruments/Scienta.py @@ -0,0 +1,578 @@ +import time +import numpy as np +from epics import caget,caput, PV + + + + +#----------------------------------------------- +#--- Beamline dependent PVs and definitions --- +#----------------------------------------------- +P="29idcScienta:" +PHV=P+'HV:' +Pcam =P+'basler:cam1:' +savePlugin = P+"HDF1:" +statsPlugin = P+"Stats4:" +dtype = "h5" +#energy scaling +KEpix=0.0000845#*PE +KEwidth=0.1085#*PE + + +def AllowedEnergyRange(*args): + """ + KEmin, KEmax for a given PassEnergy, LensMode combination + *args + = PassEnergy, LensMode => returns KEmin,KEmax + = empty => returns entire table + + """ + Table={} + Table['Transmission']={1:(0,76),2:(0,107),5:(1,237),10:(1,453),20:(3,968),50:(7,6041),100:(21,6000),200:(30,6206),500:(283,6504)} + Table['Angular']={1:(None,None),2:(1,52),5:(2,131),10:(2,262),20:(10,523),50:(24,1309),100:(34,6105),200:(230,6206),500:(None,None)} + Table['Angular_01']={1:(None,None),2:(None,None),5:(None,None),10:(None,None),20:(None,None),50:(126,2947),100:(252,1401),200:(844,1261),500:(None,None)} + Table['Angular_05']={1:(None,None),2:(None,None),5:(None,None),10:(None,None),20:(None,None),50:(None,None),100:(252,1323),200:(1043,1270),500:(None,None)} + + if len(args)<1: + return Table + + if len(args)==2: + try: + PassEnergy,LensMode=args + KEmin,KEmax=Table[LensMode][PassEnergy] + return KEmin,KEmax + except: + return None + else: + print('Not a valid argument') + +############################################################# +########### Scienta python control functions ################ +############################################################# + +class Scienta: + """ + Scienta only talks in 'KE' anything related to the binding energy happens outside of these + controls + Usage: + EA=Scienta() + EA.get(); cagets all Scienta parameters and returns vars(EA); dictionary of variables + EA.PE(),EA.KE(),EA.LensMode() + """ + + def __init__(self): + #High Voltage Setting + self.PHV = PHV + self._Pcam=Pcam + self._savePlugin=savePlugin + self._statsPlugin=statsPlugin + + self.dtype=dtype + self.wk = None + + self.ElementSet = None #HV for XPS, LV for UPS + + self.LensMode = None + self.PassEnergy = None + self.KineticEnergy = None + self.SpectraMode = None + + #Camera Settings + self.Frames = None + + self.get() + return + + def get(self,q=1): + """ + Gets the current Scienta parameters + returns the dictionary for q!=1 + """ + for key in vars(self): + if key not in ["PHV","_Pcam","_savePlugin","_statsPlugin","wk","Frames","dtype"]: + vars(self)[key]=caget(self.PHV+key+".VAL") + if key in ["LensMode","SpectraMode"]: + vars(self)[key]=caget(self.PHV+key+".VAL",as_string=True) + if key == "Frames": + vars(self)[key]=caget(self.PHV.split(':')[0]+':'+"ExpFrames.VAL") + if key == "wk": + vars(self)[key]=caget(self.PHV+"WorkFunction") + if q !=1: + for key in vars(self): + print(key+" = "+str(vars(self)[key])) + + return vars(self) + + def counts(self): + """ + returns the current intensity on the Scienta using EA. + """ + return caget(self._savePlugin+"Total_RBV") + + def _errorCheck(self,KineticEnergy,PassEnergy,LensMode,Frames,**kwargs): + """ + check the parameters to see if they are allowed + + returns list of errors + **kwargs: + debug=False + """ + kwargs.setdefault('debug',False) + if kwargs['debug']: + print("\n _errorCheck") + error=[] + + if LensMode not in AllowedEnergyRange().keys(): + error.append("LensMode = "+LensMode+" is not a valid") + elif PassEnergy not in AllowedEnergyRange()[LensMode]: + error.append("PassEnergy = "+str(PassEnergy)+" is not a valid") + try: + KEmin,KEmax=AllowedEnergyRange(PassEnergy,LensMode) + if KEmin>KineticEnergy or KineticEnergy>KEmax: + error.append("Kinetic Energy: "+str(KineticEnergy)+" is outside allowed range for this Lens Mode,Pass Energy combination") + except: + error.append("Undefined PassEnergy/LensMode Combination "+str(PassEnergy + )+"/"+LensMode) + if Frames < 1: + error.append("Frames must be 1 or greater") + return error + + def put(self, KE=None, PE=None, LensMode="Angular",Frames=1,**kwargs): + """ + Used to set all the SES parameters at once + KE = kinetic energy (None keeps the current KE) + PE = pass energy (None keeps the current PE) + LensMode = "Angular"/"Transmission" + + **kwargs + debug + """ + + kwargs.setdefault('debug',False) + parms=self.get(q=1) + if kwargs['debug']: + print("\n EA.put") + print('KE,PE,LensMode,Frames = ',KE,PE,LensMode,Frames) + time.sleep(.1) + if KE != None: + parms.update({"KineticEnergy":KE}) + else: + parms.update({"KineticEnergy":self.KineticEnergy}) + if PE != None: + parms.update({"PassEnergy":PE}) + else: + parms.update({"PassEnergy":self.PassEnergy}) + parms.update({"LensMode":LensMode}) + parms.update({"Frames":Frames}) + + if kwargs['debug']: + print("parms:",parms) + + time.sleep(.5) + self._setHV(parms) + + def _setHV(self,parms,**kwargs): + """ + Error checks and sets the Scienta high voltage supplies + parms={'LensMode':LensMode, + 'PassEnergy':PassEnergy + 'KineticEnergy':KineticEnergy, + 'Frames':Frames} + + kwargs: + q: quiet (default = 1); to print the dictionary q!=1 + """ + kwargs.setdefault('q',1) + kwargs.setdefault('debug',False) + + if kwargs['debug']: + print('\n _setHV') + print(parms) + + #checking for errors + error=self._errorCheck(parms['KineticEnergy'],parms['PassEnergy'],parms['LensMode'],parms['Frames']) + if kwargs['debug']: + print(error) + + #setting Frames + self._frames(parms['Frames']) + + if len(error) == 0: + caput(self.PHV+"LensMode",parms["LensMode"]) + time.sleep(.25) + caput(self.PHV+"PassEnergy_Set",str(int(parms["PassEnergy"]))) + time.sleep(0.25) + caput(self.PHV.split(':')[0]+':'+"ExpFrames",parms["Frames"]) + time.sleep(.25) + caput(self.PHV+"KineticEnergy",parms["KineticEnergy"]+0.01) + time.sleep(1) + caput(self.PHV+"KineticEnergy",parms["KineticEnergy"]) + time.sleep(1) + + self.get() + if kwargs['q'] !=1: + for key in vars(self):print(key+" = "+str(vars(self)[key])) + + else: + for e in error: + #print(e) #JM need to modify + x=5 + return + + def off(self,quiet=True): + """ + Zeros the high voltage supplies + """ + self.zeroSupplies() + if quiet == False: + print ("EA HV is zeroed, visually confirm") + + def zeroSupplies(self): + """ + Zeros the Scienta HV supplies (safe-state) + """ + caput(self.PHV+"ZeroSupplies.RVAL",1) + caput(self.PHV+"ZeroSuppliesSeq.PROC",1) + + + def KE(self,val): + """ + Sets the kinetic energy of the Scienta + KE should be grearter than the PassEnergy + """ + self.put(KE=val) + + + def _setwk(self,val): + """ + Sets the wk to the value specified + """ + caput(self.PHV+"WorkFunction",val) + + def PE(self,val): + """ + Sets the pass energy of the Scienta + PassEnergy: 1, 2, 5, 10, 20, 50, 100, 200, 500 + """ + self.put(PE=val) + + def lensMode(self,val): + """ + Sets the pass energy of the Scienta + LensMode: 'Transmission','Angular','Angular_01','Angular_05' + """ + self.put(LensMode=val) + + def _frames(self,val,q=1): + """ + Sets the number of frames + Frames >=1 + """ + caput(self.PHV.split(':')[0]+':'+"ExpFrames.VAL",val) + + + def _ElementSet(self,mode,q=1): + """ + Used to switch between + 0: High Energy (XPS) and 1:Low Energy (UPS) mode + Must be done in conjunction with changing the cabling on the front of the HV supply + mode = 0 or 1 + """ + caput(self.PHV+"ElementSet",mode) + self.get() + if q !=1: + for key in vars(self):print(key+" = "+str(vars(self)[key])) + return + + + def _BurstSupplies(self,val): + """ + BurstSupplies:'Fast','Slow' + """ + caput(self.PHV+"BurstSupplies",val,as_string=True) + + def _AcqCalc(self,val): + """ + AcqCalc:'Off','Live','Scan' + """ + caput(self.PHV+"AcqCalc",val,as_string=True) + + def _AcquisitionMode(self,val): + """ + AcquisitionMode: 'Off','Scan','Spectra' + """ + caput(self.PHV+"AcquisitionMode",val) + + def _ScientaMode(self,val): + """ + ScientaMode: 'BetaScan','XYScan','Fixed','BabySweep','SweepOverlapping','SweepNo' + """ + caput(self.PHV+"ScientaMode",val,as_string=True) + + + def _babySweepSteps(self,val): + """ + sets the number of steps in baby sweep + """ + caput(self.PHV+"babySweepSteps.VAL",val) + + def _spectraStatus(self): + """ + checking the spectra status + returns 1=busy or 0=idle + """ + status=caget(self.PHV+'ScanTrigger') + return status + + def _spectraProgress(self): + """ + Monitors the spectra status every 30 seconds + returns 0 when the spectra scan is idle + """ + while True: + status=self._spectraStatus() + if (status==1): + time.sleep(30) + else: + break + return 0 + + def _SpectraMode(self,Mode): + """ + Checks that Mode exists and sets the mode + + """ + DefinedModes=["Fixed","Baby-Sweep","Sweep"] + if Mode in DefinedModes: + caput(self.PHV+"SpectraMode", "Mode") + else: + print("Not a defined SpectraMode") + + def _spectraInfo(self): + """ + returns the pertainent information for a given spectra type + modeNum=2; Swept=[start,stop,step] + """ + modeNum=caget(self.PHV+"SpectraMode") + scanType=caget(self.PHV+"SpectraMode",as_string=True) + info=[] + if modeNum==2: #swept + info.append(caget(self.PHV+"sweepStartEnergy")) + info.append(caget(self.PHV+"sweepStopEnergy")) + info.append(caget(self.PHV+"sweepStepEnergy")) + elif modeNum==1: #baby-swept + info.append(caget(self.PHV+"babySweepCenter.VAL")) + elif modeNum==0: #fixed + info.append(caget(self.PHV+"fixedEnergy.VAL")) + return scanType,info + + def live(self,KE=None,PE=None,LensMode="Angular"): + """ + puts the Scienta back in live mode (no savinga and Fixed Mode) with PE and KE + if PE or KE is None then uses the current value + """ + if self.spectraProgress() != 1: + parms=self.get() + caput('29idcScienta:HV:LiveSeq',1) + self.put(KE,PE,LensMode) + else: + print("Scienta spectra in progress") + + def _updateAttributes(self,filepath=None): + """ + filepath is the full path to the xml file + filepath = None; to update after making changes + filepath='/xorApps/epics/synApps_6_1/ioc/29idcScienta/iocBoot/ioc29idcScienta/HDF5Attributes.xml' + + from 29idcScienta:HDF1: screen + More (under process plugin) + NDPluginBase Full + """ + if filepath is None: + print(caget(self._savePlugin+"NDAttributesFile",as_string=True)) + else: + caput(self._savePlugin+"NDAttributesFile",filepath) + time.sleep(1) + print(caget(self._savePlugin+"NDAttributesStatus",as_string=True)) + + + def _spectraErrorCheck(self,KElist,PassEnergy,Frames,LensMode,**kwargs): + """ + error checking to see if parameters are allowed + """ + error=[] + parms={} + for KE in list(KElist[0:-1]): + error=self._errorCheck(KE,PassEnergy,LensMode,Frames,**kwargs) + + if len(error) > 0: + print(error) + return error + + def _spectra_Swept(self,KEstart,KEstop,KEstep,PE): + """ + setting up for a swept spectra, does not set the LensMode, PassEnergy or Frames + """ + print("setting SpectraMode") + caput(self.PHV+"SpectraMode", "Sweep") + time.sleep(1) + #input pass energy setpoint (doesn't change util KE is changed but needed for calcs) + caput(self.PHV+"PassEnergy_Set",PE) + time.sleep(0.25) + #input spectra parameters + caput(self.PHV+"sweepStartEnergy.VAL",KEstart);time.sleep(0.25) #added 20220317 - sweep calcs need time to process or you get weird stuff + caput(self.PHV+"sweepStopEnergy.VAL",KEstop);time.sleep(0.25) #added 20220317 - sweep calcs need time to process or you get weird stuff + caput(self.PHV+"sweepStepEnergy.VAL",KEstep) + time.sleep(1) + #Re-Calc + #print('Yes Re-Calc') + #caput(self.PHV+"SweepReCalc.PROC",1) + #time.sleep(1) + #Load spectra parameters + caput(self.PHV+"SweepLoadFanout.PROC",1) + time.sleep(1) + + + def _spectra_BabySwept(self, KEcenter): + """ + setting up for a Baby-Swept + """ + #setting SpectraMode + caput(self.PHV+"SpectraMode", "Baby-Sweep") + time.sleep(1) + #input spectra parameters + caput(self.PHV+"babySweepCenter.VAL",KEcenter) + time.sleep(1) + #Load spectra parameters + caput(self.PHV+"SweepLoadFanout.PROC",1) + time.sleep(1) + #settling time + #caput(self.PHV+"scan2.PDLY",0.25) + #caput(self.PHV+"scan2.DDLY",0.1) + + def _spectra_Fixed(self,KEcenter): + """ + setting up for Fixed + """ + #setting SpectraMode + caput(self.PHV+"SpectraMode", "Fixed") + caput("29idcScienta:HV:SpectraMode", "Fixed") + time.sleep(1) + #input spectra parameters + caput(self.PHV+"fixedEnergy.VAL",KEcenter) + time.sleep(1) + + def _spectraSetup(self,EAlist,**kwargs): + """ + Writes EAlist to the appropriate PVs and does error checking + and return scanType, scanPV, KElist, parms + **kwargs + run = True; will write the PVs (False just does error checking) + LensMode = "Angular" + debug = False + + """ + kwargs.setdefault("debug",False) + kwargs.setdefault("run",True) + kwargs.setdefault("LensMode","Angular") + + if kwargs['debug']: + print("\n\n _spectraSetup") + print("EAlist",EAlist) + + scanType="spectra" + if EAlist[-1] == "BS": + BS=True + EAlist=EAlist[0:-1] + else: + BS=False + Sweeps=EAlist[-1] + Frames=EAlist[-2] + PassEnergy=EAlist[-3] + EnergyMode=EAlist[0] + KElist=np.array(EAlist[1:-3]) + LensMode=kwargs['LensMode'] + + + if kwargs['debug']: + print("KElist: ",KElist) + + parms={'LensMode':LensMode,'PassEnergy':PassEnergy,'KineticEnergy':KElist[0],'Frames':Frames} + + #checking parameters are valid + error=self._spectraErrorCheck(KElist,PassEnergy,Frames,LensMode) + if len(error) == 0: #passed check + #Checking Progress + if self._spectraStatus() == 1: + print("Spectra in Progess") + + # writing scan parameters + else: + if len(EAlist)==7: #Swept Mode + scanType="Sweep" + self._spectra_Swept(KElist[0],KElist[1],KElist[2],PassEnergy) + parms={'LensMode':LensMode,'PassEnergy':PassEnergy,'KineticEnergy':KElist[0]-.01,'Frames':Frames} + elif len(EAlist)==5: #fixed or baby sweep + if BS is True: + scanType="Baby-Sweep" + self._spectra_BabySwept(KElist[0]) + parms={'LensMode':LensMode,'PassEnergy':PassEnergy,'KineticEnergy':KElist[0]-.01,'Frames':Frames} + else: + scanType="Fixed" + self._spectra_Fixed(KElist[0]) + parms={'LensMode':LensMode,'PassEnergy':PassEnergy,'KineticEnergy':KElist[0]-.01,'Frames':Frames} + else: + print("not a valid number of parameters") + #PV to initate scan" + scanPV=self.PHV+"ScanTrigger" + return scanType, scanPV, KElist, parms + + def _spectraMessage(self,scanType, scanPV, KElist): + """ + prints KE range for spectra + """ + message=str(scanType)+" scan KE: " + for KE in KElist: + message+=str(KE)+" | " + return message[0:-2] + + + + def spectra(self,EAlist,**kwargs): + """ + takes a Scienta spectra based on the number or parameters in EAlist + Sweeps are handled by scanRecord outside of this modual (see scanEA) + + Fixed Mode:["KE",CenterEnergy,PassEnergy,Frames,Sweeps] (5) + Swept Mode:["KE",StartEnergy,StopEnergy,StepEnergy,PassEnergy,Frames,Sweeps] (7) + Baby Sweep (dither):["KE",CenterEnergy,PassEnergy,Frames,Sweeps,"BS"] (6) + + **kwargs: + debug=False + run=True (executes the scan); False for error checking only + LensMode = Angular (default) + """ + kwargs.setdefault("debug",False) + kwargs.setdefault("run",True) + + #Sending Parmeters to _spectraSetup + scanType, scanPV, KElist, parms =self._spectraSetup(EAlist,**kwargs) + + if kwargs['debug']: + print(scanType,scanPV, KElist) + else: + print(scanType, "KE: ", KElist) + #Getting Filename info + fpath=caget(self._savePlugin+"FileName_RBV",as_string=True)+"_ " + fnum=caget(self._savePlugin+"FileNumber",as_string=True) + + + if kwargs['run'] is True: + dateandtime=time.strftime("%a %d %b %Y %H:%M:%S",time.localtime()) + print("\t"+fpath+fnum+" started at ",dateandtime,"\r") + self.put(parms['KineticEnergy'],parms['PassEnergy'],LensMode=parms['LensMode'],Frames=parms['Frames']) + caput(scanPV,1,wait=True,timeout=129600)#timeout=36 hours + dateandtime=time.strftime("%a %d %b %Y %H:%M:%S",time.localtime()) + print("\t"+fpath+fnum+" finished at ",dateandtime,"\r") + + diff --git a/build/lib/iexcode/instruments/VLS_PGM.py b/build/lib/iexcode/instruments/VLS_PGM.py new file mode 100644 index 0000000000000000000000000000000000000000..8f7bfdc225a080961c962b0d084059f2b535f179 --- /dev/null +++ b/build/lib/iexcode/instruments/VLS_PGM.py @@ -0,0 +1,739 @@ +""" +functions used for the mono +""" + +import time +import numpy as np + + +from epics import caget,caput +from iexcode.instruments.IEX_endstations import * +from iexcode.instruments.utilities import print_warning_message,read_dict + + +############################################################################################################## +################################ mono ############################## +############################################################################################################## +def mono_grating_names(): + """ + List of grating names + + """ + ext = ['C', 'D', 'E', 'F', 'G', 'H', 'I', "J", "K", "L" ] + GRT_names = ["MEG_Imp","HEG","MEG","Dummy", "not used", "not used", "not used","not used","not used","not used"] + GRT_names=GRT_names[0:2] # only use the first 3 slots + return GRT_names + +def mono_mirror_names(): + """ + List of grating names + + """ + ext = ['C', 'D', 'E', 'F', 'G', 'H', 'I', "J", "K", "L" ] + MIR_names = ["Au", "Silicon", "Carbon","not used","not used","not used","not used","not used","not used","not used"] + MIR_names=MIR_names[0:2] # only use the first 3 slots + return MIR_names + +def mono_extensions(): + """ + extension used for the mono mirror and grating locations + """ + ext = ['C', 'D', 'E', 'F', 'G', 'H', 'I', "J", "K", "L" ] + return ext + +def mono_energy_range(GRT=None): + """ + returns hv_min,hv_max, the minimum and maxium energy achievable the the specified grating + """ + if GRT == None: + GRT = mono_grating_get() + + if GRT == 'HEG': + hv_min=120 + hv_max=2200 + elif GRT == 'MEG': + hv_min=120 + hv_max=3000 + return hv_min,hv_max + +def mono_get_all(verbose=False): + """ + gets hv, hv_sp,grating,mirror + + Previously: Mono_Optics + """ + d = mono_get_all_extended(verbose=False) + vals = { + 'hv':d['ENERGY_MON'], + 'hv_sp':d['ENERGY_SP'], + 'grating':d['GRT'], + 'mirror':d['MIR'], + } + if verbose: + print(" hv: "+"%.2f" % vals['hv'], "eV, hv_sp: " % vals['hv_sp']) + print(" grating : "+vals['grating']," mirror : "+vals['mirror']) + return vals + +def mono_grating_num(): + """returns the current grating num""" + return caget('29idmonoGRT_TYPE_MON') + +def mono_mirror_num(): + """returns the current mirror num""" + return caget('29idmonoMIR_TYPE_MON') + +def mono_pvs(grt_num=None,mir_num=None): + """ + returns a dictionary with all the mono pvs + """ + if grt_num is None: + grt_num = mono_grating_num() + if mir_num is None: + mir_num = mono_mirror_num() + + ext=mono_extensions() + + d={ + 'energy':"29idmono:ENERGY_MON", + 'energy_sp':"29idmono:ENERGY_SP", + 'grt_density':"29idmono:GRT_DENSITY", + 'grt_offset':'29idmonoGRT:P_OFFSETS.'+ext['grt_num'], + 'grt_b2':'29idmonoGRT:B2_CALC.'+ext['grt_num'], + 'grt_pos':'29idmonoGRT:X_DEF_POS.'+ext['grt_num'], + 'grt_LD':'29idmonoGRT:TYPE_CALC.'+ext['grt_num'], + 'grt_tun0':'29idmonoGRT:TUN0_CALC.'+ext['grt_num'], + 'grt_tun1':'29idmonoGRT:TUN1_CALC.'+ext['grt_num'], + 'grt_tun2':'29idmonoGRT:TUN2_CALC.'+ext['grt_num'], + 'grt_tun3':'29idmonoGRT:TUN3_CALC.'+ext['grt_num'], + 'grt_type_sp':"29idmonoGRT_TYPE_SP", + 'grt_move':"29idb:'gr:move", + 'grt_P_status':"29idmonoGRT:P_AXIS_STS", + 'mir_P_status':"29idmonoMIR:P_AXIS_STS", + 'grt_X_status':"29idmonoGRT:X_AXIS_STS", + 'mir_X_status':"29idmonoMIR:X_AXIS_STS", + 'mir_offset':'29idmonoMIR:P_OFFSETS.'+ext['mir_num'], + 'mir_pos':'29idmonoMIR:X_DEF_POS.'+ext['mir_num'], + 'cff':'29idmono:CC_MON', + 'arm':'29idmono:PARAMETER.G' + + } + +def mono_get_all_extended(verbose=False): + """ + gets the mono parameters for the current grating and mirror + returns a dictionary with those values + + Previously: Mono_Optics + """ + grt_num = mono_grating_num() + mir_num = mono_mirror_num() + grt_names = mono_grating_names() + mir_names = mono_mirror_names() + + ext=mono_extensions() + + pvs = mono_pvs(grt_num=None,mir_num=None) + vals={ + 'grt_num':grt_num, + 'mir_num':mir_num, + 'grt':grt_names[grt_num], + 'mir':mir_names[mir_num], + 'energy':caget(pvs['energy']), + 'energy_sp':caget(pvs['energy_sp']), + 'grt_density':caget(pvs['energy_sp']), + 'grt_offset':caget(pvs['grt_offset']), + 'grt_b2':caget(pvs['grt_offset']), + 'grt_pos':caget(pvs['grt_pos']), + 'grt_LD':caget(pvs['grt_LD']), + 'grt_tun0':caget(pvs['grt_tun0']), + 'grt_tun1':caget(pvs['grt_tun1']), + 'grt_tun2':caget(pvs['grt_tun2']), + 'grt_tun3':caget(pvs['grt_tun3']), + 'grt_P_status':caget(pvs['grt_P_status']), + 'mir_P_status':caget(pvs['mir_P_status']), + 'grt_X_status':caget(pvs['grt_X_status']), + 'mir_X_status':caget(pvs['mir_X_status']), + 'mir_offset':caget(pvs['mir_offset']), + 'mir_pos':caget(pvs['mir_pos']), + 'CFF':caget('29idmono:CC_MON'), + 'arm':caget('29idmono:PARAMETER.G') + } + + if verbose: + for key in vals.keys(): + print(key,vals[key]) + + return vals + +def mono_grating_get(): + """ + returns the grating density and the string name for the grating + """ + return mono_get_all_extended()['grt'] + +def mono_energy_get(): + """ + returns the grating density and the string name for the grating + """ + return mono_get_all_extended()['energy'] + +def mono_grating_density_get(): + """ + returns the grating density and the string name for the grating + """ + return mono_get_all_extended()['grt_density'] + +def mono_energy_set(hv_eV,verbose=True): + """ + sets the mono energy + + Previously: SetMono + """ + hv_min, hv_max = mono_energy_range() + pv = mono_pvs()['energy_sp'] + if hv_min <= hv_eV <= hv_max: + caput(pv,hv_eV,wait=True,timeout=60) + time.sleep(2.5) + + mono_status = mono_status_get() + while True: + if mono_status() > 1: + mono_resest_pitch() + caput(pv,hv_eV,wait=True,timeout=60) + time.sleep(2.5) + else: + break + if verbose: + print("Mono set to",str(hv_eV),"eV") + +def mono_scan_pvs(): + """ + returns the pvs to be used in scanning + """ + val_pv = mono_pvs()['energy_sp'] + rbv_pv = mono_pvs()['energy'] + return val_pv, rbv_pv + +def mono_status_get(): + """ + returns the status of the mirror (GRT * MIR) + 1 = ready + + + Previously Mono_Status + """ + pvs = mono_pvs()['energy'] + mir_P_status = caget(pvs['mir_P_status']) + grt_P_status = caget(pvs['grt_P_status']) + mir_X_status = caget(pvs['mir_P_status']) + grt_X_status = caget(pvs['grt_P_status']) + mirror_status = mir_P_status * mir_X_status + grating_status = grt_P_status * grt_X_status + return mirror_status*grating_status + + +def mono_grating_translate(grating,verbose=True): + """ + Translate between the different grating positions + + Warning: this does not close the shutters use XX + + Previously: Move_GRT + """ + current_grating=mono_grating_get() + hv_eV = mono_energy_get() + + try: + grating_state = mono_grating_names().index(grating) + + except: + print_warning_message(grating+' not a valid grating') + + if current_grating != grating: + pvs=mono_pvs() + caput(pvs['grt_type_sp'],grating_state,wait=True,timeout=18000) + caput(pvs['grt_move'],1,wait=True,timeout=18000) + while True: + if mono_status_get() > 1: + time.sleep(5) + else: + break + mono_energy_set(hv_eV) + + else: + if verbose: + print("grating is already "+grating) + + if verbose: + print("Mono Grating:",grating) + + +def mono_resest_pitch(): + """ + resets the MIR and GRT pitch interlocks after a following error or limit + Previoulsy part of SetMono + """ + caput("29idmonoMIR:P.STOP",1) + time.sleep(1) + caput("29idmonoGRT:P.STOP",1) + time.sleep(1) + print('Mono pitch was reset') + +def mono_kill(): + """ + kills the mono pitch motors + + Previously: Kill_Mono + """ + caput("29idmonoMIR:P_KILL_CMD.PROC",1) + caput("29idmonoGRT:P_KILL_CMD.PROC",1) +# caput("29idmonoGRT:X_KILL_CMD.PROC",1) + time.sleep(5) + caput("29idmono:STOP_CMD.PROC",1) +# caput("29idmonoGRT:X_HOME_CMD.PROC",1) + + +def mono_stop(): + """ + presses the stop button on the mono motors + + Previously: Stop_Mono + """ + caput("29idmono:STOP_CMD.PROC",1) + time.sleep(5) + +def mono_enable(): + """ + re-enable the mono motors + + Previously: Enable_Mono + """ + caput("29idmonoGRT:X_ENA_CMD.PROC",1) + caput("29idmonoGRT:P_ENA_CMD.PROC",1) + caput("29idmonoMIR:X_ENA_CMD.PROC",1) + caput("29idmonoMIR:P_ENA_CMD.PROC",1) + +def mono_limits_reset(): + """ + resest the mono low limit to 200 + was changed in the pmac to the wrong value so we need to do this + + Previously: Reset_Mono_Limits + """ + # caput("29idmono_GRT_TYPE_SP.ONST", 'MEG_PA') + # caput("29idmono_GRT_TYPE_SP.TWST", 'HEG_JY') + # caput("29idmono_GRT_TYPE_SP.THST", 'MEG_JY') + caput("29idmono:ENERGY_SP.DRVL",200) + caput("29idmono:ENERGY_SP.LOW",200) + caput("29idmono:ENERGY_SP.LOLO",200) + caput("29idmono:ENERGY_SP.LOPR",200) + print("Mono limits have been reset.") + +def mono_cff_print(): + """ + print the cff tuning parameters and arm for the current grating + + Previously: Get_CFF + """ + d = mono_get_all_extended + cff = d['cff'] + tun0 = d['grt_tun0'] + tun1 = d['grt_tun1'] + tun2 = d['grt_tun2'] + tun3 = d['grt_tun3'] + arm = d['arm'] + print(" cff : "+"%.4f" % cff , " exit arm: "+"%.1f" % arm,"mm") + print(" tun0 : "+"%.4e" % tun0 , " tun1: "+"%.4e" % tun1) + print(" tun2 : "+"%.4e" % tun2 , " tun3: "+"%.4e" % tun3) + +def mono_parameters_pv(grt_num=None,mir_num=None): + """ + returns dictionary with mono_parameter for current grating/mirror + """ + if grt_num is None: + grt_num = mono_grating_num()() + if mir_num is None: + mir_num = mono_mirror_num()() + + ext = mono_extensions() + + d={ + 'mir_offset':"29idmonoMIR:P_OFFSETS."+ext[mir_num], + 'mir_pos':"29idmonoMIR:X_DEF_POS."+ext[mir_num], + 'grt_offset':"29idmonoGRT:P_OFFSETS."+ext[grt_num], + 'grt_pos':"29idmonoGRT:X_DEF_POS."+ext[grt_num], + 'grt_density':"29idmonoGRT:TYPE_CALC."+ext[grt_num], + 'grt_b2':"29idmonoGRT:B2_CALC."+ext[grt_num] + } + return d + + +def mono_parameters_get(): + """ + Gets the mono parameters and prints them for the History + + Previously: Mono_Parameters_Get + """ + date=time.strftime("%Y%m%d",time.localtime()) + mirList = mono_mirror_names() + grtList = mono_grating_names() + pvList = mono_extensions() + + #MIR + txt="MonoParm[\'"+date+"\']= {\n\t" + for i in range(0,len(mirList)): + d = mono_parameters_pv(mir_num=i) + mir = mirList[i] + offset = caget(d['mir_offset']) + position = caget(d['mir_pos']) + txt+="\'"+mir+"\':["+str(offset)+","+str(position)+"]," + + #GRT + txt+="\n\t" + for i in range(0,len(grtList)): + d = mono_parameters_pv(grt_num=i) + grt = grtList[i] + offset = caget(d['grt_offset']) + position = caget(d['grt_pos']) + density = caget(d['grt_density']) + b2 = caget(d['grt_b2']) + txt+="\'"+grt+"\':["+str(offset)+","+str(position)+","+str(density)+","+str(b2)+"]," + + txt+="}" + print(txt) + +def mono_parameters_history_read(date): + """ + Dictionary of Mono parameters used in Mono_Parameters(date) which sets the parameters + #MonoParm['date']={'Au':[],Si:[],'Carbon':[],'MEG_Imp':[],'HEG_JY':[],'MEG_JY':[]} + Mono_Parameters_Set(date) writes the parameters from the Dictionary + + Previously: Mono_Parameters_History + """ + #MonoParm['date']={'Au':[],Si:[],'Carbon':[],'MEG_Imp':[],'HEG_JY':[],'MEG_JY':[]} + + MonoParm=read_dict('mono_parameters.txt') + return MonoParm[date] + + +def mono_parameters_history_write(date): + """ + + Previously: Mono_Parameters_Set + """ + hv_eV=caget("29idmono:ENERGY_SP") + MonoParm=mono_parameters_history_read(date) + pvList=['C','D','E'] + mirList=["Au","Si","Carbon"] + for i in range(0,len(mirList)): + mir=mirList[i] + caput("29idmonoMIR:P_OFFSETS."+pvList[i],MonoParm[mir][0]) + caput("29idmonoMIR:X_DEF_POS."+pvList[i],MonoParm[mir][1]) + grtList=["MEG_Imp", "HEG_JY", "MEG_JY"] + for i in range(0,len(grtList)): + grt=grtList[i] + caput("29idmonoGRT:P_OFFSETS."+pvList[i],MonoParm[grt][0]) + caput("29idmonoGRT:X_DEF_POS."+pvList[i],MonoParm[grt][1]) + caput("29idmonoGRT:TYPE_CALC."+pvList[i],MonoParm[grt][2]) + caput("29idmonoGRT:B2_CALC."+pvList[i],MonoParm[grt][3]) + time.sleep (1) + mono_energy_set(hv_eV,verbose=True) + + + +def mono_temperature_interlock(): + """ + userCalcOut to monitor the temperatures on the Mono if the temperature gets too high then it closes the main shutter + #29idb:userCalcOut10.VAL =0 => OK; =1 => Too hot + + Previously: Mono_TemperatureInterlock + """ + pv='29idb:userCalcOut10' + caput(pv+'.DESC', 'Mono Temperature Interlock') + caput(pv+'.INPA','29idmono:TC1_MON CP NMS') + caput(pv+'.INPB','29idmono:TC2_MON CP NMS') + caput(pv+'.INPC','29idmono:TC3_MON CP NMS') + caput(pv+'.INPD','29idmono:TC4_MON CP NMS') + caput(pv+'.INPE','29idmono:TC5_MON CP NMS') + caput(pv+'.INPF','29idmono:TC6_MON CP NMS') + + caput(pv+'.H','31') + + caput(pv+'.CALC','A>H | B>H | C>H |D>H') + caput(pv+'OOPT','Transition To Non-zero') + caput(pv+'.OUT','PC:29ID:FES_CLOSE_REQUEST.VAL PP NMS') + + + +def mono_scan_fillin(hv_start,hv_stop,hv_step,**kwargs): + """ + fills in the scanRecord for scanning the mono + + puts the positioner in stay after scan + + **kwargs => scanRecord.fillin kwargs + positioner_settling_time: increased because busy record is too fast => 0.2 (default) + """ + kwargs.setdefault('positioner_settling_time',0.2) + + + #Setting up the ScanRecord for Mono in Table mode + val_pv, rbv_pv = mono_scan_pvs() + BL.mda.fillin(val_pv,rbv_pv,hv_start,hv_stop,hv_step,**kwargs) + + #mono needs to stay and have a longer settling time + BL.mda.positioner_after_scan("STAY") + + +def mono_scan_fillin_table(hv_array,**kwargs): + """ + fills in the scanRecord for scanning the mono + + puts the positioner in stay after scan + + **kwargs => scanRecord.fillin kwargs + positioner_settling_time: increased because busy record is too fast => 0.2 (default) + + """ + kwargs.setdefault('positioner_settling_time',0.2) + + #Setting up the ScanRecord for Mono in Table mode + val_pv, rbv_pv = mono_scan_pvs() + BL.mda.fillin.table(val_pv,rbv_pv,hv_array,**kwargs) + + #mono needs to stay and have a longer settling time + BL.mda.positioner_settling_time(kwargs['positioner_settling_time']) + BL.mda.positioner_after_scan("STAY") + +def mono_scan_after(**kwargs): + """ + resets mda after scanning the mono + """ + after_scan_pv = BL.mda.default_after_scan_seq + caput(after_scan_pv+".PROC",1) + BL.mda.positioner_after_scan("PRIOR POS") + + +############################################################################################################## +################################ aligmnent and commissioning ############################## +############################################################################################################## +def mono_motor_move(motor,value): + """ + for pitch motor => MIR:P or GRT:P + for translation motor => MIR:X or GRT:X + + Previously: Move_FMBMono + """ + val_pv,rbv_pv = mono_motor_scan_pvs() + caput(val_pv+".PREC",3) + caput(val_pv,value,wait=True,timeout=18000) + +def mono_motor_scan_pvs(motor): + """ + returns the rbv and val for scanning + """ + val_pv = "29idmono"+motor+"_SP" + rbv_pv = "29idmono"+motor+"_MON" + return val_pv,rbv_pv + +def mono_motor_scan_fillin(motor,start,stop,step,**kwargs): + """ + for pitch motor => MIR:P or GRT:P + for translation motor => MIR:X or GRT:X + + Previously: Scan_FMBMono + """ + val_pv,rbv_pv = mono_motor_scan_pvs(motor) + caput(val_pv+".PREC",3) # database sets .PREC==0. We want more digits than that. + + BL.mda.fillin(val_pv,rbv_pv,start,stop,step,**kwargs) + +def mono_zero_order(angle): + """ + puts the beam in zero order => grating/mirror are parallel + range ~1 - 5 degrees + + Previously: Mono_zero + """ + angle=angle*1.0 + caput("29idmonoMIR:P_POS_SP",angle,wait=True,timeout=18000) + caput("29idmonoMIR:P_MOVE_CMD.PROC",1,wait=True,timeout=18000) + caput("29idmonoGRT:P_POS_SP",angle,wait=True,timeout=18000) + caput("29idmonoGRT:P_MOVE_CMD.PROC",1,wait=True,timeout=18000) + print("Mono set to zero order: MIR_pitch = "+str(angle)+", GRT_pitch = "+str(angle)) + +def mono_angles_set(alpha,beta): #JM modified to monitor the ready, moving sequentialy ended up in crash sometimes + """ + Sets the mirror pitch (alpha) and grating pitch (beta) angles + + Previously: Mono_angle + """ + alpha=alpha*1.0 + beta=beta*1.0 + #Putting Setpoints Go + caput("29idmonoGRT:P_SP",alpha) + caput("29idmonoMIR:P_SP",beta) + ready=0 + while ready != 1: + time.sleep(0.1) + ready=caget('29idmono:ERDY_STS') + print("Mono set to zero order: MIR_pitch = "+str(alpha)+", GRT_pitch = "+str(beta)) + +def mono_pink_beam(): + """ + moves grating and mirror out of beam + x-rays will hit the pink beamstop + + Previously: Mono_pinkbeam + """ + caput("29idmonoMIR:P_POS_SP",0,0) + caput("29idmonoMIR:P_MOVE_CMD.PROC",0) + time.sleep(3) + caput("29idmonoGRT:P_POS_SP",0.0) + caput("29idmonoGRT:P_MOVE_CMD.PROC",0) + time.sleep(3) + caput("29idmonoMIR:X_POS_SP",-52) + caput("29idmonoMIR:X_MOVE_CMD.PROC",0) + time.sleep(3) + caput("29idmonoGRT:X_POS_SP",210) + caput("29idmonoGRT:X_MOVE_CMD.PROC",0,wait=True,timeout=18000) + +def mono_CC(): + """ + ##used for commissioning + + Previously: Mono_CC + """ + caput("29idmonoMIR_TYPE_SP",3) + caput("29idmonoMIR:X_DCPL_CALC.PROC",0) + caput("29idmonoGRT_TYPE_SP", 10) + caput("29idmonoGRT:X_DCPL_CALC.PROC",0) + + caput("29idmono:ENERGY_SP", 440) + +def mono_grating_offset_set(val,grt_num=None): + """ + sets the grating offset for the grating + + Previously: Mono_Set_GRT0 + """ + pvs=mono_pvs(grt_num,None) + caput(pvs['grt_offset'],val) + mono_get_all_extended(verbose=True) + +def mono_mirror_offset_set(val,mir_num=None): + """ + sets the mirror offset for the grating + + Previously: Mono_Set_MIR0 + """ + pvs=mono_pvs(None,mir_num) + caput(pvs['mir_offset'],val) + mono_get_all_extended(verbose=True) + +def mono_grating_mirror_offsets_set(mirror_offset): + """ + changes the mirror and grating offsets to maintain parallelism + After determining parallelism (zero order a=b) + Get the correct take-off angle delta, equivalent to scan ExitSlit_Vcenter + + Previously: Mono_Set_MIR0_GRT0,MIR_GRT_Offset,Mono_Set_MIR0_GRT0_all + """ + current_vals = mono_get_all_extended(verbose=False) + energy_sp = current_vals['energy_sp'] + mirror_offset_old = current_vals['mir_offset'] + + #get current grating offsets + grating_offsets=[] + for grt_num in range(0,3): + grating_offsets.append(mono_parameters_pv(grt_num=grt_num,mir_num=None)['grt_offset']) + + #calc mirror_offset - grating_grating + mir_grt_offsets = mirror_offset_old-np.array(grating_offsets) # list of MIR-GRT for all 3 gratings + + #set mirror_offset + mono_mirror_offset_set(mirror_offset) + + #set grating_offsets + for grt_num in range(0,3): + mono_grating_offset_set(mirror_offset - mir_grt_offsets[grt_num],grt_num) + + time.sleep (1) + mono_energy_set(energy_sp) + mono_get_all_extended(verbose=True) + + +def mono_grating_b2_set(val,grt_num=None): + """ + sets the grating offset for the grating + Previously: Mono_Set_b2 + """ + hv = mono_energy_get() + pvs = mono_pvs(grt_num,None) + caput(pvs['grt_b2t'],val) + time.sleep(1) + + mono_energy_set(hv) + mono_get_all_extended(verbose=True) + +def mono_cff_set(val,tune_num): + """ + sets the tuning parameters for the cff calculation + tune_num = order + + Previously: Mono_Set_cff + """ + hv = mono_energy_get() + pvs = mono_pvs() + + #get current info + current_vals = mono_get_all_extended(verbose=False) + grt_pitch = current_vals['grt_pitch'] + mir_pitch = current_vals['mir_pitch'] + print ('Pitch grating, mirror: ',grt_pitch,mir_pitch) + + #set the tuning coeffient + tun='tun'+str(tune_num) + caput(pvs[tun],val) + time.sleep(1) + + #set then energy + mono_energy_set(hv) + + #print differences in pitch + mono_get_all_extended(verbose=False) + grt_dif = grt_pitch-current_vals['grt_pitch'] + mir_dif = mir_pitch-current_vals['mir_pitch'] + + print('Pitch grating, mirror: ',current_vals['grt_pitch'],current_vals['mir_pitch']) + print('Differences : ',grt_dif,mir_dif) + +def mono_arm_set(distance_mm): + """ + sets the exit arm for the grating + + Previously: Mono_Set_ExitArm + """ + hv = mono_energy_get() + pvs = mono_pvs() + + #get current info + current_vals = mono_get_all_extended(verbose=False) + grt_pitch = current_vals['grt_pitch'] + mir_pitch = current_vals['mir_pitch'] + print ('Pitch grating, mirror: ',grt_pitch,mir_pitch) + + #set the exit arm + caput("29idmono:PARAMETER.G",distance_mm) + time.sleep(1) + + #set then energy + mono_energy_set(hv) + + #print differences in pitch + mono_get_all_extended(verbose=False) + grt_dif = grt_pitch-current_vals['grt_pitch'] + mir_dif = mir_pitch-current_vals['mir_pitch'] + + print('Pitch grating, mirror: ',current_vals['grt_pitch'],current_vals['mir_pitch']) + print('Differences : ',grt_dif,mir_dif) \ No newline at end of file diff --git a/build/lib/iexcode/instruments/__init__.py b/build/lib/iexcode/instruments/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e244a3c105e5bc09da608c5fd6134ba1ef425528 --- /dev/null +++ b/build/lib/iexcode/instruments/__init__.py @@ -0,0 +1,42 @@ + +""" from iexcode.instruments.AD_utilites import * +from iexcode.instruments.ARPES import * +from iexcode.instruments.bakeout import * +from iexcode.instruments.beamline import * +from iexcode.instruments.cameras import * +from iexcode.instruments.conversions_constants import * +from iexcode.instruments.current_amplifiers import * +from iexcode.instruments.diagnostics import * +from iexcode.instruments.electron_analyzer import * +from iexcode.instruments.encoders import * +from iexcode.instruments.files_and_folders import * +from iexcode.instruments.FMB_mirrors import * +from iexcode.instruments.gate_valves import * +from iexcode.instruments.hxp_mirrors import * +from iexcode.instruments.IEX_endstations import * +from iexcode.instruments.IEX_VPU import * +from iexcode.instruments.Kappa import * +from iexcode.instruments.Kappa_det import * +from iexcode.instruments.Kappa_Euler import * +from iexcode.instruments.Lakeshore_335 import * +from iexcode.instruments.logfile import * +from iexcode.instruments.m3r import * +from iexcode.instruments.Motors import * +from iexcode.instruments.mpa import * +from iexcode.instruments.remote_controlers import * +from iexcode.instruments.resolution import * +from iexcode.instruments.s29_temp_cntl import * +from iexcode.instruments.scalers import * +from iexcode.instruments.Scienta import * +from iexcode.instruments.shutters import * +from iexcode.instruments.slits import * +from iexcode.instruments.spec_stuff import * +from iexcode.instruments.staff import * +from iexcode.instruments.storage_ring import * +from iexcode.instruments.userCalcs import * +from iexcode.instruments.utilities import * +from iexcode.instruments.VLS_PGM import * +from iexcode.instruments.vortexs29 import * +from iexcode.instruments.xrays import * + + """ diff --git a/build/lib/iexcode/instruments/bakeout.py b/build/lib/iexcode/instruments/bakeout.py new file mode 100644 index 0000000000000000000000000000000000000000..94dfd1a00e1173fabb280bf94cd6090258599878 --- /dev/null +++ b/build/lib/iexcode/instruments/bakeout.py @@ -0,0 +1,193 @@ +from time import sleep +from os import mkdir +from os.path import exists + +from epics import caget,caput + +from iexcode.instruments.files_and_folders import get_next_fileNumber, check_run +from iexcode.instruments.scanRecord import * + +############################################################################################################## +############################## Scan Bakeout ############################## +############################################################################################################## + +def bakout_scan(scan_ioc_name,chamber): + """ + sets up the scan record to record temperature and pressures + + scan_ioc_name = 'ARPES', 'Kappa','Test' + chamber = "Beamline"; Yokawgawa + all beamline ion pumps and vacuum gauges + chamber = "Mono"; Beamline + mono thermocouples + chamber = "ARPES"; Beamline + ARPES pressures and temperatures + chamber = "Kappa"; Beamline + Kappa pressures and temperatures + chamber = "Stinger"; Stinger temperatures + ARPES and Kappa temperatures and pressures + + Previously: Scan_Bakeout + """ + #setting the folders and save datat + run = check_run() + folder='/net/s29data/export/data_29idb/Bakeout/' + subfolder='/'+chamber+'/'+run + prefix='mda_' + + scan_ioc = '29id'+scan_ioc_name+":" + + caput(scan_ioc+'saveData_fileSystem',folder) + caput(scan_ioc+'saveData_subDir',subfolder) + caput(scan_ioc+'saveData_baseName',prefix) + + MyPath="/net/s29data/export/data_29idb/Bakeout/"+chamber+"/"+run + print("\nBakeout folder: " + MyPath) + if not (exists(MyPath)): + mkdir(MyPath) + sleep(1) + FileNumber=1 + else: + FileNumber=get_next_fileNumber(MyPath,prefix[:-1]) + caput(scan_ioc+'saveData_scanNumber',FileNumber) + + sleep(5) + SaveStatus=caget(scan_ioc+'saveData_status',as_string=True) + SaveMessage=caget(scan_ioc+'saveData_message',as_string=True) + print("\nSave Status "+scan_ioc+" "+SaveStatus+" - "+SaveMessage) + + #setting up scan record + detector_dictionary = bakeout_detector_dictionary(chamber) + + #caput("29idb:ca1:read.SCAN",0) + #trigger_dictionary = {1:"29idb:ca1:read"} + trigger_dictionary = {1:""} + + before_scan_pv = "" + after_scan_pv = "" + + mda_scan = ScanRecord(scan_ioc,detector_dictionary,trigger_dictionary,before_scan_pv,after_scan_pv) + + mda_scan.time_scan(99999,60) + + + +def bakeout_detector_dictionary(chamber): + """ + returns a dictionary of the default detectors + + """ + thermocouples={ + 1:"29iddau1:dau1:001:ADC", + 2:"29iddau1:dau1:002:ADC", + 3:"29iddau1:dau1:003:ADC", + 4:"29iddau1:dau1:004:ADC", + 6:"29iddau1:dau1:006:ADC", + 7:"29iddau1:dau1:007:ADC", + 8:"29iddau1:dau1:008:ADC", + 9:"29iddau1:dau1:009:ADC", + 10:"29iddau1:dau1:010:ADC", + } + ion_gauges={ + 21:"29idb:VS1A.VAL", + 22:"29idb:VS2A.VAL", + 23:"29idb:VS3AB.VAL", + 24:"29idb:VS4B.VAL", + 25:"29idb:VS5B.VAL", + 26:"29idb:VS6B.VAL", + 27:"29idb:VS7B.VAL", + 28:"29idb:VS8C.VAL", + 29:"29idb:VS8CSP.VAL", + 30:"29idb:VS9C.VAL", + 31:"29idb:VS10C.VAL", + 32:"29idb:VS8D.VAL", + 33:"29idb:VS9D.VAL", + 34:"29idb:VS10D.VAL", + } + ion_pumps={ + 41:"29idb:IP1A.VAL", + 42:"29idb:IP2A.VAL", + 43:"29idb:IP3A.VAL", + 44:"29idb:IP3B.VAL", + 45:"29idb:IP4B.VAL", + 46:"29idb:IP5B.VAL", + 47:"29idb:IP6B.VAL", + 48:"29idb:IP7B.VAL", + 49:"29idb:IP7C.VAL", + 51:"29idb:IP8C1.VAL", + 52:"29idb:IP8C2.VAL", + 53:"29idb:IP9C.VAL", + 54:"29idb:IP10C1.VAL", + 55:"29idb:IP10C2.VAL", + 56:"29idb:IP7D.VAL", + 57:"29idb:IP8D1.VAL", + 58:"29idb:IP8D2.VAL", + 59:"29idb:IP9D.VAL", + 60:"29idb:IP10D1.VAL", + 61:"29idb:IP10D2.VAL", + } + + mono = { + 11:"29idmono:TC1_MON", + 12:"29idmono:TC2_MON", + 13:"29idmono:TC3_MON", + 14:"29idmono:TC4_MON", + 15:"29idmono:TC5_MON", + 16:"29idmono:TC6_MON", + } + + ARPES = { + 11:"29idc:VS11C.VAL", + 12:"29idc:VSCUBE.VAL", + 13:"29idc:IP11C1.VAL", + 14:"29idc:IP11C2.VAL", + 15:"29idc:IPCUBE.VAL", + 16:"29idARPES:LS335:TC1:IN1", + 17:"29idARPES:LS335:TC1:IN2", + } + + Kappa = { + 11:"29idb:VS11D.VAL", + 12:"29idb:VS12D.VAL", + 13:"29idd:LS331:TC1:SampleA", + 14:"29idd:LS331:TC1:SampleB", + } + + Stinger = { + 1:"29idc:LS340:TC2:Control", + 2:"29idc:LS340:TC2:Sample", + + 3:"29idARPES:LS335:TC1:IN1", + 4:"29idARPES:LS335:TC1:IN2", + + 5:"29idd:LS331:TC1:SampleA", + 6:"29idd:LS331:TC1:SampleB", + + 7:"29idc:VS11C.VAL", + 8:"29idc:IP11C1.VAL", + 9:"29idc:IP11C2.VAL", + + 10:"29idb:VS11D.VAL", + } + d={} + if chamber.lower() == "Beamline".lower(): + d.update(thermocouples) + d.update(ion_gauges) + d.update(ion_pumps) + print("ScanRecord ready") + + if chamber.lower() == "Mono".lower(): + d.update(thermocouples) + d.update(ion_gauges) + d.update(ion_pumps) + d.update(mono) + print('Setting up Mono temperatures') + + if chamber.lower() == "ARPES".lower(): + d.update(ARPES) + print('Setting up ARPES temperatures') + + if chamber.lower() == "Kappa".lower(): + d.update(Kappa) + print('Setting up Kappa temperatures') + + if chamber.lower() == "Stinger".lower(): + d.update(Stinger) + print('Setting up Stinger temperatures') + + return d diff --git a/build/lib/iexcode/instruments/beamline.py b/build/lib/iexcode/instruments/beamline.py new file mode 100644 index 0000000000000000000000000000000000000000..6817162fdad3533041139170c96a0fa810e51958 --- /dev/null +++ b/build/lib/iexcode/instruments/beamline.py @@ -0,0 +1,94 @@ + +""" +short name for functions used with or without x-rays + +""" + +import numpy as np +from time import sleep + +from epics import PV +from iexcode.instruments.IEX_endstations import * + + +############################################################################################################## +########################### Scan stuff ###################### +############################################################################################################## +def scan_fillin(VAL,RBV,start,stop,steps_points,**kwargs): + """ + fills in the scan record for the curretn beamline ioc + """ + BL.mda.fillin(VAL,RBV,start,stop,steps_points,**kwargs) + +def scan_fillin_table(VAL,RBV,my_table,**kwargs): + """ + fills in the scan record for the curretn beamline ioc + """ + BL.mda.fillin_table(VAL,RBV,my_table,**kwargs) + +def scan_go(**kwargs): + """ + Starts a scan + by default: scanDIM=1 + Logging is automatic: use **kwargs or the optional logging arguments see scanlog() for details + kwargs: + X-ray = True (default), does shutter checks + = False no shutter checks + """ + BL.mda.go(verbose=True,**kwargs) + + +def last_mda(): + """ + returns the last mda file number in the ioc defined by BL_ioc + Previously: LastMDA + """ + filenum = BL.mda.lastFileNum() + return filenum + + + +############################################################################################################## +############################## Beeper ############################## +############################################################################################################## + + + +def print_beeper(scanDIM=1): + """ + Prints pv to copy/paste into the beeper + + Previously: Print_Beeper + """ + branch=BL.branch + if branch == "c": + print("29idcEA:det1:Acquire") + pv=BL.ioc()+":scan"+str(scanDIM)+".FAZE" + print(pv) + print("ID29:BusyRecord") + + +def branch_cams_enable(branch=BL.branch): + """ + """ + cam_dict={'c':[0,1,2],'c':[3,4,6]} # index of cam_list + pvcam1=PV("29id_ps1:cam1:Acquire") + pvcam2=PV("29id_ps2:cam1:Acquire") + pvcam3=PV("29id_ps3:cam1:Acquire") + pvcam4=PV("29id_ps4:cam1:Acquire") + pvcam6=PV("29id_ps6:cam1:Acquire") + pvcam7=PV("29id_ps7:cam1:Acquire") + cam_list=[pvcam1,pvcam2,pvcam3,pvcam4,pvcam6,pvcam7] + sleep(0.1) + for pvcam in cam_list: # turn OFF all cam + try: + if pvcam.connected: pvcam.put(0) + except: + pass + for i in cam_dict[branch]: # turn ON relevant cam + try: + if cam_list[i].connected: cam_list[i].put(1) + else: print(cam_list[i].pvname+' not connected') + except: + pass + diff --git a/build/lib/iexcode/instruments/cameras.py b/build/lib/iexcode/instruments/cameras.py new file mode 100644 index 0000000000000000000000000000000000000000..1436d9b1a71c4892faa97870f1835e1003bc1bd9 --- /dev/null +++ b/build/lib/iexcode/instruments/cameras.py @@ -0,0 +1,52 @@ + +from epics import caget, caput + +from iexcode.instruments.userCalcs import userStringSeq_clear +from iexcode.instruments.AD_utilities import * +from iexcode.instruments.IEX_endstations import * + + +def cam_pv_dictionary(cam_num): + """ + dictionary of pv names for the beamline cameras + """ + d={ + 1:"29id_ps1:", + 2:"29id_ps2:", + 3:"29id_ps3:", + 4:"29id_ps4:", + 5:"29idarv5:", + 6:"29id_ps6:", + } + return d[cam_num] + +def cam_scan_setup(cam_num,ADtype='TIFF',**kwargs): + """ + sets up the BL scanRecord to trigger the camera (trigger - 2) + """ + ADplugin = cam_pv_dictionary(cam_num)+ADtype+":" + ADplugin_ScanSetup(ADplugin,BL.mda, **kwargs) + +def cam_snap(cam_num,ADtype='TIFF',**kwargs): + """ + takes a camera image and saves it in the user folder + + **kwargs: + ExposureTime: changes both the exposure time and the acquire time for the snapshot + resets after acquisition + FreeRun: True => disable setting and go back to continuous acquision + False => leave saving enabled and camera in single acquision + + """ + ADplugin = cam_pv_dictionary(cam_num)+ADtype+":" + AD_SaveFileSetup(ADplugin,BL.mda,**kwargs) + AD_snap(ADplugin,**kwargs) + +def cam_live(cam_num,ADtype='TIFF',**kwargs): + """ + puts camera in no save and continuous + a.k.a free run + + """ + ADplugin = cam_pv_dictionary(cam_num)+ADtype+":" + AD_FreeRun(ADplugin,**kwargs) diff --git a/build/lib/iexcode/instruments/conversions_constants.py b/build/lib/iexcode/instruments/conversions_constants.py new file mode 100644 index 0000000000000000000000000000000000000000..45f1aea59c570ce29108135e34ade471f665f24b --- /dev/null +++ b/build/lib/iexcode/instruments/conversions_constants.py @@ -0,0 +1,109 @@ +import numpy as np + +from epics import caget + +############################################################################################################## +############################## conversions ############################## +############################################################################################################## +h=4.135667516e-15 +c=299792458 + +def deg2rad(angle_deg): + angle_rad=angle_deg*np.pi/180 + return angle_rad + +def rad2deg(angle_rad): + angle_deg=angle_rad*180/np.pi + return angle_deg + +def eV2Lambda(eV): + """ + Converts energy (eV) into wavelenght (Angstrom) + """ + + Angstrom = h*c/eV*1e9*10 + return Angstrom + +def Lambda2eV(Angstrom): + """ + Converts wavelenghth (Angstrom) into energy (eV) + """ + + eV = h*c/Angstrom*1e9*10 + return eV + +############################################################################################################## +############################## Kappa to Euler Conversion ############################## +############################################################################################################## +def Kappa2Fourc(ang1,ang2,ang3,conversion,k_arm=50): + + a,b,c=0,0,0 + if conversion=='Kappa': + a,b,c=EtoK(ang1,ang2,ang3,k_arm) + print(("\n"+"th = "+str(ang1))) + print(("chi = "+str(ang2))) + print(("phi = "+str(ang3))) + print("~~~~~~~~") + print(("kth = "+str(a))) + print(("kap = "+str(b))) + print(("kphi = "+str(c)+"\n")) + elif conversion=='fourc': + a,b,c=KtoE(ang1,ang2,ang3,k_arm) + print(("\n"+"kth = "+str(ang1))) + print(("kap = "+str(ang2))) + print(("kphi = "+str(ang3))) + print("~~~~~~~~") + print(("th = "+str(a))) + print(("chi = "+str(b))) + print(("phi = "+str(c)+"\n")) + else: + print('2nd argument invalid; please choose one of the following:') + print('"Kappa" or "fourc"') + return a,b,c + + + +def EtoK(e_theta,e_chi,e_phi,k_arm=50): + conv = np.pi/180.0 + kth_offset=caget('29idKappa:userCalcOut1.G') + if(abs(e_chi)> 2.0*k_arm): + print("Chi should be no more than twice the Kappa arm offset angle.") + kth,kap,kphi=0,0,0 + else: + print(("Calculating Kappa angles using kth0 = "+str(kth_offset))) + k_ang = k_arm*conv + delta = np.asin( - np.tan(e_chi*conv/2.0) / np.tan(k_ang) ) + k_theta = e_theta*conv - delta + k_kappa = 2.0 * np.asin( np.sin(e_chi*conv/2.0) / np.sin(k_ang)) + k_phi = e_phi*conv - delta + #print k_theta, k_kappa,k_phi + kth = rounder(k_theta)-(57.045-kth_offset) + kap = rounder(k_kappa) + kphi = rounder(k_phi) + #print delta + return (kth,kap,kphi) + + + + +def KtoE(k_theta,k_kappa,k_phi,k_arm=50): + conv = np.pi/180.0 + kth_offset=caget('29idKappa:userCalcOut1.G') + print(("Calculating Euler angles using kth0 = "+str(kth_offset))) + k_ang = k_arm*conv + delta = np.atan( np.tan(k_kappa*conv/2.0) * np.cos(k_ang) ) + e_theta = k_theta*conv - delta + e_chi = 2.0 * np.asin( np.sin(k_kappa*conv/2.0) * np.sin(k_ang) ) + e_phi = k_phi*conv - delta + #print round(e_theta,1),round(e_phi,1),round(e_chi,1) + theta = rounder(e_theta)+(57.045-kth_offset) + chi = rounder(e_chi) # convert from rad to deg + phi = rounder(e_phi) + #print round(delta,1) + return (theta,chi,phi) + + +def rounder(val): # convert from rad to deg + conv = np.pi/180.0 + roundVal=round(1000.0*val/conv)/1000.0 + return roundVal diff --git a/build/lib/iexcode/instruments/current_amplifiers.py b/build/lib/iexcode/instruments/current_amplifiers.py new file mode 100644 index 0000000000000000000000000000000000000000..5df2d30e8f19252ea87e2abba7c42b3f4427c3a1 --- /dev/null +++ b/build/lib/iexcode/instruments/current_amplifiers.py @@ -0,0 +1,367 @@ +import numpy as np +from time import sleep + +from epics import caget, caput +from iexcode.instruments.userCalcs import userStringSeq_pvs, userStringSeq_clear +from iexcode.instruments.VLS_PGM import mono_energy_get + + +def ca_detector_list(branch): + """ + returns the list of keithley current amplifiers based on key + key: 'ARPES' / 'Staff' + """ + ca_list = list(ca_dictionary()[branch].keys()) + + return ca_list + +def ca_dictionary(): + """ + dictionary of connected Kiethlys and thier names + + Previously: CA_Name + """ + ca={} + ca["b"] = { + 1: 'W-mesh', + 2: 'H-wire', + 3: 'V-wire', + 4: 'Slit1A', + 5: 'Slit1A', + 9: 'D2B', + 10: 'B-branch', + 12: '', + 13: 'Slit3C', + 14: 'MeshD', + 15: 'DiodeC', + } + + ca["c"] = { + 1:'TEY', + } + return ca + +############################################################################################################## +################################ Keithley ############################## +############################################################################################################## +def Keithley_pv(ca_ioc, ca_num): + return "29id"+ca_ioc+":ca"+str(ca_num)+":" + +class Keithley: + """ + class for Keithley current amplifiers + """ + def __init__(self,ca_ioc, ca_num): + self._pv = Keithley_pv(ca_ioc, ca_num) + try: + self.name = ca_dictionary()[ca_ioc][ca_num] + except: + self.name = 'CA'+ca_ioc+str(ca_num) + + self.current + self.rate + self.filter_num + self.range + + def get(self): + """ + reads the current SRS and corresponding scaler values + """ + self.current = caget(self.pv+"read") + self.range = 'Autoscale' if caget(self.pv+"rangeAuto",as_string=True)=='On' else caget(self.pv+"range",as_string=True) + self.rate = caget(self.pv+"rate") + digital_filter = (self.pv+'digitalFilter') + self.filter_num = 1 if digital_filter == 'On' else (self.pv+'digitalFilterCount') + + + def reset(self,rate="Slow"): + """ + + Previously: Reset_CA + """ + + pv = self.pv + caput(pv+":reset.PROC",1) + caput(pv+":digitalFilterSet","Off") + caput(pv+":medianFilterSet","Off") + caput(pv+":zeroCheckSet",0) + caput(pv+":rangeAuto",1) + caput(pv+":rateSet",rate) + caput(pv+":rangeAutoUlimit","20mA") + caput(pv+":read.SCAN",".5 second") + + def autoscale(self,On_Off='On',gain=7): + """ + ca_ioc = 'b' / 'c' + ca_num = 2 + + On_Off= 'On' => Turns On the Autoscale; gain is irrelevant. + On_Off= 'Off' => Turns Off the Autoscale with gain below: + 0 = 2nA + 1 = 20nA + 2 = 200nA + 3 = 2uA + 4 = 20uA + 5 = 200uA + 6 = 2mA + 7 = 20mA + + Previously: CA_Autoscale + """ + pv = self.pv + caput(pv+":rangeAutoSet",On_Off) + sleep(0.5) + caput(pv+":rangeSet",gain) + print(pv,"Autoscale",On_Off) + + if On_Off == 'Off': + sleep(1) + print("Gain set to:",caget(pv+":range",as_string=True)) + + + + def avg(self,num_averages,rate='Slow',verbose=True): + """ + Turns on the filtering for the Keithlys for average during a scan + + rate: Keithley sampling rate + 'Slow' / 'Medium' / 'Fast' + + num_averages: number of points to average + + returns the settling_time + + Previously: CA_Filter + """ + + pv = self.pv + name=self.name + t=0.1 + if rate == "Slow": + t=6/60.0 + elif rate == "Medium": + t=1/60.0 + elif rate == "Fast": + t=0.1/60.0 + + settling_time=round(max(0.15,num_averages*t+0.1),2) + + if num_averages <= 1: # no averaging + self.reset(rate) + settling_time = None + if verbose: + print("Average disabled: "+name+" - "+pv) + + else: + caput(pv+"read.SCAN","Passive",wait=True,timeout=500) + caput(pv+"rateSet",rate) + sleep(1) + caput(pv+"digitalFilterCountSet",num_averages,wait=True,timeout=500) + caput(pv+"digitalFilterControlSet","Repeat",wait=True,timeout=500) + caput(pv+"digitalFilterSet","On",wait=True,timeout=500) + + if verbose: + print("Average enabled: "+name+" - "+pv) + print("Detector settling time: "+str(settling_time)+"s") + + return settling_time + + + +def ca_reset_all(rate="Slow"): + """" + + Previously: Reset_CA_all + """ + ca_dict = ca_dictionary() + for ca_ioc in ca_dict.keys(): + for ca_num in ca_dict[ca_ioc].keys(): + CA = Keithley(ca_ioc,ca_num) + CA.reset() + + caput("29idb:ca5:read.SCAN","Passive") # CA5 in passive + print("\nAll the current amplifiers have been reset; ca5 set to passive.") + +def ca_live_sequence(ioc,seq_num,detector_list): + """ + creates a string sequence to put keithleys back in live mode + + ca_list = list of ca to go in live + + Previously: CA_Live_StrSeq + """ + userStringSeq_pv, userStringSeq_proc = userStringSeq_pvs(ioc, seq_num) # do we need to add 29idb:ca5 ??? + + userStringSeq_clear(ioc,seq_num) + + caput(userStringSeq_pv+".DESC","CA Live "+ioc) + + for (i,ca) in enumerate(detector_list): + pv = "29id"+ca[0]+":ca"+str(ca[1])+":" + ca_read_pv = pv+'read.SCAN CA NMS' + ca_avg_pv = pv+'digitalFilterSet PP NMS' + + caput(userStringSeq_pv+".LNK"+str(i+1),ca_avg_pv) + caput(userStringSeq_pv+".STR" +str(i+1),"Off") + + n=len(detector_list) + if n+1+i < 10: + caput(userStringSeq_pv+".LNK" +str(n+1+i),ca_read_pv) + caput(userStringSeq_pv+".STR" +str(n+1+i),".5 second") + caput(userStringSeq_pv+".WAIT"+str(n+1+i),"After"+str(n)) + elif n+1+i == 10: + caput(userStringSeq_pv+".LNKA",ca_read_pv) + caput(userStringSeq_pv+".STRA",".5 second") + caput(userStringSeq_pv+".WAITA","After"+str(n)) + + return userStringSeq_proc + +def ca_average(avg_pts,ca_list,rate="Slow",verbose=True): + """ + Average reading of the relevant current amplifiers for the current scanIOC/branch. + + Previously: CA_average + """ + print("\nAverage set to: "+str(max(avg_pts,1))) + for i in range(0,len(ca_list)): + ca = Keithley(ca_list[i][0],ca_list[i][1]) + ca.avg(avg_pts,rate=rate,verbose=verbose) + + +def load_responsivity_curve(): + """ + Loads the responsivity curve for the AUX100 photo diode, used to convert + current to flux at a given photon energy + + Previously: loadResponsivityCurve + """ + FilePath='/home/beams/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/' + FileName="DiodeResponsivityCurve" + data = np.loadtxt(FilePath+FileName, delimiter=' ', skiprows=1) + return data + +def current2flux(current,hv=None,verbose=True): + """ + Converts the current to flux for of an AUX 100 diode using the responisity curves + + hv = None; gets the current mono energy; otherwise you will need to specify + + Previously CA2flux + """ + try: + curve=load_responsivity_curve() + except: + print('responsivity curve not loaded') + return + responsivity=curve[:,0] + energy=curve[:,1] + charge = 1.602e-19 + if hv is None: + try: + hv = mono_energy_get() + except: + print('specify hv') + return + eff=np.interp(hv,energy,responsivity) + flux = current/(eff*hv*charge) + if verbose: + print("\nCalculating flux for:") + print(" hv = %.1f eV" % hv) + print(" current = %.3e Amp" % current) + print("Flux = %.3e ph/s\n" % flux) + return flux + + +def flux2current(flux,hv=None,verbose=True): + """ + Converts the specified flux to a current for of an AUX 100 diode using the responisity curves + + hv = None; gets the current mono energy; otherwise you will need to specify + """ + try: + curve=load_responsivity_curve() + except: + print('responsivity curve not loaded') + return + responsivity=curve[:,0] + energy=curve[:,1] + charge = 1.602e-19 + if hv is None: + try: + hv = mono_energy_get() + except: + print('specify hv') + return + eff=np.interp(hv,energy,responsivity) + current = flux*(eff*hv*charge) + if verbose: + print("\nCalculating current for:") + print(" hv = %.1f eV" % hv) + print(" flux = %.3e ph/s" % flux) + print("Current = %.3e Amp/n" % current) + return current + + + +############################################################################################################## +################################ SRS ############################## +############################################################################################################## +class SRS: + """ + SRS current amplifier and corresponding scalers + """ + + def __init__(self,scaler_pv,srs_pv): + self._scaler_pv = scaler_pv + self._srs_pv = srs_pv + + self.scaler_value + self.gain + self.unit + self.current + self.get() + + def get(self): + """ + reads the current SRS and corresponding scaler values + """ + self.scaler_value = caget(self._scaler_pv) + self.gain = float(caget(self._scaler_pv+'sens_num.VAL',as_string=True)) + self.unit = caget(self._scaler_pv+'sens_unit.VAL',as_string=True) + CA = {'pA':1e-12, 'nA':1e-9, 'uA':1e-6, 'mA':1e-3} + self.current = self.scaler_value * self.gain * CA[self.unit] + + def setgain(self,gain,unit): + """ + gain = 1,2,5,10,20,50,100,200,500 + unit = 'pA, 'nA', 'uA', 'mA' + """ + caput(self._srs_pv+'sens_num.VAL',str(gain)) + caput(self._srs_pv+'sens_unit.VAL',str(unit)) + + + def srs_print_all(self, long=False): + """ + prints SRS setting + """ + + invert=caget(self._srs_pv+'invert_on.VAL',as_string=True) + currentUnit=caget(self._srs_pv+'sens_unit.VAL',as_string=True) + currentValue=caget(self._srs_pv+'sens_num.VAL',as_string=True) + offsetValue=caget(self._srs_pv+"offset_num.VAL",as_string=True) + offsetUnit=caget(self._srs_pv+"offset_unit.VAL",as_string=True) + offsetSign=caget(self._srs_pv+"offset_sign.VAL",as_string=True) + offsetFactor=caget(self._srs_pv+"off_u_put.VAL",as_string=True) + print('Gain: '+currentValue+' '+currentUnit+' (invert '+invert+')') + print('Baseline: '+offsetSign+' '+offsetFactor+' x '+offsetValue+" "+offsetUnit) + if long: + filterType=caget(self._srs_pv+'filter_type.VAL',as_string=True) + filterLow=caget(self._srs_pv+'low_freq.VAL',as_string=True) + filterHigh=caget(self._srs_pv+'high_freq.VAL',as_string=True) + blank=caget(self._srs_pv+'blank_on.VAL',as_string=True) + biasOnOff=caget(self._srs_pv+'bias_on.VAL',as_string=True) + biasValue=caget(self._srs_pv+'bias_put.VAL',as_string=True) + print('Filter: '+filterType+' - Low/High: '+filterLow+' -'+filterHigh) + print('Bias: '+biasOnOff+'- '+biasValue) + print('Blank: '+blank) + diff --git a/build/lib/iexcode/instruments/diagnostics.py b/build/lib/iexcode/instruments/diagnostics.py new file mode 100644 index 0000000000000000000000000000000000000000..50814ae88854f644fb99cd2b62123794f6428fac --- /dev/null +++ b/build/lib/iexcode/instruments/diagnostics.py @@ -0,0 +1,225 @@ +from numpy import nan + +from epics import caput, caget +from iexcode.instruments.IEX_endstations import * + +############################################################################################################## +################################ default positions ############################## +############################################################################################################## + +###### We should make pvs in the 29idb ioc to hold these values: +def diagnostics_dict(): + """ + Dictionary of Diagnostic positions In and Out by either motor number or name + WARNING: When updating motor values, also update the following screens: + - 29id_BL_Layout.ui (for MeshD and DiodeC) + - 29id_Diagnostic.ui + - 29idd_graphic + usage: + diagnostics_dict()['name'] returns dictionary motor:name + diagnostics_dict()['motor'] returns dictionary name:motor + diagnostics_dict()['In'] returns dictionary motor:In position (where val can be a list for multiple position) + diagnostics_dict()['Out'] returns dictionary motor:In position + motor=diagnostics_dict()['motor']['gas-cell'] + pos_in=diagnostics_dict()['In'][motor] + + WARNING: When updating MeshD (D5D) value: update value in the dictionnary + caQtdM (29id_BL_Diag.ui + 29idd_graphic.ui + Diagnostic.ui) + + Previously: AllDiag_dict + """ + diag={} + diag["In"] = { 5:-55, 6:-46, 17:-56, 20:-30, 25:-56, 28:[-3,-3]} + + diag["Out"] = {1:-4, 2:-10, 3:-4, 4:-4, 5:-20, 6:-20, 7:-20, 17:-20, 20:-21, 25:-20, 28:-3} + diag["name"]= {1:"H-wire", 2:"V-wire", 3:"H-Diagon", 4:"V-Diagon", 5:"W-mesh", + 6:"D2B", 7:"D3B", 17:"D4C/pre-slit", 20:"gas-cell", 25:"D4D/pre-slit", 28:"D5D/pre-RSXS"} + diag["motor"]= {"H-wire":1, "V-wire":2, "H-Diagon":3, "V-Diagon":4,"W-mesh":5, + "D2B":6, "D3B":7, "D4C":17, "gas-cell":20,"D4D":25,"D5D":28} + return diag + +def diagnostic_CA_dict(): + CA_dict={ + 'diode_c':'29idb:ca15:' + } + return CA_dict + + +def diagnostic(diagnostic_name,in_out): + "Inserts/retracts a diagnostic(motor number or name) either = \"In\" or \"Out\"" + diag=diagnostics_dict() + if type(diagnostic_name) is int: + motor=diagnostic_name + name=diag['name'][motor] + else: + name=diagnostic_name + motor=diag["motor"][name] + position=diag[in_out][motor] + + caput("29idb:m"+str(motor)+".VAL",position,wait=True,timeout=18000) + print("\n"+name+": "+ in_out) + +def diagnostics_all_out(diode_stay_in=False): + """ + Retracts all diagnostic + diode_to_stay_in = True / False (checks beamline) + + Previously: AllDiagOut + """ + diag=diagnostics_dict() + text="" + + #which motor is Diode of interest + if diode_stay_in: + branch = BL.branch + + if branch == 'c': + diode_motor=diag["motor"]["gas-cell"] + elif branch == 'd': + diode_motor=diag["motor"]["D5D"] + else: + diode_motor=None + + #Taking out the diagnostic + for motor in list(diag["Out"].keys()): + if motor is diode_motor: + text=' except Diode-'+BL.branch + #putting Diode In if not already in -JM + position=diag["In"][motor] + caput("29idb:m"+str(motor)+".VAL",position,wait=True,timeout=18000) + else: + position=diag["Out"][motor] + caput("29idb:m"+str(motor)+".VAL",position,wait=True,timeout=18000) + text="All diagnostics out"+text + print("\n",text) + +def diagnostics_all_in(): + """ + Inserts all diagnostic (meshes and diodes) for pinhole scans + + Previously: AllDiagIn and AllMeshIn() + """ + diag=diagnostics_dict() + for motor in list(diag["In"].keys()): + position=diag["In"][motor] + if type(position) == list: + position=position[0] + caput("29idb:m"+str(motor)+".VAL",position,wait=True,timeout=18000) + print('m'+str(motor)+' = '+str(position)) + print("All diagnostics in (meshes and diodes) for pinhole scans") + +def mesh_W(In_Out): + """ + Inserts/retracts RSXS mesh (post-slit); arg = \"In\" or \"Out\" + + Previously MeshW + """ + diag=diagnostics_dict() + motor=5; position=diag[In_Out][motor] + caput("29idb:m"+str(motor)+".VAL",position,wait=True,timeout=18000) + print("\nD1A mesh_W: "+ In_Out) + + +def diodeC(In_Out): + """ + Inserts/retracts ARPES (gas-cell) diode; arg = \"In\" or \"Out\" + + Previously: DiodeC + """ + diag=diagnostics_dict() + motor=20; position=diag[In_Out][motor] + caput("29idb:m"+str(motor)+".VAL",position,wait=True,timeout=18000) + print("\nARPES Diode: "+ In_Out) + + +def diodeD(In_Out): + """ + Inserts/retracts RSXS diode; arg = \"In\" or \"Out\" + + Previously:DiodeD + """ + diag=diagnostics_dict() + motor=28; position=position=diag[In_Out][motor] + if type(position) == list: + position=position[1] + caput("29idb:m"+str(motor)+".VAL",position,wait=True,timeout=18000) + print("\nRSXS Diode: "+ In_Out) + + + +def meshC(In_Out,which="postSlit"): + """ + Inserts/retracts ARPES mesh (preSlit or postSlit); arg = \"In\" or \"Out\" + + Previously: MeshC + """ + diag=diagnostics_dict() + if which == "postSlit": + motor=20; position=-31 + elif which == "preSlit": + motor=17; position=diag[In_Out][motor] + + caput("29idb:m"+str(motor)+".VAL",position,wait=True,timeout=18000) + print("\nD4C Au-Mesh: "+ In_Out) + +def meshD(In_Out): + """ + Inserts/retracts RSXS mesh (post-slit); arg = \"In\" or \"Out\" + + Previoulsy: MeshD + """ + diag=diagnostics_dict() + motor=28; position=position=diag[In_Out][motor] + if type(position) == list: + position=position[0] + caput("29idb:m"+str(motor)+".VAL",position,wait=True,timeout=18000) + print("\nD5D Au-Mesh: "+ In_Out) + +def diagnostic_read(diode_d, quiet=True): + """ + reads the current amplifier and returns the value + quiet = False to pring + """ + try: + diode_pv = diagnostic_CA_dict['diode_d'] + val=caget(diode_pv+'read') + except: + diode_pv="not connected" + val = nan + print('pv not defined') + + if not quiet: + print('Diode-D ',val, "(pv = "+diode_pv+")") + return val + +def diodeC_read(quiet=True): + """ + reads the current amplifier and returns the value + quiet = False to pring + """ + val = diagnostic_read('diode_d',quiet) + return val + +def diodeD_read(quiet=True): + """ + reads the current amplifier and returns the value + quiet = False to pring + """ + val = diagnostic_read('diode_d',quiet) + return val + +def meshD_read(quiet=True): + """ + reads the current amplifier and returns the value + quiet = False to pring + """ + val = diagnostic_read('diode_d',quiet) + return val + + +############################################################################################### +####################################### FLUX CONVERSION ####################################### +############################################################################################### + + + + diff --git a/build/lib/iexcode/instruments/electron_analyzer.py b/build/lib/iexcode/instruments/electron_analyzer.py new file mode 100644 index 0000000000000000000000000000000000000000..8cfbb778c92dd9ce36f68ab6a062d44c5b9814af --- /dev/null +++ b/build/lib/iexcode/instruments/electron_analyzer.py @@ -0,0 +1,797 @@ +############################################################# +###################### Imports ############################## +############################################################# + +from os.path import join, isfile, exists, dirname +from os import mkdir +from operator import itemgetter +import time +from datetime import timedelta +from math import ceil,floor,modf + +import numpy as np +from scipy.interpolate import interp1d + +from epics import caput,caget +from iexcode.instruments.IEX_endstations import * + +from iexcode.instruments.scanRecord import * +from iexcode.instruments.conversions_constants import * +from iexcode.instruments.xrays import energy, scanXAS_BL, BL_energy_tables +from iexcode.instruments.shutters import branch_shutter_close +from iexcode.instruments.VLS_PGM import mono_energy_get +from iexcode.instruments.files_and_folders import get_next_fileNumber +from iexcode.instruments.logfile import * +from iexcode.instruments.ARPES import ARPES_motor_dictionary, ARPES_motor_scan, ARPES_mvsample,ARPES_scan_2D +from iexcode.instruments.Scienta import * + +def __main__(): + global EA + EA = Scienta() + +mda = BL.mda +########################################################################### + +def EA_ioc_init(**kwargs): + """ + run after restarting the 29idcScienta IOC + kwargs: + Close_CShutter="Close" default, if something else then it doesn't close the shutter + """ + kwargs.setdefault("close_shutter",True) + if kwargs['close_shutter']==True: + branch_shutter_close('c') + #Addding HDF5 atttributes + filepath='/xorApps/epics/synApps_6_1/ioc/29idcScienta/iocBoot/ioc29idcScienta/HDF5Attributes.xml' + EA._updateAttributes(filepath) + #Allow EA to make directories + caput('29idcScienta:HDF1:CreateDirectory',-1) + #Enabling User CalcOut, needed for BE + caput("29idcScienta:userCalcOutEnable.VAL","Enable") + #Enabling User StringCalc for caQtDM + ioc="29idcScienta:" + pv=ioc+"userStringCalc2" + caput(pv+".DESC","scan1 trigger2 calc") + caput(pv+".INAA",ioc+"scan1.T2PV CP NMS") + caput(pv+".BB",ioc+"HV:ScanTrigger") + caput(pv+".CALC$","AA==BB") + caput(ioc+"userStringCalcEnable.VAL","Enable") + + #clipping and other processing + caput("29idcScienta:Proc1:EnableLowClip","Enable") + caput("29idcScienta:Proc1:LowClip",1) + caput("29idcScienta:Proc1:EnableHighClip",'Disable') + caput("29idcScienta:Proc1:EnableOffsetScale","Enable") + caput("29idcScienta:Proc1:Scale",10) + caput("29idcScienta:Proc1:Offset",-1) + + #Global Detector Setting + caput('29idcScienta:HV:AngularROImin.VAL',290) + caput('29idcScienta:HV:AngularROImax.VAL',830) + caput('29idcScienta:HV:AngularBinning','Off') + + ### Add here + #Setting ExpFrames + caput("29idcScienta:ExpFrames.VAL",1) + #setting save default lens values + EA._AcquisitionMode('Spectra') + time.sleep(0.25) + try: + KE = mono_energy_get() + except: + KE = 2000 + EA.put(KE, PE=50, LensMode="Angular") + caput(EA.PHV+"KineticEnergy:TWV.VAL",1) + caput(EA._Pcam+"Acquire","Acquire") + + print("C-Shutter is closed for initialization ") + +def getSESslit(): + SES=caget("29idc:m8.RBV") + return SES + +def folders_EA(userPath,filePrefix="EA",**kwargs): + """ + For Staff: folder='b', userName='Staff' + For ARPES: folder ='c' + + setFolders = True; creates the data folder and sets scanRecords/AreaDetectors + = False: only creates the data folders; does NOT set + """ + kwargs.setdefault('set_folders',True) + kwargs.setdefault('debug',False) + try: + ADplugin=EA._savePlugin + dtype=EA.dtype + if dtype == "nc": + df="netCDF" + else: + df=EA.dtype + except: + df="h5" + + fpath=join(userPath,df) + print("\nFolder: " + fpath) + + if exists(fpath): + if kwargs['debug']==True: + print("exists") + try: + fileNumber=get_next_fileNumber(fpath,filePrefix, debug=False) + except: + kwargs['create_only']=True + print("fileNumber not set, EA not connected, create_only=True") + else: + if kwargs['debug']==True: + print("making") + mkdir(fpath) + fileNumber=1 + try: + if kwargs['set_folders']: + caput(ADplugin+"FilePath",fpath) + caput(ADplugin+"FileName",filePrefix) + caput(ADplugin+"FileNumber",fileNumber) + + #setup AD + caput(ADplugin+"FileTemplate","%s%s_%4.4d."+dtype) + caput(ADplugin+"AutoIncrement","Yes") + caput(ADplugin+"AutoSave","Yes") + + print("EA path: "+fpath) + print("Next "+filePrefix+" file: "+str(fileNumber)) + except: + df='h5' + fpath=join(userPath,df) + +def EA_log_update(): + """ + spectra entries for the log file + """ + spectra_info = { + 'PE':[EA.PassEnergy,".0f"], + 'lens_mode':[EA.LensMode,"s"], + "scan_mode":[EA.scan_mode,"s"], + "KE":[str(EA.KE),"s"], + "sweeps":[EA.Sweeps,".0f"], + "frames":[EA.ExpFrames,".0f"] + } + + try: + entry_list=[] + pv_list=[] + format_list=[] + for key in spectra_info: + entry_list.append(key) + pv_list.append(spectra_info[key][0]) + format_list.append(spectra_info[key][1]) + logfile_update("ARPES",BL.ioc,entry_list,pv_list,format_list) + except: + print("EAlog did not write to file, check for errors.") + +def log_headerEA():##JM - need to update so that we get the keys from log_EA + s="\nscan x y z th chi phi T scan_mode E1 E2 step i f PE lens_mode SES slit # ID_mode hv exit_slit GRT TEY1 TEY2 time\n" + kwargs={'comment': s} + logfile_print("ARPES",BL.ioc,comment='') + +def EAsweptTime_estimate(EAlist,overhead=[60,.22]): + """ + estimates the time for spectra with the current analyzer settings + overhead[0] = intiating scan (seconds) + overhead[1] = per point (seconds) + """ + E=1392#image width + HVscanDIM=2 + + B=EAlist[4]*0.000078# PixelEnergy=PassEnergy*0.000078 + + C=EAlist[1]# Estart + A=ceil(EAlist[3]/B)*B # Estep + D=C+ceil((EAlist[2]-C)/A)*A # Estop + + E0=ceil((D-C)/(ceil(A/B)*B)) + E1=E/min(floor(ceil(A/B)+0.001),E) + E2=(E/min(floor(ceil(A/B)+0.001),E))%2 + numPnts=E0+E1-E2+1 + print(numPnts) + + PDLY=caget(EA.PHV+"scan"+str(HVscanDIM)+".PDLY") + DDLY=caget(EA.PHV+"scan"+str(HVscanDIM)+".PDLY") + time_seconds=overhead[0]+numPnts*(1/17+PDLY+DDLY+overhead[1]) + print(C,D,B, EAlist[4]) + return str(timedelta(seconds=time_seconds)) + + +def _scanEATrigger(EAlist,before_after,**kwargs): + """ + before_after="before" sets up scanIOC scanRecord for EA scan and sets prefix to "MDAscan0000" + before_after="after" clears up scanIOC scanRecord of EA scan and resets prefix to "EA" + Trigger EA + Det20 = EA scanNum + + set the EA._savePlugin Prefix to be 'MDAscan0045_' + **kwargs: + scan_dim=1 + detTrig=2 + """ + kwargs.setdefault("scan_dim",1) + kwargs.setdefault("detTrig",2) + kwargs.setdefault("dtype",EA.dtype) + kwargs.setdefault("detNum",20) + kwargs.setdefault("prefix","EA")# if not None then over rides the auto + kwargs.setdefault("debug",False) + + scanPV=BL.ioc+"scan"+str(kwargs["scan_dim"]) + triggerPV=scanPV+".T"+str(kwargs["detTrig"])+"PV" + + if kwargs["debug"]: + print("scanPV: "+scanPV) + print("before_after: "+before_after) + + #setting EA._savePlugin FilePath, FileName,FileNumber + if before_after == "before": + _scanEAPrefix("mda",**kwargs) + scantype, HVscanPV, KElist, parms =EA._spectraSetup(EAlist,**kwargs) + caput(triggerPV,HVscanPV) + + if before_after == "after": + _scanEAPrefix(kwargs["prefix"],**kwargs) + caput(triggerPV,"") + + if kwargs["debug"]: + print(triggerPV,caget(triggerPV, as_string=True)) + return + + +def _scanEAPrefix(ptype,**kwargs): + """ + sets the EA file prefix based on + ptype = "mda" -> for "MDAscan"+current MDA file + else prefix = ptype + kwargs: + debug = False (default) + prefix + """ + kwargs.setdefault("debug",False) + kwargs.setdefault("nzeros",4) + kwargs.setdefault("debug",False) + + prefix="" + if kwargs["debug"]: + print(ptype) + + if ptype == "mda": + fpath = mda.filepath[0:-3]+EA.dtype + nextMDA = mda.fileNum + prefix = "MDAscan"+str.zfill(str(nextMDA),kwargs["nzeros"]) + else: + prefix = ptype + + if kwargs["debug"]==kwargs["debug"]: + print("_scanEAPrefix prefix: ",prefix) + + + #setting the file path for the EA saving + fpath=caget(EA._savePlugin +"FilePath",as_string=True) + caput(EA._savePlugin+"FileName",prefix) + nextNum=get_next_fileNumber(fpath,prefix,**kwargs) + caput(EA._savePlugin+"FileNumber",nextNum) + time.sleep(.5) + if kwargs["debug"]: + print("FilePath: ",caget(EA._savePlugin +"FilePath", as_string=True)) + print("FileName: ",caget(EA._savePlugin +"FileName", as_string=True)) + print("FileNumber: ",caget(EA._savePlugin +"FileNumber", as_string=True)) + +def _BE2KE_setupCalc(BE,DESC,CalcOutNum,OutputPV): + """ + used by scanEA for talking in BE + """ + pvCalcOut="29idcScienta:userCalcOut"+str(CalcOutNum) + if len(OutputPV)==0: + caput(pvCalcOut+"Enable","D") + else: + caput(pvCalcOut+"Enable","E") + caput(pvCalcOut+".DESC", DESC) + caput(pvCalcOut+".A",BE) + caput(pvCalcOut+".INPB","29idmono:ENERGY_MON CP NMS") + caput(pvCalcOut+".INPC","29idcScienta:HV:WorkFunction CP NMS") + caput(pvCalcOut+".CALC$","B-A-C") + caput(pvCalcOut+".OUT",OutputPV+" PP") + return pvCalcOut + +def scanEA_reset(**kwargs): + """resets the IOC after a forced stop + """ + kwargs.setdefault("scan_dim",1) + + _scanEATrigger([],"after",**kwargs) + mda.positioners_clear(kwargs["scan_dim"]) + +def scanEA(EAlist,**kwargs): + """ + Uses the scanRecord (mda) to take multiple Scienta spectra + EAlist= + Fixed Mode:["KE"/"BE",CenterEnergy,PassEnergy,Frames,Sweeps] (5) + Swept Mode:["KE"/"BE",StartEnergy,StopEnergy,StepEnergy,PassEnergy,Frames,Sweeps] (7) + Baby Sweep (dither):["KE"/"BE",CenterEnergy,PassEnergy,Frames,Sweeps,"BS"] (6) + + (+) BE is positive below Ef + (-) BE is negative above Ef + + **kwargs + scanIOC=BL_ioc() + scan_dim=1 + execute: True/False to start the scan => True (default) + debug=False + + """ + + kwargs.setdefault('scanIOC',BL.ioc()) + kwargs.setdefault('scan_dim',1) + kwargs.setdefault('execute',True) + kwargs.setdefault("debug",False) + + if EAlist[0]=="KE" or EAlist[0]=="BE": + pass + else: + print("need to specify BE or KE") + + if EAlist[-1]=='BS': + sweeps=EAlist[-2] + else: + sweeps=EAlist[-1] + + if kwargs['debug']: + print("sweeps: "+str(sweeps)) + + if EAlist[0]=="BE": + if len(EAlist)==5: #Fixed + pvCalcOut1=_BE2KE_setupCalc(EAlist[1],"BE_center",10,"29idcScienta:HV:fixedEnergy.VAL") + EAlist[1]=caget(pvCalcOut1+'.VAL') + arrayP1=list(np.full(sweeps, EAlist[1])) + mda.fillin_table(pvCalcOut1+'.PROC',"",kwargs["scanIOC"],kwargs["scan_dim"],arrayP1,1) + EAlist[1]=arrayP1[0] + if kwargs['debug']: + print('\npvCalcOut1: ',pvCalcOut1) + print('Pos1 table:',arrayP1) + elif len(EAlist)==6: #Baby-Swept + pvCalcOut1=_BE2KE_setupCalc(EAlist[1],"BE_center",10,"29idcScienta:HV:babySweepCenter.VAL") + EAlist[1]=caget(pvCalcOut1+'.VAL') + arrayP1=list(np.full(sweeps, EAlist[1])) + mda.fillin_table(pvCalcOut1+'PROC',"",kwargs["scanIOC"],kwargs["scan_dim"],arrayP1,1) + print('\npvCalcOut1: ',pvCalcOut1) + print('Pos1 table:',arrayP1) + elif len(EAlist)==7: #Sweep + pvCalcOut1=_BE2KE_setupCalc(EAlist[1],"BE_start",9,"29idcScienta:HV:sweepStartEnergy.VAL") + pvCalcOut2=_BE2KE_setupCalc(EAlist[2],"BE_stop",10,"29idcScienta:HV:sweepStopEnergy.VAL") + EAlist[1]=caget(pvCalcOut1+'.VAL') + EAlist[2]=caget(pvCalcOut2+'.VAL') + arrayP1=list(np.full(sweeps, EAlist[1])) + arrayP2=list(np.full(sweeps, EAlist[2])) + mda.fillin_table(pvCalcOut1+'.PROC',"",kwargs["scanIOC"],kwargs["scan_dim"],arrayP1,1) + mda.fillin_table(pvCalcOut2+'.PROC',"",kwargs["scanIOC"],kwargs["scan_dim"],arrayP2,2) + if kwargs['debug']: + print("\npvCalcOut1",pvCalcOut1) + print("\npvCalcOut2",pvCalcOut2) + print('Pos1 table:',arrayP1) + print('Pos2 table:',arrayP2) + EAlist[0]=='KE' + else: + _BE2KE_setupCalc(0,"",9,"") + _BE2KE_setupCalc(0,"",10,"") + + if kwargs['debug']: + print('/n EAlist => ',EAlist) + + #set up name and add HV trigger and FileNum as det scan1 (sweeps) + _scanEATrigger(EAlist,"before",**kwargs) + + if kwargs['debug']: + print("Clearing scan positioners and filling in sweeps") + #Fill in Sweeps scan + mda.positioners_clear(**kwargs) + VAL="" + RBV="" + mda.fillin(VAL,RBV,1,sweeps,1,**kwargs) + if kwargs['debug']: + scanPV="29id"+kwargs["scanIOC"]+":scan"+str(kwargs["scan_dim"]) + print("scanPV: "+scanPV) + + + + #Writing EA parameters + EAscanType, EAscanPV, KElist, EAparms =EA._spectraSetup(EAlist,**kwargs) + + if kwargs['debug']: + print("EA._spectraSetup: ") + print(EAscanType,EAscanPV, KElist) + + print(EA._spectraMessage(EAscanType, EAscanPV, KElist)) + #print(EA._EAspectraTime()) + + #executing the scan + if kwargs['execute']: + EA.put(EAparms['KineticEnergy'],EAparms['PassEnergy'],LensMode="Angular",Frames=EAparms['Frames'],**kwargs) + time.sleep(10) + EA.put(EAlist[1]-.05,EAlist[-3],LensMode="Angular") + time.sleep(2) + mda.go(**kwargs) + #After scan + EA_log_update() + scanEA_reset(**kwargs) + mda.table_reset_after(**kwargs) + else: + return EAparms + + + +def scanFM(RoughPositions,thList,EAlist,**kwargs): + """ + New FermiMap using ScanRecord table scans to move motors + RoughPositions is a List rough positions from which to interpolate (use RoughPositions_Find()) + thList=[th_start,th_stop,th_step] + EAlist to be finish only one scan at the moment[can be a single list if you are only taking a single scan or a list of lists to take multiple scans] + **kwargs + scanIOC = BL_ioc() + scan_dim = 1 + + logfile(**kwargs) + """ + kwargs.setdefault("scan_dim",2) + kwargs.setdefault("debug",False) + kwargs.setdefault('execute',True) + + # Making Tables and Filling positioners + x,y,z,th,chi,phi=interpRoughPositions(RoughPositions,thList[0],thList[1],thList[2]) + if kwargs['debug']: + print(x,y,z,th,chi,phi) + + mda.fillin_table(ARPES_motor_dictionary("th")[1],ARPES_motor_dictionary("th")[0],th,positioner_num=1) + mda.fillin_table(ARPES_motor_dictionary("x")[1],ARPES_motor_dictionary("x")[0],x,positioner_num=2) + mda.fillin_table(ARPES_motor_dictionary("y")[1],ARPES_motor_dictionary("y")[0],y,positioner_num=3) + mda.fillin_table(ARPES_motor_dictionary("z")[1],ARPES_motor_dictionary("z")[0],z,positioner_num=4) + + #setting up EA + EAkwargs={ + 'execute':False, + 'scan_dim':1 + } + EAparms=scanEA(EAlist,**EAkwargs) + + #executing the scan + if kwargs["execute"]==True: + print(EAparms) + EA.put(EAparms['KineticEnergy'],EAparms['PassEnergy'],LensMode="Angular",Frames=EAparms['Frames'],**kwargs) + mda.go(**kwargs) + EA_log_update() + scanEA_reset(**kwargs) + + +def interpRoughPositions(RoughPositions,thStart,thStop,thStep,**kwargs): + """ + Interpolate sample position as a function of theta, based on RoughPosition, + a list of motor position lists and returns x,y,z,th,chi,phi + + **kwargs: + kind="cubic" by default, interpolation type ("linear","cubic","quadratic") + + Usage: + x,y,z,th,chi,phi=interpRoughPositions(RoughPositions,3,-8,0.5) + + (direction to minimize backlash) + RoughPositions=[ + [x,y,z,th,chi,phi], + [x,y,z,th,chi,phi] + ] + """ + kwargs.setdefault('kind','cubic') + kwargs.setdefault('debug',False) + + #Puts Rough Position in increasing theta order + RoughPositions=sorted(RoughPositions, key=itemgetter(3))[::-1] + RoughPositions=np.array(RoughPositions) + if kwargs['debug']: + print('RoughPositions: ',RoughPositions) + + #thlist + if kwargs['debug']: + print('ths: ',thStart,thStop,thStep) + th=np.arange(np.max([thStart,thStop]),np.min([thStart,thStop])-1.0*abs(thStep),-1.0*abs(thStep),dtype=float) + if kwargs['debug']: + print('th: ',th) + + #interpolating + def func(th,th_col,m_col,**kwargs): + f=interp1d(th_col,m_col) + m=f(th) + return m + x=func(th,RoughPositions[:,3], RoughPositions[:,0]) + y=func(th,RoughPositions[:,3], RoughPositions[:,1]) + z=func(th,RoughPositions[:,3], RoughPositions[:,2]) + chi=func(th,RoughPositions[:,3], RoughPositions[:,4]) + phi=func(th,RoughPositions[:,3], RoughPositions[:,5]) + + return x,y,z,th,chi,phi + +def mvth_interp(RoughPositions, thVal,**kwargs): + """ + Moves to the interpolated position for a give theta and RoughPosition list + uses interpRoughPositions + """ + x,y,z,th,chi,phi=interpRoughPositions(RoughPositions,thVal,thVal-.1,1,**kwargs) + Pos=[x[0],y[0],z[0],th[0],chi[0],phi[0]] + #print("Pos = ",Pos) + ARPES_mvsample(Pos) + +def scanEA_hv(hv_start_stop_step_lists,EAlist=[],**kwargs): + """ + triggers and EAscan for each photon energy in *hvs + + hv_start_stop_step_lists, listoflist ... see scanXAS for more info + + EAlist = + Fixed Mode: EAlist=["KE/BE",CenterEnergy,PassEnergy,Frames,Sweeps] (5) + Swept Mode: EAlist=["KE/BE",StartEnergy,StopEnergy,StepEnergy,PassEnergy,Frames,Sweeps] (7) + Baby Sweep (dither): EAlist=["KE"/"BE",CenterEnergy,PassEnergy,Frames,Sweeps,"BS"] (6) + KE => Auger + BE => Core levels + (+) BE is positive below Ef + (-) BE is negative above Ef + + usage: + scanEA_hv([400,500,1200],EAlist=["BE",-5,200,17*60,1]) + NOTE that EAlist = needs to be written explicitly + + **kwargs + execute: True/False to start the scan => True (default) + debug: default => False + + (Note: scan_dim=2 is hardcoded for photon energy) + + """ + kwargs.setdefault("average",None) + kwargs.setdefault("execute",True) + kwargs.setdefault("debug",False) + + if(kwargs['debug']): + print('EAlist: ',EAlist) + + #setting up EA + EAkwargs={ + 'execute':False, + 'scan_dim':1 + } + EAparms=scanEA(EAlist,**EAkwargs) + + scanGo = kwargs['execute'] + #Setting up the ScanRecord for Mono and ID in Table mode + kwargs["scan_dim"]=2 + kwargs["execute"]=False + mono_array,ID_array = BL_energy_tables(hv_start_stop_step_lists) + scanXAS_BL(hv_start_stop_step_lists,**kwargs) + + if scanGo == True: + #Setting the beamline energy to the first point, and EA at first KE + energy(mono_array[0]) + #Scanning + EA.put(mono_array[0]-EAlist[1],EAparms['PassEnergy'],LensMode="Angular",Frames=EAparms['Frames'],**kwargs) + mda.go(**kwargs) + #After scan + scanEA_reset(**kwargs) + mda.table_reset_after(**kwargs) + +def scanEA_y(EAlist, start,stop,step,mode='absolute',**kwargs): + scanEA_motor(EAlist,'y',start,stop,step,mode=mode,**kwargs) + +def scanEA_z(EAlist, start,stop,step,mode='absolute',**kwargs): + scanEA_motor(EAlist,'z',start,stop,step,mode=mode,**kwargs) + + +def scanEA_motor(EAlist, motor,start,stop,step,mode='absolute',**kwargs): + """ + scans an ARPES motor (scan_dim=2) while triggering the EA (scan_dim=1) + + EAlist = + Fixed Mode:["BE",CenterEnergy,PassEnergy,Frames,Sweeps] (5) + Swept Mode:["BE",StartEnergy,StopEnergy,StepEnergy,PassEnergy,Frames,Sweeps] (7) + Baby Sweep (dither):["KE"/"BE",CenterEnergy,PassEnergy,Frames,Sweeps,"BS"] (6) + + (+) BE is positive below Ef + (-) BE is negative above Ef + + **kwargs + execute: True/False to start the scan => True (default) + debug=False + (Note: scan_dim=2 is hardcoded) + """ + kwargs.setdefault("execute",True) + kwargs.setdefault("debug",False) + + #setting up EA + EAkwargs={ + 'execute':False, + 'scan_dim':1 + } + EAparms=scanEA(EAlist,**EAkwargs) + + #Setting up the ScanRecord for motor scans + scan_dim=2 #hard coded + kwargs.update({'scan_dim':scan_dim}) + + ARPES_motor_scan(motor,start,stop,step,**kwargs) + + if kwargs['debug']: + print("ScanGo scan_dim = ",scan_dim) + + if kwargs["execute"]==True: + #Scanning + EA.put(EAlist[1],EAparms['PassEnergy'],LensMode="Angular",Frames=EAparms['Frames'],**kwargs) + BL.mda.go(kwargs["scanIOC"],scan_dim) + EA_log_update() + #After scan + scanEA_reset(**kwargs) + +def scanEA_Mesh(EAlist,y_start_stop_step,z_start_stop_step,**kwargs): + """ + 2D scan mesh (y/z) while triggering the EA: scan_dim=1 + y_start_stop_step=[start1,stop1,step1] #y: scan_dim=2 + z_start_stop_step=[start2,stop2,step2] #z: scan_dim=3 + + + EAlist = + Fixed Mode:["BE",CenterEnergy,PassEnergy,Frames,Sweeps] (5) + Swept Mode:["BE",StartEnergy,StopEnergy,StepEnergy,PassEnergy,Frames,Sweeps] (7) + Baby Sweep (dither):["KE"/"BE",CenterEnergy,PassEnergy,Frames,Sweeps,"BS"] (6) +1205 + (+) BE is positive below Ef + (-) BE is negative above Ef + + **kwargs + execute: True/False to start the scan => True (default) + debug=False + (Note: scan_dims are hardcoded) + """ + kwargs.setdefault("execute",True) + kwargs.setdefault("debug",False) + + #setting up EA + EAkwargs={ + 'execute':False, + 'scan_dim':1 + } + EAparms=scanEA(EAlist,**EAkwargs) + + #Setting up the ScanRecord for motor scans + outer_scan_dim=3 #hard coded + inner_loop_list = y_start_stop_step.insert(0,"y") + outer_loop_list = z_start_stop_step.insert(0,"z") + ARPES_scan_2D(inner_loop_list,outer_loop_list,outer_scan_dim,**kwargs) + + if kwargs['debug']: + print("ScanGo scan_dim = ",outer_scan_dim) + + if kwargs['execute']: + #Scanning + EA.put(EAlist[1],EAparms['PassEnergy'],LensMode="Angular",Frames=EAparms['Frames'],**kwargs) + mda.go(scan_dim=outer_scan_dim) + EA_log_update() + + #After scan + scanEA_reset(**kwargs) + + + + + +def hv2kz(lattice,V0,hv): + """ + Converts a hv value for the nth zone had returns corresponding kz values + [0]for zone boundary and [1] for zone center in inverse angstroms + lattice = c; assuming kz orthoganal to a-b plane (i.e. 2np.pi/c = GZ distance) + and at zone center (kx,ky)=0 /cos(th=0)=1 + V0 = the inner potential + """ + work_fct=EA.wk + Ek=hv-work_fct + k_z=0.5124*np.sqrt(Ek+V0) # Kz at (kx,ky)=0 i.e. cos(th)=1 + c_star=2*np.pi/lattice # 2pi/c = GZ distance + GZ_n=round((k_z/c_star*2),2) + G_n=round((k_z/c_star),2) + print(" kz = "+str(round(k_z,2))+" A^(-1) = " +str(GZ_n)+" * pi/c = " +str(G_n)+" * 2pi/c") + return GZ_n,G_n + +def kz2hv(lattice,V0,n): + """ + Converts a kz value for the nth zone had returns corresponding hv + lattice = c; assuming kz orthoganal to a-b plane (i.e. 2pi/c = GZ distance) + and at zone center (kx,ky)=0 /cos(th=0)=1 + V0 = the inner potential + """ + work_fct=EA.wk + c_star=2*np.pi/lattice # 2pi/c = GZ distance + Ek=(n*c_star/0.5124)**2-V0 # Ek at (kx,ky)=0 i.e. cos(th)=1 + hv=Ek+work_fct + mono=round(hv,1) + print("\n") + print(" hv = Ek + Phi = "+str(round(hv,2))+" eV") + print(" kz = n*2pi/c with n = "+str(n)) + return mono + + +def Print_Gamma_n(lattice,V0,n1,n2): + work_fct=EA.wk + c_star=2*np.pi/lattice # 2pi/c = GZ distance + for n in range(n1,n2+1,1): + Ek_Gn=(n*c_star/0.5124)**2-V0 # Ek at G + Ek_Zn=((n+0.5)*c_star/0.5124)**2-V0 # Ek at Z + hv_Gn=round(Ek_Gn+work_fct,2) + hv_Zn=round(Ek_Zn+work_fct,2) + print("\n G["+str(n)+"]: hv = Ek + Phi = "+str(round(hv_Gn,2))+" eV ") + print(" Z["+str(n)+"]: hv = Ek + Phi = "+str(round(hv_Zn,2))+" eV") + +def Print_Gamma_hv(lattice,V0,hv1,hv2): + work_fct=EA.wk + c_star=2*np.pi/lattice # 2pi/c = GZ distance + Ek1=hv1-work_fct + Ek2=hv2-work_fct + k_z1=0.5124*np.sqrt(Ek1+V0) # Kz at (kx,ky)=0 i.e. cos(th)=1 + k_z2=0.5124*np.sqrt(Ek2+V0) # Kz at (kx,ky)=0 i.e. cos(th)=1 + GZ_n1=round((k_z1/c_star*2),1) + G_n1=round((k_z1/c_star),1) + GZ_n2=round((k_z2/c_star*2),1) + G_n2=round((k_z2/c_star),1) + if modf(G_n1)[0]>=0.5: + n1=modf(G_n1)[1]+1,0 + else: + n1=modf(G_n1)[1] + n2=modf(G_n2)[1] + print("\n hv1 = "+str(hv1)+" eV: " +str(GZ_n1)+" * pi/c = " +str(G_n1)+" * 2pi/c") + if type(n1) == tuple: n1 = n1[0] + if type(n2) == tuple: n2 = n2[0] + Print_Gamma_n(lattice,V0,n1,n2) + print("\n hv2 = "+str(hv2)+" eV: " +str(GZ_n2)+" * pi/c = " +str(G_n2)+" * 2pi/c") + return n1,n2 + +def kx2deg(lattice,hv): + a=np.pi/lattice + b=0.5124*np.sqrt(hv) + c=a/b + theta_rad=np.asin(c) + theta_deg=rad2deg(theta_rad) + print(" 1/2-BZ (GX) = "+str(round(theta_deg,1))+" deg") + +def resolution_EA(PE,slit_SES): # updated 10/30/17: straight slits scaled to slit width not area + SES_Table={} + SES_Table[2] = {1: 1.6, 2:2, 3:2, 4:4, 5:4, 6:6, 7:12, 8:20, 9:32} + SES_Table[5] = {1: 2.7, 2:4, 3:4, 4:7, 5:7, 6:11, 7:20, 8:34, 9:54} + SES_Table[10] = {1: 5.7, 2:9, 3:9, 4:14, 5:14, 6:23, 7:43, 8:71, 9:114} + SES_Table[20] = {1:10.8, 2:16, 3:16, 4:27, 5:27, 6:43, 7:81, 8:135, 9:216} + SES_Table[50] = {1:34.6, 2:52, 3:52, 4:87, 5:87, 6:138, 7:260, 8:433, 9:692} + SES_Table[100] = {1:49.5, 2:74, 3:74, 4:124, 5:124, 6:198, 7:371, 8:619, 9:990} + SES_Table[200] = {1:88.9, 2:133, 3:133, 4:222, 5:222, 6:356, 7:667, 8:1111, 9:1778} + SES_Table[500] = {1:250, 2:375, 3:375, 4:625, 5:625, 6:1000, 7:1875, 8:3125, 9:5000} + try: + SES=SES_Table[PE][slit_SES] + except KeyError: + print("WARNING: Not a valid PE/Slit combination") + SES=0 + return SES + + +def SES_slit(val): + """ + Set the Scienta Slit + val w_mm l_mm Shape + 1 0.2 25 Curved + 2 0.3 30 Straight + 3 0.3 25 Curved + 4 0.5 30 Straight + 5 0.5 25 Curved + 6 0.8 25 Curved + 7 1.5 30 Straight + 8 2.5 30 Straight + 8.5 open apperture + 9 4.0 30 Straight + """ + caput("29idc:m8.VAL",val,wait=True,timeout=18000) + + diff --git a/build/lib/iexcode/instruments/encoders.py b/build/lib/iexcode/instruments/encoders.py new file mode 100644 index 0000000000000000000000000000000000000000..ef7cb08aceb1e1e7a0ec92ecf5915498cdf357bf --- /dev/null +++ b/build/lib/iexcode/instruments/encoders.py @@ -0,0 +1,62 @@ +from epics import caput,caget + +def encoder_dictionary_entry(name): + """ + returns a dictionary with the encoder pvs + encoder_dictionary_entry(name) = encoder_ioc, motor_ioc, encoder_list + + """ + d={ + 'slit2B':("29idMini1:",[13,14,15,16]), + 'slit3D':("29idMini2:",[26,27]), + 'ARPES':("ARPES:",[1,2,3,4]), + } + return d[name] + +def encoder_sync(name): + """ + sync all the encoders for name + """ + encoder_ioc, motor_ioc, encoder_list = encoder_dictionary_entry(name) + for encoder_num in encoder_list: + pv = motor_ioc+":m"+str(encoder_num)+".SYNC" + caput(pv,1) + +def encoders_reset(name,Hcenter,Vcenter): + """ + Resetting Slit 2B encoders to 0 for a given position (Hcenter,Vcenter). + Slit size need to be set to 0. + + Previously: Reset_Slit2B_Encoders + """ + encoder_sync('name') + encoder_ioc, motor_ioc, encoder_list = encoder_dictionary_entry(name) + + print('\nCurrent Position:') + for e_num in encoder_list: + pv = encoder_ioc+'e'+(e_num)+'Pos' + print('e'+(e_num)+' = '+str(caget(pv))) + + print('\nSetting all Offsets to 0:') + for e_num in encoder_list: + pv = encoder_ioc+'e'+(e_num)+'Pos.EOFF' + caput(pv,0) + + print('\nCurrent Position:') + for e_num in encoder_list: + pv = encoder_ioc+'e'+(e_num)+'Pos' + print('e'+(e_num)+' = '+str(caget(pv))) + + print('\nSetting back Offsets:') + for e_num in encoder_list: + pos_pv = encoder_ioc+'e'+(e_num)+'Pos' + offset_pv = encoder_ioc+'e'+(e_num)+'Pos.EOFF' + caput(offset_pv,-caget(pos_pv)) + + print('\nCurrent Position:') + for e_num in encoder_list: + pv = encoder_ioc+'e'+(e_num)+'Pos' + print('e'+(e_num)+' = '+str(caget(pv))) + + encoder_sync(name) + print('sync '+name) diff --git a/build/lib/iexcode/instruments/files_and_folders.py b/build/lib/iexcode/instruments/files_and_folders.py new file mode 100644 index 0000000000000000000000000000000000000000..9710c1bd6907b1f7340147aad3a073d28daf1c82 --- /dev/null +++ b/build/lib/iexcode/instruments/files_and_folders.py @@ -0,0 +1,268 @@ +from os import listdir,mkdir,chmod +from os.path import join, isfile, exists +import datetime +from time import sleep +import re + +from epics import caget, caput + + +############################################################################################################## +################################ Standard Paths ############################## +############################################################################################################## + + +path_User_Folders='/home/beams/29IDUSER/Documents/User_Folders/' + +def path_dserv(folder,run,user_name): + """ + Returns the path to a user folder + dataFolder='/net/s29data/export/data_29id'+folder+'/'+run+'/'+user_name + + previously: _userDataFolder + """ + + dataFolder='/net/s29data/export/data_29id'+folder+'/'+run+'/'+user_name + return dataFolder + + + + + + + +############################################################################################################## +################################ Folders ############################## +############################################################################################################## +def check_run(): + """ + gets the current date and determines the run number from that + run = year_cycle + cycle 1 => Jan - April + cycle 2 => May - September + cycle 1 => October - December + + previously: Check_run + """ + todays_date = datetime.date.today() + + date1 = ( 1, 1) # start date run_1 + date2 = ( 5, 1) # start date run_2 + date3 = (10, 1) # start date run_3 + + datex = (todays_date.month,todays_date.day) + + if date1 <= datex < date2: + run=str(todays_date.year)+'_1' + elif date2 <= datex < date3: + run=str(todays_date.year)+'_2' + else: + run=str(todays_date.year)+'_3' + + return(run) + +def make_ftp(folder,run,user_name): + """ + Creates the folders on kip (ftp server) and prints what is needed for the cronjob + + folder = 'c' /'d' + + Previously: was part of Make_DataFolder + """ + crontime={ + 'mda2ascii':'0,30 * * * * ', + 'chmod':'1,31 * * * * ', + 'data_other':'2,32 * * * * ', + 'notebook':'*/3 * * * * ', + } + + #making the crontab text + print('-------------------------------------------------------------') + #mda2ascii + MyPath_kip_run='/net/kip/sftp/pub/29id'+folder+'ftp/files/'+run+'/' + MyPath_kip='/net/kip/sftp/pub/29id'+folder+'ftp/files/'+run+'/'+user_name+'/' + cmd_mda2ascii=crontime['mda2ascii']+' /net/s29dserv/APSshare/bin/mda2ascii -d '+MyPath_kip+'ascii '+MyPath_kip+'mda/*.mda' + print(cmd_mda2ascii) + #chmode + cmd_chmod=crontime['chmod']+' chmod 664 '+MyPath_kip+'ascii/*.asc' + print(cmd_chmod) + #notebooks + cmd_notebook=crontime['notebook']+' /usr/bin/rsync -av --exclude=core /home/beams22/29IDUSER/Documents/User_Folders/'+user_name+'/* kip:'+MyPath_kip+'notebook > /home/beams22/29ID/cronfiles/cptoftp-currrun-d-User.log 2>&1' + print(cmd_notebook) + print('-------------------------------------------------------------\n\n') + + #making folders + print("\n\n") + print(MyPath_kip) + print(MyPath_kip+"ascii") + if not (exists(MyPath_kip_run)): + mkdir(MyPath_kip_run) + chmod(MyPath_kip_run, 0o775) + if not (exists(MyPath_kip)): + mkdir(MyPath_kip) + chmod(MyPath_kip, 0o775) + if not (exists(MyPath_kip+"ascii")): + mkdir(MyPath_kip+'ascii') + chmod(MyPath_kip+'ascii', 0o775) + if not (exists(MyPath_kip+"notebook")): + mkdir(MyPath_kip+"notebook") + chmod(MyPath_kip+"notebook", 0o775) + +def make_user_folders(run,folder,user_name,endstation_name,ftp=False): + """ + if user_name is not a folder in path_User_Folders, then it creates a new folder + + if ftp = True / False (default) creates the folders on kip (ftp server) and modifies the cronjob + + previously: Make_DataFolder + """ + + if (folder == 'c'or folder == 'd'): + if ftp: + make_ftp(folder,run,user_name) + else: + print("To create ftp folders & update contrab, you need to run the following as 29id:") + print("\tFolder_"+str(endstation_name)+"('"+str(run)+"','"+str(user_name)+"',ftp=True)") + + #create user folder for saving log files + path_user=join(path_User_Folders,user_name) + user_name = "/"+user_name + if not (exists(path_user)): + mkdir(path_user) + + +def folder_mda(run,folder,user_name,file_prefix,ioc,verbose=True): + """ + sets the folder, prefix and file number for the scan record + ioc is the full ioc, e.g. '29idb', or '29idARPES' + + For Staff: folder='b', user_name='' + For ARPES: folder ='c' + For Kappa: folder = 'd' + + mda_path="/net/s29data/export/data_29id"+folder+"/"+run+"/"+user_name+"mda" + """ + + if user_name == 'Staff': + user_name="" + else: + user_name=user_name+"/" + + mda_path="/net/s29data/export/data_29id"+folder+"/"+run+"/"+user_name+"/mda" + print("\nMDA folder: " + mda_path) + if not (exists(mda_path)): + mkdir(mda_path) + FileNumber=1 + else: + FileNumber=get_next_fileNumber(mda_path,file_prefix) + + if ioc in ['29idb','29idc','29idd']: #VME iocs + caput(ioc+"saveData_fileSystem","//s29data/export/data_29id"+folder+"/"+run) + sleep(0.25) + caput(ioc+"saveData_subDir",user_name+"mda") + + else: #soft iocs + caput(ioc+"saveData_fileSystem","/net/s29data/export/data_29id"+folder+"/"+run) + sleep(0.25) #needed so that it has time to write + caput(ioc+"saveData_subDir","/"+user_name+"mda") + + caput(ioc+"saveData_baseName",file_prefix+"_") + caput(ioc+"saveData_scanNumber",FileNumber) + + print("\nioc set to:", ioc) + sleep(5) + + if verbose: + SaveStatus=caget(ioc+'saveData_status',as_string=True) + SaveMessage=caget(ioc+'saveData_message',as_string=True) + print("\nSave Status "+ioc+": "+SaveStatus+" - "+SaveMessage) + + +def folder_SPEC(run,folder,user_name): + if folder == "b": + user_name = "Staff" + else: + user_name = user_name+"/" + MyPath="/home/beams22/29IDUSER/spec/data/"+run+"/"+user_name + print("\nSPEC folder: " + MyPath) + print("You will need to create folder and set up the path manually in SPEC:") + print(" cd "+MyPath) + print(" newfile FileName") + print("To start SPEC fresh: ./bin/kappa29ID -f") + #if not (exists(MyPath)): + # mkdir(MyPath) + + +def folder_MPA(run,folder,user_name,file_prefix="mpa"): + if folder == "b": + windows_ioc = "X" + user_name = "" + windows_path = windows_ioc+':\\'+run+"\\mpa" + else: + windowsIOC = "Z" + user_name = user_name+"/" + windows_path=windows_ioc+':\\'+run+"\\"+user_name[:-1]+"\\mpa" + mpa_path="/net/s29data/export/data_29id"+folder+"/"+run+"/"+user_name+"mpa" + print("\nMPA folder: " + mpa_path) + if not (exists(mpa_path)): + mkdir(mpa_path) + FileNumber=1 + else: + FileNumber=get_next_fileNumber(mpa_path,file_prefix) + caput("29iddMPA:det1:MPAFilename",windows_ioc+":/"+run+"/"+user_name+"mpa/mpa_") + + save_plugin='TIFF1' + caput("29iddMPA:"+save_plugin+":FilePath",windows_path) + print("\nMPA folder on Crabby: "+windows_path) + caput("29iddMPA:"+save_plugin+":FileName",file_prefix) + caput("29iddMPA:"+save_plugin+":FileNumber",FileNumber) + +def _filename_key(filename): + return (len(filename), filename) + +def get_next_fileNumber(data_dir, file_prefix,**kwargs): + """ + gets the next file number for the pattern + data_dir/file_prefix_filenum + + kwargs: + debug = False (default); if True then print lo + q = True (default); if False then prints next file number + + Previously: getNextFileNumber + """ + kwargs.setdefault("debug",False) + kwargs.setdefault("q",True) + + onlyfiles = [f for f in listdir(data_dir) if isfile(join(data_dir, f)) and f[:len(file_prefix)] == file_prefix] + sortedfiles = sorted(onlyfiles, key=_filename_key) + pattern = re.compile('(.*)_(.*)\.(.*)') + try: + lastFile = sortedfiles[-1] + except IndexError as errObj: + nextFileNumber = 1 + if kwargs["debug"]: + print("Data directory = ", data_dir) + print("File prefix =", file_prefix) + print("File number =", None) + print("File extension =", "TBD") + print("Next File number =", nextFileNumber) + else: + matchObj = pattern.match(lastFile) + nextFileNumber = int(matchObj.group(2)) + 1 + if kwargs["debug"]: + print("Data directory = ", data_dir) + print("File prefix =", matchObj.group(1)) + print("File number =", matchObj.group(2)) + print("File extension =", matchObj.group(3)) + print("Next File number =", nextFileNumber) + if kwargs["q"] == False: + print("Next File Number: ",nextFileNumber) + return nextFileNumber + + + + + + + diff --git a/build/lib/iexcode/instruments/gate_valves.py b/build/lib/iexcode/instruments/gate_valves.py new file mode 100644 index 0000000000000000000000000000000000000000..1e122c526975534f743216fa16ae2f089094db2d --- /dev/null +++ b/build/lib/iexcode/instruments/gate_valves.py @@ -0,0 +1,35 @@ +from epics import caget, caput + +def branch_valves(): + """ + returns a dictionary of the gate valves for a given branch + + used by close_valve and safe_state + """ + + GVs={ + 'c':('GV10'), + 'd':('GV14'), + 'e':() + } + return GVs + +def valve_close(GV, verbose=True): + """ + closes the gate valve ('GV10', 'GV14'), EPS nomenclature + + Previously: Close_DValve,Close_DValve + """ + caput("29id:BLEPS:"+GV+":CLOSE.VAL",1,wait=True,timeout=18000) + if verbose: + print("Closing gate valve: "+GV+"...") + +def valve_open(GV, verbose=True): + """ + closes the gate valve ('GV10', 'GV14'), EPS nomenclature + + Previously: Close_DValve,Close_DValve + """ + caput("29id:BLEPS:"+GV+":OPEN.VAL",1,wait=True,timeout=18000) + if verbose: + print("Opening gate valve: "+GV+"...") \ No newline at end of file diff --git a/build/lib/iexcode/instruments/hxp_mirrors.py b/build/lib/iexcode/instruments/hxp_mirrors.py new file mode 100644 index 0000000000000000000000000000000000000000..0eb90509f2784ff042fbcb4ef78235ec102d02fd --- /dev/null +++ b/build/lib/iexcode/instruments/hxp_mirrors.py @@ -0,0 +1,64 @@ +from re import M +from epics import caput, caget +from iexcode.instruments.utilities import print_warning_message +from iexcode.instruments.m3r import m3r_branch + +def hxp_ioc(mirror_name): + """ + returns the ioc for a given + mirror_name: 'm3a' / 'm4a' / 'm4r' + """ + hxp_namelist={ + 'm4r':'hxp2', + 'm3a':'hxp1', + 'm4a':'hxp3', + } + if mirror_name not in hxp_namelist: + print("not a valid mirror name ("+list(hxp_namelist.keys())+")") + else: + ioc = '29idHXP:'+hxp_namelist[mirror_name]+":" + return ioc + + +def HXP_synch(mirror_name): + """ + synchs the rbv and sp for all axes + + mirror_name: 'm3a' / 'm4a' / 'm4r' + + Previously: Sync_m4r + """ + pv = hxp_ioc(mirror_name) + try: + for m in range(1,7): + caput(pv+'m'+str(m)+'.SYNC',1) + except: + print_warning_message("Check if ioc is running") + + +def hxp_print(mirror_name): + """ + + Previously: Get_HXP + """ + pv = hxp_ioc(mirror_name) + + Tx=caget(pv+"m1.RBV") + Ty=caget(pv+"m2.RBV") + Tz=caget(pv+"m3.RBV") + Rx=caget(pv+"m4.RBV") + Ry=caget(pv+"m5.RBV") + Rz=caget(pv+"m6.RBV") + print("\n"+mirror_name+" @ "+"%.3f" % Tx, "/","%.3f" % Ty, "/","%.3f" % Tz, "/","%.3f" % Rx, "/","%.3f" % Ry, "/","%.3f" % Rz) + +def hxp_get(): + """ + + Previously: Get_HXP + """ + branch = m3r_branch() + if branch == 'c': + hxp_print('m3a') + hxp_print('m4a') + else: + hxp_print('m4r') \ No newline at end of file diff --git a/build/lib/iexcode/instruments/logfile.py b/build/lib/iexcode/instruments/logfile.py new file mode 100644 index 0000000000000000000000000000000000000000..dec2ce2547f2096f5ebeda2597e496a1723b44d4 --- /dev/null +++ b/build/lib/iexcode/instruments/logfile.py @@ -0,0 +1,169 @@ +from os.path import join,isfile + +from epics import caget, caput +from iexcode.instruments.IEX_endstations import * +from iexcode.instruments.utilities import today +from iexcode.instruments.ARPES import ARPES_log_entries +from iexcode.instruments.Kappa import Kappa_log_entries + + +############################################################################################################## +############################## logging ############################## +############################################################################################################## +def log_print(**kwargs): + """ + prints a comment to the logfile + """ + logfile_print(BL.endstation_name,BL.ioc,kwargs['comment']) + +def log_update(): + """ + updates the log file with the last scan info + """ + if BL.endstation_name == 'ARPES': + entry_list,pv_list, format_list = ARPES_log_entries() + elif BL.endstation_name == 'Kappa': + entry_list,pv_list, format_list = Kappa_log_entries() + logfile_update(BL.endstation_name,BL.ioc,entry_list,pv_list,format_list) + + +############################################################################################################## +############################## general logfile functions ############################## +############################################################################################################## + + +def logfile_name_pv(endstation_name): + """ + Dictionary to get the PV in which the FileName for logging is stored + + endstation: 'ARPES' / 'Kappa' / 'Test + + Previously: logname_pv + """ + pv_dict={ + 'Test':'29idb:userStringSeq10.STR1', + 'ARPES':'29idb:userStringSeq10.STR2', + 'Kappa':'29idb:userStringSeq10.STR3', + 'RSoXS':'29idb:userStringSeq10.STR4', + } + if endstation_name in pv_dict.keys(): + pv=pv_dict[endstation_name] + else: + pv='29idb:userStringSeq10.STR10' + return pv + +def logfile_name_set(endstation_name,**kwargs): + """ + Sets the string used for the FileName in scanlog and EAlog + uses logname_PV to reference PV associated with a particular ioc + **kwargs: + filename = to set a specific filename, default => YYYYMMDD_log.txt + + Previously: logname_set + """ + kwargs.setdefault('filename_suffix','_log') + kwargs.setdefault('filename',today()+kwargs['filename_suffix']+'.txt') + + filename = kwargs['filename'] + + try: + caput(logfile_name_pv(endstation_name),filename) + print("\nLog filename = \'"+filename+"\' @ "+logfile_name_pv(endstation_name)) + print('To change filename, use logname_set(endstation_name,new_name)') + except: + print("Error: was not able to set the filename, check that 29idb ioc is running") + + +def logfile_name_get(endstation_name): + """ + Gets the string used for the FileName in scanlog and EAlog for the given scanIOC. + + Previously: logname + """ + + return caget(logfile_name_pv(endstation_name)) + +def logfile_fpath(endstation_name,mda_ioc): + """ + returns the full path to the logfile based on the current user in the mda scanRecord + + + Previously: logname, logname_generate + """ + + try: + filename = logfile_name_get(endstation_name) + user_name = BL.mda.scanRecord_user(mda_ioc) + fpath_with_subfolder = join(user_name,filename) + except: + fpath_with_subfolder = "logfile.txt" + print("Couldn't read log file path, using: "+fpath_with_subfolder) + + return fpath_with_subfolder + + +def logfile_print(endstation_name,mda_ioc,comment=''): + """ + Writes comments to the logfile on a new line + comment is a string of what you want to add to the file + e.g. comment = "------- New Sample--------" + + Previously: logprint + """ + + logfile_name = logfile_name_get(endstation_name) + + try: + fpath_with_subfolder=logfile_fpath(endstation_name,mda_ioc) + if not isfile(fpath_with_subfolder): + logfile_header(fpath_with_subfolder,entry=None) + with open(fpath_with_subfolder,'a') as myfile: + myfile.write(comment) + myfile.write('\n') + #print(comment,FileNameWithSubFolder) + except: + print("Logprint failed") + + +def logfile_header(endstation_name,mda_ioc,header_list): + """ + file path = path to where file_name lives + file_name = name of the logfile + entry is a list + + Previously: SaveFile_Header + """ + version = '1.4' + + fpath_with_subfolder=logfile_fpath(endstation_name,mda_ioc) + with open(fpath_with_subfolder, "w+") as f: + f.write('@Log version: '+ version+'\n\n') + file_path = BL.mda.scanRecord_filepath(mda_ioc) + f.write('FilePath '+endstation_name+': '+file_path+'\n') + + for key in header_list.keys(): + f.write(key+' Header: '+ header_list[key]+'\n\n') + + + +def logfile_update(endstation_name,mda_ioc,entry_list,pv_list,format_list): + """ + To be used for scanlog and scanEA functions. + Update SaveFile_Header version number when changing the structure of the file (indexing). + + Previously: SaveFile + """ + fpath_with_subfolder=logfile_fpath(endstation_name,mda_ioc) + + if not isfile(fpath_with_subfolder): + logfile_header(endstation_name,mda_ioc,entry_list) + + with open(fpath_with_subfolder, "a+") as f: + for i in range(len(format_list)): + pv_format = "{0:"+format_list[i]+"}," + f.write(pv_format.format(pv_list[i])) + last_entry=len(format_list)-1 + pv_format="{0:"+format_list[last_entry]+"}\n" + f.write(pv_format.format(pv_list[last_entry])) + + diff --git a/build/lib/iexcode/instruments/m3r.py b/build/lib/iexcode/instruments/m3r.py new file mode 100644 index 0000000000000000000000000000000000000000..54bb5ec77693a6857ce71dd5b87d6b4aeffd3386 --- /dev/null +++ b/build/lib/iexcode/instruments/m3r.py @@ -0,0 +1,126 @@ +from cgi import print_arguments + +from epics import caget, caput + +from iexcode.instruments.utilities import print_warning_message +from iexcode.instruments.FMB_mirrors import * + +############################################################################################################## +################################ M3R ############################## +############################################################################################################## +M3R_RY_POS_SP_initial = -16.52 +M3R_camera = '29id_ps6:' +M3R_cam1 = M3R_camera+"cam1:" +M3R_stats = M3R_camera+"Stats1:" +M3R_pitch = "29id_m3r:RY_MON" +M3R_align_pv = "29idKappa:align_m3r:" + +############################################################################################################## +################################ M3R default positions ############################## +############################################################################################################## +def m3r_get(verbose=True): + position = FMB_mirror_get(3,verbose) + return position + +def m3r_RY_pos_sp(): + return M3R_RY_POS_SP_initial + +def m3r_RY_pos_sp_get(): + RY_SP = caget('29id_m3r:RY_POS_SP') + return RY_SP + +def m3R_tweak (axis,val): + """ + \"TX\" = lateral \"RX\" = Yaw + \"TY\" = vertical \"RY\" = Pitch + \"TZ\" = longitudinal \"RZ\" = Roll + + Previously: Tweak_M3R + """ + mirror_num = 3 + FMB_mirror_tweak(mirror_num,axis,val,verbose=True) + +def m3r_tweak_pitch(sign,val=0.005): + """ + Previously: Tweak_M3R_Pitch + """ + axis="RY" + if sign == "+": + m3R_tweak(axis,val) + elif sign == "-": + m3R_tweak(axis,-val) + + +def m3r_table(branch): + """ + Defines the positions used by switch_branch() form M3R + WARNING: branch_pv uses: D => (Tx <= 0) and (Ry < 0) - Make sure this remains true or change it + """ + branch = branch.lower() + positions={ + "c":[10,0,0,0,0,0], + "d":[-2.5,0,0,-13.955,-16.450,-5.15], + "e":[-2.000,0,0,-13.960,-16.614,-7.500] + } + # d => optimized for MEG @ 500 eV on 2/29/def start + # e => 2018_3-- JM changed for RSoXS alignment max diode current + + try: + position = positions[branch] + except KeyError: + print_warning_message("not a valid branch") + position = FMB_mirror_get(3,verbose=False) + return position + +def m3r_branch(): + """ + get which branch based on the mirror position and returns the branch + """ + PV="29id_m3r:" + TX=caget(PV+"TX_MON") + if TX > 6: + branch = 'c' + elif TX < -1: + branch = 'd' + else: + print('M3R is not in a default position') + return branch + +def m3r_switch_branch(branch): + """ + switches the mirror to the position defined in m3r_table + """ + position = m3r_table(branch) + FMB_mirror_move_all(3,position,verbose=False) + # Relax bellows by doing large Z translation: + FMB_mirror_move_all(3,"TY",5,verbose=False) + FMB_mirror_move_all(3,"TY",5,verbose=False) + + FMB_mirror_get(3,verbose=True) + +############################################################################################################## +################################ M3R alignment ############################## +############################################################################################################## + +def centroid(t=None,q=1): + ''' + Return position of centroid, sigma, m3r:RY (mirror pitch) + Optional argument t to set camera intergration time. + ''' + if t is not None: + caput(M3R_cam1+'AcquireTime',t) + else: + t=caget(M3R_cam1+'AcquireTime') + position = round(caget(M3R_stats+'CentroidX_RBV'),2) + sigma = round(caget(M3R_stats+'SigmaX_RBV'),2) + intensity = round(caget(M3R_stats+'CentroidTotal_RBV'),2) + m3rRY = round(caget(M3R_pitch),4) + if q != None: + print('(position, sigma, total intensity, integration time (s), mirror pitch):') + return position,sigma,intensity,t,m3rRY + +def m3r_align(pxl=None): + if pxl == None: + pxl = caget(M3R_align_pv+'desired_pixel') + caput(M3R_align_pv+'desired_pixel',pxl) + caput(M3R_align_pv+'startAlign',1,wait=True,timeout=180) diff --git a/build/lib/iexcode/instruments/mpa.py b/build/lib/iexcode/instruments/mpa.py new file mode 100644 index 0000000000000000000000000000000000000000..6408b462eb1ab840d591207d7a6d0ec37d3794d7 --- /dev/null +++ b/build/lib/iexcode/instruments/mpa.py @@ -0,0 +1,440 @@ +from time import sleep +from os.path import dirname, join +import socket + +from epics import caget, caput +from iexcode.instruments.userCalcs import userCalcOut_clear,userStringSeq_clear +from iexcode.instruments.Kappa import Kappa_motor_dictionary,Kappa_cts, mda +from iexcode.instruments.AD_utilities import AD_ROI_setup +from iexcode.instruments.scalers import scaler_cts +from iexcode.instruments.scanRecord import * + + +""" +To do, get busy record in the mpa ioc, get user calcs in the mpa ioc + + +""" +############################################################################################################## +############################## PVs ############################## +############################################################################################################## +mpa_pv = "29iddMPA:" +mpaDet_pv = mpa_pv + "det1:" +mpa_busy = "29idcScienta:mybusy2" +userCalc_pv = "29idTest" +DAC_pv = '29iddau1:dau1:011:DAC' +max_HV = 2990 +ratio = 500 +tth_dLLM=13.73 +tth_dHLM=23.73 + + +def mpa_reset_pv(): + """ + returns the pv used for resetting the mpa + "writing a 1 resets" + """ + return mpa_pv+'C1O' + +def mpa_on_off_pv(): + """ + returns the pv used for turning on/off the mpa + on => caput 1 + off => caput0 + """ + return mpa_pv+'C0O' + +def mpa_HV_pvs(): + """ + returns the pvs for the userCalcout which hold the pvs for the mpa high voltage + """ + val_pv = "29idKappa:userCalcOut9.A" + rbv_pv ="29idKappa:userCalcOut10.OVAL" + return val_pv, rbv_pv + +############################################################################################################## +############################## HV Control ############################## +############################################################################################################## + +def mpa_HV_set(volt,verbose=True): + """ + sets the high voltage for the mpa + + Previously: MPA_HV_Set + """ + val_pv, rbv_pv = mpa_HV_pvs() + volt=min(volt,2990) + + caput(val_pv,volt,wait=True,timeout=18000) + sleep(1) + HV_rbv=caget(rbv_pv) + + if verbose: + print("HV = "+str(HV_rbv)+" V") + + +def mpa_HV_get(): + """ + sets the high voltage for the mpa + """ + val_pv, rbv_pv = mpa_HV_pvs() + + return caget(rbv_pv) + + +def mpa_HV_on(): + """ + turns the mpa high voltage on + + Previously: MPA_HV_ON + """ + n_on=1 + tth_pv = Kappa_motor_dictionary('tth')[3] + tth_dial = caget(tth_pv+'.DRBV') + if 13.73<= tth_dial <=23.73: + print('MPA OFF: detector in direct beam (-5 < tth for mcp < 5); move away before turning HV ON.') + else: + caput(mpa_reset_pv,1,wait=True,timeout=18000) + caput(mpa_reset_pv,0,wait=True,timeout=18000) + caput(mpa_on_off_pv,n_on,wait=True,timeout=18000) + print("MPA - HV On") + +def mpa_HV_off(): + """ + turns the mpa high voltage off + + Previously: MPA_HV_OFF + """ + n_off=0 + caput(mpa_on_off_pv,wait=True,timeout=18000) + print("MPA - HV Off") + + +def mpa_HV_reset(): + """ + resets the mpa high voltage + + Previously: MPA_HV_Reset + """ + caput(mpa_reset_pv,1) + print("MPA - Reset") + + +def mpa_HV_scan(start=2400,stop=2990,step=10,**kwargs): + """ + + Previously: MPA_HV_scan + """ + kwargs.setdefault('positioner_settling_time',1) + Kappa_cts(1) + val_pv, rbv_pv = mpa_HV_pvs() + mda.fillin(val_pv, rbv_pv,start,stop,step,**kwargs) + mda.go(**kwargs) + +############################################################################################################## +############################## MCP Scripts ############################## +############################################################################################################## +def mpa_ROI_setup(ROI_num=1,xcenter=535,ycenter=539,xsize=50,ysize=50,binX=1,binY=1): + """ + usage: + center of MCP, roiNum = 1 => MPA_ROI_SetUp(1,535,539,50,50) + to set up all use: mpa_ROI_setup_all(xcenter,ycenter) + """ + AD_ROI_setup('29iddMPA',ROI_num,xcenter,ycenter,xsize,ysize,binX,binY) + ROI_pv = mpa_pv+"ROI"+str(ROI_num)+':' + mpa_ROI_stats(ROI_num) + +def mpa_ROI_setup_all(xcenter=535,ycenter=539): + """ + setup up ROI + 1 => size = 50 x 50 + 2 => size = 100 x 100 + 3 => size = 150 x 150 + 4 => size = 200 x 200 + + """ + mpa_ROI_setup(1,xcenter,ycenter,xsize=50,ysize=50) + mpa_ROI_setup(2,xcenter,ycenter,xsize=100,ysize=100) + mpa_ROI_setup(3,xcenter,ycenter,xsize=150,ysize=150) + mpa_ROI_setup(4,xcenter,ycenter,xsize=200,ysize=200) + + +def mpa_ROI_stats(ROI_num): + """ + sequence to enable stats for mpa ROI + """ + ROI_pv=mpa_pv+"ROI"+str(ROI_num)+':' + stats_pv=mpa_pv+"Stats"+str(ROI_num)+':' + caput(stats_pv+'NDArrayPort','ROI'+str(ROI_num)) + caput(stats_pv+'EnableCallbacks','Enable') + caput(stats_pv+'ArrayCallbacks','Enable') + caput(stats_pv+'ComputeStatistics','Yes') + caput(stats_pv+'ComputeCentroid','Yes') + caput(stats_pv+'ComputeProfiles','Yes') + +def _mpa_trigger_calcOut(**kwargs): + """ + writes strSeq and calcOut for MPA this should go into the IOC + + **kwargs: + ADplugin = 'TIFF1:' (default) + """ + + kwargs.setdefault("ADplugin","TIFF1:") + kwargs.setdefault("save_image",False) + + ADplugin = mpa_pv + kwargs["ADplugin"] + Proc1 = mpa_pv + "Proc1:" + + #All this should moved into the MPA IOC + Calcs_mda = ScanRecord("29idTest:") + + desc = "MPA busy" + n=9 + busy_CalcOut = userCalcOut_clear(Calcs_mda,n) + caput(busy_CalcOut+".DESC",desc) + caput(busy_CalcOut+".INPA",mpa_busy+" CP") + caput(busy_CalcOut+".OOPT",'Transition to non-zero') + caput(busy_CalcOut+".OUT",start_strSeq+".PROC PP") + + desc = "MPA start" + n=1 + start_strSeq = userStringSeq_clear(Calcs_mda,n) + caput(start_strSeq+".DESC",desc) + caput(start_strSeq+".LNK1", Proc1+"ResetFilter PP") + caput(start_strSeq+".STR1","Yes") + + desc = "MPA wait" + n=10 + wait_CalcOut = userCalcOut_clear(Calcs_mda,n) + caput(wait_CalcOut+".DESC",desc) + caput(wait_CalcOut+".INPA",Proc1+"NumFilter_RBV") + caput(wait_CalcOut+".INPB",Proc1+"NumFiltered_RBV") + caput(wait_CalcOut+".OOPT",'Transition to non-zero') + caput(wait_CalcOut+".OUT",done_strSeq+".PROC PP") + + desc = "MPA writeDone" + n=1 + done_strSeq = userStringSeq_clear(Calcs_mda,n) + caput(done_strSeq+".DESC","MPA writeDone") + caput(done_strSeq+".LNK1", ADplugin+"WriteFile PP") + caput(done_strSeq+".STR1","Write") + caput(done_strSeq+".LNK1", mpa_busy+" PP") + caput(done_strSeq+".STR1","Done") + + + +def _mpa_trigger_callback(trigger,saveImg=False,**kwargs): + """ + used for triggering the MPA in the scanRecord, reset Proc1 and waits for finish + + trigger: adds/removes trigger to mda (True/False) + + **kwargs: + save_image = False used for appropriate trigger of ROIs + = True also saves an image based on ADplugin type + ADplugin = 'TIFF1:' (default + + by default ADplugin = 29iddMPA:TIFF1: + can use 29iddMPA:HDF1: + """ + + kwargs.setdefault("ADplugin","TIFF1:") + kwargs.setdefault("save_image",False) + + ADplugin = mpa_pv + kwargs['ADplugin'] + + _mpa_trigger_calcOut(**kwargs) + + if trigger==True: + caput(ADplugin+"AutoResetFilter","Yes") + if saveImg: + caput(ADplugin+"AutoSave", "No") + caput(ADplugin+"EnableCallbacks", "Enable") + + if trigger==False: + caput(ADplugin+"AutoResetFilter","No") + if saveImg: + caput(ADplugin+"EnableCallbacks", "Disable") + caput(ADplugin+"AutoSave", "Yes") + + return mpa_busy + +def _mpa_prefix(**kwargs): + """ + """ + kwargs.setdefault("debug",False) + + fpath=join(dirname(dirname(mda.filepath)),"mpa",'') + nextMDA = mda.fileNum + prefix="mda"+str.zfill(str(nextMDA),4)+"_mpa" + return prefix + +def mpa_trigger(trigger, **kwargs): + """ + Sets up / Cleans up the ScanRecord to trigger the MPA + + trigger: adds/removes trigger to mda (True/False) + + + **kwargs: + save_image = False used for appropriate trigger of ROIs + = True also saves an image based on ADplugin type + detTrigNum = 2 (default) + scan_dim = 1 (default) + ADplugin = "TIFF1" / "HDF1" + + Previously: MPA_Trigger + """ + kwargs.setdefault("detTrigNum",2) + kwargs.setdefault("save_image",False) + kwargs.setdefault('scan_dim',1) + kwargs.setdefault("ADplugin","TIFF1:") + + mpa_busy = _mpa_trigger_callback(trigger, **kwargs) + + #adding the MPA to the scanRecord trigger + if trigger == True: + _mpa_prefix(**kwargs) + mda.triggers_set(kwargs['scan_dim'],{2:mpa_busy}) + + if trigger == False: + mda.triggers_set(kwargs['scan_dim'],{2:''}) + + + +def mpa_save_strSeq(**kwargs): + """ + **kwargs: + ADplugin: "TIFF1:" + """ + kwargs.setdefault("ADplugin","TIFF1:") + + ADplugin = mpa_pv + kwargs["ADplugin"] + + desc = "MCP datamode" + n=2 + strSeq_pv = userStringSeq_clear(mda,n) + caput(strSeq_pv+".DESC",desc) + caput(strSeq_pv+".LNK1",mpaDet_pv+"Acquire CA NMS") + caput(strSeq_pv+".STR1","Done") + caput(strSeq_pv+".WAIT1","Wait") + caput(strSeq_pv+".LNK2",mpaDet_pv+"RunTimeEnable PP NMS") + caput(strSeq_pv+".STR2","1") + caput(strSeq_pv+".WAIT2","Wait") + caput(strSeq_pv+".LNK3",ADplugin+"EnableCallbacks PP NMS") + caput(strSeq_pv+".STR3","1") + +def mpa_freerun_strSeq(): + """ + """ + desc = "MCP freerun" + n=1 + strSeq_pv = userStringSeq_clear(mda,n) + caput(strSeq_pv+".DESC",desc) + caput(strSeq_pv+".LNK1",mpaDet_pv+"Acquire PP NMS") + caput(strSeq_pv+".WAIT1","Wait") + caput(strSeq_pv+".STR1","Done") + caput(strSeq_pv+".LNK2","29iddMPA:TIFF1:EnableCallbacks PP NMS") + caput(strSeq_pv+".STR2","0") + caput(strSeq_pv+".WAIT2","Wait") + caput(strSeq_pv+".LNK3",mpaDet_pv+"RunTimeEnable PP NMS") + caput(strSeq_pv+".STR3","0") + caput(strSeq_pv+".WAIT3","Wait") + caput(strSeq_pv+".LNK4",mpaDet_pv+"Acquire PP NMS") + caput(strSeq_pv+".STR4","Acquire") + + +def mpa_HV_sp_calcOut(): + """ + """ + + desc = "MPA HV SP" + n=9 + calcOut_pv = userCalcOut_clear(mda,n) + + caput(calcOut_pv+".DESC",desc) + caput(calcOut_pv+".A",0) + caput(calcOut_pv+".B",ratio) + caput(calcOut_pv+".C",max_HV) + caput(calcOut_pv+".CALC$","A") + caput(calcOut_pv+".OCAL$","MIN(A/B,C/B)") + caput(calcOut_pv+".OOPT",1) # On Change + caput(calcOut_pv+".DOPT",1) # Use 0CALC + caput(calcOut_pv+".IVOA",0) # Continue Normally + caput(calcOut_pv+".OUT",DAC_pv+" PP NMS") + +def mpa_HV_rbv_calcOut(): + """ + """ + desc = "MPA HV RBV" + n=10 + calcOut_pv = userCalcOut_clear(mda,n) + + caput(calcOut_pv+".DESC",desc) + caput(calcOut_pv+".INPA",DAC_pv+' CP NMS') + caput(calcOut_pv+".B",ratio) + caput(calcOut_pv+".CALC$","A*B") + +def mpa_interlock_mpa(): + """ + """ + desc = "MPA Interlock mpa" + n=7 + calcOut_pv = userCalcOut_clear(mda,n) + + caput(calcOut_pv+".DESC",desc) + tth_pv = Kappa_motor_dictionary('tth')[3] + caput(calcOut_pv+".INPA",tth_pv+".DRBV CP NMS") + caput(calcOut_pv+".B",1) + caput(calcOut_pv+".CALC$","ABS((("+str(tth_dLLM)+"<A && A<"+str(tth_dHLM)+") && (B>0))-1)") + caput(calcOut_pv+".OCAL$",'A') + caput(calcOut_pv+".OOPT",2) # When zero + caput(calcOut_pv+".DOPT",0) # Use CALC + caput(calcOut_pv+".IVOA",0) # Continue Normally + caput(calcOut_pv+".OUT",mpa_on_off_pv()+"PP NMS") + + +def mpa_interlock_DAC(): + """ + """ + desc = "MPA Interlock DAC" + n=8 + calcOut_pv = userCalcOut_clear(mda,n) + + caput(calcOut_pv+".DESC",desc) + tth_pv = Kappa_motor_dictionary('tth')[3] + caput(calcOut_pv+".INPA",tth_pv+".DRBV CP NMS") + caput(calcOut_pv+".B",1) + caput(calcOut_pv+".CALC$","ABS((("+str(tth_dLLM)+"<A && A<"+str(tth_dHLM)+") && (B>0))-1)") + caput(calcOut_pv+".OCAL$",'A') + caput(calcOut_pv+".OOPT",2) # When zero + caput(calcOut_pv+".DOPT",0) # Use CALC + caput(calcOut_pv+".IVOA",0) # Continue Normally + caput(calcOut_pv+".OUT",DAC_pv+"_Se PP NMS") + +def reset_mpa_HV(): + """ + resetting the SRS which controls the MPA HV + Model: SRS PS350 + ip = "164.54.118.57" + """ + ip = "164.54.118.57" + # Open TCP connect to poet 1234 of GPIB-ETHERNET + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP) + sock.settimeout(0.1) + sock.connect((ip, 1234)) + + # Set mode as CONTROLLER + sock.send(b'++mode 1\n') + + # specify GPIB address of device being controlled + addr = "14" + str1="++addr"+addr+'\n' + sock.send(bytes(str1,'utf-8')) + + # reset SRS PS350 + #sock.send("*RST\n") + + # turn the high voltage on, clearing any current or voltage trips + sock.send(b"HVON\n") \ No newline at end of file diff --git a/build/lib/iexcode/instruments/remote_controlers.py b/build/lib/iexcode/instruments/remote_controlers.py new file mode 100644 index 0000000000000000000000000000000000000000..2c65239be40dcfcbbbc0a218203d49a0a2a08562 --- /dev/null +++ b/build/lib/iexcode/instruments/remote_controlers.py @@ -0,0 +1,356 @@ +from epics import caget,caput + +############################################################################################################## +############################## RSXS Remote control ############################## +############################################################################################################## + +# To start ioc for ARPES(RSXS) Surly(Sneezy) +# cd /net/s29dserv/xorApps/epics/synApps_5_8/ioc/29idSurlySoft/iocboot/iocLinux +# 29idSurlySoft start + +# to bring up epics screen +# cd /net/s29dserv/xorApps/epics/synApps_5_8/ioc/29idSurlySoft/ +# start_epics_29idSurlySoft + +def ARPES_Controller(): + """ + Button={} with Button[][0]=PV name and Button[][1]=value (for tweaks or other procs value=1) + ".TWF -> (+)tweak" + ".TWR -> (-)tweak" + """ + Controller="29idSurlySoft" + ioc="29idc:" + + Triggers={} #['LTSeq','RTSeq','LBSeq','RBSeq'] + Triggers[0]=ioc+"allstop.VAL",1 + Triggers[1]=ioc+"allstop.VAL",1 + Triggers[2]=ioc+"allstop.VAL",1 + Triggers[3]=ioc+"allstop.VAL",1 + + DPad={} #['UpSeq','DownSeq','LeftSeq','RightSeq'] + DPad[0]=ioc+"m1.TWF",1 #x + DPad[1]=ioc+"m1.TWR",1 + DPad[2]=ioc+"m4.TWR",1 #th + DPad[3]=ioc+"m4.TWF",1 + + Buttons={} #['YSeq','ASeq','XSeq','BSeq'] + Buttons[0]=ioc+"m3.TWF",1 #z + Buttons[1]=ioc+"m3.TWR",1 + Buttons[2]=ioc+"m2.TWR",1 #y + Buttons[3]=ioc+"m2.TWF",1 + + Ljoy={} #['LSUpSeq','LSDownSeq','LSLeftSeq','LSRightSeq'] + Ljoy[0]="",0 + Ljoy[1]="",0 + Ljoy[2]=ioc+"m6.TWR",1 #phi + Ljoy[3]=ioc+"m6.TWF",1 #phi + Lclick={} #['L3Seq'] + Lclick[0]=ioc+"m1.TWV",.25 #x + Lclick[1]=ioc+"m2.TWV",.25 #y + Lclick[2]=ioc+"m3.TWV",.25 #z + Lclick[3]=ioc+"m4.TWV",1 #th + Lclick[4]=ioc+"m5.TWV",1 #chi + Lclick[5]=ioc+"m6.TWV",1 #phi + Lclick[6]="",0 + Lclick[7]="",0 + Lclick[8]="",0 + + Rjoy={} #['RSUpSeq','RSDownSeq','RSLeftSeq','RSRightSeq'] + Rjoy[0]="",0 + Rjoy[1]="",0 + Rjoy[2]=ioc+"m5.TWR",1 #chi + Rjoy[3]=ioc+"m5.TWF",1 #chi + Rclick={} #['R3Seq'] + Rclick[0]=ioc+"m1.TWV",.5 #x + Rclick[1]=ioc+"m2.TWV",.5 #y + Rclick[2]=ioc+"m3.TWV",.5 #z + Rclick[3]=ioc+"m4.TWV",5 #th + Rclick[4]=ioc+"m5.TWV",5 #chi + Rclick[5]=ioc+"m6.TWV",5 #phi + Rclick[6]="",0 + Rclick[7]="",0 + Rclick[8]="",0 + + Controller_setup(Controller,Triggers,DPad,Buttons,Ljoy,Lclick,Rjoy,Rclick) + + +def RSXS_Kappa_Controller_backup(): #Keep JM modified below when kth broke + """ + Button={} with Button[][0]=PV name and Button[][1]=value (for tweaks or other procs value=1) + ".TWF -> (+)tweak" + ".TWR -> (-)tweak" + """ + Controller="29idSneezySoft" + ioc="29idKappa:" + + Triggers={} #['LTSeq','RTSeq','LBSeq','RBSeq'] + Triggers[0]=ioc+"m9.TWR",1 #tth + Triggers[1]=ioc+"m9.TWF",1 + Triggers[2]=ioc+"allstop.VAL",1 + Triggers[3]=ioc+"allstop.VAL",1 + + DPad={} #['UpSeq','DownSeq','LeftSeq','RightSeq'] + DPad[0]=ioc+"m4.TWF",1 #z + DPad[1]=ioc+"m4.TWR",1 + DPad[2]=ioc+"m1.TWR",1 #phi + DPad[3]=ioc+"m1.TWF",1 + + Buttons={} #['YSeq','ASeq','XSeq','BSeq'] + Buttons[0]=ioc+"m3.TWF",1 #y + Buttons[1]=ioc+"m3.TWR",1 + Buttons[2]=ioc+"m2.TWR",1 #x + Buttons[3]=ioc+"m2.TWF",1 + + Ljoy={} #['LSUpSeq','LSDownSeq','LSLeftSeq','LSRightSeq'] + Ljoy[0]="",0 + Ljoy[1]="",0 + Ljoy[2]=ioc+"m8.TWR",1 #th + Ljoy[3]=ioc+"m8.TWF",1 + Lclick={} #['L3Seq'] + Lclick[0]=ioc+"m2.TWV",50 #x + Lclick[1]=ioc+"m3.TWV",50 #y + Lclick[2]=ioc+"m4.TWV",50 #z + Lclick[3]=ioc+"m1.TWV",0.5 #phi (0.5 deg) + Lclick[4]=ioc+"m7.TWV",0.5 #kappa + Lclick[5]=ioc+"m8.TWV",0.5 #th + Lclick[6]=ioc+"m9.TWV",0.5 #tth + Lclick[7]="",0 + Lclick[8]="",0 + + Rjoy={} #['RSUpSeq','RSDownSeq','RSLeftSeq','RSRightSeq'] + Rjoy[0]="",0 + Rjoy[1]="",0 + Rjoy[2]=ioc+"m7.TWR",1 #kappa + Rjoy[3]=ioc+"m7.TWF",1 + Rclick={} #['R3Seq'] + Rclick[0]=ioc+"m2.TWV",250 #x + Rclick[1]=ioc+"m3.TWV",250 #y + Rclick[2]=ioc+"m4.TWV",250 #z + Rclick[3]=ioc+"m1.TWV",5 #phi (45 deg) + Rclick[4]=ioc+"m7.TWV",5 #kappa + Rclick[5]=ioc+"m8.TWV",5 #th + Rclick[6]=ioc+"m9.TWV",5 #tth + Rclick[7]="",0 + Rclick[8]="",0 + + Controller_setup(Controller,Triggers,DPad,Buttons,Ljoy,Lclick,Rjoy,Rclick) + +def RSXS_Kappa_Controller(): + """ + Button={} with Button[][0]=PV name and Button[][1]=value (for tweaks or other procs value=1) + ".TWF -> (+)tweak" + ".TWR -> (-)tweak" + """ + Controller="29idSneezySoft" + ioc="29idKappa:" + + Triggers={} #['LTSeq','RTSeq','LBSeq','RBSeq'] + Triggers[0]=ioc+"m9.TWR",1 #tth + Triggers[1]=ioc+"m9.TWF",1 + Triggers[2]=ioc+"allstop.VAL",1 + Triggers[3]=ioc+"allstop.VAL",1 + + DPad={} #['UpSeq','DownSeq','LeftSeq','RightSeq'] + DPad[0]=ioc+"m4.TWF",1 #z + DPad[1]=ioc+"m4.TWR",1 + DPad[2]=ioc+"m1.TWR",1 #phi + DPad[3]=ioc+"m1.TWF",1 + + Buttons={} #['YSeq','ASeq','XSeq','BSeq'] + Buttons[0]=ioc+"m3.TWF",1 #y + Buttons[1]=ioc+"m3.TWR",1 + Buttons[2]=ioc+"m2.TWR",1 #x + Buttons[3]=ioc+"m2.TWF",1 + + Ljoy={} #['LSUpSeq','LSDownSeq','LSLeftSeq','LSRightSeq'] + Ljoy[0]="29idd:Unidig1Bo0",0 #light on + Ljoy[1]="29idd:Unidig1Bo0",1 #light off + Ljoy[2]=ioc+"",0 #th + Ljoy[3]=ioc+"",0 + Lclick={} #['L3Seq'] + Lclick[0]=ioc+"m2.TWV",250 #x + Lclick[1]=ioc+"m3.TWV",250 #y + Lclick[2]=ioc+"m4.TWV",250 #z + Lclick[3]=ioc+"m1.TWV",0.5 #phi (0.5 deg) + Lclick[4]=ioc+"m7.TWV",0.5 #kappa + Lclick[5]=ioc+"m8.TWV",0.5 #th + Lclick[6]=ioc+"m9.TWV",0.5 #tth + Lclick[7]="",0 + Lclick[8]="",0 + + Rjoy={} #['RSUpSeq','RSDownSeq','RSLeftSeq','RSRightSeq'] + Rjoy[0]="",0 + Rjoy[1]="",0 + Rjoy[2]=ioc+"",0 #kappa + Rjoy[3]=ioc+"",0 + Rclick={} #['R3Seq'] + Rclick[0]=ioc+"m2.TWV",500 #x + Rclick[1]=ioc+"m3.TWV",500 #y + Rclick[2]=ioc+"m4.TWV",500 #z + Rclick[3]=ioc+"m1.TWV",5 #phi (45 deg) + Rclick[4]=ioc+"m7.TWV",5 #kappa + Rclick[5]=ioc+"m8.TWV",5 #th + Rclick[6]=ioc+"m9.TWV",5 #tth + Rclick[7]="",0 + Rclick[8]="",0 + + Controller_setup(Controller,Triggers,DPad,Buttons,Ljoy,Lclick,Rjoy,Rclick) + + +def RSoXS_Controller(): + """ + Button={} with Button[][0]=PV name and Button[][1]=value (for tweaks or other procs value=1) + ".TWF -> (+)tweak" + ".TWR -> (-)tweak" + """ + Controller="29idSneezySoft" + ioc="29idRSoXS:" + + Triggers={} #['LTSeq','RTSeq','LBSeq','RBSeq'] + Triggers[0]=ioc+"allstop.VAL",1 + Triggers[1]=ioc+"allstop.VAL",1 + Triggers[2]=ioc+"allstop.VAL",1 + Triggers[3]=ioc+"allstop.VAL",1 + + DPad={} #D-Pad:['UpSeq','DownSeq','LeftSeq','RightSeq'] + DPad[0]=ioc+"m10.TWF",1 #Det-V + DPad[1]=ioc+"m10.TWR",1 + DPad[2]=ioc+"m11.TWR",1 #Det-Q + DPad[3]=ioc+"m11.TWF",1 + + Buttons={} #Buttons:['YSeq','ASeq','XSeq','BSeq'] + Buttons[0]=ioc+"m2.TWF",1 #y + Buttons[1]=ioc+"m2.TWR",1 + Buttons[2]=ioc+"m1.TWR",1 #x + Buttons[3]=ioc+"m1.TWF",1 + + Ljoy={} #Left Joystick:['LSUpSeq','LSDownSeq','LSLeftSeq','LSRightSeq'] + Ljoy[0]=ioc+"m5.TWF",1 #phi + Ljoy[1]=ioc+"m5.TWR",1 + Ljoy[2]=ioc+"m9.TWR",1 #tth + Ljoy[3]=ioc+"m9.TWF",1 + Lclick={} #['L3Seq'] + Lclick[0]="",0 + Lclick[1]="",0 + Lclick[2]="",0 + Lclick[3]="",0 + Lclick[4]="",0 + Lclick[5]="",0 + Lclick[6]="",0 + Lclick[7]="",0 + Lclick[8]="",0 + + Rjoy={} #Right Joystick:['RSUpSeq','RSDownSeq','RSLeftSeq','RSRightSeq'] + Rjoy[0]=ioc+"m3.TWF",1 #z + Rjoy[1]=ioc+"m3.TWF",1 + Rjoy[2]=ioc+"m8.TWR",1 #th + Rjoy[3]=ioc+"m8.TWF",1 + Rclick={} #['R3Seq'] + Rclick[0]=ioc+"m2.TWV",1 #x + Rclick[1]=ioc+"m3.TWV",1 #y + Rclick[2]=ioc+"m4.TWV",1 #z + Rclick[3]=ioc+"m1.TWV",1 #th + Rclick[4]=ioc+"m7.TWV",1 #phi + Rclick[5]=ioc+"m8.TWV",1 #tth + Rclick[6]=ioc+"m9.TWV",1 #Det-V + Rclick[7]=ioc+"m9.TWV",1 #Det-Q + Rclick[8]="",0 + + Controller_setup(Controller,Triggers,DPad,Buttons,Ljoy,Lclick,Rjoy,Rclick) + +def Controller_setup(Controller,Triggers,DPad,Buttons,Ljoy,Lclick,Rjoy,Rclick): + """ -------- Standard set up for the Logitech controllers -------------- + Controller -> controller ioc name + + Button={} + Button[][0]=PV name + Button[][1]=value (for tweaks or other procs value=1) + ".TWF -> (+)tweak" + ".TWR -> (-)tweak" + + Trigger[0,3] -> PVs for link 1 of the 4 buttons (bottoms are typically the allstop) + DPad[0,3] -> PVs for link 1 of the 4 buttons (order: Top/Bottom/Left/Right) + Buttons[0,3] -> PVs for link 1 of the 4 buttons (order: Top/Bottom/Left/Right) + Ljoy[0,3] -> PVs for link 1 of the 4 buttons (order: Top/Bottom/Left/Right) + Lclick[0,8] -> PVs for Link 1-9 of the center click (typically coarse tweak values) + RJoy[0,3] -> PVs for link 1 of the 4 buttons (order: Top/Bottom/Left/Right) + Rclick[0,8] -> PVs for Link 1-9 of the center click (typically fine tweak values) + """ + + #Triggers + Ctrl_button(Controller,"LTSeq",1,Triggers[0][0],Triggers[0][1]) + Ctrl_button(Controller,"RTSeq",1,Triggers[1][0],Triggers[1][1]) + Ctrl_button(Controller,"LBSeq",1,Triggers[2][0],Triggers[2][1])#All Stop + Ctrl_button(Controller,"RBSeq",1,Triggers[3][0],Triggers[3][1])#All Stop + + # D-Pad + Ctrl_button(Controller,"UpSeq",1, DPad[0][0],DPad[0][1]) + Ctrl_button(Controller,"DownSeq",1, DPad[1][0],DPad[1][1]) + Ctrl_button(Controller,"LeftSeq",1, DPad[2][0],DPad[2][1]) + Ctrl_button(Controller,"RightSeq",1,DPad[3][0],DPad[3][1]) + + + #Buttons + Ctrl_button(Controller,"YSeq",1,Buttons[0][0],Buttons[0][1]) + Ctrl_button(Controller,"ASeq",1,Buttons[1][0],Buttons[1][1]) + Ctrl_button(Controller,"XSeq",1,Buttons[2][0],Buttons[2][1]) + Ctrl_button(Controller,"BSeq",1,Buttons[3][0],Buttons[3][1]) + + + #Left Joystick + Ctrl_button(Controller,"LSUpSeq",1, Ljoy[0][0],Ljoy[0][1]) + Ctrl_button(Controller,"LSDownSeq",1, Ljoy[1][0],Ljoy[1][1]) + Ctrl_button(Controller,"LSLeftSeq",1, Ljoy[2][0],Ljoy[2][1]) + Ctrl_button(Controller,"LSRightSeq",1,Ljoy[3][0],Ljoy[3][1]) + #Left Click Coarse Tweak Values + Ctrl_button(Controller,"L3Seq",1,Lclick[0][0],Lclick[0][1]) + Ctrl_button(Controller,"L3Seq",2,Lclick[1][0],Lclick[1][1]) + Ctrl_button(Controller,"L3Seq",3,Lclick[2][0],Lclick[2][1]) + Ctrl_button(Controller,"L3Seq",4,Lclick[3][0],Lclick[3][1]) + Ctrl_button(Controller,"L3Seq",5,Lclick[4][0],Lclick[4][1]) + Ctrl_button(Controller,"L3Seq",6,Lclick[5][0],Lclick[5][1]) + Ctrl_button(Controller,"L3Seq",7,Lclick[6][0],Lclick[6][1]) + Ctrl_button(Controller,"L3Seq",8,Lclick[7][0],Lclick[7][1]) + Ctrl_button(Controller,"L3Seq",9,Lclick[8][0],Lclick[8][1]) + + #Right Joystick + Ctrl_button(Controller,"RSUpSeq",1, Rjoy[0][0],Rjoy[0][1]) + Ctrl_button(Controller,"RSDownSeq",1, Rjoy[1][0],Rjoy[1][1]) + Ctrl_button(Controller,"RSLeftSeq",1, Rjoy[2][0],Rjoy[2][1]) + Ctrl_button(Controller,"RSRightSeq",1,Rjoy[3][0],Rjoy[3][1]) + #Right Click Fine Tweak Values + Ctrl_button(Controller,"R3Seq",1,Rclick[0][0],Rclick[0][1]) + Ctrl_button(Controller,"R3Seq",2,Rclick[1][0],Rclick[1][1]) + Ctrl_button(Controller,"R3Seq",3,Rclick[2][0],Rclick[2][1]) + Ctrl_button(Controller,"R3Seq",4,Rclick[3][0],Rclick[3][1]) + Ctrl_button(Controller,"R3Seq",5,Rclick[4][0],Rclick[4][1]) + Ctrl_button(Controller,"R3Seq",6,Rclick[5][0],Rclick[5][1]) + Ctrl_button(Controller,"R3Seq",7,Rclick[6][0],Rclick[6][1]) + Ctrl_button(Controller,"R3Seq",8,Rclick[7][0],Rclick[7][1]) + Ctrl_button(Controller,"R3Seq",9,Rclick[8][0],Rclick[8][1]) + + +def Ctrl_reset(Controller): + PV="" + val=0 + CtrlButtonList = ['LTSeq','RTSeq','LBSeq','RBSeq','UpSeq','DownSeq','LeftSeq','RightSeq','YSeq','ASeq','XSeq','BSeq'] + CtrlButtonList.extend(['LSUpSeq','LSDownSeq','LSLeftSeq','LSRightSeq','L3Seq','RSUpSeq','RSDownSeq','RSLeftSeq','RSRightSeq','R3Seq']) + for button in CtrlButtonList: + for link in range(1,10): + Ctrl_button(Controller,button,link,PV,val) + +def Ctrl_button(Controller,button,link,PV,val):#writes to specified link (controller has 1 to 9) + ctlpv=Controller+":ctl1:"+button + caput(ctlpv+".LNK"+str(link),PV+" NPP NMS") + caput(ctlpv+".DO"+str(link),val) + +def Ctrl_print(Controller): + CtrlButtonList = ['LTSeq','RTSeq','LBSeq','RBSeq','UpSeq','DownSeq','LeftSeq','RightSeq','YSeq','ASeq','XSeq','BSeq'] + CtrlButtonList.extend(['LSUpSeq','LSDownSeq','LSLeftSeq','LSRightSeq','L3Seq','RSUpSeq','RSDownSeq','RSLeftSeq','RSRightSeq','R3Seq']) + for button in CtrlButtonList: + print("---"+button+"---") + for link in range(1,10): + ctlpv=Controller+":ctl1:"+button + PV=caget(ctlpv+".LNK"+str(link)) + val=caget(ctlpv+".DO"+str(link)) + print(" "+PV+", "+str(val)) diff --git a/build/lib/iexcode/instruments/resolution.py b/build/lib/iexcode/instruments/resolution.py new file mode 100644 index 0000000000000000000000000000000000000000..a34f8919c7df6eca028e3216ec5b13e3d5973da2 --- /dev/null +++ b/build/lib/iexcode/instruments/resolution.py @@ -0,0 +1,106 @@ +import numpy as np + +from iexcode.instruments.electron_analyzer import resolution_EA +############################################################################################################# +############################## Resolution ############################## +############################################################################################################# +def resolution_calculate_beamline(grt,hv_eV,slit_size): + """ + + Previously: Calc_BL_Resolution + """ + res_function={} + res_function[10] = {"MEG":(-0.000800494,2.56761e-05,1.83724e-08,-1.69223e-12,0), "HEG":(-0.000414482,1.07456e-05,8.79034e-09,-8.42361e-13,0)} + res_function[20] = {"MEG":(-0.00156643, 3.16894e-05,2.72121e-08,-2.63642e-12,0), "HEG":(-0.00054591, 1.35647e-05,2.01775e-08,-4.30789e-12,5.70112e-16)} + res_function[50] = {"MEG":(-0.00251543, 4.89022e-05,7.70055e-08,-1.66358e-11,2.21272e-15),"HEG":(-0.00173081, 2.97625e-05,4.90646e-08,-1.0706e-11, 1.43011e-15)} + res_function[100] = {"MEG":(-0.00545563, 9.14928e-05,1.51335e-07,-3.30332e-11,4.41314e-15),"HEG":(-0.00360316, 5.83265e-05,9.76881e-08,-2.13767e-11,2.85877e-15)} + res_function[200] = {"MEG":(-0.0111658, 0.000179785,3.01277e-07,-6.59309e-11,8.81755e-15),"HEG":(-0.00728107, 0.000116055,1.95149e-07,-4.27331e-11,5.71638e-15)} + try: + a,b,c,d,e = res_function[slit_size][grt] + resolution = a + b*hv_eV + c*hv_eV**2 + d*hv_eV**3 + e*hv_eV**4 + + except KeyError: + print("WARNING: Slit size not listed, please choose one of the following:") + print(" 10, 20, 50, 100, 200 um.") + resolution=0 + + return resolution*1000 + + +def resolution_mono_noise(grt,hv_eV): + """ + jitter/noise in the mono contribution to the resolution + + Previoulsy: Resolution_Mono + """ + if grt == "MEG": + K0=-2.3836 + K1=0.02083 + K2=7.8886e-06 + if grt == "HEG": + K0=-2.0984 + K1=0.011938 + K2=3.6397e-06 + noise = K0 + K1*hv_eV + K2*hv_eV**2 + return noise + + +def resolution_beamline(grt,hv_eV,slit_size,verbose=True): + """ + resolution of the beamline optics + + Resolution_BL + """ + mono_noise = resolution_mono_noise(grt,hv_eV) + theortical = resolution_calculate_beamline(grt,hv_eV,slit_size) + resolution=np.sqrt(theortical**2 + mono_noise**2) + if verbose: + print("BL : "+"%.0f" % theortical, "meV") + print("Mono : "+"%.0f" % mono_noise, "meV") + print("Total: "+"%.0f" % resolution, "meV") + return resolution + + +def resolution_ARPES(grt,hv_eV,slit_size,PE,slit_SES,T,verbose=True): + """ + resolution of the ARPES + """ + bl = resolution_beamline(grt,hv_eV,slit_size,verbose=False) + KbT = T*25/300 + SES = resolution_EA(PE,slit_SES) + + resolution = np.sqrt(bl**2 + KbT**2 + SES**2) + + if verbose: + print("BL + mono : "+"%.0f" % bl, "meV") + print("SES : "+"%.0f" % SES, "meV") + print("KbT : "+"%.0f" % KbT, "meV") + print("Total: "+"%.0f" % resolution, "meV") + + return resolution + +def Resolution_BL_eff(grating,hv,slit_3C,PE,slit_SES,T,Ef): + M = resolution_mono_noise(grating,hv) + KbT = T*25/300 + BL = resolution_calculate_beamline(grating,hv,slit_3C) + SES = resolution_EA(PE,slit_SES) + resolution = np.sqrt(BL**2+SES**2+KbT**2+M**2) + effective = np.sqrt(Ef**2-SES**2-KbT**2-M**2) + print("BL_th : "+"%.0f" % BL, "meV SES : "+"%.0f" % SES, "meV") + print("Mono : "+"%.0f" % M, "meV KbT : "+"%.0f" % KbT, "meV") + print("Total : "+"%.0f" % resolution, "meV Fermi : "+"%.0f" % Ef, "meV") + print("BL_eff: "+"%.0f" % effective, "meV") + + +def Resolution_BL_eff2(grating,hv,slit_3C,PE,slit_SES,T,Ef,Dirty_Au): + M = resolution_mono_noise(grating,hv) + KbT = T*25/300 + BL = resolution_calculate_beamline(grating,hv,slit_3C) + SES = resolution_EA(PE,slit_SES) + resolution = np.sqrt(BL**2+SES**2+KbT**2+M**2+Dirty_Au**2) + effective = np.sqrt(Ef**2-SES**2-KbT**2-M**2-Dirty_Au**2) + print("BL_th : "+"%.0f" % BL, "meV SES : "+"%.0f" % SES, "meV") + print("Mono : "+"%.0f" % M, "meV KbT : "+"%.0f" % KbT, "meV") + print("Total : "+"%.0f" % resolution, "meV Fermi : "+"%.0f" % Ef, "meV") + print("BL_eff: "+"%.0f" % effective, "meV Sample : "+"%.0f" % Dirty_Au, "meV") + diff --git a/build/lib/iexcode/instruments/s29_temp_cntl.py b/build/lib/iexcode/instruments/s29_temp_cntl.py new file mode 100644 index 0000000000000000000000000000000000000000..4bffcdae02016ef54eeb3e51bff3f8d9b26c390d --- /dev/null +++ b/build/lib/iexcode/instruments/s29_temp_cntl.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +from epics import caget, caput +from time import sleep, gmtime, strftime, localtime + +#Define caput with wait function +def caputw(PVname,PVinput): + return caput(PVname,PVinput,wait=True, timeout = 100000) + +def dateandtime(): + return strftime("%a %d %b %Y %H:%M:%S",localtime()) + +def tempr(): + print("RSXS Sample Temperature: {} K".format(caget("29idd:LS331:TC1:SampleA"))) + +def temps(tempset): + print("Initial Sample Temperature:",caget("29idd:LS331:TC1:SampleA")," K",dateandtime()) + caput("29idd:LS331:TC1:wr_SP",1.0*tempset) + stop_var=0 + b=0 + sleep(10) + while b == 0: + delta=abs(caget("29idd:LS331:TC1:SampleA")-1.0*tempset) + if abs(delta) < 1: + c=0 + while c < 10: + sleep(1) + delta=delta+(caget("29idd:LS331:TC1:SampleA")-1.0*tempset) + c=c+1 + if abs(delta/10) < 1: + print("Stable Sample Temperature:",caget("29idd:LS331:TC1:SampleA")," K",dateandtime()) + b=1 + else: + temp1=caget("29idd:LS331:TC1:SampleA") + sleep(10) + temp2=caget("29idd:LS331:TC1:SampleA") + if abs(temp1-temp2) < 0.1: + sleep(30) + temp2=caget("29idd:LS331:TC1:SampleA") + if abs(temp1-temp2) < .5: + print("UNABLE TO STABLIZE TEMPERATURE! Stopped at T=:",caget("29idd:LS331:TC1:SampleA")," K",dateandtime()) + b=1 + + diff --git a/build/lib/iexcode/instruments/scalers.py b/build/lib/iexcode/instruments/scalers.py new file mode 100644 index 0000000000000000000000000000000000000000..89be3dbabd0b813aa88d6e5088354e5aa049ee33 --- /dev/null +++ b/build/lib/iexcode/instruments/scalers.py @@ -0,0 +1,31 @@ +from math import floor + +from epics import caput,PV + +from iexcode.instruments.IEX_endstations import BL + +def scaler_cts(time_seconds=0.1,verbose=True): + """ + sets the scalers counting for the endstation defined in BL + """ + if BL.ioc == 'Kappa': + Kappa_scaler(time_seconds,verbose=verbose) + + +def Kappa_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="29idMZ0:scaler1.TP" + mpa_NumFilter = '29iddMPA:Proc1:NumFilter' + + caput(pv,time_seconds) + + pv=PV(mpa_NumFilter) + if pv.connected(): + caput(mpa_NumFilter,floor(time_seconds)) + + if verbose: + print("Integration time set to:", str(time_seconds)) + diff --git a/build/lib/iexcode/instruments/scanRecord.py b/build/lib/iexcode/instruments/scanRecord.py new file mode 100644 index 0000000000000000000000000000000000000000..2e01a97a40feb0cabc45a2affce438fa7ef800d9 --- /dev/null +++ b/build/lib/iexcode/instruments/scanRecord.py @@ -0,0 +1,688 @@ + +from os.path import join +import time + +from epics import caget, caput, PV + +from iexcode.instruments.utilities import dateandtime, print_warning_message +from iexcode.instruments.logfile import log_update +from iexcode.instruments.userCalcs import userStringSeq_pvs,userStringSeq_clear + + +def saveData_get_all(ioc_pv): + """ + returns saveData info: + """ + saveData_info = { + 'fileSystem':caget(ioc_pv+":saveData_fileSystem",as_string=True), + 'subDir':caget(ioc_pv+":saveData_subDir",as_string=True), + 'scanNumber':caget(ioc_pv+":saveData_scanNumber"), + 'baseName':caget(ioc_pv+":saveData_baseName",as_string=True), + } + + filepath = join(saveData_info['fileSystem'],saveData_info['subDir']) + filepath=filepath.replace('//','/') + + +default_positioner_settling_time = 0.05 +default_detector_settling_time = 0.1 + +class ScanRecord: + """ + used for short hand scanning and to get info related to a scanRecord + """ + + def __init__(self,scan_ioc,detector_dictionary,trigger_dictionary,before_scan_pv,after_scan_pv,**kwargs): + """ + scan_ioc: full pv for the ioc, "29idARPES:", "29idc:" + detector_dictionary: dictionary corresponding to detector num and pv to proc => {det_num:'det_pv'} + trigger_dictionary: dictionary corresponding to trigger num and trigger pv => {trigger_num:'trigger_pv'} + before_scan_pv: pv to be proc'ed be for the start of a scan + after_scan_pv: pv to be proc'ed be for the start of a scan + + **kwargs + reset: resets the scanRecord (True / False) => default = True + + """ + kwargs.setdefault('reset',True) + self.ioc = scan_ioc + + if kwargs['reset']: + self.reset_all(detector_dictionary,trigger_dictionary,before_scan_pv,after_scan_pv) + + pass + +############################################################################################################## +################################ MDA (ScanRecord) files and folders ############################## +############################################################################################################## + + def fileNum(self): + """ + returns the current fileNum in the SaveData of ioc is scanning + or next if idle + + """ + + return saveData_get_all(self.ioc)['scanNumber'] + + def lastFileNum(self): + """ + returns the last saved fileNum in the SaveData of ioc + + previously: MDA_GetLastFileNum + """ + + fileNum = self.fileNum(self) + return fileNum - 1 + + + def filepath(self): + """ + returns the full filepath for the SaveData of ioc + + previously: MDA_CurrentDirectory + """ + return saveData_get_all(self.ioc)['filepath'] + + def prefix(self): + """ + returns the prefix for the SaveData of ioc + + previously: MDA_CurrentPrefix + """ + return saveData_get_all(self.ioc)['baseName'] + + def scanRecord_run(self): + """ + returns the current run by parsing the filepath in the SaveData for ioc + + previously: MDA_CurrentRun + """ + filepath = self.filepath() + m=filepath.find('data_29id')+len('data_29id')+2 + current_run=filepath[m:m+6] + return current_run + + def scanRecord_user(self): + """ + returns the current user by parsing the filepath in the SaveData for ioc + + previously: MDA_CurrentUser + """ + subdir=caget(self.ioc+":saveData_subDir",as_string=True) + m=subdir.find('/mda') + if m == 0 : + current_user='Staff' + elif m > 0: + current_user=subdir[1:m] + else: + current_user="" + print_warning_message("mda_user is empty string") + return current_user + + +############################################################################################################## +############################# filling in the scan record ############################## +############################################################################################################## + + + ### before and after scans + def _before_after_scan(self,**kwargs): + """ + Fills in the before and after user sequences into the scan record + **kwargs + before_scan_pv => '' + after_scan_pv => self.default_after_scan_seq() + """ + kwargs.setdefault('scan_dim',1) + kwargs.setdefault('before_scan_pv','') + kwargs.setdefault('after_scan_pv',self._default_after_scan_seq()) + + scan_pv = self.ioc+"scan"+str(kwargs['scan_dim']) + + #Clearing all Before/Afters in all dims + for dim in [1,2,3,4]: + caput(self.ioc+"scan"+str(dim)+".BSPV","") + caput(self.ioc+"scan"+str(dim)+".ASPV","") + + caput(scan_pv+".BSPV",kwargs['before_scan_pv']) + caput(scan_pv+".BSCD",1) + caput(scan_pv+".BSWAIT","Wait") + + caput(scan_pv+".ASPV",kwargs['after_scan_pv']) + caput(scan_pv+".ASCD",1) + caput(scan_pv+".ASWAIT","Wait") + + def default_after_scan_seq(self,**kwargs): + """ + writes the user string sequence to happen at the end of a scan + returns after_scan_pv = pv for userStringSeq for after scan + + uses links 1-4, link 10 is reserved for snake scans + + **kwargs + seq_num: userStringSeq number in ioc => 10 (default) + positioner_settling_time + detector_settling_time + + + Previously: AfterScan_StrSeq + """ + kwargs.setdefault(seq_num,10) + kwargs.setdefault('positioner_settling_time',default_positioner_settling_time) + kwargs.setdefault('detector_settling_time',default_detector_settling_time) + + scan_dim = 1 + scan_pv = self.ioc+"scan"+str(scan_dim) + + seq_num=kwargs['seq_num'] + after_scan_pv = userStringSeq_pvs(self.ioc, seq_num) + + #clear and write the after scan user sequence + userStringSeq_clear(self.ioc,seq_num) + caput(after_scan_pv+".DESC","After Scan") + + #link 1 - clears positioners + caput(after_scan_pv+".LNK1",scan_pv+'.P1AR'+" PP NMS") + caput(after_scan_pv+".DO1","Clear pos&rdbk PV's, etc") + + #link 2 - sets positioner mode to to abosolute + caput(after_scan_pv+".LNK2",scan_pv+'.CMND'+" PP NMS") + caput(after_scan_pv+".DO2","ABSOLUTE") + + #link 3 - sets positioner delay time to default + settling_time = kwargs['positioner_settling_time'] + caput(after_scan_pv+".LNK3",scan_pv+'.PDLY'+" PP NMS") + caput(after_scan_pv+".DO3",settling_time) + + #link 4 - sets detector delay time to default + settling_time = kwargs['detector_settling_time'] + caput(after_scan_pv+".LNK4",scan_pv+'.DDLY'+" PP NMS") + caput(after_scan_pv+".DO4",settling_time) + + return after_scan_pv + + ### Resetting: + def reset_scan_dim(self,scan_dim,detector_dictionary,trigger_dictionary,before_scan_pv,after_scan_pv): + """ + Resets all the scanRecords (scanDIM=1,2,3,4) for a given IOC + uses Reset_Scan() + **kwargs + scaler='y', only for Kappa ioc + + Previously: Reset_ScanAll + """ + self.detectors_clear(scan_dim) + self.triggers_clear(scan_dim) + self.positioners_clear(scan_dim) + + self.detectors_set(scan_dim,detector_dictionary) + self.triggers_set(scan_dim,trigger_dictionary) + self.before_after_sequences_set(scan_dim,before_scan_pv,after_scan_pv) + + self.detector_settling_time(scan_dim) + self.positioner_settling_time(scan_dim) + + def reset_all(self,detector_dictionary,trigger_dictionary,before_scan_pv,after_scan_pv): + """ + Resets all the scanRecords (scanDIM=1,2,3,4) for a given IOC + uses Reset_Scan() + **kwargs + scaler='y', only for Kappa ioc + + Previously: Reset_ScanAll + """ + + for scan_dim in range(4,1): + self.reset_scan_dim(scan_dim,{},{},'','') + self.reset_scan_dim(1,detector_dictionary,trigger_dictionary,before_scan_pv,after_scan_pv) + + ### default setting + def settings_defaults(self,scan_dim,verbose=True,**kwargs): + """ + Reset scan settings to default: ABSOLUTE, STAY, 0.05/0.1 positioner/detector settling time + + Previous: Reset_Scan + """ + scan_pv = self.ioc+"scan"+str(scan_dim) + + self.positioner_absolute_mode(absolute=True,**kwargs) # Absolute position + self.positioner_after_scan(after="PRIOR POS",**kwargs) # After scan: prior position + self.positioner_settling_time(**kwargs)# Positioner Settling time => default + self.detector_settling_time(**kwargs)# Detector Settling time => default + self.triggers_reset(verbose=False,**kwargs) + + if verbose: + print("Scan record "+self.ioc+" reset to default settings.") + + ### positioners + def positioners_clear(self,scan_dim,verbose=True): + """ + Clear all extra scan positioners + + Previously: Clear_Scan_Positioners + """ + scan_pv = self.ioc+"scan"+str(scan_dim) + caput(scan_pv+".CMND",3) # Clear all Positionners + + if verbose: + print("\nAll extra positionners cleared") + + def positioner_settling_time(self,**kwargs): + """ + sets the positioner settling time + """ + kwargs.setdefault('scan_dim',1) + kwargs.setdefault('positioner_settling_time',self.default_positioner_settling_time()) + + scan_pv = self.ioc+"scan"+str(kwargs['scan_dim']) + + caput(scan_pv+".PDLY",kwargs['positioner_settling_time']) # Positioner Settling time + return scan_pv+".PDLY",kwargs['positioner_settling_time'] + + def positioner_after_scan(self,after="PRIOR POS",**kwargs): + """ + sets the positioner after scan + after = "PRIOR POS" + "STAY" + + """ + kwargs.setdefault('scan_dim',1) + scan_pv = self.ioc+"scan"+str(kwargs['scan_dim']) + caput(scan_pv+".PASM",after) + + def positioner_absolute_mode(self,absolute=True,**kwargs): + """ + absolute = True + = False => relative + + """ + kwargs.setdefault('scan_dim',1) + + scan_pv = self.ioc+"scan"+str(kwargs['scan_dim']) + if absolute: + ab_state = 0 + else: + ab_state = 1 + + caput(scan_pv+".P1AR",ab_state) # Absolute position + + def fillin(self,val_pv,rbv_pv,start,stop,steps_points,**kwargs): + """ + Fills in the scanRecord for the positionner + dim: scan dim + val_pv: drive pv + rbv_pv: readback pv + start: first point + stop: last point + step: step size (only used for positioner_num = 1, otherwise ignored) + kwargs: + num_points: False (default) => steps_points is the step size + True => steps_points is the number of points + positioner_num: default => 1 + positioner_settling_time: default => 0.1 + detector_settling_time: default => 0.1 + + Previously: Scan_FillIn + """ + kwargs.setdefault('scan_dim',1) + kwargs.setdefault("positioner_num",1) + kwargs.setdefault('detector_settling_time',default_detector_settling_time) + kwargs.setdefault('positioner_settling_time',default_positioner_settling_time) + + scan_dim = kwargs['scan_dim'] + self.progress(scan_dim) + + scan_pv = self.ioc+"scan"+str(scan_dim) + posNum = kwargs['positioner_num'] + + caput(scan_pv+".P"+str(posNum)+"PV",val_pv) + caput(scan_pv+".R"+str(posNum)+"PV",rbv_pv) + caput(scan_pv+".P"+str(posNum)+"SP",start*1.0) + caput(scan_pv+".P"+str(posNum)+"EP",stop*1.0) + if kwargs['positioner_num'] == 1: + if kwargs['num_points'] : + caput(scan_pv+".NPTS",steps_points) + else: + caput(scan_pv+".P1SI",steps_points*1.0) + + self.detector_settling_time(scan_dim,kwargs['detector_settling_time']) + self.positioner_settling_time(scan_dim,kwargs['positioner_settling_time']) + + #checking that PVs and positioner limits are good + self._check(scan_dim) + + + ### detectors and detector settling time + def detectors_clear(self,scan_dim,verbose=True): + """ + Clear all scan detectors + + Previously: Clear_Scan_Detectors + """ + scan_pv = self.ioc+"scan"+str(scan_dim) + for i in range(1,10): + caput(scan_pv+".D0"+str(i)+"PV","") + for i in range(10,71): + caput(scan_pv+".D"+str(i)+"PV","") + if verbose: + print("\nAll detectors cleared") + + def detectors_set(self,scan_dim,detector_dictionary): + """ + sets the detectors + detector_dictionary = {detNum:pv} + """ + scan_pv = self.ioc+"scan"+str(scan_dim) + for det_num in detector_dictionary.keys(): + det_pv=caget(scan_pv+".D"+det_num+"PV") + caput(det_pv,detector_dictionary[det_num]) + + def detector_settling_time(self,**kwargs): + """ + set the detector settling time + """ + kwargs.setdefault('scan_dim',1) + kwargs.setdefault('detector_settling_time',self.default_detector_settling_time()) + + scan_pv = self.ioc+"scan"+str(kwargs['scan_dim']) + + caput(scan_pv+".DDLY",kwargs['detector_settling_time']) + return scan_pv+".DDLY",kwargs['detector_settling_time'] + + ### triggers + def triggers_set(self,scan_dim,trigger_dictionary): + """ + Clear all scan detectors triggers + + trigger_dictionary = {trigger_num:pv} + Previously: Clear_Scan_Triggers + """ + scan_pv = self.ioc+"scan"+str(scan_dim) + if len(trigger_dictionary.keys())>0: + for tigger_num in trigger_dictionary.keys(): + caput(scan_pv+".T"+str(tigger_num)+"PV",trigger_dictionary[tigger_num]) + + def triggers_clear(self,scan_dim,trigger_dictionary,verbose=True): + """ + Clear all scan detectors triggers + + Previously: Clear_Scan_Triggers + """ + scan_pv = self.ioc+"scan"+str(scan_dim) + inner_scan_trigger = self.ioc+"scan"+str(scan_dim-1)+".EXSC" + + if len(trigger_dictionary.keys())>0: + for dim in range(1,5): + if dim==1 and scan_dim>1: + caput(scan_pv+".T1PV",inner_scan_trigger) + else: + caput(scan_pv+'.T'+str(dim)+'PV',"") + + def triggers_reset(self,verbose=True,**kwargs): + """ + sets the trigger1 to be the lower dim execute, does not change the other triggers + does nothing if scan_dim = 1 + """ + kwargs.setdefault('scan_dim',1) + scan_pv = self.ioc+"scan"+str(kwargs['scan_dim']) + + inner_scan_trigger = self.ioc+"scan"+str(kwargs['scan_dim']-1)+".EXSC" + if kwargs['scan_dim'] > 1: + caput(scan_pv+".T1PV",inner_scan_trigger) #Resets the higher dimensional scans to trigger the inner scan + + if verbose: + print("Scan record "+self.ioc+"Trigger 1 is reset") + + + ### checks + def check(self,scan_dim): + """ + checks pvs connects and that positioners are within limits + """ + self._check_pvs(scan_dim) + if not self._check_limits(scan_dim): + print("check positioner limits") + + def _check_pvs(self,scan_dim): + """ + Check if any of the detectors or positions pvs are not connected + + Previously: Scan_Check + """ + print('Checking if all detectors & positioners are connected...') + scan_pv = self.ioc+"scan"+str(scan_dim) + + #Detectors + for i in range(1,71): + det_num=(str(i).zfill(2)) + det_pv=caget(scan_pv+".D"+det_num+"PV") + if det_pv !='': + det=PV(det_pv); time.sleep(0.1)#smallest sleep to allow for PV traffic + if not det.connected: + print("Detector "+det_num+" has a bad PV: "+det.pvname+" not connected") + #Positioners + for i in range(1,5): + pos_num=str(i) + pos_pv=caget(scan_pv+".P"+pos_num+"PV") + if pos_pv != '': + pos=PV(pos_pv) + if not pos.connected: + print("Positioner "+pos_num+" has a BAD PV: "+pos.pvname+" not connected") + + def _check_limits(self,scan_dim): + """ + checks if the scan parameters are within the limits + returns limits_ok (True / False) + """ + scan_pv = self.ioc+"scan"+str(scan_dim) + caput(scan_pv+'.CMND',1) + time.sleep(.5) + SMSG = caget(scan_pv+'SMSG',as_string=True) + if len(SMSG) > 0: + print_warning_message('Positioner out of limits \n '+SMSG) + limits_ok = False + else: + limits_ok = True + + + ############################################################################################################## + ############################# table scans ############################## + ############################################################################################################## + def fillin_table(self,scan_dim,val_pv,rbv_pv,myarray,**kwargs): + """ + Fills in the scan record for table scans given positioner=posNum + myarray can be generated by myarray=Scan_MakeTable(StartStopStepLists) + + kwargs: + positioner_num: default => 1 + detector_settling_time: + positioner_settling_time + + Previously: Scan_FillIn_Table + """ + kwargs.setdefault("positioner_num",1) + kwargs.setdefault('detector_settling_time',default_detector_settling_time) + kwargs.setdefault('positioner_settling_time',default_positioner_settling_time) + + self.progress(scan_dim) + + scan_pv = self.ioc+"scan"+str(scan_dim) + posNum = kwargs['positioner_num'] + + caput(scan_pv+".P"+str(posNum)+"SM","TABLE") + caput(scan_pv+".P"+str(posNum)+"PV",val_pv) #Drive + caput(scan_pv+".R"+str(posNum)+"PV",rbv_pv) #Read + caput(scan_pv+".P"+str(posNum)+"PA",myarray) + caput(scan_pv+'.NPTS',len(myarray)) + + self.detector_settling_time(scan_dim,kwargs['detector_settling_time']) + self.positioner_settling_time(scan_dim,kwargs['positioner_settling_time']) + + #checking that PVs and positioner limits are good + self.check(scan_dim) + + def table_reset_after(self,scan_dim): + """ + resets positioner settling time 0.1 + sets all positionitonser to linear + clears positioners + + Previously: Scan_Reset_AfterTable + """ + #Setting everything back + scan_pv = self.ioc+"scan"+str(scan_dim) + + self.detector_settling_time(self.ioc,scan_dim) + + for i in range(1,5): + caput(scan_pv+".P"+str(i)+"SM","LINEAR") + + self.positioners_clear(self.ioc,scan_dim) + + ############################################################################################################## + ############################# progress, go and abort ############################## + ############################################################################################################## + def progress(self,scan_dim,verbose=True): + """ + Checks if a scan is in progress, and sleeps until it is done + + pv now includes the full 29idARPES: + Previously: Scan_Progress + """ + pv = self.ioc+"scan"+str(scan_dim) + check=caget(pv+".FAZE") + while (check!=0): + if verbose: + print(pv+" in progress - please wait...") + time.sleep(30) + check=caget(pv+".FAZE") + + def abort(self): + """ + aborts a scan for the command line + + Previously: Scan_Abort + """ + caput(self.ioc+"AbortScans.PROC",1) + + def go(self,verbose=True,**kwargs): + """ + checks limits and then starts a scan for a given ioc and scan_dim + + Previously: part of Scan_Go + """ + kwargs.setdefault('scan_dim',1) + scan_dim = kwargs['scan_dim'] + + self.progress(scan_dim) + + if verbose: + for i in range(1,scan_dim+1): + drive = caget(self.ioc+"scan"+str(i)+".P1PV") + start = caget(self.ioc+"scan"+str(i)+".P1SP") + stop = caget(self.ioc+"scan"+str(i)+".P1EP") + step = caget(self.ioc+"scan"+str(i)+".P1SI") + print('Scan'+str(i)+': '+drive+'= '+str(start)+' / '+str(stop)+' / '+str(step)) + + if self._check_limits(scan_dim): + filename = self.prefix(self.ioc) + fileNum = self.fileNum(self.ioc) + print(filename+str(fileNum)+" started at ", dateandtime()) + scan_pv = self.ioc+"scan"+str(scan_dim) + caput(scan_pv+".EXSC",1,wait=True,timeout=900000) #pushes scan button + log_update() # writes the log file + print(filename+str(fileNum)+" finished at ", dateandtime()) + print('\n') + + + ############################################################################################################## + ############################# empty and time scans ############################## + ############################################################################################################## + + + def empty_scan(self,**kwargs): + """ + starts a scan with out a drive + + Previously: Scan_Empty_Go + """ + kwargs.setdefault('execute',True) + self.fillin("","",0,1,1,**kwargs) + if kwargs['execute']: + self.go(**kwargs) + + def time_scan(self,duration_min,step_sec,**kwargs): + """ + starts a scan with the readback as time in seconds + + **kwargs + trigger_dictionary = {1:'29idb:ca5:read'} (default) + + Previously: Scan_Time_Go + """ + + stop=duration_min*60.0/step_sec + self.fillin("","time",1,stop,1,**kwargs) + + print("Time scan - Settling time : "+str(step_sec)) + if kwargs['execute']: + self.go(**kwargs) + + ############################################################################################################## + ############################# 2D scans typewriter/snake scans ############################## + ############################################################################################################## + def fillin_2D(self,inner_loop_list,outer_loop_list,outer_scan_dim=2,**kwargs): + """ + Fills in a the Scan Record for a 2D scan (Mesh), + InnerMotorList=[val_pv1,rbv_pv1,start1,stop1,step1] #scanDIM=1 + OuterMotorList=[val_pv2,rbv_pv2,start2,stop2,step2] #scanDIM=2 + kwargs: + num_points: False (default) => steps_points is the step size + True => steps_points is the number of points + positioner_num: default => 1 + detector_settling_time: default => 0.1 + snake: coming soon + """ + kwargs.setdefault("snake",False) + + #fillin inner loop + kwargs.update({'scan_dim':outer_scan_dim-1}) + self.fillin(inner_loop_list[0],inner_loop_list[1],inner_loop_list[2],inner_loop_list[3],inner_loop_list[4],**kwargs) + #fillin outer loop + kwargs.update({'scan_dim':outer_scan_dim}) + self.fillin(outer_loop_list[0],outer_loop_list[1],outer_loop_list[2],outer_loop_list[3],outer_loop_list[1],**kwargs) + + + + def snake_pv(self,snake_dim,enable=True): + """ + used for snake scans (as opposed to typewriter scans) + """ + snake_proc = self.snake_scan_userCalcOut(self.ioc,snake_dim=snake_dim,calc_num=1,enable=enable) + return snake_proc + + + def snake_scan_userCalcOut(self,snake_dim=1,calc_num=1,enable=False): + """ + for snake scans you need to add this userCalcOut to the after scan + it multiplies the step of the inner scan by -1 + + return the userCalcOut.PROC pv + """ + snake_calc_pv = self.ioc+"userCalcOut"+str(calc_num) #Snake userCalc + caput(self.ioc+"userCalcOutEnable.VAL",1) #global enable for userCalcs + + step_pv = self.ioc+"scan"+str(snake_dim)+".P1SI" + ### Setting up the user + caput(snake_calc_pv+".DESC","Snake Calc") + caput(snake_calc_pv+".INPA",step_pv+" NPP NMS") + caput(snake_calc_pv+".CALC$","A*-1*B") + caput(snake_calc_pv+".OUT",step_pv+" PP NMS") + + if enable: + caput(snake_calc_pv+".B",1) + else: + caput(snake_calc_pv+".B",0) + + return snake_calc_pv+".PROC" \ No newline at end of file diff --git a/build/lib/iexcode/instruments/scratch.py b/build/lib/iexcode/instruments/scratch.py new file mode 100644 index 0000000000000000000000000000000000000000..ded5e799532a9f085e7e81f233ff0d2a7e4267a8 --- /dev/null +++ b/build/lib/iexcode/instruments/scratch.py @@ -0,0 +1,44 @@ +############################################################################################################## +############################## setting folder from ARPES ############################## +############################################################################################################## +def folders_ARPES(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',True) + 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,BL.folder,user_name,BL.ioc,kwargs['ftp']) + + # Create User Folder: + make_user_folders(run,BL.folder,user_name,BL.endstation,ftp=kwargs['ftp']) + sleep(5) + + if kwargs["set_folders"]: + # Set up MDA folder: + folder_mda(run,BL.folder,user_name,BL.prefix,BL.ioc) + logfile_name_set(BL.endstation) + logfile_header(BL.endstation,BL.ioc,ARPES_log_header()) + + + #Set up Scienta folders: + try: + userPath = "/net/s29data/export/data_29id"+BL.folder+"/"+run+"/"+user_name+"/" + folders_EA(userPath,filePrefix="EA") + except: + print_warning_message("EA ioc is not running, cannot set folder") \ No newline at end of file diff --git a/build/lib/iexcode/instruments/shutters.py b/build/lib/iexcode/instruments/shutters.py new file mode 100644 index 0000000000000000000000000000000000000000..2afd8422a141b6b3b7b8467d8a6ef7b50ecc94e7 --- /dev/null +++ b/build/lib/iexcode/instruments/shutters.py @@ -0,0 +1,112 @@ +""" +main shutter and branch shutter functions +""" +from time import sleep +from epics import caget, caput + +from iexcode.instruments.utilities import dateandtime, print_warning_message + + +############################################################################################################## +################################ main shutter ############################## +############################################################################################################## + +def main_shutter_open(): + """ + opens the main shutter + + Previously: Open_MainShutter + """ + caput("PC:29ID:FES_OPEN_REQUEST.VAL",1, wait=True,timeout=180000) + print("Opening Main Shutter...") + +def main_shutter_close(): + """ + closes the main shutter + + Previously: Close_MainShutter + """ + caput("PC:29ID:FES_CLOSE_REQUEST.VAL",1,wait=True,timeout=18000) + print("Closing Main Shutter...") + +def main_shutter_status(): + """ + checks on the status of the main shutter + and returns shutter_open = True / False + + """ + SS1=caget("EPS:29:ID:SS1:POSITION") + SS2=caget("EPS:29:ID:SS2:POSITION") + PS2=caget("EPS:29:ID:PS2:POSITION") + check=SS1*SS2*PS2 + + if check == 8: + shutter_open = True + else: + shutter_open = False + + return shutter_open + + +def main_shutter_check_open(): + """ + Checks main shutter is open, if not opens it" + + Previously: Check_MainShutter + """ + while True: + shutter_open = main_shutter_status() + if shutter_open == False: + print("MAIN SHUTTER CLOSED !!!" , dateandtime()) + main_shutter_open() + sleep(10) + else: + print("Shutter is now open" , dateandtime()) + break +############################################################################################################## +################################ branch shutters ############################## +############################################################################################################## + +def branch_shutter_status(branch,verbose=False): + """ + checks on the status of the main shutter + and returns shutter_open = True / False + """ + pvA="PA:29ID:S"+branch+"S_BLOCKING_BEAM.VAL" + pvB="PB:29ID:S"+branch+"S_BLOCKING_BEAM.VAL" + #"ON" = 1 => shutter open + status=caget(pvA)+caget(pvA) + if status == 2: + shutter_open=True + else: + shutter_open=False + + if verbose: + status = 'Open' if shutter_open else 'Closed' + print(branch+"-shutter is "+status) + return shutter_open + +def branch_shutter_close(branch): + """ + closes current branch shutter + + Previously: Close_BranchShutter + """ + caput("PC:29ID:S"+branch+"S_CLOSE_REQUEST.VAL",1,wait=True,timeout=18000) + print("Closing "+branch+"-Shutter...") + + +def branch_shutter_open(branch): + """ + Opens current branch shutter + + Previoulsy: Open_BranchShutter + + """ + shutter_status = branch_shutter_status + if shutter_status: + print(branch+"-Shutter already open...") + else: + caput("PC:29ID:S"+branch+"S_OPEN_REQUEST.VAL",1,wait=True,timeout=18000) + print("Opening "+branch+"-Shutter...") + \ No newline at end of file diff --git a/build/lib/iexcode/instruments/slits.py b/build/lib/iexcode/instruments/slits.py new file mode 100644 index 0000000000000000000000000000000000000000..1b323e3ead9d82e35929bd013f277f8cfc7b3bd3 --- /dev/null +++ b/build/lib/iexcode/instruments/slits.py @@ -0,0 +1,509 @@ +from numpy import inf,nan + +from epics import caget, caput +from .IEX_endstations import * + + +from iexcode.instruments.shutters import main_shutter_close +from iexcode.instruments.utilities import print_warning_message, read_dict +from iexcode.instruments.VLS_PGM import mono_get_all +from iexcode.instruments.encoders import encoders_reset + +slit_ioc="29idb:" + +def slits_dictionary(): + """ + dictionary of slit pv names for two and four blade slit assemblies + + slit_name = slit1A, slit2B, slit3D + """ + #'slit3C' : (None, "uses a flexure stage so is different"), + + d = { + 'slit1A' : ('Slit1H','Slit1V'), + 'slit2B' : ('Slit2H','Slit2V'), + 'slit3D' : ('Slit4V') + } + return d + +def slits_pvs(slit_name): + """ + returns the rbv and drive for the size,center + (rbv_size,val_size),(rvb_center,val_center) + """ + slit_pv = slit_ioc + slit_name + size_rbv = slit_pv +'t2.D' + size_val = slit_pv +'center.VAL' + center_rbv = slit_pv +'t2.C' + center_val = slit_pv +'center.VAL' + + return (size_rbv,size_val),(center_rbv,center_val) + +def slits_synch(slit_name): + """ + synch the motor position and the slit table for all the beamline slits + """ + slit_pv = slit_ioc + slit_name+'sync.PROC' + caput(slit_pv,1) + +def slits_sync_all(): + """ + synch the motor position and the slit table for all the beamline slits + Slit-1A, slit-2B, slit-3C, slit-3D + + Previously: SyncAllSlits + """ + slit_list = slits_dictionary() + for slit_name in slit_list.keys(): + slits_synch(slit_name) + +def slits_print_all(): + """ + gets the current position of slit-1A, slit-2B, slit-3C, slit-3D + + Previously Get_Slits + """ + slits_sync_all() + slit1A_get(verbose=True) + slit2B_get(verbose=True) + + slit3C_get(verbose=True) + slit3D_get(verbose=True) + +def slits_get_all(verbose=False): + """ + returns a dictionary with the current slit status + """ + vals = {} + vals['slit1A_size'], vals['slit1A_center'] = slit1A_get(verbose=False) + vals['slit2B_size'], vals['slit2B_center'] = slit2B_get(verbose=False) + vals['slit3C_size'] = slit3C_get(verbose=False) + vals['slit3D_size'],vals['slit3D_center'] = slit3D_get(verbose=False) + + if verbose: + slits_print_all() + return vals + +def slits_set(slit_name,size,center,verbose=True): + """ + synchs the slit motors and the slit table and then sets the center and size + + slit_name is key in slits_dictionary + size = (H_size, V_size) + center = (H_center, V_center) + + Previously: SetSlit + """ + d = slits_dictionary() + #syncing + slits_synch(slit_name) + + for i,slit_HV in enumerate(d[slit_name]): #H and V + (size_rbv,size_val),(center_rbv,center_val) = slits_pvs(slit_HV) + caput(size_val, size[i],timeout=180) + caput(center_val, center[i],timeout=180) + + if verbose: + if (d[slit_name])>1: + print(slit_name + " = ("+str(round(size[0],3))+"x"+str(round(size[1],3))+") @ ("+str(center[0])+","+str(center[1])+")") + else: + print(slit_name + " = ("+str(round(size[0],3))+") @ ("+str(center[0])+")") + + return size,center + + +def slits_get(slit_name,verbose=True): + """ + returns the current H_size,V_size,H_center,V_center + + """ + d=slits_dictionary() + size = [] + center = [] + + #syncing + slits_synch(slit_name) + + for slit_HV in d[slit_name]: #H and V + (size_rbv,size_val),(center_rbv,center_val) = slits_pvs(slit_HV) + size.append(caget(size_rbv)) + center.append(caget(center_rbv)) + + if verbose: + if (d[slit_name])>1: + print(slit_name + " = ("+str(round(size[0],3))+"x"+str(round(size[1],3))+") @ ("+str(center[0])+","+str(center[1])+")") + else: + print(slit_name + " = ("+str(round(size[0],3))+") @ ("+str(center[0])+")") + + return tuple(size),tuple(center) + +def slits_set_size(slit_name,size): + """ + sets the slit size with the current slit center + + size = (H,V) for slit1A, slit2B + size = V for slit3D + """ + size_current,center = slits_get(slit_name,verbose=False) + slits_set(size,center) + +def slits_set_center(slit_name,center): + """ + sets the slit size with the current slit center + + center = (H,V) for slit1A, slit2B + center = V for slit3D + """ + size,center_current = slits_get(slit_name,verbose=False) + slits_set(size,center) + +def slits_scan_size(slit_name,direction,start,stop,step,**kwargs): + """ + slit_name = 'slit1A','slit2B','slit3D' + direction = 'H', 'V' + **kwargs + center: slits center, if not specified then uses current center position + """ + kwargs.setdefault('center',slits_get(slit_name,verbose=False)[1]) + kwargs.setdefault('execute',True) + + slit_H,slit_V = slits_dictionary()[slit_name] + + if direction == 'H': + (size_rbv,size_val),(center_rbv,center_val) = slits_pvs(slit_H) + if direction == 'V': + (size_rbv,size_val),(center_rbv,center_val) = slits_pvs(slit_V) + + #set slit center + slits_set_center(slit_name,kwargs['center']) + #scan + BL.mda.fillin(size_rbv,size_val,start,stop,step,**kwargs) + if kwargs['execute']: + BL.mda.go(**kwargs) + +def slits_scan_center(slit_name,direction,start,stop,step,**kwargs): + """ + slit_name = 'slit1A','slit2B','slit3D' + direction = 'H', 'V' + **kwargs + size: slits size, if not specified then uses current size + """ + kwargs.setdefault('size',slits_get(slit_name,verbose=False)[0]) + kwargs.setdefault('execute',True) + + slit_H,slit_V = slits_dictionary()[slit_name] + + if direction == 'H': + (size_rbv,size_val),(center_rbv,center_val) = slits_pvs(slit_H) + if direction == 'V': + (size_rbv,size_val),(center_rbv,center_val) = slits_pvs(slit_V) + + #set slit center + slits_set_size(slit_name,kwargs['size']) + #scan + BL.mda.fillin(center_rbv,center_val,start,stop,step,**kwargs) + if kwargs['execute']: + BL.mda.go(**kwargs) + +def slit1A_scribe_marks(): + """ + moves slit1A to the position which corresponds to the scribe marks + used to check if we have lost steps + + Dial values should be 0 on when on the scribe marks + User values are set to correspond to the center of the beam + + Previously: GoToSlit1AScribe + """ + main_shutter_close() + for m in range(9,13): + caput('29idb:m'+str(m)+'.DVAL',0) + +def slit1A_set(H_size,V_size,verbose=True,**kwargs): + """ + sets the first aperture / slit to the specificed size + if Hsize / Vsize = inf then goes to maximim 4.5 / 4.5 + **kwargs + center = slit center, by default => (0,0) + + Previously: SetSlit1A + """ + kwargs.setdefault('center',(0,0)) + slit_name = 'slit1A' + + if H_size in [inf,nan,None]: + H_size=4.5 + if V_size in [inf,nan,None]: + V_size=4.5 + + size = (H_size,V_size) + center = kwargs['center'] + slits_set(slit_name,size,center, verbose=verbose) + +def slit1A_get(verbose=True): + """ + returns the current (H_size,V_size),(H_center,V_center) + """ + slit_name = "slit1A" + + return slits_get(slit_name,verbose=verbose) + +def slit2B_set(H_size,V_size,verbose=True,**kwargs): + """ + sets the clean up aperture / slit downstream of the mono to the specificed size + if Hsize / Vsize = inf then goes to maximim 6 / 8 + + **kwargs + center = slit center, by default => (0,0) + + Previously: SetSlit2B + """ + kwargs.setdefault('center',(0,0)) + slit_name = "slit2B" + + if H_size in [inf,nan,None]: + H_size=6 + if V_size in [inf,nan,None]: + V_size=8 + + size = (H_size,V_size) + center = kwargs['center'] + slits_set(slit_name,size,center, verbose=verbose) + +def slit2B_set_small(Hsize,Vsize,coef,verbose=True,**kwargs): + """ + Used to scale the aperature size by coef + Hsize = Hsize * coef + Vsize = Vsize * coef + """ + Hsize = Hsize * coef + Vsize = Vsize * coef + print_warning_message("closing Slit-2B down by a factor of", coef, "!!!") + slit2B_set(Hsize,Vsize,verbose=True,**kwargs) + +def slit2B_get(verbose=True): + """ + returns the current (H_size,V_size),(H_center,V_center) + """ + slit_name = "slit2B" + return slits_get(slit_name,verbose=verbose) + +def slit2B_encoders_reset(Hcenter,Vcenter): + """ + Resetting Slit 2B encoders to 0 for a given position (Hcenter,Vcenter). + Slit size need to be set to 0. + + Previously: Reset_Slit2B_Encoders + """ + encoders_reset('slit2B',Hcenter,Vcenter) + slits_synch('slit2B') + + +def slit3C_set(size,verbose=True): + """ + sets slit-3C (ARPES resolution defining slit) + + Previously SetSlit3C + """ + position=round(slit_3C_fit(size),1) + caput("29idb:Slit3CFit.A",size,wait=True,timeout=18000) + + if verbose: + print("Slit-3C =",size,"um - ( m24 =",position,")") + +def slit3C_get(size,verbose=True): + """ + gets slit-3C (ARPES resolution defining slit) + returns size, position + """ + size, position = slit_3C_rbv() + + if verbose: + print("Slit-3C =",size,"um - ( m24 =",position,")") + + return size, position + +def slit3D_set(V_size,verbose=True,**kwargs): + """ + sets the clean up aperture / slit downstream of the mono to the specificed size + if Hsize / Vsize = inf then goes to maximim 6 / 8 + + **kwargs + center = slit center, by default => current value + + Previously: SetSlit3D + """ + kwargs.setdefault('center',slit3D_get(verbose=False)[1]) + slit_name = "slit3D" + + if V_size in [inf,nan,None]: + V_size=2000 + + size = (V_size) + center = kwargs['center'] + slits_set(slit_name,size,center,verbose=verbose) + + +def slit3D_get(verbose=True): + """ + returns the current V_size,V_center + """ + slit_name = "slit1A" + (V_size),(V_center) = slits_get(slit_name) + V_size = round(V_size,3) + V_center = round(V_center,3) + + return V_size,V_center + +def slit3D_encoders_reset(Hcenter,Vcenter): + """ + Resetting Slit 2B encoders to 0 for a given position (Hcenter,Vcenter). + Slit size need to be set to 0. + + Previously: Reset_Slit2B_Encoders + """ + encoders_reset('slit3D',Hcenter,Vcenter) + slits_synch('slit3D') + +def exit_slit(branch, size, verbose=True): + """ + verbose used to supress printing + + Previously: SetExitSlit + """ + if branch == "c": + slit3C_set(size, verbose) + elif branch == "d": + slit3D_set(size, verbose) + elif branch == "e": + slit3D_set(size, verbose) + + + + + +############################################################################################################## +################################ slit fits ############################## +############################################################################################################## + + +def aperture_fit(hv,slit_num): + """ + used close the beamline apertures/slits to only take the center of the beam, + i.e. no heat bump (determined emperically by looking at the the shift in energy vs slit position) + + Previously Aperture_Fit + """ + K=slit_Coef(slit_num)[1] + sizeH=K[0]+K[1]*hv+K[2]*hv*hv + sizeV=K[3]+K[4]*hv+K[5]*hv*hv + return [round(sizeH,3),round(sizeV,3)] + +def slit_Coef(slit_num): + """ + 3rd order polynomials coeffients for closing slit1A / slit2B to minimize heat bump effects + slit_num = 1 / 2 for slit1A / slit2B + """ + if slit_num == 1: + pv='29id:k_slit1A' + #Redshifted x (H): + H0=2.3325 + H1=-.000936 + H2=2.4e-7 + #Redshifted z (V): + V0=2.3935 + V1=-.0013442 + V2=3.18e-7 + if slit_num == 2: + pv='29id:k_slit2B' + #Redshifted x (H): + H0=3.61 + H1=-0.00186 + H2=5.2e-7 + #Redshifted z (V): + V0=6.8075 + V1=-0.003929 + V2=9.5e-7 + K=H0,H1,H2,V0,V1,V2 + return pv,K + + +def slit_3C_fit(size): + """ + used to convert slit size to motor position for slit 3C - flexure stage + + empirically determine offline with a camera + + Previously: Slit3C_Fit + """ + K0=-36.383 + K1=0.16473 + K2=-0.00070276 + K3=8.4346e-06 + K4=-5.6215e-08 + K5=1.8223e-10 + K6=-2.2635e-13 + motor=K0+K1*size+K2*size**2+K3*size**3+K4*size**4+K5*size**5+K6*size**6 + return motor + +def slit_3C_rbv(): + """ + used to convert slit motor position to size + + Previously: Slit3C_RBV + """ + position=caget("29idb:m24.RBV") + K0=299.66 + K1=16.404 + K2=1.5572 + K3=0.14102 + K4=0.0064767 + K5=0.00014501 + K6=1.2617e-06 + size=round(K0+K1*position+K2*position**2+K3*position**3+K4*position**4+K5*position**5+K6*position**6,0) + return size, position + +############################################################################################################## +################################ beamline slits ############################## +############################################################################################################## + +def slits_set_BL(c_2B=1,c_1A=1,verbose=True): + """ + Sets slit-1A and slit-2B for the current + grating and photon energy to remove the heat bump + + c_1A and c_2B are used to take a different ratio of the beam + (1 = normal ops, < 1 to reduce flux) + + Previously: SetSlit_BL + """ + mono_vals=mono_get_all() + hv_rbv = mono_vals['ENERGY_MON'] + grt = mono_vals['GRT'] + + # slit were defined for the range: 500 - 2000 + hv = max(hv_rbv,500) + hv = min(hv_rbv,2000) + c = 4.2/2.2 # to account for the magnification difference between gratings + + if grt == 'MEG': + V=0.65 # set to 65% of RR calculation for both grt => cf 2016_2_summary + elif grt=='HEG': + V=0.65*c # set to 65% of RR calculation (no longer 80%) => cf 2016_2_summary + + try: + slit_position = read_dict(FileName='Dict_Slit.txt') + except KeyError: + print_warning_message("Unable to read dictionary") + return + + V2_center= slit_position[grt]['S2V'] + H2_center= slit_position[grt]['S2H'] + V1_center= slit_position[grt]['S1V'] + H1_center= slit_position[grt]['S1H'] + + Size1A=( aperture_fit(hv,1)[0]*c_1A, aperture_fit(hv,1)[1]*c_1A ) + Size2B=( aperture_fit(hv,2)[0]*c_2B, round(aperture_fit(hv,2)[1]*c_2B*V,3)) + slit1A_set(Size1A[0],Size1A[1],H1_center,V1_center,verbose) # standard operating + slit1A_set(Size2B[0],Size2B[1],H2_center,V2_center,verbose) + diff --git a/build/lib/iexcode/instruments/spec_stuff.py b/build/lib/iexcode/instruments/spec_stuff.py new file mode 100644 index 0000000000000000000000000000000000000000..61cc85925755a39d9b1fa2395e72d18b22c30cf8 --- /dev/null +++ b/build/lib/iexcode/instruments/spec_stuff.py @@ -0,0 +1,14 @@ + +def folders_spec(run,folder,UserName): + if folder == "b": + UserName = "Staff" + else: + UserName = UserName+"/" + MyPath="/home/beams22/29IDUSER/spec/data/"+run+"/"+UserName + print("\nSPEC folder: " + MyPath) + print("You will need to create folder and set up the path manually in SPEC:") + print(" cd "+MyPath) + print(" newfile FileName") + print("To start SPEC fresh: ./bin/kappa29ID -f") + #if not (exists(MyPath)): + # mkdir(MyPath) diff --git a/build/lib/iexcode/instruments/staff.py b/build/lib/iexcode/instruments/staff.py new file mode 100644 index 0000000000000000000000000000000000000000..b9d6eef6b0732753a2c5c190dd1903e2f2d2652c --- /dev/null +++ b/build/lib/iexcode/instruments/staff.py @@ -0,0 +1,82 @@ +from os import listdir,mkdir,chmod +from os.path import join, isfile, exists + +#from .ARPES import folders_ARPES +#from .Kappa import folders_Kappa + + +def folders_startup(run): + """ + Creates the run directories for the following: + data_29idb + data_29idc + data_29idd + + calls folder_ARPES('Staff');folder_Kappa('Staff') + + print text required to modify the rsynch crontab + + previously: Folders_Startup + """ + data_directories=['data_29idb','data_29idc','data_29idd'] + dserv="/net/s29data/export/" + for dataDir in data_directories: + path=join(dserv,dataDir,run) + print(path) + if not (exists(path)): + mkdir(path) + + #folders_ARPES('Staff',create_only=True) + #folders_Kappa('Staff',create_only=True) + + txt="\n\n\nupdate the rsync portion the 29id@nerdy crontab\n" + txt+="*/1 * * * * /usr/bin/rsync -av --exclude=core /net/s29data/export/data_29idd/"+run+" kip:/net/kip/sftp/pub/29iddftp/files > /home/beams22/29ID/cronfiles/cptoftp-currrun-d.log 2>&1" + txt+=("\n") + txt+="*/1 * * * * /usr/bin/rsync -av --exclude=core /net/s29data/export/data_29idd/"+run+" kip:/net/kip/sftp/pub/29iddftp/files > /home/beams22/29ID/cronfiles/cptoftp-currrun-d.log 2>&1" + print(txt) + +############################################################################################################## +############################## staff detectors ############################## +############################################################################################################## + + +def staff_detector_dictionary(xrays=True): + """ + returns a dictionary of the default detectors + + Previously: Detector_Default + """ + det_dict={} + diodes={ + 15:"29idb:ca15:read" + } + slits_apertures={ + 58:"29idb:Slit1Ht2.C", + 59:"29idb:Slit1Ht2.D", + 60:"29idb:Slit1Vt2.C", + 61:"29idb:Slit1Vt2.D", + 62:"29idb:Slit2Ht2.C", + 63:"29idb:Slit2Ht2.D", + 64:"29idb:Slit2Vt2.C", + 65:"29idb:Slit2Vt2.D", + 66:"29idb:Slit3CRBV", + 67:"29idb:Slit4Vt2.C" + } + vacuum_shutters={ + 61:"29idb:VS1A.VAL", + 62:"29idb:VS2A.VAL", + 63:"29idb:VS3AB.VAL", + 64:"29idb:VS4B.VAL", + 65:"29idb:IP4B.VAL", + 66:"PA:29ID:SCS_BLOCKING_BEAM.VAL", + 67:"PA:29ID:SDS_BLOCKING_BEAM.VAL" + } + mono_details={ + 68:"29idmono:ENERGY_SP", + 69:"29idmonoMIR:P.RBV", + 70:"29idmonoGRT:P.RBV" + } + det_dict.update(diodes) + det_dict.update(slits_apertures) + det_dict.update(mono_details) + return det_dict \ No newline at end of file diff --git a/build/lib/iexcode/instruments/storage_ring.py b/build/lib/iexcode/instruments/storage_ring.py new file mode 100644 index 0000000000000000000000000000000000000000..a2269b8e853b181f4efacb0c0be43d4316c028e8 --- /dev/null +++ b/build/lib/iexcode/instruments/storage_ring.py @@ -0,0 +1,23 @@ + + +""" +Functions dealing with the storage ring pvs + +""" +from epics import caget +from time import sleep + +from iexcode.instruments.utilities import dateandtime + +def wait_for_beam(): + """ + Monitors the storage ring current and breaks when the ring current is above 60 mA + Checks the status every 30 seconds + """ + while True: + SR=caget("S:SRcurrentAI.VAL") + if (SR<80): + sleep(30) + else: + print("Beam is back -"+dateandtime()) + break \ No newline at end of file diff --git a/build/lib/iexcode/instruments/userCalcs.py b/build/lib/iexcode/instruments/userCalcs.py new file mode 100644 index 0000000000000000000000000000000000000000..367ceec1dc83cdd175e6f4547c8021f6d09d117d --- /dev/null +++ b/build/lib/iexcode/instruments/userCalcs.py @@ -0,0 +1,177 @@ +from epics import caget, caput +############################################################################################################## +########################### String Sequences ###################### +############################################################################################################## +def userStringSeq_pvs(ioc, seq_num): + """ + returns the proc pv for a given userStringSeq + userStringSeq, proc_pv + + Previously: BeforeScan_StrSeq, AfterScan_StrSeq + """ + userStringSeq_pv = ioc+"userStringSeq"+str(seq_num) + userStringSeq_proc = userStringSeq_pv+".PROC" + return userStringSeq_pv, userStringSeq_proc + + +def userStringSeq_clear(ioc,seq_num): + """ + clears the nth suserStringSeq in the specified ioc + + Previously: ClearStringSeq + """ + pv=ioc+"userStringSeq"+str(seq_num) + caput(pv+".DESC","") + for i in range(1,10): + caput(pv+".STR"+str(i),"") + caput(pv+".LNK"+str(i),"") + caput(pv+".DOL"+str(i),"") + caput(pv+".DO"+str(i),0.0) + caput(pv+".DLY"+str(i),0.0) + caput(pv+".WAIT"+str(i),"NoWait") + caput(pv+".STRA","") + caput(pv+".LNKA","") + caput(pv+".DOLA","") + caput(pv+".DOA",0.0) + caput(pv+".DLYA",0.0) + caput(pv+".WAITA","NoWait") + caput(pv+".FLNK","") + return pv + +############################################################################################################## +########################### User CalcsOut ###################### +############################################################################################################## +def userCalcOut_clear(ioc,calcOut_num): + """ + clears the nth userCalcOut in the specified ioc + + Previously:ClearCalcOut + """ + pv=ioc+"userCalcOut"+str(calcOut_num) + caput(pv+".DESC","") + + for i in ["A","B","C","D","E","F","G","H","I","J","K","L"]: + caput(pv+".INP"+i,"") + caput(pv+"."+i,0) + + caput(pv+".CALC$","A") + caput(pv+".OCAL$","A") + caput(pv+".OUT","") + caput(pv+".OOPT","On Change") + return pv + + +############################################################################################################## +########################### User Calcs, User Average User Average ###################### +############################################################################################################## +def userAvg_clear(ioc,userAvg_num): + """ + clears the nth userAvg in the specified ioc + + Previously: ClearUserAvg + """ + pv = ioc+"userAve"+str(userAvg_num) + caput(pv+".DESC","") + caput(pv+".INPB","") + return pv + +def userAvg_pvs(ioc, userAve_num): + """ + returns the proc pv for a given userStringSeq + userStringSeq, proc_pv + + """ + userAve_pv = ioc+"userAve"+str(userAve_num) + userAve_proc = userAve_pv+".PROC" + return userAve_pv, userAve_proc + + +def userAvg_trigger_strSeq(ioc,num,userAvg_num=8): + """ + num = number of userAvg + """ + userAvg_num = 8 + userAvg_clear(ioc,userAvg_num) + str_pv="29id"+ioc+":userStringSeq"+str(userAvg_num) + caput(str_pv+".DESC","Average Triggers_"+ioc) + if num < 10: + str_num = str(num) + else: + str_num = "A" + for userAve_num in range(1,userAve_num+1,1): + if userAve_num < 10: + userAve_num = str(userAve_num) + else: + userAve_num = "A" + userAve_pv, userAve_proc = userAvg_pvs(ioc, userAve_num) + caput(str_pv+".LNK"+userAve_num,userAve_proc+" CA NMS") + caput(str_pv+".WAIT"+userAve_num,"After"+str_num) + + +def UserAvg_setup(ioc,userAvg_num,det_num,average_pts,UserAvg_trigger_strSeq_pv,scan_dim=1): + """ + kappa + userAv_num 1->10 + det_num 61 -> 70 + Previously:UserAvg + """ + userAvg_pv = ioc+"userAve"+str(userAvg_num) + scan_pv = ioc+"scan"+str(scan_dim) + det_pv = scan_pv+".D"+str(det_num)+"PV" + + trigger_strSeq_pv,trigger_strSeq_proc = userAvg_trigger_strSeq(ioc) + + if average_pts > 0: + caput(scan_pv+".T2PV",trigger_strSeq_proc) #set all Avg as Det + caput(userAvg_pv+".A",average_pts) + caput(det_pv,userAvg_pv+".VAL") + print("User Average enabled") + elif average_pts == 0: + caput(scan_pv+".T2PV","") + caput(det_pv,"") + print("User Average disabled") + + +def userAvg_setup(ioc,pv,userAvg_num,name,average_pts=10,mode="ONE-SHOT"): + """ + + Previously: UserAvg_PV + """ + trigger_strSeq_pv,trigger_strSeq_proc = userAvg_trigger_strSeq(ioc) + + # Fill User Average: + userAvg_clear(ioc,userAvg_num) + userAve_pv, userAve_proc = userAvg_pvs(ioc, userAvg_num) + + caput(userAve_pv+".SCAN","Passive") + caput(userAve_pv+".INPB",trigger_strSeq_pv+" CP NMS") + caput(userAve_pv+".A",average_pts) + caput(userAve_pv+".PREC",9) + caput(userAve_pv+"_mode.VAL",mode) + caput(userAve_pv+"_algorithm.VAL","AVERAGE") + caput(userAve_pv+".DESC",name) + + +def userAvg_trigger_strSeq(ioc,num, seq_num=8): + """ + + Previously: UserAvg_Trigger_StrSeq + """ + userStringSeq_clear(ioc,seq_num) + trigger_strSeq_pv,trigger_strSeq_proc = userStringSeq_pvs(ioc, seq_num) + caput(trigger_strSeq_pv+".DESC",ioc+" Average Triggers") + + if num < 10: + str_num=str(num) + else: + str_num="A" + for i in range(1,num+1,1): + if i < 10: + i=str(i) + else: + i="A" + avg_pv="29id"+ioc+":userAve"+i + caput(trigger_strSeq_pv+".LNK"+i,avg_pv+"_acquire.PROC CA NMS") + caput(trigger_strSeq_pv+".WAIT"+i,"After"+str_num) + + return trigger_strSeq_pv,trigger_strSeq_proc \ No newline at end of file diff --git a/build/lib/iexcode/instruments/utilities.py b/build/lib/iexcode/instruments/utilities.py new file mode 100644 index 0000000000000000000000000000000000000000..3e4b739171c309dee52bff4b64bcfba7f6fedf8d --- /dev/null +++ b/build/lib/iexcode/instruments/utilities.py @@ -0,0 +1,213 @@ +""" +useful functions + +""" +import time +import datetime +import select +import sys +import ast +import os +import numpy as np +from numpy import inf + +from epics import caget, caput + +def dateandtime(): + return time.strftime("%a %d %b %Y %H:%M:%S",time.localtime()) + +def today(which='default'): + dt=datetime.date.today() + today_year = dt.year + today_month = dt.month + today_day = dt.day + if which == 'slash': + today_str=("{:02d}/{:02d}/{:04d}".format(today_month,today_day,today_year)) + elif which == 'int': + today_str=int(("{:04d}{:02d}{:02d}".format(today_year,today_month,today_day))) + else: # 'default': + today_str=("{:04d}{:02d}{:02d}".format(today_year,today_month,today_day)) + return today_str + + +def print_warning_message(message_string): + print('\n==================================') + print("WARNING: " +message_string+ " !!!!! ") + print('==================================\n') + + +def wait_for_it(D,H,M): + """ + D = how many days from now + H,M = what time that day in 24h clock + + e.g.: if today is Wed Nov 21 at 14:00 + WaitForIt(2,9,0) => Fri Nov 23 at 9:00 + """ + t = datetime.datetime.now()() + day = datetime.timedelta(days=D) + future = t + day + returnTime = datetime.datetime(future.year, future.month, future.day, int(H), int(M)) + timeToWait = returnTime - t + s=round(timeToWait.total_seconds(),1) + m=round(timeToWait.total_seconds()/60.0,1) + h=round(timeToWait.total_seconds()/3600.0,1) + print("Now is: "+str(t)) + print("Target date: "+str(returnTime)) + print("Sleeping for "+str(s)+" s = "+str(m)+" m = "+str(h)+" h") + print("Waaaaaaaait for it...") + time.sleep(timeToWait.total_seconds()) + print(dateandtime()) + + +def input_timeout(question,t): + print("You have "+str(t)+" seconds to answer!") + i, o, e = select.select( [sys.stdin], [], [], t ) + if (i): + print("You said", sys.stdin.readline().strip()) + else: + print("You said nothing!") + +def playsound(sound='FF'): + """ + plays a sound when run + 'FF' Final Fantasy victory sound + 'ding' a subtle ding noise + 'hallelujah' hallelujah chorus + """ + if sound == 'FF': + sounds = '/home/beams/29IDUSER/Documents/User_Macros/Macros_29id/Sound_Files/VictoryFF.wav' + elif sound == 'ding': + sounds = '/home/beams/29IDUSER/Documents/User_Macros/Macros_29id/Sound_Files/ding.wav' + elif sound == 'hallelujah': + sounds = '/home/beams/29IDUSER/Documents/User_Macros/Macros_29id/Sound_Files/hallelujah.wav' + os.system('aplay ' + sounds) + +def RangeUp(start,end,step): + while start <= end: + yield start + start += abs(step) + +def RangeDown(start,end,step): + while start >= end: + yield start + start -= abs(step) + +def EgForLoop(): + for hv in RangeDown(2000,500,-500): + print(hv) + for hv in RangeUp(500,2000,500): + print(hv) + +def take_closest_value(my_list,my_number): + """ + Given a list of integers, I want to find which number is the closest to a number x. + + Previously: TakeClosest + """ + return min(my_list, key=lambda x:abs(x-my_number)) + +def read_dict(filename,**kwargs): + """ + filename = name with extension of dictionary to read + **kwargs: + path = path to folder containing dictionary file (default: .IEX_dictionaries) + """ + if 'path' in kwargs: + path = kwargs['path'] + else: + path = os.path.join(os.path.dirname(__file__),'IEX_dictionaries') + fpath = os.path.join(path,filename) + with open(fpath) as f: + for c,line in enumerate(f.readlines()): + if line[0] == '=': + lastdate=line[8:16] + lastline=line + mydict=ast.literal_eval(lastline) + return mydict + + +def make_table(start_stop_step_lists): + """ + Creates and returns a np.array with values based on StartStopStepList + StartStopStepList is a list of lists defining regions for a table array + StartStopStepList[[start1,stop1,step1],[start1,stop1,step1],...] + Automatically removes duplicates and sorts into ascending order + if you want descending + myarray=XAS_Table(StartStopStepLists)[::-1] + + Previously: Scan_MakeTable + """ + table_array=np.array([]) + if type(start_stop_step_lists) is not list: + start = start_stop_step_lists[0] + stop = start_stop_step_lists[1] + step = start_stop_step_lists[2] + j = start + while j<=stop: + table_array=np.append(table_array, j) + j+=step + else: + for i in range(0,len(start_stop_step_lists)): + start=start_stop_step_lists[i][0] + stop=start_stop_step_lists[i][1] + step=start_stop_step_lists[i][2] + j=start + while j<=stop: + table_array=np.append(table_array, j) + j+=step + table_array=np.unique(table_array)#removing duplicate + table_array=np.sort(table_array) #sort into ascending order + return table_array + + + +def SendText(msg,which='user'): + """ + + which = 'user' or 'staff' + + Edit the following file with the correct email/phone number: + [sleepy /home/beams22/29ID/bin] pvMailSomething # for staff + [sleepy /home/beams22/29IDUSER/bin] pvMailUser # for user + + Use the following website to figure out carriers email: + https://20somethingfinance.com/how-to-send-text-messages-sms-via-email-for-free/ + + In a terminal, run the screen session: + pvMailUser (or pvMailSomething) + + To kill the screen session: + screen -ls #show list of screen session + screen -r screen# #reattached to a given screen session + screen -XS screen# kill #kill a given screen session + + + """ + if which == 'staff':n='6' + elif which == 'user':n='7' + caput('29idb:userCalcOut'+n+'.DESC',msg) + caput('29idb:userCalcOut'+n+'.A',0) + time.sleep(1) + caput('29idb:userCalcOut'+n+'.A',1) + print('Sending text/email') + + +def AbortScript(): + """ + Example: + while True: + try: + print 'do something' + sleep(5) + except KeyboardInterrupt: + if AbortScript() == 'y': + break + """ + try: + print('\n\nWARNING: Do you want to abort?') + print('Type y to ABORT, anything else to CONTINUE >') + foo = input() + return foo + except KeyboardInterrupt as e: + raise e diff --git a/build/lib/iexcode/instruments/vortexs29.py b/build/lib/iexcode/instruments/vortexs29.py new file mode 100644 index 0000000000000000000000000000000000000000..81deb7330942fbeaeb31d6e092c9fbceeb878a78 --- /dev/null +++ b/build/lib/iexcode/instruments/vortexs29.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python + +from epics import caget, caput +from time import sleep, gmtime, strftime, localtime + +#Define caput with wait function +def caputw(PVname,PVinput): + return caput(PVname,PVinput,wait=True, timeout = 100000) + +def dateandtime(): + return strftime("%a %d %b %Y %H:%M:%S",localtime()) + +def vortex(energy,time=1): + cen, wid = vortex_Ecal(energy) + set_roi1(cen,wid) + +def set_roi1(cen,wid): + caput('29idVORTEX:mca1.R0LO',round(cen-wid/2)) + caput('29idVORTEX:mca1.R0HI',round(cen+wid/2)) + +def set_roi2(cen,wid): + caput('29idVORTEX:mca1.R1LO',round(cen-wid/2)) + caput('29idVORTEX:mca1.R1HI',round(cen+wid/2)) + +def vortex_Ecal(energy): + cen = 12.8 + 0.72*energy + wid = 120 + return cen, wid + +def mcacounttime(time): + caput('29idVORTEX:mca1.PRTM',time) + +def runmca(time): + caput('29idVORTEX:mca1.PRTM',time) + sleep(0.1) + caputw('29idVORTEX:mca1EraseStart',1) + +def mcaoff(): + caput('29idd:Unidig1Bo1',1) + +def mcaon(): + caput('29idd:Unidig1Bo1',0) + +def savemca(): + caput('29idKappa:scan1.T2PV','29idVORTEX:scanH.EXSC') + caput('29idKappa:scan1.D16PV','29idVORTEX:mca1.R0') + caput('29idKappa:scan1.D17PV','29idVORTEX:mca1.R1') + caput('29idKappa:scan1.D49PV','29idd:userTran1.D') + caput('29idKappa:scan1.D50PV','29idd:userTran1.E') + sleep(1) + +def nosavemca(): + caput('29idKappa:scan1.T2PV','29idVORTEX:mca1EraseStart') + caput('29idKappa:scan1.D16PV','29idVORTEX:mca1.R0') + caput('29idKappa:scan1.D17PV','29idVORTEX:mca1.R1') + caput('29idKappa:scan1.D49PV','29idd:userTran1.D') + caput('29idKappa:scan1.D50PV','29idd:userTran1.E') + sleep(1) + +def nomca(): + caput('29idKappa:scan1.T2PV','') + caput('29idKappa:scan1.D16PV','') + caput('29idKappa:scan1.D17PV','') + caput('29idKappa:scan1.D49PV','') + caput('29idKappa:scan1.D50PV','') + sleep(1) + + +def scan_num(): + scan = caget('29idKappa:saveData_message') + loc = scan.find('.') + if (loc==-1): + scannum=0 + else: + scannum =int(scan[loc-4:loc]) + return scannum + +def mcafileinit(): + # mainpath = '/net/s4data/export/sector4/4idc/mda' + scanrecpath = caget('29idKappa:saveData_subDir') + scan = scan_num()+1 + caput('4idcVORTEX:saveData_subDir', '/'+ scanrecpath+'/S'+str(scan)) + caput('4idcVORTEX:saveData_scanNumber',1) + + +def chkmcasave(): + if (caget('29idKappa:scan1.T2PV')=='29idVORTEX:scanH.EXSC'): + print('Saving mca files') + mcafileinit() + + diff --git a/build/lib/iexcode/instruments/xrays.py b/build/lib/iexcode/instruments/xrays.py new file mode 100644 index 0000000000000000000000000000000000000000..aa029404a075cb0b00ddbf7f9878598afc57032b --- /dev/null +++ b/build/lib/iexcode/instruments/xrays.py @@ -0,0 +1,700 @@ +""" +functions related to using x-rays + +""" +import numpy as np +from time import sleep + +from epics import caget,caput +from iexcode.instruments.IEX_endstations import BL + +from iexcode.instruments.resolution import * +from iexcode.instruments.IEX_VPU import * +from iexcode.instruments.VLS_PGM import * +from iexcode.instruments.slits import * +from iexcode.instruments.shutters import * +from iexcode.instruments.gate_valves import * +from iexcode.instruments.diagnostics import * +from iexcode.instruments.m3r import * +from iexcode.instruments.logfile import * +from iexcode.instruments.utilities import print_warning_message,make_table, take_closest_value +from iexcode.instruments.mpa import * +from iexcode.instruments.current_amplifiers import ca_average +from iexcode.instruments.beamline import branch_cams_enable + +from iexcode.instruments.ARPES import ARPES_mprint,ARPES_extra_pvs +from iexcode.instruments.Kappa import Kappa_mprint +from iexcode.instruments.electron_analyzer import getSESslit, EA +############################################################################################################## +############################## resets and detector lists ############################## +############################################################################################################## +def test_function(): + print('hello world') + +def xrays_reset(): + mono_limits_reset() + xray_motor_encoder_sync() + + +def xrays_detector_list(): + """ + defualt detectors for the APRES endstation + used by: + CA_Live_StrSeq() + Detector_Triggers_StrSeq() + BeforeScan_StrSeq() => puts everybody in passive + CA_Average() + WARNING: can't have more than 5 otherwise CA_Live_StrSeq gets angry. + + Previously: part of Detector_List + """ + ca_list=[["b",4],["b",13]] + + return ca_list + + +def xrays_detector_dictionary(): + """ + returns a dictionary of the default detectors + + Previously: Detector_Default + """ + det_dict={} + sr_main_shutter={ + 1:"S:SRcurrentAI.VAL", + 2:"EPS:29:ID:SS1:POSITION" + } + bl_energy={ + 3:"29idmono:ENERGY_MON", + 4:"ID29:EnergySet.VAL", + 5:"ID29:Energy.VAL" + } + bl_keithleys={ + 6:"29idb:ca1:read", + 7:"29idb:ca2:read", + 8:"29idb:ca3:read", + 9:"29idb:ca4:read", + 10:"29idb:ca5:read", + 11:"29idb:ca9:read", + 12:"29idb:ca12:read", + 13:"29idb:ca13:read" + } + det_dict.update(sr_main_shutter) + det_dict.update(bl_energy) + det_dict.update(bl_keithleys) + return det_dict + +############################################################################################################## +############################## get beamline info ############################## +############################################################################################################## + +def xrays_get_all(verbose=False): + """ + gets info about current beamline setting + returns a dictionary + + """ + vals={} + print("\n===========================================================") + vals.update(ID_get_all(verbose=True)) + vals.update(mono_get_all(verbose=True)) + print("-----------------------------------------------------------") + vals.update(slits_get_all(verbose=True)) + vals.update(FMB_mirror_get(0,verbose=True)) + vals.update(FMB_mirror_get(1,verbose=True)) + vals.update(FMB_mirror_get(3,verbose=True)) + print("-----------------------------------------------------------") + vals.update({'ARPES':ARPES_mprint()}) + print("ARPES = ",ARPES_mprint()) + vals.update({'Kappa':Kappa_mprint()}) + print("Kappa = ",Kappa_mprint()) + print("===========================================================") + return vals + +def xrays_log_entries(**kwargs): + """ + Writes CSV file for the MDA scans with the following default parameters: + FilePath='/home/beams/29IDUSER/Documents/User_Folders/UserName/' + Filename is set by logname_set(FileName=None), default:YYYYMMDD_log.txt, where YYYYMMDD is when folders were set + (FileName=None,FileSuffix=None) is they are specified then it will use those values instead + + comment="Additional comments, last column" + + Previously: scanlog + """ + #default parameters + kwargs.setdefault('comment','') + + ioc = BL.ioc + + #scan Num + scan = BL.mda.prefix(ioc)+str(BL.mda.fileNum(ioc)) + entry_list=["scan"] + pv_list=[scan] + format_list=["s" ] + #scan info + drive = caget(ioc+"scan1.P1PV") + start = caget(ioc+"scan1.P1SP") + stop = caget(ioc+"scan1.P1EP") + step = caget(ioc+"scan1.P1SI") + entry_list.append('drive','start','stop' ,'step') + pv_list.append(drive,start,stop ,step) + format_list.append("s",".3f",".3f",".3f") + + #endstation info + if BL.endstation_name == 'ARPES': + endstation_entry, endstation_pv, endstation_format = ARPES_log_entries(**kwargs) + entry_list.append(endstation_entry) + pv_list.append(endstation_pv) + format_list.append(endstation_format) + elif BL.endstation_name == 'Kappa': + endstation_entry, endstation_pv, endstation_format = Kappa_log_entries(**kwargs) + entry_list.append(endstation_entry[:-7]) + pv_list.append(endstation_pv[:-7]) + format_list.append(endstation_format[:-7]) + + #beamline info + ID_mode = ID_mode_get(verbose=False) if BL.xrays else "no_xrays" + ID_QP_ratio = ID_QP_ratio_get (verbose=False) if BL.xrays else "no_xrays" + ID_sp = round(ID_SP_get_eV()) if BL.xrays else 0 + ID_rbv = round(ID_rbv_get_eV,4) if BL.xrays else 0 + hv = mono_energy_get() if BL.xrays else 0 + grt = mono_grating_get() if BL.xrays else 0 + slit_size = slit_get()[0] if BL.xrays else 0 + entry_list.append("hv","exit_slit","GRT", "ID_SP", "ID_RBV", "ID_Mode", "ID_QP") + pv_list.append(hv,slit_size,grt, ID_sp, ID_rbv,ID_mode, ID_QP_ratio) + format_list.append(".2f",".0f","s",".1f",".1f","s", ".0f") + + #endstation info 2: Fanny can I change to order to get rid of this complication? + if BL.endstation_name == 'Kappa': + endstation_entry, endstation_pv, endstation_format = Kappa_log_entries(**kwargs) + entry_list.append(endstation_entry[-7:]) + pv_list.append(endstation_pv[-7:]) + format_list.append(endstation_format[-7:]) + + #timestamp and comments + t = time.strftime("%D-%H:%M:%S") + comment = kwargs["comment"] + entry_list.append('time','comment') + pv_list.append(t,comment) + format_list.append("s","s") + + try: + logfile_update(BL.endstation,BL.ioc,entry_list,pv_list,format_list) + except: + print("scanlog did not write to file, check for errors.") + +############################################################################################################## +############################## beamline encoders ############################## +############################################################################################################## + +def xray_motor_encoder_sync(): + ioc = "29idb:" + for motor in [13,14,15,16,26,27]: + pv = ioc+"m"+str(motor)+".SYNC" + caput(pv,1) + print("synch encoder: "+pv) + +############################################################################################################## +############################## energy : ID + mono ############################## +############################################################################################################## +def energy_get_all(verbose=True): + """ + returns ID_mode,ID_QP_ratio,ID_sp,ID_rbv,hv,grt + + """ + d = ID_get_all(verbose=False) + d.update(mono_get_all(verbose=False)) + keylist = ['ID_Mode', 'ID_QP_ratio', 'ID_SP', 'ID_RBV','hv','grating'] + values = [] + for key in keylist: + values.append(d[key]) + if verbose: + print(key,d[key]) + + return tuple(values) + +def energy_get(): + hv = getE() + return hv + +def energy(hv_eV,slit_coeff=1,m3r=True,verbose=True): + """ + sets the ID for optimal flux based on calibration + sets the mono + sets the beamline aperture/slits + + slit_coeff < 1 is used to kill flux by closing the aperature after the mono (slit-2B) + + m3r => if True optimizes the mirror for the d-branch only + Previously: Set_BL, energy + """ + if BL.xrays: + if hv_eV != energy_range_check(hv_eV): + message_string = 'request photon energy '+str(hv_eV)+' not with the allowed range' + message_string = '\n closest allowed energy is '+str(energy_range_check(hv_eV)) + print_warning_message(message_string) + + + ID_energy_set(hv_eV,verbose=verbose) + mono_energy_set(hv_eV,verbose=verbose) + slits_set_BL(c_2B=slit_coeff,c_1A=1,verbose=verbose) + + if m3r == True: + if BL.branch() == 'd': + print('\nalign_m3r()') + try: + m3r_align() + sleep(1) + if m3r_RY_pos_sp_get() == m3r_RY_pos_sp(): + m3r_align() + except: + print('Unable to align; check camera settings.') + else: + message_string = 'BL.xrays = False, energy is not set' + print_warning_message(message_string) + +def energy_range_min_max(): + """ + returns the min,max energies for the current grating/ID setting + """ + ID_min, ID_max = ID_energy_range() + mono_min, mono_max = mono_energy_range() + hv_max = np.min(ID_max, mono_max) + hv_min = np.max(ID_min, mono_min) + return hv_min,hv_max + +def energy_range_check(hv): + """ + checks if the energy is within the allowed range for both the mono + and the ID. If outside the ranges set it to the closest allowed value + + Previously: SetRange() + """ + hv_min,hv_max = energy_range_min_max() + hv = np.min(hv_max,hv) + hv = np.max(hv_min,hv) + return hv + +def mvid(val): + """ + Sets the ID absolute set point (not optimized , mono & apertures stay fixed). + + to go to most flux use energy + """ + ID_SP_set() + +def scan_ID(ID_sp_start,ID_sp_stop,ID_sp_step,**kwargs): + """ + scan the ID set point + """ + val_pv,rbv_pv = ID_scan_pvs() + mda.fillin(val_pv,rbv_pv,ID_sp_start,ID_sp_stop,ID_sp_step,**kwargs) + + +def mvmono(val): + """ + Sets the mono energy (insertion device & apertures stay fixed). + """ + mono_energy_set(val) + +def getE(): + """ + Returns current mono set point. + """ + return mono_energy_get() + +def switch_gratings(grating): + """ + used to switch between gratings + grating = 'HEG' / 'MEG' + + check current grating + closes the main shutter + sets the mono energy + + Previously: Switch_Grating + """ + current_grt = mono_grating_get() + if grating != current_grt: + shutter_open = main_shutter_status() + main_shutter_close() + print("Switching grating, please wait...") + mono_grating_translate(grating,quiet=True) + slits_set_BL() + + if shutter_open: + main_shutter_open() + + print(dateandtime()," grating: "+grating) + else: + print("grating: "+grating) + +def mvgrating(grating): + """ + Change mono grating: + HEG = high resolution, low flux + MEG = medium resolution, high flux + """ + switch_gratings(grating) + +def polarization(ID_mode): + """ + Change beam polarization: ID_mode = 'H', 'V', 'RCP' or 'LCP' + """ + ID_switch_mode(ID_mode) + +def polarization_get(): + """ + gets the current polarization + """ + ID_mode_get() + +def scanhv(start,stop,step,average_pnts=1,**kwargs): + """ + scans the mono at the current ID value + + """ + ca_average(average_pnts) + + mono_scan_fillin(mda,start,stop,step,**kwargs) + + mono_energy_set(start) + mda.go(**kwargs) + + mono_scan_after(mda) + + +def scanE(start,stop,step,ID_offset=0,mesh='stay',average_pnts=1,scan_dim=1,**kwargs): + """ + sets the ID and then scans the mono + + hv_start,hv_stop,hv_step: are the mono start, stop, step energies + ID_offset: used to position the ID + None => the ID does not move + otherwise ID_energy_set = (stop-start)/2 + ID_offset + mesh: used to specifiy mesh status (for normalization) + => mesh='y': drops in the mesh for normalization (D branch only); retracts it at the end. + => mesh='stay': to leave the mesh in after the scan is finished + => mesh='n': no mesh. + **kwargs + scan_dim + positioner_settling_time = 0.2 + """ + mda = BL.mda + ca_average(average_pnts) + + if ID_offset != None: + ID_energy_set = (start+stop)/2.0 + ID_offset + + slits_set_BL() + + mono_scan_fillin(mda,scan_dim,start,stop,step,**kwargs) + + mono_energy_set(start) + BL.mda.go(scan_dim) + + mono_scan_after(mda,scan_dim) + + +def scanXAS(ID_eV,start_stop_step_lists,**kwargs): + """ + Sets the beamline to ID_eV and then scans the mono for XAS scans + + start_stop_step_lists is a list of lists for the different scan ranges + start_stop_step_lists = [[start1,stop1,step1], [start1,stop1,step1],...] + Note duplicates are removed and the resulting array is sorted in ascending order + + **kwargs: + scan_dim = 1 (default) + average_pnts: if using Keithlys this set the averaging; None for no averaging + m3r: if True the mirror is optimized before the start of the scan + mcp + execute: True/False to start the scan => True (default) + + Normalization: + - If in the D-branch the Mesh is put in but is not removed + - If in the C-branch we use the slit blades for normalization (ca13) + """ + kwargs.setdefault("scan_dim",1) + kwargs.setdefault("average_pnts",1) + kwargs.setdefault("m3r",True) + kwargs.setdefault("mcp",True) + kwargs.setdefault('execute',True) + + scan_dim=kwargs['scan_dim'] + + #Setting up the ScanRecord for Mono in Table mode + hv_array = make_table(start_stop_step_lists) + mono_scan_fillin_table(BL.mda,scan_dim,hv_array,**kwargs) + + #Averaging and Normalization + ca_average(kwargs['average_pnts']) + if BL.branch=="d": + meshD("In") + + #Setting the beamline energy + energy(ID_eV,m3r=kwargs["m3r"]) + + #mpa + if BL.branch == "d" and kwargs["mcp"]: + mpa_HV_on() + + #Scanning + if kwargs['execute']: + mono_energy_set(hv_array[0]) + BL.mda.go(scan_dim) + + #Setting everything back + mono_energy_set(ID_eV) + mono_scan_after(mda,scan_dim) + mda.table_reset_after(scan_dim) + + if BL.branch == "d": + if kwargs["mcp"]: + mpa_HV_off() + print("WARNING: Mesh"+BL.branch+" is still In") + +def scanXAS_BL(start_stop_step_lists,**kwargs): + """ + scans the mono and the ID for XAS scans + Note: this is slow, but required in if the c-branch + + start_stop_step_lists is a list of lists for the different scan ranges + start_stop_step_lists = [[start1,stop1,step1], [start1,stop1,step1],...] + Note duplicates are removed and the resulting array is sorted in ascending order + + **kwargs: + scan_dim = 1 (default) + average_pnts: if using Keithlys this set the averaging; None for no averaging + m3r: if True the mirror is optimized before the start of the scan + mcp + execute: True/False to start the scan => True (default) + + Normalization: + - If in the D-branch the Mesh is put in but is not removed + - If in the C-branch we use the slit blades for normalization (ca13) + """ + kwargs.setdefault("scan_dim",1) + kwargs.setdefault("average_pnts",1) + kwargs.setdefault("m3r",True) + kwargs.setdefault("mcp",True) + kwargs.setdefault('execute',True) + + scan_dim=kwargs['scan_dim'] + + #Setting up the ScanRecord for Mono and ID in Table mode + mono_array,ID_array = BL_energy_tables(start_stop_step_lists) + + kwargs.update('positioner_num',1) + mono_scan_fillin_table(mda,scan_dim,mono_array,**kwargs) + + kwargs.update('positioner_num',2) + ID_scan_fillin_table(mda,scan_dim,ID_array,**kwargs) + + #Averaging and Normalization + ca_average(kwargs['average_pnts']) + if BL.branch=="d": + meshD("In") + + #Setting the beamline energy + slits_set_BL(mono_array[0],m3r=kwargs["m3r"]) + + #mpa + if BL.branch == "d" and kwargs["mcp"]: + mpa_HV_on() + + #Scanning + if kwargs['execute']: + mono_energy_set(mono_array[0]) + ID_SP_set(ID_array[0]) + BL.mda.go(scan_dim) + + #Setting everything back + mono_energy_set(mono_array[0]) + mono_scan_after(mda,scan_dim) + mda.table_reset_after(scan_dim) + + if BL.branch == "d": + if kwargs["mcp"]: + mpa_HV_off() + print("WARNING: Mesh"+BL.branch+" is still In") + +def BL_energy_tables(start_stop_step_lists): + """ + returns mono_array and ID_array for BL energy scans + *energies: + start,stop,step + ListofLists, e.g.{[400,420,1],[420,425,0.25]...} + + Previously: Tables_BLenergy + """ + mono_array = make_table(start_stop_step_lists) + ID_array=np.array([]) + ID_mode,ID_QP_ratio,ID_sp,ID_rbv,hv,grt = energy_get_all(verbose=False) + for hv_eV in mono_array: + ID_array=np.append(ID_array,ID_calc_SP(grt,ID_mode,hv_eV)) + return mono_array,ID_array + + +############################################################################################################## +########################### branch shutter, valves, safe_state ###################### +############################################################################################################## +def get_branch(verbose=True): + """ + gets the branch based on the position of m3r + """ + branch = m3r_branch(verbose) + return branch + + +def open_branch(branch=None,valve=False): + """ + Opens the branch shutter, if branch is none, then uses the position of m3r to determine branch + + Previously: Check_BranchShutter + """ + branch = get_branch(verbose=False) + + if branch_shutter_status(branch): + print(dateandtime(), +branch+" shutter already open..." ,) + else: + while True: + if branch_shutter_status(branch) == False : + print(dateandtime(), "Opening "+branch+" shutter ..." ,) + branch_shutter_open(branch,verbose=False) + sleep(30) + else: + print(dateandtime(), +branch+" shutter is now open..." ,) + break + if valve: + GVs = branch_valves() + for GV in GVs: + valve_open(GV) + +def close_shutter(branch=None): + """ + Closes the branch shutter, if branch is none, then uses the position of m3r to determine branch + + Previously: Close_CShutter,Close_DShutter + """ + if branch is None: + branch = get_branch() + caput("PC:29ID:S"+branch+"S_CLOSE_REQUEST.VAL",1,wait=True,timeout=18000) + print("Closing "+branch+"-Shutter...") + +def switch_branch(branch, force=False, shutter=True,scan_reset=True,enable_cams=True): + """Switch beam into which = \"c\" or \"d\" branch (by retracting/inserting deflecting mirror) + Optionnal keyword argument: + force: change m3r even if the beamline think it is already there (default=False) + shutter: open the branch shutter, does not open the valve (default=False) + reset: resets the scanRecord and the global BL for the selected branch + enable_cams: to turn on/off branch camera + + Previously: Switch_Branch + """ + branch = branch.lower() + if branch in ["c","d","e"]: + + # Check current branch: + if get_branch() == branch and not force: + m3r_position = FMB_mirror_get(3,verbose=False) + if np.sum(np.array(m3r_position)): + print("\nMirror homed...") + print("...Try again using: Switch_Branch(which, forced=True)") + else: + print("\nWell, looks like the beam is already in this branch...") + print("...if you want to force the mirror motion, use the argument: forced=True") + else: + # Close both shutters: + print("\n") + print("Switching branch, please wait...") + if shutter: + branch_shutter_close('c') + branch_shutter_close('d') + + #Move M3R: + m3r_switch_branch(branch) + print(dateandtime()," - In "+branch+"-Branch") + sleep(2) + + # Open branch shutters: + if shutter: + open_branch(branch,valve=False) + + if scan_reset: + BL.mda.reset() + + if enable_cams: + branch_cams_enable(branch) + + else: + print_warning_message(branch+' is not a valid branch selection') +# if not nocam: + +############################################################################################################## +########################### mirrors ###################### +############################################################################################################## +def get_mirrors(): + for mirror_num in [0,1,3]: + FMB_mirror_get(mirror_num,verbose=True) + + +############################################################################################################## +########################### slits and resolution ###################### +############################################################################################################## +def slit(size): + """ + sets the exit slit based on BL.endstation + + ARPES = 0 < x < 300 um + Kappa = 0 < x < 1000 um + """ + branch = BL.branch + if branch == "c": + slit3C_set(size, quiet=False) + elif branch == "d": + slit3D_set(size, quiet=False) + + +def slit_get(verbose=True): + """ + sets the exit slit based on BL.endstation + + ARPES = 0 < x < 300 um + Kappa = 0 < x < 1000 um + """ + branch = BL.branch + if branch == "c": + slit_size = slit3C_get(verbose=False) + slit_center = np.nan + elif branch == "d": + slit_size,slit_center = slit3D_get(verbose=False) + + if verbose: + message = BL.branch+' exit slit: '+str(slit_size) + message += ", @ "+str(slit_center) if BL.branch is not 'c' else '' + print(message) + return slit_size,slit_center + +def resolution(): + """ + Calculate the theoretical resolution for the current beamline settings: + ARPES: total resolution i.e. sqrt(kbT^2 + analyzer^2 + BL^2); default SES slit = 5. + Kappa: beamline contribution only + """ + branch = get_branch() + grt = mono_grating_get() + hv_eV = getE() + slit_size = take_closest_value([10,20,50,100,200],round(slit_get(),0)) + + if branch == "c": + slit_SES = getSESslit() + PE = int(EA.PassEnergy) + T = caget(ARPES_extra_pvs['TA']) + resolution_ARPES(grt,hv_eV,slit_size,PE,slit_SES,T,verbose=True) + else: + resolution_beamline(grt,hv_eV,slit_size,verbose=True) + + + diff --git a/build/lib/iexcode/macros/ARPES_macros.py b/build/lib/iexcode/macros/ARPES_macros.py new file mode 100644 index 0000000000000000000000000000000000000000..240e6d80e466ef7ca34fc6bff6eae7cd8d249a51 --- /dev/null +++ b/build/lib/iexcode/macros/ARPES_macros.py @@ -0,0 +1,96 @@ +import numpy as np + +from epics import caget,caput + +from .ScanFunctions_plot import mda_1D,fit_gauss + +from ..instruments.electron_analyzer import scanEA +from ..instruments.slits import slit3C_set +from ..instruments.xrays import energy +from ..instruments.ARPES import mvth,scanx,mvx,mprint + + +############################################################################################################## +############################## SES Work Function ############################## +############################################################################################################## + +def WorkFunction_Measure(PE,KE=409,**kwargs): + ''' + Takes data with 1st and 2nd order light of core level with KE at @ hv=500eV + **kwargs + + ''' + frames=round(17*60*200/PE,0) + energy(500) + + #Fermi Level + slit3C_set(150) + kwargs.update({'comment': 'EF1'}) + EAlist=['KE',495,PE,frames,1] + scanEA(EAlist,**kwargs) + + #Core level first order + slit3C_set(50) + kwargs.update({'comment': 'KE1'}) + EAlist=['KE',KE,PE,frames/10,1] + scanEA(EAlist,**kwargs) + + #Core level second order + slit3C_set(150) + kwargs.update({'comment': 'KE2'}) + EAlist=['KE',KE+500,PE,frames*10,1] + scanEA(EAlist,**kwargs) + print("""Fit the data : + - EF1 = EF in first order light (scan #1) + - KE1 = Au_3/2 in first order light (scan #2) + - KE2 = Au_3/2 for 2nd order light (scan #3) + => wk = KE2-2*KE1-(EF1-KE1)` + Details of the math is page 16 of commissionning book IV + Now if you know what you are doing you can: + caput('29idcEA:det1:ENERGY_OFFSET',new_wk_value)""") + +def WorkFunction_Calc(EF1,KE1,KE2): + """Fit the data : + - EF1 = EF in first order light (scan #1) + - KE1 = Au_3/2 in first order light (scan #2) + - KE2 = Au_3/2 for 2nd order light (scan #3) + => wk = KE2-2*KE1-(EF1-KE1)` + Details of the math is page 16 of commissionning book IV""" + wk = KE2-2*KE1-(EF1-KE1) + print("wk = KE2-2*KE1-(EF1-KE1) = ",wk) + print("Now if you know what you are doing you can:") + print("EA._setwk("+str(round(wk,2))+")") + +def WorkFunction(KE1,KE2,Ef): + Phi=round(KE2-2*KE1-(Ef-KE1),3) + print(('Phi = '+str(Phi)+' eV')) + return Phi + +def RoughPositions_Find(th_start,th_stop, th_step,**kwargs): + """automatically scans and creates the RoughPosition list used in FermiMap for + relatively uniform samples by: + 1) scanx(-0.5,0.5,.05,mode='relative') + 2) does a gaussian fits the mda EAV intesnity to determine center of the fit x_center + 3) mv(x_center) + 4) mprint() and appends current position to list + 5) moves to the next theta value and repeats + + Note: before starting move to the first theta position and adjust the focus leaving the EA is Live Mode + + **kwargs + scanDet=17 + """ + kwargs.setdefault("scanDet",17) + if caget("29idcEA:det1:Acquire") !=1: + print("Turn on the EA!!! EALive(PE,KE,Lens=\'Transmission\')") + else: + RefinedPositions=[] + for th in (th_start,th_stop+th_step,th_step): + mvth(th) + scanx(-0.5,0.5,.05,mode='relative') + scanNum=caget("29idARPES:saveData_scanNumber")-1 + x,y,x_name,y_name=mda_1D(scanNum,kwargs["scanDet"]) + results=fit_gauss(np.array(x),np.array(y)) + mvx(results[2][1]) + RefinedPositions.append(mprint()) + print("RefinedPositions=",RefinedPositions) diff --git a/build/lib/iexcode/macros/BL_shutdown.py b/build/lib/iexcode/macros/BL_shutdown.py new file mode 100644 index 0000000000000000000000000000000000000000..800bf0c93902b720273eb0e63ef5d15fba729d02 --- /dev/null +++ b/build/lib/iexcode/macros/BL_shutdown.py @@ -0,0 +1,47 @@ +from epics import caget,caput + +from ..instruments.electron_analyzer import EA +from ..instruments.shutters import main_shutter_close,branch_shutter_close +from ..instruments.diagnostics import diagnostics_all_out + +############################################################################################################## +############################################ Shut down ################################################# +############################################################################################################## + +def BL_Shutdown(): + BL_CloseAllShutters() + BL_Valve_All(state="CLOSE") + diagnostics_all_out() + try: + EA.off() + except: + print('EA is not running, visually confirm HV is off') + + caput("29iddau1:dau1:011:DAC_Set",0) #RSXS HV = "OFF" + +def BL_CloseAllShutters(): + main_shutter_close() + branch_shutter_close('c') + branch_shutter_close('d') + +def BL_Valve_All(state="CLOSE"): + ValveList=["V1A","V2A","V3B","V4B","V5B","V6B","V7C","V8C","V9C","V10C","V7D","V8D","V9D","V10D"] + for Vname in ValveList: + pv=BL_Valve2pv(Vname)+state+".VAL" + caput(pv,1) + +def BL_Valve(Vname,state="CLOSE"): + pv=BL_Valve2pv(Vname)+state+".VAL" + caput(pv,1) + +def BL_Valve2pv(Vname): + Valve={ + "V1A":"GV01","V2A":"GV02", #A-Hutch + "V3B":"GV03","V4B":"GV04","V5B":"GV05","V6B":"GV15", #B-Branch + "V7C":"GV06","V8C":"GV08","V9C":"GV09","V10C":"GV10", #C-Branch + "C-Turbo":"GV16", #ARPES + "V7D":"GV11","V8D":"GV12","V9D":"GV13","V10D":"GV14", #D-Branch + "D-Turbo":"GV17","D-TES":"GV18" #RSXS + } + pv="29id:BLEPS:"+Valve[Vname]+":" + return pv \ No newline at end of file diff --git a/build/lib/iexcode/macros/Kappa_optimization.py b/build/lib/iexcode/macros/Kappa_optimization.py new file mode 100644 index 0000000000000000000000000000000000000000..378f9c598983c35739c1894748dbd5275e9b1b80 --- /dev/null +++ b/build/lib/iexcode/macros/Kappa_optimization.py @@ -0,0 +1,100 @@ +import matplotlib.pyplot as plt + +from epics import caget,caput +from ..instruments.Kappa import * +from ..instruments.Motors import * + +from .ScanFunctions_plot import fit_mda, mda_1D + +##### Kappa Optimization scans ##### +def Opt_d4(iteration,moveZ,graph='y',srs=None,start=-0.5,stop=0.5,step=0.04): + tth_w=0.1 + if srs==None: det=21 + else: det=34 + z=caget('29idKappa:m4.RBV') + current_det=caget('29idKappa:userStringSeq6.STR1',as_string=True) + if current_det != 'd4': + print('Switching detector to d4') + tthdet.set('d4',move=False) + mvtth(0) + if moveZ is not None: + mvz(z-1000) + for i in range(iteration): + scantth(start,stop,step,'relative') + scannum = mda.lastFileNum() + tth0=fit_mda(scannum,det,tth_w,'gauss',graph=graph) + mvtth(tth0) + mvz(z) + return tth0,scannum + +def Opt_z0(iteration,movetth,movekth,det='d4',srs=None,graph='y'): + z_w=400 + current_det=caget('29idKappa:userStringSeq6.STR1',as_string=True) + if current_det != det: + print('Switching detector to '+det) + tthdet.set(det,move=False) + if det=='d3' and srs==None: det=20 + if det=='d3' and srs!=None: det=33 + if det=='d4' and srs==None: det=21 + if det=='d4' and srs!=None: det=34 + if movetth is not None: + mvtth(movetth) + if movekth is not None: + mvkth(movekth) + if iteration>1: + scanz(-2000,2000,250,'relative') + scannum=mda.fileNum() + z0=fit_mda(scannum,det,z_w,'erf',graph=graph) + mvz(z0) + scanz(-700,700,50,'relative') + scannum = mda.lastFileNum() + z0=fit_mda(scannum,det,z_w,'erf',graph=graph) + mvz(z0) + return z0,scannum + +def Opt_kth(kth_0,theta,det='d4',srs=None,graph='y'): + current_det=caget('29idKappa:userStringSeq6.STR1',as_string=True) + if current_det != det: + print('Switching detector to '+det) + tthdet.set(det,move=False) + if det == 'd4': + if srs==None: det=21 + else: det=34 + i=1 + elif det == 'd3': + if srs==None: det=20 + else: det=33 + i=5 + mvtth(theta*2) + mvkth(kth_0+theta) + scankth(-0.5*i,0.5*i,0.05*i,'relative') + new_kth=fit_mda(mda.lastFileNum(),det,0.1,'gauss',graph=graph) + mvkth(new_kth) + scankth(-0.2*i,0.2*i,0.02*i,'relative') + new_kth=fit_mda(mda.lastFileNum(),det,0.1,'gauss',graph=graph) + mvkth(new_kth) + scannum=mda.lastFileNum + kth0=round(new_kth-theta,3) + print('\nkth0 = ',kth0) + print('To plot use:') + print(' fit_mda('+str(scannum)+',21,0.2,"gauss",mytitle=\'theta ='+str(theta)+'\')') + print('If you are happy with that, you can set this value as kth0 using:') + print(' kth0_set('+str(kth0)+')') + + return kth0,scannum + +def plot_opt(opt_scan_list,energy_list,det,mytitle=''): + fig,(ax1)=plt.subplots(1,1) + fig.set_size_inches(5,4) + + for i,j in zip(opt_scan_list,energy_list): + x,y,x_name,y_name=mda_1D(i,det,1,0) + xdata = np.array(x) + ydata = np.array(y) + Imax=np.max(ydata) + ax1.plot(x,y/Imax,label=str(j)+" eV") + ax1.set(ylabel='Intensity') + ax1.set(xlabel=x_name) + ax1.ticklabel_format(style='sci', axis='y', scilimits=(0,0)) + ax1.grid(color='lightgray', linestyle='-', linewidth=0.5) + ax1.legend(bbox_to_anchor=[1.2, 1],ncol=2,shadow=True, title=mytitle, fancybox=True) diff --git a/build/lib/iexcode/macros/ScanFunctions_plot.py b/build/lib/iexcode/macros/ScanFunctions_plot.py new file mode 100644 index 0000000000000000000000000000000000000000..c4ca21637d4ca36a0b2bec68618036e5544fd27d --- /dev/null +++ b/build/lib/iexcode/macros/ScanFunctions_plot.py @@ -0,0 +1,2787 @@ +""" +#ScanFunctions_plot.py +how to copy tabs in stabs and not spaces jupyter + +For Fanny: Converting spaces to tabs from the terminal +cp ScanFunctions_IEX.py ScanFunctions_IEXbackup.py +sed -e 's/ /\t/g' ScanFunctions_IEXbackup.py > ScanFunctions_IEX.py +""" + +#### Other utilities: +import csv +from os import listdir +from os.path import join, isfile, dirname +from scipy.optimize import curve_fit +from scipy.special import erf +import numpy.polynomial.polynomial as poly +import ast + +### Data analysis: +from inspect import CO_ASYNC_GENERATOR +from sre_constants import CATEGORY_DIGIT +import matplotlib.pyplot as plt +import matplotlib.image as mpimg +import numpy as np +from math import * + +from netCDF4 import Dataset + + +##### APS / 29ID-IEX: +from IEX_plotting_and_analysis.mda import readMDA,scanDim +from IEX_plotting_and_analysis.IEX_nData import * + +try: + from epics import caget + from ..instruments.IEX_endstations import BL + from ..instruments.utilities import read_dict,today + from ..instruments.slits import slits_set_BL + from IEXcode.iexcode.current_amplifiers import current2flux +except: + print("EPICS package and dependent functions are not installed") + + + +############################################################################################################## +############################## JM Curves and Curve Fitting ############################## +############################################################################################################## + +def gauss(x, *p): + """ + Function for a guassian where p=[A,x0,sigma] + f(x)=A*numpy.exp(-(x-x0)**2/(2.*sigma**2) + fwhm=2.355*sigma + """ + A, x0, sigma = p + return A*np.exp(-(x-x0)**2/(2.*sigma**2)) + +def gauss_p0(y,x): + """ + Inital guesses for guassian fit + x and y are np.arrays + returns p0=[A,x0,sigma] + """ + A=max(y) + x0=x[np.where(y == max(y))][0] + sigma=0.2 + return [A,x0,sigma] + +def fit_gauss(x,y,xrange=None): + """ + x,y=EA_Spectrum(ScanNum, EnergyAxis,FilePath,Prefix) + x,y,x_name,y_name=mda_1D(ScanNum,DetectorNum) + + xrange = None to fit the full range + = [x1,x2] to fit a subrange + returns input_x,fit_y,coeff,var_matrix + where input_x and fit_y are the sub range x and the fitted data respectivley + coeff=[A,x0,sigma] + var_matrix is the fit variance + """ + if xrange is None: + input_y=y + input_x=x + else: + index1=np.where(x == x.flat[np.abs(x - xrange[0]).argmin()])[0][0] + index2=np.where(x == x.flat[np.abs(x - xrange[1]).argmin()])[0][0] + input_x=x[index1:index2] + input_y=y[index1:index2] + coeff, var_matrix = curve_fit(gauss, input_x, input_y, p0=gauss_p0(input_y,input_x)) + fit_y= gauss(input_x, *coeff) + return input_x,fit_y,coeff,var_matrix + + +############################################################################################################## +############################## Plot Tiff,JPEG,PNG ############################## +############################################################################################################## + +# filepath='/home/beams/29IDUSER/Documents/User_Folders/Topp/S089.tif' +def plot_image(filepath,h=20,v=10,**kwargs): + """ + filepath = '/home/beams/29IDUSER/Documents/User_Folders/UserName/TifFile.tif' + ** kwargs are imshow kwargs: + cmap = colormap; examples => 'gray','BuPu','Inferno' + vmin,vmax, adjust max and min of colormap + """ + + image = mpimg.imread(filepath) + plt.figure(figsize=(h,v)) + plt.imshow(image,**kwargs) + plt.axis('off') + plt.show() + + + +def plot_image2(Filepath1,Filepath2,h=20,v=10): + """ + filepath = '/home/beams/29IDUSER/Documents/User_Folders/UserName/TifFile.tif' + """ + print(Filepath1) + print(Filepath2) + image1 = mpimg.imread(Filepath1) + image2 = mpimg.imread(Filepath2) + plt.figure(figsize=(h,v)) + plt.subplot(1,2,1), plt.imshow(image1,cmap='gray') + plt.axis('off') + plt.subplot(1,2,2), plt.imshow(image2,cmap='gray') + plt.axis('off') +# fig.subplots_adjust(wspace=0.5,hspace=0.5,left=0.125,right=0.9,top=0.85,bottom=0.15) + plt.tight_layout() + plt.show() + + +############################################################################################################## +############################## Extract mda Data ############################## +############################################################################################################## + +## mda_1D(1691,44,1,0,'/net/s29data/export/data_29idb/2018_1/mda_b')??? + +def mda_unpack(ScanNum,filepath=None,prefix=None): + """ Return data file + dictionary D##:("pv",index##) + filepath: by default plot scans for the current data folder (as defined in BL_ioc() ScanRecord SaveData) + or specified folder path: + e.g. filepath='/net/s29data/export/data_29idb/2018_1/mda_b/' + prefix: by default, uses prefix as defined in ScanRecord + "mda_" for users, "Kappa_" or "ARPES_" for staff (sometimes) + """ + try: + if filepath is None: + filepath = BL.mda.filepath + if prefix is None: + prefix = BL.mda.prefix + except: + print('Please specify filepath and prefix, BL is not defined') + + mdaFile=filepath + prefix+'{:04}.mda'.format(ScanNum) + data_file = readMDA(mdaFile) + try: + D={} + n=len(data_file)-1 + for i in range(0,data_file[n].nd): + detector=data_file[n].d[i].fieldName + D[int(detector[1:])]=(data_file[n].d[i].name,i) + return (data_file,D) + except: + pass + +def mda_1D(ScanNum,DetectorNum,coeff=1,bckg=0,filepath=None,prefix=None): + """ Return x=positionner and y=detector(DetectorNum) + for a given detector number DYY (as shown in dview). """ + try: + (data_file,det)=mda_unpack(ScanNum,filepath,prefix) + index=det[DetectorNum][1] + x = data_file[1].p[0].data + y = data_file[1].d[index].data + x_name = data_file[1].p[0].name + y_name = data_file[1].d[index].name + if type(x_name) == bytes: + x_name=x_name.decode("utf-8") + if type(y_name) == bytes: + y_name=y_name.decode("utf-8") + n=list(zip(x,y)) + d=[n[i] for i, e in enumerate(n) if e != (0.0,0.0)] + if len(d)<len(n): + x=x[:len(d)] + y=y[:len(d)] + y=[(y[i]+bckg)*coeff for i, e in enumerate(y)] + #y=[(y[i]*coeff)+bckg for i, e in enumerate(y)] + return x,y,x_name,y_name + except: + print('error') + pass + + +def mda_1D_unscaled(ScanNum,DetectorNum,filepath=None,prefix=None): + """ Return x=positionner and y=detector(DetectorNum) + for a given detector number DYY (as shown in dview). """ + try: + (data_file,det)=mda_unpack(ScanNum,filepath,prefix) + if (data_file,det) == (None,None): + return(None) + else: + index=det[DetectorNum][1] + x = data_file[1].p[0].data + y = data_file[1].d[index].data + x_name = data_file[1].p[0].name + y_name = data_file[1].d[index].name + if type(x_name) == bytes: + x_name=x_name.decode("utf-8") + if type(y_name) == bytes: + y_name=y_name.decode("utf-8") + n=list(zip(x,y)) + d=[n[i] for i, e in enumerate(n) if e != (0.0,0.0)] + if len(d)<len(n): + x=x[:len(d)] + y=y[:len(d)] + bckg=min(y) + coeff=max(y)-min(y) + y=[(y[i]-bckg)/coeff for i, e in enumerate(y)] + return x,y,x_name,y_name + except: + pass + +def mda_1D_Xindex(ScanNum,DetectorNum,coeff=1,bckg=0,filepath=None,prefix=None): + """ Return x=index and y=detector(DetectorNum) + for a given detector number DYY (as shown in dview). """ + try: + (data_file,det)=mda_unpack(ScanNum,filepath,prefix) + index=det[DetectorNum][1] + x = data_file[1].d[0].data + y = data_file[1].d[index].data + x_name = data_file[1].d[0].name + y_name = data_file[1].d[index].name + if type(x_name) == bytes: + x_name=x_name.decode("utf-8") + if type(y_name) == bytes: + y_name=y_name.decode("utf-8") + n=list(zip(x,y)) + d=[n[i] for i, e in enumerate(n) if e != (0.0,0.0)] + if len(d)<len(n): + y=y[:len(d)] + x=list(range(1,len(y)+1)) + y=[(y[i]*coeff)+bckg for i, e in enumerate(y)] + return x,y,x_name,y_name + except: + pass + +def mda_1D_vsDet(ScanNum,DetectorNum,DetectorNum2,coeff=1,bckg=0,filepath=None,prefix=None): + """ Return x=index and y=detector(DetectorNum) + for a given detector number DYY (as shown in dview). """ + try: + #print(ScanNum,filepath,prefix,scanIOC) + (data_file,det)=mda_unpack(ScanNum,filepath,prefix) + index=det[DetectorNum][1] + index2=det[DetectorNum2][1] + x = data_file[1].d[0].data + x2 = data_file[1].d[index2].data + y = data_file[1].d[index].data + x_name = data_file[1].d[0].name + x2_name = data_file[1].d[index2].name + y_name = data_file[1].d[index].name + x = data_file[1].p[0].data + x2= data_file[1].d[index2].data + y= data_file[1].d[index].data + if type(x_name) == bytes: + x_name=x_name.decode("utf-8") + if type(y_name) == bytes: + y_name=y_name.decode("utf-8") + if type(x2_name) == bytes: + x2_name=x2_name.decode("utf-8") + n=list(zip(x,y)) + d=[n[i] for i, e in enumerate(n) if e != (0.0,0.0)] + if len(d)<len(n): + y=y[:len(d)] + x2=x2[:len(d)] + y=[(y[i]*coeff)+bckg for i, e in enumerate(y)] + return x2,y,x2_name,y_name + except: + pass + +def mda_Flux(ScanNum,DetectorNum,EnergyNum,filepath=None,prefix=None): + """ Return x=positionner and y=Flux(DetectorNum) + for a given diode recorded as detector number DYY (see ## in dview). + EnergyNum is the detector number for the mono RBV. + + """ + try: + (data_file,det)=mda_unpack(ScanNum,filepath,prefix) + index=det[DetectorNum][1] + Eindex=det[EnergyNum][1] + x = data_file[1].p[0].data + y = data_file[1].d[index].data + energy = data_file[1].d[Eindex].data + x_name = data_file[1].p[0].name + y_name = data_file[1].d[index].name + if type(x_name) == bytes: + x_name=x_name.decode("utf-8") + if type(y_name) == bytes: + y_name=y_name.decode("utf-8") + n=list(zip(x,y)) + d=[n[i] for i, e in enumerate(n) if e != (0.0,0.0)] + if len(d)<len(n): + x=x[:len(d)] + y=y[:len(d)] + y=[current2flux(y[i],energy[i],p=None) for (i, e) in enumerate(y)] + return x,y,x_name,y_name + except: + pass + + + +def mda_NormDet(ScanNum,DetectorNum,NormNum,coeff=1,bckg=0,filepath=None,prefix=None): + """ Return x=positionner and y=detector(DetectorNum) + for a given detector number DYY (as shown in dview). """ + try: + (data_file,det)=mda_unpack(ScanNum,filepath,prefix) + index=det[DetectorNum][1] + index_Norm=det[NormNum][1] + x = data_file[1].p[0].data + y= data_file[1].d[index].data + y_Norm=data_file[1].d[index_Norm].data + x_name = data_file[1].p[0].name + y_name = data_file[1].d[index].name#+"_norm:"+str(NormNum) + if type(x_name) == bytes: + x_name=x_name.decode("utf-8") + if type(y_name) == bytes: + y_name=y_name.decode("utf-8") + + n=list(zip(x,y)) + d=[n[i] for i, e in enumerate(n) if e != (0.0,0.0)] + if len(d)<len(n): + x=x[:len(d)] + y=y[:len(d)] + y=[y[i]/y_Norm[i] for i, e in enumerate(y)] + return x,y,x_name,y_name + except: + pass + +def mda_DivScan(ScanNum1,DetectorNum1,ScanNum2,DetectorNum2,coeff=1,bckg=0,filepath=None,prefix=None): + """ Return x=positionner and y=detector(DetectorNum) + for a given detector number DYY (as shown in dview). """ + try: + (data_file1,det1)=mda_unpack(ScanNum1,filepath,prefix) + index1=det1[DetectorNum1][1] + (data_file2,det2)=mda_unpack(ScanNum2,filepath,prefix) + index2=det2[DetectorNum2][1] + x1 = data_file1[1].p[0].data + y1= data_file1[1].d[index1].data + y2= data_file2[1].d[index2].data + x_name = data_file1[1].p[0].name + y_name = data_file1[1].d[index1].name+"_norm:"+str(ScanNum2) + if type(x_name) == bytes: + x_name=x_name.decode("utf-8") + if type(y_name) == bytes: + y_name=y_name.decode("utf-8") + + n=list(zip(x1,y1)) + d=[n[i] for i, e in enumerate(n) if e != (0.0,0.0)] + if len(d)<len(n): + x1=x1[:len(d)] + y1=y1[:len(d)] + y=[y1[i]/y2[i] for i, e in enumerate(y1)] + return x1,y,x_name,y_name + except: + pass + + + +def mda_2D(ScanNum,DetectorNum,filepath=None,prefix=None): + """ Return x=positionner and y=detector(DetectorNum) + for a given detector number DYY (as shown in dview). """ + try: + (data_file,det)=mda_unpack(ScanNum,filepath,prefix) + index=det[DetectorNum][1] + x_temp = data_file[2].p[0].data + y_temp = data_file[1].p[0].data + z_temp = data_file[2].d[index].data + x_name = data_file[2].p[0].name + y_name = data_file[1].p[0].name + z_name = data_file[2].d[index].name + if type(x_name) == bytes: + x_name=x_name.decode("utf-8") + if type(y_name) == bytes: + y_name=y_name.decode("utf-8") + if type(z_name) == bytes: + z_name=z_name.decode("utf-8") + + n=list(zip(x_temp,y_temp,z_temp)) + d=[n[i] for i, e in enumerate(n) if e != (0.0,0.0,0.0)] + if len(d)<len(n): + x_temp=x_temp[:len(d)] + y_temp=y_temp[:len(d)] + z_temp=z_temp[:len(d)] + x = x_temp[0] + y = y_temp + z = np.asarray(z_temp) #2-D array + return x,y,z,x_name,y_name,z_name + except: + pass + + +############################################################################################### +#################################### PLOT MDA ################################### +############################################################################################### + + + + +def plot_mda2D(ScanNum,DetectorNum,title=None,color=None,filepath=None,prefix=None): + try: + x,y,z,xName,yName,zName=mda_2D(ScanNum,DetectorNum,filepath,prefix) + fig, ax0 = plt.subplots() + if color is None: + color='gnuplot' + img = ax0.imshow(z, cmap=color, interpolation = 'nearest', extent = [min(x), max(x), max(y), min(y)], aspect = 'auto') + fig.colorbar(img) + if title is None: + plt.title(zName) + else: + plt.title(title) + ax0.set_xlabel(xName) + ax0.set_ylabel(yName) + # ax0.set_ylim(y.max(),y.min()) + plt.show() + except: + pass + + + +def plot_mda_series(*ScanDet,**kwArg): + """plot_mda_series(1217, 1226, 1, 39 ,0.025, **kwArg) + (first,last,countby,det,offset,**kwArg) + Optional data analysis keywords arguments: + Flux conversion (for diode only): flux= 3(User) or 25(Staff). + Norm option: norm = 'yes' normalizes all the scans to 1 (default: None) + NormDet= 1 for SR current, 14 for Mesh (D-branch); Normalize by the mesh does not work with norm='yes' + Optional graphical keywords arguments: + sizeH = 1,1.5,... increase horizontal figure size + sizeV = 1,1.5,... increase vertical figure size + marker = 'x','+','o','v','^','D',... (default:None) + markersize = 1,2,3,... (default: 5) + linewidth = 0.5,1,2... (default: 1) + linestyle = '-','--','-.',':' (default: solid '-') + color = 'r','b','m','c','g','y'... (default: jupyter colors series) + legend = 'best',Supper left', 'lower right'... (default: None) + log = 'log' (default: None = linear) + xrange = [x1,x2] (default: None = Autoscale) + yrange = [y1,y2] (default: None = Autoscale) + xlabel = 'mxLabel' (default: pv name) + ylabel = 'myLabel' (default: pv name) + ytickstyle = 'sci' for y axes (default: 'plain') + xtickstyle = 'sci' for y axes (default: 'plain') + filepath: by default plot scans for the current data folder (as defined in BL_ioc() ScanRecord SaveData) + or specified folder path: + e.g. user : filepath='/net/s29data/export/data_29idc/2018_2/UserName/mda/' + e.g. staff: filepath='/net/s29data/export/data_29idb/2018_2/mda/' + prefix: by default, uses prefix as defined in ScanRecord ("mda_") + scanIOC: by default, uses the IOC for the current branch as define in BL_IOC() + """ + + if type(ScanDet[0]) is not tuple: + ScanDet=(tuple(ScanDet),) + m=1 + else: m= len(ScanDet) + + scanlist="" + j=0 + offset=0 + for n in range(m): + print(n) + print(m) + print(ScanDet) + det=ScanDet[n][3] + if len(ScanDet)>4 and isinstance(ScanDet[n][3],str)== False: + offset=ScanDet[n][4] + for scanNum in range(ScanDet[n][0],ScanDet[n][1]+ScanDet[n][2],ScanDet[n][2]): + scanlist+=str(scanNum)+',(det,1,'+str(offset)+'),' + j+=offset + cmd="plot_mda("+scanlist + if kwArg is not None: + for key, value in list(kwArg.items()): + if type(value) == str: + cmd=cmd+(key+'=\"'+value+'\",') + else: + cmd=cmd+(key+'='+str(value)+',') + if cmd[-1]==",": + cmd=cmd[:-1] + cmd=cmd+")" + if kwArg is not None: + for key, value in list(kwArg.items()): + if key=='q': + print('det=',det) + print(cmd) + exec(cmd) + + + +def plot_mda(*ScanDet,**kwArg): + + """ + Plot mda scans: *ScanDet = (scan,det,scan,det...),(scan,det,scan,det...),title=(subplot_title1,subplot_title2) + = subplot1, subplot2 + Optional data analysis keywords arguments: + Flux conversion (for diode only): flux= 3(D## for mono rbv, typically 3). + Norm option: norm = 'yes' normalizes all the scans to 1 (default: None) + NormDet = 1 for SR current, 14 for Mesh (D-branch); Normalize by the mesh does not work with norm='yes' + DivScan = ? + Optional graphical keywords arguments: + sizeH = 1,1.5,... increase horizontal figure size + sizeV = 1,1.5,... increase vertical figure size + marker = 'x','+','o','v','^','D',... (default:None) + markersize = 1,2,3,... (default: 5) + linewidth = 0.5,1,2... (default: 1) + linestyle = '-','--','-.',':' (default: solid '-') + color = 'r','b','m','c','g','y'... (default: jupyter colors series) + legend = 'best',Supper left', 'lower right'... (default: None) + log = 'log' (default: None = linear) + xrange = [x1,x2] (default: None = Autoscale) + yrange = [y1,y2] (default: None = Autoscale) + xlabel = 'mxLabel' (default: pv name) + ylabel = 'myLabel' (default: pv name) + ytickstyle = 'sci' for y axes (default: 'plain') + xtickstyle = 'sci' for y axes (default: 'plain') + filepath: by default plot scans for the current data folder (as defined in BL_ioc() ScanRecord SaveData) + or specified folder path: + e.g. user : filepath='/net/s29data/export/data_29idc/2018_2/UserName/mda/' + e.g. staff: filepath='/net/s29data/export/data_29idb/2018_2/mda/' + prefix: by default, uses prefix as defined in ScanRecord ("mda_") + scanIOC: by default, uses the IOC for the current branch as define in BL_IOC() + """ + + args={ + 'marker':None, + 'markersize':5, + 'linewidth':1, + 'linestyle':'-', + 'color':None, + 'nticks':None, + 'sizeH':1, + 'sizeV':1, + 'title':'', + 'filepath':None, + 'prefix':None, + 'norm':None, + 'flux':None, + 'NormDet':None, + 'scanIOC':None, + 'legend':None, + 'vs_index':None, + 'vs_det':None, + 'xrange':[None,None], + 'yrange':[None,None], + 'save':True + } + + args.update(kwArg) + + mkr=args['marker'] + ms=args['markersize'] + lw=args['linewidth'] + ls=args['linestyle'] + c=args['color'] + path=args['filepath'] + prefix=args['prefix'] + scanIOC=args['scanIOC'] + save=args['save'] + + if 'legend' in args: + if args['legend'] == 'center left': + hsize=7 + + if type(ScanDet[0]) is not tuple: + ScanDet=(tuple(ScanDet),) + m=1 + else: m= len(ScanDet) + + def SubplotsLayout(m): + if m >1: + ncols=2 + else: + ncols=1 + nrows=max(sum(divmod(m,2)),1) + hsize=ncols*5*args['sizeH'] + vsize=nrows*4*args['sizeV'] + if nrows==1: vsize=nrows*3.5*args['sizeV'] + return nrows,ncols,hsize,vsize + + try: + nrows,ncols,hsize,vsize=SubplotsLayout(m) + + fig, axes = plt.subplots(nrows,ncols,figsize=(hsize,vsize)) # HxV + axes=np.array(axes) + + for (n,ax) in zip(list(range(m)),axes.flat): + for (i,j) in zip(ScanDet[n][0::2],ScanDet[n][1::2]): + if type(j) is tuple: + p,k,l=j + x,y,x_name,y_name=mda_1D(i,p,k,l,path,prefix) + elif args['flux'] is not None: + x,y,x_name,y_name=mda_Flux(i,j,args['flux'],path,prefix,scanIOC) + elif args['norm'] is not None: + x,y,x_name,y_name=mda_1D_unscaled(i,j,path,prefix,scanIOC) + elif args['NormDet'] is not None: + x,y,x_name,y_name=mda_NormDet(i,j,args['NormDet'],1,0,path,prefix,scanIOC) + elif args['vs_index'] is not None: + x,y,x_name,y_name=mda_1D_Xindex(i,j,1,0,path,prefix) + elif args['vs_det'] is not None: + x,y,x_name,y_name=mda_1D_vsDet(i,j,args['vs_det'],1,0,path,prefix) + #elif DivScan is not None: + # x,y,x_name,y_name=mda_DivScan(i,j,DivScan,DivDet,1,0,path,prefix,scanIOC) + else: + x,y,x_name,y_name=mda_1D(i,j,1,0,path,prefix,scanIOC) + ax.plot(x,y,label="mda_"+str(i),color=c,marker=mkr,markersize=ms,linewidth=lw,linestyle=ls) + ax.grid(color='lightgray', linestyle='-', linewidth=0.5) + + #modifying graph + if args['legend'] != None: + if args['legend'] == 'center left': + box = ax.get_position() + ax.set_position([box.x0, box.y0, box.width * 0.6, box.height]) + ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) + myleft=0.1 + myright=0.55 + else: + ax.legend(args['legend'], frameon=True) + if 'ytickstyle' in args: + ax.ticklabel_format(style=args['ytickstyle'], axis='y', scilimits=(0,0)) + if 'xtickstyle' in args: + ax.ticklabel_format(style=args['xtickstyle'], axis='x', scilimits=(0,0)) + if 'log' in args: + ax.set_yscale('log') + if args['xrange'] != [None,None]: + ax.set_xlim(args['xrange'][0],args['xrange'][1]) + if args['yrange'] != [None,None]: + ax.set_ylim(args['yrange'][0],args['yrange'][1]) + if 'xlabel' in args: + x_name=args['xlabel'] + if 'ylabel' in args: + y_name=args['ylabel'] + if args['nticks'] != None: + tck=args['nticks']-1 + ax.locator_params(tight=None,nbins=tck) + + + if 'title' in args: + mytitle=args['title'] + if type(mytitle) is not tuple: + ax.set(xlabel=x_name,ylabel=y_name,title=mytitle) + else: + p=len(mytitle) + if n == p: + ax.set(xlabel=x_name,ylabel=y_name,title='') + else: + ax.set(xlabel=x_name,ylabel=y_name,title=mytitle[n]) + # ax.text(0.5, 1.025,mytitle,horizontalalignment='center',fontsize=14,transform = ax.transAxes) + ax.grid(color='lightgray', linestyle='-', linewidth=0.5) + + if ncols==1 and nrows==1 and kwArg.get('legend')!='center left': + fig.subplots_adjust(wspace=0.5,hspace=0.5,left=0.25,right=0.88,top=0.85,bottom=0.22) + elif ncols==1 and kwArg.get('legend')=='center left': + fig.subplots_adjust(wspace=0.5,hspace=0.5,left=myleft,right=myright,top=0.85,bottom=0.22) + else: + fig.subplots_adjust(wspace=0.5,hspace=0.5,left=0.125,right=0.9,top=0.85,bottom=0.15) + + plt.tight_layout() + if save: + try: + fname=join('/home/beams/29IDUSER/Documents/User_Folders/','lastfigure.png') + print(fname) + plt.savefig(fname) + except: + pass + plt.show() + except: + pass + + + +def plot_mda_lists(*ScanDet,**kwArg): + """ + Plot mda scans: *ScanDet = (scanNum_list,detNum_list),(scanNum_list,detNum_list) + = subplot1, subplot2 + Optional data analysis keywords arguments: + Flux conversion (for diode only): flux= 3(User) or 25(Staff). + Norm option: norm = 'yes' normalizes all the scans to 1 (default: None) + NormDet= 1 for SR current, 14 for Mesh (D-branch); Normalize by the mesh does not work with norm='yes' + Optional graphical keywords argudef plot_mdaments: + sizeH = 1,1.5,... increase horizontal figure size + sizeV = 1,1.5,... increase vertical figure size + marker = 'x','+','o','v','^','D',... (default:None) + markersize = 1,2,3,... (default: 5) + linewidth = 0.5,1,2... (default: 1) + linestyle = '-','--','-.',':' (default: solid '-') + color = 'r','b','m','c','g','y'... (default: jupyter colors F) + legend = 'best',Supper left', 'lower right'... (default: None) + log = 'log' (default: None = linear) + xrange = [x1,x2] (default: None = Autoscale) + yrange = [y1,y2] (default: None = Autoscale) + xlabel = 'mxLabel' (default: pv name) + ylabel = 'myLabel' (default: pv name) + ytickstyle = 'sci' for y axes (default: 'plain') + xtickstyle = 'sci' for y axes (default: 'plain') + filepath: by default plot scans for the current data folder (as defined in BL_ioc() ScanRecord SaveData) + or specified folder path: + e.g. user : filepath='/net/s29data/export/data_29idc/2018_2/UserName/mda/' + e.g. staff: filepath='/net/s29data/export/data_29idb/2018_2/mda/' + prefix: by default, uses prefix as defined in ScanRecord ("mda_") + scanIOC: by default, uses the IOC for the current branch as define in BL_IOC() + """ + + args={ + 'marker':None, + 'markersize':5, + 'linewidth':1, + 'linestyle':'-', + 'color':None, + 'nticks':None, + 'sizeH':1, + 'sizeV':1, + 'title':'', + 'filepath':None, + 'prefix':None, + 'norm':None, + 'flux':None, + 'NormDet':None, + 'scanIOC':None, + 'legend':None, + 'vs_index':None, + 'xrange':[None,None], + 'yrange':[None,None] + } + + args.update(kwArg) + + mkr=args['marker'] + ms=args['markersize'] + lw=args['linewidth'] + ls=args['linestyle'] + c=args['color'] + path=args['filepath'] + prefix=args['prefix'] + scanIOC=args['scanIOC'] + + + + if 'legend' in args: + if args['legend'] == 'center left': + hsize=7 + + #setting up the subplot + if type(ScanDet[0]) is not tuple: + ScanDet=(tuple(ScanDet),) + m=1 + else: m= len(ScanDet) + + def SubplotsLayout(m): + if m >1: + ncols=2 + else: + ncols=1 + nrows=max(sum(divmod(m,2)),1) + hsize=ncols*5*args['sizeH'] + vsize=nrows*4*args['sizeV'] + if nrows==1: vsize=nrows*3.5*args['sizeV'] + return nrows,ncols,hsize,vsize + + try: + nrows,ncols,hsize,vsize=SubplotsLayout(m) + fig, axes = plt.subplots(nrows,ncols,figsize=(hsize,vsize)) # HxV + axes=np.array(axes) + + + for (n,ax) in zip(list(range(m)),axes.flat): #n=subplot tuple + scanNum_list=ScanDet[n][0] + detNum_list=ScanDet[n][1] + + if type(scanNum_list) is int: + scanNum_list=[scanNum_list] + if type(detNum_list) is int: + detNum_list=[detNum_list] + for i in range(1,len(scanNum_list)): + detNum_list.append(detNum_list[0]) + if type(args['filepath']) is not list: + filepath_list=[args['filepath']] + for i in range(1,len(scanNum_list)): + filepath_list.append(filepath_list[0]) + else: filepath_list=args['filepath'] + if type(args['prefix']) is not list: + prefix_list=[args['prefix']] + for i in range(1,len(scanNum_list)): + prefix_list.append(prefix_list[0]) + else: prefix_list=args['prefix'] + if type(args['scanIOC']) is not list: + scanIOC_list=[args['scanIOC']] + for i in range(1,len(scanNum_list)): + scanIOC_list.append(scanIOC_list[0]) + else: scanIOC_list=args['scanIOC'] + #loading the data + for index in range(0,len(scanNum_list)): + i=scanNum_list[index] + j=detNum_list[index] + path=filepath_list[index] + prefix=prefix_list[index] + scanIOC=scanIOC_list[index] + #print(i) + if type(j) is tuple: + p,k,l=j + x,y,x_name,y_name=mda_1D(i,p,k,l,path,prefix) + elif args['flux'] is not None: + x,y,x_name,y_name=mda_Flux(i,j,args['flux'],path,prefix,scanIOC) + elif args['norm'] is not None: + x,y,x_name,y_name=mda_1D_unscaled(i,j,path,prefix,scanIOC) + elif args['NormDet'] is not None: + x,y,x_name,y_name=mda_NormDet(i,j, args['NormDet'],1,0,path,prefix,scanIOC) + else: + x,y,x_name,y_name=mda_1D(i,j,1,0,path,prefix,scanIOC) + #adding to graph + ax.grid(color='lightgray', linestyle='-', linewidth=0.5) + ax.plot(x,y,label="mda_"+str(i),color=c,marker=mkr,markersize=ms,linewidth=lw,linestyle=ls) + + #modifying graph + if args['legend'] != None: + if args['legend'] == 'center left': + box = ax.get_position() + ax.set_position([box.x0, box.y0, box.width * 0.6, box.height]) + ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) + myleft=0.1 + myright=0.55 + else: + ax.legend(args['legend'], frameon=True) + if 'ytickstyle' in args: + ax.ticklabel_format(style=args['ytickstyle'], axis='y', scilimits=(0,0)) + if 'xtickstyle' in args: + ax.ticklabel_format(style=args['xtickstyle'], axis='x', scilimits=(0,0)) + if 'log' in args: + ax.set_yscale('log') + if args['xrange'] != [None,None]: + ax.set_xlim(args['xrange'][0],args['xrange'][1]) + if args['yrange'] != [None,None]: + ax.set_ylim(args['yrange'][0],args['yrange'][1]) + if 'xlabel' in args: + x_name=args['xlabel'] + if 'ylabel' in args: + y_name=args['ylabel'] + if args['nticks'] != None: + tck=args['nticks']-1 + ax.locator_params(tight=None,nbins=tck) + + if 'title' in args: + if type(args['title']) is not str: + mytitle=args['title'][n] + else: + mytitle=args['title'] + ax.set(xlabel=x_name,ylabel=y_name,title=mytitle) + #adjusting subplots + if ncols==1 and nrows==1 and kwArg.get('legend')!='center left': + fig.subplots_adjust(wspace=0.5,hspace=0.5,left=0.25,right=0.88,top=0.85,bottom=0.22) + elif ncols==1 and kwArg.get('legend')=='center left': + fig.subplots_adjust(wspace=0.5,hspace=0.5,left=myleft,right=myright,top=0.85,bottom=0.22) + else: + fig.subplots_adjust(wspace=0.5,hspace=0.5,left=0.125,right=0.9,top=0.85,bottom=0.15) + #show plot + plt.tight_layout() + plt.show() + + except: + pass + + + + +############################################################################################### +#################################### PLOT netCDF ################################### +############################################################################################### + + + + +def nc_unpack(ScanNum,FilePath=None,Prefix=None): + """ + Returns the full netCDF data file + meta data (Attributes/Exta PVs) + c.variables['Attr_EnergyStep_Swept'][:][0] + data array is accessed + nc.variables['array_data'][:][0] + + FilePath: by default plot scans for the current data folder (as shown on detector panel) + or specified folder path ending with '/': + e.g. user : FilePath='/net/s29data/export/data_29idc/2018_2/UserName/netCDF/' + e.g. staff: FilePath='/net/s29data/export/data_29idb/2018_2/netCDF/' + Prefix: by default, uses prefix as shown on detector panel ("EA_") + """ + def GetFileName(): + SubFolder= caget('29idcEA:netCDF1:FilePath',as_string=True) + if SubFolder[0]=='X': drive='b' + elif SubFolder[0]=='Y': drive='c' + FilePath='/net/s29data/export/data_29id'+drive+SubFolder[2:]+'/' + Prefix = caget("29idcEA:netCDF1:FileName_RBV",as_string=True) + return FilePath, Prefix + + if FilePath is None: + FilePath=GetFileName()[0] + if Prefix is None: + Prefix= GetFileName()[1] + myFile=FilePath+Prefix+'{:04}.nc'.format(ScanNum) + nc = Dataset(myFile,mode='r') + return nc + +def EA_data(nc): + """ Returns: x,xname,ycrop,yname,img,ActualPhotonEnergy,WorkFunction,PE + """ + + LowEnergy=nc.variables['Attr_LowEnergy'][:][0] + HighEnergy=nc.variables['Attr_HighEnergy'][:][0] + ActualPhotonEnergy=nc.variables['Attr_ActualPhotonEnergy'][:][0] + EnergyStep_Swept=nc.variables['Attr_EnergyStep_Swept'][:][0] + EnergyStep_Swept_RBV=nc.variables['Attr_EnergyStep_Swept_RBV'][:][0] + EperChannel=nc.variables['Attr_EnergyStep_Fixed_RBV'][:][0] + GratingPitch=nc.variables['Attr_GratingPitch'][:][0] + MirrorPitch=nc.variables['Attr_MirrorPitch'][:][0] + + WorkFunction=nc.variables['Attr_Energy Offset'][:][0] + + DetMode=nc.variables['Attr_DetectorMode'][:][0] # BE=0,KE=1 + AcqMode= nc.variables['Attr_AcquisitionMode'][:][0] # Swept=0, Fixed=1, BS=2 + LensMode=nc.variables['Attr_LensMode'][:][0] + + PassEnergyMode=nc.variables['Attr_PassEnergy'][:][0] + PEdict={0:1,1:2,2:5,3:10,4:20,5:50,6:100,7:200,8:500} + PE=PassEnergyMode + + #ActualPhotonEnergy,WorkFunction,PE=EA_metadata(nc)[0:3] + data = nc.variables['array_data'][:][0] + + def SelectValue(which,x1,x2): + if which == 0: value=x1 + if which == 1: value=x2 + return value + + ### Energy Scaling: + Edelta = SelectValue(DetMode,-EnergyStep_Swept,EnergyStep_Swept) + if AcqMode == 0: # Swept + Ehv=ActualPhotonEnergy + Estart = SelectValue(DetMode, Ehv-LowEnergy, LowEnergy) + #Estop = SelectValue(DetMode, Ehv-HighEnergy, HighEnergy) + if AcqMode >= 1: # Fixed or Baby Swept + Ecenter=nc.variables['Attr_CentreEnergy_RBV'][:][0] + #print nc.variables#JM was here + #print Ecenter,Edelta#JM was here + Estart=Ecenter-(data.shape[1]/2.0)*Edelta + Eunits=SelectValue(DetMode,"Binding Energy (eV)","Kinetic Energy (eV)") + + x=[Estart+Edelta*i for i,e in enumerate(data[0,:])] + xname=Eunits + + ### Angular Scaling: + if LensMode>-1: # Angular Modes RE changed from >0 (Angular) to >-1 (all mode) + CenterChannel=571 + FirstChannel=0 + Ddelta =0.0292717 + Dstart = (FirstChannel-CenterChannel)*Ddelta + y=[Dstart+Ddelta*i for i,e in enumerate(data[:,0])] + #getting rid of edges with no data + data=nc.variables['array_data'] + #x1=338;x2=819 #old + x1=338-100;x2=819-10 + datacrop=data[:,x1:x2] + ycrop=y[x1:x2] + yname='Degrees' + else: + ycrop,yname=None,'mm' + return x,xname,ycrop,yname,datacrop,ActualPhotonEnergy,WorkFunction,PE + + + + +def EA_Image(ScanNum,EnergyAxis='KE',FilePath=None,Prefix=None): + """ + Returns + x = KE or BE energy scale; BE is calculated based on the wk in the SES and the mono energy + y = Integrated intensity + + FilePath: by default plot scans for the current data folder (as shown on detector panel) + or specified folder path ending with '/': + e.g. user : FilePath='/net/s29data/export/data_29idc/2018_2/UserName/netCDF/' + e.g. staff: FilePath='/net/s29data/export/data_29idb/2018_2/netCDF/' + Prefix: by default, uses prefix as shown on detector panel ("EA_") + + x,y,img=EA_Image(1) + plt.imshow(img,extent = [min(x), max(x), min(y), max(y)], aspect = 'auto') + plt.show()) + """ + nc=nc_unpack(ScanNum,FilePath,Prefix) + x,xname,y,yname,img,hv,wk,PE=EA_data(nc) + y=np.array(y) + img=img[0] + if EnergyAxis == 'KE': + x=np.array(x) + else: + x=hv-wk-np.array(x) + return x, y, img + +def EA_Spectrum(ScanNum,EnergyAxis='KE',FilePath=None,Prefix=None): + """ + Returns + x = KE or BE energy scale; BE is calculated based on the wk in the SES and the mono energy + y = Integrated intensity + FilePath: by default plot scans for the current data folder (as shown on detector panel) + or specified folder path ending with '/': + e.g. user : FilePath='/net/s29data/export/data_29idc/2018_2/UserName/netCDF/' + e.g. staff: FilePath='/net/s29data/export/data_29idb/2018_2/netCDF/' + Prefix: by default, uses prefix as shown on detector panel ("EA_") + + Simple plot: x,y=EA_Spectrum(ScanNum);plt.plot(x,y);plt.xlim(min(x),xmax(x));plt.show() +""" + x, ang, img = EA_Image(ScanNum, EnergyAxis,FilePath,Prefix) + y = np.asarray([sum(img[:,i]) for i in range(img.shape[1])]) + return x, y + +def EA_metadata(ScanNum,FilePath=None,Prefix=None): + """ Returns: ActualPhotonEnergy,WorkFunction,GratingPitch,MirrorPitch + """ + nc=nc_unpack(ScanNum,FilePath,Prefix) + # SES parameters + LowEnergy=nc.variables['Attr_LowEnergy'][:][0] + HighEnergy=nc.variables['Attr_HighEnergy'][:][0] + EnergyStep_Swept=nc.variables['Attr_EnergyStep_Swept'][:][0] + EnergyStep_Swept_RBV=nc.variables['Attr_EnergyStep_Swept_RBV'][:][0] + EperChannel=nc.variables['Attr_EnergyStep_Fixed_RBV'][:][0] + WorkFunction=nc.variables['Attr_Energy Offset'][:][0] + DetMode=nc.variables['Attr_DetectorMode'][:][0] # BE=0,KE=1 + AcqMode= nc.variables['Attr_AcquisitionMode'][:][0] # Swept=0, Fixed=1, BS=2 + LensMode=nc.variables['Attr_LensMode'][:][0] + PassEnergyMode=nc.variables['Attr_PassEnergy'][:][0] + PEdict={0:1,1:2,2:5,3:10,4:20,5:50,6:100,7:200,8:500} + PE=PassEnergyMode + + TEY=nc.variables['Attr_TEY'][:][0] + + # Mono parameters + ActualPhotonEnergy=nc.variables['Attr_ActualPhotonEnergy'][:][0] + GratingPitch=nc.variables['Attr_GratingPitch'][:][0] + MirrorPitch=nc.variables['Attr_MirrorPitch'][:][0] + Grating_Density=nc.variables['Attr_Grating_Density'][:][0] + Grating_Slot=nc.variables['Attr_Grating_Slot'][:][0] + GRT_Offset_1=nc.variables['Attr_GRT_Offset_1'][:][0] + GRT_Offset_2=nc.variables['Attr_GRT_Offset_2'][:][0] + GRT_Offset_3=nc.variables['Attr_GRT_Offset_3'][:][0] + MIR_Offset_1=nc.variables['Attr_MIR_Offset_1'][:][0] + b2_GRT1=nc.variables['Attr_b2-GRT1'][:][0] + b2_GRT2=nc.variables['Attr_b2-GRT2'][:][0] + b2_GRT3=nc.variables['Attr_b2-GRT3'][:][0] + + offset=[MIR_Offset_1,GRT_Offset_1,GRT_Offset_2,GRT_Offset_3] + b2=[0,b2_GRT1,b2_GRT2,b2_GRT3] + + return WorkFunction,ActualPhotonEnergy,MirrorPitch,GratingPitch,Grating_Density,Grating_Slot,offset,b2 + + +def Get_EDCmax(ScanNum,EnergyAxis='KE',FilePath=None,Prefix=None): + x,y=EA_Spectrum(ScanNum, EnergyAxis,FilePath,Prefix) + maxY= max(y) + maxX=round(x[np.where(y == max(y))][0],3) + return maxX,maxY # energy position, intensity of the peak + + + +def EDC_Series(first,last,countby, EnergyAxis='BE',title="",norm=None,FilePath=None,Prefix=None): + """ + Plots a seriew of EA_Spectrum + """ + if title == "": + title="Scans: "+str(first)+"/"+str(last)+"/"+str(countby) + fig = plt.figure(figsize=(6,6)) + a1 = fig.add_axes([0,0,1,1]) + for ScanNum in range(first,last+countby,countby): + x,y=EA_Spectrum(ScanNum, EnergyAxis,FilePath,Prefix) + if norm is not None: maxvalue=max(y) + else: maxvalue=1 + plt.plot(x,y/maxvalue,label='#'+str(ScanNum)) + plt.legend(ncol=2, shadow=True, title=title, fancybox=True) + plt.grid(color='lightgray', linestyle='-', linewidth=0.5) + a1.plot + if EnergyAxis == 'BE': + a1.set_xlim(max(x),min(x)) + plt.show() + + + + +def plot_nc(*ScanNum,**kwgraph): + """ + ScanNum = Scan number to be plotted: single scan, or range (first,last,countby) to average. + kwgraph = EDC / FilePath / Prefix + - Transmission mode: angle integrated EDC. + - Angular mode: + default: band map only + EDC = 'y' : angle integrated EDC only + EDC = 'both': angle integrated EDC + band map + EnergyAxis = KE (default) or BE (BE uses work function from SES) + FilePath: by default plot scans for the current data folder (as shown on detector panel) + or specified folder path ending with '/': + e.g. user : FilePath='/net/s29data/export/data_29idc/2018_2/UserName/netCDF/' + e.g. staff: FilePath='/net/s29data/export/data_29idb/2018_2/netCDF/' + Prefix: by default, uses prefix as shown on detector panel ("EA_") + + """ + FilePath,Prefix,EDC,EnergyAxis,avg=None,None,None,'KE',None + if kwgraph is not None: + for key, value in list(kwgraph.items()): + if key=='FilePath': FilePath=value + if key=='Prefix': Prefix=value + if key=='EDC': EDC=value + if key=='EnergyAxis': EnergyAxis=value + if key=='avg': avg=1 + #Get lens mode + nc=nc_unpack(ScanNum[0],FilePath,Prefix) + LensMode=nc.variables['Attr_LensMode'][:][0] + #Loading Scans () + first=ScanNum[0] + if len(ScanNum)==1: + last =ScanNum[0] + countby=1 + else: + last=ScanNum[1] + countby=ScanNum[2] + for n in range(first,last+countby,countby): + x,intensity=EA_Spectrum(n,EnergyAxis,FilePath,Prefix) + x,y,img =EA_Image(n,EnergyAxis,FilePath,Prefix) + if n == first: + Spectra=intensity + Img=img + else: + if avg == 1: #Summing the Scans + print('averaging') + Spectra=np.add(Spectra, intensity) + Img=np.add(Img,img) + + #Getting plot size + if LensMode == 0 or EDC != None and EDC != 'both': #Integrated Angle only + hsize,vsize=6,3.5 + elif LensMode >0 and EDC == None: + hsize,vsize=6,4 + elif LensMode >0 and EDC == 'both': + hsize,vsize=6,8 + if kwgraph is not None: + for key, value in list(kwgraph.items()): + if key=='hsize': hsize=value + if key=='vsize': vsize=value + #plotting\ + if LensMode == 0 or EDC != None and EDC != 'both': #Integrated Angle only + #print('p-DOS only') + fig, ax = plt.subplots(figsize=(hsize,vsize)) # HxV + ax.plot(x,Spectra) + if EnergyAxis == "BE": + ax.set_xlim(max(x),min(x)) + else: + ax.set_xlim(min(x),max(x)) + ax.set(xlabel=EnergyAxis,ylabel='Intensity') + ax.ticklabel_format(style='sci', axis='y', scilimits=(0,0)) + ax.grid(color='lightgray', linestyle='-', linewidth=0.5) + elif LensMode >0 and EDC is None: #Imgage Only + #print('Image Only') + fig, ax = plt.subplots(figsize=(hsize,vsize)) # HxV + if EnergyAxis == 'BE': + fig=ax.imshow(Img,extent = [max(x), min(x), min(y), max(y)], aspect = 'auto') + else: + fig=ax.imshow(Img,extent = [min(x), max(x), min(y), max(y)], aspect = 'auto') + ax.set(xlabel=EnergyAxis,ylabel="Angle") + elif LensMode >0 and EDC == 'both': + #print('both') + fig, axes = plt.subplots(2,1,figsize=(hsize,vsize)) # HxV + axes=np.array(axes) + for (n,ax) in zip(list(range(2)),axes.flat): + if n == 0: + ax.ticklabel_format(style='sci', axis='y', scilimits=(0,0)) + ax.grid(color='lightgray', linestyle='-', linewidth=0.5) + ax.plot(x,Spectra) + if EnergyAxis == "BE": + ax.set_xlim(max(x),min(x)) + else: + ax.set_xlim(min(x),max(x)) + ax.set(xlabel=EnergyAxis,ylabel='Intensity') + if n == 1: + if EnergyAxis == 'BE': + ax.imshow(Img,extent = [max(x), min(x), min(y), max(y)], aspect = 'auto') + else: + ax.imshow(Img,extent = [min(x), max(x), min(y), max(y)], aspect = 'auto') + ax.set(xlabel=EnergyAxis,ylabel='Angle') + plt.tight_layout() + plt.show() + + +def plot_nc_Sum(first,last,**kwgraph): + + FilePath,Prefix=None,None + if kwgraph is not None: + for key, value in list(kwgraph.items()): + if key=='FilePath': FilePath=value + if key=='Prefix': Prefix=value + for n in range(first,last+1): + print(n) + nc=nc_unpack(n,FilePath,Prefix) + x,xname,ycrop,yname,img,hv,wk,PE=EA_data(nc) + LensMode=nc.variables['Attr_LensMode'][:][0] + if n == first: + datasum = nc.variables['array_data'] + x,xname,ycrop,yname,img,hv,wk,PE=EA_data(nc) + else: + data = nc.variables['array_data'] + tmp=datasum + datasum=np.add(tmp,data) + crop_data=data[:,338:819] + fig, ax = plt.subplots(figsize=(6,4)) # HxV + fig=ax.imshow(crop_data.squeeze(),extent = [min(x), max(x), min(ycrop), max(ycrop)], aspect = 'auto') + plt.show() + + + + + + + + + + + +############################################################################################### +##################################### FR curves fitting ####################################### +############################################################################################### + + +def fit_mda(scannum,det,FWHM_or_PolyOrder,fct,hkl_positionner=False,xrange=None,title='',marker='x',graph=True, filepath=None,prefix=None): + """ + fct= 'gauss','lorz','erf','poly','box' + hkl_positionner = 'H','K','L','tth','th','chi','phi' + """ + + if hkl_positionner == False: + x,y,x_name,y_name=mda_1D(scannum,det,1,0,filepath,prefix) + if hkl_positionner: + d={'h':46,'k':47,'l':48,'tth':54,'th':55,'chi':56,'phi':57} + x,y,x_name,y_name=mda_1D_vsDet(scannum,det,d[hkl_positionner.lower()],1,0,filepath,prefix) + + + + if BL.endstation == 'Kappa' and fct != 'poly': + try: + title=title + ' centroid = '+str(centroid_avg(scannum)) + except: + pass + + def closest(lst, K): + return lst[min(range(len(lst)), key = lambda i: abs(lst[i]-K))] + + def gaussian(x,*p): + amp, cen, wid, bkgd = p + return bkgd+amp*np.exp(-np.power(x - cen, 2.) / (2 * np.power(wid, 2.))) + + def lorentzian( x, *p): + amp, x0, gam, bkgd =p + return bkgd+amp * gam**2 / ( gam**2 + ( x - x0 )**2) + + def step(z,amp=1,bkgd=0,z0=0,width=1): + return (amp*erf((z-z0)/width))+bkgd + + def box(x, *p): + height, center, width ,bkgd = p + return bkgd+height*(center-width/2 < x)*(x < center+width/2) + + + + if xrange is not None: + x1=closest(x,xrange[0]) + x2=closest(x,xrange[1]) + xrange=[x.index(x1),x.index(x2)] + xmin=min(xrange) + xmax=max(xrange) + xcrop=x[xmin:xmax] + ycrop=y[xmin:xmax] + xdata = np.array(xcrop) + ydata = np.array(ycrop) + else: + xdata = np.array(x) + ydata = np.array(y) + + + Imax=np.max(ydata) + #print(xdata) + #print(ydata) + x0=xdata[np.where(ydata==Imax)][0] + A0=xdata[0] + + nPt_fit=200 + xfit = np.linspace(min(x),max(x), nPt_fit) + + + if fct == 'gauss': + FWHM=FWHM_or_PolyOrder + best_vals, covar = curve_fit(gaussian, xdata, ydata, p0=[Imax, x0, FWHM, A0]) #5 p0=[amp,cen,wid] + yfit=gaussian(xfit,*best_vals) + FWHM=2.355*best_vals[2] + center=best_vals[1] + print('Amplitude: ',best_vals[0]) + elif fct == 'lorz': + FWHM=FWHM_or_PolyOrder + best_vals, covar = curve_fit(lorentzian, xdata, ydata, p0=[Imax, x0, FWHM, A0]) #5 p0=[amp,cen,wid] + yfit=lorentzian(xfit,*best_vals) + FWHM=2.355*best_vals[2] + center=best_vals[1] + print('Amplitude: ',best_vals[0]) + elif fct == 'erf' or fct == 'box': + FWHM=FWHM_or_PolyOrder + xmax=np.max(xdata) + xmin=np.min(xdata) + amp=np.mean(ydata) + x0=np.mean(xdata) + ymin=np.min(ydata) + if fct == 'erf': + yfirst=ydata[np.where(xdata == xmin)][0] + ylast =ydata[np.where(xdata == xmax)][0] + if yfirst-ylast >0: amp=-abs(amp) #amp <0 step down + else: amp = abs(amp) #amp >0 step up + p0=[amp, ymin, x0, FWHM] + popt,pcor = curve_fit(step, xdata, ydata, p0=p0) + yfit=step(xfit,*popt) + FWHM=popt[3] + center=popt[2] + elif fct == 'box': + p0=[amp, x0, FWHM, A0] + popt,pcor = curve_fit(box, xdata, ydata, p0=p0) + yfit=box(xfit,*popt) + FWHM=popt[2] + center=popt[1] + elif fct == 'poly': + PolyRank=FWHM_or_PolyOrder + coefs = poly.polyfit(xdata, ydata, PolyRank) + yfit = poly.polyval(xfit, coefs) + result='' + for i in list(range(len(coefs))): + result=result+'a'+str(i)+' = '+str(round(coefs[i],3))+'\n' + print(result) + center=coefs + + if fct != 'poly': + print('Center: ',center) + print('FWHM: ',FWHM) + print('\n') + + + if graph == True: + center=round(center,4) + fig,(ax1)=plt.subplots(1,1) + fig.set_size_inches(5,4) + ax1.plot(xdata,ydata,label='mda #'+str(scannum),marker=marker) + ax1.plot(xfit,yfit,label='fit @ '+str(center)[0:6]) + ax1.set(ylabel=y_name) + ax1.set(xlabel=x_name) + ax1.ticklabel_format(style='sci', axis='y', scilimits=(0,0)) + ax1.grid(color='lightgray', linestyle='-', linewidth=0.5) + ax1.legend(shadow=True, title=title, fancybox=True) + + return center + + +def fit_centroid(n): + fit_mda(n,25,0,'poly',graph=False) + +def centroid_avg(scannum,det=25): # det = detector number for centroid position + avg=round(fit_mda_poly(scannum,det,0,graph=None)[0],2) + return avg + + +def fit_mda_gauss(scannum,det,FWHM,xrange=None,title='',marker='x',graph=1, filepath=None,prefix=None,scanIOC=None): + fct='gauss' + fit_mda(scannum,det,FWHM,fct,xrange,title,marker,graph, filepath,prefix,scanIOC) + + +def fit_mda_lorz(scannum,det,FWHM,xrange=None,title='',marker='x',graph=1, filepath=None,prefix=None,scanIOC=None): + fct='lorz' + fit_mda(scannum,det,FWHM,fct,xrange,title,marker,graph, filepath,prefix,scanIOC) + + +def fit_mda_erf(scannum,det,FWHM,xrange=None,title='',marker='x',graph=1, filepath=None,prefix=None,scanIOC=None): + fct='erf' + fit_mda(scannum,det,FWHM,fct,xrange,title,marker,graph, filepath,prefix,scanIOC) + +def fit_mda_poly(scannum,det,PolyRank,xrange=None,title='',marker='x',graph=1, filepath=None,prefix=None,scanIOC=None): + fct='poly' + fit_mda(scannum,det,PolyRank,fct,xrange,title,marker,graph, filepath,prefix,scanIOC) + + +def fit_mda_box(scannum,det,FWHM,xrange=None,title='',marker='x',graph=1, filepath=None,prefix=None,scanIOC=None): + fct='box' + fit_mda(scannum,det,FWHM,fct,xrange,title,marker,graph, filepath,prefix,scanIOC) + + + + + + + + +############################################################################################### +######################################### hkl ################################### +############################################################################################### + + + +def plot_hkl(mydata,n,x,y,title='',nlabel=''): + """mydata = instance of mdaFile object + n = scan number or [scan number1, ..., scan number N] + x = h, k or l index (D##) + d = detector index (D##) + """ + if type(n) == int: + maxpts=mydata.dim1[n].curr_pt + x_index=mydata.dim1[n].kappaDet()[x][0] + y_index=mydata.dim1[n].kappaDet()[y][0] + x_name =mydata.dim1[n].d[x_index].desc + y_name =mydata.dim1[n].kappaDet()[y][2] + plt.plot(mydata.dim1[n].d[x_index].data[:maxpts],mydata.dim1[n].d[y_index].data[:maxpts],label='scan #'+str(n)+' '+nlabel) + elif type(n) == list: + for i,j in enumerate(n): + maxpts=mydata.dim1[j].curr_pt + x_index=mydata.dim1[j].kappaDet()[x][0] + y_index=mydata.dim1[j].kappaDet()[y][0] + x_name =mydata.dim1[j].d[x_index].desc + y_name =mydata.dim1[j].kappaDet()[y][2] + try: + curve_label='scan #'+str(j)+' '+nlabel[i] + except: + curve_label='scan #'+str(j) + plt.plot(mydata.dim1[j].d[x_index].data[:maxpts],mydata.dim1[j].d[y_index].data[:maxpts],label=curve_label) + else: + print('n must be a single scan (int) or a list of scan') + return + plt.xlabel(x_name) + plt.ylabel(y_name) + plt.locator_params(tight=None,nbins=5,axis='x') + plt.legend(ncol=1, shadow=True, title=title, fancybox=True,loc='center left', bbox_to_anchor=(1, 0.5)) + plt.grid(color='lightgray', linestyle='-', linewidth=0.5) + plt.show() + + +def fit_hkl(mydata,n,pos,det,FWHM,fct='gauss',xrange=None,title='',marker='x',graph=1): + """ + mydata = instance of the class mdaFile + n = scan number + pos = D## for positioner + det = D## for detector + FWHM = width estimate + fct = 'gauss' or 'lorz' + xrange = [x1,x2] subrange for fit + """ + + + x_index=mydata.dim1[n].kappaDet()[pos][0] + y_index=mydata.dim1[n].kappaDet()[det][0] + x_name =mydata.dim1[n].d[x_index].desc + y_name =mydata.dim1[n].kappaDet()[det][2] + + x=mydata.dim1[n].d[x_index].data + y=mydata.dim1[n].d[y_index].data + + def closest(lst, K): + return lst[min(range(len(lst)), key = lambda i: abs(lst[i]-K))] + + if xrange is not None: + x1=closest(x,xrange[0]) + x2=closest(x,xrange[1]) + xrange=[np.where(x==x1),np.where(x==x2)] + xmin=min(xrange) + xmax=max(xrange) + xmin=min(xrange[0][0]) + xmax=max(xrange[1][0]) + xcrop=x[xmin:xmax] + ycrop=y[xmin:xmax] + xdata = np.array(xcrop) + ydata = np.array(ycrop) + else: + xdata = np.array(x) + ydata = np.array(y) + + Imax=np.max(ydata) + x0=xdata[np.where(ydata==Imax)][0] + + nPt_gaus=200 + xfit = np.linspace(min(x),max(x), nPt_gaus) + + + def lorentzian( x, amp, x0, gam ): + return amp * gam**2 / ( gam**2 + ( x - x0 )**2) + + def gaussian(x, amp, cen, wid): + return amp*np.exp(-np.power(x - cen, 2.) / (2 * np.power(wid, 2.))) + + if fct == 'gauss': + best_vals, covar = curve_fit(gaussian, xdata, ydata, p0=[Imax, x0, FWHM]) #5 p0=[amp,cen,wid] + yfit=gaussian(xfit,*best_vals) + elif fct == 'lorz': + best_vals, covar = curve_fit(lorentzian, xdata, ydata, p0=[Imax, x0, FWHM]) #5 p0=[amp,cen,wid] + yfit=lorentzian(xfit,*best_vals) + else: + print('Not a valid function: fct = "gauss" or fct = "lorz"') + return + + FWHM=2.355*best_vals[2] + center=best_vals[1] + print('Amplitude: ',best_vals[0]) + print('Center: ',center) + print('FWHM: ',FWHM) + + if graph is not None: + fig,(ax1)=plt.subplots(1,1) + fig.set_size_inches(5,4) + ax1.plot(xdata,ydata,label='data',marker=marker) + ax1.plot(xfit,yfit,label='fit @ '+str(center)[0:6]) + ax1.set(ylabel=y_name) + ax1.set(xlabel=x_name) + ax1.locator_params(tight=None,nbins=5,axis='x') + ax1.ticklabel_format(style='sci', axis='y', scilimits=(0,0)) + ax1.grid(color='lightgray', linestyle='-', linewidth=0.5) + ax1.legend(shadow=True, title=title, fancybox=True) + + return center + + +def fit_d4(n=BL.mda.lastFileNum()): + d4=fit_mda(n,34,0.1,'gauss',title='mda_'+str(n).zfill(4)) + return round(d4,3) + +def fit_d3(n=BL.mda.lastFileNum()): + d3=fit_mda(n,33,3,'gauss',title='mda_'+str(n).zfill(4)) + return round(d3,3) + +def fit_z(n=BL.mda.lastFileNum(),d=33): + z=fit_mda(n,d,500,'erf',title='mda_'+str(n).zfill(4)) + return round(z,0) + +def plotd(): + dets=[34,33,35] + n=BL.mda.lastFileNum() + d=dets[caget('29idKappa:det:set')] + plot_mda(n,d,title='mda_'+str(n).zfill(4)) + + + +def Find_kth_zero(th_0,th_180): + """ + th_0 is the motor position for specular near zero + th_180 is motor position for spectular near 180 + """ + + Offset =0.5*(180 - th_180 - th_0) + + print("with motor at 0, the actual value is ",Offset) + + +# def read_hkl_old(n,user=None,run=None): +# h=[] +# k=[] +# l=[] +# if user is None: user=MDA_CurrentUser() +# if run is None: run=MDA_CurrentRun() +# with open('/home/beams/29IDUSER/Documents/User_Folders/'+user+'/hkl/scan_'+str(n)+'.txt') as csv_file: +# csv_f=csv.reader(csv_file,delimiter=',') +# for row in csv_f: +# if not row[0]=='h': +# h.append(float(row[0])) +# k.append(float(row[1])) +# l.append(float(row[2])) +# return np.array(h), np.array(k), np.array(l) + +# def plot_hkl_old(mydata,n1,n2=None,which='h',det=39,cropMin=None,cropMax=None,title=''): +# D=mydata.kappaDet(n1) +# d=D[det][1] +# if which == 'h': +# m = 0 +# if which == 'k': +# m = 1 +# if which == 'l': +# m = 2 + +# plt.figure(num=None, figsize=(6, 6), dpi=80, facecolor='w', edgecolor='k') +# if n2 == None: +# n=n1 +# #dif=len(read_hkl(n)[m])-mydata.dim1[n].curr_pt +# if cropMax is not None: +# x=read_hkl(n)[m][cropMin:-cropMax] +# else: +# x=read_hkl(n)[m][cropMin:] + +# plt.plot(x,mydata.dim1[n].d[d].data,label='scan #'+str(n),marker='+') +# else: +# for n in range(n1,n2+1): +# #dif=len(read_hkl(n)[m])-mydata.dim1[n].curr_pt +# if cropMax is not None: +# x=read_hkl(n)[m][cropMin:-cropMax] +# else: +# x=read_hkl(n)[m][cropMin:] + +# plt.plot(x,mydata.dim1[n].d[d].data,label='scan #'+str(n),marker='+') +# plt.xlabel(which) +# plt.ylabel(D[det][-1]) +# plt.legend(ncol=1, shadow=True, title=title, fancybox=True,loc='center left', bbox_to_anchor=(1, 0.5)) +# #plt.title(title) +# plt.grid(color='lightgray', linestyle='-', linewidth=0.5) +# plt.show() + + + +# def fit_hkl_gauss_old(scannum,det,FWHM,which='l',cropMin=None,cropMax=None,xrange=None,title='',marker='x',graph=1): +# motor,y,motor_name,y_name=mda_1D(scannum,det,1,0) +# if which == 'h': +# m = 0 +# if which == 'k': +# m = 1 +# if which == 'l': +# m = 2 +# if cropMax is not None: +# x=read_hkl(scannum)[m][cropMin:-cropMax] +# else: +# x=read_hkl(scannum)[m][cropMin:] +# def closest(lst, K): +# return lst[min(range(len(lst)), key = lambda i: abs(lst[i]-K))] + +# if xrange is not None: +# x1=closest(x,xrange[0]) +# x2=closest(x,xrange[1]) +# xrange=[np.where(x==x1),np.where(x==x2)] +# xmin=min(xrange) +# xmax=max(xrange) +# xmin=min(xrange[0][0]) +# xmax=max(xrange[1][0]) +# xcrop=x[xmin:xmax] +# ycrop=y[xmin:xmax] +# xdata = np.array(xcrop) +# ydata = np.array(ycrop) +# else: +# xdata = np.array(x) +# ydata = np.array(y) + +# Imax=np.max(ydata) +# x0=xdata[np.where(ydata==Imax)][0] + +# nPt_gaus=200 +# xfit = np.linspace(min(x),max(x), nPt_gaus) + +# def gaussian(x, amp, cen, wid): +# return amp*np.exp(-np.power(x - cen, 2.) / (2 * np.power(wid, 2.))) + +# best_vals, covar = curve_fit(gaussian, xdata, ydata, p0=[Imax, x0, FWHM]) #5 p0=[amp,cen,wid] +# yfit=gaussian(xfit,*best_vals) +# FWHM=2.355*best_vals[2] +# center=best_vals[1] +# print('Amplitude: ',best_vals[0]) +# print('Center: ',center) +# print('FWHM: ',FWHM) + +# if graph is not None: +# fig,(ax1)=plt.subplots(1,1) +# fig.set_size_inches(5,4) +# ax1.plot(xdata,ydata,label='data',marker=marker) +# ax1.plot(xfit,yfit,label='fit @ '+str(center)[0:6]) +# ax1.set(ylabel=y_name) +# ax1.set(xlabel=which) +# ax1.ticklabel_format(style='sci', axis='y', scilimits=(0,0)) +# ax1.grid(color='lightgray', linestyle='-', linewidth=0.5) +# ax1.legend(shadow=True, title=title, fancybox=True) + +# return center + + +############################################################################################### +######################################### Start Of The Week ################################### +############################################################################################### + +def plot_StartOfTheWeek_DetDict(branch): + """ + returns the detectors for a given branch + + """ + DetDict={'c':(9,7,8,15),'d':(9,7,8,14)} + return DetDict[branch] + +def StartOfTheWeek_plot(branch,FirstScanNum,**kwargs): + """ + Plots the data from StartOfTheWeek + + branch is used to set the detectors + detCA4,detH,detV,detDiode=plot_StartOfTheWeek_Det(branch) + + FirstScanNum is based on slit1A + slit1A-H = FirstScanNum + slit1A-V = FirstScanNum + 1 + wire1-H = FirstScanNum + 2 + wire1-V = FirstScanNum + 3 + monoVslit = FirstScanNum + 4/5/6/7 + flux = FirstScanNum + 8 + + Slit 1A and Wire scans: determine ID steering and Slit1A position + Scan_MonoVsSlit: determine the steering from M0/M1 + by default the full range is plotted (pnt_first=0, pnt_last=inf) + refine the plot via + plot_StartOfTheWeek_mono(branch,FirstScanNum,pnt_first,pnt_last) + + kwargs: + filepath = None, uses current mda filepath unless specified + e.g. user : filepath='/net/s29data/export/data_29idc/2018_2/UserName/mda/' + e.g. staff: filepath='/net/s29data/export/data_29idb/2018_2/mda/' + prefix = None, uses current mda prefix unless specified + scanIOC = None, uses BL_ioc() unless specified + + scanType = ['slit1','wire','flux','monoVslit'], full set by default + + ref_firstScanNum to plot reference spectra + ref_branch = branch, unless specified + ref_filepath = filepath, unless specified + ref_prefix = prefix, unless specified + + steering out => moves beam more positive (20 urad ~ 0.5 mm) + steering up => moves beam more positive (20 urad ~ 0.5 mm) + +figure, axes = plt.subplots(nrows=2, ncols=2) +axes[0, 0].plot(x, y) + """ + + kwargs.setdefault('filepath',BL.mda.filepath()) + kwargs.setdefault('prefix',BL.mda.prefix()) + + kwargs.setdefault('scanType',['slit1','wire','flux','monoVslit']) + + kwargs.setdefault('ref_firstScanNum',None) + kwargs.setdefault('ref_fpath',None) + kwargs.setdefault('ref_branch',branch) + kwargs.setdefault('ref_filepath',BL.mda.filepath()) + kwargs.setdefault('ref_prefix',BL.mda.prefix()) + + kwargs.setdefault('debug',False) + + + scanNum=FirstScanNum + ref_firstScanNum=kwargs['ref_firstScanNum'] + detCA4,detH,detV,detDiode=plot_StartOfTheWeek_DetDict(branch) + + + if 'slit1' in kwargs['scanType']: + if kwargs['debug']: + print('slit1') + plot_StartOfTheWeek_slit1A(branch,scanNum,**kwargs) + scanNum+=2 + if kwargs['ref_firstScanNum'] is not None: + kwargs.update({'ref_firstScanNum':ref_firstScanNum+2}) + + + if 'wire' in kwargs['scanType']: + if kwargs['debug']: + print('wire') + plot_StartOfTheWeek_wire(branch,scanNum,**kwargs) + scanNum+=2 + if kwargs['ref_firstScanNum'] is not None: + ref_firstScanNum+=2 + kwargs.update({'ref_firstScanNum':ref_firstScanNum+2}) + + if 'monoVslit' in kwargs['scanType']: + d=IEXdata(scanNum,path=kwargs['filepath'],prefix=kwargs['prefix'],q=1) + if d.mda[scanNum].header.all['rank']<2: #quick + print(scanNum, detDiode) + V2=fit_mda(scanNum,detDiode,1,'gauss',filepath=kwargs['filepath'],prefix=kwargs['prefix'],scanIOC=kwargs['scanIOC'],title='2V - mda_'+str(scanNum)) + H2=fit_mda(scanNum+1,detDiode,1,'gauss',filepath=kwargs['filepath'],prefix=kwargs['prefix'],scanIOC=kwargs['scanIOC'],title='2H - mda_'+str(scanNum+1)) + V1=fit_mda(scanNum+2,detDiode,1,'gauss',filepath=kwargs['filepath'],prefix=kwargs['prefix'],scanIOC=kwargs['scanIOC'],title='1V - mda_'+str(scanNum+2)) + H1=fit_mda(scanNum+3,detDiode,1,'gauss',filepath=kwargs['filepath'],prefix=kwargs['prefix'],scanIOC=kwargs['scanIOC'],title='1H - mda_'+str(scanNum+3)) + plt.show() + print('\nFit positions:') + print(f"V2={round(V2,3)}") + print(f"H2={round(H2,3)}") + print(f"V1={round(V1,3)}") + print(f"H1={round(H1,3)}") + + else: #MonoVsSlit + print('\n# To plot the Mono vs Slit data use:\n') + print('\tplot_MonoVsSlit(\"'+branch+'\",'+str(scanNum)+','+str(detDiode)+',0,inf)'+'\t#2V') + print('\tplot_MonoVsSlit(\"'+branch+'\",'+str(scanNum+1)+','+str(detDiode)+',0,inf)'+'\t#2H') + print('\tplot_MonoVsSlit(\"'+branch+'\",'+str(scanNum+2)+','+str(detDiode)+',0,inf)'+'\t#1V') + print('\tplot_MonoVsSlit(\"'+branch+'\",'+str(scanNum+3)+','+str(detDiode)+',0,inf)'+'\t#1H') + print('\n# (pnt_first,pnt_last0=(0,inf) => plots all') + print('# select specific first/last to refine.') + + print('\nREMEMBER to update slit center using: \tupdate_slit_dict()' ) + scanNum+=4 + if kwargs['ref_firstScanNum'] is not None: + kwargs.update({'ref_firstScanNum':ref_firstScanNum+4}) + + if 'flux' in kwargs['scanType']: + if kwargs['debug']: + print('flux') + plot_StartOfTheWeek_flux(branch,scanNum,**kwargs) + +def plot_StartOfTheWeek_slit1A(branch,scanNum,**kwargs): + """ + plots the slit1A scans + scanNum = slit1A-H scanNum + """ + kwargs.setdefault('filepath',BL.mda.filepath()) + kwargs.setdefault('prefix',BL.mda.prefix()) + kwargs.setdefault('plotType',['slit1','wire','flux','monoVslit']) + kwargs.setdefault('ref_firstScanNum',None) + kwargs.setdefault('ref_fpath',None) + kwargs.setdefault('ref_branch',branch) + kwargs.setdefault('ref_filepath',BL.mda.filepath()) + kwargs.setdefault('ref_prefix',BL.mda.prefix()) + kwargs.setdefault('debug',False) + + detCA4,detH,detV,detDiode=plot_StartOfTheWeek_DetDict(branch) + ref_detCA4,ref_detH,ref_detV,ref_detDiode=plot_StartOfTheWeek_DetDict(kwargs['ref_branch']) + + figure, axes = plt.subplots(nrows=1, ncols=2,figsize=(10,3)) + for i,t in enumerate(['1H center scan','1V center scan']): + d=IEXdata(scanNum,path=kwargs['filepath'],prefix=kwargs['prefix'],q=1) + axes[i].plot(d.mda[scanNum].det[detCA4].scale['x'], d.mda[scanNum].det[detCA4].data,marker='x',label=str(scanNum)) + scanNum+=1 + if kwargs['ref_firstScanNum'] is not None: + ref_scanNum=kwargs['ref_firstScanNum']+i + ref_d=IEXdata(ref_scanNum,path=kwargs['ref_filepath'],prefix=kwargs['ref_prefix'],q=1) + axes[i].plot(ref_d.mda[ref_scanNum].det[ref_detCA4].scale['x'], ref_d.mda[ref_scanNum].det[ref_detCA4].data,marker='x',label=str(ref_scanNum)) + axes[i].grid(color='lightgray', linestyle='-', linewidth=0.5) + axes[i].title.set_text(t) + axes[i].legend() + plt.show() + print("\nsteering out => move beam more positive (10 urad ~ 0.25 mm)") + print("steering up => move beam more positive (10 urad ~ 0.25 mm)") + print("\nTo fit beam position use:\n") + print("detCA4,detH,detV,detDiode=plot_StartOfTheWeek_DetDict('"+kwargs['ref_branch']+"')") + print("fit_mda("+str(scanNum-2)+",detCA4,1,'gauss',xrange=(-1,1))") + print("fit_mda("+str(scanNum-1)+",detCA4,1,'gauss',xrange=(-1,1))\n") + + +def plot_StartOfTheWeek_wire(branch,scanNum,**kwargs): + """ + plots the wire scans + scanNum = wire-H scanNum + """ + kwargs.setdefault('filepath',BL.mda.filepath()) + kwargs.setdefault('prefix',BL.mda.prefix()) + kwargs.setdefault('plotType',['slit1','wire','flux','monoVslit']) + kwargs.setdefault('ref_firstScanNum',None) + kwargs.setdefault('ref_fpath',None) + kwargs.setdefault('ref_branch',branch) + kwargs.setdefault('ref_filepath',BL.mda.filepath()) + kwargs.setdefault('ref_prefix',BL.mda.prefix()) + kwargs.setdefault('debug',False) + + detCA4,detH,detV,detDiode=plot_StartOfTheWeek_DetDict(branch) + ref_detCA4,ref_detH,ref_detV,ref_detDiode=plot_StartOfTheWeek_DetDict(kwargs['ref_branch']) + + figure, axes = plt.subplots(nrows=1, ncols=2,figsize=(10,3)) + for i,t in enumerate(['H-wire','V-wire']): + d=IEXdata(scanNum,path=kwargs['filepath'],prefix=kwargs['prefix'],q=1) + #niceplot(d.mda[scanNum].det[DetDict[branch][1+i]],marker='x',label=str(scanNum)) + detNum=plot_StartOfTheWeek_DetDict(branch)[1+i] + axes[i].plot(d.mda[scanNum].det[detNum].scale['x'], d.mda[scanNum].det[detNum].data,marker='x',label=str(scanNum)) + scanNum+=1 + if kwargs['ref_firstScanNum'] is not None: + ref_scanNum=kwargs['ref_firstScanNum']+i + ref_d=IEXdata(ref_scanNum,path=kwargs['ref_filepath'],prefix=kwargs['ref_prefix'],q=1) + #niceplot(ref_d.mda[ref_scanNum].det[DetDict[kwargs["ref_branch"]][1+i]],marker='x',label=str(ref_scanNum)) + detNum=plot_StartOfTheWeek_DetDict(kwargs["ref_branch"])[1+i] + axes[i].plot(ref_d.mda[ref_scanNum].det[detNum].scale['x'], ref_d.mda[ref_scanNum].det[detNum].data,marker='x',label=str(ref_scanNum)) + axes[i].grid(color='lightgray', linestyle='-', linewidth=0.5) + axes[i].title.set_text(t) + axes[i].legend() + plt.show() + +def plot_StartOfTheWeek_flux(branch,scanNum,**kwargs): + """ + plots the wire scans + scanNum = wire-H scanNum + """ + kwargs.setdefault('filepath',BL.mda.filepath()) + kwargs.setdefault('prefix',BL.mda.prefix()) + kwargs.setdefault('plotType',['slit1','wire','flux','monoVslit']) + kwargs.setdefault('ref_firstScanNum',None) + kwargs.setdefault('ref_fpath',None) + kwargs.setdefault('ref_branch',branch) + kwargs.setdefault('ref_filepath',BL.mda.filepath()) + kwargs.setdefault('ref_prefix',BL.mda.prefix()) + kwargs.setdefault('debug',False) + + detCA4,detH,detV,detDiode=plot_StartOfTheWeek_DetDict(branch) + ref_detCA4,ref_detH,ref_detV,ref_detDiode=plot_StartOfTheWeek_DetDict(kwargs['ref_branch']) + + for t in ['ID peak @ 500eV']: + d=IEXdata(scanNum,path=kwargs['filepath'],prefix=kwargs['prefix'],q=1) + niceplot(d.mda[scanNum].det[detDiode],marker='x',label=str(scanNum)) + scanNum+=1 + if kwargs['ref_firstScanNum'] is not None: + ref_scanNum=kwargs['ref_firstScanNum']+2 + ref_d=IEXdata(ref_scanNum,path=kwargs['ref_filepath'],prefix=kwargs['ref_prefix'],q=1) + niceplot(ref_d.mda[ref_scanNum].det[ref_detDiode],marker='x',label=str(ref_scanNum)) + ref_scanNum+=1 + plt.grid(color='lightgray', linestyle='-', linewidth=0.5) + plt.title(t) + plt.legend() + plt.show() + +def plot_MonoVsSlit(branch,ScanNum,detDiode,pnt_first,pnt_last,norm=True,filepath=None,prefix=None,scanIOC=None): + """ + Plots Scan_MonoVsSlit to determine the steering from M0/M1 + To plot the full range (pnt_first=0, pnt_last=inf) + plot_StartofWeek_mono(branch,FirstScanNum+4,pnt_first,pnt_last) + + filepath: by default plot scans for the current data folder (as defined in BL_ioc() ScanRecord SaveData) + or specified folder path ending with '/': + e.g. user : filepath='/net/s29data/export/data_29idc/2018_2/UserName/mda/' + e.g. staff: filepath='/net/s29data/export/data_29idb/2018_2/mda/' + prefix: by default, uses prefix as defined in ScanRecord ("mda_") + """ + x,y,z,x_name,y_name,z_name=mda_2D(ScanNum,detDiode,filepath,prefix,scanIOC) + Which=str(y_name)[10:12] + if pnt_last is inf: + pnt_last=len(z)-1 + for i in range(pnt_first,pnt_last+1): + maxvalue=max(z[i]) + if norm == True: + plt.plot(x,z[i]/maxvalue,label='#'+str(i)+': '+str(round(y[i],2))) + else: + plt.plot(x,z[i],label='#'+str(i)+': '+str(round(y[i],2))) + plt.legend(bbox_to_anchor=(1, 0), loc='lower left', ncol=2,shadow=True, title="ScanNum: "+str(ScanNum)+"\nSlit-"+Which+" position", fancybox=True) + #plt.legend(loc='lower left',ncol=2, shadow=True, title="ScanNum: "+str(ScanNum)+"\nSlit-"+Which+" position", fancybox=True) + plt.grid(color='lightgray', linestyle='-', linewidth=0.5) + plt.show() + + +############################################################################################### +######################################### IDCalibration New ################################### +############################################################################################### + + + +def id_calibration_fit(first_scan,last_scan,det,PolyRank,**kwargs): + + + #id_calibration_fit(FirstLast[0],FirstLast[1],det,poly_order,mytitle=mytitle,countby=countby,plotMin=plt_min,plotMax=plt_max,plotType=plotType,filepath=filepath,prefix=prefix) + """ + Fits calibration curves fpr each GRTs and modes included in the data set. Creates 3 dictionnaries: + + coefs={[GRT][mode][[breakpoint1,[coefs]],[breakpoint2,[coefs]...} + xdata= {[GRT][mode][[breakpoint1,[flux curve x axis]],[breakpoint2,[flux curve x axis]...} + fdata= {[GRT][mode][[breakpoint1,[flux curve y axis]],[breakpoint2,[flux curve y axis]...} + + kwargs: + countby = 1 by default + mytitle = '' by default + plotMin = min x range for plotting (default 250) + plotMax = max x range for plotting (default 3000) + plotType = ['dif,'fit,'flux'], full set by default + filepath = None, uses current mda filepath unless specified + e.g. user : filepath='/net/s29data/export/data_29idc/2018_2/UserName/mda/' + e.g. staff: filepath='/net/s29data/export/data_29idb/2018_2/mda/' + prefix = None, uses current mda prefix unless specified + scanIOC = None, uses BL_ioc() unless specified + """ + + kwargs.setdefault('countby',1) + kwargs.setdefault('mytitle','') + #kwargs.setdefault('plotMin',2000) + kwargs.setdefault('plotMin',225) + kwargs.setdefault('plotMax',3000) + kwargs.setdefault('plotType',['fit','dif','flux']) + kwargs.setdefault('filepath',BL.mda.filepath()) + kwargs.setdefault('prefix',BL.mda.prefix()) + + countby=kwargs['countby'] + mytitle=kwargs['mytitle'] + plotMin=kwargs['plotMin'] + plotMax=kwargs['plotMax'] + filepath=kwargs['filepath'] + prefix=kwargs['prefix'] + + + def calibration_curve(first,last,det,countby,filepath,prefix): + mono_list=[] + ID_list=[] + max_list=[] + flux_list=[] + print("filepath = ",filepath) + print("prefix = ",prefix) + print("First scan = ",first) + print("Last scan = ",last) + for i in range(first,last,countby): + x,y,x_name,y_name=mda_1D(i,det,1,0,filepath,prefix) #mda_1D(ScanNum,DetectorNum,coeff=1,bckg=0,filepath=None,prefix=None,scanIOC=None): + v,w,v_name,w_name=mda_1D(i, 4 ,1,0,filepath,prefix) + if y != []: + n=y.index(max(y)) # finds the peak max intensity index + e=round(x[n],2) # finds the corresponding mono energy + sp=round(w[2]*1000,0) # reads the ID set point + mono_list.append(e) + max_list.append(max(y)) + ID_list.append(sp) + flux_list.append(current2flux(max(y),e,p=None)) + return mono_list,ID_list,max_list,flux_list + + Mono_max,ID_SP,int_max,flux=calibration_curve(first_scan,last_scan+1,det,countby,filepath,prefix) + nPt_gaus=200 + x_HR = np.linspace(Mono_max[0], Mono_max[-1], nPt_gaus) + + # Data + xdata = np.array(Mono_max) + ydata = np.array(ID_SP) + zdata = np.array(int_max) + fdata = np.array(flux) + # Fitting + coefs = poly.polyfit(xdata, ydata, PolyRank) + ffit_HR = poly.polyval(x_HR, coefs) + ffit_Coarse = poly.polyval(xdata, coefs) + # Residual + Dif=np.array(ID_SP)-np.array(ffit_Coarse) + ratio=(np.array(ID_SP)-np.array(ffit_Coarse))/(np.array(ID_SP)/100) + # Plot differences + #print('plotMin = ',str(plotMin)) + if 'dif' in kwargs['plotType']: + fig = plt.figure(figsize=(12,6)) + plt.plot(Mono_max,ID_SP,marker='x',markersize=5,color='g',linewidth=0,label='data') + plt.plot(x_HR,ffit_HR,color='b',label='SP-fit') + plt.plot(xdata,Dif*100,marker='x',color='r',label='Dif x100') + plt.plot(xdata,ratio*1000,marker='x',color='g',label='Difx1000/ID') + plt.ylabel('ID SP') + plt.xlabel('Mono') + plt.xlim(plotMin,plotMax) + plt.legend(ncol=2, shadow=True, title=mytitle, fancybox=True) + plt.grid(linestyle='-', linewidth='0.5', color='grey') + plt.show() + # Plot raw data + fit + if 'fit' in kwargs['plotType']: + fig = plt.figure(figsize=(12,6)) + a1 = fig.add_axes([0,0,1,1]) + a1.plot(xdata+Dif,zdata,marker='*',markersize=10,color='r',linewidth=0,label='Interpolated ID SP') + for i in range(first_scan,last_scan+1): + x,y,x_name,y_name=mda_1D(i,det,1,0,filepath,prefix) + a1.plot(x,y,color='b') + a1.set_xlim(plotMin,plotMax) + a1.set(xlabel='Mono') + a1.set(ylabel='ID SP') + a1.ticklabel_format(style='sci', axis='y', scilimits=(0,0)) + a1.grid(linestyle='-', linewidth='0.5', color='grey') + plt.legend(ncol=2, shadow=True, title=mytitle, fancybox=True) + plt.show() + # Plot flux curves: + fdata_x=xdata+Dif + if 'flux' in kwargs['plotType']: + fig = plt.figure(figsize=(12,6)) + a1 = fig.add_axes([0,0,1,1]) + a1.plot(fdata_x,fdata,color='r',linewidth=1,label='Flux curves') + a1.set_xlim(plotMin,plotMax) + a1.set(xlabel='Mono') + a1.set(ylabel='ID SP') + a1.set_yscale('log') + #a1.ticklabel_format(style='sci', axis='y', scilimits=(0,0)) + a1.grid(linestyle='-', linewidth='0.5', color='grey') + plt.legend(ncol=2, shadow=True, title=mytitle, fancybox=True) + plt.show() + return coefs, fdata_x,fdata + + + + + + +def read_id_files(first,last,filepath=None,prefix=None,q=True): + """ + Reads extra PVs + Return a list of [[ScanNum,ID_SP,grt,mode],...] for mda files between first and last. + """ + if filepath == None: + filepath=BL.mda.filepath() + if prefix == None: + prefix=BL.mda.prefix()[:-1] + elif prefix[-1] == "_": + prefix=prefix[:-1] + mydata=mdaFile(first,last,filepath=filepath,prefix=prefix,q=q) + value=[] + modeDict={'CW, RCP':'RCP','CCW, LCP':'LCP','H':'H','V':'V'} + grtDict={1200:'MEG',2400:'HEG'} + for mdaNum in mydata.scanList: + if first<=mdaNum<=last: + extraPVs=mydata.header[mdaNum].all + try: + ID=round(extraPVs['ID29:EnergySet.VAL'][2][0]*1000,2) + mode=modeDict[extraPVs['ID29:ActualMode'][2]] # extraPVs return 'CW, RCP' + grt=grtDict[extraPVs['29idmono:GRT_DENSITY'][2][0]] # extraPVs return 1200 + except KeyError: + ID=round(extraPVs[b'ID29:EnergySet.VAL'][2][0]*1000,2) + mode=modeDict[str(extraPVs[b'ID29:ActualMode'][2])[2:-1]] + grt=grtDict[extraPVs[b'29idmono:GRT_DENSITY'][2][0]] # extraPVs return 1200 + if len(value)>0 and value[-1][1:] == [ID,grt,mode]: + pass + else: + value.append([mdaNum,ID,grt,mode]) + return value + + + +def id2num(ID,grt,mode,first=0,last=inf,ignore=[],filepath=None,prefix=None,q=True): # Not efficient - requires to read all 600 files everytime + """ + Return ScanNum corresponding to a given ID_SP from ExtraPVs (using mdaFile) + """ + if filepath == None: + filepath=BL.mda.filepath() + if prefix == None: + prefix=BL.mda.prefix()[:-1] + elif prefix[-1] == "_": + prefix=prefix[:-1] + ScanNum = 0 + data_list = read_id_files(first,last,filepath,prefix,q) + data_short=[x for x in data_list if x[2:]==[grt,mode] and x[0] not in ignore] + step=data_short[1][1]-data_short[0][1] + precision=int(step/2) + ID1=ID-precision + ID2=ID+precision + ScanNum=[x[0] for x in data_short if ID1<= x[1]<= ID2] + if len(ScanNum)==0: result=None + else: result=ScanNum[0] + return result + + + +def num2id(ScanNum,grt,mode,first=0,last=inf,ignore=[],filepath=None,prefix=None,q=True): # Not efficient - requires to read all 600 files everytime + """ + Return ID SP corresponding to a given ScanNum from ExtraPVs (using mdaFile) + """ + if filepath == None: + filepath=BL.mda.filepath() + if prefix == None: + prefix=BL.mda.prefix()[:-1] + elif prefix[-1] == "_": + prefix=prefix[:-1] + ID = 0 + data_short=[] + data_list = read_id_files(first,last,filepath,prefix,q) + data_short=[x for x in data_list if x[2:]==[grt,mode] and x[0] not in ignore] + ID=[x[1] for x in data_short if x[0] == ScanNum] + return ID[0] + + + +def extract_id(first,last,ignore=[],breakpts={'RCP':[600],'H':[400,600],'V':[600],'LCP':[600],'HEG':[],'MEG':[2200,2475]},filepath=None,prefix=None,q=True): + """ + Breaksdown the info from a calibration files into grt & mode with the corresponding breakpoints (hardcoded): + [[first, last, 'HEG', 'RCP', [600]], + [first, last, 'HEG', 'H', [400, 600]]...] + """ + if filepath == None: + filepath=BL.mda.filepath() + if prefix == None: + prefix=BL.mda.prefix()[:-1] + elif prefix[-1] == "_": + prefix=prefix[:-1] + IDlog=read_id_files(first,last,filepath,prefix,q) + #breakpts={'RCP':[600],'H':[400,600],'V':[600],'LCP':[600],'HEG':[],'MEG':[2200]} + #breakpts={'RCP':[600],'H':[400,600],'V':[600],'LCP':[600],'HEG':[],'MEG':[2200]} + #breakpts={'RCP':[600],'H':[600],'V':[600],'LCP':[600],'HEG':[],'MEG':[2200,2475]} # FR changed H breakpoints, missing low energy scans 06/14/2021 + data=[] + for grt in ['HEG','MEG']: + for mode in ['RCP','H','V','LCP']: + tmp=[x for x in IDlog if x[2:]==[grt,mode] and x[0] not in ignore] + #print(tmp) + if len(tmp)>0: + tmp=[tmp[0][0],tmp[-1][0],grt,mode,breakpts[mode]+breakpts[grt]] + data.append(tmp) + return data + + + +def update_id_dict(first,last,det,update_file,ignore,**kwargs): + + + + """ + Calculate new calibration curve for a full set of data.' + But what if the set is not complete? To be addressed by Future Me + If update_file == True (ONLY): + \tupdate the ID dictionary '/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/Dict_IDCal.txt' + """ + + if update_file == True: + foo=input('\nAre you sure you want to update the ID calibration dictionary?\n>') + if foo == 'Y' or foo == 'y' or foo == 'yes'or foo == 'YES' or foo == 'Yes': + foo = 'yes' + print('\nWill save new dictionary to: \'/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/Dict_IDCal.txt\'\n') + else: + print('\nCalibration curves will not be saved.\n') + else: + print('\nCalibration curves will not be saved.\n') + + kwargs.setdefault('countby',1) + kwargs.setdefault('mytitle','') + kwargs.setdefault('plotMin',225) + kwargs.setdefault('plotMax',3000) + kwargs.setdefault('plotType',['fit','dif','flux']) + kwargs.setdefault('filepath',BL.mda.filepath()) + kwargs.setdefault('prefix',BL.mda.prefix()) + kwargs.setdefault('q',True) + kwargs.setdefault('breakpts',{'RCP':[600],'H':[400,600],'V':[600],'LCP':[600],'HEG':[],'MEG':[2200,2475]}) + + + breakpts=kwargs['breakpts'] + plotType=kwargs['plotType'] + filepath=kwargs['filepath'] + prefix=kwargs['prefix'] + q=kwargs['q'] + + ID_data=extract_id(first,last,ignore,breakpts,filepath,prefix,q) + + ##### Extract parameters: + + mode_dict ={'RCP':0,'LCP':1,'V':2,'H':3} + id_coef={} + new_id_function={} + id_flux={} + flux_dict={} + id_energy={} + energy_dict={} + for mylist in ID_data: + if len(mylist) > 0: # in case of incomplete data set + tmp0,tmp1,tmp2=[],[],[] + first_scan=mylist[0] + last_scan=mylist[1] + scan_list=[[first_scan,last_scan]] + countby=1 + #det=15 + #det=33 + poly_order=4 + grt=mylist[2] + mode=mylist[3] + breakpts_energy=mylist[4] + breakpts_scan=[] + mytitle=mode+' - '+grt + + ## generating list of scans depending on breakpoints: + if breakpts_energy != []: + scan_list=[] + for x in breakpts_energy: + breakpts_scan.append(id2num(x,grt,mode,first,last,ignore,filepath,prefix,q)) + breakpts_scan = [i for i in breakpts_scan if i] + print(breakpts_scan) + for c,x in enumerate(breakpts_scan): # can get the number by extracting step size then /2 + if c == 0: + if x == first_scan: pass + else: scan_list.append([first_scan,x]) + if 0 < c < len(breakpts_scan)-1: + scan_list.append([breakpts_scan[c-1],x]) + scan_list.append([x,breakpts_scan[c+1]]) + if c == len(breakpts_scan)-1 and (c-1) == 0: + scan_list.append([breakpts_scan[c-1],x]) + if c == len(breakpts_scan)-1: + scan_list.append([x,last_scan]) + final_list = [i for n, i in enumerate(scan_list) if i not in scan_list[:n]] # remove doubles + energy_list=[] + for x in final_list: + ID1=num2id(x[0],grt,mode,first,last,ignore,filepath,prefix,q) + ID2=num2id(x[1],grt,mode,first,last,ignore,filepath,prefix,q) + energy_list.append([ID1,ID2]) + energy_list_2=energy_list # we need the final value for plot purposes (max value) + if grt == 'HEG': + energy_list_2[-1][-1]=2500 # but we don't want it to be a cutoff for ID_Calc in dict + for (FirstLast,ID,cutoff) in zip(final_list,energy_list,energy_list_2): + plt_min=ID[0]-200 + plt_max=ID[1]+100 + if grt=='MEG' and ID[1]>2900: + poly_order=5 + plt_min=ID[0]-200 + print('det =',det) + print('poly_order =',poly_order) + + subkwargs=kwargs # kwargs contains plotType, filepath, prefix and q + newkwargs={'mytitle':mytitle,'countby':countby,"plotMin":plt_min,'plotMax':plt_max} + subkwargs.update(newkwargs) + #print(newkwargs) + #print(FirstLast[0],FirstLast[1]) + #result,energy_data,flux_data=id_calibration_fit(FirstLast[0],FirstLast[1],det,poly_order,subkwargs) + result,energy_data,flux_data=id_calibration_fit(FirstLast[0],FirstLast[1],det,poly_order,mytitle=mytitle,countby=countby,plotMin=plt_min,plotMax=plt_max,plotType=['fit','dif'],filepath=filepath,prefix=prefix) + tmp0.append([cutoff[1],result.tolist()]) + tmp1.append([cutoff[1],energy_data]) + tmp2.append([cutoff[1],flux_data]) + + if 2900<tmp0[-1][0]<3000: tmp0[-1][0]=3000 + id_coef[mode_dict[mode]]=tmp0 # dictionary that + new_id_function[grt]=id_coef # dictionary containing all the calibration curves forthe data set + id_energy[mode_dict[mode]]=tmp1 # dictionary that + energy_dict[grt]=id_energy + id_flux[mode_dict[mode]]=tmp2 # dictionary that + flux_dict[grt]=id_flux + + ##### Read & update old dictionary: + + try: + id_function=read_dict('Dict_IDCal.txt') + print(id_function) + id_function.update(new_id_function) + + except KeyError: + print("Unable to read previous dictionary") + + + if update_file == True and foo == 'yes': + filepath = "/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/" + filename = 'Dict_IDCal.txt' + + with open(join(filepath, filename), "a+") as f: + f.write('\n======= '+today()+': \n') + f.write(str(id_function)) + f.write('\n') + print('\nWriting dictionary to:',join(filepath, filename)) + + if update_file == True and foo == 'yes': + filepath = "/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/" + filename = 'Flux_Curves.txt' + + with open(join(filepath, filename), "a+") as f: + f.write('\n======= '+today()+': \n') + f.write('\n----- flux_x:\n') + f.write(str(energy_dict)) + f.write('\n----- flux_y:\n') + f.write(str(flux_dict)) + f.write('\n') + print('\nWriting flux curves to:',join(filepath, filename)) + + return id_function,energy_dict,flux_dict + + +def update_slit_dict(**kwargs): + """ + Interactive function to update the slit position dictionary (Dict_Slit.txt) + + **kwargs + readOnly == False, if true just pring the current slit dictionary + """ + filepath = "/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/" + filename ='Dict_Slit.txt' + + kwargs.setdefault("readOnly",False) + + print('\n\nWARNING: 2V slit should always be centered at zero ie steer M1 center beam on the grating') + print('Increasing the roll moves the beam more positive: +0.05 pitch => ~ +0.04 slit position; Use:\n') + print("Get_Mirror(1);Move_M1('RZ',x)") + print("energy(500);mono(505);slit(200)") + print("Scan_NarrowSlit_Go(which='2V',slit_parameters=[0.25, -2, 2, 0.25]) #for MEG; slit_parameters=[0.5, -2, 2, 0.25] for HEG") + print("Scan_NarrowSlit_Go(which='2V',slit_parameters=[0.50, -2, 2, 0.25]) #for HEG") + print('Once steering is completed, check 2H position:') + print("Scan_NarrowSlit_Go(which='2H',slit_parameters=[0.25, -6, 6, 0.25]) ") + + try: + slit_position=read_dict(filename) + print('\nCurrent dictionary:\n') + print(slit_position) + + except KeyError: + print("Unable to read previous dictionary") + return + + if kwargs['readOnly']== True: + return slit_position + + else: + grt=input('\nWhich grating do you want to update (HEG or MEG) >') + s2v=input('New Slit 2B-V center >') + s2h=input('New Slit 2B-H center >') + s1v=input('New Slit 1A-V center >') + s1h=input('New Slit 1A-H center >') + + if grt == '' or s1h == '' or s1v == '' or s2h == '' or s2v == '': + print('\nMissing input. No changes made in file.') + return + + if grt[0] == '"' or grt[0]=="'": grt = grt[1:4] + + # new_slit_position={grt.upper():{'S1H':float(s1h),'S1V':float(s1v),'S2H':float(s2h),'S2V':float(s2v)}} # change order to match scan/fit order + new_slit_position={grt.upper():{'S2V':float(s2v),'S2H':float(s2h),'S1V':float(s1v),'S1H':float(s1h)}} + slit_position.update(new_slit_position) + + + with open(join(filepath, filename), "a+") as f: + f.write('\n======= '+today()+': \n') + f.write(str(slit_position)) + f.write('\n') + print('\nWriting dictionary to:',join(filepath, filename)) + + slits_set_BL() + return slit_position + + + + + + +def read_flux(FileName='Flux_Curves.txt',FilePath="/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/"): + print('test') + with open(join(FilePath, FileName)) as f: + for c,line in enumerate(f.readlines()): + if line[0] == '=': + lastdate=line[8:16] + print(lastdate) + if line[0] == '-' and line[-2] == 'x': + axis='x' + print(axis) + line_x=line + if line[0] == '-' and line[-2] == 'y': + axis='y' + print(axis) + line_y=line + mydict_x=ast.literal_eval(line_x) + mydict_y=ast.literal_eval(line_y) + return mydict_x,mydict_y + + + + + + +############################################################################################### +######################################### Object Oriented ##################################### +############################################################################################### + +class _mdaData(scanDim): + + def __init__(self): + scanDim.__init__(self) + self.poslist = None + self.detlist = None + + + def _getDetIndex(self,d): + """ + d = det Num + """ + D=self.detlist + if D==[]: + print('Data contains no detectors. Try higher dimensions: mydata.dim2[n]') + index=[None] + else: + index=[x for x, y in enumerate(D) if y[1] == 'D'+str(d).zfill(2)] + if index == []: + print('Detector '+str(d)+' not found.') + index=[None] + return index[0] + + + + def plt(self,d): + d=self._getDetIndex(d) + if d== None: + return + x=self.p[0] + y=self.d[d] + if self.dim == 2: + print('This is a 2D scan; use method mydata.img(n,d)') + for i in range(len(y.data)): + plt.plot(x.data[i], y.data[i],label=y.fieldName,marker='+') # crop aborted scans (curr_pt<npts) + else: plt.plot(x.data[:self.curr_pt], y.data[:self.curr_pt],label=y.fieldName,marker='+') # crop aborted scans (curr_pt<npts) + plt.xlabel(x.name) + plt.ylabel(y.name) + plt.legend() + plt.grid(color='lightgray', linestyle='-', linewidth=0.5) + + + + def kappaDet(self,q=None): + if q is not None: + print('\nUse detIndex for plot: mydata.dim1[n].d[detIndex].data\nIf D=mydata.dim1[n].kappaDet => detIndex=D[detNum][1]\n') + print('key = (detIndex, detNum, description, pv)') + det={} + D=self.detlist + for (i,j) in zip([32,33,34,35,31,36,37,38,39,41,42,43,44,45,46,47,48,54,55,56,57],['TEY','D3','D4','MCP','mesh','TEY / mesh','D3 / mesh','D4 / mesh','MCP / mesh','ROI1','ROI2','ROI3','ROI4','ROI5','<H>','<K>','<L>','tth','th','chi','phi']): + d=self._getDetIndex(i) + if d != None: + det[i]=(d,D[d][1],j,D[d][2]) + else: + det[i]=None + return det + + + + + +class _mdaHeader: + def __init__(self): + self.all = None + self.sample = None + self.mono = None + self.ID = None + self.energy = None + self.det = None + self.motor = None + self.mirror = None + self.centroid = None + self.slit=None + self.comment=None + + + + +class mdaFile: + + + '''mydata=mdaFile(first=0,last=None,name=datasetName,filepath=None,prefix=None) + + /net/s29data/export/data_29idb/2020_3/mda/Kappa_0107.mda is a 1-D file; 1 dimensions read in. + + mydata.header[n] = dictionary of 163 scan-environment PVs + + usage: mydata.header[n]['sampleEntry'] -> ('description', 'unit string', 'value', 'EPICS_type', 'count') + + mydata.dim1[n] = 1D data from '29idKappa:scan1' acquired on Oct 20, 2020 19:06:23: + 33/33 pts; 1 positioners, 65 detectors + + usage: mydata.dim1[n].p[2].data -> 1D array of positioner 1 data + + Each scan dimension (i.e., dim1, dim2, ...) has the following fields: + time - date & time at which scan was started: Oct 20, 2020 19:06:23 + name - name of scan record that acquired this dimension: 29idKappa:scan1 + curr_pt - number of data points actually acquired: 33 + npts - number of data points requested: 33 + nd - number of detectors for this scan dimension: 65 + d[] - list of detector-data structures + np - number of positioners for this scan dimension: 1 + p[] - list of positioner-data structures + nt - number of detector triggers for this scan dimension: 1 + t[] - list of trigger-info structures + + Each detector-data structure (e.g., dim[1].d[0]) has the following fields: + desc - description of this detector + data - data list + unit - engineering units associated with this detector + fieldName - scan-record field (e.g., 'D01') + + Each positioner-data structure (e.g., dim[1].p[0]) has the following fields: + desc - description of this positioner + data - data list + step_mode - scan mode (e.g., Linear, Table, On-The-Fly) + unit - engineering units associated with this positioner + fieldName - scan-record field (e.g., 'P1') + name - name of EPICS PV (e.g., 'xxx:m1.VAL') + readback_desc - description of this positioner + readback_unit - engineering units associated with this positioner + readback_name - name of EPICS PV (e.g., 'xxx:m1.VAL') + ''' + + def __init__(self,first=1,last=None,name='mydata',filepath=None,prefix=None,q=False): + if filepath == None: + filepath = BL.mda.filepath() + self.path = filepath + self._name = name + self._first = first + self._last = last + if prefix != None and prefix[-1]=='_': + self._prefix= prefix[:-1] + else: + self._prefix= prefix + + self._allFiles = None + self._allPrefix = None + self.loadedFiles = None + self.scanList = None + self.dim1 = None + self.dim2 = None + self.dim3 = None + self.header = None + + self._extractFiles() + self._extractData(q) + + + #def __str__(self): + + + + def _extractFiles(self): + allFiles = [f for f in listdir(self.path) if isfile(join(self.path, f))] + loadedFiles= [x for (i,x) in enumerate(allFiles) if allFiles[i].split('.')[-1]=='mda'] + allPrefix = [loadedFiles[i][:loadedFiles[i].find('_')] for (i,x) in enumerate(loadedFiles)] + scanList = [int(loadedFiles[i][loadedFiles[i].find('_')+1:loadedFiles[i].find('_')+5]) for (i,x) in enumerate(loadedFiles)] + if self._prefix != None: + allPrefix=[s for s in allPrefix if s == self._prefix] + scanList = [int(loadedFiles[i][loadedFiles[i].find('_')+1:loadedFiles[i].find('_')+5]) for (i,x) in enumerate(loadedFiles) if loadedFiles[i][:loadedFiles[i].find('_')] == self._prefix] + loadedFiles = [s for s in loadedFiles if s[:s.find('_')] == self._prefix] + else: + self._prefix=allPrefix[-1] + if allPrefix[0]!=allPrefix[-1]: + print('\nWARNING: Found more than one file prefix: {}, {}.\n\nData with the same scan number will be overwriten in the order they are loaded. \nPlease specify the one you want to load with arg prefix="which".\n\n'.format(allPrefix[0],allPrefix[-1])) + if self._last == None: + self._last = self._first + shortlist = [i for (i,x) in enumerate(scanList) if self._first<=x<=self._last] + self._allFiles = allFiles + self.loadedFiles = [loadedFiles[i] for i in shortlist] + self.scanList = [scanList[i] for i in shortlist] + self._allPrefix=[allPrefix[i] for i in shortlist] + + + def _extractData(self,q): + + allheader = {} + alldata1 = {} + alldata2 = {} + alldata3 = {} + + for (i,mda) in enumerate(self.loadedFiles): + + ##### File info: + + filename=mda + filepath=self.path + #print(filepath) + num=self.scanList[i] + #print(num) + fullpath=join(filepath,filename) + #print(fullpath) + data=readMDA(fullpath,useNumpy=True) # data = scanDim object of mda module + + ###### Extract header: + + D0 = _mdaHeader() # initiate D0 = mdaHeader object + D1 = _mdaData() + D2 = _mdaData() + D3 = _mdaData() + + D=[] + + for d in range(0,4): + if d in range(0,len(data)): D.append(data[d]) + else: D.append(None) + + # D[0]=data[0] + # D[1]=data[1] + # D[2]=None if 1D data, data[2] if 2D data + # D[3]=None if 2D data, data[3] if 3D data + + + D0.all=D[0] + + + if filename[:5] == 'Kappa': + try: + D0.sample={**{key:value[:3] for key, value in D[0].items() if '29idKappa:m' in key},**{key:value[:3] for key, value in D[0].items() if '29idKappa:Euler' in key},**{key:value[:3] for key, value in D[0].items() if 'LS331' in key}} + D0.mirror = {key:value[:3] for key, value in D[0].items() if '29id_m3r' in key} + D0.centroid={key:value[:3] for key, value in D[0].items() if 'ps6' in key.lower()} + D0.det = {key:value[:3] for key, value in D[0].items() if '29idd:A' in key} + detkeys=['29idMZ0:scaler1.TP','29idKappa:m9.RBV','29idKappa:userCalcOut10.OVAL','29iddMPA:C0O','29idKappa:userStringSeq6.STR1','29idd:Unidig1Bo0'] + for k in detkeys: + if k in D[0]: D0.det[k]=D[0][k][:3] + D0.ID={key:value[:3] for key, value in D[0].items() if 'ID29' in key} + D0.UB={key:value[:3] for key, value in D[0].items() if 'UB' in key} + D0.mono={key:value[:3] for key, value in D[0].items() if 'mono' in key} + D0.energy={key:value[:3] for key, value in D[0].items() if 'energy' in key.lower()} + D0.motor = {key:value[:3] for key, value in D[0].items() if '29idb:m' in key} + D0.slit={key:value[:3] for key, value in D[0].items() if 'slit3d' in key.lower()} + except: + pass + if filename[:5] == 'ARPES': + try: + #D0.sample={**{key:value[:3] for key, value in D[0].items() if '29idKappa:m' in key},**{key:value[:3] for key, value in D[0].items() if '29idKappa:Euler' in key},**{key:value[:3] for key, value in D[0].items() if 'LS331' in key}} + #D0.mirror = {key:value[:3] for key, value in D[0].items() if '29id_m3r' in key} + #D0.centroid={key:value[:3] for key, value in D[0].items() if 'ps6' in key.lower()} + #D0.det = {key:value[:3] for key, value in D[0].items() if '29idd:A' in key} + #detkeys=['29idMZ0:scaler1.TP','29idKappa:m9.RBV','29idKappa:userCalcOut10.OVAL','29iddMPA:C0O','29idKappa:userStringSeq6.STR1','29idd:Unidig1Bo0'] + #for k in detkeys: + # if k in D[0]: D0.det[k]=D[0][k][:3] + D0.ID={key:value[:3] for key, value in D[0].items() if 'ID29' in key} + #D0.UB={key:value[:3] for key, value in D[0].items() if 'UB' in key} + D0.mono={key:value[:3] for key, value in D[0].items() if 'mono' in key} + D0.energy={key:value[:3] for key, value in D[0].items() if 'energy' in key.lower()} + D0.motor = {key:value[:3] for key, value in D[0].items() if '29idb:m' in key} + D0.slit={key:value[:3] for key, value in D[0].items() if 'slit3c' in key.lower()} + except: + pass + + try: + cmt1=D[0]['29id'+self._prefix+':saveData_comment1'][2] + cmt2=D[0]['29id'+self._prefix+':saveData_comment2'][2] + if cmt2 != '': D0.comment = cmt1+' - '+cmt2 + else: D0.comment = cmt1 + except: + D0.comment = '' + + + ###### Extract data: + + DIMS=[D1,D2,D3] + + for counter, value in enumerate(DIMS): + c=counter+1 + if D[c] is not None: + value.rank=D[c].rank + value.dim=D[c].dim + value.npts=D[c].npts + value.curr_pt=D[c].curr_pt + value.plower_scans=D[c].plower_scans + value.name=D[c].name # + value.time=D[c].time + value.np=D[c].np + value.p=D[c].p + value.nd=D[c].nd + value.d=D[c].d + value.nt=D[c].nt + value.t=D[c].t + value.detlist=[(i,D[c].d[i].fieldName,D[c].d[i].name,D[c].d[i].desc) for i in range(0,D[c].nd)] + value.poslist=[(i,D[c].p[i].fieldName,D[c].p[i].name,D[c].p[i].desc) for i in range(0,D[c].np)] + else: + value=None + + allheader[num] = D0 + alldata1[num] = D1 + alldata2[num] = D2 + alldata3[num] = D3 + + d=D.index(None)-1 + if q is False: + print('Loading {} as {}.dim{}[{}]:\n\t\t...{}D data, {}/{} pts; {} positioners, {} detectors'.format( + filename,self._name,d,self.scanList[i],D[d].dim,D[d].curr_pt, D[d].npts, D[d].np, D[d].nd)) + + self.header=allheader + self.dim1=alldata1 + self.dim2=alldata2 + self.dim3=alldata3 + + + + + + def updateFiles(self,first=0,last=inf,name=None,filepath=None,prefix=None): + new=mdaFile(first,last,name,filepath,prefix) + self.loadedFiles=list(dict.fromkeys(self.loadedFiles+new.loadedFiles)) + self._allFiles=list(dict.fromkeys(self._allFiles+new._allFiles)) # merging the 2 list and removing duplicates + self.scanList=list(dict.fromkeys(self.scanList+new.scanList)) + self._allPrefix=list(dict.fromkeys(self._allPrefix+new._allPrefix)) + self.dim1.update(new.dim1) + self.dim2.update(new.dim2) + self.dim3.update(new.dim3) + self.header.update(new.header) + return self + + + + def plt(self,*argv): + if self.dim2[argv[0]].dim == 0: #1D scan + for index,arg in enumerate(argv): + if index %2 !=0: + pass + else: + n=arg + d=argv[index+1] + d=self.dim1[n]._getDetIndex(d) + x=self.dim1[n].p[0] + y=self.dim1[n].d[d] + plt.plot(x.data[:self.dim1[n].curr_pt], y.data[:self.dim1[n].curr_pt],label='mda #'+str(n)+' - '+y.fieldName,marker='+') + plt.xlabel(x.name) + plt.ylabel(y.name+' - ('+y.fieldName+')') + plt.legend() + plt.grid(color='lightgray', linestyle='-', linewidth=0.5) + plt.show() + elif self.dim2[argv[0]].dim == 2: # 2D scan + for index,arg in enumerate(argv): + if index %2 !=0: + pass + else: + n=arg + d=argv[index+1] + d=self.dim2[n]._getDetIndex(d) + if d == None: + return + x=self.dim2[n].p[0] + y=self.dim1[n].p[0] + z=self.dim2[n].d[d] + zlim=self.dim2[n].curr_pt + fig, ax0 = plt.subplots() + img = ax0.imshow(z.data[:zlim],cmap='gnuplot', interpolation = 'nearest', extent = [min(x.data[0]), max(x.data[0]), min(y.data),max(y.data)], aspect = 'auto') + fig.colorbar(img) + plt.title(z.name+' - ('+z.fieldName+')') + ax0.set_xlabel(x.name) + ax0.set_ylabel(y.name) + plt.show() + + + + + + + diff --git a/build/lib/iexcode/macros/__init__.py b/build/lib/iexcode/macros/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/build/lib/iexcode/macros/__init__.py @@ -0,0 +1 @@ + diff --git a/build/lib/iexcode/macros/commissioning.py b/build/lib/iexcode/macros/commissioning.py new file mode 100644 index 0000000000000000000000000000000000000000..675889f949a341e87f8a5b9886768e49fef05040 --- /dev/null +++ b/build/lib/iexcode/macros/commissioning.py @@ -0,0 +1,944 @@ +""" +Functions for commissioning, alignment and start of the week + +""" +from os.path import join, isfile, exists, dirname +from time import sleep + +from epics import caget, caput + + +from ..instruments.files_and_folders import check_run, folder_mda +from ..instruments.scanRecord import scanRecord_run,scanRecord_filepath +from ..instruments.xrays import energy +from ..instruments.m3r import M3R_branch + +from ..instruments.IEX_VPU import ID_switch_mode +from ..instruments.diagnostics import diagnostics_all_out, diagnostics_all_in,diodeC,diodeD +from ..instruments.current_amplifiers import current2flux +from ..instruments.slits import set_exit_slit +from ..instruments.logfile import * +from ..instruments.cameras import * + +from ..instruments.ARPES import * +from ..instruments.electron_analyzer import * +from ..instruments.Kappa import * + + +from .ScanFunctions_plot import fit_mda, mda_1D + +############################################################################################################## +################################ setting the mda folder ############################## +############################################################################################################## + +def staff_init(endstation_name=None,set_folders=True,reset=True): + """ + endstation_name : sets the scan record and BL + set_folders: sets the mda and EA folders; default => False + reset: resets the scanRecord (detectors,triggers...) + + **kwargs: + xrays: sets global variable; default => True + BL_mode: 'user' / 'staff' => used for saving, detectors + + Previously: folders_staff + """ + if endstation_name is None: + endstation_name = BL.endstation + + if endstation_name == 'ARPES': + ARPES_init(set_folders,reset,BL_mode='staff') + if endstation_name == 'Kappa': + Kappa_init(set_folders,reset,BL_mode='staff') + + + +def check_staff_directory(BL, **kwargs): + """ + Switchs to the staff directory + + **kwargs for folder_ARPES + + Previously: Check_Staff_Directory + """ + + ioc = BL.ioc() + run = check_run() + + directory = scanRecord_filepath(ioc) + current_run = scanRecord_run(ioc) + + if directory.find('data_29idb') < 1 or current_run != run: + print('You are not currently saving in the Staff directory and/or the desired run.') + # foo=input('\nAre you ready to switch to the '+run+' Staff directory (y or n)? >') + # if foo.lower() == 'y' or foo.lower() == 'yes': + if not (exists(directory)): + print('Staff directory does not exist for this run.') + print('Open ipython as 29id to create a new run directory using:\n\tFolder_'+ioc+'(run,"Staff")') + foo=input('\nPress enter when done >') + if foo == '': pass + print('Switching directory...') + if ioc=='ARPES': + folders_ARPES('Staff',mdaOnly=True,**kwargs) + elif ioc=='Kappa': + folders_Kappa('Staff',create_only=False) + else: + print('\nFolder not set.') + else: + print('Staff directory OK.') + directory = scanRecord_filepath(ioc) + print('\nCurrent directory: '+directory) + + + +############################################################################################################## +################################ checking alignment ############################## +############################################################################################################## + +def check_flux(hv=500,ID_mode='RCP',stay=False): + """ + puts the diode in + measures flux at energy ID_mode specified + stay: diode position after the scan + + Previously: CheckFlux + """ + ID_switch_mode(ID_mode) + energy(hv) + diagnostics_all_out(diode_to_stay_in=m3r_branch()) + SR=round(caget("S:SRcurrentAI.VAL"),2) + if m3r_branch() == "c": + current_slit=caget('29idb:Slit3CFit.A') + diodeC('In') + set_exit_slit(50) + sleep(10) + diode=diodeC_read() + elif m3r_branch() == "d": + current_slit=caget('29idb:Slit4Vsize.VAL') + sleep(10) + diodeD("In") + set_exit_slit(50) + diode=caget('29idb:ca14:read') + flux=current2flux(diode) + print("\n----- Current on diode : %.3e" % diode, "A") + print("----- Corresponding flux: %.3e" % flux, "ph/s \n") + print("----- Storage ring current: %.2f" % SR, "mA") + print("\nFlux at hv=500 as off Feb 2019 for RCP and HEG: ~3.3e-06 A = ~1.5e+11 ph/s") + + if not stay: + diagnostics_all_out() + set_exit_slit(current_slit) + +def check_m0m1(hv=500,stay=True,wire=True,**kwargs): + """ + Prints Flux in C-branch + stay = 'yes' => Leaves diagnostics in the beam + wire ='yes'=> Does wire scans to determine M0M1 alignment + Logging is automatic: use **kwargs or the optional logging arguments see scanlog() for details + + Previously: CheckM0M1 + """ + + switch_branch('c') + switch_gratings('HEG') + print("\nFlux at hv=500 as off Feb 2019: ~3.3e-06 A = ~1.5e+11 ph/s") + branch_shutter_open() + check_flux(hv=hv,stay=stay) + if wire is not None: + scan_wire('H',**kwargs) + scan_wire('V',**kwargs) + +def scan_wire(direction,all_diag=True,**kwargs): + """ + Scans the wires located just downstream of M0/M1, + which = 'H' for the horizontal, typically CA2 + which = 'V' for the vertical, typically CA3 + all_diag =True -> AllDiagIn(), otherwise you have to put any diagnostics in by hand + Logging is automatic: use **kwargs or the optional logging arguments see scanlog() for details + **kwargs: + execute + + Previously: WireScan + """ + kwargs.setdefault('execute',True) + if all_diag: + diagnostics_all_in() + + + if direction == 'H': + name = "H-wire" + + elif direction == 'V': + name = "V-wire" + + diag = diagnostics_dict() + pv = "29idb:m"+str(diag["motor"][name]) + print("\n================== "+name+" scan (29idb:ca2):") + BL.mda.fillin(pv+".VAL",pv+".RBV",1,-17,-30,-0.25,**kwargs) + + if kwargs['execute']: + BL.mda.go(**kwargs) + + if all_diag: + diagnostics_all_out() + + +############################################################################################################## +########################### Beam Profile ###################### +############################################################################################################## +def scan_narrow_slit(slit='2V',slit_parameters=[0.25,-2,2,0.5],**kwargs): + """ + slit = '1V','1H','2V','2H' + slit_parameters = [SlitSize,start,stop,step] + + Typical slit sizes/start/stop/step are (for full range): + 1H/1V : [0.50, -4.5, 4.5, 0.2] + 2H : [0.25, -3.0, 3.0, 0.2] + 2V-MEG: [0.25, -4.0, 4.0, 0.2] + 2V-HEG: [0.50, -8.0, 8.0, 0.2] + + **kwargs: + scan_dim = 1 + execute = True + + Previously: Scan_NarrowSlit + """ + kwargs.setdefault('scan_dim',1) + kwargs.setdefault('execute',True) + + size,start,stop,step = slit_parameters + + direction = slit[1] + if direction == "V": + size = (inf, size) + center = (0, 0) + elif direction == "H": + size = (size, inf) + center = (0, 0) + + if slit[0] == '1': + slit_name = "slit1A" + slit1A_set(size,center) + slit2B_set((inf,inf),(0,0)) + + elif slit[0] == '2': + slit_name = "slit2B" + slit1A_set((3,3),(0,0)) + slit2B_set(size,center) + + slits_scan_center(slit_name,direction,start,stop,step,**kwargs) + if kwargs['execute']: + BL.mda.go(kwargs['scan_dim']) + + +def scan_mono_vs_slit(slit='2V',slit_parameters=[0.25,-2,2,0.5],energy_parameters=[470,530,2],**kwargs): + """ + This can be used to find the center of the resonant beam i.e. the slit value for the most blue shifted curve: + slit='1V','1H','2V','2H' + slit_parameters = [SlitSize,start,stop,step] + energy_parameters = [eVstart,eVstop,eVstep]= [470,530,2] + + Typical slit sizes/start/stop/step are (for full range): + 1H/1V : [0.50, -4.5, 4.5, 0.2] + 2H : [0.25, -3.0, 3.0, 0.2] + 2V-MEG: [0.25, -4.0, 4.0, 0.2] + 2V-HEG: [0.50, -8.0, 8.0, 0.2] + + Previously: Scan_MonoVsSlit + """ + hv_start,hv_stop,hv_step = energy_parameters + # Filling Scans: + mono_scan_fillin(hv_start,hv_stop,hv_step) + scan_narrow_slit(slit='2V',slit_parameters=[0.25,-2,2,0.5],**kwargs) + + # Resetting everybody to normal: + mono_energy_set((hv_start+hv_stop)/2.0) + slits_set_BL() + + +############################################################################################################## +################################ mono alignment ############################## +############################################################################################################## +def mono_MIR_GRT_find_offset(grating,slit_list,**kwargs): + """ + Find MIR-GRT offset by scanning 0 order through exit slit + **kwargs: + detNum = 15 + + Previously: MIR_GRT_Offset + """ + kwargs.setdefault("detNum",15) + + switch_gratings(grating) + exit_slit(50) + diodeC('In') + slit2B_set(2,0.5,0,0) + + #set zero order, scan grating pitch + for ang in RangeUp(1.5,5,0.5): + print("\r") + mono_zero_order(ang) + print("Mirror pitch: "+str(ang)+"\r") + for s in slit_list: + exit_slit(s) + print("\r") + + mono_motor_scan_fillin("GRT:P",ang-0.0005*s, ang+0.0005*s ,0.00002*s) + BL.mda.go(**kwargs) + + sleep(1) + print("\r") + grating_ang = fit_mda(mda.fileNum(),kwargs['detNum'],.1,'gauss') + print("Peak: ",grating_ang) + print("\r") + print("-------------------------") + +##################### mono slit scans => Energy calibration ##################### +def exit_slit_vs_hv(hv,c=3): + ''' + Adjust slit size to keep reasonable count vs hv + c=3 for nominal slit2B size + c=10 for apertured slit2B (e.g 0.25 or 0.5) + + Previously: Mono_Set_Slitvshv + ''' + slit(hv/100.0*c) + + +def scan_energy_along_grating(hv,peakBE=84,pts=11,r=0.75,i=1,**kwargs): + """ + Takes a Slit-2V map for a range of photon energies + peakBE=84; fixed mode + pts = number of pts in slit positions, default: 11 + r = % of range in slit size, default: 0.75 + i = scanEA time in minute (default:1 for MEG, 2 for HEG?) + Takes 2.5h with default parameters (i=1) + + Previously: Mono_Scan_Slit2BV + """ + grt_density = mono_grating_density_get() + c=grt_density/1200 # c = 1 for MEG, 2 for HEG + + # Getting EA parameters vs hv: + PE=200 + + #Getting Slit-2B parameters + Vsize=0.25*c + n=(4.5-hv/500) + Vstart=-((floor((2*n)/Vsize/2)+1)*Vsize*c)*r + Vstep=-round(Vstart*2/pts,2) + + #Setting energy: + energy(hv) + exit_slit_vs_hv(hv,c=10) + + #Aperturing slit 2V (note that we have the nominal size horizontally) + (size_rbv,size_val),(center_rbv,center_val) = slits_pvs('slit2B') + caput(size_val,Vsize) + + print("\n--------------- Starting core level vs Slit-2B(V) map ---------------") + + #Take XPS for each Slit-2V position + for V_center in RangeUp(Vstart,-Vstart,Vstep): + caput(center_val,V_center,wait=True,timeout=18000) + kwargs.update({'comment': "2-V center ="+str(V_center)[0:6]}) + EAlist=["BE",peakBE,PE,17*60*i,1] + scanEA(EAlist,**kwargs) + + #reset the slits + slits_set_BL() + + + +def scan_mono_energy_drift(start,stop,step,peakBE=84,EF=None,**kwargs): + ''' + Measure core level (by default Au 4f) in fixed mode vs energy while maintaining resonable count rate + If EF='y' (by default None) takes the Fermi edge as well. + kwargs: + c=3 is the default slit2B size + + Used for grating calibration (changing grating_offset and b2 effects this - use grating_offset since b2 was measured) + + Previously: Mono_Scan_hv_drift + ''' + kwargs.setdefault('c','3') + + for hv in RangeUp(start,stop,step): + energy(hv) + c=int(kwargs['c']) + exit_slit_vs_hv(hv,c) + kwargs.update({'comment': "Core level @ hv = "+str(hv)}) + scanEA(["BE",peakBE,200,17*60*1,1],**kwargs) + if EF is not None: + kwargs.update({'comment': "EF @ hv = "+str(hv)}) + scanEA(["BE",0,200,17*60*10,1],**kwargs) + + + +############################################################################################################## +########################### Pinhole Scripts ###################### +############################################################################################################## +def scan_pinhole_full(): + """ + Does a pinhole with .1 mm step with AllDiagIn and then with only branch diode in + + Previously: FullPinhole + """ + diagnostics_all_in() + scan_pinhole([-3, 3, .5, .1], [-3, 3, .1, .5]) + diagnostics_all_out(diode_stay_in=True) + scan_pinhole([-3, 3, .5, .1], [-3, 3, .1, .5]) + + +def scan_pinhole(H_list,V_list,**kwargs): + """ + Sets up the pinhole scan for slit1A + Make sure that you have the appropriate Diagnostics in can use AllDiagIn() + + H_list = [Hstart, Hstop, Hstep, Hsize] => [-3, 3, .1, .5] + V_list = [Vstart, Vstop, Vstep, Vsize] => [-3, 3, .1, .5] + + *kwargs: + H_scan_dim => 1 + V_scan_dim => 2 + execute => True + + Previously: Scan_Pinhole_Go, Scan_Pinhole + """ + kwargs.setdefault('H_scan_dim',1) + kwargs.setdefault('V_scan_dim',2) + kwargs.setdefault('execute',True) + + #Synching slits + slits_synch("slit1A") + + #Getting initial slit size + (Hsize0,Vsize0),(Hcenter0,Vcenter0) = slit1A_get(verbose=False) + + #Filling in the ScanRecord + slits_scan_center("slit1A","H",H_list[0],H_list[1],H_list[2],scan_dim=kwargs['H_scan_dim'],execute=False) + slits_scan_center("slit1A","V",V_list[0],V_list[1],V_list[2],scan_dim=kwargs['V_scan_dim'],execute=False) + + #Set the slit size + slit1A_set((H_list[2],V_list[2]),(0,0),verbose=True) + + if kwargs['execute']: + print("\rPinhole scan: ("+str(kwargs['H_scan_dim'])+","+str(kwargs['V_scan_dim'])+") " + +str(H_list[0])+"/"+str(H_list[1])+"/"+str(H_list[2])+"/"+str(H_list[3])+"/" + +str(V_list[0])+"/"+str(V_list[1])+"/"+str(V_list[2])+"/"+str(V_list[3])) + + BL.mda.go(max(kwargs['H_scan_dim'],kwargs['V_scan_dim'])) + print("\rNow setting the slits back to:") + slits_set_BL() + + print("\r") + print_warning_message("Don't forget to pull all of the diagnostics out.") + + + +############################################################################################################## +################## Slit Calibration & Beam Steering scripts ################## +############################################################################################################## + + +def Notes_from_20191212(): + print(""" looking at diode 3 in scattering chamber, open 3D all the way (2000) + WARNING: 10% energy detune is enough to see the 2 lobes with 2B but not for 1A => 20% + Red shifted (485eV) = edges give center of the grating + Blue shifted (510eV) = gaussian center gives center of the beam + => we want the slit centered on the grating center and the beam centered on the slits/grating + => 5 urad down = 1 mm negative motion on 2B-V with HEG""") + + +def procedure_alignment_M1(): + print("""\n-Start with a very red shifted line cut to localize the edges of the grating: + Set_IDraw(510) + mono(485) + Scan_NarrowSlit('2V',[0.25,-8,8,0.5]) + Scan_NarrowSlit('2H',[0.25,-4,4,0.5]) + => Verticaly: The edges/center of the grating define the center of 2V + => Horizontaly: The edges are defined by the aperture upstream. + As long as the beam makes it through the pipe to the next mirror, we are good. + Each M1 pitch will have its own slit-2H zero + It can be a good idea to check that GRT or M2 translation does not change anything. +\n-Once the slits are centered on the grating, center resonant beam on the grating (zero slit): + Get_Mirror(1) # to get current values + for roll in RangeUp(3,4,0.2): + print('\\n') + Move_M1('RZ',roll) + sleep(5) + scan_mono_vs_slit('2V',[0.25,-0.5,0.5,0.25],[490,530,2]) + for pitch in RangeUp(8.5,8.7,0.05): + print('\\nMove_M1('RY',pitch)') + Move_M1('RY',pitch) + sleep(5) + scan_mono_vs_slit('2H',[0.25,-0.5,0.5,0.25],[490,530,2]) + => The resonant beam is the slit value for the most blue shifted curve. + + WARNING: It is more accurate (and easier) to compare the leading edge of the ID peak + than trying to look at the perpendicular direction (slit line cut) because of the + asymetry in the beam intensity (uneven carbon strip along the grating?) +""") + + + # 2017_3 - HEG after opitmization: mba_b_0241-0244 + # 2018_1 - HEG before opitmization: mba_b_0005-0008 + + +def beamsteering_2B(v_position): + vroll=round(v_position*0.05/0.04,3) + if v_position<0: v_direction=' +' + else: v_direction=' -' + v_steering=v_direction+str(vroll)+' urad' + return v_steering + +def beamsteering_1A(h_position,v_position): + hrad=round(h_position*10/0.25,0) + vrad=round(v_position*10/0.25,0) + if h_position<0: h_direction=' urad outboard' + else: h_direction=' urad inboard' + if v_position<0: v_direction=' urad up' + else: v_direction=' urad down' + h_steering=str(hrad)+h_direction + v_steering=str(vrad)+v_direction + return h_steering,v_steering + + + + + +##################################################################################### +### Slit-1A Procedures +##################################################################################### + +def check_slit1A(step=0.1): + """ + Checks that Slit1A is centered on the fixed aperature/theoretical optic axis + top='m9' -> CA5 + inboard='m10' -> CA4 + + Scans the top blade - CA4 sees an step function + top_center = midpoint of motor position for zero current and when current saturates + Scans the inner blade - CA4 sees box fuction convoluted with gaussian beam position + inner_center - midpoint bewteen box edges + + SetSlit1A(0,0,inner_center,top_center) + for m in range(9,13): + Reset_Motor_User(m,'b',0) + SyncAllSlits() + + If data makes no sense then Reset_Slit1A_Procedure() + + """ + #scanning top-blade + slit1A_set(8,8,0,0) # aperture wide open + caput('29idb:m10.VAL',0) # Inboard blade centered-ish in the beam + m=9 + VAL='29idb:m'+str(m)+'.VAL' + RBV='29idb:m'+str(m)+'.RBV' + BL.mda.fillin(VAL,RBV,-4,4.0,step) + BL.mda.go() + FileNum1 = BL.mda.lastFileNum() + + #scanning inboard-blade + slit1A_set(8,8,0,0) # aperture wide open + caput('29idb:m9.VAL',0) # top blade centered-ish in the beam + m=10 + VAL='29idb:m'+str(m)+'.VAL' + RBV='29idb:m'+str(m)+'.RBV' + BL.mda.fillin(VAL,RBV,-4,4.0,step) + BL.mda.go() + FileNum2 = BL.mda.lastFileNum() + + return FileNum1, FileNum2 + + +def procedure_reset_slit1A(): + """ + Prints the procedure for Resetting Slit1A + """ + print("\n#------- Checking and Resetting the Dial -------") + print(" GoToSlit1AScribe()") + print("# if not on the scribe marks tweek the position until the scribe marks are aligned") + print(" for m in [9,10,11,12]: Reset_Motor_Dial(m,\'b\',0);SyncAllSlits()") + print("\n#------- Resetting the User -------") + print("# SetSlit1A by hand such that you have some beam coming through") + print(" Scan_SlitSize(\"1H\",start,stop,step) #looking at CA4") + print(" Scan_SlitSize(\"1V\",start,stop,step) #looking at CA4") + print("# Then SetSlit1A(1Hsize,1Vsize,0,0); where 1Hsize and 1Vsize are the size where CA4 = 0") + print(" for m in [9,10,11,12]: Reset_Motor_User(m,'b',0);SyncAllSlits()") + + +def check_ID_steering(hv=2000): + """ + Scans Slit1A center (set to a (0.25,0.25) pinhole) while looking at the back blade: + - slit center vs fixed aperture: given by the position of the edges + - beam center vs fixed aperture: given by the position of the bump in the middle + """ + slit1A_set(0.25,0.25,0,0) + ID_SP_set(hv) + scan_slit_center('1H',-3,3,0.1) + scan_slit_center('1V',-3,3,0.1) + +def scan_slit_center(slit,start,stop,step,size=0.25): + """ + slit = '1H','1V','2H' or '2V' + + Previously: Scan_SlitCenter + """ + if slit[0] == '1': + slit_name = "slit1A" + elif slit[0] == '2': + slit_name = "slit2B" + direction = slit[1] + slits_scan_center(slit_name,direction,start,stop,step,size=size) + + +def scan_slit_size(slit,start,stop,step,center=(0,0)): + """ + slit = '1H','1V','2H' or '2V' + + Previously: Scan_SlitSize + """ + if slit[0] == '1': + slit_name = "slit1A" + elif slit[0] == '2': + slit_name = "slit2B" + direction = slit[1] + slits_scan_center(slit_name,direction,start,stop,step,center=center) + + + +##################################################################################### +# Checking the beam steering uses the gas-cell to see if the beam is centered on the grating +# and that the slits are centered +##################################################################################### + +def ID_beam_profile(grt,slit_list,c_slit=1,c_energy=1,**kwargs): + """ + Makes a nice 2D image of the energy distribution of the beam across the grating at ID=500 + Does NOT put the diagnostics into the beam you need to run the following if you haven't already (AllDiagOut(); DiodeCIn()) + SlitList=["2H","2V","1H","1V"] + c_slit = scaling of step size (c=1 Slit-1: step = 0.25. Slit-2: step = 0.5) + c_energy = scaling of mono step size ( c=1 eV step = 2) + with c_slit=1 and c_energy = 1 Each slit ~ 1:10 min + + Previously + """ + switch_gratings(grt) + grt_density = mono_grating_density_get() + c=grt_density/1200 + ID=500 + eVstart,eVstop,eVstep=460,540,4 + for slit in slit_list: + if slit=="1H": + #Hsize,Vsize,Hstart,Hstop,Hstep = 0.50,2,-2,2,0.25*c_slit # => 35 min + #MonoVsSlit1AH_Go(ID,eVstart,eVstop,eVstep*c_energy,Hstart,Hstop,Hstep,Hsize,Vsize,scanIOC,**kwargs) + scan_mono_vs_slit('1H',[0.5,-2,2,0.25*c_slit],[eVstart,eVstop,eVstep],comment='Mono/Slit - 1H') + elif slit == "1V": + #Hsize,Vsize,Vstart,Vstop,Vstep = 2,0.50,-2,2,0.25*c_slit + #MonoVsSlit1AV_Go(ID,eVstart,eVstop,eVstep*c_energy,Vstart,Vstop,Vstep,Hsize,Vsize,scanIOC,**kwargs) + scan_mono_vs_slit('1V',[0.5,-2,2,0.25*c_slit],[eVstart,eVstop,eVstep],comment='Mono/Slit - 1V') + elif slit =="2H": + #Hsize,Vsize,Hstart,Hstop,Hstep = 0.50,8,-3,3,0.5*c_slit + #MonoVsSlit2BH_Go(ID,eVstart,eVstop,eVstep*c_energy,Hstart,Hstop,Hstep,Hsize,Vsize,scanIOC,**kwargs) + scan_mono_vs_slit('2H',[0.5,-3,3,0.5*c_slit],[eVstart,eVstop,eVstep],comment='Mono/Slit - 2H') + elif slit =="2V": + #Hsize,Vsize,Vstart,Vstop,Vstep = 6,0.25*c,-4*c,4*c,0.5*c_slit + #MonoVsSlit2BV_Go(ID,eVstart,eVstop,eVstep*c_energy,Vstart,Vstop,Vstep,Hsize,Vsize,scanIOC,**kwargs) + scan_mono_vs_slit('2V',[0.5,-4,4,0.5*c_slit],[eVstart,eVstop,eVstep],comment='Mono/Slit - 2V') + + +def CheckAllSlits_long(hv_list=[500],slit_list=["1H","1V","2H","2V"],**kwargs): + """ + For each photon energy in hvList, takes 3 slit curves @ mono below / resonance / above + For given SlitList + For both gratings + """ + for grt in ["HEG","MEG"]: # One full loop for a given grating and 3 energies takes 5h for average 20 + switch_gratings(grt) + for hv in hv_list: + slits_set_BL(hv) + step=hv/100.0 + start=hv-step + stop=hv+step + for slit in slit_list: + for hv in range(start,stop,step): + print("\r") + mono_energy_set(hv) + check_ID_beam_steering(slit) + + +def CheckSlitCalibration(slit_list,BL=500,hvList=[485,510],scanIOC=None,**kwargs): + """ + Slit scan for red shifted and blue shifted mono values + used to determine in the beam is centered on the grating (gaussian) + and if the slits are centered on the grating (humped) + hv=500; hvList=[485,510] + hv=1500;hvList=[hv*0.97,hv*1.01] + Note: sets the exit slit to 50 + """ + if scanIOC is None: + scanIOC=BL_ioc() + exit_slit(50) + slits_set_BL(BL) + for hv in hvList: + mono_energy_set(hv) + for slit in slit_list: + check_ID_beam_steering(slit) + print("\n") + +def check_ID_beam_steering(slit): #here + """ + checks the ID beam steering by scanning the slit with the ID detuned + if there is carbon on the mirror you might need to do the full ID_beam_profile to + find the red shifted beam + + slit = '1V','1H','2V','2H' + + Previously: CheckBeamPosition + """ + + grt_density = mono_grating_density_get() # can be plotted directly on dview using the buffer. That should + c=grt_density/1200 # be fairly quick and not require any data loading/analysis + + slit1A_set((3.5,3.5),(0,0),verbose=False) + slit2B_set((6.0,8.0),(0,0),verbose=False) # Open up all the slits to make sure we scan the full beam + + if slit == "1H": + size,start,stop,step = 0.50,-4.5,4.5,0.2 + elif slit == "1V": + size,start,stop,step = 0.50,-4.5,4.5,0.2 + elif slit == "2H": + size,start,stop,step = 0.25,-8.0,8.0,0.2 + elif slit == "2V": + size,start,stop,step = 0.25*c,-4*c,4*c,0.2*c + + scan_slit_center(slit,start,stop,step,size=size) + slits_set_BL() + + +############################################################################################################## +################## Commissioning paper curves ################## +############################################################################################################## +def FermiEdges(Energy,Slit): + EF_Table={} + EF_Table[500] = {10:20, 20:20, 50:20, 100:20, 200:20} + EF_Table[1000] = {10:50, 20:50, 50:50, 100:50, 200:50} + EF_Table[1500] = {10:100, 20:100, 50:100, 100:100, 200:100} + PE = EF_Table[Energy][Slit] + return PE + + + + +def QP_curves(ID_energy,ID_mode_list,hv_start,hv_stop,hv_step): + """ + """ + exit_slit(200) + #Switch_Grating("MEG") + #print "\r" + #print "**************** QP OFF ****************" + #for mode in list_mode: + # Switch_IDMode(mode) + # SetID_Raw(hv) + # SetSlit_BL() + # SetMono(250) + # Scan_Mono(1,start,stop,step) + # Scan_Go("b",1) + #print "\r" + #print "**************** QP ON ****************" + #Switch_IDQP("on") + for ID_mode in ID_mode_list: + polarization(ID_mode) + ID_SP_set(ID_energy) + slits_set_BL()() + mono_energy_set(250) + mono_scan_fillin(hv_start,hv_stop,hv_step) + BL.mda.go() + #Switch_IDQP("off") + #Switch_Grating("HEG") + #Switch_IDMode("RCP") + + +############################################################################################################## +################################ ID calibration scripts ############################## +############################################################################################################## + +###### Energy range follows ID ######## + +def ID_calibration_scan(ID_start,ID_stop,ID_step,bandwidth=10,QP=None,Harm=1,scanIOC=None): + """ + Sets the ID_SP and scans the mono: + start,stop,step are for ID + if QP is not None adjusts the mono range to offset accordingly + !!! DOES NOT CHANGE QP VALUE !!!! + !!! Doesn't put diodes in !!! + """ + + print(""" + !!! DOES NOT CHANGE QP VALUE !!!! + !!! Doesn't put diodes in !!!""") + + logfile_name_set(BL.endstation,filename_suffix='IDCalibration') + + #Getting mono max range based on grating + grt_density = mono_grating_density_get() + c=grt_density/1200 # c = 1 for MEG, 2 for HEG + if c == 1: + maxhv = 3000 + elif c == 2: + maxhv = 2000 + + log_print(comment="====== Starting Mono Scan vs ID ======") + + for ID_energy in RangeUp(ID_start,ID_stop,ID_step): + print("\n------------------ ID-SP @ "+str(ID_energy)+" ------------------") + mono_energy_set(ID_energy) + ID_SP_set(ID_energy) + slits_set_BL() + branch = m3r_branch() + if branch == 'd': + m3r_align() + if QP is None: + start_hv=min(ID_energy-ID_energy/(bandwidth*1.0)*Harm,maxhv) # FR update range 11/20/2019 + stop_hv=min(ID_energy+ID_energy/(bandwidth*2.0)*Harm,maxhv) + step_hv=round(ID_energy/300.0,1) +# start_hv=min(ID_energy-ID_energy/(bandwidth*2.0)*Harm,maxhv) # shift the window by doing -BW*2/+BW*1 instead of -BW*1'/'+BW*2 +# stop_hv=min(ID_energy+ID_energy/(bandwidth*1.0)*Harm,maxhv) +# step_hv=round(ID_energy/500.0,1) + else: + start_hv=min(ID_energy-ID_energy/(bandwidth*2.5)*Harm,maxhv) + stop_hv=min(ID_energy+ID_energy/(bandwidth*0.7)*Harm,maxhv) + step_hv=round(ID_energy/300.0,1) + + mono_scan_fillin(start_hv,stop_hv,step_hv) + BL.mda.go() + sleep(1) + + FileNum = BL.mda.lastFileNum + if ID_energy == ID_start: + FirstFileNum = FileNum # Record First Scan Number + + LastFileNum = FileNum # Record Last Scan Number + + print("Use: update_id_dict("+str(FirstFileNum)+","+str(LastFileNum)+"ignore=[] ,update_file,path=None,prefix='ARPES',q=True)") + + + + +def ID_calibration_mode(ID_mode,start=None,stop=None,step=25,Harm=1): + ''' + Runs full calibration with a 25 eV step (by default) for a given mode: + which = 'RCP','LCP', 'V','H' + Better to run each mode in a separated cell (print statement at the end helps with calibration) + ''' + branch = m3r_branch() + diagnostics_all_out(diode_stay_in=True) + + polarization(ID_mode) + + grt = mono_grating_get() + + QP_ratio = ID_QP_ratio_get() + + hv_min,hv_max = energy_range_min_max() + if start == None: + start = hv_min + if stop == None: + stop=hv_max-50 + + if QP_ratio <100: + stop=min(stop,1500) + QP_ratio=1 + else: + QP_ratio=None + + ID_calibration_scan(start,stop,step,QP=QP_ratio,Harm=Harm) + + +############################################################################################################## +############################## Beam Motion ############################## +############################################################################################################## +def scan_cam_motor(motor_name,start,stop,step,cam_num,ExposureTime): + """ + motor_name = 'x','y','z'... + cam_num = 1,2,3... uses cam_pv to get the pv + + Previously: Pixel_Calibration + """ + cam_scan_setup(cam_num,ADtype='TIFF') + + if BL.branch == 'ARPES': + ARPES_Motors.scan(motor_name,start,stop,step) + if BL.branch == 'Kappa': + Kappa_Motors.scan(motor_name,start,stop,step) + + cam_live() + + + +def scan_cam_hv(start,stop,step,cam_num,**kwargs): + """ + takes and image as a function of photon energy + **kwargs: + ExposureTime + Previously: BeamMotion_Vs_BL_Go + """ + cam_scan_setup(cam_num,ADtype='TIFF') + scanhv(start,stop,step,**kwargs) + + cam_live() + + + +def scan_cam_mono_zero_order(start,stop,step,cam_num,iterations=1,**kwargs): + """ + Previously: BeamMotion_Vs_MonoZero_Go + """ + i = 0 + while i < iterations: + for angle in range(start,stop+step,step): + mono_zero_order(angle) + sleep(5) + cam_snap(cam_num,ADtype='TIFF',**kwargs) + i+=1 + + cam_live() + +def scan_cam_mono_pitch(motor,angle,delta,cam_num,iterations=1,**kwargs): + """ + takes image at zero order (alpha = beta = angle) + takes image at zeror order with delta + + motor = 'grating' or 'mirror + if 'grating': + alpha = angle + beta = angle + delta + if 'mirror': + alpha = angle + delta + beta = angle + + Previously:BeamMotion_Vs_MirPitch_Go + """ + if motor == 'grating': + alpha = angle + beta = angle + delta + if motor == 'mirror': + alpha = angle + delta + beta = angle + i=0 + while i<iterations: + mono_angles_set(angle,angle) + sleep(5) + cam_snap(cam_num,ADtype='TIFF',**kwargs) + + mono_angles_set(alpha,beta) + sleep(5) + cam_snap(cam_num,ADtype='TIFF',**kwargs) + i+=1 + + cam_live() + + + diff --git a/build/lib/iexcode/macros/start_of_the_week.py b/build/lib/iexcode/macros/start_of_the_week.py new file mode 100644 index 0000000000000000000000000000000000000000..ce69923b1f444649ca4fef215592bb4872e9a601 --- /dev/null +++ b/build/lib/iexcode/macros/start_of_the_week.py @@ -0,0 +1,303 @@ +import matplotlib.pyplot as plt + +from ..instruments.diagnostics import diodeC +from ..instruments.files_and_folders import check_run +from ..instruments.utilities import wait_for_it +from ..instruments.current_amplifiers import Keithley +from ..instruments.IEX_VPU import * +from ..instruments.VLS_PGM import * +from ..instruments.xrays import * +from ..instruments.shutters import * +from ..instruments.slits import * + +from ..instruments.Kappa import * +from ..instruments.ARPES import * + +from .commissioning import * +from .ScanFunctions_plot import * + +def start_of_the_week(grt,branch,wait=False,**kwargs): + """ + This should be run every at the start of every week; 50 min total. + Switch to C-branch,. + If wait=True, wait for next day a 8:05. + + kwargs defaults: + run = None: used today's date to set run appropriatetly + repeat = False: sets everything: switches branch, sets BL_Mode to Staff, resets scan/CAs/mono + scanType = ['slit1','wire','flux','monoVslit'] + sound = False; no sounds + = True => plays sound after Slit1A scans and when script is complete + } + ID steering: (slit1A) + steering out => move beam more positive (10 urad ~ 0.25 mm) + steering up => move beam more positive (10 urad ~ 0.25 mm) + + M1 steering: (monoVslit-2V and 2H) + Roll: Rz more positive => 2V more positive (0.25 => .25 mm) + Pitch: Ry more positive => 2H more positive (0.03 => .5 mm + + Previously: StartOfTheWeek + """ + kwargs.setdefault('repeat',False) + kwargs.setdefault('run',check_run()) + kwargs.setdefault('quick',True) + kwargs.setdefault('interactive',True) + kwargs.setdefault('scanType',['slit1','wire','flux','monoVslit']) + kwargs.setdefault('sound',True) + kwargs.setdefault('extended_range',False) + + for scan in kwargs['scanType']: + if scan not in ['slit1','wire','flux','monoVslit']: + print(scan+" is not a valid scan scanType=['slit1','wire','flux','monoVslit']") + return + + + ### checking diode settings: + if branch == 'c': + diode = Keithley('b',15) + diode.autoscale() + diodeC('In') + else: + foo=input('Do you have a diode in direct beam (y or n)? >') + if foo.lower() == 'y' or foo.lower() == 'yes': + print('Resuming...') + + + ### checking QP ratio: + QP_ratio = ID_QP_ratio_get() + if QP_ratio != 100: + foo=input('QP on!!! Continue (y or n)? >') + if foo.lower() == 'y' or foo.lower() == 'yes': + print('Resuming...') + + ### Stuff that doesn't need beam & does not need to be run if repeating SoTW: + print("\n\n================== Sets Beamline & Scans:") + switch_gratings(grt) + + if not kwargs['repeat']: + switch_branch(branch) + + print("\n\n================== Sets Directory:") + + if branch=='c': + ARPES_init(BL_mode='staff') + + fname='StartOfTheWeek_log.txt' + logfile_name_set(BL.endstation,filename=fname) + + + ### checking branch shutter: + if branch_shutter_status() == False: + branch_shutter_open() + + + ### Wait for next 8AM: + if wait: + t = datetime.today() + if 0 <= t.hour <= 8: + wait_for_it(0,8,5) + else: + wait_for_it(1,8,5) + + ### checking ID: + print("\n\n================== Start ID:") + polarization('RCP') + + + ### Ready to start: + FirstScan=BL.mda.fileNum+1 + + + if not kwargs['repeat']: + log_print("\n\n================== Start Of The Week @ "+today('slash')+':\n') + + + def interactive_fct(comment='scans'): + foo=input('\nRepeat '+comment+' (y or n)? >') + if foo.lower() == 'y' or foo.lower() == 'yes': + print('\nRepeating...\n');flag=True + + else: + print('\nResuming...\n'); flag=False + return flag + + DetDict={'c':(9,7,8,15),'d':(9,7,8,14)} + detCA4,detH,detV,detDiode=DetDict[branch] + + ###### Scan front-end slit center: + if 'slit1' in kwargs['scanType']: + print("\n\n================== Slit 1A scans:") + ID_SP_set(2000) + flag=True + while flag: + + #Scan_SlitCenter('1H',-3,3,0.1,comment='Slit center - 1H') + #Scan_SlitCenter('1V',-3,3,0.1,comment='Slit center - 1V') + scan_narrow_slit('1H',[0.25,-3,3,0.1],comment='Slit center - 1H') + scan_narrow_slit('1V',[0.25,-3,3,0.1],comment='Slit center - 1V') + #SetSlit1A(4.5,4.5,0,0) + slit1A_set((4.5,4.5),(0,0)) + m=BL.mda.lastFileNum() + print('\nsteering out => move beam more positive (10 urad ~ 0.25 mm)') + print('steering up => move beam more positive (10 urad ~ 0.25 mm)') + try: + h_position=fit_mda(m-1,detCA4,1,'gauss',xrange=[-1,1]);plt.show() + v_position=fit_mda(m ,detCA4,1,'gauss',xrange=[-1,1]);plt.show() + print('\nBeam position:') + print(' - horizontal: '+str(h_position)) + print(' - vertical: '+str(v_position)) + h_steering,v_steering=beamsteering_1A(h_position,v_position) + print('\nBeam steering:') + print(' - horizontal: '+h_steering) + print(' - vertical: '+v_steering) + print('\n') + except: + print('Unable to fit position; try to tweak xrange or FWHM:') + print('fit_mda('+str(m)+','+str(detCA4)+',1,"gauss",xrange=[-1,1])') + print('fit_mda('+str(m+1)+','+str(detCA4)+',1,"gauss",xrange=[-1,1])') + print('\n') + if kwargs['sound']:playsound() + if kwargs['interactive']: flag=interactive_fct() + else: break + + ###### Wire scans: + if 'wire' in kwargs['scanType']: + ID_SP_set(2000) + slit1A_set(4.5,4.5,0,0) + scan_wire('H',comment='Wire scan - H',all_diag=False) # by default puts all meshes in + DiodeC + scan_wire('V',comment='Wire scan - V',all_diag=False) + m=BL.mda.lastFileNum() + try: + plot_mda(m-1,detH,m,detV,title='wire-H (blue) & wire-V (orange)');plt.show() + except: + print('Unable to plot.') + if kwargs['sound']:playsound() + + + ###### Mono/slit scans: + list_position=[] + if 'monoVslit' in kwargs['scanType']: + if grt=="HEG": + slit(300) + c=2 + else: + slit(200) + c=1 + print("\n\n================== Mono/slit scans:") + if 'quick' in kwargs: + energy(500) + mono_energy_set(505) + print('\n---------- Scanning slit 2B:\n') + flag=True + while flag: + scan_narrow_slit('2V',[0.25*c, -8, 8, 0.25]) + sleep(1) + scan_narrow_slit('2H',[0.25, -6, 6, 0.25]) + sleep(1) + m=BL.mda.lastFileNum() + try: + V2=fit_mda(m-1,detDiode,1*c,'gauss') + plt.show() + H2=fit_mda(m ,detDiode,1,'gauss') + plt.show() + list_position.append(V2) + list_position.append(H2) + #print(f"V2 = {round(V2,3)}") + #print(f"H2 = {round(H2,3)}") + + print('\nBeam position:') + print(f" - vertical: V1 = {round(V2,3)}") + print(f" - horizontal: H1 = {round(H2,3)}") + v_steering=beamsteering_2B(V2) + print('\nM1 roll (RZ) steering:') + print(' - vertical: ~ '+v_steering) + print(' - horizontal: reset slit 2BH center to ',str(H2)) + print('\n') + + print('\n\nWARNING: 2V slit should always be centered at zero') + print('Increasing M1 roll moves the beam more positive on 2V:') + print('\t+0.05 pitch => ~ +0.04 slit position') + print('To steer M1, use:') + print("\tGet_Mirror(1);Move_M1('RZ',x)") + except: + print('Unable to fit position.') + if kwargs['sound']:playsound() + if kwargs['interactive']: flag=interactive_fct('slit 2B') + else: break + print('\n---------- Scanning slit 1A:\n') + flag=True + while flag: + scan_narrow_slit('1V',[0.25, -4, 4, 0.1]) + sleep(1) + scan_narrow_slit('1H',[0.25, -3, 3, 0.1]) + sleep(1) + slits_set_BL() + m=BL.mda.lastFileNum() + try: + V1=fit_mda(m-1,detDiode,1,'gauss');plt.show() + H1=fit_mda(m ,detDiode,1,'gauss');plt.show() + list_position.append(V1) + list_position.append(H1) + print('\nBeam position:') + print(f" - vertical: V1 = {round(V1,3)}") + print(f" - horizontal: H1 = {round(H1,3)}") + except: + print('Unable to fit position.') + if kwargs['sound']:playsound() + if kwargs['interactive']: flag=interactive_fct('slit 1A') + else: break + print('\nBeam center fit @ [2V,2H,1V,1H]:',list_position) + print('\nTo update slit center using: update_slit_dict()\n') + else: # longer full slit scans + ID_SP_set(500) + flag=True + while flag: + mono_energy_set(500) + slits_set_BL() + n=2 if 'extended_range' in kwargs else 1 + scan_mono_vs_slit('2V',[0.25*c,-2*c*n,2*c*n,0.5],[475,515,2],comment='Mono/Slit - 2V') #10/20 min for MEG/HEG + scan_mono_vs_slit('2H',[0.25,-2*n,2*n,0.5],[475,515,2],comment='Mono/Slit - 2H') #10min + scan_mono_vs_slit('1V',[0.5,-0.75*n,0.75*n,0.25*c],[475,515,2],comment='Mono/Slit - 1V') #10min + scan_mono_vs_slit('1H',[0.5,-0.75*n,0.75*n,0.25],[475,515,2],comment='Mono/Slit - 1H') #10min + #interactive + if kwargs['interactive']: flag=interactive_fct() + else: break + + ###### Check flux: + if 'flux' in kwargs['scanType']: + if m3r_branch == 'c': + diodeC('In') + print("\n\n================== Check Flux:") + flag=True + while flag: + check_flux(stay=True) + exit_slit(50) + energy(500) + scanhv(475,525,1,comment='Mono Scan @ 500eV') + try: + m=BL.mda.lastFileNum() + plot_mda(m,detDiode,flux=3);plt.show() + except: + print('Unable to fit position.') + ### interactive + if kwargs['interactive']: flag=interactive_fct() + else: break + + diagnostics_all_out() + + print("\n\n================== All done:") + print("\nDon't forget to put back the user folder !!!!") + + ###### Plotting instructions and return first scan number + if FirstScan is not None: + log_print(comment="\nFirstScan = "+str(FirstScan)) + print('StartOfTheWeek_plot("'+branch+'",'+str(FirstScan)+')' ) + print('Beam center fit @ [2V,2H,1V,1H]:',list_position) + print('\nREMEMBER to update slit center using: update_slit_dict()') + + if kwargs['sound']: + playsound() + + return list_position + diff --git a/iexcode.egg-info/PKG-INFO b/iexcode.egg-info/PKG-INFO new file mode 100644 index 0000000000000000000000000000000000000000..c7569a8a5f1231b768831c7a738f3efe0558c8b3 --- /dev/null +++ b/iexcode.egg-info/PKG-INFO @@ -0,0 +1,12 @@ +Metadata-Version: 2.1 +Name: iexcode +Version: 0.0.1 +Summary: python scripts to run 29id of the APS +Home-page: https://github.com/xxx +Maintainer: Jessica McChesney +Maintainer-email: jmcchesn@anl.gov +License: UNKNOWN +Platform: UNKNOWN + +UNKNOWN + diff --git a/iexcode.egg-info/SOURCES.txt b/iexcode.egg-info/SOURCES.txt new file mode 100644 index 0000000000000000000000000000000000000000..e22a33a508fd45a06267a30d008faaffa8c624a0 --- /dev/null +++ b/iexcode.egg-info/SOURCES.txt @@ -0,0 +1,57 @@ +README.md +setup.py +iexcode/__init__.py +iexcode.egg-info/PKG-INFO +iexcode.egg-info/SOURCES.txt +iexcode.egg-info/dependency_links.txt +iexcode.egg-info/requires.txt +iexcode.egg-info/top_level.txt +iexcode/instruments/AD_utilities.py +iexcode/instruments/ARPES.py +iexcode/instruments/FMB_mirrors.py +iexcode/instruments/IEX_VPU.py +iexcode/instruments/IEX_endstations.py +iexcode/instruments/Kappa.py +iexcode/instruments/Kappa_Euler.py +iexcode/instruments/Kappa_det.py +iexcode/instruments/Lakeshore_335.py +iexcode/instruments/Motors.py +iexcode/instruments/Scienta.py +iexcode/instruments/VLS_PGM.py +iexcode/instruments/__init__.py +iexcode/instruments/bakeout.py +iexcode/instruments/beamline.py +iexcode/instruments/cameras.py +iexcode/instruments/conversions_constants.py +iexcode/instruments/current_amplifiers.py +iexcode/instruments/diagnostics.py +iexcode/instruments/electron_analyzer.py +iexcode/instruments/encoders.py +iexcode/instruments/files_and_folders.py +iexcode/instruments/gate_valves.py +iexcode/instruments/hxp_mirrors.py +iexcode/instruments/logfile.py +iexcode/instruments/m3r.py +iexcode/instruments/mpa.py +iexcode/instruments/remote_controlers.py +iexcode/instruments/resolution.py +iexcode/instruments/s29_temp_cntl.py +iexcode/instruments/scalers.py +iexcode/instruments/scanRecord.py +iexcode/instruments/scratch.py +iexcode/instruments/shutters.py +iexcode/instruments/slits.py +iexcode/instruments/spec_stuff.py +iexcode/instruments/staff.py +iexcode/instruments/storage_ring.py +iexcode/instruments/userCalcs.py +iexcode/instruments/utilities.py +iexcode/instruments/vortexs29.py +iexcode/instruments/xrays.py +iexcode/macros/ARPES_macros.py +iexcode/macros/BL_shutdown.py +iexcode/macros/Kappa_optimization.py +iexcode/macros/ScanFunctions_plot.py +iexcode/macros/__init__.py +iexcode/macros/commissioning.py +iexcode/macros/start_of_the_week.py \ No newline at end of file diff --git a/iexcode.egg-info/dependency_links.txt b/iexcode.egg-info/dependency_links.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/iexcode.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/iexcode.egg-info/requires.txt b/iexcode.egg-info/requires.txt new file mode 100644 index 0000000000000000000000000000000000000000..52556943b71432c57250dc0ac297d318372c7967 --- /dev/null +++ b/iexcode.egg-info/requires.txt @@ -0,0 +1,5 @@ +matplotlib +numpy +scipy +h5py +netCDF4 diff --git a/iexcode.egg-info/top_level.txt b/iexcode.egg-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..3dc2072e0b7c51426134239fbc2e3afd8f41a12f --- /dev/null +++ b/iexcode.egg-info/top_level.txt @@ -0,0 +1 @@ +iexcode diff --git a/iexcode/__pycache__/__init__.cpython-37.pyc b/iexcode/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e2d0eaad8087d6fedb2ad12bc304ce79bc95a05c Binary files /dev/null and b/iexcode/__pycache__/__init__.cpython-37.pyc differ diff --git a/iexcode/instruments/AD_utilities.py b/iexcode/instruments/AD_utilities.py new file mode 100644 index 0000000000000000000000000000000000000000..f8d43d23aed84bf5a1ee86d46cefdbb81f5d1ffa --- /dev/null +++ b/iexcode/instruments/AD_utilities.py @@ -0,0 +1,347 @@ +""" +General functions for dealing with Area Detectors and Cameras at 29ID + +work in progress need to redo +""" +############################################################################################################## +############################## General Area Detector ############################## +############################################################################################################## +import datetime +import re +from os import listdir,mkdir,chown,system,chmod +from os.path import join, isfile, exists, dirname +from time import sleep + +from epics import caget, caput +from iexcode.instruments.IEX_endstations import * +from iexcode.instruments.files_and_folders import get_next_fileNumber + + +def AD_CurrentDirectory(ADplugin): + """ + returns the current directory for area detector SavePlugin + handles both Winodws and linux IOCs + ADplugin = "29idc_ps1:TIFF1:"; $(P)$(SavePlugin) + """ + SubDir=caget(ADplugin+"FilePath",as_string=True) + if SubDir[0] == 'X': + Dir='/net/s29data/export/data_29idb/' + SubDir=SubDir.split('\\')[1:] + elif SubDir[0] == 'Y': + Dir='/net/s29data/export/data_29idc/' + SubDir=SubDir.split('\\')[1:] + elif SubDir[0] == 'Z': + Dir='/net/s29data/export/data_29idd/' + SubDir=SubDir.split('\\')[1:] + else: + Dir = SubDir + SubDir=[] + FilePath=join(Dir,*SubDir,'') + return FilePath + +def AD_prefix(ADplugin): + """ + returns the prefix for AreaDetector plugin based on ADplugin + """ + prefix = caget(ADplugin+"FileName_RBV",as_string=True) + return prefix + +def AD_EnableStats(ADplugin): + """ + Enabling the statistics in an AreaDector + ADplugin = "29idc_ps1:Stats1:"; (ADplugin=$(P)$(StatsPlugin)) + """ + caput(ADplugin+"EnableCallbacks","Enable") + caput(ADplugin+"ComputeStatistics","Yes") + caput(ADplugin+"ComputeCentroid","Yes") + + +def AD_SaveFileSetup(ADplugin,mda,**kwargs): + """ + ADplugin = "29id_ps1:TIFF1:" which IOC and which filesaving plugin + (ADplugin=$(P)$(SavePlugin)) + uses to get the current MDA directory and then set the path to one up + /dtype + MDA_CurrentDirectory(scanIOC=None) + + **kwargs (defaults) + scanIOC = BL_ioc() + userpath = extracted from ScanRecord unless specified + subfolder = taken from ADplugin unless specified + filepath = userpath/subfolder + + prefix = default same as subfolder + ext = file extension is extracted for ADplugin unless specified + (TIFF -> tif, HDF -> h5, ...) + FileTemplate="%s%s_%4.4d."+ext; format for filename first %s = filepath, second %s = prefix + + """ + kwargs.setdefault("userpath",dirname(dirname(mda.filepath))) + kwargs.setdefault("subfolder",ADplugin.split(":")[-2][:-1]) + + kwargs.setdefault("prefix",ADplugin.split(":")[-2][:-1]) + extDict={"TIFF":".tif","HDF":"h5"} + kwargs.setdefault("ext",ADplugin.split(":")[-2][:-1]) + kwargs.setdefault("FileTemplate","%s%s_%4.4d."+kwargs["ext"]) + + kwargs.setdefault("debug",False) + + if kwargs['debug']: + print("kwargs: ",kwargs) + + fpath=join(kwargs['userpath'],kwargs['subfolder'],'') + print("\nFolder: " + fpath) + if not (exists(fpath)): + fileNumber=1 + else: + fileNumber=get_next_fileNumber(fpath,kwargs["prefix"]) + print("NextFile: "+str(fileNumber)) + caput(ADplugin+"CreateDirectory",-1) #allows IOC to create directories + caput(ADplugin+"FilePath",fpath) + caput(ADplugin+"FileName",kwargs["prefix"]) + caput(ADplugin+"FileNumber",fileNumber) + + #setup AD + caput(ADplugin+"FileTemplate",kwargs["FileTemplate"]) + caput(ADplugin+"AutoIncrement","Yes") + caput(ADplugin+"AutoSave","Yes") + +def AD_CurrentPrefix(ADplugin): + """ + returns the prefix (without _) for area detector SavePlugin + ADplugin = "29id_ps1:TIFF1:"; $(P)$(SavePlugin) + """ + Prefix=caget(ADplugin+'FileName',as_string=True) + return Prefix + +def AD_CurrentRun(ADplugin): + """ + returns the curent run specified in the filepath for area detector SavePlugin + ADplugin = "29id_ps1:TIFF1:"; $(P)$(SavePlugin) + """ + fpath=caget(ADplugin+"FilePath",as_string=True) + current_run=re.findall("\d\d\d\d_\d", fpath)[0] + return current_run + +def AD_CurrentUser(ADplugin): + """ + returns the curent user specified in the filepath for area detector SavePlugin + ADplugin = "29id_ps1:TIFF1:"; $(P)$(SavePlugin) + """ + folder_name = ADplugin.split(":")[1] + folder_name[:-1] + SubDir=caget(ADplugin+":FilePath",as_string=True) + if SubDir[0] == 'X': + current_user='Staff' + elif SubDir[0] == 'Y': + m=SubDir.find(AD_CurrentRun(ADplugin)) + n=SubDir.find(folder_name) + current_user=SubDir[m+7:n] + else: current_user=None + return current_user + +def AD_DoneSingleSave(ADplugin,**kwargs): + """ + sets and AD up ready to save images + Acquire -> Done + ImageMode -> Single + Save -> Enable + e.g. ADplugin="29id_ps2:TIFF1:" + + **kwargs: + P=first part of ADplugin if not specified + R="cam1:"; other AD have "det1:" + """ + kwargs.setdefault("P",ADplugin.split(":")[0]+":") + kwargs.setdefault("R","cam1:") + caput(kwargs["P"]+kwargs["R"]+"Acquire","Done",wait=True,timeout=5*60);sleep(.1) + caput(kwargs["P"]+kwargs["R"]+"ImageMode","Single");sleep(.5) + caput(ADplugin+"EnableCallbacks","Enable");sleep(.1) + +def AD_FreeRun(ADplugin,**kwargs): + """ + sets and AD to disable saving and free run + Saving -> Disable + Acquire -> Done + ImageMode -> Single + + e.g. ADplugin="29id_ps2:TIFF1:" + + **kwargs: + P=first part of ADplugin if not specified + R="cam1:"; other AD have "det1:" + """ + kwargs.setdefault("P",ADplugin.split(":")[0]+":") + kwargs.setdefault("R","cam1:") + caput(kwargs["P"]+kwargs["R"]+"Acquire","Done",wait=True,timeout=5*60) + caput(ADplugin+"EnableCallbacks","Disable");sleep(.1) + caput(kwargs["P"]+kwargs["R"]+"ImageMode","Continuous");sleep(.1) + caput(kwargs["P"]+kwargs["R"]+"Acquire","Acquire");sleep(.1) + + +def AD_snap(ADplugin,**kwargs): + """ + takes an image and save the image for ADplugin + e.g. ADplugin="29id_ps2:TIFF1:" + + use AD_SaveFileSetup to set filepath, prefix etc. + use AD_CurrentDirectory to see current directory + use AD_prefix to see current prefix + + **kwargs: + P=first part of ADplugin if not specified + R="cam1:"; other AD have "det1:" + + ExposureTime: changes both the exposure time and the acquire time for the snapshot + resets after acquisition + FreeRun: True => disable setting and go back to continuous acquision + False => leave saving enabled and camera in single acquision + """ + kwargs.setdefault("P",ADplugin.split(":")[0]+":") + kwargs.setdefault("R","cam1:") + kwargs.setdefault("FreeRun",True) + + expT=caget(kwargs["P"]+kwargs["R"]+"AcquireTime_RBV") + acqT=caget(kwargs["P"]+kwargs["R"]+"AcquirePeriod_RBV") + + AD_DoneSingleSave(ADplugin,**kwargs) + + if "ExposureTime" in kwargs: + caput(kwargs["P"]+kwargs["R"]+"AcquireTime",kwargs["ExposureTime"]) + caput(kwargs["P"]+kwargs["R"]+"AcquireTime",kwargs["ExposureTime"]+.01) + + caput(kwargs["P"]+kwargs["R"]+"Acquire","Acquire",wait=True,timeout=5*60) + + if "ExposureTime" in kwargs: + caput(kwargs["P"]+kwargs["R"]+"AcquireTime",expT) + caput(kwargs["P"]+kwargs["R"]+"AcquireTime",acqT) + + if kwargs["FreeRun"]: + sleep(.1) + AD_FreeRun(ADplugin,**kwargs) + + + +def AD_ScanTrigger(ADplugin,mda,**kwargs): + """ + Add Triggering of AreaDetector to scanIOC + ADplugin = "29idc_ps1:TIFF1:" (ADplugin=$(P)$(SavePlugin)) + + **kwargs + scanIOC = "29id"+BL_ioc() if not specified + scanDIM = 1 + P=first part of ADplugin if not specified + R="cam1:"; other AD have "det1" + detTrig = 2; detectorTrigger number + """ + kwargs.setdefault("scanDIM",1) + kwargs.setdefault("P",ADplugin.split(":")[0]+":") + kwargs.setdefault("R","cam1:") + kwargs.setdefault("detTrig",2) + + scanPV=mda.ioc+"scan"+str(kwargs["scanDIM"]) + trigger=".T"+str(kwargs["detTrig"])+"PV" + caput(scanPV+trigger,kwargs["P"]+kwargs["R"]+"Acquire",wait=True,timeout=5*60) + +def ADplugin_ScanSetup(ADplugin,mda, **kwargs): + """ + stop the acquisition, puts in ImageMode=Single + enables saving + add to detector trigger + Does not press go + + ADplugin = "29idc_ps1:TIFF1:"; (ADplugin=$(P)$(SavePlugin)) + **kwargs + # AD_ScanTrigger + scanIOC = "29id"+BL_ioc() if not specified + scanDIM = 1 + P=first part of ADplugin if not specified + R="cam1:"; other AD have "det1:" + detTrig = 2; detectorTrigger number + + # AD_SaveFileSetup + filepath=userpath (from BL_ioc scanRecord)+"/dtype" + (e.g. filepath="/net/s29data/export/data_29id"+folder+"/"+run+"/"+userName+"/"+df) + dtype = taken from ADplugin + FileTemplate="%s%s_%4.4d."+dtype; format for filename first %s = filepath, second %s = prefix + prefix = dtype by default + + """ + #from AD_ScanTrigger + kwargs.setdefault("P",ADplugin.split(":")[0]+":") + kwargs.setdefault("R","cam1:") + + AD_DoneSingleSave(ADplugin,**kwargs) + + AD_SaveFileSetup(ADplugin,**kwargs) + AD_ScanTrigger(ADplugin, **kwargs) + trigger=".T"+str(kwargs["detTrig"])+"PV" + scanPV=mda.ioc+"scan"+str(kwargs["scanDIM"]) + print("WARNING: you need to need to disable saving and clear the trigger by hand after the scan") + print("\tAD_FreeRun("+ADplugin+"); caput("+scanPV+trigger+",'')") + +def AD_ROI_setup(AD,ROInum,xcenter=500,ycenter=500,xsize=50,ysize=50,binX=1,binY=1): + """ + AD = "29id_ps4" + AD = "29iddMPA" + """ + # roiNUM=1 MPA_ROI_SetUp(535,539,50,50) center of MCP + + ADplugin=AD+':ROI'+str(ROInum)+':' + xstart=xcenter-xsize/2.0 + ystart=ycenter-ysize/2.0 + caput(ADplugin+'MinX',xstart) + caput(ADplugin+'MinY',ystart) + caput(ADplugin+'SizeX',xsize) + caput(ADplugin+'SizeY',ysize) + caput(ADplugin+'BinX',binX) + caput(ADplugin+'BinY',binY) + caput(ADplugin+'EnableCallbacks','Enable') + print(ADplugin+' - '+caget(ADplugin+'EnableCallbacks_RBV',as_string=True)) + #MPA_ROI_Stats(roiNUM) + +def AD_OVER_SetUp(AD,ROInum,OVERnum,linewidth=5,shape='Rectangle'): + """ + AD = "29id_ps4" + AD = "29iddMPA" + shape= 'Cross', 'Rectangle', 'Ellipse','Text' + """ + OVER1=AD+":Over1:"+str(OVERnum)+":" + ROI=AD+":ROI"+str(ROInum)+":" + + caput(ROI+'EnableCallbacks','Enable') + caput(OVER1+"Name","ROI"+str(ROInum)) + caput(OVER1+"Shape",shape) + caput(OVER1+"Red",0) + caput(OVER1+"Green",255) + caput(OVER1+"Blue",0) + caput(OVER1+'WidthX',linewidth) + caput(OVER1+'WidthY',linewidth) + + caput(OVER1+"PositionXLink.DOL",ROI+"MinX_RBV CP") + caput(OVER1+"SizeXLink.DOL",ROI+"SizeX_RBV CP") + caput(OVER1+"PositionYLink.DOL",ROI+"MinY_RBV CP") + caput(OVER1+"SizeYLink.DOL",ROI+"SizeY_RBV CP") + + caput(OVER1+"Use","Yes") + + +def AD_OverLayCenter(x,y,AD,OverLay=1,Num=1): + """ + Sets CenterX and CenterY for AD:Over(OverLay):Num: + eg. 29id_ps2:Over1:1: AD='29id_ps2',Overlay=1, Num=1 + """ + caput(AD+":Over"+str(OverLay)+":"+str(Num)+":CenterX",x) + caput(AD+":Over"+str(OverLay)+":"+str(Num)+":CenterY",y) + +def AD_OverLayCenter_get(AD,OverLay=1,Num=1): + """ + Sets CenterX and CenterY for AD:Over(OverLay):Num: + eg. 29id_ps2:Over1:1: AD='29id_ps2',Overlay=1, Num=1 + """ + print('x = '+str(caget(AD+":Over"+str(OverLay)+":"+str(Num)+":CenterX"))) + print('y = '+str(caget(AD+":Over"+str(OverLay)+":"+str(Num)+":CenterY"))) + + + + + diff --git a/iexcode/instruments/ARPES.py b/iexcode/instruments/ARPES.py index b07a8c491f0306e935ab1eba28c10e828811b2b1..90f825f9fa07a93d36c82263dbf7404f0ea79efd 100644 --- a/iexcode/instruments/ARPES.py +++ b/iexcode/instruments/ARPES.py @@ -2,27 +2,28 @@ import numpy as np from time import sleep from epics import caget,caput,PV -from .IEX_endstations import * -from .staff import staff_detector_dictionary - -from .files_and_folders import check_run,make_user_folders,folder_mda -from .staff import staff_detector_dictionary -from .logfile import logfile_name_set,logfile_header - -from .conversions_constants import * -from .utilities import * -from .userCalcs import userStringSeq_clear, userStringSeq_pvs - -from .scanRecord import * -from .Motors import * -from .xrays import * -from .current_amplifiers import * -from .gate_valves import valve_close, branch_valves -from .shutters import branch_shutter_close -from .slits import slit3C_get - -from .Lakeshore_335 import Lakeshore_reset -from .electron_analyzer import folders_EA,EA + +from iexcode.instruments.IEX_endstations import * +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.logfile import logfile_name_set,logfile_header + +from iexcode.instruments.conversions_constants import * +from iexcode.instruments.utilities import * +from iexcode.instruments.userCalcs import userStringSeq_clear, userStringSeq_pvs + +from iexcode.instruments.scanRecord import * +from iexcode.instruments.Motors import * +from iexcode.instruments.xrays import * +from iexcode.instruments.current_amplifiers import * +from iexcode.instruments.gate_valves import valve_close, branch_valves +from iexcode.instruments.shutters import branch_shutter_close +from iexcode.instruments.slits import slit3C_get + +from iexcode.instruments.Lakeshore_335 import Lakeshore_reset +from iexcode.instruments.electron_analyzer import folders_EA,EA ############################################################################# diff --git a/iexcode/instruments/FMB_mirrors.py b/iexcode/instruments/FMB_mirrors.py index c7c0069713de70bca39173e5fa7265b05c95e32d..888d9b9425b99a75ac9d39dcac6447fafe0680f7 100644 --- a/iexcode/instruments/FMB_mirrors.py +++ b/iexcode/instruments/FMB_mirrors.py @@ -2,9 +2,9 @@ from time import sleep from epics import caget, caput -from .IEX_endstations import * -from .utilities import read_dict, print_warning_message -from .m3r import m3r_branch +from iexcode.instruments.IEX_endstations import * +from iexcode.instruments.utilities import read_dict, print_warning_message +from iexcode.instruments.m3r import m3r_branch M0M1_fpath="/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/Dict_IDCal.txt" diff --git a/iexcode/instruments/IEX_VPU.py b/iexcode/instruments/IEX_VPU.py index 10274c00e35def08a4b8ea7f5bd777cfb61f812c..6678eb16903a7372b42583b5b4cfae682fa56a56 100644 --- a/iexcode/instruments/IEX_VPU.py +++ b/iexcode/instruments/IEX_VPU.py @@ -6,10 +6,10 @@ import numpy.polynomial.polynomial as poly from epics import caget, caput -from .utilities import dateandtime, print_warning_message, read_dict -from .shutters import main_shutter_check_open -from .VLS_PGM import mono_grating_get -from .userCalcs import userCalcOut_clear +from iexcode.instruments.utilities import dateandtime, print_warning_message, read_dict +from iexcode.instruments.shutters import main_shutter_check_open +from iexcode.instruments.VLS_PGM import mono_grating_get +from iexcode.instruments.userCalcs import userCalcOut_clear IDcal_fpath="/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/Dict_IDCal.txt" diff --git a/iexcode/instruments/IEX_endstations.py b/iexcode/instruments/IEX_endstations.py index 5c3fd1895611de62aa2c47eb62225feae413d52e..94ee6e1eb9ce4b609d49ca490ac53f24acb5cf32 100644 --- a/iexcode/instruments/IEX_endstations.py +++ b/iexcode/instruments/IEX_endstations.py @@ -10,6 +10,8 @@ it makes the default stuff work this will prompt for the endstation and will set the default parameters, look at the init kwargs to see which defaults you can change. """ +global BL +BL = None class Endstation: """ diff --git a/iexcode/instruments/Kappa.py b/iexcode/instruments/Kappa.py index 6fcb40d23ba58d30f716673b87569d6cb4f4c838..18c98109e657face5c89a1a35b50e2ae272c9966 100644 --- a/iexcode/instruments/Kappa.py +++ b/iexcode/instruments/Kappa.py @@ -3,27 +3,28 @@ from time import sleep from math import floor from epics import caget, caput,PV -from .IEX_endstations import * -from .staff import staff_detector_dictionary - -from .files_and_folders import check_run,make_user_folders,folder_mda -from .staff import staff_detector_dictionary -from .logfile import logfile_name_set,logfile_header - -from .conversions_constants import * -from .utilities import * -from .userCalcs import userStringSeq_clear, userStringSeq_pvs - -from .scanRecord import * -from .Motors import * -from .xrays import * -from .current_amplifiers import * -from .gate_valves import valve_close, branch_valves -from .shutters import branch_shutter_close -from .slits import slit3D_get - -from .Kappa_det import * -from .spec_stuff import folders_spec + +from iexcode.instruments.IEX_endstations import * +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.logfile import logfile_name_set,logfile_header + +from iexcode.instruments.conversions_constants import * +from iexcode.instruments.utilities import * +from iexcode.instruments.userCalcs import userStringSeq_clear, userStringSeq_pvs + +from iexcode.instruments.scanRecord import * +from iexcode.instruments.Motors import * +from iexcode.instruments.xrays import * +from iexcode.instruments.current_amplifiers import * +from iexcode.instruments.gate_valves import valve_close, branch_valves +from iexcode.instruments.shutters import branch_shutter_close +from iexcode.instruments.slits import slit3D_get + +from iexcode.instruments.Kappa_det import * +from iexcode.instruments.spec_stuff import folders_spec diff --git a/iexcode/instruments/Kappa_Euler.py b/iexcode/instruments/Kappa_Euler.py index cd2dbfba809e9dd872a3dbbd3429210cf57ff883..42dfe2f1bac9ec223a1c6a78a4d20ab9f32720bf 100644 --- a/iexcode/instruments/Kappa_Euler.py +++ b/iexcode/instruments/Kappa_Euler.py @@ -1,9 +1,9 @@ import numpy as np from epics import caget, caput -from .userCalcs import userCalcOut_clear -from .IEX_endstations import mda -from .userCalcs import userCalcOut_clear +from iexcode.instruments.userCalcs import userCalcOut_clear +from iexcode.instruments.IEX_endstations import mda +from iexcode.instruments.userCalcs import userCalcOut_clear #### Obsolete? diff --git a/iexcode/instruments/Kappa_det.py b/iexcode/instruments/Kappa_det.py index 14b2f04beb839662c0cc883b804fbd1656527838..9a1a19071153d757e6dd4897cf40339b8fd4a73f 100644 --- a/iexcode/instruments/Kappa_det.py +++ b/iexcode/instruments/Kappa_det.py @@ -1,7 +1,7 @@ from time import sleep from epics import caget, caput -from .IEX_endstations import Motors +from iexcode.instruments.IEX_endstations import Motors ############################################################################################################## diff --git a/iexcode/instruments/Lakeshore_335.py b/iexcode/instruments/Lakeshore_335.py index 080c578697c5042e8d578d2805c132f837261847..5acc6b95dd8ba5c3da389836f2b159966a62fd99 100644 --- a/iexcode/instruments/Lakeshore_335.py +++ b/iexcode/instruments/Lakeshore_335.py @@ -7,8 +7,8 @@ import numpy as np from epics import caget, caput -from .IEX_endstations import * -from .utilities import read_dict +from iexcode.instruments.IEX_endstations import * +from iexcode.instruments.utilities import read_dict def Lakeshore_reset(pv,d): """ diff --git a/iexcode/instruments/Motors.py b/iexcode/instruments/Motors.py index 24085c5a29908b4789a68ab03e4a8979504fd9ac..119b51bb725c0a065f3f6eb245b342d17eb3dad4 100644 --- a/iexcode/instruments/Motors.py +++ b/iexcode/instruments/Motors.py @@ -3,7 +3,7 @@ from math import floor from epics import caget, caput -from IEX_endstations import * +from iexcode.instruments.IEX_endstations import * class Motors: diff --git a/iexcode/instruments/VLS_PGM.py b/iexcode/instruments/VLS_PGM.py index 4ca6dd8164e2089ba1132de1861e722a0674ec6e..8f7bfdc225a080961c962b0d084059f2b535f179 100644 --- a/iexcode/instruments/VLS_PGM.py +++ b/iexcode/instruments/VLS_PGM.py @@ -7,8 +7,8 @@ import numpy as np from epics import caget,caput -from .IEX_endstations import * -from .utilities import print_warning_message,read_dict +from iexcode.instruments.IEX_endstations import * +from iexcode.instruments.utilities import print_warning_message,read_dict ############################################################################################################## diff --git a/iexcode/instruments/__init__.py b/iexcode/instruments/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e244a3c105e5bc09da608c5fd6134ba1ef425528 --- /dev/null +++ b/iexcode/instruments/__init__.py @@ -0,0 +1,42 @@ + +""" from iexcode.instruments.AD_utilites import * +from iexcode.instruments.ARPES import * +from iexcode.instruments.bakeout import * +from iexcode.instruments.beamline import * +from iexcode.instruments.cameras import * +from iexcode.instruments.conversions_constants import * +from iexcode.instruments.current_amplifiers import * +from iexcode.instruments.diagnostics import * +from iexcode.instruments.electron_analyzer import * +from iexcode.instruments.encoders import * +from iexcode.instruments.files_and_folders import * +from iexcode.instruments.FMB_mirrors import * +from iexcode.instruments.gate_valves import * +from iexcode.instruments.hxp_mirrors import * +from iexcode.instruments.IEX_endstations import * +from iexcode.instruments.IEX_VPU import * +from iexcode.instruments.Kappa import * +from iexcode.instruments.Kappa_det import * +from iexcode.instruments.Kappa_Euler import * +from iexcode.instruments.Lakeshore_335 import * +from iexcode.instruments.logfile import * +from iexcode.instruments.m3r import * +from iexcode.instruments.Motors import * +from iexcode.instruments.mpa import * +from iexcode.instruments.remote_controlers import * +from iexcode.instruments.resolution import * +from iexcode.instruments.s29_temp_cntl import * +from iexcode.instruments.scalers import * +from iexcode.instruments.Scienta import * +from iexcode.instruments.shutters import * +from iexcode.instruments.slits import * +from iexcode.instruments.spec_stuff import * +from iexcode.instruments.staff import * +from iexcode.instruments.storage_ring import * +from iexcode.instruments.userCalcs import * +from iexcode.instruments.utilities import * +from iexcode.instruments.VLS_PGM import * +from iexcode.instruments.vortexs29 import * +from iexcode.instruments.xrays import * + + """ diff --git a/iexcode/instruments/__pycache__/AD_utilites.cpython-37.pyc b/iexcode/instruments/__pycache__/AD_utilites.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8a370ff2b8c85e414b0f9ab7954b00e977d81b09 Binary files /dev/null and b/iexcode/instruments/__pycache__/AD_utilites.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/AD_utilities.cpython-37.pyc b/iexcode/instruments/__pycache__/AD_utilities.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..763286c8ddcdce49fed5d93a0cf42c0560f773e6 Binary files /dev/null and b/iexcode/instruments/__pycache__/AD_utilities.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/ARPES.cpython-37.pyc b/iexcode/instruments/__pycache__/ARPES.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..062ed0acd605454bc28bed0f3204edf64921a4eb Binary files /dev/null and b/iexcode/instruments/__pycache__/ARPES.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/FMB_mirrors.cpython-37.pyc b/iexcode/instruments/__pycache__/FMB_mirrors.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cc28ad732f71f5749fe7379b7c1c41463fa49469 Binary files /dev/null and b/iexcode/instruments/__pycache__/FMB_mirrors.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/IEX_VPU.cpython-37.pyc b/iexcode/instruments/__pycache__/IEX_VPU.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..48fdfabc4675e10f548048eafc93655f24cb372c Binary files /dev/null and b/iexcode/instruments/__pycache__/IEX_VPU.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/IEX_endstations.cpython-37.pyc b/iexcode/instruments/__pycache__/IEX_endstations.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b4ef735bafb06232202d431f08609321d27de902 Binary files /dev/null and b/iexcode/instruments/__pycache__/IEX_endstations.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/Kappa.cpython-37.pyc b/iexcode/instruments/__pycache__/Kappa.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b280eebee6bb33b0a5a9ee70a1958a91420d40e9 Binary files /dev/null and b/iexcode/instruments/__pycache__/Kappa.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/Kappa_Euler.cpython-37.pyc b/iexcode/instruments/__pycache__/Kappa_Euler.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d7e5066528a6d569653c3be9a202fe97ce5d86f4 Binary files /dev/null and b/iexcode/instruments/__pycache__/Kappa_Euler.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/Kappa_det.cpython-37.pyc b/iexcode/instruments/__pycache__/Kappa_det.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..64a16ee6fa9eb6ab0e825aeb9dc61f7afccee3c6 Binary files /dev/null and b/iexcode/instruments/__pycache__/Kappa_det.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/Lakeshore_335.cpython-37.pyc b/iexcode/instruments/__pycache__/Lakeshore_335.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8fe68e9b0219fe031f8768107e920399efdadc2c Binary files /dev/null and b/iexcode/instruments/__pycache__/Lakeshore_335.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/Motors.cpython-37.pyc b/iexcode/instruments/__pycache__/Motors.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c3ada008630f4d6119799aa0b66f9b538493f799 Binary files /dev/null and b/iexcode/instruments/__pycache__/Motors.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/Scienta.cpython-37.pyc b/iexcode/instruments/__pycache__/Scienta.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9008e02435a9fc2c2c5df84e805f720754feb2a6 Binary files /dev/null and b/iexcode/instruments/__pycache__/Scienta.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/VLS_PGM.cpython-37.pyc b/iexcode/instruments/__pycache__/VLS_PGM.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b24f7623fd135e0ec917cb7d239a015d5dc153ef Binary files /dev/null and b/iexcode/instruments/__pycache__/VLS_PGM.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/__init__.cpython-37.pyc b/iexcode/instruments/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4c3c008b246ea4aaf58e2d55d10549b1f5dd589b Binary files /dev/null and b/iexcode/instruments/__pycache__/__init__.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/bakeout.cpython-37.pyc b/iexcode/instruments/__pycache__/bakeout.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ed7fa33afb66085ab5615af80990bfae05fdd2fe Binary files /dev/null and b/iexcode/instruments/__pycache__/bakeout.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/beamline.cpython-37.pyc b/iexcode/instruments/__pycache__/beamline.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bb16662015007d4b73929f7a716b9331a54537d8 Binary files /dev/null and b/iexcode/instruments/__pycache__/beamline.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/cameras.cpython-37.pyc b/iexcode/instruments/__pycache__/cameras.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..314916561858f01cd5b932833b4edd3f4acfa988 Binary files /dev/null and b/iexcode/instruments/__pycache__/cameras.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/conversions_constants.cpython-37.pyc b/iexcode/instruments/__pycache__/conversions_constants.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2eaf10078a2d3ae7767b79bdbca730a979c03442 Binary files /dev/null and b/iexcode/instruments/__pycache__/conversions_constants.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/current_amplifiers.cpython-37.pyc b/iexcode/instruments/__pycache__/current_amplifiers.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..17f97f1549d6930c4f0d1af030b664f4227c3664 Binary files /dev/null and b/iexcode/instruments/__pycache__/current_amplifiers.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/diagnostics.cpython-37.pyc b/iexcode/instruments/__pycache__/diagnostics.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bc05a7a8e2024e0b4a86b65d0f8a0ca36bdad5f6 Binary files /dev/null and b/iexcode/instruments/__pycache__/diagnostics.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/electron_analyzer.cpython-37.pyc b/iexcode/instruments/__pycache__/electron_analyzer.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..91ff70dc60fd8a66b8eb2c045939a252083917e3 Binary files /dev/null and b/iexcode/instruments/__pycache__/electron_analyzer.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/encoders.cpython-37.pyc b/iexcode/instruments/__pycache__/encoders.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3b073fe79b3370736b5f54c0b7df04e2a5372cc9 Binary files /dev/null and b/iexcode/instruments/__pycache__/encoders.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/files_and_folders.cpython-37.pyc b/iexcode/instruments/__pycache__/files_and_folders.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d07f6e1e79cca22aff31195d4481cfe94d9ffbaa Binary files /dev/null and b/iexcode/instruments/__pycache__/files_and_folders.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/gate_valves.cpython-37.pyc b/iexcode/instruments/__pycache__/gate_valves.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b226d256630f6017a49ca7160868608128964e54 Binary files /dev/null and b/iexcode/instruments/__pycache__/gate_valves.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/hxp_mirrors.cpython-37.pyc b/iexcode/instruments/__pycache__/hxp_mirrors.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8747a50a2eed658297f8b7cb72d64d78f027bda7 Binary files /dev/null and b/iexcode/instruments/__pycache__/hxp_mirrors.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/logfile.cpython-37.pyc b/iexcode/instruments/__pycache__/logfile.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b49542070a25057382ecc6276ee31b7fe9f44a17 Binary files /dev/null and b/iexcode/instruments/__pycache__/logfile.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/m3r.cpython-37.pyc b/iexcode/instruments/__pycache__/m3r.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bc9f6764e739a8d6050c03f89d8ed03dc58736b8 Binary files /dev/null and b/iexcode/instruments/__pycache__/m3r.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/mpa.cpython-37.pyc b/iexcode/instruments/__pycache__/mpa.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..706901ac024918e144fc9eece5186afcac389293 Binary files /dev/null and b/iexcode/instruments/__pycache__/mpa.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/remote_controlers.cpython-37.pyc b/iexcode/instruments/__pycache__/remote_controlers.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6af0c322f5a4b610f11108737fbae1bc8057e3ec Binary files /dev/null and b/iexcode/instruments/__pycache__/remote_controlers.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/resolution.cpython-37.pyc b/iexcode/instruments/__pycache__/resolution.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ff69f443a3bdb693d5a4a10a67e75ff819044f0a Binary files /dev/null and b/iexcode/instruments/__pycache__/resolution.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/s29_temp_cntl.cpython-37.pyc b/iexcode/instruments/__pycache__/s29_temp_cntl.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fb69f7e781be3eb592bbd3fe33c50cba8a604c99 Binary files /dev/null and b/iexcode/instruments/__pycache__/s29_temp_cntl.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/scalers.cpython-37.pyc b/iexcode/instruments/__pycache__/scalers.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..66dfe7809dd855ff40fe37bc83daf9b7275f17a3 Binary files /dev/null and b/iexcode/instruments/__pycache__/scalers.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/scanRecord.cpython-37.pyc b/iexcode/instruments/__pycache__/scanRecord.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4a2f063245c768dd7a2f4c18e550b51ae6fa01c5 Binary files /dev/null and b/iexcode/instruments/__pycache__/scanRecord.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/shutters.cpython-37.pyc b/iexcode/instruments/__pycache__/shutters.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..63ecf2bc4e4cee714175f614eaa967f2b1e6e58c Binary files /dev/null and b/iexcode/instruments/__pycache__/shutters.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/slits.cpython-37.pyc b/iexcode/instruments/__pycache__/slits.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1d3c0b6595d26512aaace68743436f4a86bc9707 Binary files /dev/null and b/iexcode/instruments/__pycache__/slits.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/spec_stuff.cpython-37.pyc b/iexcode/instruments/__pycache__/spec_stuff.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..233507689e4b15634113b3e21e2bbb3cc81c6e5a Binary files /dev/null and b/iexcode/instruments/__pycache__/spec_stuff.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/staff.cpython-37.pyc b/iexcode/instruments/__pycache__/staff.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c323fc27e5c18ca6a135a8417e28121eee33a507 Binary files /dev/null and b/iexcode/instruments/__pycache__/staff.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/storage_ring.cpython-37.pyc b/iexcode/instruments/__pycache__/storage_ring.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..efa0198e6e77c11ece2df7d1e27b632650dc0c14 Binary files /dev/null and b/iexcode/instruments/__pycache__/storage_ring.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/userCalcs.cpython-37.pyc b/iexcode/instruments/__pycache__/userCalcs.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..580ff6a9df83ae20d6aa1f0833e6156dee94d33f Binary files /dev/null and b/iexcode/instruments/__pycache__/userCalcs.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/utilities.cpython-37.pyc b/iexcode/instruments/__pycache__/utilities.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5d801bc7a5477c18181ad534cbc761ccf908fe29 Binary files /dev/null and b/iexcode/instruments/__pycache__/utilities.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/vortexs29.cpython-37.pyc b/iexcode/instruments/__pycache__/vortexs29.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ac73f08f263bedd80815a13b5b4a6dae8cf422fb Binary files /dev/null and b/iexcode/instruments/__pycache__/vortexs29.cpython-37.pyc differ diff --git a/iexcode/instruments/__pycache__/xrays.cpython-37.pyc b/iexcode/instruments/__pycache__/xrays.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6d7ea418488f9414d9abefdb6532e7066cd55956 Binary files /dev/null and b/iexcode/instruments/__pycache__/xrays.cpython-37.pyc differ diff --git a/iexcode/instruments/backups.py b/iexcode/instruments/backups.py deleted file mode 100644 index 05d3c3aa0baf555372cbc61939de622a85ec0e5a..0000000000000000000000000000000000000000 --- a/iexcode/instruments/backups.py +++ /dev/null @@ -1,339 +0,0 @@ -def ARPES_scan_before_sequence(**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(BL.ioc, seq_num) - - #clear and write the before scan user sequence - userStringSeq_clear(BL.ioc,seq_num) - caput(before_scan_pv+".DESC","Before Scan") - - #sequence put CAs in passive - ca_list = ARPES_detector_list() - for (i,ca) in enumerate(ca_list): - ca_pv = Keithley_pv(ca[0], ca[1])+':read.SCAN PP NMS' - caput(before_scan_pv+".LNK" +str(i+1),ca_pv) - caput(before_scan_pv+".STR" +str(i+1),"Passive") - - return before_scan_proc - - -def ARPES_after_scan_clear_sequence(**kwargs): - """ - writes the user string sequence to clean up after a scan - returns clear_scan_pv = pv for userStringSeq for before scan - - **kwargs - ioc: ioc where the string sequence lives => ARPES_ioc (default) - seq_num: userStringSeq number in ioc => 6 (default) - - Previously: ARPES_Scan_Clear_StringSeq - """ - - kwargs.setdefault(seq_num,6) - seq_num=kwargs['seq_num'] - - - #clear the userStringSeq - userStringSeq_clear(BL.ioc,seq_num=kwargs['seq_num']) - - clear_scan_userStringSeq = BL.ioc+"userStringSeq"+str(seq_num) - - caput(clear_scan_userStringSeq+".DESC","ARPES_Scan_Clear") - caput(clear_scan_userStringSeq+".LNK1",BL.ioc+"scan1.T2PV PP") - caput(clear_scan_userStringSeq+".STR1","") - - ca_live_sequence_pv = ARPES_ca_live_sequence(**kwargs) - caput(clear_scan_userStringSeq+".LNK2",ca_live_sequence_pv+" PP") - - caput(clear_scan_userStringSeq+".STR2","1") - caput(clear_scan_userStringSeq+".LNK3",BL.ioc+"scan1.CMND PP") - caput(clear_scan_userStringSeq+".STR3","6") - caput(clear_scan_userStringSeq+".LNK4",BL.ioc+"scan2.CMND PP") - caput(clear_scan_userStringSeq+".STR4","6") - caput(clear_scan_userStringSeq+".LNK5",BL.ioc+"scan3.CMND PP") - caput(clear_scan_userStringSeq+".STR5","6") - caput(clear_scan_userStringSeq+".LNK6",BL.ioc+"scan4.CMND PP") - caput(clear_scan_userStringSeq+".STR6","6") - - clear_scan_userStringSeq_pv = clear_scan_userStringSeq+".PROC" - return clear_scan_userStringSeq_pv - - from IEX_beamline.IEX_beamline.instruments.IEX_VPU import ID_SP - -def scan2D(InnerMotorList,OuterMotorList,mode="absolute",settling_time=0.1,**kwargs): - """ Scans two motors.using the motor name (e.g. x,y,z,th). - InnerMotorList=[name1,start1,stop1,step1](x in the plot) - OuterMotorList=[name2,start2,stop2,step2](y in the plot) - name = 'x'/'y'/'z'/'th'... - Logging is automatic: use **kwargs or the optional logging arguments see scanlog() for details - """ - mybranch=CheckBranch() - if mybranch == "c": - Scan_ARPES_2D_Go(InnerMotorList,OuterMotorList,**kwargs) - elif mybranch == "d": - Scan_Kappa_2D_Go(InnerMotorList,OuterMotorList,**kwargs) - else: - print("Not yet implemented") - -def scan3D(list1,list2,list3,mode="absolute",settling_time=0.1,**kwargs): - """ Scans two motors.using the motor name (e.g. x,y,z,th). - listn=[name,start,stop,step] - list1 is for the inner loop -> fast (x in the plot) - list2 is for the middle loop -> slow (y in the plot) - list3 is for the outer loop -> slow (y in the plot) - """ - scanIOC=BL_ioc() - mybranch=CheckBranch() - if mybranch == "c": - m1_RBV=ARPES_PVmotor(list1[0])[0] - m1_VAL=ARPES_PVmotor(list1[0])[1] - m2_RBV=ARPES_PVmotor(list2[0])[0] - m2_VAL=ARPES_PVmotor(list2[0])[1] - m3_RBV=ARPES_PVmotor(list3[0])[0] - m3_VAL=ARPES_PVmotor(list3[0])[1] - elif mybranch == "d": - m1_RBV=Kappa_PVmotor(list1[0])[0] - m1_VAL=Kappa_PVmotor(list1[0])[1] - m2_RBV=Kappa_PVmotor(list2[0])[0] - m2_VAL=Kappa_PVmotor(list2[0])[1] - m3_RBV=Kappa_PVmotor(list3[0])[0] - m3_VAL=Kappa_PVmotor(list3[0])[1] - else: - print("Not yet implemented") - if mode == "relative": - current_value1=caget(m1_RBV) - abs_start1=round(current_value1+list1[1],3) - abs_stop1 =round(current_value1+list1[2],3) - current_value2=caget(m2_RBV) - abs_start2=round(current_value2+list2[1],3) - abs_stop2 =round(current_value2+list2[2],3) - current_value3=caget(m3_RBV) - abs_start3=round(current_value3+list3[1],3) - abs_stop3 =round(current_value3+list3[2],3) - else: - abs_start1=list1[1] - abs_stop1 =list1[2] - abs_start2=list2[1] - abs_stop2 =list2[2] - abs_start3=list3[1] - abs_stop3 =list3[2] - step1=list1[3] - step2=list2[3] - step3=list3[3] - Scan_FillIn(m1_VAL, m1_RBV, scanIOC, 1, abs_start1, abs_stop1, step1, point=None) - Scan_FillIn(m2_VAL, m2_RBV, scanIOC, 2, abs_start2, abs_stop2, step2, point=None) - Scan_FillIn(m3_VAL, m3_RBV, scanIOC, 3, abs_start3, abs_stop3, step3, point=None) - - Scan_Go(scanIOC,scanDIM=3,**kwargs) - - - - - -############################################################################################################## -############################## Move Sample ############################## -############################################################################################################## - - -def Print_Motor(): - mybranch=CheckBranch() - if mybranch == "c": - x=round(caget(ARPES_PVmotor('x')[0]),2) - y=round(caget(ARPES_PVmotor('y')[0]),2) - z=round(caget(ARPES_PVmotor('z')[0]),2) - th=round(caget(ARPES_PVmotor('th')[0]),2) - chi=round(caget(ARPES_PVmotor('chi')[0]),2) - phi=round(caget(ARPES_PVmotor('phi')[0]),2) - return [x,y,z,th,chi,phi] - # print "x="+str(x), " y="+str(y)," z="+str(z), " theta="+str(th) - print("\nx,y,z,th = ["+str(x)+","+str(y)+","+str(z)+","+str(th)+","+str(chi)+","+str(phi)+"]") - elif mybranch == "d": - x=round(caget("29idKappa:m2.RBV"),0) - y=round(caget("29idKappa:m3.RBV"),0) - z=round(caget("29idKappa:m4.RBV"),0) - tth= round(caget("29idKappa:m9.RBV"),2) - kth= round(caget("29idKappa:m8.RBV"),2) - kap= round(caget("29idKappa:m7.RBV"),2) - kphi=round(caget("29idKappa:m1.RBV"),2) - th= round(caget("29idKappa:Euler_ThetaRBV"),3) - chi= round(caget("29idKappa:Euler_ChiRBV"),3) - phi=round(caget("29idKappa:Euler_PhiRBV"),3) - #(th,chi,phi)=KtoE(kth,kap,kphi) - print("\nx,y,z,tth,th,chi,phi = ["+str(x)+","+str(y)+","+str(z)+","+str(tth)+","+str(th)+","+str(chi)+","+str(phi)+"]") - print("x,y,z,tth,kth,kap,kphi = ["+str(x)+","+str(y)+","+str(z)+","+str(tth)+","+str(kth)+","+str(kap)+","+str(kphi)+"]") - #print "\ntth,th,chi,phi = ["+str(round(tth,1))+","+str(round(th,1))+","+str((round(chi,1)))+","+str((round(phi,1)))+"]" - pos=[x,y,z,tth,kth,kap,kphi] - return pos - #elif mybranch == "e": - # print(Get_mRSoXS()[1]) - - - - - -def Move_Kappa_Sample(ListPosition): - """ListPosition = ["Sample Name", x, y, z, tth, kth, kap, kphi] - keeps tth fixes - """ - if not isinstance(ListPosition[0],str): - ListPosition.insert(0,"") - #tth=round(caget("29idHydra:m1.RBV"),2) - name,x,y,z,tth,kth,kap,kphi=ListPosition - print("\nx="+str(x), " y="+str(y)," z="+str(z), " tth="+str(tth), " kth="+str(kth), " kap="+str(kap), " kphi="+str(kphi),"\n") - caput("29idKappa:m2.VAL",x,wait=True,timeout=18000) - caput("29idKappa:m3.VAL",y,wait=True,timeout=18000) - caput("29idKappa:m4.VAL",z,wait=True,timeout=18000) - caput("29idKappa:m8.VAL",kth,wait=True,timeout=18000) - caput("29idKappa:m7.VAL",kap,wait=True,timeout=18000) - caput("29idKappa:m1.VAL",kphi,wait=True,timeout=18000) - print("Sample now @:",name) - -cts: integration time for scalers and mpa/mcp => 0.1 (default) -kwargs.setdefault('cts',0.1) -Kappa_cts(kwargs['cts'],verbose=False) - -kwargs: - mode: "absolute" (default) / "relative" - scan_dim: 1 (default) - cts: integration time for scalers and mpa/mcp => 0.1 (default) - - kwargs.setdefault('mode',"absolute") - kwargs.setdefault('scan_dim',1) - kwargs.setdefault('cts',0.1) - scan_dim = kwargs['scan_dim'] - - if kwargs['mode'] == "relative": - - - -kwargs.setdefault('run',True) - -if kwarg['run']: - BL.mda.go(kwargs['scan_dim']) - -run: True/False to start the scan => True (default) - - - - - kth_val,kth_rbv,kth_spmg,kth_pv = motor_dictionary['kth'] - tth_val,tth_rbv,tth_spmg,tth_pv = motor_dictionary['tth'] - - - kwargs.update("positioner_num",1) - BL.mda.fillin_table(scan_dim,kth_val,kth_rbv,kth_table,**kwargs) - - kwargs.update("positioner_num",2) - BL.mda.fillin_table(scan_dim,tth_val,tth_rbv,tth_table,**kwargs) - - tthdet - - - -def scan_reset(scan_dim=1,**kwargs): - """ - kwargs: - scaler='y', for Kappa IOC only, ARPES ignors this keyword - detTrig=2, for ARPES/Kappa IOC, used to clear SES/MPA trigger - - Previously: Reset_Scan - """ - print("\nResetting "+BL.ioc) - - #Clear Scan Settings - for dim in range(1,5): - scanRecord.clear_reset(BL.ioc,dim,verbose=True) - - #Setting Detectors - detector_dictionary = ARPES_detector_list() - scanRecord.detectors_set(BL.ioc,scan_dim,detector_dictionary) - ARPES_detectors=ARPES_detector_dictionary() - if BL.xrays: - ARPES_detectors.update(xray_detector_dictionary()) - scanRecord.detectors_set(BL.ioc,scan_dim,ARPES_detectors) - - #Set the Detector Triggers - - - if scanIOC == 'Kappa': - caput('29idKappa:UBmatrix',[0,0,0,0,0,0,0,0,0]) - caput('29idKappa:UBsample','') - caput('29idKappa:UBlattice',[0,0,0,0,0,0]) - caput('29idKappa:UBenergy',0) - caput('29idKappa:UBlambda',0) - caput(pv+".T1PV",'') - caput(pv+".T2PV",'') - caput(pv+".T3PV",'') - caput(pv+".T4PV",'') - caput("29id"+scanIOC+":scan1.CMND",7) - caput("29id"+scanIOC+":scan2.CMND",7) - caput("29id"+scanIOC+":scan3.CMND",7) - caput("29id"+scanIOC+":scan4.CMND",7) - if scaler == 'y': - caput(pv+".T1PV",'29idMZ0:scaler1.CNT') - caput('29idMZ0:scaler1.TP',0.1) - print('Kappa scalers are triggered. Counting time set to 0.1s') - #Reset_CA_all(); Reset_MonoMPA_ROI_Trigger() - else: - caput(pv+".T1PV",Detector_Triggers_StrSeq(scanIOC)) - print('Kappa scalers are NOT triggered. Triggering StrSeq Kappa #8 instead (empty, to be filled).') - #print("\nDetector triggered:", Detector_List(scanIOC)) -# if scanIOC=='Kappa' and scaler is not None: -# print('\nDo you want to use the scalers as detector trigger? (Note to self: to be modified (FR))>') -# foo = input() -# if foo in ['yes','y','Y','YES']: -# caput(pv+".T1PV",'29idMZ0:scaler1.CNT') -# caput('29idMZ0:scaler1.TP',0.1) -# print('Scalers added as trigger 2') -# print('Counting time set to 0.1s') -# else: -# print('\nScalers not triggered. To trigger use: \n\n Reset_Scan(\'Kappa\',scaler=\'y\')') - caput(pv+".BSPV",BeforeScan_StrSeq(scanIOC)) - caput(pv+".ASPV",AfterScan_StrSeq(scanIOC,scanDIM)) - caput(pv+".BSCD",1) - caput(pv+".BSWAIT","Wait") - caput(pv+".ASCD",1) - caput(pv+".ASWAIT","Wait") - #SaveData - caput("29id"+scanIOC+":saveData_realTime1D",1) - #Check that detector and positioner PVs are good - sleep(10) - Scan_Check(scanIOC,scanDIM) -############################################################################################################## -############################## ARPES & Kappa scan ############################## -############################################################################################################## - -def scanMesh(InnerMotorList,OuterMotorList,**kwargs): - """ - InnerMotorList=[startH,stopH,stepH](x in the plot) - OuterMotorList=[startV,stopV,stepV](y in the plot) - - Raster/maps the sample with outer/inner loop being the vertical/horizontal direction: - - yz scan for ARPES - - yx scan for Kappa (sample is assumed to be normal to the beam i.e kth/ksap/kphi = 147/134.7/57) - - **kwargs defaults - mode='Absolute' - settling_time=0.1, - scanIOC=BL_ioc - Snake; coming soon - """ - branch = BL.branch - startH,stopH,stepH=InnerMotorList - startV,stopV,stepV=OuterMotorList - if branch == "c": - ARPES_scan_2D(["y",startH,stopH,stepH],["z",startV,stopV,stepV],**kwargs) - elif branch == "d": - Kappa_scan_2D(["y",startH,stopH,stepH],["x",startV,stopV,stepV],**kwargs) - else: - print("Not yet implemented") \ No newline at end of file diff --git a/iexcode/instruments/bakeout.py b/iexcode/instruments/bakeout.py index 979393cd2c9225aaed88070ec53faeab737a9896..94dfd1a00e1173fabb280bf94cd6090258599878 100644 --- a/iexcode/instruments/bakeout.py +++ b/iexcode/instruments/bakeout.py @@ -4,8 +4,8 @@ from os.path import exists from epics import caget,caput -from .files_and_folders import get_next_fileNumber, check_run -from .scanRecord import * +from iexcode.instruments.files_and_folders import get_next_fileNumber, check_run +from iexcode.instruments.scanRecord import * ############################################################################################################## ############################## Scan Bakeout ############################## diff --git a/iexcode/instruments/beamline.py b/iexcode/instruments/beamline.py index c4d045ac683cff917e1cce371f88e4216b6463b5..6817162fdad3533041139170c96a0fa810e51958 100644 --- a/iexcode/instruments/beamline.py +++ b/iexcode/instruments/beamline.py @@ -8,14 +8,7 @@ import numpy as np from time import sleep from epics import PV -from .IEX_endstations import * -#from .logfile import * -#from .ARPES import ARPES_log_entries -#from .Kappa import Kappa_log_entries -#from .IEX_VPU import * -#from .VLS_PGM import * -#from .slits import * -#from .m3r import * +from iexcode.instruments.IEX_endstations import * ############################################################################################################## diff --git a/iexcode/instruments/cameras.py b/iexcode/instruments/cameras.py index 56ac0ceca7b67ad16356c8d3cb7b08c439e27def..1436d9b1a71c4892faa97870f1835e1003bc1bd9 100644 --- a/iexcode/instruments/cameras.py +++ b/iexcode/instruments/cameras.py @@ -1,9 +1,9 @@ from epics import caget, caput -from .userCalcs import userStringSeq_clear -from .AD_utilites import * -from .IEX_endstations import * +from iexcode.instruments.userCalcs import userStringSeq_clear +from iexcode.instruments.AD_utilities import * +from iexcode.instruments.IEX_endstations import * def cam_pv_dictionary(cam_num): diff --git a/iexcode/instruments/current_amplifiers.py b/iexcode/instruments/current_amplifiers.py index 6a72551a16e7f25a5faa4041738fcbe17a10da74..5df2d30e8f19252ea87e2abba7c42b3f4427c3a1 100644 --- a/iexcode/instruments/current_amplifiers.py +++ b/iexcode/instruments/current_amplifiers.py @@ -2,8 +2,8 @@ import numpy as np from time import sleep from epics import caget, caput -from .userCalcs import userStringSeq_pvs, userStringSeq_clear -from .VLS_PGM import mono_energy_get +from iexcode.instruments.userCalcs import userStringSeq_pvs, userStringSeq_clear +from iexcode.instruments.VLS_PGM import mono_energy_get def ca_detector_list(branch): diff --git a/iexcode/instruments/diagnostics.py b/iexcode/instruments/diagnostics.py index d22bca803ed3c14414eecf05389ff3dccdc026ae..50814ae88854f644fb99cd2b62123794f6428fac 100644 --- a/iexcode/instruments/diagnostics.py +++ b/iexcode/instruments/diagnostics.py @@ -1,7 +1,7 @@ from numpy import nan from epics import caput, caget -from IEX_endstations import * +from iexcode.instruments.IEX_endstations import * ############################################################################################################## ################################ default positions ############################## diff --git a/iexcode/instruments/electron_analyzer.py b/iexcode/instruments/electron_analyzer.py index 4427551dd4ada4e365e7d77052ff1e5b5919c554..8cfbb778c92dd9ce36f68ab6a062d44c5b9814af 100644 --- a/iexcode/instruments/electron_analyzer.py +++ b/iexcode/instruments/electron_analyzer.py @@ -13,17 +13,17 @@ import numpy as np from scipy.interpolate import interp1d from epics import caput,caget -from .IEX_endstations import * - -from .scanRecord import * -from .conversions_constants import * -from .xrays import energy, scanXAS_BL, BL_energy_tables -from .shutters import branch_shutter_close -from .VLS_PGM import mono_energy_get -from .files_and_folders import get_next_fileNumber -from .logfile import * -from .ARPES import ARPES_motor_dictionary, ARPES_motor_scan, ARPES_mvsample,ARPES_scan_2D -from .Scienta import * +from iexcode.instruments.IEX_endstations import * + +from iexcode.instruments.scanRecord import * +from iexcode.instruments.conversions_constants import * +from iexcode.instruments.xrays import energy, scanXAS_BL, BL_energy_tables +from iexcode.instruments.shutters import branch_shutter_close +from iexcode.instruments.VLS_PGM import mono_energy_get +from iexcode.instruments.files_and_folders import get_next_fileNumber +from iexcode.instruments.logfile import * +from iexcode.instruments.ARPES import ARPES_motor_dictionary, ARPES_motor_scan, ARPES_mvsample,ARPES_scan_2D +from iexcode.instruments.Scienta import * def __main__(): global EA diff --git a/iexcode/instruments/encoders.py b/iexcode/instruments/encoders.py index e45ab7f7e1b56991740af37e3e0dd33c1d1086f4..ef7cb08aceb1e1e7a0ec92ecf5915498cdf357bf 100644 --- a/iexcode/instruments/encoders.py +++ b/iexcode/instruments/encoders.py @@ -9,7 +9,7 @@ def encoder_dictionary_entry(name): d={ 'slit2B':("29idMini1:",[13,14,15,16]), 'slit3D':("29idMini2:",[26,27]), - 'ARPES':("ARPES:"),[1,2,3,4]) + 'ARPES':("ARPES:",[1,2,3,4]), } return d[name] diff --git a/iexcode/instruments/files_and_folders.py b/iexcode/instruments/files_and_folders.py index 6f1e48d1b6e5a4f5b4d379c4123bb719c44ddaab..9710c1bd6907b1f7340147aad3a073d28daf1c82 100644 --- a/iexcode/instruments/files_and_folders.py +++ b/iexcode/instruments/files_and_folders.py @@ -1,26 +1,3 @@ -""" -Utilities to set beamline folders - -# to caget path: caget("29idc:saveData_fileSystem",as_string=True) - -# Data folder structure: -# -# STAFF: data_29idb / 2017_2 / mda -## h5 -# mpa -# g5 -# SES -# tif -# mpa -# -# USERS (C): data_29idc / 2017_2 / user_name / mda -# h5 -# -# -# USERS (D): data_29idd / 2017_2 / user_name / mda -# - -""" from os import listdir,mkdir,chmod from os.path import join, isfile, exists import datetime @@ -29,9 +6,6 @@ import re from epics import caget, caput -from .utilities import dateandtime -from .ARPES import folders_ARPES -from .Kappa import folders_Kappa ############################################################################################################## ################################ Standard Paths ############################## @@ -51,35 +25,7 @@ def path_dserv(folder,run,user_name): dataFolder='/net/s29data/export/data_29id'+folder+'/'+run+'/'+user_name return dataFolder -def folders_startup(run): - """ - Creates the run directories for the following: - data_29idb - data_29idc - data_29idd - - calls folder_ARPES('Staff');folder_Kappa('Staff') - print text required to modify the rsynch crontab - - previously: Folders_Startup - """ - data_directories=['data_29idb','data_29idc','data_29idd'] - dserv="/net/s29data/export/" - for dataDir in data_directories: - path=join(dserv,dataDir,run) - print(path) - if not (exists(path)): - mkdir(path) - - folders_ARPES('Staff',create_only=True) - folders_Kappa('Staff',create_only=True) - - txt="\n\n\nupdate the rsync portion the 29id@nerdy crontab\n" - txt+="*/1 * * * * /usr/bin/rsync -av --exclude=core /net/s29data/export/data_29idd/"+run+" kip:/net/kip/sftp/pub/29iddftp/files > /home/beams22/29ID/cronfiles/cptoftp-currrun-d.log 2>&1" - txt+=("\n") - txt+="*/1 * * * * /usr/bin/rsync -av --exclude=core /net/s29data/export/data_29idd/"+run+" kip:/net/kip/sftp/pub/29iddftp/files > /home/beams22/29ID/cronfiles/cptoftp-currrun-d.log 2>&1" - print(txt) diff --git a/iexcode/instruments/hxp_mirrors.py b/iexcode/instruments/hxp_mirrors.py index a757fc55ae0c44a5e3cb7ac79ea4995cdd1aa20b..0eb90509f2784ff042fbcb4ef78235ec102d02fd 100644 --- a/iexcode/instruments/hxp_mirrors.py +++ b/iexcode/instruments/hxp_mirrors.py @@ -1,7 +1,7 @@ from re import M from epics import caput, caget -from utilities import print_warning_message -from m3r import m3r_branch +from iexcode.instruments.utilities import print_warning_message +from iexcode.instruments.m3r import m3r_branch def hxp_ioc(mirror_name): """ diff --git a/iexcode/instruments/logfile.py b/iexcode/instruments/logfile.py index 2f158f66e1d8aa14426121604666d0448bfcbc7c..dec2ce2547f2096f5ebeda2597e496a1723b44d4 100644 --- a/iexcode/instruments/logfile.py +++ b/iexcode/instruments/logfile.py @@ -1,10 +1,10 @@ -from os.path import join,open,isfile +from os.path import join,isfile from epics import caget, caput -from .IEX_endstations import * -from .utilities import today -from .ARPES import ARPES_log_entries -from .Kappa import Kappa_log_entries +from iexcode.instruments.IEX_endstations import * +from iexcode.instruments.utilities import today +from iexcode.instruments.ARPES import ARPES_log_entries +from iexcode.instruments.Kappa import Kappa_log_entries ############################################################################################################## diff --git a/iexcode/instruments/m3r.py b/iexcode/instruments/m3r.py index 903ed76680384b85c7073612c5d2a61d783cf6d8..54bb5ec77693a6857ce71dd5b87d6b4aeffd3386 100644 --- a/iexcode/instruments/m3r.py +++ b/iexcode/instruments/m3r.py @@ -2,8 +2,8 @@ from cgi import print_arguments from epics import caget, caput -from .utilities import print_warning_message -from .FMB_mirrors import * +from iexcode.instruments.utilities import print_warning_message +from iexcode.instruments.FMB_mirrors import * ############################################################################################################## ################################ M3R ############################## diff --git a/iexcode/instruments/mpa.py b/iexcode/instruments/mpa.py index f941431c5f1d437bcc0a65e60ee471d32bde1784..6408b462eb1ab840d591207d7a6d0ec37d3794d7 100644 --- a/iexcode/instruments/mpa.py +++ b/iexcode/instruments/mpa.py @@ -3,11 +3,11 @@ from os.path import dirname, join import socket from epics import caget, caput -from .userCalcs import userCalcOut_clear,userStringSeq_clear -from .Kappa import Kappa_motor_dictionary,Kappa_cts, mda -from .AD_utilites import AD_ROI_setup -from .scalers import scaler_cts -from scanRecord import * +from iexcode.instruments.userCalcs import userCalcOut_clear,userStringSeq_clear +from iexcode.instruments.Kappa import Kappa_motor_dictionary,Kappa_cts, mda +from iexcode.instruments.AD_utilities import AD_ROI_setup +from iexcode.instruments.scalers import scaler_cts +from iexcode.instruments.scanRecord import * """ diff --git a/iexcode/instruments/resolution.py b/iexcode/instruments/resolution.py index 9b2e864b5c4a7697ee1f8d5d05da3a8a13991efd..a34f8919c7df6eca028e3216ec5b13e3d5973da2 100644 --- a/iexcode/instruments/resolution.py +++ b/iexcode/instruments/resolution.py @@ -1,6 +1,6 @@ import numpy as np -from electron_analyzer import resolution_EA +from iexcode.instruments.electron_analyzer import resolution_EA ############################################################################################################# ############################## Resolution ############################## ############################################################################################################# diff --git a/iexcode/instruments/scalers.py b/iexcode/instruments/scalers.py index 33da16e9605f0975a140f87140b866febd837e78..89be3dbabd0b813aa88d6e5088354e5aa049ee33 100644 --- a/iexcode/instruments/scalers.py +++ b/iexcode/instruments/scalers.py @@ -2,7 +2,7 @@ from math import floor from epics import caput,PV -from .IEX_endstations import BL +from iexcode.instruments.IEX_endstations import BL def scaler_cts(time_seconds=0.1,verbose=True): """ diff --git a/iexcode/instruments/scanRecord.py b/iexcode/instruments/scanRecord.py index c2719c45e49a4d414620130d64f5be5ee89a28fe..2e01a97a40feb0cabc45a2affce438fa7ef800d9 100644 --- a/iexcode/instruments/scanRecord.py +++ b/iexcode/instruments/scanRecord.py @@ -4,9 +4,9 @@ import time from epics import caget, caput, PV -from .utilities import dateandtime, print_warning_message -from .logfile import log_update -from .userCalcs import userStringSeq_pvs,userStringSeq_clear +from iexcode.instruments.utilities import dateandtime, print_warning_message +from iexcode.instruments.logfile import log_update +from iexcode.instruments.userCalcs import userStringSeq_pvs,userStringSeq_clear def saveData_get_all(ioc_pv): diff --git a/iexcode/instruments/scratch.py b/iexcode/instruments/scratch.py new file mode 100644 index 0000000000000000000000000000000000000000..ded5e799532a9f085e7e81f233ff0d2a7e4267a8 --- /dev/null +++ b/iexcode/instruments/scratch.py @@ -0,0 +1,44 @@ +############################################################################################################## +############################## setting folder from ARPES ############################## +############################################################################################################## +def folders_ARPES(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',True) + 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,BL.folder,user_name,BL.ioc,kwargs['ftp']) + + # Create User Folder: + make_user_folders(run,BL.folder,user_name,BL.endstation,ftp=kwargs['ftp']) + sleep(5) + + if kwargs["set_folders"]: + # Set up MDA folder: + folder_mda(run,BL.folder,user_name,BL.prefix,BL.ioc) + logfile_name_set(BL.endstation) + logfile_header(BL.endstation,BL.ioc,ARPES_log_header()) + + + #Set up Scienta folders: + try: + userPath = "/net/s29data/export/data_29id"+BL.folder+"/"+run+"/"+user_name+"/" + folders_EA(userPath,filePrefix="EA") + except: + print_warning_message("EA ioc is not running, cannot set folder") \ No newline at end of file diff --git a/iexcode/instruments/shutters.py b/iexcode/instruments/shutters.py index 909009f0acbf272454b93353d567dc75801ab7fa..2afd8422a141b6b3b7b8467d8a6ef7b50ecc94e7 100644 --- a/iexcode/instruments/shutters.py +++ b/iexcode/instruments/shutters.py @@ -4,7 +4,7 @@ main shutter and branch shutter functions from time import sleep from epics import caget, caput -from .utilities import dateandtime, print_warning_message +from iexcode.instruments.utilities import dateandtime, print_warning_message ############################################################################################################## diff --git a/iexcode/instruments/slits.py b/iexcode/instruments/slits.py index 5a1ead3b31292e05bb4de2e8f775ef7b106d41ec..1b323e3ead9d82e35929bd013f277f8cfc7b3bd3 100644 --- a/iexcode/instruments/slits.py +++ b/iexcode/instruments/slits.py @@ -4,10 +4,10 @@ from epics import caget, caput from .IEX_endstations import * -from .shutters import main_shutter_close -from .utilities import print_warning_message, read_dict -from .VLS_PGM import mono_get_all -from .encoders import encoders_reset +from iexcode.instruments.shutters import main_shutter_close +from iexcode.instruments.utilities import print_warning_message, read_dict +from iexcode.instruments.VLS_PGM import mono_get_all +from iexcode.instruments.encoders import encoders_reset slit_ioc="29idb:" diff --git a/iexcode/instruments/staff.py b/iexcode/instruments/staff.py index 8ff6206d5d3e2609f6398ca0b24b73f169f56527..b9d6eef6b0732753a2c5c190dd1903e2f2d2652c 100644 --- a/iexcode/instruments/staff.py +++ b/iexcode/instruments/staff.py @@ -1,3 +1,39 @@ +from os import listdir,mkdir,chmod +from os.path import join, isfile, exists + +#from .ARPES import folders_ARPES +#from .Kappa import folders_Kappa + + +def folders_startup(run): + """ + Creates the run directories for the following: + data_29idb + data_29idc + data_29idd + + calls folder_ARPES('Staff');folder_Kappa('Staff') + + print text required to modify the rsynch crontab + + previously: Folders_Startup + """ + data_directories=['data_29idb','data_29idc','data_29idd'] + dserv="/net/s29data/export/" + for dataDir in data_directories: + path=join(dserv,dataDir,run) + print(path) + if not (exists(path)): + mkdir(path) + + #folders_ARPES('Staff',create_only=True) + #folders_Kappa('Staff',create_only=True) + + txt="\n\n\nupdate the rsync portion the 29id@nerdy crontab\n" + txt+="*/1 * * * * /usr/bin/rsync -av --exclude=core /net/s29data/export/data_29idd/"+run+" kip:/net/kip/sftp/pub/29iddftp/files > /home/beams22/29ID/cronfiles/cptoftp-currrun-d.log 2>&1" + txt+=("\n") + txt+="*/1 * * * * /usr/bin/rsync -av --exclude=core /net/s29data/export/data_29idd/"+run+" kip:/net/kip/sftp/pub/29iddftp/files > /home/beams22/29ID/cronfiles/cptoftp-currrun-d.log 2>&1" + print(txt) ############################################################################################################## ############################## staff detectors ############################## diff --git a/iexcode/instruments/storage_ring.py b/iexcode/instruments/storage_ring.py index 3e71edda0bc85d3032c585205a2fc27de1fdbc5a..a2269b8e853b181f4efacb0c0be43d4316c028e8 100644 --- a/iexcode/instruments/storage_ring.py +++ b/iexcode/instruments/storage_ring.py @@ -7,7 +7,7 @@ Functions dealing with the storage ring pvs from epics import caget from time import sleep -from .utilities import dateandtime +from iexcode.instruments.utilities import dateandtime def wait_for_beam(): """ diff --git a/iexcode/instruments/xrays.py b/iexcode/instruments/xrays.py index fdf2e7f0b95bc788e646204729f5afdf588c6051..aa029404a075cb0b00ddbf7f9878598afc57032b 100644 --- a/iexcode/instruments/xrays.py +++ b/iexcode/instruments/xrays.py @@ -6,25 +6,25 @@ import numpy as np from time import sleep from epics import caget,caput -from .IEX_endstations import BL - -from .resolution import * -from .IEX_VPU import * -from .VLS_PGM import * -from .slits import * -from .shutters import * -from .gate_valves import * -from .diagnostics import * -from .m3r import * -from .logfile import * -from .utilities import print_warning_message,make_table, take_closest_value -from .mpa import * -from .current_amplifiers import ca_average -from .beamline import branch_cams_enable - -from .ARPES import ARPES_mprint,ARPES_extra_pvs -from .Kappa import Kappa_mprint -from .electron_analyzer import getSESslit, EA +from iexcode.instruments.IEX_endstations import BL + +from iexcode.instruments.resolution import * +from iexcode.instruments.IEX_VPU import * +from iexcode.instruments.VLS_PGM import * +from iexcode.instruments.slits import * +from iexcode.instruments.shutters import * +from iexcode.instruments.gate_valves import * +from iexcode.instruments.diagnostics import * +from iexcode.instruments.m3r import * +from iexcode.instruments.logfile import * +from iexcode.instruments.utilities import print_warning_message,make_table, take_closest_value +from iexcode.instruments.mpa import * +from iexcode.instruments.current_amplifiers import ca_average +from iexcode.instruments.beamline import branch_cams_enable + +from iexcode.instruments.ARPES import ARPES_mprint,ARPES_extra_pvs +from iexcode.instruments.Kappa import Kappa_mprint +from iexcode.instruments.electron_analyzer import getSESslit, EA ############################################################################################################## ############################## resets and detector lists ############################## ##############################################################################################################