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
+