diff --git a/instruments/AD_utilites.py b/instruments/AD_utilites.py new file mode 100644 index 0000000000000000000000000000000000000000..684736bc9044b16e98f7fdbf4c79350cc8f272dd --- /dev/null +++ b/instruments/AD_utilites.py @@ -0,0 +1,544 @@ +""" +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 .IEX_endstations import * +from files_and_folders import get_next_fileNumber +from scanRecord import * + +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"))) + +def Cam_ScanSetup(mda,scanDIM,camNUM): #individual files saving + pvCam="29id_ps"+str(camNUM)+":" + pvIOC=mda.ioc + #beforscan + Cam_SaveStrSeq(camNUM) + caput(pvIOC+"scan"+str(scanDIM)+".BSPV",pvIOC+"userStringSeq2.PROC") + #scan record (filename and trigger) + nextfile=str(caget(pvIOC+"saveData_baseName"))+str(caget(pvIOC+"saveData_scanNumber")) + filepath=caget(pvIOC+"saveData_fileSystem") + filepath="/net"+filepath[1:len(filepath)]+"/tif" + caput(pvCam+"TIFF1:FilePath",filepath) + caput(pvCam+"TIFF1:FileName",nextfile) + caput(pvCam+"TIFF1:FileWriteMode","Single") + caput(pvIOC+"scan1.T2PV",pvCam+"cam1:Acquire") + #afterscan + Cam_FreeStrSeq(camNUM) + caput(pvIOC+"scan"+str(scanDIM)+".ASPV",pvIOC+"userStringSeq1.PROC") + caput(pvIOC+"scan1.ASCD",1) + print("DON'T FORGET TO CLEAR SCAN RECORD AT THE END OF THE SCRIPT!!!!! ") + print("Use Script: Cam_ScanClear(scanIOC,scanDIM)") + + + +def Cam_FreeRun(camNUM): + camNUM=str(camNUM) + pv="29id_ps"+camNUM+":" + caput(pv+"TIFF1:AutoSave",0) + caput(pv+"TIFF1:EnableCallbacks",0) + sleep(0.5) + caput(pv+"cam1:ImageMode",2) + caput(pv+"cam1:Acquire",1) + caput(pv+"cam1:AcquireTime",0.015) + caput(pv+"cam1:AcquirePeriod",0.030) + print("Cam"+str(camNUM)+": Free run mode") + + + + + +def Cam_SaveMode(camNUM): + camNUM=str(camNUM) + pv="29id_ps"+camNUM+":" + caput(pv+"cam1:Acquire",0) + sleep(0.5) + caput(pv+"cam1:ImageMode",0) + caput(pv+"TIFF1:AutoSave",1) + caput(pv+"TIFF1:EnableCallbacks",1) + caput(pv+"TIFF1:FileNumber",1) + caput(pv+"cam1:AcquireTime",0.015) + caput(pv+"cam1:AcquirePeriod",0.030) + print("Cam"+str(camNUM)+": Saving mode") + +def Cam_Start(camNUM): + Cam_FreeRun(camNUM) + +def Cam_Stop(camNUM): + camNUM=str(camNUM) + pv="29id_ps"+camNUM+":" + caput(pv+"cam1:Acquire",0) + + + +def Cam_ROI_SetUp(xstart,ystart,xsize,ysize,camNUM,roiNUM=1,binX=1,binY=1): + pv="29id_ps"+str(camNUM)+":ROI"+str(roiNUM)+':' + caput(pv+'MinX',xstart) + caput(pv+'MinY',ystart) + caput(pv+'SizeX',xsize) + caput(pv+'SizeY',ysize) + caput(pv+'BinX',binX) + caput(pv+'BinY',binY) + caput(pv+'EnableCallbacks','Enable') + print(('ROI'+str(roiNUM)+' - '+caget(pv+'EnableCallbacks_RBV',as_string=True))) + +def Cam_ROI_Stats(xstart,ystart,xsize,ysize,camNUM,roiNUM=1,binX=1,binY=1): + pv="29id_ps"+str(camNUM)+":Stats1:" + Cam_ROI_SetUp(xstart,ystart,xsize,ysize,camNUM,roiNUM,binX,binY) + caput(pv+'EnableCallbacks','Enable') + roi=caget(pv+'NDArrayPort_RBV',as_string=True) + print((roi+' Stats => '+pv+'Total_RBV')) + print('To set-up as detector use:') + print('Cam_ROI_Det(detNUM,scanIOC,camNUM='+str(camNUM)+',roiNUM='+str(roiNUM)+')') + +def Cam_ROI_Det(detNUM,scanIOC,camNUM,roiNUM,scanDIM=1): + pvdet='29id'+scanIOC+':scan'+str(scanDIM)+'.D'+str(detNUM)+'PV' + pvroi="29id_ps"+str(camNUM)+":Stats1:Total_RBV" + caput(pvdet,pvroi) + print('ROI stats set up as detector D'+str(detNUM)+' in '+scanIOC+' scan'+str(scanDIM)) + +### Scan Record Set-Up: + +def Scan_Cam_Go(mda,VAL,RBV,scanDIM,start,stop,step,camNUM): + mda.fillin(scanDIM,VAL,RBV,start,stop,step) + Cam_ScanSetup(scanDIM,camNUM) + + caput("29id"+scanIOC+":scan"+str(scanDIM)+".PASM","STAY") + + # Scan_Go() without Before_After_Scan() + BL_mode=BL_Mode_Read()[0] + if BL_mode != 2: + Check_MainShutter() + FileName = caget("29id"+scanIOC+":saveData_baseName",as_string=True) + FileNum = caget("29id"+scanIOC+":saveData_scanNumber") + print(FileName+": #"+str(FileNum)+" started at ", dateandtime()) + caput("29id"+scanIOC+":scan"+str(scanDIM)+".EXSC",1,wait=True,timeout=900000) #pushes scan button + print(FileName+": #"+str(FileNum)+" finished at ", dateandtime()) + + Cam_ScanClear(scanIOC,scanDIM) + caput("29id"+scanIOC+":scan"+str(scanDIM)+".PASM","PRIOR POS") + +def Scan_Cam_Pos2_Go(VAL1,RBV1,VAL2,RBV2,scanDIM,start1,stop1,step1,start2,stop2,camNUM): + scanIOC=BL_ioc() + pvCam="29id_ps"+str(camNUM)+":" + Cam_ScanSetup(scanDIM,camNUM) + Scan_FillIn(VAL1,RBV1,scanIOC,scanDIM,start1,stop1,step1) + Scan_FillIn_Pos2(VAL2,RBV2,scanIOC,scanDIM,start2,stop2) + caput("29id"+scanIOC+":scan"+str(scanDIM)+".PASM","STAY") + mda.goScan_Go(scanIOC,scanDIM=1 ) + Cam_ScanClear(scanIOC,scanDIM) + caput("29id"+scanIOC+":scan"+str(scanDIM)+".PASM","PRIOR POS") + +def Cam_ScanClear(scanIOC,scanDIM): + caput("29id"+scanIOC+":scan"+str(scanDIM)+".BSPV","") + caput("29id"+scanIOC+":scan"+str(scanDIM)+".ASPV","") + caput("29id"+scanIOC+":scan"+str(scanDIM)+".T2PV","") + caput("29id"+scanIOC+":scan"+str(scanDIM)+".DDLY",0.5) + #print "Scan Record cleared from Camera Settings" + + + +### Image Acquisition: + +def TakeImageSetFolder(camNUM,NewFolder=""): + scanIOC=BL.ioc + pvCam="29id_ps"+str(camNUM)+":" + pvIOC="29id"+scanIOC+":" + #beforscan + Cam_SaveMode(camNUM) + #FilePath + filepath=caget(pvIOC+"saveData_fileSystem")+"/tif" + filepath="/net"+filepath[1:len(filepath)]+"/"+NewFolder + caput(pvCam+"TIFF1:FilePath",filepath) + print("WARNING: Make sure NewFolder exists !!!") + +def TakeImageSetFileNum(camNUM,n): + scanIOC=BL.mda.ioc + pvCam="29id_ps"+str(camNUM)+":" + pvIOC="29id"+scanIOC+":" + #beforscan +# Cam_SaveMode(camNUM) + #Filename + if n<10: + nextfile="29id"+scanIOC+"_000"+str(n) + elif n<100: + nextfile="29id"+scanIOC+"_00"+str(n) + elif n<1000: + nextfile="29id"+scanIOC+"_0"+str(n) + elif n<10000: + nextfile="29id"+scanIOC+"_"+str(n) + caput(pvCam+"TIFF1:FileName",nextfile) + caput(pvCam+"TIFF1:AutoIncrement",1) + caput(pvCam+"TIFF1:FileNumber",2) + +def TakeImageSetup(camNUM): + scanIOC=BL.mda.ioc + pvCam="29id_ps"+str(camNUM)+":" + pvIOC="29id"+scanIOC+":" + #beforscan + Cam_SaveMode(camNUM) + #Filename + nextfile=str(caget(pvIOC+"saveData_baseName"))+str(caget(pvIOC+"saveData_scanNumber")-1) + filepath=caget(pvIOC+"saveData_fileSystem")+"/tif" + if scanIOC == "Test": + filepath="/"+filepath[1:len(filepath)] # for 29idTest + else: + filepath="/net"+filepath[1:len(filepath)] # for 29idb/c/d + + caput(pvCam+"TIFF1:FilePath",filepath) + caput(pvCam+"TIFF1:FileName",nextfile) + #afterscan + +def TakeImage(camNUM,AcqTime): + AcqPeriode=AcqTime+0.040 + pvCam="29id_ps"+str(camNUM)+":" + caput(pvCam+"cam1:AcquireTime",AcqTime) + caput(pvCam+"cam1:AcquirePeriod",AcqPeriode) + sleep(1) + caput(pvCam+"cam1:Acquire",1,wait=True,timeout=500) + sleep(1) + TiffNum =caget(pvCam+"TIFF1:FileNumber_RBV")-1 + FileName= caget(pvCam+"TIFF1:FileName_RBV",as_string=True) + print("\n"+FileName+": #"+str(TiffNum)+" started at ", dateandtime()) + print("\n================================================\n") + + + + + + + + + diff --git a/instruments/ARPES.py b/instruments/ARPES.py new file mode 100644 index 0000000000000000000000000000000000000000..1a60b81c8e13caf4c6df8dd055a54cee39a8a329 --- /dev/null +++ b/instruments/ARPES.py @@ -0,0 +1,758 @@ +import numpy as np +from time import sleep + +from epics import caget,caput,PV +from .IEX_endstations import * + +from .files_and_folders import check_run,make_user_folders,folder_mda +from .userCalcs import userStringSeq_clear, userStringSeq_pvs +from .logfile import logfile_name_set,logfile_header +from .utilities import * +from .conversions_constants import * +from .scanRecord import * +from .current_amplifiers import * +from .slits import slit3C_get +from .gate_valves import valve_close, branch_valves +from .shutters import branch_shutter_close +from .xrays import * +from .Lakeshore_335 import Lakeshore_reset +from .electron_analyzer import folders_EA +from .Motors import * + + +EA_pv="29idcScienta:HV:KineticEnergy.VAL" + +############################################################################# +def __main__(set_folders=False,reset=False,**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 + mda_scanRecord = ScanRecord(kwargs['scan_ioc'],ARPES_detector_dictionary,ARPES_trigger_dictionary,ARPES_scan_before_sequence,ARPES_scan_after_sequence,mda) + + #endstation + global BL + BL=Endstation('ARPES',kwargs['scan_ioc'],kwargs['xrays'],kwargs['BL_mode'],mda_scanRecord) + + #EA + global EA + pv=PV(EA_pv);sleep(0.1) + if not pv.connected: + 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) + global CA15 + ca15 = Keithley('b',15) + + #setting folders + if 'set_folders': + 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) + +############################################################################################################## +############################## 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: + pv=PV(EA_pv); sleep(0.1) + if pv.connected: + 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) \ No newline at end of file diff --git a/instruments/FMB_mirrors.py b/instruments/FMB_mirrors.py new file mode 100644 index 0000000000000000000000000000000000000000..c7c0069713de70bca39173e5fa7265b05c95e32d --- /dev/null +++ b/instruments/FMB_mirrors.py @@ -0,0 +1,174 @@ +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 + +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/instruments/IEX_VPU.py b/instruments/IEX_VPU.py new file mode 100644 index 0000000000000000000000000000000000000000..71de8b5035cd91aaf07eb3b5f77cb10835d37781 --- /dev/null +++ b/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 .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 + +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_put(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_put(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_put(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_put(hv) + +def ID_SP_put(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/instruments/IEX_dictionaries/Dict_IDCal.txt b/instruments/IEX_dictionaries/Dict_IDCal.txt new file mode 100644 index 0000000000000000000000000000000000000000..d3b7d3435d0ab93b9bc1b7e0713c1541b18cab9c --- /dev/null +++ b/instruments/IEX_dictionaries/Dict_IDCal.txt @@ -0,0 +1,27 @@ +======= 20210408: +{'HEG': {0: [[600.0, [-6635.813431810828, 53.075898114105726, -0.15253171108859886, 0.00019792480095656869, -9.598209896301075e-08]], [1950.0, [46.600135556920925, 0.8412063733137993, 0.00023492720237763438, -1.2593652551917328e-07, 2.5435326557098538e-11]]], 3: [[400.0, [1051.452570904546, -13.099314837713008, 0.06939879665006896, -0.00014784669111041307, 1.155031075284652e-07]], [600.0, [2782.786054275039, -21.145755715684032, 0.06554921272398154, -8.534237586539917e-05, 4.134061079155964e-08]], [1950.0, [87.23060103156234, 0.7171860430279529, 0.0003793918782124725, -1.9605428816497513e-07, 3.6770897051532086e-11]]], 2: [[590.0, [-12422.076427583952, 100.54771064816772, -0.29845648627641835, 0.00039688772576782855, -1.97439876026206e-07]], [1940.0, [-33.02431482418943, 1.1302724323594304, -0.00013479679549416608, 7.22272393581498e-08, -1.373032035520199e-11]]], 1: [[600.0, [-4701.14124376318, 38.11250082824693, -0.10953080869095329, 0.00014349645302935956, -7.03019927601252e-08]], [1950.0, [84.53488099145231, 0.7066601865786498, 0.00043283422433330405, -2.2608518373215027e-07, 4.202604094132355e-11]]]}, 'MEG': {0: [[600.0, [-5.94257709e+03, 4.83142929e+01, -1.40776556e-01, 1.85809382e-04,-9.17570684e-08]], [1900.0, [120.48660483356667, 0.5730901209923781, 0.0005878274491379978, -3.237518769395626e-07, 6.578470645318609e-11]], [2450.0, [-861236.5488172219, 1692.5132268182851, -1.2423466873397095, 0.00040435487123940126, -4.9199035821220396e-08]]], 3: [[350.0, [ 1.29955075e+03, -1.51058939e+01, 7.30495977e-02, -1.42335671e-04,1.00248119e-07]], [600.0, [ 1.56157353e+02, 3.36244395e-01, 2.51121782e-04, 2.14546965e-06, -2.26975845e-09]], [1900.0, [182.12010345268018, 0.35919202965098807, 0.0008707482678487033, -4.856922998327794e-07, 9.884030291073737e-11]], [2450.0, [-679879.9418255178, 1343.4719860308003, -0.9910723460051563, 0.00032416433932345637, -3.962726476099227e-08]]], 2: [[590.0, [-5012.940342322967, 40.90754759075464, -0.11882247811910264, 0.0001569980318593441, -7.761119020096338e-08]], [1890.0, [91.60119828336364, 0.6656924204319927, 0.0004832519962652505, -2.757432638354398e-07, 5.703445281307984e-11]], [2440.0, [-714890.9962893045, 1416.2262295207256, -1.0473031488528242, 0.00034332048746509047, -4.205442003546835e-08]]], 1: [[600.0, [-8.23417867e+02, 5.78831891e+00, -9.17524831e-03, 5.90781467e-06]], [1900.0, [129.0956307507799, 0.5398695804747401, 0.0006597026712875963, -3.5782948211437904e-07, 6.972425989874214e-11]], [2450.0, [444764.6379492582, -918.182910481471, 0.7119893610136518, -0.0002449458846156531, 3.158154965241037e-08]]]}} + +======= 20210325: +{'HEG': {0: [[600.0, [-6635.813431810828, 53.075898114105726, -0.15253171108859886, 0.00019792480095656869, -9.598209896301075e-08]], [1950.0, [46.600135556920925, 0.8412063733137993, 0.00023492720237763438, -1.2593652551917328e-07, 2.5435326557098538e-11]]], 3: [[400.0, [1051.452570904546, -13.099314837713008, 0.06939879665006896, -0.00014784669111041307, 1.155031075284652e-07]], [600.0, [2782.786054275039, -21.145755715684032, 0.06554921272398154, -8.534237586539917e-05, 4.134061079155964e-08]], [1950.0, [87.23060103156234, 0.7171860430279529, 0.0003793918782124725, -1.9605428816497513e-07, 3.6770897051532086e-11]]], 2: [[590.0, [-12422.076427583952, 100.54771064816772, -0.29845648627641835, 0.00039688772576782855, -1.97439876026206e-07]], [1940.0, [-33.02431482418943, 1.1302724323594304, -0.00013479679549416608, 7.22272393581498e-08, -1.373032035520199e-11]]], 1: [[600.0, [-4701.14124376318, 38.11250082824693, -0.10953080869095329, 0.00014349645302935956, -7.03019927601252e-08]], [1950.0, [84.53488099145231, 0.7066601865786498, 0.00043283422433330405, -2.2608518373215027e-07, 4.202604094132355e-11]]]}, 'MEG': {0: [[600.0, [-5.94257709e+03, 4.83142929e+01, -1.40776556e-01, 1.85809382e-04,-9.17570684e-08]], [1900.0, [120.48660483356667, 0.5730901209923781, 0.0005878274491379978, -3.237518769395626e-07, 6.578470645318609e-11]], [2450.0, [-861236.5488172219, 1692.5132268182851, -1.2423466873397095, 0.00040435487123940126, -4.9199035821220396e-08]]], 3: [[400.0, [2847.79940016946, -36.333603982010075, 0.18104460124913768, -0.0003840780707796322, 3.0129211549627434e-07]], [600.0, [5465.629361402122, -44.12377192190018, 0.13886417042191168, -0.0001885833582746921, 9.547898180355825e-08]], [1900.0, [182.12010345268018, 0.35919202965098807, 0.0008707482678487033, -4.856922998327794e-07, 9.884030291073737e-11]], [2450.0, [-679879.9418255178, 1343.4719860308003, -0.9910723460051563, 0.00032416433932345637, -3.962726476099227e-08]]], 2: [[590.0, [-5012.940342322967, 40.90754759075464, -0.11882247811910264, 0.0001569980318593441, -7.761119020096338e-08]], [1890.0, [91.60119828336364, 0.6656924204319927, 0.0004832519962652505, -2.757432638354398e-07, 5.703445281307984e-11]], [2440.0, [-714890.9962893045, 1416.2262295207256, -1.0473031488528242, 0.00034332048746509047, -4.205442003546835e-08]]], 1: [[600.0, [-8.23417867e+02, 5.78831891e+00, -9.17524831e-03, 5.90781467e-06]], [1900.0, [129.0956307507799, 0.5398695804747401, 0.0006597026712875963, -3.5782948211437904e-07, 6.972425989874214e-11]], [2450.0, [444764.6379492582, -918.182910481471, 0.7119893610136518, -0.0002449458846156531, 3.158154965241037e-08]]]}} + +======= 20200621: +{'HEG': {0: [[600.0, [-6635.813431810828, 53.075898114105726, -0.15253171108859886, 0.00019792480095656869, -9.598209896301075e-08]], [1950.0, [46.600135556920925, 0.8412063733137993, 0.00023492720237763438, -1.2593652551917328e-07, 2.5435326557098538e-11]]], 3: [[400.0, [1051.452570904546, -13.099314837713008, 0.06939879665006896, -0.00014784669111041307, 1.155031075284652e-07]], [600.0, [2782.786054275039, -21.145755715684032, 0.06554921272398154, -8.534237586539917e-05, 4.134061079155964e-08]], [1950.0, [87.23060103156234, 0.7171860430279529, 0.0003793918782124725, -1.9605428816497513e-07, 3.6770897051532086e-11]]], 2: [[590.0, [-12422.076427583952, 100.54771064816772, -0.29845648627641835, 0.00039688772576782855, -1.97439876026206e-07]], [1940.0, [-33.02431482418943, 1.1302724323594304, -0.00013479679549416608, 7.22272393581498e-08, -1.373032035520199e-11]]], 1: [[600.0, [-4701.14124376318, 38.11250082824693, -0.10953080869095329, 0.00014349645302935956, -7.03019927601252e-08]], [1950.0, [84.53488099145231, 0.7066601865786498, 0.00043283422433330405, -2.2608518373215027e-07, 4.202604094132355e-11]]]}, 'MEG': {0: [[600.0, [-5436.760853858342, 43.96983227683935, -0.12687747514944603, 0.00016616428936737506, -8.139167807653272e-08]], [1900.0, [120.48660483356667, 0.5730901209923781, 0.0005878274491379978, -3.237518769395626e-07, 6.578470645318609e-11]], [2450.0, [-861236.5488172219, 1692.5132268182851, -1.2423466873397095, 0.00040435487123940126, -4.9199035821220396e-08]]], 3: [[400.0, [2847.79940016946, -36.333603982010075, 0.18104460124913768, -0.0003840780707796322, 3.0129211549627434e-07]], [600.0, [5465.629361402122, -44.12377192190018, 0.13886417042191168, -0.0001885833582746921, 9.547898180355825e-08]], [1900.0, [182.12010345268018, 0.35919202965098807, 0.0008707482678487033, -4.856922998327794e-07, 9.884030291073737e-11]], [2450.0, [-679879.9418255178, 1343.4719860308003, -0.9910723460051563, 0.00032416433932345637, -3.962726476099227e-08]]], 2: [[590.0, [-5012.940342322967, 40.90754759075464, -0.11882247811910264, 0.0001569980318593441, -7.761119020096338e-08]], [1890.0, [91.60119828336364, 0.6656924204319927, 0.0004832519962652505, -2.757432638354398e-07, 5.703445281307984e-11]], [2440.0, [-714890.9962893045, 1416.2262295207256, -1.0473031488528242, 0.00034332048746509047, -4.205442003546835e-08]]], 1: [[600.0, [-3621.195557803563, 29.38209496572412, -0.08337726780845282, 0.00010909919798197781, -5.3540413516786254e-08]], [1900.0, [129.0956307507799, 0.5398695804747401, 0.0006597026712875963, -3.5782948211437904e-07, 6.972425989874214e-11]], [2450.0, [444764.6379492582, -918.182910481471, 0.7119893610136518, -0.0002449458846156531, 3.158154965241037e-08]]]}} + +======= 20200622: +{'HEG': {0: [[600.0, [-6635.813431810828, 53.075898114105726, -0.15253171108859886, 0.00019792480095656869, -9.598209896301075e-08]], [1950.0, [46.600135556920925, 0.8412063733137993, 0.00023492720237763438, -1.2593652551917328e-07, 2.5435326557098538e-11]]], 3: [[400.0, [1051.452570904546, -13.099314837713008, 0.06939879665006896, -0.00014784669111041307, 1.155031075284652e-07]], [600.0, [2782.786054275039, -21.145755715684032, 0.06554921272398154, -8.534237586539917e-05, 4.134061079155964e-08]], [1950.0, [87.23060103156234, 0.7171860430279529, 0.0003793918782124725, -1.9605428816497513e-07, 3.6770897051532086e-11]]], 2: [[590.0, [-12422.076427583952, 100.54771064816772, -0.29845648627641835, 0.00039688772576782855, -1.97439876026206e-07]], [1940.0, [-33.02431482418943, 1.1302724323594304, -0.00013479679549416608, 7.22272393581498e-08, -1.373032035520199e-11]]], 1: [[600.0, [-4701.14124376318, 38.11250082824693, -0.10953080869095329, 0.00014349645302935956, -7.03019927601252e-08]], [1950.0, [84.53488099145231, 0.7066601865786498, 0.00043283422433330405, -2.2608518373215027e-07, 4.202604094132355e-11]]]}, 'MEG': {0: [[600.0, [-5436.760853858342, 43.96983227683935, -0.12687747514944603, 0.00016616428936737506, -8.139167807653272e-08]], [1900.0, [120.48660483356667, 0.5730901209923781, 0.0005878274491379978, -3.237518769395626e-07, 6.578470645318609e-11]], [2200.0, [871551.4774974757, -1768.0310136624694, 1.3455105429844192, -0.0004544802466941742, 5.7523770112673466e-08]], [2450.0, [172814587.77370718, -314312.8362227405, 214.2281301218352, -0.06484750125371046, 7.355540503587943e-06]]], 3: [[400.0, [2847.79940016946, -36.333603982010075, 0.18104460124913768, -0.0003840780707796322, 3.0129211549627434e-07]], [600.0, [5465.629361402122, -44.12377192190018, 0.13886417042191168, -0.0001885833582746921, 9.547898180355825e-08]], [1900.0, [182.12010345268018, 0.35919202965098807, 0.0008707482678487033, -4.856922998327794e-07, 9.884030291073737e-11]], [2200.0, [362187.83689184266, -726.3913418571299, 0.54768053740453, -0.00018321591051596335, 2.2978901938142268e-08]], [2450.0, [163215386.96623987, -297217.6590198315, 202.81927145830707, -0.06146587413251898, 6.9799301086463304e-06]]], 2: [[590.0, [-5012.940342322967, 40.90754759075464, -0.11882247811910264, 0.0001569980318593441, -7.761119020096338e-08]], [1890.0, [91.60119828336364, 0.6656924204319927, 0.0004832519962652505, -2.757432638354398e-07, 5.703445281307984e-11]], [2190.0, [45693.94622214341, -75.57511935673534, 0.04636435676939522, -1.1778591339230115e-05, 1.017435459087865e-09]], [2440.0, [-192889190.47764766, 346563.0252901632, -233.37468139750922, 0.06980799193170947, -7.826020204253014e-06]]], 1: [[600.0, [-3621.195557803563, 29.38209496572412, -0.08337726780845282, 0.00010909919798197781, -5.3540413516786254e-08]], [1900.0, [129.0956307507799, 0.5398695804747401, 0.0006597026712875963, -3.5782948211437904e-07, 6.972425989874214e-11]], [2200.0, [-14542.156374389713, 38.281229302666205, -0.03424149697876769, 1.3575206568333219e-05, -1.972456982132864e-09]], [2450.0, [446086157.2495124, -829455.8119188424, 578.3010967459121, -0.17917865071552705, 2.081637200558685e-05]]]}} + +======= 20200706: +{'HEG': {0: [[600, [-6635.813431810828, 53.075898114105726, -0.15253171108859886, 0.00019792480095656869, -9.598209896301075e-08]], [3000, [46.600135556920925, 0.8412063733137993, 0.00023492720237763438, -1.2593652551917328e-07, 2.5435326557098538e-11]]], 3: [[400, [1051.452570904546, -13.099314837713008, 0.06939879665006896, -0.00014784669111041307, 1.155031075284652e-07]], [600, [2782.786054275039, -21.145755715684032, 0.06554921272398154, -8.534237586539917e-05, 4.134061079155964e-08]], [3000, [87.23060103156234, 0.7171860430279529, 0.0003793918782124725, -1.9605428816497513e-07, 3.6770897051532086e-11]]], 2: [[590, [-12422.076427583952, 100.54771064816772, -0.29845648627641835, 0.00039688772576782855, -1.97439876026206e-07]], [3000, [-33.02431482418943, 1.1302724323594304, -0.00013479679549416608, 7.22272393581498e-08, -1.373032035520199e-11]]], 1: [[600, [-4701.14124376318, 38.11250082824693, -0.10953080869095329, 0.00014349645302935956, -7.03019927601252e-08]], [3000, [84.53488099145231, 0.7066601865786498, 0.00043283422433330405, -2.2608518373215027e-07, 4.202604094132355e-11]]]}, 'MEG': {0: [[600, [-5436.760853858342, 43.96983227683935, -0.12687747514944603, 0.00016616428936737506, -8.139167807653272e-08]], [2200, [56.06352322156944, 0.8254716336525104, 0.00023420268295012815, -1.1314108538379183e-07, 2.0621468462144593e-11]], [3000, [172814587.77370718, -314312.8362227405, 214.2281301218352, -0.06484750125371046, 7.355540503587943e-06]]], 3: [[400, [2847.79940016946, -36.333603982010075, 0.18104460124913768, -0.0003840780707796322, 3.0129211549627434e-07]], [600, [5465.629361402122, -44.12377192190018, 0.13886417042191168, -0.0001885833582746921, 9.547898180355825e-08]], [2200, [99.53668134362802, 0.6852352218453821, 0.00041049997712041544, -2.0966225686036783e-07, 3.9272109948245565e-11]], [3000, [163215386.96623987, -297217.6590198315, 202.81927145830707, -0.06146587413251898, 6.9799301086463304e-06]]], 2: [[590, [-5012.940342322967, 40.90754759075464, -0.11882247811910264, 0.0001569980318593441, -7.761119020096338e-08]], [2190, [45.055606320266705, 0.8510934669860255, 0.00021908816244155997, -1.1578973121798198e-07, 2.2181508654369528e-11]], [3000, [-192889190.47764766, 346563.0252901632, -233.37468139750922, 0.06980799193170947, -7.826020204253014e-06]]], 1: [[600, [-3621.195557803563, 29.38209496572412, -0.08337726780845282, 0.00010909919798197781, -5.3540413516786254e-08]], [2200, [98.2725122115956, 0.6600798933531754, 0.0004924159000925939, -2.5906403174375766e-07, 4.8760807025108714e-11]], [3000, [446086157.2495124, -829455.8119188424, 578.3010967459121, -0.17917865071552705, 2.081637200558685e-05]]]}} + +======= 20210614: +{'HEG': {0: [[600, [-6635.813431810828, 53.075898114105726, -0.15253171108859886, 0.00019792480095656869, -9.598209896301075e-08]], [3000, [46.600135556920925, 0.8412063733137993, 0.00023492720237763438, -1.2593652551917328e-07, 2.5435326557098538e-11]]], 3: [[400, [1051.452570904546, -13.099314837713008, 0.06939879665006896, -0.00014784669111041307, 1.155031075284652e-07]], [600, [2782.786054275039, -21.145755715684032, 0.06554921272398154, -8.534237586539917e-05, 4.134061079155964e-08]], [3000, [87.23060103156234, 0.7171860430279529, 0.0003793918782124725, -1.9605428816497513e-07, 3.6770897051532086e-11]]], 2: [[590, [-12422.076427583952, 100.54771064816772, -0.29845648627641835, 0.00039688772576782855, -1.97439876026206e-07]], [3000, [-33.02431482418943, 1.1302724323594304, -0.00013479679549416608, 7.22272393581498e-08, -1.373032035520199e-11]]], 1: [[600.0,[-4765.159827798981,39.08508762376964,-0.11372474852884872,0.00015063687981483728,-7.456557379431018e-08]], [3000, [84.53488099145231, 0.7066601865786498, 0.00043283422433330405, -2.2608518373215027e-07, 4.202604094132355e-11]]]}, 'MEG': {0: [[600.0, [-5940.176848239725, 48.30636368582396, -0.14075467796987542, 0.00018579017325356665, -9.17653113254405e-08]], [2200.0, [20.344164869431648, 0.942351240250947, 0.00010121556917763097, -4.949527030585497e-08, 9.675448511744878e-12]], [3000.0, [-4404763.957023886, 8771.484099309775, -6.96403516159204, 0.0027567541197318075, -5.440997034278868e-07, 4.283864981515836e-11]]], 3: [[600.0, [-634.0261758446517, 7.262520018224911, -0.022419323576083252, 3.49681129089603e-05, -1.999932008653819e-08]], [2200.0, [58.93716149881088, 0.8198484295498225, 0.0002490011121555607, -1.2688431897796926e-07, 2.37752539333468e-11]], [3000.0, [-4631113.606305979, 9166.887699472501, -7.234158616723412, 0.002846359389924523, -5.583729142369206e-07, 4.369437481746841e-11]]], 2: [[600.0, [-604.5006436697821, 3.0530278050672597, 0.0006285185258970196, -7.876285868395855e-06, 6.618688516815772e-09]], [2200.0, [34.67137980324179, 0.8848938354598829, 0.00017775770898386393, -9.469862981232054e-08, 1.8324158207531115e-11]], [3000.0, [-2860246.725610371, 5647.919349714751, -4.443144683580959, 0.0017419171106990991, -3.403199365489676e-07, 2.651081000072826e-11]]], 1: [[600.0, [-3677.005333394253, 29.772255818860682, -0.0843978889369737, 0.00011023738262993015, -5.399238835077749e-08]], [2200.0, [46.243321909129264, 0.8454613578261618, 0.00024604317670495594, -1.1956387793694198e-07, 2.0350719268411266e-11]], [3000.0, [-3805516.9914133963, 7585.769563793042, -6.02924886735418, 0.0023897269861474146, -4.7232898993001013e-07, 3.724663288363978e-11]]]}} + +======= 20220209: +{'HEG': {0: [[600, [-6635.813431810828, 53.075898114105726, -0.15253171108859886, 0.00019792480095656869, -9.598209896301075e-08]], [3000, [46.600135556920925, 0.8412063733137993, 0.00023492720237763438, -1.2593652551917328e-07, 2.5435326557098538e-11]]], 3: [[400, [1051.452570904546, -13.099314837713008, 0.06939879665006896, -0.00014784669111041307, 1.155031075284652e-07]], [600, [2782.786054275039, -21.145755715684032, 0.06554921272398154, -8.534237586539917e-05, 4.134061079155964e-08]], [3000, [87.23060103156234, 0.7171860430279529, 0.0003793918782124725, -1.9605428816497513e-07, 3.6770897051532086e-11]]], 2: [[590, [-12422.076427583952, 100.54771064816772, -0.29845648627641835, 0.00039688772576782855, -1.97439876026206e-07]], [3000, [-33.02431482418943, 1.1302724323594304, -0.00013479679549416608, 7.22272393581498e-08, -1.373032035520199e-11]]], 1: [[600.0, [-4765.159827798981, 39.08508762376964, -0.11372474852884872, 0.00015063687981483728, -7.456557379431018e-08]], [3000, [84.53488099145231, 0.7066601865786498, 0.00043283422433330405, -2.2608518373215027e-07, 4.202604094132355e-11]]]}, 'MEG': {0: [[600.0, [-3934.5121751152246, 33.06771682164138, -0.09748027014943843, 0.00013134538357912652, -6.6156258423234e-08]], [2200.0, [37.641114276917925, 0.8805247038981882, 0.000177319710501711, -8.681533726733966e-08, 1.637418437746742e-11]], [2475.0, [37283044.37499022, -66946.28212137106, 45.04278902689384, -0.013457675462255252, 1.506533154743431e-06]], [2975.0, [17.45662531316536, 0.9879977565183667, -1.4023065577422464e-05, 4.13598612141151e-08, -1.10678651468184e-11]]], 3: [[600.0, [-327.2776484031912, 4.250523583656505, -0.011420286241297649, 1.7377653116404346e-05, -9.625686600221612e-09]], [2200.0, [115.13378003090979, 0.62518020085401, 0.000493471405264986, -2.541590613504621e-07, 4.7566608931331754e-11]], [2475.0, [67723621.24081981, -121554.95831214589, 81.75236674834781, -0.02441691402082744, 2.7324624578449198e-06]], [2975.0, [282015.3094934323, -421.5392502375951, 0.2368599641813117, -5.886206039411446e-05, 5.4722692634234e-09]]], 2: [[600.0, [-604.5006436697821, 3.0530278050672597, 0.0006285185258970196, -7.876285868395855e-06, 6.618688516815772e-09]], [2200.0, [34.67137980324179, 0.8848938354598829, 0.00017775770898386393, -9.469862981232054e-08, 1.8324158207531115e-11]], [3000.0, [-2860246.725610371, 5647.919349714751, -4.443144683580959, 0.0017419171106990991, -3.403199365489676e-07, 2.651081000072826e-11]]], 1: [[600.0, [-5546.5982856048695, 45.335675108612506, -0.13258153746595475, 0.000176077206850398, -8.750569596947354e-08]], [2200.0, [92.51295555787782, 0.6803805602551622, 0.000465091752020332, -2.401401686918187e-07, 4.423893424043697e-11]], [2475.0, [3449361.27208402, -5801.739949520198, 3.631288689620224, -0.0010005763773733346, 1.0226450881073942e-07]], [2975.0, [3927.9644361329165, 2.1528284786200116, -0.004967658772507909, 2.429386882858212e-06, -3.4831847463365186e-10]]]}} + +======= 20220224: +{'HEG': {0: [[600, [-6635.813431810828, 53.075898114105726, -0.15253171108859886, 0.00019792480095656869, -9.598209896301075e-08]], [3000, [46.600135556920925, 0.8412063733137993, 0.00023492720237763438, -1.2593652551917328e-07, 2.5435326557098538e-11]]], 3: [[400, [1051.452570904546, -13.099314837713008, 0.06939879665006896, -0.00014784669111041307, 1.155031075284652e-07]], [600, [2782.786054275039, -21.145755715684032, 0.06554921272398154, -8.534237586539917e-05, 4.134061079155964e-08]], [3000, [87.23060103156234, 0.7171860430279529, 0.0003793918782124725, -1.9605428816497513e-07, 3.6770897051532086e-11]]], 2: [[590, [-12422.076427583952, 100.54771064816772, -0.29845648627641835, 0.00039688772576782855, -1.97439876026206e-07]], [3000, [-33.02431482418943, 1.1302724323594304, -0.00013479679549416608, 7.22272393581498e-08, -1.373032035520199e-11]]], 1: [[600.0, [-4765.159827798981, 39.08508762376964, -0.11372474852884872, 0.00015063687981483728, -7.456557379431018e-08]], [3000, [84.53488099145231, 0.7066601865786498, 0.00043283422433330405, -2.2608518373215027e-07, 4.202604094132355e-11]]]}, 'MEG': {0: [[600.0, [-3934.5121751152246, 33.06771682164138, -0.09748027014943843, 0.00013134538357912652, -6.6156258423234e-08]], [2200.0, [37.641114276917925, 0.8805247038981882, 0.000177319710501711, -8.681533726733966e-08, 1.637418437746742e-11]], [2475.0, [37283044.37499022, -66946.28212137106, 45.04278902689384, -0.013457675462255252, 1.506533154743431e-06]], [3000.0, [17.45662531316536, 0.9879977565183667, -1.4023065577422464e-05, 4.13598612141151e-08, -1.10678651468184e-11]]], 3: [[600.0, [-327.2776484031912, 4.250523583656505, -0.011420286241297649, 1.7377653116404346e-05, -9.625686600221612e-09]], [2200.0, [115.13378003090979, 0.62518020085401, 0.000493471405264986, -2.541590613504621e-07, 4.7566608931331754e-11]], [2475.0, [67723621.24081981, -121554.95831214589, 81.75236674834781, -0.02441691402082744, 2.7324624578449198e-06]], [3000.0, [282015.3094934323, -421.5392502375951, 0.2368599641813117, -5.886206039411446e-05, 5.4722692634234e-09]]], 2: [[600.0, [-604.5006436697821, 3.0530278050672597, 0.0006285185258970196, -7.876285868395855e-06, 6.618688516815772e-09]], [2200.0, [34.67137980324179, 0.8848938354598829, 0.00017775770898386393, -9.469862981232054e-08, 1.8324158207531115e-11]], [3000.0, [-2860246.725610371, 5647.919349714751, -4.443144683580959, 0.0017419171106990991, -3.403199365489676e-07, 2.651081000072826e-11]]], 1: [[600.0, [-5546.5982856048695, 45.335675108612506, -0.13258153746595475, 0.000176077206850398, -8.750569596947354e-08]], [2200.0, [92.51295555787782, 0.6803805602551622, 0.000465091752020332, -2.401401686918187e-07, 4.423893424043697e-11]], [2475.0, [3449361.27208402, -5801.739949520198, 3.631288689620224, -0.0010005763773733346, 1.0226450881073942e-07]], [3000.0, [3927.9644361329165, 2.1528284786200116, -0.004967658772507909, 2.429386882858212e-06, -3.4831847463365186e-10]]]}} + + +======= 20220302: +{'HEG': {0: [[600.0, [-3934.5121751152246, 33.06771682164138, -0.09748027014943843, 0.00013134538357912652, -6.6156258423234e-08]], [2200.0, [37.641114276917925, 0.8805247038981882, 0.000177319710501711, -8.681533726733966e-08, 1.637418437746742e-11]], [2475.0, [37283044.37499022, -66946.28212137106, 45.04278902689384, -0.013457675462255252, 1.506533154743431e-06]], [3000.0, [17.45662531316536, 0.9879977565183667, -1.4023065577422464e-05, 4.13598612141151e-08, -1.10678651468184e-11]]], 3: [[600.0, [-327.2776484031912, 4.250523583656505, -0.011420286241297649, 1.7377653116404346e-05, -9.625686600221612e-09]], [2200.0, [115.13378003090979, 0.62518020085401, 0.000493471405264986, -2.541590613504621e-07, 4.7566608931331754e-11]], [2475.0, [67723621.24081981, -121554.95831214589, 81.75236674834781, -0.02441691402082744, 2.7324624578449198e-06]], [3000.0, [282015.3094934323, -421.5392502375951, 0.2368599641813117, -5.886206039411446e-05, 5.4722692634234e-09]]], 2: [[600.0, [-604.5006436697821, 3.0530278050672597, 0.0006285185258970196, -7.876285868395855e-06, 6.618688516815772e-09]], [2200.0, [34.67137980324179, 0.8848938354598829, 0.00017775770898386393, -9.469862981232054e-08, 1.8324158207531115e-11]], [3000.0, [-2860246.725610371, 5647.919349714751, -4.443144683580959, 0.0017419171106990991, -3.403199365489676e-07, 2.651081000072826e-11]]], 1: [[600.0, [-5546.5982856048695, 45.335675108612506, -0.13258153746595475, 0.000176077206850398, -8.750569596947354e-08]], [2200.0, [92.51295555787782, 0.6803805602551622, 0.000465091752020332, -2.401401686918187e-07, 4.423893424043697e-11]], [2475.0, [3449361.27208402, -5801.739949520198, 3.631288689620224, -0.0010005763773733346, 1.0226450881073942e-07]], [3000.0, [3927.9644361329165, 2.1528284786200116, -0.004967658772507909, 2.429386882858212e-06, -3.4831847463365186e-10]]]}, 'MEG': {0: [[600.0, [-3934.5121751152246, 33.06771682164138, -0.09748027014943843, 0.00013134538357912652, -6.6156258423234e-08]], [2200.0, [37.641114276917925, 0.8805247038981882, 0.000177319710501711, -8.681533726733966e-08, 1.637418437746742e-11]], [2475.0, [37283044.37499022, -66946.28212137106, 45.04278902689384, -0.013457675462255252, 1.506533154743431e-06]], [3000.0, [17.45662531316536, 0.9879977565183667, -1.4023065577422464e-05, 4.13598612141151e-08, -1.10678651468184e-11]]], 3: [[600.0, [-327.2776484031912, 4.250523583656505, -0.011420286241297649, 1.7377653116404346e-05, -9.625686600221612e-09]], [2200.0, [115.13378003090979, 0.62518020085401, 0.000493471405264986, -2.541590613504621e-07, 4.7566608931331754e-11]], [2475.0, [67723621.24081981, -121554.95831214589, 81.75236674834781, -0.02441691402082744, 2.7324624578449198e-06]], [3000.0, [282015.3094934323, -421.5392502375951, 0.2368599641813117, -5.886206039411446e-05, 5.4722692634234e-09]]], 2: [[600.0, [-604.5006436697821, 3.0530278050672597, 0.0006285185258970196, -7.876285868395855e-06, 6.618688516815772e-09]], [2200.0, [34.67137980324179, 0.8848938354598829, 0.00017775770898386393, -9.469862981232054e-08, 1.8324158207531115e-11]], [3000.0, [-2860246.725610371, 5647.919349714751, -4.443144683580959, 0.0017419171106990991, -3.403199365489676e-07, 2.651081000072826e-11]]], 1: [[600.0, [-5546.5982856048695, 45.335675108612506, -0.13258153746595475, 0.000176077206850398, -8.750569596947354e-08]], [2200.0, [92.51295555787782, 0.6803805602551622, 0.000465091752020332, -2.401401686918187e-07, 4.423893424043697e-11]], [2475.0, [3449361.27208402, -5801.739949520198, 3.631288689620224, -0.0010005763773733346, 1.0226450881073942e-07]], [3000.0, [3927.9644361329165, 2.1528284786200116, -0.004967658772507909, 2.429386882858212e-06, -3.4831847463365186e-10]]]}} \ No newline at end of file diff --git a/instruments/IEX_dictionaries/Dict_Slit.txt b/instruments/IEX_dictionaries/Dict_Slit.txt new file mode 100644 index 0000000000000000000000000000000000000000..12ba84e10e0a5536d0f46c66aabe0d9649c9084a --- /dev/null +++ b/instruments/IEX_dictionaries/Dict_Slit.txt @@ -0,0 +1,135 @@ + +======= 20201231: +{'HEG':{'S1H':0,'S1V':0.25,'S2H':0,'S2V':-0.75},'MEG':{'S1H':0.25,'S1V':0.125,'S2H':-0.5,'S2V':0.5}} + +======= 20210101: +{'HEG': {'S1H':0,'S1V':0.25,'S2H':0,'S2V':-0.75}, 'MEG': {'S1H':0.25,'S1V':0.125,'S2H':-0.5,'S2V':0.5}} + +======= 20210126: +{'HEG': {'S1H': 0, 'S1V': 0.25, 'S2H': 0, 'S2V': -0.75}, 'MEG': {'S1H': 0.0, 'S1V': 0.0, 'S2H': 0.25, 'S2V': 0.0}} + +======= 20210127: +{'HEG': {'S1H': 0.0, 'S1V': 0.0, 'S2H': 0.0, 'S2V': 0.0}, 'MEG': {'S1H': 0.0, 'S1V': 0.0, 'S2H': 0.25, 'S2V': 0.0}} + +======= 20210209: +{'HEG': {'S1H': 0.0, 'S1V': 0.0, 'S2H': 0.0, 'S2V': 0.0}, 'MEG': {'S1H': 0.0, 'S1V': 0.0, 'S2H': 0.0, 'S2V': 0.0}} + +======= 20210316: +{'HEG': {'S1H': 0.0, 'S1V': 0.0, 'S2H': 0.0, 'S2V': 0.0}, 'MEG': {'S1H': -0.125, 'S1V': 0.0, 'S2H': -0.325, 'S2V': -0.25}} + +======= 20210323: +{'HEG': {'S1H': 0.0, 'S1V': 0.0, 'S2H': 0.0, 'S2V': 0.0}, 'MEG': {'S1H': -0.5, 'S1V': 0.0, 'S2H': -0.25, 'S2V': 0.0}} + +======= 20210330: +{'HEG': {'S1H': 0.0, 'S1V': 0.0, 'S2H': 0.0, 'S2V': 0.0}, 'MEG': {'S1H': -0.125, 'S1V': 0.0, 'S2H': -0.25, 'S2V': 0.0}} + +======= 20210406: +{'HEG': {'S1H': 0.0, 'S1V': 0.0, 'S2H': 0.0, 'S2V': 0.0}, 'MEG': {'S1H': 0.0, 'S1V': 0.0, 'S2H': 0.0, 'S2V': 0.0}} + +======= 20210408: +{'HEG': {'S1H': 0.0, 'S1V': 0.0, 'S2H': 0.0, 'S2V': 0.0}, 'MEG': {'S1H': -0.125, 'S1V': -0.125, 'S2H': 0.0, 'S2V': -0.25}} + +======= 20210413: +{'HEG': {'S1H': 0.0, 'S1V': 0.0, 'S2H': 0.0, 'S2V': 0.0}, 'MEG': {'S1H': -0.125, 'S1V': -0.1, 'S2H': -0.25, 'S2V': 0.0}} + +======= 20210413: +{'HEG': {'S1H': 0.0, 'S1V': 0.0, 'S2H': 0.0, 'S2V': 0.0}, 'MEG': {'S1H': 0.125, 'S1V': -0.1, 'S2H': 0.25, 'S2V': -0.25}} + +======= 20210603: +{'HEG': {'S1H': 0.0, 'S1V': 0.0, 'S2H': 0.0, 'S2V': 0.0}, 'MEG': {'S1H': 0.125, 'S1V': 0.0, 'S2H': 0.5, 'S2V': 0.0}} + +======= 20210603: +{'HEG': {'S1H': 0.125, 'S1V': 0.0, 'S2H': 0.75, 'S2V': -1.0}, 'MEG': {'S1H': 0.125, 'S1V': 0.0, 'S2H': 0.5, 'S2V': 0.0}} + +======= 20210603: +{'HEG': {'S1H': 0.125, 'S1V': -0.125, 'S2H': 0.75, 'S2V': -1.0}, 'MEG': {'S1H': 0.125, 'S1V': 0.0, 'S2H': 0.5, 'S2V': 0.0}} + +======= 20210622: +{'HEG': {'S1H': 0.125, 'S1V': -0.125, 'S2H': 0.75, 'S2V': -1.0}, 'MEG': {'S1H': 0.0, 'S1V': -0.125, 'S2H': -0.25, 'S2V': -0.25}} + +======= 20210629: +{'HEG': {'S1H': 0.125, 'S1V': -0.125, 'S2H': 0.75, 'S2V': -1.0}, 'MEG': {'S1H': 0.0, 'S1V': 0.0, 'S2H': -0.5, 'S2V': 0.25}} + +======= 20210708: +{'HEG': {'S1H': 0.125, 'S1V': -0.125, 'S2H': 0.75, 'S2V': -1.0}, 'MEG': {'S1H': 0.125, 'S1V': -0.125, 'S2H': -0.25, 'S2V': -0.25}} + +======= 20210714: +{'HEG': {'S1H': 0.125, 'S1V': -0.125, 'S2H': 0.75, 'S2V': -1.0}, 'MEG': {'S1H': 0.125, 'S1V': 0.0, 'S2H': -0.75, 'S2V': 0.0}} + +======= 20210727: +{'HEG': {'S1H': 0.125, 'S1V': -0.125, 'S2H': 0.75, 'S2V': -1.0}, 'MEG': {'S1H': 0.125, 'S1V': -0.125, 'S2H': -0.25, 'S2V': -0.25}} + +======= 20210914: +{'HEG': {'S1H': 0.25, 'S1V': 0.0, 'S2H': -0.25, 'S2V': 0.0}, 'MEG': {'S1H': 0.125, 'S1V': -0.125, 'S2H': -0.25, 'S2V': -0.25}} + +======= 20210914: +{'HEG': {'S1H': 0.25, 'S1V': 0.0, 'S2H': -0.25, 'S2V': 0.0}, 'MEG': {'S1H': 0.125, 'S1V': 0.0, 'S2H': -0.25, 'S2V': 0.0}} + +======= 20211004: +{'HEG': {'S1H': 0.25, 'S1V': 0.0, 'S2H': -0.25, 'S2V': 0.0}, 'MEG': {'S1H': 0.125, 'S1V': 0.0, 'S2H': -0.5, 'S2V': 0.0}} + +======= 20211019: +{'HEG': {'S1H': 0.25, 'S1V': 0.0, 'S2H': -0.25, 'S2V': 0.0}, 'MEG': {'S1H': 0.125, 'S1V': 0.0, 'S2H': -0.75, 'S2V': 0.0}} + +======= 20211103: +{'HEG': {'S1H': 0.25, 'S1V': 0.0, 'S2H': -0.25, 'S2V': 0.0}, 'MEG': {'S1H': 0.0, 'S1V': -0.125, 'S2H': -0.75, 'S2V': 0.0}} + +======= 20211109: +{'HEG': {'S1H': -0.125, 'S1V': 0.0, 'S2H': -0.25, 'S2V': -0.25}, 'MEG': {'S1H': 0.0, 'S1V': -0.125, 'S2H': -0.75, 'S2V': 0.0}} + +======= 20211117: +{'HEG': {'S1H': -0.125, 'S1V': 0.0, 'S2H': -0.25, 'S2V': -0.25}, 'MEG': {'S1H': 0.125, 'S1V': 0.0, 'S2H': -0.25, 'S2V': 0.0}} + +======= 20211117: +{'HEG': {'S1H': -0.125, 'S1V': 0.0, 'S2H': -0.25, 'S2V': -0.25}, 'MEG': {'S1H': 0.125, 'S1V': 0.0, 'S2H': -0.25, 'S2V': 0.0}} + +======= 20211214: +{'HEG': {'S1H': -0.125, 'S1V': 0.0, 'S2H': -0.25, 'S2V': -0.25}, 'MEG': {'S1H': 0.25, 'S1V': 0.0, 'S2H': -0.75, 'S2V': 0.0}} + +======= 20220202: +{'HEG': {'S1H': 0.25, 'S1V': 0.0, 'S2H': 0.25, 'S2V': 0.25}, 'MEG': {'S1H': 0.25, 'S1V': 0.0, 'S2H': -0.75, 'S2V': 0.0}} + +======= 20220202: +{'HEG': {'S1H': 0.25, 'S1V': 0.0, 'S2H': 0.25, 'S2V': 0.25}, 'MEG': {'S1H': 0.0, 'S1V': 0.0, 'S2H': 0.0, 'S2V': 0.0}} + +======= 20220209: +{'HEG': {'S1H': 0.25, 'S1V': 0.0, 'S2H': 0.25, 'S2V': 0.25}, 'MEG': {'S1H': 0.125, 'S1V': -0.125, 'S2H': -0.25, 'S2V': 0.0}} + +======= 20220215: +{'HEG': {'S1H': 0.25, 'S1V': 0.0, 'S2H': 0.25, 'S2V': 0.25}, 'MEG': {'S1H': 0.125, 'S1V': 0.0, 'S2H': -0.25, 'S2V': 0.125}} + +======= 20220215: +{'HEG': {'S1H': 0.25, 'S1V': 0.0, 'S2H': 0.25, 'S2V': 0.25}, 'MEG': {'S1H': 0.125, 'S1V': 0.0, 'S2H': -0.25, 'S2V': 0.0}} + +======= 20220222: +{'HEG': {'S1H': 0.25, 'S1V': 0.0, 'S2H': 0.25, 'S2V': 0.25}, 'MEG': {'S1H': 0.1, 'S1V': 0.0, 'S2H': 0.22, 'S2V': 0.0}} + +======= 20220228: +{'HEG': {'S2V': 0.25, 'S2H': 0.25, 'S1V': 0.0,'S1H': 0.25 }, 'MEG': {'S2V': 0.0, 'S2H': 0.22, 'S1V': 0.0, 'S1H': 0.1}} + +======= 20220302: +{'HEG': {'S2V': 0.25, 'S2H': 0.25, 'S1V': 0.0, 'S1H': 0.25}, 'MEG': {'S2V': 0.0, 'S2H': 0.352, 'S1V': -0.132, 'S1H': 0.12}} + +======= 20220302: +{'HEG': {'S2V': -0.3, 'S2H': 0.2, 'S1V': 0.0, 'S1H': 0.0}, 'MEG': {'S2V': 0.0, 'S2H': 0.352, 'S1V': -0.132, 'S1H': 0.12}} + +======= 20220308: +{'HEG': {'S2V': -0.3, 'S2H': 0.2, 'S1V': 0.0, 'S1H': 0.0}, 'MEG': {'S2V': 0.2, 'S2H': 0.2, 'S1V': -0.08, 'S1H': 0.16}} + +======= 20220310: +{'HEG': {'S2V': -0.3, 'S2H': 0.2, 'S1V': 0.0, 'S1H': 0.0}, 'MEG': {'S2V': 0.133, 'S2H': 0.245, 'S1V': -0.105, 'S1H': 0.17}} + +======= 20220310: +{'HEG': {'S2V': -0.3, 'S2H': 0.2, 'S1V': 0.0, 'S1H': 0.0}, 'MEG': {'S2V': 0.107, 'S2H': 0.109, 'S1V': -0.105, 'S1H': 0.166}} + +======= 20220316: +{'HEG': {'S2V': -0.3, 'S2H': 0.2, 'S1V': 0.0, 'S1H': 0.0}, 'MEG': {'S2V': 0.0, 'S2H': 0.284, 'S1V': -0.055, 'S1H': 0.156}} + +======= 20220322: +{'HEG': {'S2V': -0.244, 'S2H': -0.125, 'S1V': 0.0, 'S1H': 0.09}, 'MEG': {'S2V': 0.0, 'S2H': 0.284, 'S1V': -0.055, 'S1H': 0.156}} + +======= 20220322: +{'HEG': {'S2V': -0.244, 'S2H': -0.125, 'S1V': 0.0, 'S1H': 0.09}, 'MEG': {'S2V': 0.0976, 'S2H': -0.002, 'S1V': -0.0353, 'S1H': 0.1558}} + +======= 20220329: +{'HEG': {'S2V': -0.244, 'S2H': -0.125, 'S1V': 0.0, 'S1H': 0.09}, 'MEG': {'S2V': 0.05, 'S2H': -0.02, 'S1V': -0.05, 'S1H': 0.1}} diff --git a/instruments/IEX_dictionaries/Dict_TempDiode.txt b/instruments/IEX_dictionaries/Dict_TempDiode.txt new file mode 100644 index 0000000000000000000000000000000000000000..4e851f702a7ccb73ca32e6628f41851fb6cce453 --- /dev/null +++ b/instruments/IEX_dictionaries/Dict_TempDiode.txt @@ -0,0 +1 @@ +{"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],"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]} diff --git a/instruments/IEX_dictionaries/DiodeResponsivityCurve b/instruments/IEX_dictionaries/DiodeResponsivityCurve new file mode 100644 index 0000000000000000000000000000000000000000..02429176220d8db8fa80b69b0cebd641378de690 --- /dev/null +++ b/instruments/IEX_dictionaries/DiodeResponsivityCurve @@ -0,0 +1,200 @@ +Responsivity Energy +0.109341 10.0752 +0.1075 10.168 +0.105579 10.2777 +0.103737 10.3979 +0.101656 10.5007 +0.099895 10.614 +0.0978137 10.719 +0.0959725 10.8153 +0.0943715 10.9124 +0.0926103 11.0203 +0.0910093 11.1193 +0.0896484 11.1792 +0.0880474 11.2695 +0.0864464 11.3809 +0.0847653 11.514 +0.0830042 11.6591 +0.0812431 11.8378 +0.0798822 11.9762 +0.0790816 12.2033 +0.0788414 12.457 +0.0790015 12.7502 +0.079882 12.992 +0.081403 13.2029 +0.083084 13.4172 +0.0842847 13.5257 +0.0866862 13.733 +0.0882072 13.844 +0.0898882 14.006 +0.0918894 14.1572 +0.0939708 14.3613 +0.0965323 14.5553 +0.0983735 14.6862 +0.100215 14.8049 +0.101976 14.9113 +0.103817 15.0453 +0.106058 15.2077 +0.107899 15.3169 +0.109981 15.4546 +0.112062 15.5796 +0.113983 15.7196 +0.115824 15.8325 +0.117585 15.9748 +0.119747 16.1328 +0.121588 16.2342 +0.123349 16.3654 +0.12535 16.5421 +0.127832 16.7207 +0.130233 16.9466 +0.132419 17.1223 +0.135033 17.342 +0.137321 17.5348 +0.139608 17.7901 +0.141896 18.0644 +0.144837 18.3742 +0.14756 18.6576 +0.149957 18.881 +0.152462 19.1722 +0.154532 19.4348 +0.157364 19.7345 +0.159325 20.0048 +0.161395 20.2615 +0.163356 20.5216 +0.165752 20.7673 +0.167822 21.016 +0.170545 21.3039 +0.172942 21.5957 +0.175774 21.9287 +0.178389 22.248 +0.180131 22.4379 +0.182419 22.7259 +0.184707 22.9981 +0.186667 23.2932 +0.188193 23.6323 +0.189718 24.0376 +0.191352 24.4498 +0.193203 24.975 +0.194837 25.4466 +0.196036 25.8609 +0.197016 26.3044 +0.198105 26.9839 +0.199086 27.5401 +0.19963 27.9886 +0.200284 28.5655 +0.201062 29.1788 +0.202043 29.8563 +0.202874 30.4717 +0.203931 31.2588 +0.204762 31.8625 +0.205385 32.3423 +0.205728 32.6468 +0.2059 33.0831 +0.205685 33.4729 +0.205685 33.9202 +0.205814 34.4273 +0.205942 34.8329 +0.206423 35.5101 +0.206929 36.335 +0.207582 37.2736 +0.208236 38.2689 +0.20878 39.2241 +0.209543 40.3401 +0.210196 41.4878 +0.211068 43.0324 +0.211721 44.1815 +0.212375 45.5159 +0.213029 46.8506 +0.213847 48.4147 +0.21499 51.095 +0.217278 56.3781 +0.220137 63.5332 +0.222901 71.5962 +0.225284 79.93 +0.227667 88.1947 +0.23024 98.0003 +0.232909 110.697 +0.235768 124.745 +0.238437 137.322 +0.240915 151.521 +0.24406 168.367 +0.24692 187.965 +0.25016 211.325 +0.252924 234.82 +0.256451 265.864 +0.259215 294.732 +0.26217 329.039 +0.263599 344.016 +0.26522 365.622 +0.266649 386.769 +0.267602 405.322 +0.268365 421.79 +0.269127 442.023 +0.270176 464.314 +0.271034 482.048 +0.271863 502.915 +0.272661 524.768 +0.273353 544.89 +0.273888 560.168 +0.274296 577.813 +0.274432 596.754 +0.274432 613.265 +0.274387 630.233 +0.274387 655.755 +0.274577 677.334 +0.274896 698.718 +0.275163 720.777 +0.275588 742.318 +0.275801 762.005 +0.275908 786.062 +0.275961 813.536 +0.275961 836.479 +0.275961 860.069 +0.275961 881.435 +0.275854 906.293 +0.275804 934.582 +0.275686 968.151 +0.27545 999.14 +0.275214 1031.12 +0.275095 1056.11 +0.274918 1083.07 +0.274682 1109.32 +0.274446 1141.94 +0.27421 1174.05 +0.273856 1210.1 +0.273561 1248.84 +0.273207 1287.19 +0.272819 1322.48 +0.272499 1357.16 +0.272086 1386.55 +0.271732 1413.01 +0.271437 1436.35 +0.271161 1464.13 +0.270905 1482.33 +0.270669 1501.13 +0.270374 1520.17 +0.269961 1543.33 +0.26943 1568.82 +0.268401 1596.21 +0.26707 1629.27 +0.265713 1664.55 +0.264474 1696.32 +0.26347 1724.34 +0.26228 1755.08 +0.261215 1786.94 +0.259937 1822.37 +0.259032 1849.4 +0.258155 1871.57 +0.257397 1894.63 +0.256576 1915.74 +0.255377 1947.28 +0.275058 1957.05 +0.275058 2160.44 +0.275058 2389.74 +0.275058 2507.09 +0.275058 2604.07 +0.275058 2715.63 +0.275058 2962.14 +0.275058 3276.53 +0.275058 3649.72 +0.275058 3981.03 diff --git a/instruments/IEX_dictionaries/DiodeResponsivityCurve_2 b/instruments/IEX_dictionaries/DiodeResponsivityCurve_2 new file mode 100644 index 0000000000000000000000000000000000000000..b51d96dc29fe857d259516bebd1ce629d778d8cd --- /dev/null +++ b/instruments/IEX_dictionaries/DiodeResponsivityCurve_2 @@ -0,0 +1,200 @@ +Responsivity Energy +0.109341 10.0752 +0.1075 10.168 +0.105579 10.2777 +0.103737 10.3979 +0.101656 10.5007 +0.099895 10.614 +0.0978137 10.719 +0.0959725 10.8153 +0.0943715 10.9124 +0.0926103 11.0203 +0.0910093 11.1193 +0.0896484 11.1792 +0.0880474 11.2695 +0.0864464 11.3809 +0.0847653 11.514 +0.0830042 11.6591 +0.0812431 11.8378 +0.0798822 11.9762 +0.0790816 12.2033 +0.0788414 12.457 +0.0790015 12.7502 +0.079882 12.992 +0.081403 13.2029 +0.083084 13.4172 +0.0842847 13.5257 +0.0866862 13.733 +0.0882072 13.844 +0.0898882 14.006 +0.0918894 14.1572 +0.0939708 14.3613 +0.0965323 14.5553 +0.0983735 14.6862 +0.100215 14.8049 +0.101976 14.9113 +0.103817 15.0453 +0.106058 15.2077 +0.107899 15.3169 +0.109981 15.4546 +0.112062 15.5796 +0.113983 15.7196 +0.115824 15.8325 +0.117585 15.9748 +0.119747 16.1328 +0.121588 16.2342 +0.123349 16.3654 +0.12535 16.5421 +0.127832 16.7207 +0.130233 16.9466 +0.132419 17.1223 +0.135033 17.342 +0.137321 17.5348 +0.139608 17.7901 +0.141896 18.0644 +0.144837 18.3742 +0.14756 18.6576 +0.149957 18.881 +0.152462 19.1722 +0.154532 19.4348 +0.157364 19.7345 +0.159325 20.0048 +0.161395 20.2615 +0.163356 20.5216 +0.165752 20.7673 +0.167822 21.016 +0.170545 21.3039 +0.172942 21.5957 +0.175774 21.9287 +0.178389 22.248 +0.180131 22.4379 +0.182419 22.7259 +0.184707 22.9981 +0.186667 23.2932 +0.188193 23.6323 +0.189718 24.0376 +0.191352 24.4498 +0.193203 24.975 +0.194837 25.4466 +0.196036 25.8609 +0.197016 26.3044 +0.198105 26.9839 +0.199086 27.5401 +0.19963 27.9886 +0.200284 28.5655 +0.201062 29.1788 +0.202043 29.8563 +0.202874 30.4717 +0.203931 31.2588 +0.204762 31.8625 +0.205385 32.3423 +0.205728 32.6468 +0.2059 33.0831 +0.205685 33.4729 +0.205685 33.9202 +0.205814 34.4273 +0.205942 34.8329 +0.206423 35.5101 +0.206929 36.335 +0.207582 37.2736 +0.208236 38.2689 +0.20878 39.2241 +0.209543 40.3401 +0.210196 41.4878 +0.211068 43.0324 +0.211721 44.1815 +0.212375 45.5159 +0.213029 46.8506 +0.213847 48.4147 +0.21499 51.095 +0.217278 56.3781 +0.220137 63.5332 +0.222901 71.5962 +0.225284 79.93 +0.227667 88.1947 +0.23024 98.0003 +0.232909 110.697 +0.235768 124.745 +0.238437 137.322 +0.240915 151.521 +0.24406 168.367 +0.24692 187.965 +0.25016 211.325 +0.252924 234.82 +0.256451 265.864 +0.259215 294.732 +0.26217 329.039 +0.263599 344.016 +0.26522 365.622 +0.266649 386.769 +0.267602 405.322 +0.268365 421.79 +0.269127 442.023 +0.270176 464.314 +0.271034 482.048 +0.271863 502.915 +0.272661 524.768 +0.273353 544.89 +0.273888 560.168 +0.274296 577.813 +0.274432 596.754 +0.274432 613.265 +0.274387 630.233 +0.274387 655.755 +0.274577 677.334 +0.274896 698.718 +0.275163 720.777 +0.275588 742.318 +0.275801 762.005 +0.275908 786.062 +0.275961 813.536 +0.275961 836.479 +0.275961 860.069 +0.275961 881.435 +0.275854 906.293 +0.275804 934.582 +0.275686 968.151 +0.27545 999.14 +0.275214 1031.12 +0.275095 1056.11 +0.274918 1083.07 +0.274682 1109.32 +0.274446 1141.94 +0.27421 1174.05 +0.273856 1210.1 +0.273561 1248.84 +0.273207 1287.19 +0.272819 1322.48 +0.272499 1357.16 +0.272086 1386.55 +0.271732 1413.01 +0.271437 1436.35 +0.271161 1464.13 +0.270905 1482.33 +0.270669 1501.13 +0.270374 1520.17 +0.269961 1543.33 +0.26943 1568.82 +0.268401 1596.21 +0.26707 1629.27 +0.265713 1664.55 +0.264474 1696.32 +0.26347 1724.34 +0.26228 1755.08 +0.261215 1786.94 +0.259937 1822.37 +0.259032 1849.4 +0.258155 1871.57 +0.257397 1894.63 +0.256576 1915.74 +0.255377 1947.28 +0.275058 1957.05 +0.275058 2160.44 +0.275058 2389.74 +0.275058 2507.09 +0.275058 2604.07 +0.275058 2715.63 +0.275058 2962.14 +0.275058 3276.53 +0.275058 3649.72 +0.275058 3981.03 diff --git a/instruments/IEX_dictionaries/Flux_Curves.txt b/instruments/IEX_dictionaries/Flux_Curves.txt new file mode 100644 index 0000000000000000000000000000000000000000..44cd178cd21cffb737b3276b8dd4c03c49b64db4 --- /dev/null +++ b/instruments/IEX_dictionaries/Flux_Curves.txt @@ -0,0 +1,420 @@ + +======= 20210614: + +----- flux_x: +{'MEG': {0: [[600.0, array([397.9252127 , 416.78300518, 438.75401384, 462.56121553, + 487.33355277, 512.03992257, 536.47780752, 561.22181765, + 587.97345224])], [2200.0, array([ 587.46430084, 612.03800702, 636.53676495, 661.0013687 , + 685.42558925, 709.81638238, 734.17842701, 758.50826907, + 782.81254347, 807.1746918 , 831.42021454, 855.65315484, + 879.96522503, 904.16448883, 928.3469178 , 952.59181238, + 976.74554652, 1000.88329295, 1025.00777645, 1049.12246101, + 1073.35612614, 1097.45284047, 1121.47889554, 1145.55371549, + 1169.76864907, 1193.82702085, 1217.8791137 , 1242.00838726, + 1266.04511137, 1290.0737721 , 1314.09595788, 1338.10961268, + 1362.11333886, 1386.11416896, 1410.19201899, 1434.17382119, + 1458.14541467, 1482.10703038, 1506.27933764, 1530.09117842, + 1554.0208766 , 1578.17227423, 1602.08283189, 1625.97586073, + 1649.85652425, 1673.71768583, 1697.65562303, 1721.48042527, + 1745.28391005, 1769.06551088, 1793.13420224, 1816.65473024, + 1840.68892848, 1864.02913999, 1887.67252086, 1911.65687838, + 1935.2466612 , 1958.79315798, 1982.42605617, 2005.90605258, + 2029.32530332, 2052.7073116 , 2076.03860369, 2099.44966785, + 2123.21651619])], [3000.0, array([2118.88592738, 2094.67127337, 2097.87802688, 2109.77514789, + 2130.39313876, 2163.66662705, 2189.35934478, 2221.72499406, + 2248.20562552, 2256.84132602, 2359.40737965, 2392.34274277, + 2423.07541114, 2450.14018859, 2476.00931755, 2499.40250005, + 2520.86957515, 2541.04013424, 2560.9167578 , 2580.30105169, + 2601.8955564 , 2621.08117798, 2644.24358248, 2667.75472794, + 2692.77716544, 2719.36695553, 2744.92823708, 2776.4914143 , + 2803.31259197, 2828.10579807, 2846.61432704, 2864.71720116, + 2879.30477412])]], 3: [[600.0, array([339.31458253, 364.54794409, 390.02020716, 415.15538078, + 439.78196471, 463.86684938, 487.40141206, 510.82411214, + 534.32704516, 558.5890677 , 584.4314343 ])], [2200.0, array([ 583.85491637, 608.81499149, 633.68951928, 658.48432773, + 683.2045639 , 707.85662166, 732.4439953 , 756.97608323, + 781.45489408, 805.88742599, 830.33418089, 854.68923824, + 879.00889942, 903.29590914, 927.55871675, 951.8703746 , + 976.09296782, 1000.29845478, 1024.4904691 , 1048.67313555, + 1072.96910378, 1097.14170657, 1121.2561395 , 1145.41952498, + 1169.71715113, 1193.88290664, 1218.05387362, 1242.16170005, + 1266.47759455, 1290.65910564, 1314.84857478, 1339.04363087, + 1363.2430578 , 1387.45091073, 1411.73012516, 1435.94765377, + 1460.16592507, 1484.39059798, 1508.61293853, 1532.90895389, + 1557.13491617, 1581.35890457, 1605.57415237, 1629.78473372, + 1653.98696636, 1678.17757444, 1702.42651407, 1726.5854458 , + 1750.7263016 , 1774.83965663, 1798.9234026 , 1823.06422641, + 1847.58574689, 1871.06680127, 1895.00617073, 1918.88866696, + 1943.04789622, 1966.84194618, 1990.6849626 , 2014.3510584 , + 2037.95499606, 2061.47241692, 2084.89921993, 2108.37921613, + 2131.62724662])], [3000.0, array([2113.09739181, 2101.26248454, 2101.00201702, 2116.36481428, + 2134.14351318, 2164.82867589, 2198.43413519, 2246.55922932, + 2242.07828211, 2261.5552126 , 2358.47938377, 2396.94367111, + 2429.21024934, 2457.21889939, 2484.25022238, 2508.55465704, + 2530.64512258, 2551.15606066, 2571.22309682, 2592.63610493, + 2610.32325931, 2631.02166373, 2654.026949 , 2677.31382516, + 2702.18421301, 2728.00476115, 2758.33419361, 2787.24733677, + 2814.29370729, 2840.93862939, 2862.5537757 , 2882.33819506, + 2890.82626685])]], 2: [[600.0, array([515.7 , 540.03, 565.01, 590.04])], [2200.0, array([ 588.59207188, 613.29232402, 637.97110398, 662.57340343, + 687.12474643, 711.68069367, 736.15669802, 760.59539356, + 785.00374666, 809.45542616, 833.80369103, 858.13744719, + 882.45492481, 906.75832891, 931.04756366, 955.30204659, + 979.66597315, 1003.93097636, 1028.18914249, 1052.44888328, + 1076.70535099, 1101.07613296, 1125.2948017 , 1149.5579364 , + 1173.82843999, 1198.22025055, 1222.50041089, 1246.7358534 , + 1271.02496099, 1295.44955514, 1319.75613835, 1344.07193302, + 1368.39361843, 1392.72133011, 1417.11685819, 1441.45452985, + 1465.79816705, 1490.14139828, 1514.4908973 , 1538.76153096, + 1563.24358479, 1587.5878241 , 1611.92900804, 1636.2580953 , + 1660.58143526, 1684.89426205, 1709.26181957, 1733.54473844, + 1757.80840349, 1782.04510776, 1806.26272635, 1830.52526946, + 1855.11862401, 1878.80412994, 1902.89256794, 1926.92958315, + 1950.91730234, 1974.85597288, 1998.83995273, 2022.67582641, + 2046.79085718, 2070.50604723, 2094.15235072, 2117.83647278, + 2141.33335819])], [3000.0, array([2068.39339727, 2077.8636703 , 2094.02808006, 2118.40161583, + 2145.85806279, 2174.7344634 , 2212.52150526, 2225.6200711 , + 2251.56338273, 2266.84943568, 2384.79661648, 2416.55012196, + 2445.06868447, 2473.34713435, 2499.22086174, 2523.07266553, + 2545.28394299, 2566.32851269, 2587.11746746, 2607.28060474, + 2629.28983705, 2648.85607613, 2671.91639575, 2694.99417755, + 2719.1471953 , 2744.18930277, 2771.18896115, 2799.39175188, + 2825.78922987, 2852.29306995, 2876.86567103, 2898.00801271, + 2913.84002181])]], 1: [[600.0, array([399.12769577, 418.49469008, 439.93258901, 462.56063504, + 486.01877885, 509.62295213, 533.37313034, 557.23457724, + 581.99495154])], [2200.0, array([ 581.59355677, 605.89662183, 630.18496435, 654.32224083, + 678.38395029, 702.37427034, 726.29886619, 750.28824129, + 774.10677729, 797.87626071, 821.70681147, 845.39726538, + 869.04951022, 892.84619441, 916.44653035, 939.94903762, + 963.69659782, 987.24278657, 1010.76750368, 1034.29215874, + 1058.03228309, 1081.54474546, 1105.17023542, 1128.69191982, + 1152.20880076, 1175.73840477, 1199.26713083, 1222.92123452, + 1246.47831526, 1270.04940305, 1293.63014763, 1317.4971171 , + 1341.11605231, 1364.75354241, 1388.23750626, 1412.17787973, + 1435.87743969, 1459.58965134, 1483.32486716, 1507.17021884, + 1530.94090009, 1554.7369362 , 1578.54733968, 1602.38124282, + 1626.23286351, 1650.0974754 , 1674.0585297 , 1697.95071727, + 1721.85985412, 1745.77791888, 1769.71195156, 1793.71858522, + 1817.66125846, 1841.88300235, 1865.266227 , 1889.49356226, + 1913.42993328, 1937.35252055, 1961.35057708, 1985.25116793, + 2009.14175642, 2033.00113326, 2056.84517489, 2080.74275066, + 2104.52957983])], [3000.0, array([2126.60650642, 2111.02986395, 2095.52361314, 2103.01317725, + 2117.35653637, 2138.97846781, 2171.96811167, 2197.28539696, + 2229.55355723, 2240.42411385, 2260.81739969, 2360.46405459, + 2390.47745703, 2421.07073067, 2448.34628975, 2475.05294358, + 2499.26962659, 2522.90806839, 2543.94307398, 2565.33881346, + 2586.75485829, 2609.79309622, 2631.63670032, 2655.72130668, + 2680.70358274, 2706.65302715, 2733.57080242, 2761.8581053 , + 2788.54893184, 2812.25398818, 2831.934257 , 2850.67753865, + 2873.4360033 ])]]}} +----- flux_y: +{'MEG': {0: [[600.0, array([1.05787759e+11, 1.17707922e+11, 1.35482529e+11, 1.52382368e+11, + 1.67291686e+11, 1.80713800e+11, 1.82555545e+11, 2.03366402e+11, + 2.12880296e+11])], [2200.0, array([2.12880296e+11, 2.37905861e+11, 2.50552640e+11, 2.66132706e+11, + 2.79974677e+11, 2.93171490e+11, 3.09433493e+11, 3.21608032e+11, + 3.40828814e+11, 3.60730671e+11, 3.75179629e+11, 3.88153187e+11, + 4.00435048e+11, 4.10313396e+11, 4.16605767e+11, 4.18895964e+11, + 4.21711594e+11, 4.22031212e+11, 4.19994750e+11, 4.15927026e+11, + 4.12828899e+11, 4.08474706e+11, 4.00982666e+11, 3.91273735e+11, + 3.82563920e+11, 3.73120381e+11, 3.62436303e+11, 3.48795347e+11, + 3.38034718e+11, 3.24032282e+11, 3.12350710e+11, 2.99049488e+11, + 2.87546355e+11, 2.74392320e+11, 2.64853782e+11, 2.53544384e+11, + 2.43384146e+11, 2.31829509e+11, 2.24403448e+11, 2.15608729e+11, + 2.07360940e+11, 2.01165608e+11, 1.94772927e+11, 1.88566115e+11, + 1.82083994e+11, 1.75964346e+11, 1.71887478e+11, 1.66570026e+11, + 1.61260525e+11, 1.55872471e+11, 1.50553701e+11, 1.45252365e+11, + 1.38620052e+11, 1.11920197e+11, 1.12047697e+11, 1.07967716e+11, + 1.05094052e+11, 9.42437887e+10, 8.94819732e+10, 8.48363550e+10, + 7.95215214e+10, 7.36009644e+10, 6.72478081e+10, 6.04803020e+10, + 5.34604689e+10])], [3000.0, array([5.34604689e+10, 4.52567478e+10, 3.61080071e+10, 2.67172138e+10, + 1.81294146e+10, 1.33547019e+10, 1.00884235e+10, 7.95095235e+09, + 6.42884437e+09, 4.67669952e+09, 2.77456794e+09, 3.14088543e+09, + 3.57381686e+09, 3.94598123e+09, 4.07784528e+09, 4.33204318e+09, + 4.52807170e+09, 4.51042435e+09, 4.76784357e+09, 4.75517272e+09, + 4.64595426e+09, 4.60829652e+09, 4.50253010e+09, 4.33441779e+09, + 3.90656852e+09, 3.57836039e+09, 2.99910776e+09, 3.03045417e+09, + 3.19268453e+09, 3.34728938e+09, 3.33070342e+09, 3.36400361e+09, + 5.73442182e+09])]], 3: [[600.0, array([4.26194666e+10, 5.02113296e+10, 6.28563167e+10, 7.40900175e+10, + 8.52105930e+10, 9.53337973e+10, 1.04697260e+11, 1.13238554e+11, + 1.16720766e+11, 1.26989816e+11, 1.36144750e+11])], [2200.0, array([1.36144750e+11, 1.45220456e+11, 1.52904435e+11, 1.62182699e+11, + 1.70570931e+11, 1.79279242e+11, 1.88992187e+11, 1.97313348e+11, + 2.12209239e+11, 2.25831745e+11, 2.36150779e+11, 2.48115866e+11, + 2.57968789e+11, 2.65646727e+11, 2.70867390e+11, 2.75979131e+11, + 2.79703808e+11, 2.81050361e+11, 2.79506556e+11, 2.77807800e+11, + 2.77603719e+11, 2.75688858e+11, 2.72086850e+11, 2.66469488e+11, + 2.60304120e+11, 2.55081867e+11, 2.49202286e+11, 2.40049376e+11, + 2.33330590e+11, 2.25266925e+11, 2.17411366e+11, 2.09451238e+11, + 2.01700613e+11, 1.94633671e+11, 1.87044546e+11, 1.80299832e+11, + 1.74394448e+11, 1.67489714e+11, 1.61395156e+11, 1.56868308e+11, + 1.51351214e+11, 1.46492178e+11, 1.41431542e+11, 1.37267000e+11, + 1.33422085e+11, 1.29209158e+11, 1.26536206e+11, 1.22667178e+11, + 1.19031164e+11, 1.15240656e+11, 1.12099739e+11, 1.08749902e+11, + 9.68819456e+10, 8.74304458e+10, 8.48436203e+10, 8.19361749e+10, + 7.94640394e+10, 7.13605866e+10, 6.82394353e+10, 6.47005439e+10, + 6.05950413e+10, 5.59464191e+10, 5.10585121e+10, 4.57918481e+10, + 3.96842463e+10])], [3000.0, array([3.96842463e+10, 3.34697346e+10, 2.61732973e+10, 1.82511792e+10, + 1.20362878e+10, 8.88774761e+09, 6.55333746e+09, 5.07778735e+09, + 3.92683060e+09, 2.93930526e+09, 2.31398666e+09, 2.59658141e+09, + 3.15765631e+09, 3.26555055e+09, 3.50716754e+09, 3.74699133e+09, + 3.77669439e+09, 3.90792502e+09, 4.05431641e+09, 3.96351040e+09, + 3.89511096e+09, 3.85718009e+09, 3.72656893e+09, 3.56037390e+09, + 3.27421252e+09, 2.95752202e+09, 2.42772309e+09, 2.73886766e+09, + 2.85841927e+09, 2.92548929e+09, 3.00301704e+09, 3.01355902e+09, + 2.97164566e+09])]], 2: [[600.0, array([1.10913268e+11, 1.09538115e+11, 1.23972721e+11, 1.36876724e+11])], [2200.0, array([1.36876724e+11, 1.43965903e+11, 1.50515394e+11, 1.59487447e+11, + 1.66847090e+11, 1.76924734e+11, 1.87158862e+11, 1.96033976e+11, + 2.09796344e+11, 2.23189756e+11, 2.34901279e+11, 2.46333705e+11, + 2.55652870e+11, 2.63836494e+11, 2.69829576e+11, 2.70637860e+11, + 2.76693732e+11, 2.78924982e+11, 2.79031200e+11, 2.78744482e+11, + 2.76010786e+11, 2.73882177e+11, 2.71542981e+11, 2.66333325e+11, + 2.59773806e+11, 2.54399855e+11, 2.48605481e+11, 2.40406280e+11, + 2.32438797e+11, 2.23853775e+11, 2.17488890e+11, 2.09470494e+11, + 2.01388563e+11, 1.94070216e+11, 1.85564867e+11, 1.79008230e+11, + 1.73360450e+11, 1.67047019e+11, 1.61405923e+11, 1.55075556e+11, + 1.49569456e+11, 1.45160841e+11, 1.41286583e+11, 1.37344916e+11, + 1.33592076e+11, 1.30030726e+11, 1.26376530e+11, 1.23069119e+11, + 1.19792566e+11, 1.16104036e+11, 1.12847429e+11, 1.09507179e+11, + 8.88825407e+10, 8.89769598e+10, 8.52909380e+10, 8.33048431e+10, + 7.66083439e+10, 7.15549682e+10, 6.84012663e+10, 6.40623751e+10, + 5.97367788e+10, 5.51697965e+10, 5.00078783e+10, 4.44022059e+10, + 3.77089629e+10])], [3000.0, array([3.77089629e+10, 3.04645147e+10, 2.28043971e+10, 1.59166460e+10, + 1.23502577e+10, 9.53106453e+09, 8.03925388e+09, 6.48456194e+09, + 5.18492746e+09, 3.91324899e+09, 2.63776009e+09, 3.11454045e+09, + 3.34659497e+09, 3.43487179e+09, 3.77158730e+09, 3.92648793e+09, + 4.03250148e+09, 4.03521484e+09, 4.09863656e+09, 4.02228363e+09, + 4.00315181e+09, 3.87934578e+09, 3.69188021e+09, 3.41015992e+09, + 3.06924870e+09, 2.53124188e+09, 2.66007286e+09, 2.87908337e+09, + 2.94754668e+09, 3.08473120e+09, 3.03460642e+09, 2.99270106e+09, + 3.00250068e+09])]], 1: [[600.0, array([1.05108554e+11, 1.18282887e+11, 1.35046175e+11, 1.51330849e+11, + 1.66019972e+11, 1.78844074e+11, 1.82884495e+11, 1.97647863e+11, + 2.15292313e+11])], [2200.0, array([2.15292313e+11, 2.26627262e+11, 2.40652409e+11, 2.54077210e+11, + 2.65995101e+11, 2.77464072e+11, 2.87582490e+11, 3.00861181e+11, + 3.16001893e+11, 3.35064937e+11, 3.50123125e+11, 3.67935776e+11, + 3.77972277e+11, 3.85369064e+11, 3.95585942e+11, 4.01874169e+11, + 4.08282206e+11, 4.11735896e+11, 4.11493161e+11, 4.07834385e+11, + 4.06566207e+11, 4.04077640e+11, 3.97410693e+11, 3.93198360e+11, + 3.86740051e+11, 3.77386633e+11, 3.65481439e+11, 3.54578045e+11, + 3.43019805e+11, 3.30948944e+11, 3.16987988e+11, 3.05093096e+11, + 2.93248244e+11, 2.80450123e+11, 2.67515364e+11, 2.58087230e+11, + 2.48283481e+11, 2.38695133e+11, 2.29814484e+11, 2.19119621e+11, + 2.11282903e+11, 2.04185516e+11, 1.96882906e+11, 1.90417358e+11, + 1.84085098e+11, 1.78580043e+11, 1.73660460e+11, 1.68740021e+11, + 1.63886087e+11, 1.58375206e+11, 1.53705220e+11, 1.49132098e+11, + 1.44140123e+11, 1.34420868e+11, 1.11622798e+11, 1.12207795e+11, + 1.07985457e+11, 1.05012207e+11, 9.40518882e+10, 8.94809007e+10, + 8.45472561e+10, 7.91587350e+10, 7.36436119e+10, 6.70525115e+10, + 5.99405928e+10])], [3000.0, array([5.99405928e+10, 5.24754540e+10, 4.42483842e+10, 3.49968960e+10, + 2.54918765e+10, 1.72310971e+10, 1.30912461e+10, 9.77428545e+09, + 7.74785109e+09, 5.74413495e+09, 3.24618508e+09, 2.86068986e+09, + 3.22057452e+09, 3.80254059e+09, 4.03703779e+09, 4.17626111e+09, + 4.51894980e+09, 4.68285098e+09, 4.69449299e+09, 4.84737016e+09, + 4.86243638e+09, 4.66702393e+09, 4.60609696e+09, 4.51325777e+09, + 4.31153332e+09, 3.92055690e+09, 3.48410919e+09, 2.91562362e+09, + 3.14866374e+09, 3.29959429e+09, 3.42849443e+09, 3.38018130e+09, + 5.81395146e+09])]]}} + +======= 20220209: + +----- flux_x: +{'MEG': {0: [[600.0, array([438.03258717, 462.65482499, 487.49723498, 512.05111655, + 536.40666766, 561.20416681, 587.97340183])], [2200.0, array([ 586.99536661, 611.68381298, 636.28152766, 660.81802496, + 685.29090924, 709.70701715, 734.074155 , 758.39043136, + 782.7422201 , 806.98204823, 831.16625417, 855.42579805, + 879.55969963, 903.66179552, 927.74094995, 951.88107715, + 975.91650598, 999.92545458, 1024.06339466, 1048.04173213, + 1072.01201878, 1095.96759787, 1120.00451662, 1143.9364645 , + 1167.86041953, 1191.77433917, 1215.68171887, 1239.67717505, + 1263.56868552, 1287.45623736, 1311.33879109, 1335.42554192, + 1359.29674203, 1383.16482553, 1407.12781317, 1430.9819778 , + 1454.83143035, 1478.67552902, 1502.5092139 , 1526.43368135, + 1550.24720756, 1574.05040372, 1598.11278261, 1621.89355503, + 1645.66295535, 1669.4127228 , 1693.24790282, 1716.95466147, + 1740.64470489, 1764.29955372, 1787.94097196, 1811.66024097, + 1835.21976439, 1858.7629108 , 1882.25216821, 1905.70556458, + 1929.56026928, 1952.93666632, 1976.40697173, 1999.65629865, + 2022.87196158, 2046.03425204, 2069.12895151, 2092.29392599, + 2115.87973751])], [2475.0, array([2110.93931759, 2140.69411263, 2132.70556261, 2112.51253682, + 2113.97429417, 2158.38716407, 2165.13279514, 2212.62413576, + 2240.8055932 , 2227.21289605, 2204.3417601 , 2383.49982987])], [2975.0, array([2362.98040538, 2387.05467179, 2411.92362366, 2436.48350106, + 2461.31328464, 2486.27851517, 2511.34192794, 2536.52974153, + 2561.88784628, 2587.19615709, 2613.09428076, 2638.60317633, + 2664.48386207, 2690.62824806, 2716.4206392 , 2742.25858016, + 2771.70456178, 2797.94804267, 2825.20192574, 2852.46881938, + 2880.15614113, 387.20987385, 412.32506828, 437.4288514 , + 462.50921593, 487.56030371, 512.57390995, 537.54910446, + 562.48315077, 587.36387809, 612.22155922, 637.02297211, + 661.77914357, 686.48492816, 711.14160104, 735.74865002, + 760.30337698, 784.86205337, 809.32159808, 833.71561815, + 858.14283389, 882.44634478, 906.69504152, 930.89123405, + 955.11415883, 979.20950863, 1003.24604679, 1027.38129729, + 1051.32155691, 1075.21391048, 1099.05619318, 1122.95176288, + 1146.69237913, 1170.38717396, 1194.02855823, 1217.62457021, + 1241.30307653, 1264.80965116, 1288.27027436, 1311.68686024, + 1335.36651672, 1358.7142621 , 1382.02325857, 1405.45464926, + 1428.68519327, 1451.89150841, 1475.07612402, 1498.22642364, + 1521.5019886 , 1544.59786061, 1567.67349535, 1590.73145658, + 1614.21216957, 1637.24261197, 1660.26935602, 1682.96669619, + 1706.44504467, 1729.45245878, 1752.44828931, 1775.45694003, + 1798.62773198, 1821.63450099, 1844.67272552, 1867.70576536, + 1890.76620799, 1914.37851585, 1937.49431088, 1960.26812197, + 1983.94858702, 2007.15748776, 2030.40789023, 2053.71712245, + 2077.18979434, 2100.58320742, 2124.48973348, 2148.45680058, + 2172.44839341, 2196.96232732, 2222.37518265, 2246.97861384, + 2272.00306088, 2297.5229657 , 2321.68514377, 2345.4164492 , + 2362.77189191, 2387.05338354, 2411.92446697, 2436.48243546, + 2461.31328464, 2486.27855268, 2511.30235281, 2536.53053247, + 2561.8896297 , 2587.19991062, 2613.09270119, 2638.95488381, + 2664.89337958, 2690.63836511, 2716.42008523, 2742.25737632, + 2771.7004586 , 2798.82957193, 2825.19515638, 2852.46671038, + 2880.15268441])]], 3: [[600.0, array([245.70314621, 266.39921187, 289.3296737 , 313.23069808, + 337.90258326, 363.07926928, 388.4417711 , 413.6429634 , + 438.5033378 , 463.00701554, 487.16183932, 510.94478568, + 534.575359 , 558.26215606, 582.40618968])], [2200.0, array([ 580.50747836, 605.94231918, 631.21214519, 656.32978201, + 681.30553135, 706.15111963, 730.87774339, 755.49579839, + 780.01620792, 804.44485061, 828.78032135, 853.05978114, + 877.37072432, 901.54013397, 925.664198 , 949.71069691, + 973.88429255, 997.91391215, 1021.92213646, 1045.91040778, + 1069.8949488 , 1093.86984261, 1117.93880965, 1141.91647415, + 1165.90376026, 1190.06451944, 1214.07750084, 1238.01360397, + 1262.21716751, 1286.26685924, 1310.34012349, 1334.43254467, + 1358.54397839, 1382.67074241, 1406.89280666, 1431.05042366, + 1455.23150158, 1479.4260245 , 1503.63019466, 1527.91234504, + 1552.13035559, 1576.35519517, 1600.57824787, 1624.79778207, + 1649.0046293 , 1673.19749995, 1697.43743366, 1721.58823212, + 1745.70366325, 1769.78117541, 1793.80729019, 1817.87643802, + 1842.07650138, 1865.64629507, 1889.42026997, 1913.09966963, + 1936.69647209, 1960.60278168, 1984.1432092 , 2007.43658114, + 2030.57947312, 2053.5963034 , 2076.44649051, 2099.30289988, + 2122.58135816])], [2475.0, array([2117.23123252, 2153.35413115, 2132.72115921, 2100.64603461, + 2147.58222984, 2144.48831723, 2172.94627753, 2226.80679681, + 2227.94892341, 2231.52546798, 2201.64583864, 2399.78359109])], [2975.0, array([2392.82575179, 2420.40214737, 2445.73677504, 2470.26216903, + 2492.41943627, 2515.50644172, 2537.18640159, 2558.89268794, + 2581.62113316, 2602.11377994, 2624.26342714, 2647.75215167, + 2670.99902687, 2694.75994359, 2719.31453274, 2744.22211476, + 2770.1757187 , 2796.82385546, 2822.08734838, 2848.73548372, + 2874.31967313])]], 1: [[600.0, array([397.49928026, 416.59117797, 437.75502876, 460.7487904 , + 484.4873963 , 508.07696465, 531.54790849, 555.11326022, + 580.14019296])], [2200.0, array([ 578.25702345, 602.92018229, 627.40834975, 651.74472795, + 675.95777791, 700.05316719, 724.03617543, 748.04362601, + 771.85774141, 795.58673806, 819.35097446, 842.9552623 , + 866.50136135, 890.18993581, 913.66040442, 937.00139197, + 960.61919285, 984.00205324, 1007.37519525, 1030.73952254, + 1054.09542433, 1077.7072342 , 1101.18936266, 1124.56235711, + 1147.95153063, 1171.34424786, 1194.75748241, 1218.30297692, + 1241.76209758, 1265.24046876, 1288.7441263 , 1312.54963551, + 1336.10596743, 1359.6955962 , 1383.40040289, 1407.040665 , + 1430.70220955, 1454.39627623, 1478.11015008, 1501.93843833, + 1525.69456023, 1549.47165445, 1573.26397076, 1597.07293224, + 1620.89310585, 1644.7129421 , 1668.61906751, 1692.43957137, + 1716.25300744, 1740.05868414, 1763.84315086, 1787.68906322, + 1811.42593621, 1835.13191294, 1858.78189739, 1882.39425322, + 1905.92968885, 1929.42329658, 1952.93377424, 1976.26197526, + 1999.50004327, 2023.20284914, 2046.27157676, 2068.73173275, + 2092.19189962])], [2475.0, array([2086.15797557, 2125.13190438, 2132.02677613, 2131.54510875, + 2124.63957102, 2132.44303561, 2175.8953685 , 2185.44908901, + 2229.38441511, 2223.55934688, 2198.54299606, 2375.02441307])], [2975.0, array([2366.8519058 , 2391.80737328, 2415.5657483 , 2440.2183244 , + 2463.01537074, 2485.96857319, 2509.55186283, 2531.34521011, + 2553.76827074, 2577.17521781, 2599.67448478, 2621.48429069, + 2645.38037613, 2668.63449885, 2692.36002612, 2716.65636879, + 2741.59278361, 2768.0522457 , 2796.32904733, 2823.12118386, + 2852.55683692])]]}} +----- flux_y: +{'MEG': {0: [[600.0, array([3.01312333e+11, 3.40265766e+11, 3.70456821e+11, 3.93344627e+11, + 3.97257930e+11, 4.37994557e+11, 4.58576447e+11])], [2200.0, array([4.58576447e+11, 5.12218889e+11, 5.42509990e+11, 5.77778252e+11, + 6.05706695e+11, 6.36302486e+11, 6.68436411e+11, 6.83162188e+11, + 7.28593213e+11, 7.64930485e+11, 7.90092679e+11, 8.23576866e+11, + 8.49740651e+11, 8.65802625e+11, 8.74418092e+11, 8.86168311e+11, + 8.91978426e+11, 8.84623409e+11, 8.80824228e+11, 8.77492591e+11, + 8.67633235e+11, 8.49045478e+11, 8.33678648e+11, 8.15049828e+11, + 7.92640615e+11, 7.71122498e+11, 7.43453155e+11, 7.17233599e+11, + 6.94932438e+11, 6.68330486e+11, 6.41732849e+11, 6.19328298e+11, + 5.97861798e+11, 5.76654342e+11, 5.54113369e+11, 5.34085931e+11, + 5.15622021e+11, 4.96274742e+11, 4.78335925e+11, 4.62317413e+11, + 4.48622747e+11, 4.32194157e+11, 4.16324281e+11, 4.07563322e+11, + 3.96628060e+11, 3.86306341e+11, 3.74159451e+11, 3.65979513e+11, + 3.57884262e+11, 3.47333117e+11, 3.37447501e+11, 3.26879714e+11, + 3.17286175e+11, 2.90156947e+11, 2.84995734e+11, 2.74806075e+11, + 2.69672510e+11, 2.50471919e+11, 2.29897265e+11, 2.19380047e+11, + 2.06559210e+11, 1.94089222e+11, 1.78416211e+11, 1.62248648e+11, + 1.45650327e+11])], [2475.0, array([1.45650327e+11, 1.26596016e+11, 1.04588347e+11, 8.20507981e+10, + 6.12999037e+10, 4.71199361e+10, 3.50847953e+10, 2.67181351e+10, + 2.08936638e+10, 1.57950091e+10, 9.05374714e+09, 6.08442340e+09])], [2975.0, array([6.08442340e+09, 7.19094527e+09, 8.25079545e+09, 8.44888698e+09, + 9.06227825e+09, 9.58047092e+09, 9.40492498e+09, 9.80104019e+09, + 9.88020032e+09, 9.61358007e+09, 9.48197037e+09, 9.19598506e+09, + 8.81565454e+09, 8.19827176e+09, 7.37681248e+09, 6.37423327e+09, + 5.59790936e+09, 6.07332980e+09, 6.28561669e+09, 6.40094099e+09, + 6.56188801e+09, 2.48217214e+11, 2.72519725e+11, 3.03110560e+11, + 3.43307210e+11, 3.72939665e+11, 3.97302077e+11, 4.02407311e+11, + 4.43043354e+11, 4.64074444e+11, 5.15662388e+11, 5.44717227e+11, + 5.79845473e+11, 6.10547654e+11, 6.39655097e+11, 6.72250363e+11, + 6.89580944e+11, 7.28871205e+11, 7.69815849e+11, 7.95373701e+11, + 8.25347411e+11, 8.52038472e+11, 8.68788178e+11, 8.73983420e+11, + 8.86389619e+11, 8.96043849e+11, 8.89368539e+11, 8.85819238e+11, + 8.77367740e+11, 8.66802781e+11, 8.54151237e+11, 8.37505446e+11, + 8.18655876e+11, 7.96576542e+11, 7.69411253e+11, 7.40339386e+11, + 7.21676288e+11, 6.97940919e+11, 6.69952441e+11, 6.42615931e+11, + 6.19128245e+11, 5.95336912e+11, 5.74709809e+11, 5.51033742e+11, + 5.33193028e+11, 5.13845211e+11, 4.95922432e+11, 4.74165934e+11, + 4.61709216e+11, 4.45577308e+11, 4.34574818e+11, 4.19781277e+11, + 4.06643837e+11, 3.96689089e+11, 3.85667240e+11, 3.73359110e+11, + 3.66505278e+11, 3.58393329e+11, 3.47431594e+11, 3.36762283e+11, + 3.28764936e+11, 3.17820695e+11, 2.90160125e+11, 2.84443582e+11, + 2.75052596e+11, 2.67037537e+11, 2.49612014e+11, 2.29085024e+11, + 2.20185106e+11, 2.06453663e+11, 1.94117024e+11, 1.77512282e+11, + 1.62703700e+11, 1.45132937e+11, 1.26522769e+11, 1.04155499e+11, + 8.17607509e+10, 6.06845730e+10, 4.64710516e+10, 3.52448589e+10, + 2.64186929e+10, 2.09555761e+10, 1.57491587e+10, 8.99071215e+09, + 6.23071224e+09, 7.20220380e+09, 8.07540715e+09, 8.42402104e+09, + 8.83300710e+09, 9.62339407e+09, 9.35840347e+09, 9.72441179e+09, + 9.78617741e+09, 9.61653958e+09, 9.43267558e+09, 9.17566396e+09, + 8.81640062e+09, 8.16313522e+09, 7.37684408e+09, 6.40673297e+09, + 5.68649187e+09, 6.09167694e+09, 6.57881056e+09, 6.50552088e+09, + 6.52796413e+09])]], 3: [[600.0, array([5.04045805e+10, 6.37327482e+10, 7.29061901e+10, 8.79213815e+10, + 9.75102433e+10, 1.15677518e+11, 1.45161063e+11, 1.70441397e+11, + 1.91672934e+11, 2.14522180e+11, 2.33506935e+11, 2.50808705e+11, + 2.56840532e+11, 2.76338369e+11, 3.02656912e+11])], [2200.0, array([3.02656912e+11, 3.24508283e+11, 3.44977530e+11, 3.68090355e+11, + 3.85308995e+11, 4.06693086e+11, 4.26793834e+11, 4.43425099e+11, + 4.68537526e+11, 4.93748570e+11, 5.18687448e+11, 5.37442575e+11, + 5.56569323e+11, 5.70291251e+11, 5.80763008e+11, 5.84440453e+11, + 5.94704040e+11, 5.97106493e+11, 5.97092917e+11, 5.91043542e+11, + 5.84491305e+11, 5.74155847e+11, 5.73229164e+11, 5.60936405e+11, + 5.44372600e+11, 5.31828291e+11, 5.19139629e+11, 5.04731449e+11, + 4.87333329e+11, 4.72508262e+11, 4.55922248e+11, 4.43777636e+11, + 4.28914096e+11, 4.11575500e+11, 3.97535587e+11, 3.84399175e+11, + 3.72893795e+11, 3.61565749e+11, 3.49294136e+11, 3.39616970e+11, + 3.29665305e+11, 3.19611471e+11, 3.10620812e+11, 3.04493608e+11, + 2.96910245e+11, 2.87193997e+11, 2.82319388e+11, 2.76353431e+11, + 2.69154055e+11, 2.62799191e+11, 2.54629528e+11, 2.48730719e+11, + 2.40078361e+11, 2.23853895e+11, 2.18775319e+11, 2.13180629e+11, + 2.06524468e+11, 1.86596635e+11, 1.80342113e+11, 1.72207080e+11, + 1.62511611e+11, 1.51699296e+11, 1.39454880e+11, 1.27253952e+11, + 1.13662818e+11])], [2475.0, array([1.13662818e+11, 9.72953942e+10, 7.96293347e+10, 6.07911131e+10, + 4.46989036e+10, 3.41079804e+10, 2.53033491e+10, 1.89330278e+10, + 1.46384848e+10, 1.09404385e+10, 6.08872756e+09, 5.46307689e+09])], [2975.0, array([5.46307689e+09, 6.56894775e+09, 1.34042406e+10, 7.43765864e+09, + 7.72193414e+09, 8.13273587e+09, 8.01109589e+09, 8.36968615e+09, + 8.38008114e+09, 8.16854565e+09, 8.17328864e+09, 7.85232015e+09, + 7.51332936e+09, 6.83204168e+09, 6.10587790e+09, 5.12255216e+09, + 5.26742499e+09, 5.58109741e+09, 5.63882089e+09, 5.78979138e+09, + 5.72800860e+09])]], 1: [[600.0, array([2.48392273e+11, 2.76221468e+11, 3.10748237e+11, 3.46460102e+11, + 3.78164129e+11, 4.00814031e+11, 4.13038975e+11, 4.36756596e+11, + 4.74239690e+11])], [2200.0, array([4.74239690e+11, 5.12246740e+11, 5.42931191e+11, 5.71196646e+11, + 5.96670690e+11, 6.22461576e+11, 6.49151746e+11, 6.73747513e+11, + 6.95450639e+11, 7.37088595e+11, 7.69044892e+11, 8.02285698e+11, + 8.24713276e+11, 8.44231600e+11, 8.56843291e+11, 8.63902338e+11, + 8.74203971e+11, 8.80817347e+11, 8.79106614e+11, 8.73677011e+11, + 8.63963273e+11, 8.55727882e+11, 8.40978085e+11, 8.28163750e+11, + 8.13594557e+11, 7.93658203e+11, 7.69701292e+11, 7.46490133e+11, + 7.21967341e+11, 6.93087889e+11, 6.67643362e+11, 6.48221689e+11, + 6.21211923e+11, 5.96867648e+11, 5.75033489e+11, 5.54876514e+11, + 5.33924161e+11, 5.14481283e+11, 4.93566915e+11, 4.75629654e+11, + 4.59443303e+11, 4.45007280e+11, 4.31492869e+11, 4.19059182e+11, + 4.06201734e+11, 3.95859290e+11, 3.83780492e+11, 3.77003970e+11, + 3.68468308e+11, 3.57011143e+11, 3.48419887e+11, 3.39298361e+11, + 3.30117801e+11, 3.21591557e+11, 2.93771520e+11, 2.86908482e+11, + 2.78319927e+11, 2.70990918e+11, 2.50388292e+11, 2.34741083e+11, + 2.22338719e+11, 2.10333511e+11, 1.96900035e+11, 1.80870211e+11, + 1.65859923e+11])], [2475.0, array([1.65859923e+11, 1.47393577e+11, 1.27897707e+11, 1.05124520e+11, + 8.29131224e+10, 6.11758992e+10, 4.70577255e+10, 3.52864162e+10, + 2.66327994e+10, 2.00556481e+10, 1.17757043e+10, 5.47905131e+09])], [2975.0, array([5.47905131e+09, 6.36038874e+09, 7.30733041e+09, 8.27980811e+09, + 8.61885535e+09, 9.04591445e+09, 9.61420872e+09, 9.48332641e+09, + 9.83228526e+09, 9.92841482e+09, 9.55612221e+09, 9.43993368e+09, + 9.16339293e+09, 8.72757672e+09, 8.04649052e+09, 7.35985215e+09, + 6.08617376e+09, 5.94104124e+09, 6.37727729e+09, 6.47862907e+09, + 6.51092118e+09])]]}} diff --git a/instruments/IEX_dictionaries/M0M1_positions.py b/instruments/IEX_dictionaries/M0M1_positions.py new file mode 100644 index 0000000000000000000000000000000000000000..c00c6d4dabd1eb824f2091ed2984acdfc7f294d7 --- /dev/null +++ b/instruments/IEX_dictionaries/M0M1_positions.py @@ -0,0 +1,3 @@ +M0M1_Pos['default']={0:'-0.400/-22.5/0/0/0.000/0.0000',1:'0.400/-21.5/0/0/8.400/2.800'} +M0M1_Pos['2019_1']= {0:'0.3010/-22.5/0/0/-0.151/0.0393',1:'1.449/-21.5/0/0/8.339/2.700'} +M0M1_Pos['2019_2']= {0:'-0.400/-22.5/0/0/ 0.000/0.000',1:'0.400 /-21.5/0/0/8.436/3.000'} \ No newline at end of file diff --git a/instruments/IEX_dictionaries/calibrationToFix.txt b/instruments/IEX_dictionaries/calibrationToFix.txt new file mode 100644 index 0000000000000000000000000000000000000000..0dd679657038047f0c0d656f727d48dc602c5b31 --- /dev/null +++ b/instruments/IEX_dictionaries/calibrationToFix.txt @@ -0,0 +1,11 @@ + +======= 20211108: +{'HEG': {0: [[600, [-6635.813431810828, 53.075898114105726, -0.15253171108859886, 0.00019792480095656869, -9.598209896301075e-08]], [3000, [46.600135556920925, 0.8412063733137993, 0.00023492720237763438, -1.2593652551917328e-07, 2.5435326557098538e-11]]], 3: [[400, [1051.452570904546, -13.099314837713008, 0.06939879665006896, -0.00014784669111041307, 1.155031075284652e-07]], [600, [2782.786054275039, -21.145755715684032, 0.06554921272398154, -8.534237586539917e-05, 4.134061079155964e-08]], [3000, [87.23060103156234, 0.7171860430279529, 0.0003793918782124725, -1.9605428816497513e-07, 3.6770897051532086e-11]]], 2: [[590, [-12422.076427583952, 100.54771064816772, -0.29845648627641835, 0.00039688772576782855, -1.97439876026206e-07]], [3000, [-33.02431482418943, 1.1302724323594304, -0.00013479679549416608, 7.22272393581498e-08, -1.373032035520199e-11]]], 1: [[600.0, [-4765.159827798981, 39.08508762376964, -0.11372474852884872, 0.00015063687981483728, -7.456557379431018e-08]], [3000, [84.53488099145231, 0.7066601865786498, 0.00043283422433330405, -2.2608518373215027e-07, 4.202604094132355e-11]]]}, +{'MEG': { +0: [[600.0, [-5940.176848239725, 48.30636368582396, -0.14075467796987542, 0.00018579017325356665, -9.17653113254405e-08]], [2200.0, [20.344164869431648, 0.942351240250947, 0.00010121556917763097, -4.949527030585497e-08, 9.675448511744878e-12]], [3000.0, [365297.2627682823, -552.812440238765, 0.3141479258407871, -7.90104068928604e-05, 7.434922126836773e-09]]], + +3: [[600.0, [-634.0261758446517, 7.262520018224911, -0.022419323576083252, 3.49681129089603e-05, -1.999932008653819e-08]], [2200.0, [58.93716149881088, 0.8198484295498225, 0.0002490011121555607, -1.2688431897796926e-07, 2.37752539333468e-11]], [3000.0, [112089.95145715227, -159.53263761672966, 0.08554887203588527, -2.0076278347329386e-05, 1.749084702165079e-09]]], + +2: [[600.0, [-604.5006436697821, 3.0530278050672597, 0.0006285185258970196, -7.876285868395855e-06, 6.618688516815772e-09]], [2200.0, [34.67137980324179, 0.8848938354598829, 0.00017775770898386393, -9.469862981232054e-08, 1.8324158207531115e-11]], [3000.0, [409195.45122128195, -612.7658620540126, 0.3445915452908224, -8.582156181499232e-05, 8.000918394998031e-09]]], + +1: [[600.0, [-3677.005333394253, 29.772255818860682, -0.0843978889369737, 0.00011023738262993015, -5.399238835077749e-08]], [2200.0, [46.243321909129264, 0.8454613578261618, 0.00024604317670495594, -1.1956387793694198e-07, 2.0350719268411266e-11]], [3000.0, [-99353.40775512981, 160.7507495025834, -0.0962536588691068, 2.5766240641565706e-05, -2.583875704169572e-09]]]} \ No newline at end of file diff --git a/instruments/IEX_dictionaries/mono_parameters.txt b/instruments/IEX_dictionaries/mono_parameters.txt new file mode 100644 index 0000000000000000000000000000000000000000..4acfebd699e47f2eb5e60e16f4138b71208680e0 --- /dev/null +++ b/instruments/IEX_dictionaries/mono_parameters.txt @@ -0,0 +1,10 @@ + MonoParm["20160822"]={ + 'Au':[0.3237,-12.04],'Si':[0.3237,-2.04],'Carbon':[0.3237,7.96], + 'MEG_Imp':[0.7290,4.872,1200.0,-7.34e-05],'HEG_JY':[0.7302,69.0,2400.0,-5.58e-05],'MEG_JY':[0.8,131.624,1200.0,0.0]} + MonoParm["20190719_4"]={ + 'Au':[0.3266,-12.04],'Si':[0.3237,-2.04],'Carbon':[0.3237,7.96], + 'MEG_Imp':[0.7306,4.872,1200.0,-7.15e-05],'HEG_JY':[0.7278,69.0,2400.0,-5.535e-05],'MEG_JY':[0.8,131.624,1200.0,0.0]} + MonoParm['20191018']= { + 'Au':[0.3203,-12.04],'Si':[0.3237,-2.04],'Carbon':[0.3237,7.96], + 'MEG_Imp':[0.7306,4.872,1200.0,-7.15e-05],'HEG_JY':[0.7123,69.0,2400.0,-5.535e-05],'MEG_JY':[0.7306,131.624,1200.0,0.0],} + \ No newline at end of file diff --git a/instruments/IEX_endstations.py b/instruments/IEX_endstations.py new file mode 100644 index 0000000000000000000000000000000000000000..d6d823ce56edf9ccf32e800012f0ab2afcbcbf92 --- /dev/null +++ b/instruments/IEX_endstations.py @@ -0,0 +1,135 @@ +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. +""" + +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 + + global mda + mda = mda_scanRecord + + global Motors + + + + 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/instruments/Kappa.py b/instruments/Kappa.py new file mode 100644 index 0000000000000000000000000000000000000000..92a8d4af274aa01a18664fe1045314bc7bd0cc18 --- /dev/null +++ b/instruments/Kappa.py @@ -0,0 +1,1107 @@ +import numpy as np +from time import sleep +from math import floor + +from epics import caget, caput,PV + +from .files_and_folders import check_run,make_user_folders,folder_mda +from .userCalcs import userStringSeq_clear, userStringSeq_pvs +from .logfile import logfile_name_set,logfile_header +from .utilities import * +from .conversions_constants import * +from .scanRecord import * +from .current_amplifiers import * +from .slits import slit3C_get +from .gate_valves import valve_close, branch_valves +from .shutters import branch_shutter_close +from .IEX_endstations import Endstation +from .xrays import * +from .Kappa_det import * +from .spec_stuff import folders_spec +from .Motors import * + + +############################################################################# +def __main__(set_folders=False,reset=False,**kwargs): + """ + kwargs: + set_folders: sets the mda and EA folders; default => False + xrays: sets global variable; default => True + """ + kwargs.setdefault('scan_ioc','29idKappa:') + kwargs.setdefault('xrays',True) + kwargs.setdefault('BL_mode','user') + + #scan + mda_scanRecord = ScanRecord(kwargs['scan_ioc'],Kappa_detector_dictionary,Kappa_trigger_dictionary,Kappa_scan_before_sequence,Kappa_scan_after_sequence,mda_scanRecord) + + #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': + 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)") + + Kappa_cts(kwargs['cts'],verbose=False) + if kwargs['execute']: + mda.go(**kwargs) + + #clean up after scan + mda.table_reset_after(**kwargs) + Kappa_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 + + 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 + kth_val,kth_rbv,kth_spmg,kth_pv = Kappa_motor_dictionary['kth'] + tth_val,tth_rbv,tth_spmg,tth_pv = Kappa_motor_dictionary['tth'] + + kwargs.update("positioner_num",1) + BL.mda.fillin(kth_val,kth_rbv,kth_val,kth_rbv,**kwargs) + + kwargs.update("positioner_num",2) + BL.mda.fillin(tth_val,tth_rbv,tth_val,tth_rbv,**kwargs) + + Kappa_cts(kwargs['cts'],verbose=False) + if kwargs['execute']: + BL.mda.go(**kwargs) + + #clean up after scan + Kappa_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") + + + Kappa_cts(kwargs['cts'],verbose=False,**kwargs) + if kwargs['execute']: + BL.mda.go(**kwargs) + + #clean up after scan + BL.mda.table_reset_after() + Kappa_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/instruments/Kappa_Euler.py b/instruments/Kappa_Euler.py new file mode 100644 index 0000000000000000000000000000000000000000..84bf299ebf20ded4f024f3a2fa4aad71f63a3da5 --- /dev/null +++ b/instruments/Kappa_Euler.py @@ -0,0 +1,118 @@ +from epics import caget, caput + +from 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",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 + scanIOC='Kappa' + ClearCalcOut(scanIOC,n) + pvcal="29id"+scanIOC+":userCalcOut"+str(n) + caput(pvcal+".DESC","EtoK_kap") + caput(pvcal+".INPA","29idKappa:userCalcOut1.VAL CP NMS") #A=th + caput(pvcal+".INPB","29idKappa:userCalcOut2.VAL CP NMS") #B=chi + caput(pvcal+".INPC","29idKappa:userCalcOut3.VAL CP NMS") #C=phi + caput(pvcal+".D",3.141592653589793) + caput(pvcal+".E",180) + caput(pvcal+".F",50) + caput(pvcal+".CALC$","((2*ASIN(SIN(B*D/E/2.0) / SIN(F*D/E))))*E/D") + caput(pvcal+".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/instruments/Kappa_det.py b/instruments/Kappa_det.py new file mode 100644 index 0000000000000000000000000000000000000000..977c1d54f2473961d5d505f539e5685633270edf --- /dev/null +++ b/instruments/Kappa_det.py @@ -0,0 +1,73 @@ +from time import sleep +from epics import caget, caput + +from .IEX_endstations import Motors + +############################################################################################################## +################################ Kappa detector class ############################## +############################################################################################################## +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/instruments/Kappa_optimization.py b/instruments/Kappa_optimization.py new file mode 100644 index 0000000000000000000000000000000000000000..8e74eac13ead1c8c998e8cab9f2274e2b2d788ef --- /dev/null +++ b/instruments/Kappa_optimization.py @@ -0,0 +1,100 @@ +import matplotlib.pyplot as plt + +from epics import caget,caput +from .Kappa import * +from .Motors import * + +from IEX_plotting_and_analysis.IEX_plotting_and_analysis.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/instruments/Lakeshore_335.py b/instruments/Lakeshore_335.py new file mode 100644 index 0000000000000000000000000000000000000000..080c578697c5042e8d578d2805c132f837261847 --- /dev/null +++ b/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 .IEX_endstations import * +from .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/instruments/Motors.py b/instruments/Motors.py new file mode 100644 index 0000000000000000000000000000000000000000..54257bedd8e2130c8a61375dacbbc54225280023 --- /dev/null +++ b/instruments/Motors.py @@ -0,0 +1,232 @@ +import time +from math import floor + +from epics import caget, caput + +from 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): + """ + 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) + mda.fillin(val_pv,rbv_pv,abs_start,abs_stop,step,**kwargs) + + if kwargs['execute']: + 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) + mda.fillin_2D(inner_loop_list,outer_loop_list, + outer_scan_dim=kwargs['outer_scan_dim'],**kwargs) + + if kwargs['execute']: + mda.go(**kwargs) + + + + diff --git a/instruments/Scienta.py b/instruments/Scienta.py new file mode 100644 index 0000000000000000000000000000000000000000..f493664c17207aa84874be71aee4433e459c25f8 --- /dev/null +++ b/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/instruments/VLS_PGM.py b/instruments/VLS_PGM.py new file mode 100644 index 0000000000000000000000000000000000000000..49f0cd87a1900133d5dce7b5104a5eb605a6ebe0 --- /dev/null +++ b/instruments/VLS_PGM.py @@ -0,0 +1,576 @@ +""" +functions used for the mono +""" + +import time +import numpy as np + + +from epics import caget,caput +from .IEX_endstations import * +from .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_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_state=caget('29idmonoGRT_TYPE_MON') + MIR_state=caget('29idmonoMIR_TYPE_MON') + GRT_names = mono_grating_names() + MIR_names = mono_mirror_names() + + ext=["C","D","E","F","G","H","I","J","K","L"] + + vals={ + 'grating_state':GRT_state, + 'mirror_state':MIR_state, + 'GRT':GRT_names[GRT_state], + 'MIR':MIR_names[MIR_state], + 'ENERGY_MON':caget("29idmono:ENERGY_MON"), + 'ENERGY_SP':caget("29idmono:ENERGY_SP"), + 'GRT_DENSITY':caget("29idmono:GRT_DENSITY"), + 'GRT_Offset':caget('29idmonoGRT:P_OFFSETS.'+ext[GRT_state]), + 'GRT_b2':caget('29idmonoGRT:B2_CALC.'+ext[GRT_state]), + 'GRT_Tx':caget('29idmonoGRT:X_DEF_POS.'+ext[GRT_state]), + 'GRT_LD':caget('29idmonoGRT:TYPE_CALC.'+ext[GRT_state]), + 'TUN0':caget('29idmonoGRT:TUN0_CALC.'+ext[GRT_state]), + 'TUN1':caget('29idmonoGRT:TUN1_CALC.'+ext[GRT_state]), + 'TUN2':caget('29idmonoGRT:TUN2_CALC.'+ext[GRT_state]), + 'TUN3':caget('29idmonoGRT:TUN3_CALC.'+ext[GRT_state]), + 'GRT_P_status':caget("29idmonoGRT:P_AXIS_STS"), + 'MIR_P_status':caget("29idmonoMIR:P_AXIS_STS"), + 'GRT_X_status':caget("29idmonoGRT:X_AXIS_STS"), + 'MIR_X_status':caget("29idmonoMIR:X_AXIS_STS"), + 'MIR_Offset':caget('29idmonoMIR:P_OFFSETS.'+ext[MIR_state]), + 'MIR_Tx':caget('29idmonoMIR:X_DEF_POS.'+ext[MIR_state]), + '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_MON'] + + +def mono_energy_set(hv_eV,verbose=True): + """ + sets the mono energy + + Previously: SetMono + """ + hv_min, hv_max = mono_energy_range() + if hv_min <= hv_eV <= hv_max: + caput("29idmono:ENERGY_SP",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("29idmono:ENERGY_SP",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 = "29idmono:ENERGY_SP" + rbv_pv = "29idmono:ENERGY_MON" + return val_pv, rbv_pv + +def mono_status_get(): + """ + returns the status of the mirror (GRT * MIR) + 1 = ready + + + Previously Mono_Status + """ + pvs = mono_get_all_extended()['ENERGY_MON'] + MIR_P_status = pvs['MIR_P_status'] + GRT_P_status = pvs['GRT_P_status'] + MIR_X_status = pvs['MIR_P_status'] + GRT_X_status = pvs['GRT_P_status'] + MIR_status = MIR_P_status * MIR_X_status + GRT_status = GRT_P_status * GRT_X_status + return MIR_status*GRT_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: + caput("29idmonoGRT_TYPE_SP",grating_state,wait=True,timeout=18000) # HEG + caput("29idb:gr: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) + 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['TUN0'] + TUN1 = d['TUN1'] + TUN2 = d['TUN2'] + TUN3 = d['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_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)): + mir=mirList[i] + offset=caget("29idmonoMIR:P_OFFSETS."+pvList[i]) + position=caget("29idmonoMIR:X_DEF_POS."+pvList[i]) + txt+="\'"+mir+"\':["+str(offset)+","+str(position)+"]," + + #GRT + txt+="\n\t" + for i in range(0,len(grtList)): + grt=grtList[i] + offset=caget("29idmonoGRT:P_OFFSETS."+pvList[i]) + position=caget("29idmonoGRT:X_DEF_POS."+pvList[i]) + spacing=caget("29idmonoGRT:TYPE_CALC."+pvList[i]) + b2=caget("29idmonoGRT:B2_CALC."+pvList[i]) + txt+="\'"+grt+"\':["+str(offset)+","+str(position)+","+str(spacing)+","+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(mda,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() + mda.fillin(val_pv,rbv_pv,hv_start,hv_stop,hv_step,**kwargs) + + #mono needs to stay and have a longer settling time + mda.positioner_after_scan("STAY") + + +def mono_scan_fillin_table(mda,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() + mda.fillin.table(val_pv,rbv_pv,hv_array,**kwargs) + + #mono needs to stay and have a longer settling time + mda.positioner_settling_time(kwargs['positioner_settling_time']) + mda.positioner_after_scan("STAY") + +def mono_scan_after(mda,**kwargs): + """ + resets mda after scanning the mono + """ + after_scan_pv = mda.default_after_scan_seq + caput(after_scan_pv+".PROC",1) + mda.positioner_after_scan("PRIOR POS") + +def mono_grating_offset_get(ext): + """ + gets the grating offset for the grating specified by ext + ext in ['C','D','E'] => mono_grating_names() + """ + return caget("29idmonoGRT:P_OFFSETS."+ext) + +def mono_grating_offset_set(ext,val): + """ + sets the grating offset for the grating specified by ext + ext in ['C','D','E'] => mono_grating_names() + """ + return caput("29idmonoGRT:P_OFFSETS."+ext,val) + +def mono_mirror_offset_get(ext): + """ + gets the grating offset for the grating specified by ext + ext in ['C','D','E'] => mono_mirror_names() + """ + return caget("29idmonoMIR:P_OFFSETS."+ext) + +def mono_mir_offset_set(ext,val): + """ + sets the grating offset for the grating specified by ext + ext in ['C','D','E'] => mono_mirror_names() + """ + return caput("29idmonoMIR:P_OFFSETS."+ext,val) + + +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 + """ + + energy_sp = mono_energy_get() + mirror_offset_old = mono_mirror_offset_get(current_mirror_ext) + + grating_offsets=[] + for ext in ['C','D','E']: + grating_offsets.append(mono_mirror_offset_get(ext)) + mir_grt_offsets = mirror_offset_old-np.array(grating_offsets) # list of MIR-GRT for all 3 gratings + + current_mirror_ext = ext[mono_get_all_extended(verbose=False)['mirror_state']] + mono_mir_offset_set(current_mirror_ext,mirror_offset) + + for ext,i in enumerate(['C','D','E']): + mono_grating_offset_set(ext,mirror_offset - mir_grt_offsets[i]) + + time.sleep (1) + mono_energy_set(energy_sp) + mono_get_all_extended(verbose=True) + +############################################################################################################## +################################ 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(mda,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. + + 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_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) + ev=caget("29idmono:ENERGY_SP") + caput("29idmono:ENERGY_SP", 440) diff --git a/instruments/backups.py b/instruments/backups.py new file mode 100644 index 0000000000000000000000000000000000000000..05d3c3aa0baf555372cbc61939de622a85ec0e5a --- /dev/null +++ b/instruments/backups.py @@ -0,0 +1,339 @@ +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/instruments/bakeout.py b/instruments/bakeout.py new file mode 100644 index 0000000000000000000000000000000000000000..979393cd2c9225aaed88070ec53faeab737a9896 --- /dev/null +++ b/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 .files_and_folders import get_next_fileNumber, check_run +from .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/instruments/beamline.py b/instruments/beamline.py new file mode 100644 index 0000000000000000000000000000000000000000..1927eab176f93e355c22d49d37c3d54e42946437 --- /dev/null +++ b/instruments/beamline.py @@ -0,0 +1,101 @@ + +""" +short name for functions used with or without x-rays + +""" + +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 * + + +############################################################################################################## +########################### Scan stuff ###################### +############################################################################################################## +def scan_fillin(VAL,RBV,start,stop,steps_points,**kwargs): + """ + fills in the scan record for the curretn beamline ioc + """ + 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 + """ + 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 + """ + mda.go(verbose=True,**kwargs) + + +def last_mda(): + """ + returns the last mda file number in the ioc defined by BL_ioc + Previously: LastMDA + """ + filenum = 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/instruments/cameras.py b/instruments/cameras.py new file mode 100644 index 0000000000000000000000000000000000000000..a217499e3d4c83e66e5d189441669b946d1f8358 --- /dev/null +++ b/instruments/cameras.py @@ -0,0 +1,45 @@ + +from epics import caget, caput +from .userCalcs import userStringSeq_clear + +def Cam_SaveStrSeq(camNUM): + ioc="b" + pvCam="29id_ps"+str(camNUM)+":" + pvIOC="29id"+ioc+":" + userStringSeq_clear("29idb:",2) + caput(pvIOC+"userStringSeq2.DESC","Camera datamode") + caput(pvIOC+"userStringSeq2.LNK1",pvCam+"cam1:Acquire CA NMS") + caput(pvIOC+"userStringSeq2.STR1","Done") + caput(pvIOC+"userStringSeq2.LNK2",pvCam+"cam1:ImageMode PP NMS") + caput(pvIOC+"userStringSeq2.STR2","Single") + caput(pvIOC+"userStringSeq2.LNK3",pvCam+"TIFF1:EnableCallbacks PP NMS") + caput(pvIOC+"userStringSeq2.STR3","Enable") + caput(pvIOC+"userStringSeq2.LNK4",pvCam+"TIFF1:AutoSave PP NMS") + caput(pvIOC+"userStringSeq2.STR4","Yes") + caput(pvIOC+"userStringSeq2.LNK5",pvCam+"TIFF1:FileNumber PP NMS") + caput(pvIOC+"userStringSeq2.DO5",1) + caput(pvIOC+"userStringSeq2.WAIT1","Wait") + caput(pvIOC+"userStringSeqEnable.VAL",1) + +def Cam_FreeStrSeq(camNUM): + ioc="b" + pvCam="29id_ps"+str(camNUM)+":" + pvIOC="29id"+ioc+":" + userStringSeq_clear("29idb:",2) + caput(pvIOC+"userStringSeq1.DESC","Camera freerun") + caput(pvIOC+"userStringSeq1.LNK1",pvCam+"TIFF1:EnableCallbacks PP NMS") + caput(pvIOC+"userStringSeq1.STR1","Disable") + caput(pvIOC+"userStringSeq1.LNK2",pvCam+"cam1:ImageMode PP NMS") + caput(pvIOC+"userStringSeq1.STR2","Continuous") + caput(pvIOC+"userStringSeq1.LNK3",pvCam+"cam1:Acquire PP NMS") + caput(pvIOC+"userStringSeq1.STR3","Acquire") + caput(pvIOC+"userStringSeq1.LNK4",pvCam+"TIFF1:AutoSave PP NMS") + caput(pvIOC+"userStringSeq1.STR4","No") + caput(pvIOC+"userStringSeq1.LNK5",pvCam+"TIFF1:FileNumber PP NMS") + caput(pvIOC+"userStringSeq1.DO5",1) + caput(pvIOC+"userStringSeq1.LNK6",pvCam+"cam1:AcquireTime PP NMS") + caput(pvIOC+"userStringSeq1.DO6",0.015) + caput(pvIOC+"userStringSeq1.WAIT1","Wait") + caput(pvIOC+"userStringSeqEnable.VAL",1) + + diff --git a/instruments/conversions_constants.py b/instruments/conversions_constants.py new file mode 100644 index 0000000000000000000000000000000000000000..45f1aea59c570ce29108135e34ade471f665f24b --- /dev/null +++ b/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/instruments/current_amplifiers.py b/instruments/current_amplifiers.py new file mode 100644 index 0000000000000000000000000000000000000000..6a72551a16e7f25a5faa4041738fcbe17a10da74 --- /dev/null +++ b/instruments/current_amplifiers.py @@ -0,0 +1,367 @@ +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 + + +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/instruments/diagnostics.py b/instruments/diagnostics.py new file mode 100644 index 0000000000000000000000000000000000000000..dffb409716bfc4f3232f6cbc5f3ecafb2919d47d --- /dev/null +++ b/instruments/diagnostics.py @@ -0,0 +1,226 @@ +from numpy import nan + +from epics import caput, caget +from 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_to_stay_in=False): + """ + Retracts all diagnostic + diode_to_stay_in = True / False (checks beamline) / 'c' /'d' + + Previously: AllDiagOut + """ + diag=diagnostics_dict() + text="" + + #which motor is Diode of interest + if diode_to_stay_in: + diode_to_stay_in = BL.branch + + if diode_to_stay_in.lower() == 'c': + diode_motor=diag["motor"]["gas-cell"] + elif diode_to_stay_in.lower() == '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-'+diode_to_stay_in + #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/instruments/electron_analyzer.py b/instruments/electron_analyzer.py new file mode 100644 index 0000000000000000000000000000000000000000..e3429fd44be9b176410e638c69866bbf66222a6f --- /dev/null +++ b/instruments/electron_analyzer.py @@ -0,0 +1,796 @@ +############################################################# +###################### 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 .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 * + +def __main__(): + global EA + EA = Scienta() + +########################################################################### + +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/instruments/files_and_folders.py b/instruments/files_and_folders.py new file mode 100644 index 0000000000000000000000000000000000000000..89be71eaa2c3f992982df92e52920051d5e5a395 --- /dev/null +++ b/instruments/files_and_folders.py @@ -0,0 +1,324 @@ + + +""" +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 +from time import sleep +import re + +from epics import caget, caput + +from .utilities import dateandtime +from .ARPES import folders_ARPES +from .Kappa import folders_Kappa + +############################################################################################################## +################################ 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 + +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) + + + + + +############################################################################################################## +################################ 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/instruments/gate_valves.py b/instruments/gate_valves.py new file mode 100644 index 0000000000000000000000000000000000000000..1e122c526975534f743216fa16ae2f089094db2d --- /dev/null +++ b/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/instruments/hxp_mirrors.py b/instruments/hxp_mirrors.py new file mode 100644 index 0000000000000000000000000000000000000000..a757fc55ae0c44a5e3cb7ac79ea4995cdd1aa20b --- /dev/null +++ b/instruments/hxp_mirrors.py @@ -0,0 +1,64 @@ +from re import M +from epics import caput, caget +from utilities import print_warning_message +from 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/instruments/logfile.py b/instruments/logfile.py new file mode 100644 index 0000000000000000000000000000000000000000..c07e582398ded480f095cdb9a44a4fbf3617714b --- /dev/null +++ b/instruments/logfile.py @@ -0,0 +1,168 @@ +from os.path import join,open,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 + + +############################################################################################################## +############################## logging ############################## +############################################################################################################## +def log_print(comment=''): + """ + prints a comment to the logfile + """ + logfile_print(BL.endstation_name,BL.ioc,comment=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',today()+'_log.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 = 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 = 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/instruments/m3r.py b/instruments/m3r.py new file mode 100644 index 0000000000000000000000000000000000000000..bf76f19e803e6c966cfec9522cd805a6042c4465 --- /dev/null +++ b/instruments/m3r.py @@ -0,0 +1,123 @@ +from cgi import print_arguments +from IEX_beamline.utilities import print_warning_message +from epics import caget, caput +from 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/instruments/mpa.py b/instruments/mpa.py new file mode 100644 index 0000000000000000000000000000000000000000..73f2ebe895cedb842003269cb303c577092c47ab --- /dev/null +++ b/instruments/mpa.py @@ -0,0 +1,400 @@ +from time import sleep +from os.path import dirname, join +from math import floor + +from epics import caget, caput +from .userCalcs import userCalcOut_clear,userStringSeq_clear +from .Kappa import Kappa_motor_dictionary,Kappa_cts, mda, Kappa_scaler_pv +from .AD_utilites import AD_ROI_setup + + +""" +To do, get busy record in the mpa ioc, get user calcs in the mpa ioc + + +""" +############################################################################################################## +############################## PVs ############################## +############################################################################################################## + +mpa_pv = "29iddMPA:" +mpa_busy="29idcScienta:mybusy2" +userCalc_pv="29idTest" + + +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_callback(BeforeAfter,saveImg=False,**kwargs): + """ + used for triggering the MPA in the scanRecord, reset Proc1 and waits for finish + + BeforeAfter = before, sets up and puts trigger in detTrigNum + = after, clear detTrigNum amd resets to defaults + + saveImg = False used for appropriate trigger of ROIs + = True also saves an image based on ADplugin type + + by default ADplugin = 29iddMPA:TIFF1: + can use 29iddMPA:HDF1: + """ + + kwargs.setdefault("ADplugin","29iddMPA:TIFF1:") + + userCalc_pv="29idTest" + PVstr1="29idTest:userStringSeq1" + PVstr2="29idTest:userStringSeq2" + PVcalcOut9="29idTest:userCalcOut9" + PVcalcOut10="29idTest:userCalcOut10" + + ADplugin=kwargs["ADplugin"] + Proc1=mpa_pv+"Proc1:" + + #All this should moved into the MPA IOC + + + if BeforeAfter=="makeStringSeqCalcCout": + #userCalcOut9 - MPA-busy + caput(PVcalcOut9+".DESC","MPA busy") + caput(PVcalcOut9+".INPA",mpa_busy+" CP") + caput(PVcalcOut9+".OOPT",'Transition to non-zero') + caput(PVcalcOut9+".OUT",PVstr1+".PROC PP") + #Enable CalcOut10 if enable exists + #userStringSeq1 - MPA-start + caput(PVstr1+".DESC","MPA start") + caput(PVstr1+".LNK1", Proc1+"ResetFilter PP") + caput(PVstr1+".STR1","Yes") + #userCalcOut9 - MPA-Proc1waiting + caput(PVcalcOut10+".DESC","MPA Proc1waitng") + caput(PVcalcOut10+".INPA",Proc1+"NumFilter_RBV") + caput(PVcalcOut10+".INPB",Proc1+"NumFiltered_RBV") + caput(PVcalcOut10+".OOPT",'Transition to non-zero') + caput(PVcalcOut10+".OUT",PVstr2+".PROC PP") + #userStringSeq1 - MPA-writeDone + caput(PVstr2+".DESC","MPA writeDone") + caput(PVstr2+".LNK1", ADplugin+"WriteFile PP") + caput(PVstr2+".STR1","Write") + caput(PVstr2+".LNK1", Busy+" PP") + caput(PVstr2+".STR1","Done") + + detTrigNum=kwargs["detTrigNum"] + + if BeforeAfter=="before": + caput(ADplugin+"AutoResetFilter","Yes") + if saveImg: + caput(ADplugin+"AutoSave", "No") + caput(ADplugin+"EnableCallbacks", "Enable") + + + if BeforeAfter=="after": + caput(ADplugin+"AutoResetFilter","No") + if saveImg: + caput(ADplugin+"EnableCallbacks", "Disable") + caput(ADplugin+"AutoSave", "Yes") + + trigger=mpa_busy + 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(BeforeAfter, saveImg, **kwargs): + """ + Sets up the ScanRecord to trigger the MPA + + saveImg = False used for appropriate trigger of ROIs + = True also saves an image based on ADplugin type + + + """ + kwargs.setdefault("scanIOC",BL_ioc()) + kwargs.setdefault("detTrigNum",2) + + cnt=floor(Kappa_scaler_pv) + caput("29iddMPA:Proc1:NumFilter",cnt) + + Busy=_mpa_trigger_callback(BeforeAfter,saveImg=saveImg,**kwargs) + scanPV="29id"+kwargs["scanIOC"]+":scan"+str(kwargs["scanDIM"]) + + #adding the MPA to the scanRecord trigger + if BeforeAfter == "before": + _mpa_prefix(**kwargs) + caput(scanPV+".T"+str(kwargs["detTrigNum"])+"PV", Busy) + + else: + caput(scanPV+".T"+str(kwargs["detTrigNum"])+"PV", "") + + + +def MPA_SaveStrSeq(): + ioc="Kappa" + n=2 + pvDet="29iddMPA:det1:" + pvTIF="29iddMPA:TIFF1:" + pvioc="29id"+ioc+":userStringSeq"+str(n) + ClearStringSeq(ioc,n) + caput(pvioc+".DESC","MCP datamode") + caput(pvioc+".LNK1",pvDet+"Acquire CA NMS") + caput(pvioc+".STR1","Done") + caput(pvioc+".WAIT1","Wait") + caput(pvioc+".LNK2",pvDet+"RunTimeEnable PP NMS") + caput(pvioc+".STR2","1") + caput(pvioc+".WAIT2","Wait") + caput(pvioc+".LNK3",pvTIF+"EnableCallbacks PP NMS") + caput(pvioc+".STR3","1") + +def MPA_FreeStrSeq(): + ioc="Kappa" + n=1 + pvDet="29iddMPA:det1:" + pvioc="29id"+ioc+":userStringSeq"+str(n) + ClearStringSeq(ioc,n) + caput(pvioc+".DESC","MCP freerun") + caput(pvioc+".LNK1",pvDet+"Acquire PP NMS") + caput(pvioc+".WAIT1","Wait") + caput(pvioc+".STR1","Done") + caput(pvioc+".LNK2","29iddMPA:TIFF1:EnableCallbacks PP NMS") + caput(pvioc+".STR2","0") + caput(pvioc+".WAIT2","Wait") + caput(pvioc+".LNK3",pvDet+"RunTimeEnable PP NMS") + caput(pvioc+".STR3","0") + caput(pvioc+".WAIT3","Wait") + caput(pvioc+".LNK4",pvDet+"Acquire PP NMS") + caput(pvioc+".STR4","Acquire") + + +def MPA_HV_SP_CalcOut(): + ioc="Kappa" + n=9 + pvioc="29id"+ioc+":userCalcOut"+str(n) + ClearCalcOut(ioc,n) + max_HV=2990 + ratio=500 + caput(pvioc+".DESC","MPA HV SP") + caput(pvioc+".A",0) + caput(pvioc+".B",ratio) + caput(pvioc+".C",max_HV) + caput(pvioc+".CALC$","A") + caput(pvioc+".OCAL$","MIN(A/B,C/B)") + caput(pvioc+".OOPT",1) # On Change + caput(pvioc+".DOPT",1) # Use 0CALC + caput(pvioc+".IVOA",0) # Continue Normally + caput(pvioc+".OUT","29iddau1:dau1:011:DAC_Set PP NMS") + +def MPA_HV_RBV_CalcOut(): + ioc="Kappa" + n=10 + pvioc="29id"+ioc+":userCalcOut"+str(n) + ClearCalcOut(ioc,n) + max_HV=2750 + ratio=500 + caput(pvioc+".DESC","MPA HV RBV") + caput(pvioc+".INPA",'29iddau1:dau1:011:DAC CP NMS') + caput(pvioc+".B",ratio) + caput(pvioc+".CALC$","A*B") + +def MPA_Interlock(): + ioc="Kappa" + n=7 + pvioc="29id"+ioc+":userCalcOut"+str(n) + ClearCalcOut(ioc,n) + LLM=13.73 + HLM=23.73 + caput(pvioc+".DESC","MPA Interlock") + caput(pvioc+".INPA","29idKappa:m9.DRBV CP NMS") + caput(pvioc+".B",1) + caput(pvioc+".CALC$","ABS((("+str(LLM)+"<A && A<"+str(HLM)+") && (B>0))-1)") + caput(pvioc+".OCAL$",'A') + caput(pvioc+".OOPT",2) # When zero + caput(pvioc+".DOPT",0) # Use CALC + caput(pvioc+".IVOA",0) # Continue Normally + caput(pvioc+".OUT","29iddMPA:C0O PP NMS") + + +def MPA_Interlock_2(): + ioc="Kappa" + n=8 + pvioc="29id"+ioc+":userCalcOut"+str(n) + ClearCalcOut(ioc,n) + LLM=13.73 + HLM=23.73 + caput(pvioc+".DESC","MPA Interlock") + caput(pvioc+".INPA","29idKappa:m9.DRBV CP NMS") + caput(pvioc+".B",1) + caput(pvioc+".CALC$","ABS((("+str(LLM)+"<A && A<"+str(HLM)+") && (B>0))-1)") + caput(pvioc+".OCAL$",'A') + caput(pvioc+".OOPT",2) # When zero + caput(pvioc+".DOPT",0) # Use CALC + caput(pvioc+".IVOA",0) # Continue Normally + caput(pvioc+".OUT","29iddau1:dau1:011:DAC_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/instruments/remote_controlers.py b/instruments/remote_controlers.py new file mode 100644 index 0000000000000000000000000000000000000000..60c3883d3e05cb5bd7dc68dc8621533b5d8eb97d --- /dev/null +++ b/instruments/remote_controlers.py @@ -0,0 +1,356 @@ +from epics import * + +############################################################################################################## +############################## 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_but(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/instruments/resolution.py b/instruments/resolution.py new file mode 100644 index 0000000000000000000000000000000000000000..9b2e864b5c4a7697ee1f8d5d05da3a8a13991efd --- /dev/null +++ b/instruments/resolution.py @@ -0,0 +1,106 @@ +import numpy as np + +from 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/instruments/s29_temp_cntl.py b/instruments/s29_temp_cntl.py new file mode 100644 index 0000000000000000000000000000000000000000..4bffcdae02016ef54eeb3e51bff3f8d9b26c390d --- /dev/null +++ b/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/instruments/scanRecord.py b/instruments/scanRecord.py new file mode 100644 index 0000000000000000000000000000000000000000..a72e5d9bd9aa1e97302d7c1552bde9fb260bd86b --- /dev/null +++ b/instruments/scanRecord.py @@ -0,0 +1,680 @@ + +from os.path import join +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 + + +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): + """ + 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 + """ + self.ioc = scan_ioc + + self.reset_all(detector_dictionary,trigger_dictionary,before_scan_pv,after_scan_pv) + +############################################################################################################## +################################ 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/instruments/scratch.py b/instruments/scratch.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/instruments/scratch.pyc b/instruments/scratch.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7b6343793f253325d6b81d2e85e2b85d7faa54bb Binary files /dev/null and b/instruments/scratch.pyc differ diff --git a/instruments/shutters.py b/instruments/shutters.py new file mode 100644 index 0000000000000000000000000000000000000000..909009f0acbf272454b93353d567dc75801ab7fa --- /dev/null +++ b/instruments/shutters.py @@ -0,0 +1,112 @@ +""" +main shutter and branch shutter functions +""" +from time import sleep +from epics import caget, caput + +from .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/instruments/slits.py b/instruments/slits.py new file mode 100644 index 0000000000000000000000000000000000000000..00b053e9ddb40c7df47d73105ecabf7f2b7d23f5 --- /dev/null +++ b/instruments/slits.py @@ -0,0 +1,490 @@ +from numpy import inf,nan + +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 userStringSeq_userCalc import userStringSeq_clear, userStringSeq_pvs + +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]) + + 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 + mda.fillin(size_rbv,size_val,start,stop,step,**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]) + + 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 + mda.fillin(center_rbv,center_val,start,stop,step,**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" + (H_size,V_size),(H_center,V_center) = slits_get(slit_name,verbose=verbose) + + return H_size,V_size,H_center,V_center + +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" + (H_size,V_size),(H_center,V_center) = slits_get(slit_name,verbose=verbose) + + return H_size,V_size,H_center,V_center + +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 set_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/instruments/spec_stuff.py b/instruments/spec_stuff.py new file mode 100644 index 0000000000000000000000000000000000000000..61cc85925755a39d9b1fa2395e72d18b22c30cf8 --- /dev/null +++ b/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/instruments/staff.py b/instruments/staff.py new file mode 100644 index 0000000000000000000000000000000000000000..7cecc2ba32e060e4a895a69af8b96d6c32b00a13 --- /dev/null +++ b/instruments/staff.py @@ -0,0 +1,94 @@ + +from time import sleep +from epics import caget, caput +from files_and_folders import check_run,make_user_folders,folder_mda +from utilities import print_warning_message +from scanRecord import scanRecord_fillin +from userStringSeq_userCalc import userStringSeq_clear, userStringSeq_pvs,snake_scan_userCalcOut +from logfile import logfile_name_set,logfile_header +from current_amplifiers import ca_live_sequence +from slits import slit3C_get + +from EA import folder_EA + +global BL +staff_ioc = BL.ioc +folder = BL.folder +endstation_name = BL.endstation_name +file_prefix = BL.endstation_name + +############################################################################################################## +############################## setting folder ############################## +############################################################################################################## +def folders_staff(user_name='Staff',**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: ",kwargs['run'],folder,user_name,ARPES_ioc,kwargs['ftp']) + + if endstation_name = 'ARPES': + folders_ARPES(user_name,**kwargs) + elif + endstation_name = 'Kappa' + folders_Kappa(user_name,**kwargs) + + + +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/instruments/storage_ring.py b/instruments/storage_ring.py new file mode 100644 index 0000000000000000000000000000000000000000..3e71edda0bc85d3032c585205a2fc27de1fdbc5a --- /dev/null +++ b/instruments/storage_ring.py @@ -0,0 +1,23 @@ + + +""" +Functions dealing with the storage ring pvs + +""" +from epics import caget +from time import sleep + +from .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/instruments/userCalcs.py b/instruments/userCalcs.py new file mode 100644 index 0000000000000000000000000000000000000000..367ceec1dc83cdd175e6f4547c8021f6d09d117d --- /dev/null +++ b/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/instruments/utilities.py b/instruments/utilities.py new file mode 100644 index 0000000000000000000000000000000000000000..7d929a579dcc563128d86beee73ae6671d3d5957 --- /dev/null +++ b/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 WaitForIt(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/instruments/vortexs29.py b/instruments/vortexs29.py new file mode 100644 index 0000000000000000000000000000000000000000..81deb7330942fbeaeb31d6e092c9fbceeb878a78 --- /dev/null +++ b/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/instruments/xrays.py b/instruments/xrays.py new file mode 100644 index 0000000000000000000000000000000000000000..05e1c4090ede85918d78aef66caa7df5948e919b --- /dev/null +++ b/instruments/xrays.py @@ -0,0 +1,683 @@ +""" +functions related to using x-rays + +""" +import numpy as np +from time import sleep + +from epics import caget,caput,PV +from .IEX_endstations import * + +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 +############################################################################################################## +############################## resets and detector lists ############################## +############################################################################################################## +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: + FileNameWithSubFolder=logfile_name_get(BL.endstation) + 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 != check_energy_allowed(hv_eV): + message_string = 'request photon energy '+str(hv_eV)+' not with the allowed range' + message_string = '\n closest allowed energy is '+str(check_energy_allowed(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 check_energy_allowed(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() + """ + ID_min, ID_max = ID_energy_range() + mono_min, mono_max = mono_energy_range() + hv = np.min(ID_max, mono_max, hv) + hv = np.max(ID_min, ID_max, 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_put() + +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 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_put(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/macros_and_scripts/ARPES_scripts b/macros_and_scripts/ARPES_scripts new file mode 100644 index 0000000000000000000000000000000000000000..89b9f23583785e14cd2ece4a8da99dc2e2bf5edf --- /dev/null +++ b/macros_and_scripts/ARPES_scripts @@ -0,0 +1,89 @@ +from pytest import CaptureFixture +from sympy import capture +from epics import caget,caput +from EA import scanEA + +############################################################################################################## +############################## 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 + slit(150) + kwargs.update({'comment': 'EF1'}) + EAlist=['KE',495,PE,frames,1] + scanEA(EAlist,**kwargs) + + #Core level first order + slit(50) + kwargs.update({'comment': 'KE1'}) + EAlist=['KE',KE,PE,frames/10,1] + scanEA(EAlist,**kwargs) + + #Core level second order + slit(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/macros_and_scripts/BL_shutdown_macros.py b/macros_and_scripts/BL_shutdown_macros.py new file mode 100644 index 0000000000000000000000000000000000000000..12cf163802e048445a8ccd4f51c7e33273e6b634 --- /dev/null +++ b/macros_and_scripts/BL_shutdown_macros.py @@ -0,0 +1,42 @@ + +############################################################################################################## +############################################ Shut down ################################################# +############################################################################################################## + +def BL_Shutdown(): + BL_CloseAllShutters() + BL_Valve_All(state="CLOSE") + AllDiagOut() + 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(): + Close_MainShutter() + Close_CShutter() + Close_DShutter() + +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/macros_and_scripts/alignment_commissioning.py b/macros_and_scripts/alignment_commissioning.py new file mode 100644 index 0000000000000000000000000000000000000000..3b7f51adb315512036e1260f7f798fbba0a2d0e0 --- /dev/null +++ b/macros_and_scripts/alignment_commissioning.py @@ -0,0 +1,1218 @@ +""" +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 files_and_folders import check_run, folder_mda +from scanRecord import scanRecord_run,scanRecord_filepath +from beamline import energy +from M3R import M3R_branch +from ARPES import folders_ARPES +from Kappa import folders_Kappa +from IEX_VPU import ID_switch_mode +from diagnostics import diagnostics_all_out, diagnostics_all_in,diodeC,diodeD +from diagnostics import diodeC_read,diodeD_read +from current_amplifiers import ca2flux +from slits import set_exit_slit + + + +############################################################################################################## +################################ setting the mda folder ############################## +############################################################################################################## + + +def folders_staff(BL): + """ + sets the scan record for Endstation to the Staff folder + """ + run=scanRecord_run(BL.ioc) + folder_mda(run,'b','Staff',BL.name,BL.ioc) + +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): + ID_switch_mode(ID_mode) + energy(hv) + branch=M3R_branch() + diagnostics_all_out(diode_to_stay_in=branch) + SR=round(caget("S:SRcurrentAI.VAL"),2) + if branch == "c": + current_slit=caget('29idb:Slit3CFit.A') + diodeC('In') + set_exit_slit(50) + sleep(10) + diode=diodeC_read() + elif branch == "d": + current_slit=caget('29idb:Slit4Vsize.VAL') + sleep(10) + diodeD("In") + set_exit_slit(50) + diode=caget('29idb:ca14:read') + flux=ca2flux(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_Grating('HEG') + print("\nFlux at hv=500 as off Feb 2019: ~3.3e-06 A = ~1.5e+11 ph/s") + Open_BranchShutter() + CheckFlux(hv=hv,stay=stay) + if wire is not None: + WireScan('H',scanIOC,**kwargs) + WireScan('V',scanIOC,**kwargs) + +def WireScan(which,scanIOC=None,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 + """ + + if scanIOC is None: + scanIOC=BL_ioc() + if all_diag: + AllDiagIn() + if which=='H': + print("\n================== H wire scan (29idb:ca3):") + Scan_FillIn("29idb:m1.VAL","29idb:m1.RBV",scanIOC,1,-13,-27,-0.25) + + elif which=='V': + print("\n================== V wire scan (29idb:ca2):") + Scan_FillIn("29idb:m2.VAL","29idb:m2.RBV",scanIOC,1,-17,-30,-0.25) + Scan_Go(scanIOC,scanDIM=1,**kwargs) + if all_diag: + AllDiagOut() + + def MIR_GRT_Offset(GRT,Slit_list): + """ "Find MIR-GRT offset by scanning 0 order through exit slit""" + Switch_Grating(GRT) + SetExitSlit(50) + scanIOC="Test" + DiodeC('In') + SetSlit2B(2,0.5,0,0) + VAL="29idmonoGRT:P_SP" + for ang in RangeUp(1.5,5,0.5): + print("\r") + Mono_angle(ang,ang) + print("\r") + for x in Slit_list: + SetExitSlit(x) + print("\r") + caput("29idTest:scan1.PASM",3) # go to peak position + caput("29idTest:scan1.REFD",44) + start,stop,step = ang-0.0005*x, ang+0.0005*x ,0.00002*x + Scan_FillIn(VAL,"",scanIOC,1,start,stop,step) + Scan_Go(scanIOC,scanDIM=1) + sleep(1) + print("\r") + ang=caget("29idmonoGRT:P_SP") + print("Peak: ",ang) + print("\r") + print("-------------------------") + caput("29idTest:scan1.PASM",2) + caput("29idTest:scan1.REFD",1) + + + + +############################################################################################################## +########################### Beam Profile ###################### +############################################################################################################## + + + +def Scan_NarrowSlit(which='2V',slit_parameters=[0.25,-2,2,0.5],scanDIM=1,scanIOC=None): + """ + which='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] + """ + if scanIOC == None: + scanIOC=BL_ioc() + size,start,stop,step = slit_parameters + + SlitDict={"V":(inf,size),"H":(size,inf),'1':'2','2':'1'} ## very complicated stuff to make a narrow slit along the direction perpendicular to the scan, and open the other slit all the way + Hsize=SlitDict[which[1]][0] + Vsize=SlitDict[which[1]][1] + scanslit=int(which[0]) + otherslit=int(SlitDict[which[0]]) + + SetSlit(scanslit,Hsize,Vsize) + SetSlit(otherslit) + if which in ['2V','2H']: + SetSlit1A(3,3,0,0) # SetSlit_BL FR added on 9/24/2020 + VAL="29idb:Slit"+which+"center.VAL" + RBV="29idb:Slit"+which+"t2.D" + Scan_FillIn(VAL,RBV,scanIOC,scanDIM,start,stop,step) + + +def Scan_NarrowSlit_Go(which='2V',slit_parameters=[0.25,-2,2,0.5],scanDIM=1,scanIOC='ARPES'): + """ + which='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] + """ + Scan_NarrowSlit(which,slit_parameters,scanDIM,scanIOC) + Scan_Go(scanIOC,scanDIM=scanDIM) + + +def Scan_MonoVsSlit(which='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: + which='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] + + """ + scanIOC=BL_ioc() + eVstart,eVstop,eVstep=energy_parameters + # Filling Scans: + Scan_Mono(1,eVstart,eVstop,eVstep) + caput("29id"+scanIOC+":scan1.PASM","STAY") + Scan_NarrowSlit(which,slit_parameters,2) + Scan_Go(scanIOC,2,**kwargs) + # Resetting everybody to normal: + caput("29id"+scanIOC+":scan1.PASM","PRIOR POS") + SetMono((eVstart+eVstop)/2.0) + SetSlit_BL() + +############################################################################################################## +####################### Mono Calibration ####################### +############################################################################################################## + + + + + + + + +def Mono_angle(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 + """ + 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: + sleep(0.1) + ready=caget('29idmono:ERDY_STS') + print("Mono set to zero order: MIR_pitch = "+str(alpha)+", GRT_pitch = "+str(beta)) + + + +def Mono_Set_b2(b2): + """ + Changes the b2 value for the current grating + """ + hvSP=caget("29idmono:ENERGY_SP") + suffix=Mono_Suffixes()[1] + caput("29idmonoGRT:B2_CALC."+suffix,b2) + sleep (1) + SetMono(hvSP) + Get_Mono() + +def Mono_Set_cff(order,cff): + """ + Changes the cff value for the current grating + """ + which=caget("29idmonoGRT_TYPE_MON") + hvSP=caget("29idmono:ENERGY_SP") + MIR_Pitch=caget("29idmonoMIR:P.RBV") + GRT_Pitch=caget("29idmonoGRT:P.RBV") + hv=caget("29idmono:ENERGY_MON") + print('MIR & GRT Pitch:',MIR_Pitch,GRT_Pitch) + suffix=Mono_Suffixes()[1] + caput("29idmonoGRT:TUN"+str(order)+"_CALC."+suffix,cff) + sleep (1) + SetMono(hvSP) + new_MIR_Pitch=caget("29idmonoMIR:P.RBV") + new_GRT_Pitch=caget("29idmonoGRT:P.RBV") + dif_MIR_Pitch=new_MIR_Pitch-MIR_Pitch + dif_GRT_Pitch=new_GRT_Pitch-GRT_Pitch + new_hv=caget("29idmono:ENERGY_MON") + print('MIR & GRT Pitch:',new_MIR_Pitch,new_GRT_Pitch) + print('Differences :',dif_MIR_Pitch,dif_GRT_Pitch) +# Get_CFF() + + +def Mono_Set_GRT0(newGRT0): + """ + Sets ONLY the GRT_offset for the current Grating + Paralellism is NOT maintained + """ + which='GRT' + suffix=Mono_Suffixes()[1] # Mono_Suffixes() returns suffixes for current MIR [0] and GRT [1] + GRT_pv='29idmono'+which+':P_OFFSETS.'+suffix + hvSP=caget("29idmono:ENERGY_SP") + caput(GRT_pv,newGRT0) + + #Putting the energy back and printing mono parameters + sleep (1) + caput("29idmono:ENERGY_SP",hvSP) + Get_Mono() + + +def Mono_Set_MIR0(newMIR0): + """ + Sets ONLY the MIR0 for the current Grating + Paralellism is NOT maintained + """ + which='MIR' + suffix=Mono_Suffixes()[0] # Mono_Suffixes() returns suffixes for current MIR [0] and GRT [1] + GRT_pv='29idmono'+which+':P_OFFSETS.'+suffix + hvSP=caget("29idmono:ENERGY_SP") + caput(GRT_pv,newMIR0) + #Putting the energy back and printing mono parameters + sleep (1) + caput("29idmono:ENERGY_SP",hvSP) + Get_Mono() + + + +def Mono_Set_MIR0_GRT0(newMIR0): + """ + Sets both the MIR0 and the GRT0 for the current Mirror and Grating + so that paralellism is maintained + """ + MIR_suffix=Mono_Suffixes()[0] # Mono_Suffixes() returns suffixes for current MIR [0] and GRT [1] + GRT_suffix=Mono_Suffixes()[1] + MIR_pv='29idmonoMIR:P_OFFSETS.'+MIR_suffix + GRT_pv='29idmonoGRT:P_OFFSETS.'+GRT_suffix + # Getting current values and current delta between GRT0 and MIR0 + hvSP=caget("29idmono:ENERGY_SP") + oldMIR0=caget(MIR_pv) + oldGRT0=caget(GRT_pv) + delta=oldGRT0-oldMIR0 + # Setting new values while maintaining delta + caput(MIR_pv,newMIR0) + caput(GRT_pv,newMIR0+delta) + #Putting the energy back and printing mono parameters + sleep (1) + caput("29idmono:ENERGY_SP",hvSP) + Get_Mono() + + +def Mono_Set_MIR0_GRT0_all(newMIR0): + """ + Sets both the MIR0 for the current mirror and the GRT0 for all grating + so that paralellism is maintained => Equivalent to moveing ExitSlit_Vcenter + """ + hvSP=caget("29idmono:ENERGY_SP") + MIR_suffix=Mono_Suffixes()[0] # Mono_Suffixes() returns suffixes for current MIR [0] and GRT [1] + MIR_pv ='29idmonoMIR:P_OFFSETS.'+MIR_suffix + GRT_pv1='29idmonoGRT:P_OFFSETS.C' + GRT_pv2='29idmonoGRT:P_OFFSETS.D' + GRT_pv3='29idmonoGRT:P_OFFSETS.E' + #Getting current values: + oldMIR0 =caget(MIR_pv) + oldGRT0_1=caget(GRT_pv1) + oldGRT0_2=caget(GRT_pv2) + oldGRT0_3=caget(GRT_pv3) + print("MIR0 : ",oldMIR0) + print("GRT0s : ",oldGRT0_1,oldGRT0_2,oldGRT0_3) + #Calculating the deltas between GRT0s and MIR0 + delta1=oldGRT0_1-oldMIR0 + delta2=oldGRT0_2-oldMIR0 + delta3=oldGRT0_3-oldMIR0 + print("GRT0(1)-MIR0", delta1) + print("GRT0(2)-MIR0", delta2) + print("GRT0(3)-MIR0", delta3) + # Setting new values while maintaining delta + caput(MIR_pv ,newMIR0) + caput(GRT_pv1,newMIR0+delta1) + caput(GRT_pv2,newMIR0+delta2) + caput(GRT_pv3,newMIR0+delta3) + #Putting the energy back and printing mono parameters + sleep (1) + caput("29idmono:ENERGY_SP",hvSP) + Get_Mono() + + + +def Mono_Set_ExitArm(distance_mm): + """ + Changes the exit arm value in mm (distance between grating and exit slit, theoritically 20000) + """ + hvSP=caget("29idmono:ENERGY_SP") + MIR_Pitch=caget("29idmonoMIR:P.RBV") + GRT_Pitch=caget("29idmonoGRT:P.RBV") + hv=caget("29idmono:ENERGY_MON") + print('MIR & GRT Pitch:',MIR_Pitch,GRT_Pitch) + caput("29idmono:PARAMETER.G",distance_mm) + sleep (1) + SetMono(hvSP) + new_MIR_Pitch=caget("29idmonoMIR:P.RBV") + new_GRT_Pitch=caget("29idmonoGRT:P.RBV") + dif_MIR_Pitch=new_MIR_Pitch-MIR_Pitch + dif_GRT_Pitch=new_GRT_Pitch-GRT_Pitch + new_hv=caget("29idmono:ENERGY_MON") + print('MIR & GRT Pitch:',new_MIR_Pitch,new_GRT_Pitch) + print('Differences :',dif_MIR_Pitch,dif_GRT_Pitch) +# Get_CFF() + + +def Mono_Set_Slitvshv(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) + ''' + slit(hv/100.0*c) + + +def Mono_Scan_Slit2BV(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) + """ + + print("\n--------------- Starting core level vs Slit-2B(V) map ---------------") + GRT=caget("29idmono:GRT_DENSITY") + c=GRT/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) + Mono_Set_Slitvshv(hv,c=10) + #Aperturing slit 2V + caput("29idb:Slit2Vsize.VAL",Vsize) + VVAL ="29idb:Slit2Vcenter.VAL" + #Take XPS for each Slit-2V position + for V in RangeUp(Vstart,-Vstart,Vstep): + caput(VVAL,V,wait=True,timeout=18000) + kwargs.update({'comment': "2-V center ="+str(V)[0:6]}) + EAlist=["BE",peakBE,PE,17*60*i,1] + scanEA(EAlist,**kwargs) + SetSlit_BL() + + + +def Mono_Scan_hv_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) + ''' + kwargs.setdefault('c','3') + + for hv in RangeUp(start,stop,step): + energy(hv) + c=int(kwargs['c']) + Mono_Set_Slitvshv(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 FullPinhole(): + """ + Does a pinhole with .1 mm step with AllDiagIn and then with only DiodeCIn() + """ + AllDiagIn() + Scan_Pinhole_Go(-3, 3, .5, .1, -3, 3, .5, .1) + AllDiagOut() + DiodeC('In') + Scan_Pinhole_Go(-3, 3, .5, .1, -3, 3, .5, .1) + + +def Scan_Pinhole_Go(Hstart, Hstop, Hsize, Hstep,Vstart, Vstop, Vsize, Vstep,HscanDim=1,VscanDim=2,scanIOC="BL_ioc"): + """ + Sets up the pinhole scan in the specified scanIOC ( BL_ioc => BL_ioc(), else scanIOC="Kappa","ARPES","RSXS"...) + Make sure that you have the appropriate Diagnostics in can use AllDiagIn() + Scan_Pinhole_Start(-3, 3, 0.5, 0.5, -3, 3, 0.5, 0.5) + """ + Scan_Pinhole(Hstart, Hstop, Hsize, Hstep, Vstart, Vstop, Vsize, Vstep,HscanDim,VscanDim,scanIOC) + print("\r") + print("Pinhole ("+str(HscanDim)+","+str(VscanDim)+"): "+str(Hstart)+"/"+str(Hstop)+"/"+str(Hsize)+"/"+str(Hstep)+"/"+str(Vstart)+"/"+str(Vstop)+"/"+str(Vsize)+"/"+str(Vstep)) + if scanIOC == "BL_ioc": + scanIOC = BL_ioc() + Scan_Go(scanIOC,scanDIM=VscanDim) + print("\r") + print("Now setting the slits back to:") + SetSlit_BL() + print("\r") + print("WARNING: Don't forget to pull all of the diagnostics out.") + +def Scan_Pinhole(Hstart, Hstop, Hsize, Hstep,Vstart, Vstop, Vsize, Vstep,HscanDim=1,VscanDim=2,scanIOC="BL_ioc"): + """ + Sets up the pinhole scan in the specified scanIOC ( BL_ioc => BL_ioc(), else scanIOC="Kappa","ARPES","RSXS"...) + Make sure that you have the appropriate Diagnostics in can use AllDiagIn() + Does not press Go + """ + if scanIOC == "BL_ioc": + scanIOC = BL_ioc() + + #Synching slits + caput("29idb:Slit1Hsync.PROC",1) + caput("29idb:Slit1Vsync.PROC",1) + #Getting initial slit size + Hsize0=caget("29idb:Slit1Ht2.C") + Vsize0=caget("29idb:Slit1Vt2.C") + Hcenter0=caget("29idb:Slit1Ht2.D") + Vcenter0=caget("29idb:Slit1Vt2.D") + #Filling in the ScanRecord + HVAL="29idb:Slit1Hcenter.VAL" + HRBV="29idb:Slit1Ht2.D" + Hstart=1.0*Hstart + Hstop=1.0*Hstop + Hstep=1.0*Hstep + VVAL="29idb:Slit1Vcenter.VAL" + VRBV="29idb:Slit1Vt2.D" + Vstart=1.0*Vstart + Vstop=1.0*Vstop + Vstep=1.0*Vstep + Scan_FillIn(HVAL,HRBV,scanIOC,HscanDim,Hstart,Hstop,Hstep) + Scan_FillIn(VVAL,VRBV,scanIOC,VscanDim,Vstart,Vstop,Vstep) + SetSlit1A(Hsize,Vsize,0,0,q=None) + print("WARNING: The slits are now set to", str(Hsize),"x",str(Vsize)) + + +############################################################################################################## +################## 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_MonoVsSlit('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_MonoVsSlit('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(scanIOC=None,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() + + """ + if scanIOC == None: + scanIOC=BL_ioc() + #scanning top-blade + + SetSlit1A(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' + Scan_FillIn(VAL,RBV,'ARPES',1,-4,4.0,step) + Scan_ARPES_Go() + FileNum1 = caget("29id"+scanIOC+":saveData_scanNumber")-1 + + #scanning inboard-blade + SetSlit1A(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' + Scan_FillIn(VAL,RBV,'ARPES',1,-4,4.0,step) + Scan_ARPES_Go() + FileNum2 = caget("29id"+scanIOC+":saveData_scanNumber")-1 + 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 Scan_SlitCenter(slit,start,stop,step,setslit=None,scanIOC=None,scanDIM=1,**kwargs): + """ + Scans the slit center: + slit='1H','1V','2H' or '2V' + Slit 1A is set to (0.25,0.25,0,0) unless setslit= not None + Logging is automatic: use **kwargs or the optional logging arguments see scanlog() for details + default: scanDIM=1 + """ + if setslit is None: + SetSlit1A(0.25,0.25,0,0) + #SetSlit1A(4.5,4.5,0,0,'q') + #SetSlit2B(6.0,8.0,0,0,'q') + if scanIOC is None: + scanIOC = BL_ioc() + VAL='29idb:Slit'+slit+'center.VAL' + RBV='29idb:Slit'+slit+'t2.D' + Scan_FillIn(VAL,RBV,scanIOC,scanDIM,start,stop,step) + Scan_Go(scanIOC,scanDIM=scanDIM,**kwargs) + + +def Scan_SlitSize(slit,start,stop,step,setslit=None,scanIOC=None,scanDIM=1,**kwargs): + """ + Scans the slit center: + slit='1H','1V','2H' or '2V' + Slit 1A is set to (1.75,1.75,0,0) unless setslit= not None + Logging is automatic: use **kwargs or the optional logging arguments see scanlog() for details + default: scanDIM=1 + """ + if setslit is None: + SetSlit1A(1.75,1.75,0,0) #why is that? + #SetSlit1A(4.5,4.5,0,0,'q') # would open all the way? + #SetSlit2B(6.0,8.0,0,0,'q') + if scanIOC is None: + scanIOC = BL_ioc() + VAL='29idb:Slit'+slit+'size.VAL' + RBV='29idb:Slit'+slit+'t2.C' + Scan_FillIn(VAL,RBV,scanIOC,scanDIM,start,stop,step) + Scan_Go(scanIOC,scanDIM=scanDIM,**kwargs) + + + + + +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 + """ + SetSlit1A(0.25,0.25,0,0) + SetID_Raw(hv) + Scan_SlitCenter('1H',-3,3,0.1) + Scan_SlitCenter('1V',-3,3,0.1) + + +##################################################################################### +# 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 BeamProfile(GRT,SlitList,c_slit=1,c_energy=1,scanIOC=None,**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 + """ + if scanIOC is None: + scanIOC=BL_ioc() + Switch_Grating(GRT) + GRT=caget("29idmono:GRT_DENSITY") + c=GRT/1200 + ID=500 + eVstart,eVstop,eVstep=460,540,4 + for slit in SlitList: + 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_MonoVsSlit('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_MonoVsSlit('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_MonoVsSlit('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_MonoVsSlit('2V',[0.5,-4,4,0.5*c_slit],[eVstart,eVstop,eVstep],comment='Mono/Slit - 2V') + + +def CheckAllSlits_long(hvList=[500],SlitList=["1H","1V","2H","2V"],scanIOC=None,**kwargs): + """ + For each photon energy in hvList, takes 3 slit curves @ mono below / resonance / above + For given SlitList + For both gratings + """ + if scanIOC is None: + scanIOC=BL_ioc() + for GRT in ["HEG","MEG"]: # One full loop for a given grating and 3 energies takes 5h for average 20 + Switch_Grating(GRT) + for hv in hvList: + SetBL(hv) + step=hv/100.0 + start=hv-step + stop=hv+step + for slit in SlitList: + for hv in RangeUp(start,stop,step): + print("\r") + SetMono(hv) + CheckBeamPosition(slit,scanIOC,**kwargs) + + +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() + SetExitSlit(50) + SetBL(BL) + for hv in hvList: + SetMono(hv) + for slit in slit_list: + CheckBeamPosition(slit,scanIOC=scanIOC,**kwargs) + print("\n") + +def CheckBeamPosition(slit,scanIOC=None,**kwargs): # instead of the full 2D map, you get 3 vertical cuts which + if scanIOC is None: + scanIOC=BL_ioc() + GRT=caget("29idmono:GRT_DENSITY") # can be plotted directly on dview using the buffer. That should + c=GRT/1200 # be fairly quick and not require any data loading/analysis + SetSlit1A(3.5,3.5,0,0,'q') + #SetSlit1A(4.5,4.5,0,0,'q') + SetSlit2B(6.0,8.0,0,0,'q') # Open up all the slits to make sure we scan the full beam + if slit == "1H": +# size,start,stop,step = 0.50,-2.5,2.5,0.1 + size,start,stop,step = 0.50,-4.5,4.5,0.2 + elif slit == "1V": +# size,start,stop,step = 0.50,-2.5,2.5,0.1 + size,start,stop,step = 0.50,-4.5,4.5,0.2 + elif slit == "2H": +# size,start,stop,step = 0.25,-3.0,3.0,0.1 + size,start,stop,step = 0.25,-8.0,8.0,0.2 + elif slit == "2V": +# size,start,stop,step = 0.25,-3.5*c,3.5*c,0.1*c + size,start,stop,step = 0.25*c,-4*c,4*c,0.2*c + VAL ="29idb:Slit"+slit+"center.VAL" + RBV ="29idb:Slit"+slit+"t2.D" + caput("29idb:Slit"+slit+"size.VAL",size) + print("\nScan "+slit+":") + scanIOC = BL_ioc() + scanDIM=1 + Scan_FillIn(VAL,RBV,scanIOC,scanDIM,start,stop,step) + Scan_Go(scanIOC,scanDIM,**kwargs) + SetSlit_BL(q='q') + + + + +def Reset_Slit2B_Encoders(Hcenter,Vcenter): + """ + Resetting Slit 2B encoders to 0 for a given position (Hcenter,Vcenter). + Slit size need to be set to 0. + """ + SetSlit2B(0,0,Hcenter,Vcenter) + print('\nCurrent Position:') + print(('e13 = '+str(caget('29idMini1:e13Pos')))) + print(('e14 = '+str(caget('29idMini1:e14Pos')))) + print(('e15 = '+str(caget('29idMini1:e15Pos')))) + print(('e16 = '+str(caget('29idMini1:e16Pos')))) + print('\nSetting all Offsets to 0:') + caput('29idMini1:e13Pos.EOFF',0) + caput('29idMini1:e14Pos.EOFF',0) + caput('29idMini1:e15Pos.EOFF',0) + caput('29idMini1:e16Pos.EOFF',0) + print('\nCurrent Position:') + print(('e13 = '+str(caget('29idMini1:e13Pos')))) + print(('e14 = '+str(caget('29idMini1:e14Pos')))) + print(('e15 = '+str(caget('29idMini1:e15Pos')))) + print(('e16 = '+str(caget('29idMini1:e16Pos')))) + print('\nSetting back Offsets:') + caput('29idMini1:e13Pos.EOFF',-caget('29idMini1:e13Pos')) + caput('29idMini1:e14Pos.EOFF',-caget('29idMini1:e14Pos')) + caput('29idMini1:e15Pos.EOFF',-caget('29idMini1:e15Pos')) + caput('29idMini1:e16Pos.EOFF',-caget('29idMini1:e16Pos')) + print('\nCurrent Position:') + print(('e13 = '+str(caget('29idMini1:e13Pos')))) + print(('e14 = '+str(caget('29idMini1:e14Pos')))) + print(('e15 = '+str(caget('29idMini1:e15Pos')))) + print(('e16 = '+str(caget('29idMini1:e16Pos')))) + Sync_Encoder_RBV('b') + SyncAllSlits() + +def Reset_Slit3D_Encoders(center): + """ + Resetting Slit 3D encoders to 0 for a given position (Hcenter,Vcenter). + Slit size need to be set to 0. + """ + caput('29idb:Slit4Vsize.VAL',0) + caput('29idb:Slit4Vcenter.VAL',center) + + print('\nCurrent Position:') + print(('e26 = '+str(caget('29idMini2:e26Pos')))) + print(('e27 = '+str(caget('29idMini2:e27Pos')))) + print('\nSetting all Offsets to 0:') + caput('29idMini2:e26Pos.EOFF',0) + caput('29idMini2:e27Pos.EOFF',0) + print('\nCurrent Position:') + print(('e26 = '+str(caget('29idMini2:e26Pos')))) + print(('e27 = '+str(caget('29idMini2:e27Pos')))) + print('\nSetting back Offsets:') + caput('29idMini2:e26Pos.EOFF',-caget('29idMini2:e26Pos')) + caput('29idMini2:e27Pos.EOFF',-caget('29idMini2:e27Pos')) + print('\nCurrent Position:') + print(('e26 = '+str(caget('29idMini2:e26Pos')))) + print(('e27 = '+str(caget('29idMini2:e27Pos')))) + Sync_Encoder_RBV('b') + SyncAllSlits() + + + +############################################################################################################## +################## 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(hv,list_mode,start,stop,step): + SetExitSlit(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 mode in list_mode: + Switch_IDMode(mode) + SetID_Raw(hv) + SetSlit_BL() + SetMono(250) + Scan_Mono(1,start,stop,step) + Scan_Go("b",scanDIM=1) + #Switch_IDQP("off") + #Switch_Grating("HEG") + #Switch_IDMode("RCP") + + +############################################################################################################## +################################ ID calibration scripts ############################## +############################################################################################################## + +###### Energy range follows ID ######## + +def IDCalibration_Scan(start,stop,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 !!!""") + + if scanIOC is None: + scanIOC=BL_ioc() + scanDIM=1 + #Setting up scan record to go to peak position at the end of the scan + PV='29id'+scanIOC+':scan'+str(scanDIM) + VAL="29idmono:ENERGY_SP" + RBV="29idmono:ENERGY_MON" + caput(PV+'.PDLY',0.2) #Detector settling time + caput(PV+'.PASM','STAY') + + #Getting mono max range based on grating + GRT=caget("29idmono:GRT_DENSITY") + c=GRT/1200 # c = 1 for MEG, 2 for HEG + if c == 1: maxhv = 3000 + elif c == 2: maxhv = 2000 + kwargs={'comment': "====== Starting Mono Scan vs ID"} + kwargs.update({'FileSuffix': "IDCalibration"}) + logprint(**kwargs) + for ID in RangeUp(start,stop,step): + print("\n------------------ ID-SP @ "+str(ID)+" ------------------") + SetMono(ID) + SetID_Raw(ID) + SetSlit_BL() + branch=CheckBranch() + if branch == 'd': + align_m3r_epics() + if QP is None: + start_hv=min(ID-ID/(bandwidth*1.0)*Harm,maxhv) # FR update range 11/20/2019 + stop_hv=min(ID+ID/(bandwidth*2.0)*Harm,maxhv) + step_hv=round(ID/300.0,1) +# start_hv=min(ID-ID/(bandwidth*2.0)*Harm,maxhv) # shift the window by doing -BW*2/+BW*1 instead of -BW*1'/'+BW*2 +# stop_hv=min(ID+ID/(bandwidth*1.0)*Harm,maxhv) +# step_hv=round(ID/500.0,1) + else: + start_hv=min(ID-ID/(bandwidth*2.5)*Harm,maxhv) + stop_hv=min(ID+ID/(bandwidth*0.7)*Harm,maxhv) + step_hv=round(ID/300.0,1) + Scan_FillIn(VAL,RBV,scanIOC,1,start_hv,stop_hv,step_hv) + Scan_Go(scanIOC,scanDIM=scanDIM,FileSuffix='IDCalibration',comment="ID-SP @ "+str(ID)) + sleep(1) + FileNum = caget("29id"+scanIOC+":saveData_scanNumber")-1 + if 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 IDCalibration_Mode(which,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=CheckBranch() + #AllDiagOut(DiodeStayIn=branch) + #DiodeC('In') + print('WARNING: commented out AllFDiagOut and DiodeC("In")') + polarization(which) + GRT=caget("29idmono:GRT_DENSITY") + if GRT==2400: GRT='HEG' + if GRT==1200: GRT='MEG' + QP_ratio=caget("ID29:QuasiRatioIn.C") + if start == None: + start=Energy_Range(GRT,which)[0] + if stop == None: + stop=Energy_Range(GRT,which)[1]-50 + if QP_ratio <100: + stop=min(stop,1500) + QP_ratio=1 + else: QP_ratio=None + IDCalibration_Scan(start,stop,step,bandwidth=10,QP=QP_ratio,Harm=Harm,scanIOC=None) + + + + + + + + + + + + + +############################################################################################################## +############################## Beam Motion ############################## +############################################################################################################## + + +def Pixel_Calibration(motorName,start,stop,step,camNUM,AcqTime): + """ + """ + scanIOC=BL_ioc() + scanDIM=1 + + branch=CheckBranch() + if branch == "c": + m_RBV,m_VAL=ARPES_PVmotor(motorName) + elif branch == "d": + m_RBV,m_VAL=Kappa_PVmotor(motorName) + pvCam="29id_ps"+str(camNUM)+":" + Scan_FillIn("","",scanIOC,scanDIM,1,1,1) + Scan_Go(scanIOC,scanDIM=scanDIM) + TakeImageSetup(camNUM) + caput(pvCam+"TIFF1:FileNumber",1) + for value in RangeUp(start,stop,step): + caput(m_VAL,value) + sleep(2) + print(motorName+" = "+str(value)) + TakeImage(camNUM,AcqTime) + Cam_FreeRun(camNUM) + + + +def BeamMotion_Vs_BL_Go(start,stop,step,camNUM,AcqTime,scanDIM=1): + """ + default: scanDIM=1 + """ + scanIOC=BL_ioc() + pvCam="29id_ps"+str(camNUM)+":" + Scan_FillIn("","",scanIOC,scanDIM,1,1,1) + Scan_Go(scanIOC,scanDIM=scanDIM) + TakeImageSetup(camNUM) + caput(pvCam+"TIFF1:FileNumber",1) + for eV in RangeUp(start,stop,step): + SetBL(eV) + # if mode == 0 or mode == 1: + # if eV>=600 or eV<=1600: + # AcqTime=AcqTime/2.0 #JM commented out + if eV > 2200: + AcqTime=AcqTime*10 + TakeImage(camNUM,AcqTime) + Cam_FreeRun(camNUM) + +def BeamMotion_Vs_hv_Go(ioc,scannum,ID,hv,AcqTime): + ioc="b" + scannum=1 + camNUM=4 + pvCam="29id_ps"+str(camNUM)+":" + SetID(ID) + SetMono(hv) + Scan_FillIn("","",ioc,scannum,1,1,1) + Scan_Go(ioc,scanDIM=1) + TakeImageSetup(camNUM) + caput(pvCam+"TIFF1:FileNumber",1) + sleep(3) + TakeImage(camNUM,AcqTime) + Cam_FreeRun(camNUM) + +def BeamMotion_Vs_MonoZero_Go(ioc,scannum,start,stop,step,camNUM,iteration,AcqTime): + pvCam="29id_ps"+str(camNUM)+":" + Scan_FillIn("","",ioc,scannum,1,1,1) + Scan_Go(ioc,scanDIM=1) + TakeImageSetup(camNUM) + caput(pvCam+"TIFF1:FileNumber",1) + i=1 + while i<=iteration: + n=start*1.0 + while n<=stop: + Mono_zero(n) + TakeImage(camNUM,AcqTime) + n+=step + i+=1 + Cam_FreeRun(camNUM) + +def BeamMotion_Vs_MirPitch_Go(ioc,scannum,angle1,angle2,camNUM,iteration,AcqTime): + pvCam="29id_ps"+str(camNUM)+":" + Scan_FillIn("","",ioc,scannum,1,1,1) + Scan_Go(ioc,scanDIM=1) + TakeImageSetup(camNUM) + caput(pvCam+"TIFF1:FileNumber",1) + i=1 + while i<=iteration: + Mono_angle(angle1,angle1) + sleep(5) + TakeImage(camNUM,AcqTime) + Mono_angle(angle2,angle1) + i+=1 +# Cam_FreeRun(camNUM) + +def BeamMotion_Vs_GrtPitch_Go(ioc,scannum,angle1,angle2,camNUM,iteration,AcqTime): + pvCam="29id_ps"+str(camNUM)+":" + Scan_FillIn("","",ioc,scannum,1,1,1) + Scan_Go(ioc,scanDIM=1) + TakeImageSetup(camNUM) + caput(pvCam+"TIFF1:FileNumber",1) + i=1 + while i<=iteration: + Mono_angle(angle1,angle1) + sleep(5) + TakeImage(camNUM,AcqTime) + Mono_angle(angle1,angle2) + i+=1 +# Cam_FreeRun(camNUM) + +def BeamMotion_Vs_GrtTx_Go(ioc,scannum,camNUM,iteration,AcqTime): + pvCam="29id_ps"+str(camNUM)+":" + Scan_FillIn("","",ioc,scannum,1,1,1) + Scan_Go(ioc,scanDIM=1) + TakeImageSetup(camNUM) + caput(pvCam+"TIFF1:FileNumber",1) + + i=1 + while i<=iteration: + grating("HEG") + Mono_zero(2) + sleep(10) + TakeImage(camNUM,AcqTime) + grating("MEG") + Mono_zero(2) + sleep(10) + TakeImage(camNUM,AcqTime) + i+=1 +# Cam_FreeRun(camNUM) + + diff --git a/macros_and_scripts/start_of_the_week.py b/macros_and_scripts/start_of_the_week.py new file mode 100644 index 0000000000000000000000000000000000000000..1bab3ca0996a495e98d32619cd8cd5fa9bb777bd --- /dev/null +++ b/macros_and_scripts/start_of_the_week.py @@ -0,0 +1,285 @@ + +def StartOfTheWeek(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 + """ + 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': + CA_Autoscale('b',15,'Off',7) #turn off autoscaling on CA15 + 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=caget('ID29:QuasiRatio.RVAL') + if QP != 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_Grating(GRT) + if not kwargs['repeat']: + Switch_Branch(branch) + scanIOC=BL_ioc() # updating scanIOC after switching branch + Clear_Scan_Positioners(scanIOC)#doesn't Reset_Scan now do this + Clear_Scan_Triggers(scanIOC) + print("\n\n================== Sets Directory:") + Check_Staff_Directory(**kwargs) + FileName='StartOfTheWeek_log.txt' + logname_set(FileName,scanIOC) + FirstScan=None + BL_Mode_Set('Staff') + Reset_Scan(BL_ioc()); Reset_CA_all(); Reset_Mono_Limits() + Get_All() + if branch=='c': + caput("29idARPES:scan1.D17PV",'') # clear EA just in case + else: + scanIOC=BL_ioc() #define scanIOC for when not switching branches + + ### checking branch shutter: + shutter=caget('PA:29ID:S'+branch.upper()+'S_BLOCKING_BEAM.VAL') + if shutter == 'ON': + foo=input_d('Shutter '+branch.upper()+' is closed, do you want to open it (y or n)? >') + if foo.lower() == 'y' or foo.lower() == 'yes': + Open_BranchShutter() + else: + print('Aborting...') + return + + ### Wait for next 8AM: + if wait: + t = datetime.today() + if 0 <= t.hour <= 8: + WaitForIt(0,8,5) + else: + WaitForIt(1,8,5) + + ### checking ID: + print("\n\n================== Start ID:") + ID_OnOff=caget('ID29:Main_on_off.VAL') + if ID_OnOff==1: # 0 = On, 1 = Off + ID_Start('RCP') + else: + polarization('RCP') + + + ### Ready to start: + FirstScan=mda_lastFileNum()+1 + + if not kwargs['repeat']: + logprint("\n\n================== Start Of The Week @ "+today('slash')+':\n',FileName=FileName) + + + 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:") + SetID_Raw(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') + SetSlit1A(4.5,4.5,0,0) + m=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']: + SetID_Raw(2000) + SetSlit1A(4.5,4.5,0,0) + WireScan('H',comment='Wire scan - H',all_diag=False) # by default puts all meshes in + DiodeC + WireScan('V',comment='Wire scan - V',all_diag=False) + m=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(505) + print('\n---------- Scanning slit 2B:\n') + flag=True + while flag: + Scan_NarrowSlit_Go(which='2V',slit_parameters=[0.25*c, -8, 8, 0.25]);sleep(1) + Scan_NarrowSlit_Go(which='2H',slit_parameters=[0.25, -6, 6, 0.25]);sleep(1) + m=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_NarrowSlit_Go(which='1V',slit_parameters=[0.25, -4, 4, 0.1]);sleep(1) + Scan_NarrowSlit_Go(which='1H',slit_parameters=[0.25, -3, 3, 0.1]);sleep(1) + SetSlit_BL() + m=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 + SetID_Raw(500) + flag=True + while flag: + mono(500) + SetSlit_BL() + n=2 if 'extended_range' in kwargs else 1 + Scan_MonoVsSlit('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_MonoVsSlit('2H',[0.25,-2*n,2*n,0.5],[475,515,2],comment='Mono/Slit - 2H') #10min + Scan_MonoVsSlit('1V',[0.5,-0.75*n,0.75*n,0.25*c],[475,515,2],comment='Mono/Slit - 1V') #10min + Scan_MonoVsSlit('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']: + DiodeC('In') + print("\n\n================== Check Flux:") + flag=True + while flag: + CheckFlux(stay='y') + slit(50) + energy(500) + scanhv(475,525,1,comment='Mono Scan @ 500eV') + try: + m=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 + + AllDiagOut() + + 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: + logprint(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 +