diff --git a/build/lib/iexcode/__init__.py b/build/lib/iexcode/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc
--- /dev/null
+++ b/build/lib/iexcode/__init__.py
@@ -0,0 +1 @@
+
diff --git a/iexcode/instruments/AD_utilites.py b/build/lib/iexcode/instruments/AD_utilites.py
similarity index 98%
rename from iexcode/instruments/AD_utilites.py
rename to build/lib/iexcode/instruments/AD_utilites.py
index 19de0238d000b53210e7f0264f01da7dc3c54ec9..f8d43d23aed84bf5a1ee86d46cefdbb81f5d1ffa 100644
--- a/iexcode/instruments/AD_utilites.py
+++ b/build/lib/iexcode/instruments/AD_utilites.py
@@ -13,8 +13,8 @@ from os.path import join, isfile, exists, dirname
 from time import sleep
 
 from epics import caget, caput
-from .IEX_endstations import *
-from .files_and_folders import get_next_fileNumber
+from iexcode.instruments.IEX_endstations import *
+from iexcode.instruments.files_and_folders import get_next_fileNumber
 
 
 def AD_CurrentDirectory(ADplugin):
diff --git a/build/lib/iexcode/instruments/AD_utilities.py b/build/lib/iexcode/instruments/AD_utilities.py
new file mode 100644
index 0000000000000000000000000000000000000000..f8d43d23aed84bf5a1ee86d46cefdbb81f5d1ffa
--- /dev/null
+++ b/build/lib/iexcode/instruments/AD_utilities.py
@@ -0,0 +1,347 @@
+"""
+General functions for dealing with Area Detectors and Cameras at 29ID
+
+work in progress need to redo
+"""
+##############################################################################################################
+##############################     General Area Detector            ##############################
+##############################################################################################################
+import datetime
+import re
+from os import listdir,mkdir,chown,system,chmod
+from os.path import join, isfile, exists, dirname
+from time import sleep
+
+from epics import caget, caput
+from iexcode.instruments.IEX_endstations import *
+from iexcode.instruments.files_and_folders import get_next_fileNumber
+
+
+def AD_CurrentDirectory(ADplugin):
+    """
+    returns the current directory for area detector SavePlugin
+    handles both Winodws and linux IOCs
+    ADplugin = "29idc_ps1:TIFF1:"; $(P)$(SavePlugin)
+    """
+    SubDir=caget(ADplugin+"FilePath",as_string=True)
+    if SubDir[0] == 'X':
+        Dir='/net/s29data/export/data_29idb/'
+        SubDir=SubDir.split('\\')[1:]
+    elif SubDir[0] == 'Y':
+        Dir='/net/s29data/export/data_29idc/'
+        SubDir=SubDir.split('\\')[1:]
+    elif SubDir[0] == 'Z':
+        Dir='/net/s29data/export/data_29idd/'    
+        SubDir=SubDir.split('\\')[1:]
+    else: 
+        Dir = SubDir
+        SubDir=[]
+    FilePath=join(Dir,*SubDir,'')
+    return FilePath 
+
+def AD_prefix(ADplugin):
+    """
+    returns the prefix for AreaDetector plugin based on ADplugin 
+    """
+    prefix = caget(ADplugin+"FileName_RBV",as_string=True)
+    return prefix
+
+def AD_EnableStats(ADplugin):
+    """
+    Enabling the statistics in an AreaDector
+    ADplugin = "29idc_ps1:Stats1:"; (ADplugin=$(P)$(StatsPlugin))
+    """
+    caput(ADplugin+"EnableCallbacks","Enable")
+    caput(ADplugin+"ComputeStatistics","Yes")
+    caput(ADplugin+"ComputeCentroid","Yes")
+    
+
+def AD_SaveFileSetup(ADplugin,mda,**kwargs):
+    """    
+    ADplugin = "29id_ps1:TIFF1:" which IOC and which filesaving plugin
+            (ADplugin=$(P)$(SavePlugin))
+    uses to get the current MDA directory and then set the path to one up + /dtype
+    MDA_CurrentDirectory(scanIOC=None)
+    
+    **kwargs (defaults)
+        scanIOC = BL_ioc()
+        userpath = extracted from ScanRecord unless specified
+        subfolder = taken from ADplugin unless specified
+            filepath = userpath/subfolder
+        
+        prefix = default same as subfolder
+        ext = file extension is extracted for ADplugin unless specified
+            (TIFF -> tif, HDF -> h5, ...)
+        FileTemplate="%s%s_%4.4d."+ext; format for filename first %s = filepath, second %s = prefix
+        
+    """
+    kwargs.setdefault("userpath",dirname(dirname(mda.filepath)))
+    kwargs.setdefault("subfolder",ADplugin.split(":")[-2][:-1])
+
+    kwargs.setdefault("prefix",ADplugin.split(":")[-2][:-1])
+    extDict={"TIFF":".tif","HDF":"h5"}
+    kwargs.setdefault("ext",ADplugin.split(":")[-2][:-1])
+    kwargs.setdefault("FileTemplate","%s%s_%4.4d."+kwargs["ext"])
+    
+    kwargs.setdefault("debug",False)
+    
+    if kwargs['debug']:
+        print("kwargs: ",kwargs)
+
+    fpath=join(kwargs['userpath'],kwargs['subfolder'],'')
+    print("\nFolder: " + fpath)
+    if not (exists(fpath)):
+        fileNumber=1
+    else:
+        fileNumber=get_next_fileNumber(fpath,kwargs["prefix"])
+    print("NextFile: "+str(fileNumber))
+    caput(ADplugin+"CreateDirectory",-1) #allows IOC to create directories    
+    caput(ADplugin+"FilePath",fpath)
+    caput(ADplugin+"FileName",kwargs["prefix"])
+    caput(ADplugin+"FileNumber",fileNumber)
+    
+    #setup AD
+    caput(ADplugin+"FileTemplate",kwargs["FileTemplate"])
+    caput(ADplugin+"AutoIncrement","Yes")
+    caput(ADplugin+"AutoSave","Yes")
+    
+def AD_CurrentPrefix(ADplugin):
+    """
+    returns the prefix (without _) for area detector SavePlugin
+    ADplugin = "29id_ps1:TIFF1:"; $(P)$(SavePlugin)
+    """
+    Prefix=caget(ADplugin+'FileName',as_string=True)
+    return Prefix
+   
+def AD_CurrentRun(ADplugin):
+    """
+    returns the curent run specified in the filepath for area detector SavePlugin
+    ADplugin = "29id_ps1:TIFF1:"; $(P)$(SavePlugin)
+    """
+    fpath=caget(ADplugin+"FilePath",as_string=True)
+    current_run=re.findall("\d\d\d\d_\d", fpath)[0]
+    return current_run
+   
+def AD_CurrentUser(ADplugin):
+    """
+    returns the curent user specified in the filepath for area detector SavePlugin
+    ADplugin = "29id_ps1:TIFF1:"; $(P)$(SavePlugin)
+    """
+    folder_name = ADplugin.split(":")[1]
+    folder_name[:-1]
+    SubDir=caget(ADplugin+":FilePath",as_string=True)
+    if SubDir[0] == 'X':
+        current_user='Staff'
+    elif SubDir[0] == 'Y':
+        m=SubDir.find(AD_CurrentRun(ADplugin))
+        n=SubDir.find(folder_name)
+        current_user=SubDir[m+7:n]
+    else: current_user=None
+    return current_user
+
+def AD_DoneSingleSave(ADplugin,**kwargs):
+    """
+    sets and AD up ready to save images
+        Acquire -> Done
+        ImageMode -> Single
+        Save -> Enable
+        e.g. ADplugin="29id_ps2:TIFF1:"
+        
+        **kwargs:
+        P=first part of ADplugin if not specified
+        R="cam1:"; other AD have "det1:"
+    """
+    kwargs.setdefault("P",ADplugin.split(":")[0]+":")
+    kwargs.setdefault("R","cam1:")
+    caput(kwargs["P"]+kwargs["R"]+"Acquire","Done",wait=True,timeout=5*60);sleep(.1)
+    caput(kwargs["P"]+kwargs["R"]+"ImageMode","Single");sleep(.5)
+    caput(ADplugin+"EnableCallbacks","Enable");sleep(.1)
+        
+def AD_FreeRun(ADplugin,**kwargs):
+    """
+    sets and AD to disable saving and free run
+        Saving -> Disable
+        Acquire -> Done
+        ImageMode -> Single
+
+        e.g. ADplugin="29id_ps2:TIFF1:"
+        
+        **kwargs:
+        P=first part of ADplugin if not specified
+        R="cam1:"; other AD have "det1:"
+    """
+    kwargs.setdefault("P",ADplugin.split(":")[0]+":")
+    kwargs.setdefault("R","cam1:")
+    caput(kwargs["P"]+kwargs["R"]+"Acquire","Done",wait=True,timeout=5*60)
+    caput(ADplugin+"EnableCallbacks","Disable");sleep(.1)
+    caput(kwargs["P"]+kwargs["R"]+"ImageMode","Continuous");sleep(.1)
+    caput(kwargs["P"]+kwargs["R"]+"Acquire","Acquire");sleep(.1)
+        
+
+def AD_snap(ADplugin,**kwargs):
+    """
+    takes an image and save the image for ADplugin
+        e.g. ADplugin="29id_ps2:TIFF1:"
+        
+    use AD_SaveFileSetup to set filepath, prefix etc.
+    use AD_CurrentDirectory to see current directory
+    use AD_prefix to see current prefix
+    
+    **kwargs:
+        P=first part of ADplugin if not specified
+        R="cam1:"; other AD have "det1:"
+        
+        ExposureTime: changes both the exposure time and the acquire time for the snapshot
+                      resets after acquisition
+        FreeRun: True => disable setting and go back to continuous acquision 
+                 False => leave saving enabled and camera in single acquision
+    """
+    kwargs.setdefault("P",ADplugin.split(":")[0]+":")
+    kwargs.setdefault("R","cam1:")
+    kwargs.setdefault("FreeRun",True)
+
+    expT=caget(kwargs["P"]+kwargs["R"]+"AcquireTime_RBV")
+    acqT=caget(kwargs["P"]+kwargs["R"]+"AcquirePeriod_RBV")
+    
+    AD_DoneSingleSave(ADplugin,**kwargs)
+    
+    if "ExposureTime" in kwargs:
+        caput(kwargs["P"]+kwargs["R"]+"AcquireTime",kwargs["ExposureTime"])
+        caput(kwargs["P"]+kwargs["R"]+"AcquireTime",kwargs["ExposureTime"]+.01)
+        
+    caput(kwargs["P"]+kwargs["R"]+"Acquire","Acquire",wait=True,timeout=5*60)
+    
+    if "ExposureTime" in kwargs:
+        caput(kwargs["P"]+kwargs["R"]+"AcquireTime",expT)
+        caput(kwargs["P"]+kwargs["R"]+"AcquireTime",acqT) 
+
+    if kwargs["FreeRun"]:
+        sleep(.1)
+        AD_FreeRun(ADplugin,**kwargs)
+        
+
+
+def AD_ScanTrigger(ADplugin,mda,**kwargs):
+    """
+    Add Triggering of AreaDetector to scanIOC
+    ADplugin = "29idc_ps1:TIFF1:" (ADplugin=$(P)$(SavePlugin))
+    
+    **kwargs
+        scanIOC = "29id"+BL_ioc() if not specified
+        scanDIM = 1
+        P=first part of ADplugin if not specified
+        R="cam1:"; other AD have "det1"
+        detTrig = 2; detectorTrigger number
+    """
+    kwargs.setdefault("scanDIM",1)
+    kwargs.setdefault("P",ADplugin.split(":")[0]+":")
+    kwargs.setdefault("R","cam1:")
+    kwargs.setdefault("detTrig",2)
+    
+    scanPV=mda.ioc+"scan"+str(kwargs["scanDIM"])    
+    trigger=".T"+str(kwargs["detTrig"])+"PV"
+    caput(scanPV+trigger,kwargs["P"]+kwargs["R"]+"Acquire",wait=True,timeout=5*60)
+    
+def ADplugin_ScanSetup(ADplugin,mda, **kwargs):
+    """
+    stop the acquisition, puts in ImageMode=Single
+    enables saving
+    add to detector trigger
+    Does not press go
+    
+    ADplugin = "29idc_ps1:TIFF1:"; (ADplugin=$(P)$(SavePlugin))
+    **kwargs
+        # AD_ScanTrigger
+        scanIOC = "29id"+BL_ioc() if not specified
+        scanDIM = 1
+        P=first part of ADplugin if not specified
+        R="cam1:"; other AD have "det1:"
+        detTrig = 2; detectorTrigger number
+        
+        # AD_SaveFileSetup
+        filepath=userpath (from BL_ioc scanRecord)+"/dtype"
+         (e.g. filepath="/net/s29data/export/data_29id"+folder+"/"+run+"/"+userName+"/"+df)
+        dtype = taken from ADplugin
+        FileTemplate="%s%s_%4.4d."+dtype; format for filename first %s = filepath, second %s = prefix
+        prefix = dtype by default
+    
+    """
+    #from AD_ScanTrigger
+    kwargs.setdefault("P",ADplugin.split(":")[0]+":")
+    kwargs.setdefault("R","cam1:")
+
+    AD_DoneSingleSave(ADplugin,**kwargs)
+    
+    AD_SaveFileSetup(ADplugin,**kwargs)
+    AD_ScanTrigger(ADplugin, **kwargs)
+    trigger=".T"+str(kwargs["detTrig"])+"PV"
+    scanPV=mda.ioc+"scan"+str(kwargs["scanDIM"])  
+    print("WARNING: you need to need to disable saving and clear the trigger by hand after the scan")
+    print("\tAD_FreeRun("+ADplugin+"); caput("+scanPV+trigger+",'')")
+
+def AD_ROI_setup(AD,ROInum,xcenter=500,ycenter=500,xsize=50,ysize=50,binX=1,binY=1):  
+    """
+    AD = "29id_ps4"
+    AD = "29iddMPA"
+    """
+    # roiNUM=1  MPA_ROI_SetUp(535,539,50,50)  center of MCP
+    
+    ADplugin=AD+':ROI'+str(ROInum)+':'
+    xstart=xcenter-xsize/2.0
+    ystart=ycenter-ysize/2.0
+    caput(ADplugin+'MinX',xstart)
+    caput(ADplugin+'MinY',ystart)
+    caput(ADplugin+'SizeX',xsize)
+    caput(ADplugin+'SizeY',ysize)
+    caput(ADplugin+'BinX',binX)
+    caput(ADplugin+'BinY',binY)
+    caput(ADplugin+'EnableCallbacks','Enable')
+    print(ADplugin+' - '+caget(ADplugin+'EnableCallbacks_RBV',as_string=True))
+    #MPA_ROI_Stats(roiNUM)
+    
+def AD_OVER_SetUp(AD,ROInum,OVERnum,linewidth=5,shape='Rectangle'):
+    """
+    AD = "29id_ps4"
+    AD = "29iddMPA"
+    shape= 'Cross', 'Rectangle', 'Ellipse','Text'
+    """
+    OVER1=AD+":Over1:"+str(OVERnum)+":"
+    ROI=AD+":ROI"+str(ROInum)+":"
+    
+    caput(ROI+'EnableCallbacks','Enable')
+    caput(OVER1+"Name","ROI"+str(ROInum))
+    caput(OVER1+"Shape",shape)
+    caput(OVER1+"Red",0)
+    caput(OVER1+"Green",255)
+    caput(OVER1+"Blue",0)
+    caput(OVER1+'WidthX',linewidth)
+    caput(OVER1+'WidthY',linewidth)
+    
+    caput(OVER1+"PositionXLink.DOL",ROI+"MinX_RBV CP")
+    caput(OVER1+"SizeXLink.DOL",ROI+"SizeX_RBV CP")
+    caput(OVER1+"PositionYLink.DOL",ROI+"MinY_RBV CP")
+    caput(OVER1+"SizeYLink.DOL",ROI+"SizeY_RBV CP")
+   
+    caput(OVER1+"Use","Yes")
+
+    
+def AD_OverLayCenter(x,y,AD,OverLay=1,Num=1):
+    """
+    Sets CenterX and CenterY for  AD:Over(OverLay):Num:
+    eg. 29id_ps2:Over1:1: AD='29id_ps2',Overlay=1, Num=1
+    """
+    caput(AD+":Over"+str(OverLay)+":"+str(Num)+":CenterX",x)
+    caput(AD+":Over"+str(OverLay)+":"+str(Num)+":CenterY",y)
+    
+def AD_OverLayCenter_get(AD,OverLay=1,Num=1):
+    """
+    Sets CenterX and CenterY for  AD:Over(OverLay):Num:
+    eg. 29id_ps2:Over1:1: AD='29id_ps2',Overlay=1, Num=1
+    """
+    print('x = '+str(caget(AD+":Over"+str(OverLay)+":"+str(Num)+":CenterX")))
+    print('y = '+str(caget(AD+":Over"+str(OverLay)+":"+str(Num)+":CenterY")))
+
+
+
+
+
diff --git a/build/lib/iexcode/instruments/ARPES.py b/build/lib/iexcode/instruments/ARPES.py
new file mode 100644
index 0000000000000000000000000000000000000000..90f825f9fa07a93d36c82263dbf7404f0ea79efd
--- /dev/null
+++ b/build/lib/iexcode/instruments/ARPES.py
@@ -0,0 +1,769 @@
+import numpy as np
+from time import sleep
+
+from epics import caget,caput,PV
+
+from iexcode.instruments.IEX_endstations import *
+from iexcode.instruments.staff import staff_detector_dictionary
+
+from iexcode.instruments.files_and_folders import check_run,make_user_folders,folder_mda
+from iexcode.instruments.staff import staff_detector_dictionary
+from iexcode.instruments.logfile import logfile_name_set,logfile_header
+
+from iexcode.instruments.conversions_constants import *
+from iexcode.instruments.utilities import *
+from iexcode.instruments.userCalcs import userStringSeq_clear, userStringSeq_pvs
+
+from iexcode.instruments.scanRecord import *
+from iexcode.instruments.Motors import *
+from iexcode.instruments.xrays import *
+from iexcode.instruments.current_amplifiers import *
+from iexcode.instruments.gate_valves import valve_close, branch_valves
+from iexcode.instruments.shutters import branch_shutter_close
+from iexcode.instruments.slits import slit3C_get
+
+from iexcode.instruments.Lakeshore_335 import Lakeshore_reset
+from iexcode.instruments.electron_analyzer import folders_EA,EA
+
+
+#############################################################################
+def ARPES_init(set_folders=True,reset=True,**kwargs):
+    """
+        kwargs:
+        set_folders: sets the mda and EA folders; default => False
+        xrays: sets global variable; default => True   
+    """
+    kwargs.setdefault('scan_ioc','29idARPES:')
+    kwargs.setdefault('xrays',True)
+    kwargs.setdefault('BL_mode','user')
+
+    #scan
+    if kwargs['BL_mode']=='staff':
+        detector_dictionary = staff_detector_dictionary()
+    else:
+        detector_dictionary = ARPES_detector_dictionary()
+    mda_scanRecord = ScanRecord(kwargs['scan_ioc'],detector_dictionary,
+    ARPES_trigger_dictionary(),ARPES_scan_before_sequence(),ARPES_scan_after_sequence())
+
+    #endstation
+    global BL
+    BL=Endstation('ARPES',kwargs['scan_ioc'],kwargs['xrays'],kwargs['BL_mode'],mda_scanRecord)
+
+    #EA
+    try: 
+        EA.get()
+    except:
+        print("\n\n NOTE: Scienta IOC is not running - start IOC and %run Macros_29id/ScanFunctions_EA.py\n\n")
+    
+    #global detectors
+    global tey,ca15
+    tey = Keithley('c',1)
+    ca15 = Keithley('b',15)
+
+    #setting folders
+    if 'set_folders':
+        if BL.mode == 'staff':
+            user_name = 'staff'
+    else:
+        user_name = input('user name: ')
+    folders_ARPES(user_name,**kwargs)
+    
+    #resetting
+    if 'reset':
+        ARPES_reset()
+
+    #motors
+    global ARPES_Motors
+    physical_motors = ['x','y','z','th','chi','phi']
+    psuedo_motors = ['focus']
+    ARPES_Motors = Motors('ARPES',ARPES_motor_dictionary(),physical_motors,psuedo_motors)
+    
+    print ('ARPES_init')
+##############################################################################################################
+##############################             ARPES detectors and motors         ##############################
+##############################################################################################################
+def ARPES_detector_list():
+    """
+    list of detectors to trigger 
+
+    Previously: part of Detector_List
+    """
+    ca_list=[["c",1],["b",15],["b",4],["b",13]]
+    return ca_list
+
+def ARPES_detector_dictionary(xrays=True):
+    """
+    returns a dictionary of the default detectors for the scan record
+
+    Previously: Detector_Default
+    """
+    det_dict={
+        14:"29idc:ca2:read",
+        16:"29idc:ca1:read",
+        17:EA._statsPlugin+"Total_RBV",
+        18:"29idARPES:LS335:TC1:IN1",
+        19:"29idARPES:LS335:TC1:IN2",
+        }
+    if xrays: 
+        det_dict.update(xrays_detector_dictionary())
+    return det_dict
+
+def ARPES_motor_dictionary():
+    """
+    returns a dictionary with  {name:[rbv,val,spmg,pv]}
+    """
+    
+    motor_nums = {'x': 1,
+      'y':2,
+      'z':3,
+      'th':4,
+      'chi':5,
+      'phi':6,
+      }
+    
+    motor_dictionary={}
+    for name in motor_nums.keys():
+        pv = '29idc:m'+str(motor_nums[name])
+        motor_dictionary.update({name:[pv+'.RBV',pv+'.VAL',pv+'.SPMG',pv]})
+
+    return motor_dictionary
+
+def ARPES_extra_pvs():
+    """
+    used to get the PV associated with a given pnuemonic
+
+    """
+    d={
+        "SES_slit":"29idc:m8.RBV",
+        "TA":"29idARPES:LS335:TC1:IN1", 
+        "TB":"29idARPES:LS335:TC1:IN2",
+        "tey1":"29idc:ca1:read",
+        "tey2":"29idc:ca2:read",
+    }
+    return d
+    
+##############################################################################################################
+##############################                 setting folder                   ##############################
+##############################################################################################################
+def folders_ARPES(user_name,**kwargs):
+    """
+    Create and sets (if create_only=False) all the folders the current run and ARPES user 
+    Sets the FileName for logging to be "UserName/YYYYMMDD_log.txt using logname_Set()"
+    
+    **kwargs:
+        set_folders = True (default); set the mda and EA scanRecords
+                    = False; only makes the folders (was create_only)
+        run: run cycle e.g. 2022_1 (default => check_run() )
+        ftp = True / False (default); print what needs to be added to the ftps crontab and create additional ftp folders
+        mda_ioc: will overwrite the default ioc for mda scans
+        debug
+           
+    """
+    kwargs.setdefault('set_folders',True)
+    kwargs.setdefault('run',check_run())
+    kwargs.setdefault('ftp',False)
+    kwargs.setdefault('debug',False)
+
+    run = kwargs['run']
+
+    if kwargs['debug']:
+        print("run,folder,user_name,ioc,ftp: ",run,BL.folder,user_name,BL.ioc,kwargs['ftp'])
+
+    # Create User Folder:
+    make_user_folders(run,BL.folder,user_name,BL.endstation,ftp=kwargs['ftp'])
+    sleep(5)
+
+    if kwargs["set_folders"]:
+        # Set up MDA folder:
+        folder_mda(run,BL.folder,user_name,BL.prefix,BL.ioc)
+        logfile_name_set(BL.endstation)
+        logfile_header(BL.endstation,BL.ioc,ARPES_log_header())
+
+        
+        #Set up Scienta folders:
+        try:
+            userPath = "/net/s29data/export/data_29id"+BL.folder+"/"+run+"/"+user_name+"/"
+            folders_EA(userPath,filePrefix="EA")
+        except:
+            print_warning_message("EA ioc is not running, cannot set folder")
+
+def ARPES_reset():
+    """
+    resets scanRecord, current amplifiers, mono limits and lakeshore
+    """
+    #resetting the scanRecord
+    BL.mda.reset()
+
+    #resetting the current amplifiers
+    if BL.xray:
+        ca_reset_all()
+    else:
+        tey.reset()
+
+    #resetting mono and anyother beamline stuff
+    if BL.xrays:
+        xrays_reset()
+
+    #reseting the ARPES Lakeshore
+    pv = "29idARPES:LS335:"
+    LS_355_defaults = {
+        "TC1:read.SCAN":".5 second",
+        "TC1:OUT1:Cntrl":"A",
+        "TC1:OUT2:Cntrl":"B",
+        "TC1:OUT1:Mode":"Closed Loop"
+    }
+    Lakeshore_reset(pv,LS_355_defaults)
+
+##############################################################################################################
+##############################                    get all                 ##############################
+##############################################################################################################
+def ARPES_get_all(verbose=True):
+    """
+    returns a dictionary with the current status of the ARPES endstation and exit slit
+    """
+    vals={}
+
+    #sample position
+    motor_dictionary = ARPES_motor_dictionary()
+    for motor in motor_dictionary.keys():
+        vals[motor]=ARPES_Motors.get(motor,verbose=False)
+        
+    #endstation pvs
+    extra_pvs = ARPES_extra_pvs()
+    for key in extra_pvs.keys():
+        vals.update(key,caget(extra_pvs[key]))
+    vals.update('exit_slit',slit3C_get())
+
+    #beamline info
+    if BL.xray:
+        beamline_info = xrays_get_all()
+        vals.update(beamline_info) 
+
+    if verbose:
+        for key in vals:
+            print(key+" = "+vals[key])
+    return vals
+
+
+
+##############################################################################################################
+##############################             logging           ##############################
+##############################################################################################################
+def ARPES_log_header():
+    header_list={
+        'EA': "scan,x,y,z,th,chi,phi,T,scan_mode,E1,E2,step,i,f,PE,lens_mode,SES slit #,hv,exit_slit,GRT,ID_SP,ID_RBV,ID_Mode,ID_QP,TEY1,TEY2,time,comment",
+        'ARPES':"scan,motor,start,stop,step,x,y,z,th,chi,phi,T,hv,exit_slit,GRT,ID_SP,ID_RBV,ID_Mode,ID_QP,TEY_1,TEY_2,time,comment"
+        }
+    return header_list
+
+def ARPES_log_entries():
+    """
+    endstation info for log file
+
+    Previously: scanlog
+    """
+    vals = ARPES_get_all(verbose=False)
+    x = vals['x']
+    y = vals['y']
+    z = vals['z']
+    th = vals['th']
+    chi = chi['chi']
+    phi = vals['phi']
+    TA = vals['TA']
+    TB = vals['TB']
+    tey1 = vals['tey1']
+    tey2 = vals['tey2']
+
+    entry_list = ["x","y","z","th","chi","phi","TA","TB","tey1","tey2"]
+    pv_list = [ x, y, z, th, chi, phi, TA, TB, tey1,tey2]  
+    format_list = [".2f",".2f",".2f",".2f",".2f",".2f",".2f",".2f","1.2e","1.2e"]
+
+    return entry_list,pv_list,format_list
+
+##############################################################################################################
+##############################             ARPES scanRecord           ##############################
+##############################################################################################################     
+def ARPES_scan_before_sequence(**kwargs):
+    """
+    writes the user string sequence to happen at the beginning of a scan
+    returns before_scan_pv = pv for userStringSeq for before scan
+
+    **kwargs
+        seq_num: userStringSeq number in ioc => 9 (default)
+
+    Previously: BeforeScan_StrSeq
+    """
+    kwargs.setdefault(seq_num,9)
+    seq_num=kwargs['seq_num']
+
+    before_scan_pv,before_scan_proc = userStringSeq_pvs(BL.ioc, seq_num)
+
+    #clear and write the before scan user sequence
+    userStringSeq_clear(BL.ioc,seq_num)
+    caput(before_scan_pv+".DESC","Before Scan")
+
+    #sequence put CAs in passive
+    ca_list = ARPES_detector_list()
+    for (i,ca) in enumerate(ca_list):
+        ca_pv = Keithley_pv(ca[0], ca[1])+':read.SCAN PP NMS'
+        caput(before_scan_pv+".LNK" +str(i+1),ca_pv)
+        caput(before_scan_pv+".STR" +str(i+1),"Passive")
+
+    return before_scan_proc
+
+def ARPES_ca_live_sequence(**kwargs):
+    """
+    """
+    kwargs.setdefault('seq_num',7)
+    ca_live_sequence_proc = ca_live_sequence(BL.ioc,kwargs['seq_num'],ARPES_detector_list())
+    return ca_live_sequence_proc
+
+def ARPES_scan_after_sequence(scan_dim, **kwargs):
+    """
+    writes the user string sequence to happen at the end of a scan
+    returns after_scan_pv = pv for userStringSeq for after scan
+
+    **kwargs
+        seq_num: userStringSeq number in ioc => 10 (default)
+        snake: for snake scanning => False (default)
+    Previously: AfterScan_StrSeq
+    """
+    kwargs.setdefault(seq_num,10)
+    kwargs.setdefault('snake',False)
+    seq_num=kwargs['seq_num']
+
+    after_scan_pv,after_scan_proc = userStringSeq_pvs(BL.ioc, seq_num)
+    
+    #clear and write the after scan user sequence
+    userStringSeq_clear(BL.ioc,seq_num)
+    caput(after_scan_pv+".DESC","After Scan")
+        
+    ## Put All relevant CA back in live mode
+    ca_live_sequence_proc = ARPES_ca_live_sequence(**kwargs)
+    caput(after_scan_pv+".LNK1",ca_live_sequence_proc+" PP NMS")
+    caput(after_scan_pv+".DO1",1)
+
+    scan_pv = BL.ioc+"scan"+str(scan_dim)
+    ## Put scan record back in absolute mode
+    caput(after_scan_pv+".LNK2",scan_pv+".P1AR")
+    caput(after_scan_pv+".STR2","ABSOLUTE")
+
+    ## Put Positionner Settling time to 0.1s
+    caput(after_scan_pv+".LNK3",scan_pv+".PDLY NPP NMS")
+    caput(after_scan_pv+".DO3",0.1)
+
+    ## Clear DetTriggers 2:
+    caput(after_scan_pv+".LNK4",scan_pv+".T2PV NPP NMS")    #remove trigger 2 (used for EA) after scan
+
+    if kwargs['snake']:
+        snake_dim = scan_dim - 1
+        #snake_proc= ARPES_snake_pv(snake_dim,enable=True)
+        #caput(after_scan_pv+".LNK10",ARPES_snake_pv()+"PP NMS")
+        #caput(after_scan_pv+".D10",1)
+
+    return after_scan_proc
+
+
+def ARPES_detector_triggers_sequence(**kwargs):    # do we need to add 29idb:ca5 ???
+    """
+    """
+    kwargs.setdefault(seq_num,8)
+    seq_num=kwargs['seq_num']
+
+    detector_triggers_pv,detector_triggers_proc = userStringSeq_pvs(BL.ioc, seq_num)
+       
+    #clear the userStringSeq
+    userStringSeq_clear(BL.ioc,seq_num=kwargs['seq_num'])
+    caput(detector_triggers_pv+".DESC","ARPES_Trigger1")
+    
+    ca_list = ARPES_detector_list
+    last = len(ca_list)
+    for i,ca in enumerate(ca_list):
+        ca_pv = Keithley_pv(ca[0], ca[1])+':read.PROC CA NMS'
+        caput(detector_triggers_pv+".LNK" +str(i+1),ca_pv)
+        caput(detector_triggers_pv+".WAIT"+str(i+1),"After"+str(last))
+
+    return detector_triggers_proc
+
+def ARPES_trigger_dictionary():
+    """
+    need to do something
+    """
+    trigger_dictionary = {
+        1:ARPES_detector_triggers_sequence(),
+    }
+    return trigger_dictionary
+
+
+##############################################################################################################
+##############################             ARPES Motor Scan Set Up        ##############################
+##############################################################################################################
+def ARPES_motor_encoder_sync():
+    ioc = "29idc:"
+    for motor in [1,2,3,4]:
+        pv = ioc+"m"+str(motor)+".SYNC"
+        caput(pv,1)
+        print("synch encoder: "+pv)
+
+
+
+
+####################################################################################################
+################    ARPES Positions (LEED,transfer, measure)    #####################################
+#####################################################################################################
+def _ARPES_DefaultPosition(destination):
+    """
+    Default ARPES positions in DIAL units
+    """
+    DefaultPosition={
+    'measure':(0.0,0.0,-13.5,0.0,0.0,0.0),
+    'LEED':(-0.0, 0.0, -141.5, 89.5, 0.0, 0.0),
+    'transfer':(-0,0.0,-141.5,180.0,0.0,0.0),
+    }
+    if destination in DefaultPosition:
+        pos=DefaultPosition[destination]
+    else:
+        pos=(None,None,None,None,None,None)
+    return pos
+
+def _ARPES_MoveSequence(destination):
+    """
+    Moves the ARPES manipulator x,y,z,th to a given destination (does not change chi or phi)
+    Resets the limits to help protect from crashes 
+        such as: phi/chi motor body into the strong back, manipulator into the LEED, manipulator into the wobble stick
+        
+    DO NOT MAKE BIG MOVE WITH OUT WATCHING THE MANIPULATOR!!!! 
+        if the theta encoder stops reading the manipulator will CRASH!!!!
+    """
+    (x,y,z,th,chi,phi)=_ARPES_DefaultPosition(destination)
+    motor_dictionary = ARPES_motor_dictionary()
+    if x is None:
+        print("Not a valid destination")
+    else:
+        #reset limits to default values
+        _ARPES_limits_set(None)
+        #print destination
+        print(("Moving to "+destination+": "+str(round(x,1))+","+str(round(y,1))+","+str(round(z,1))+","+str(round(th,1)))+'     Time:'+time.strftime("%H:%M"))
+        # move x and y to zero for all moves (helps protect the motors from crashing into the strong back)
+        caput(motor_dictionary['x'][3]+".DVAL",0,wait=True,timeout=18000)
+        caput(motor_dictionary['y'][3]+".DVAL",0,wait=True,timeout=18000)
+        # moves z and th simultaneously and monitors the .DMOV
+        caput(motor_dictionary['z'][3]+".DVAL",z,wait=False,timeout=18000)
+        caput(motor_dictionary['th'][3]+".DVAL",th,wait=False,timeout=18000)
+        while True:
+            sleep(5)
+            Test=caget(motor_dictionary['z'][3]+".DMOV")*caget(motor_dictionary['th'][3]+".DMOV")
+            if(Test==1):
+                break
+        # move x and y to final position
+        caput(motor_dictionary['x'][3]+".DVAL",x,wait=True,timeout=18000)
+        caput(motor_dictionary['y'][3]+".DVAL",y,wait=True,timeout=18000)
+        print(("Arrived at "+destination+": "+str(round(x,1))+","+str(round(y,1))+","+str(round(z,1))+","+str(round(th,1)))+'     Time:'+time.strftime("%H:%M"))
+        #set the limits for this position
+        _ARPES_limits_set(destination)
+
+def _ARPES_limits_set(destination):
+    """
+    Resets the ARPES motor limits in Dial cooridinates(remember that z is negative)
+        destination: 'measures' or 'LEED',
+        else: sets to the full range
+    ARPES_MoveSequence(destination) minimizes that chance of a crash and sets limits
+
+    Previously: ARPES_LimitsSet
+    """
+    motor_dictionary = ARPES_motor_dictionary()
+    if destination == 'measure':
+        (x,y,z,th,chi,phi)=_ARPES_DefaultPosition("measure")
+        limits={'x':[5.5,-7],'y':[7,-5],'z':[-6,-310],'th':[th+35,th-25],'chi':[45,-15],'phi':[120,-120]}
+    elif destination == 'LEED':
+        (x,y,z,th,chi,phi)=_ARPES_DefaultPosition("LEED")
+        limits={'x':[5.5,-7],'y':[6,-1],'z':[z+5,z-5],'th':[th+2,th-2],'chi':[45,-15],'phi':[120,-120]}
+    else:
+        limits={'x':[5.5,-7],'y':[7,-5],'z':[-6,-310],'th':[240,-70],'chi':[45,-15],'phi':[120,-120]}
+    #setting the limits for each motor in Dial
+    for m in limits:
+        caput(motor_dictionary[m][3]+'.DHLM',limits[m][0])
+        caput(motor_dictionary[m][3]+'.DLLM',limits[m][1])
+    if destination is not None:
+        print("Limits have been reset for "+destination+" position")
+    else:
+        print("Limits have been reset for full range")
+####################################################################################################
+def ARPES_transfer(chi=0,phi=0,**kwargs):
+    """
+    Moves the ARPES manipulator to the default transfer position
+    kwargs:
+        EA_HV_Off=True; Turns off the EA HV
+        Close_CBranch=True;  closes the C-shutter and the C-valve (main chamber to BL)
+    """
+    ARPESgo2("transfer",**kwargs)
+
+def ARPES_measure(**kwargs):
+    """
+    Moves to ARPES motors x,y,z,th to the default measurement position
+    kwargs
+        chi=None # specify a value to move chi
+        phi=None # specifiy a value to move phi
+    """
+    ARPESgo2("measure",**kwargs)
+
+def ARPES_LEED(**kwargs):
+    """
+    Moves to ARPES motors x,y,z,th to the default LEED position
+    kwargs:
+        EA_HV_Off=True; Turns off the EA HV
+        Close_CBranch=True;  closes the C-shutter and the C-valve (main chamber to BL)
+        
+        chi=None # specify a value to move chi
+        phi=None # specifiy a value to move phi
+    """
+    ARPESgo2("LEED",**kwargs)    
+####################################################################################################
+def ARPESgo2(destination,**kwargs):
+    """
+    Moves the ARPES manipulator to the default position: 
+    destination: "transfer", "measure", "LEED"
+
+    kwargs:
+        EA_off = True; turns off EA HV
+        shutter_close = True; closes the C-shutter
+        valve_close = True; closes the C-valve
+        
+        chi=None => doesn't move, otherwise specify a value to move chi
+        phi=None => doesn't move, otherwise specifiy a value to move phi 
+
+    """
+
+
+    kwargs.setdefault("EA_off",True)
+    kwargs.setdefault("shutter_close",True)
+    kwargs.setdefault("valve_close",True)
+
+    kwargs.setdefault("chi",None)
+    kwargs.setdefault("phi",None)
+    
+    ARPES_safe_state(**kwargs)
+    
+    #Move x,y,z,th
+    _ARPES_MoveSequence(destination)
+    #Move chi and phi back to 0
+    motor_dictionary = ARPES_motor_dictionary()
+    if kwargs["chi"] is not None:
+        caput(motor_dictionary['chi'][1],kwargs["chi"])
+    if kwargs["phi"] is not None:
+        caput(motor_dictionary['phi'][1],kwargs["phi"])
+
+
+##############################################################################################################
+##############################             ARPES pvs for GUIs (caQtDM)        ##############################
+##############################################################################################################
+def ARPES_StringCalc_trigger2_active():
+    """
+    setup a string calc to be used by caQtDM to indicate that the trigger 2 is filled
+    """
+    ioc="29idARPES:"
+    pv=ioc+"userStringCalc2"
+    caput(pv+".DESC","scan1 trigger2 calc")
+    caput(pv+".INAA",ioc+"scan1.T2PV CP NMS")
+    caput(pv+".CALC$","AA")
+    
+    caput(ioc+"userStringCalcEnable.VAL","Enable")
+
+
+
+##############################################################################################################
+##############################             ARPES safestate        ##############################
+##############################################################################################################
+def ARPES_safe_state(**kwargs):
+    """
+    puts the C-branch in a safe state, 
+    **kwargs
+        EA_off = True; turns off EA HV
+        shutter_close = True; closes the C-shutter
+        valve_close = True; closes the C-valve
+    """
+    kwargs.setdefault("EA_off",True)
+    kwargs.setdefault("shutter_close",True)
+    kwargs.setdefault("valve_close",True)
+    
+    if kwargs["EA_off"]:
+        try:
+            EA.off(quiet=False)
+        except:
+            print('EA is not running, visually confirm HV is off')
+
+    if kwargs['valve_close']:
+       valve_close(branch_valves('c'), verbose=True)
+
+    if kwargs['shutter_close']:
+        branch_shutter_close('c')
+
+##############################################################################################################
+##############################              ARPES motors       ##############################
+##############################################################################################################
+### x ###
+def mvx(val,**kwargs):
+    """ moves x motor in the endstation"""
+    ARPES_Motors.move('x',val,**kwargs)
+
+def dmvx(val):
+    """ relative x motor in the endstation"""
+    ARPES_Motors.move('x',val,relative=True)
+
+def scanx(start,stop,step,**kwargs):
+    """ scans the x motor in the endstation"""
+    ARPES_Motors.scan("x",start,stop,step,**kwargs)
+
+def dscanx(start,stop,step):
+    """relative scans of the x motor in the endstation """
+    ARPES_Motors.scan("x",start,stop,step,relative=True)
+
+### y ###
+def mvy(val,**kwargs):
+    """ moves y motor in the endstation"""
+    ARPES_Motors.move('y',val,**kwargs)
+
+def dmvy(val):
+    """ relative y motor in the endstation"""
+    ARPES_Motors.move('y',val,relative=True)
+
+def scany(start,stop,step,**kwargs):
+    """ scans the y motor in the endstation"""
+    ARPES_Motors.scan("y",start,stop,step,**kwargs)
+
+def dscany(start,stop,step):
+    """relative scans of the y motor in the endstation """
+    ARPES_Motors.scan("y",start,stop,step,relative=True)
+
+### z ###
+def mvz(val,**kwargs):
+    """ moves z motor in the endstation"""
+    ARPES_Motors.move('z',val,**kwargs)
+
+def dmvz(val):
+    """ relative z motor in the endstation"""
+    ARPES_Motors.move('z',val,relative=True)
+
+def scanz(start,stop,step,**kwargs):
+    """ scans the z motor in the endstation"""
+    ARPES_Motors.scan("z",start,stop,step,**kwargs)
+
+def dscanz(start,stop,step):
+    """relative scans of the z motor in the endstation """
+    ARPES_Motors.scan("z",start,stop,step,relative=True)
+
+### th ###
+def mvth(val,**kwargs):
+    """ moves th motor in the endstation"""
+    ARPES_Motors.move('th',val,**kwargs)
+
+def dmvth(val):
+    """ relative th motor in the endstation"""
+    ARPES_Motors.move('th',val,relative=True)
+
+def scanth(start,stop,step,**kwargs):
+    """ scans the th motor in the endstation"""
+    ARPES_Motors.scan("th",start,stop,step,**kwargs)
+
+def dscanth(start,stop,step):
+    """relative scans of the th motor in the endstation """
+    ARPES_Motors.scan("th",start,stop,step,relative=True)
+
+### chi ###
+def mvchi(val,**kwargs):
+    """ moves chi motor in the endstation"""
+    ARPES_Motors.move('chi',val,**kwargs)
+
+def dmvchi(val):
+    """ relative chi motor in the endstation"""
+    ARPES_Motors.move('chi',val,relative=True)
+
+def scanchi(start,stop,step,**kwargs):
+    """ scans the chi motor in the endstation"""
+    ARPES_Motors.scan("chi",start,stop,step,**kwargs)
+
+def dscanchi(start,stop,step):
+    """relative scans of the chi motor in the endstation """
+    ARPES_Motors.scan("chi",start,stop,step,relative=True)
+
+### phi ###
+def mvphi(val,**kwargs):
+    """ moves phi motor in the endstation"""
+    ARPES_Motors.move('phi',val,**kwargs)
+
+def dmvphi(val):
+    """ relative phi motor in the endstation"""
+    ARPES_Motors.move('phi',val,relative=True)
+
+def scanphi(start,stop,step,**kwargs):
+    """ scans the phi motor in the endstation"""
+    ARPES_Motors.scan("phi",start,stop,step,**kwargs)
+
+def dscanphi(start,stop,step):
+    """relative scans of the phi motor in the endstation """
+    ARPES_Motors.scan("phi",start,stop,step,relative=True)
+
+
+def mvfocus(x_val):
+    """ 
+    Moves APPES x and compensates y motor so that the beam stays in the same sample position but the focus is moved
+    """
+    x_delta = x_val - ARPES_Motors.get('x')
+    y_delta = x_delta * np.tan(55/180*np.pi)
+    y_val =  ARPES_Motors.get('y') + y_delta
+    
+    ARPES_Motors.move("x",x_val)
+    ARPES_Motors.move("y",y_val)
+
+    return x_val,y_val
+
+def mvy_fixed_focus(y_val):
+    """ 
+    Moves APPES x and compensates y motor so that the beam stays in the same sample position but the focus is moved
+    """  
+    y_delta = y_val - ARPES_Motors.get('y')
+    x_delta = y_delta / np.tan(55/180*np.pi)
+    x_val =  ARPES_Motors.get('x') + x_delta
+
+    ARPES_Motors.move("x",x_val)
+    ARPES_Motors.move("y",y_val)
+    return x_val,y_val
+
+def scanfocus(x_start,x_stop,x_step,**kwargs):
+    """
+    Scans APPES x and compensates y motor so that the beam stays in the same sample position
+    y=x*tan(55)
+
+    kwargs:
+        execute: True/False to start the scan => True (default)
+    """
+    kwargs.setdefault('execute',True)
+
+   
+
+def ARPES_sample_map2D(step_y=0.5,step_z=0.5):
+    """
+    2D map of sample area in ARPES chamber
+
+    Previously: Map_ARPES_Sample
+    """
+    print("Scan_ARPES_2Dmotor(\"y\",0,4,"+str(step_y)+",\"z\",12,16,"+str(step_z)+")")
+    ARPES_Motors.scan2D(["y",0,4,step_y],["z",12,16,step_z])
+
+
+######## mprint and mvsample ###################
+def mprint():
+    """
+    prints current position of the physical motors
+    """
+    ARPES_Motors.mprint()
+
+def mvsample(position_list):
+    """
+    moves the sample to the position sepcified by position_list
+    position_list = ['description',x,y,z,th,chi,phi]
+
+    Previously: sample
+    """
+    ARPES_Motors.mvsample(position_list)
+
diff --git a/build/lib/iexcode/instruments/FMB_mirrors.py b/build/lib/iexcode/instruments/FMB_mirrors.py
new file mode 100644
index 0000000000000000000000000000000000000000..888d9b9425b99a75ac9d39dcac6447fafe0680f7
--- /dev/null
+++ b/build/lib/iexcode/instruments/FMB_mirrors.py
@@ -0,0 +1,174 @@
+from time import sleep
+
+from epics import caget, caput
+
+from iexcode.instruments.IEX_endstations import *
+from iexcode.instruments.utilities import read_dict, print_warning_message
+from iexcode.instruments.m3r import m3r_branch
+
+M0M1_fpath="/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/Dict_IDCal.txt"
+
+
+def FMB_mirror_ioc(mirror_num):
+    """
+    returns the ioc name for the given mirror number: 
+    miror_num = 0 / 1 / 3  for M0 / M1 /M3R respectively
+    """
+    ioc = '29id_'+['M0','M1','','M3R'][mirror_num]+":"
+    return ioc
+
+def FMB_mirror_status(mirror_num):
+    """
+    returns the ioc name for the given mirror number: 
+    miror_num = 0 / 1 / 3  for M0 / M1 /M3R respectively
+
+    status =1 when positioned
+    """
+    ioc = '29id_'+['M0','M1','','M3R'][mirror_num]+":"
+    pv = FMB_mirror_ioc(mirror_num)
+    status=caget(pv+'SYSTEM_STS')
+
+    return status
+
+def FMB_mirror_axis_position(mirror_num,axis, verbose=True):
+    """
+    returns the readback and set point of an FMB mirror
+    """
+    pv = FMB_mirror_ioc(mirror_num)
+  
+    rbv = round(caget(pv+axis+"_MON"),3)
+    sp = round(caget(pv+axis+"_POS_SP"),3)
+
+    if verbose:
+        print (pv+axis+": "+str(rbv))
+    
+    return rbv,sp
+
+def FMB_mirror_get(mirror_num,verbose=True):
+    """
+    get and returns the current mirror position 
+    """
+    axis_labels=['Tx','Ty','Tz','Rx','Ry','Rz']
+    vals=[]
+    message = "\nM"+str(mirror_num)+" @ "
+    for axis in axis_labels:
+        rbv,sp = FMB_mirror_axis_position(mirror_num,axis, verbose=False)
+        vals.append(rbv)
+        message =+ "%.3f"+"/" % rbv 
+    if verbose:
+        print(message)
+        if mirror_num == 3:
+            mirror_branch = m3r_branch()
+            print(" => In "+mirror_branch+" branch")
+    return vals
+
+def FMB_mirror_move(mirror_num,axis,val,verbose=True):
+    """
+    miror_num = 0 / 1 / 3  for M0 / M1 /M3R respectively
+    and axis:
+        TX = lateral                 RX = Roll
+        TY = vertical                RY = Pitch
+        TZ = longitudinal            RZ = Yaw
+
+    "Previously: Move_M0M1
+    """  
+    pv = FMB_mirror_ioc(mirror_num)
+    axes = ['TX','TY','TZ','RX','RY','RZ']
+    if axis in axes:
+        caput(pv+axis+"_SP.PREC",3)  
+        caput(pv+axis+"_POS_SP")
+        caput(pv+"MOVE_CMD.PROC",1,wait=True,timeout=18000)
+        while True:
+            if FMB_mirror_status != 1:
+                sleep(.5)
+            else:
+                break
+        FMB_mirror_axis_position(mirror_num,axis,verbose=verbose)
+            
+    else:
+        print_warning_message(axis+' is not a valid axis chose '+axes)
+
+def FMB_mirror_move_all(mirror_num,position_list,verbose=True):
+    """
+    miror_num = 0 / 1 / 3  for M0 / M1 /M3R respectively
+    position_list = [TX,TY,TZ,RX,RY,RZ]
+
+    "Previously: Move_M0M1
+    """  
+    pv = FMB_mirror_ioc(mirror_num)
+    for axis in ['TX','TY','TZ','RX','RY','RZ']:
+        caput(pv+axis+"_SP.PREC",3)  
+        caput(pv+axis+"_POS_SP")
+    caput(pv+"MOVE_CMD.PROC",1,wait=True,timeout=18000)
+    while True:
+        if FMB_mirror_status != 1:
+            sleep(.5)
+        else:
+            break
+    FMB_mirror_axis_position(mirror_num,axis,verbose=verbose)
+    
+
+def FMB_mirror_tweak(mirror_num,axis,val,verbose=False):
+    """
+    miror_num = 0 / 1 / 3  for M0 / M1 /M3R respectively
+    and axis:
+        TX = lateral                 RX = Roll
+        TY = vertical                RY = Pitch
+        TZ = longitudinal            RZ = Yaw
+
+    "Previously: Move_M0M1
+    """
+    pv = FMB_mirror_ioc(mirror_num)
+    previous_position = FMB_mirror_axis_position(mirror_num,axis,verbose=False)
+    new_position = previous_position[0] + val
+    FMB_mirror_move(mirror_num,axis,new_position,verbose=False)
+
+    if verbose:
+     print(pv+" "+str(previous_position[0])+" -> "+str(new_position[0]))
+
+
+def FMB_mirror_scan(mirror_num,start,stop,step):
+    """
+    e.g. Scan_FMB_mirror("m1:TX",-5,5,.25)
+
+        TX = lateral                 RX = Yaw
+        TY = vertical                RY = Pitch
+        TZ = longitudinal            RZ = Roll
+    """
+    pv = FMB_mirror_ioc(mirror_num)
+    
+    # database sets .PREC==0.  We want more digits than that.
+    caput(pv+"_SP.PREC",3)
+    mda.fillin(pv+"_SP",pv+"_MON",start,stop,step)
+
+
+
+
+def M0M1_table(run,mirror):
+    """
+    Prints the positions TX / TY / TZ / RX / RY / RZ for either Mirror = 0 or 1 (M0 or M1) for the specified Run
+    Run='default' give a reasonable starting position after homing
+    M0M1_SP() will put those values as the set points, you will need to push the Move button
+    """
+    M0M1_Pos=read_dict(M0M1_fpath)
+    return M0M1_Pos[run][mirror[-1]]
+
+def M0M1_SP(run,mirror,Go=False):
+    """
+    Gets the values from the mirror position from a previous run and
+    put values as defined by M0M1_Table as the set points
+    Go = True / False (default); True to moves to that position
+    """
+    mirror_pos=M0M1_table(run,mirror).split('/')
+    motor=['TX','TY','TZ','RX','RY','RZ']
+    mirror=mirror[-1]
+    for i in range(len(motor)):
+        PV="29id_m"+str(mirror)+":"+motor[i]+"_POS_SP"
+        Val=mirror_pos[i] #float(MirrorPos[i])
+        print(PV+" = "+Val)
+        caput(PV,Val)
+    sleep(0.5)
+    if Go:
+        caput('29id_m'+str(mirror)+':MOVE_CMD.PROC',0,wait=True,timeout=18000)
+    else:
+        print(" caput(\'29id_m"+str(mirror)+":MOVE_CMD.PROC\',0)")
diff --git a/build/lib/iexcode/instruments/IEX_VPU.py b/build/lib/iexcode/instruments/IEX_VPU.py
new file mode 100644
index 0000000000000000000000000000000000000000..6678eb16903a7372b42583b5b4cfae682fa56a56
--- /dev/null
+++ b/build/lib/iexcode/instruments/IEX_VPU.py
@@ -0,0 +1,528 @@
+
+
+from math import *
+from time import sleep
+import numpy.polynomial.polynomial as poly
+
+from epics import caget, caput
+
+from iexcode.instruments.utilities import dateandtime, print_warning_message, read_dict
+from iexcode.instruments.shutters import main_shutter_check_open
+from iexcode.instruments.VLS_PGM import mono_grating_get
+from iexcode.instruments.userCalcs import userCalcOut_clear
+
+IDcal_fpath="/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/Dict_IDCal.txt"
+
+##############################################################################################################
+################################             ID limits and calibration             ##############################
+##############################################################################################################
+
+def ID_calc_SP(mono_grating,ID_mode,hv_eV):    # Mode = state (0=RCP,1=LCP,2=V,3=H)
+    """Calculate the ID SP for a given polarization mode and energy;
+    with Mode = 0 (RCP),1 (LCP), 2 (V), 3 (H)
+    
+    Previously: ID_Calc
+    """
+    
+    
+    if type(ID_mode)== str:
+        ID_state=ID_state_mode()[ID_mode]
+    try:
+        K=ID_Coef(mono_grating,ID_mode,hv_eV)
+        ID=poly.polyval(hv_eV,K)
+    except KeyError:
+        message_string='Not a valid ID mode!'+"\nValid Modes: "+str(ID_mode_list)
+        print_warning_message(message_string)
+        ID=caget("ID29:EnergySeteV")
+    return round(ID,1)
+
+##############################################################################################################
+################################             ID Functions             ##############################
+##############################################################################################################
+
+
+def ID_wait_for_permission():
+    """
+    Monitors the ID permissions and waits for the ID to be in User Mode and then breaks
+    Checks the status every 30 seconds
+
+    Previously: WaitForPermission
+    """
+    while True:
+        ID_Access=caget("ID29:AccessSecurity.VAL")
+        if (ID_Access!=0):
+            print("Checking ID permission, please wait..."+dateandtime())
+            sleep(30)
+        else:
+            print("ID now in user mode -"+dateandtime())
+            break
+
+##############################################################################################################
+def ID_get_all(verbose=False):
+    """ 
+    returns dictionart with: ID_Mode, ID_QP_ratio, ID_SP, ID_RBV
+
+    Previously: Get_energy
+    """
+    vals={    
+        "ID_mode":ID_mode_get(verbose=False),
+        "ID_QP_ratio":ID_QP_ratio_get(verbose=False),
+        "ID_sp":ID_SP_get_eV(verbose=False),
+        "ID_rbv":ID_rbv_get_eV(verbose=False)
+    }
+
+    if verbose:
+        print(" ID SP  : "+"%.2f" % vals["ID_sp"] , "eV    ID mode : "+vals["ID_mode"])
+        print(" ID RBV : "+"%.2f" % vals['ID_rbv'], "eV    QP mode : "+str(vals['ID_QP_ratio']) +" %")
+    return vals
+
+def ID_energy_range(ID_mode=None):  
+    """
+    Returns the ID_min_SP, ID_max_SP for a given ID mode
+    
+    Previously: ID_Range
+    """
+    if ID_mode == None:
+        ID_state=caget("ID29:ActualMode")
+    else:
+        ID_state = ID_state_mode(ID_mode)
+    #       RCP,LCP, V , H , HN
+    ID_min_SP = [400,400,440,250,250]
+    ID_max_SP = 3800
+    #hv_min=[390,390,430,245,245]
+
+    return ID_min_SP[ID_state],ID_max_SP
+
+def ID_mode_list():
+    """
+    returns the ID_mode_List
+    current mode = 
+    """
+    return ["RCP", "LCP", "V", "H", "HN"]
+
+
+def ID_state_mode(ID_mode):
+    """ 
+    Returns the state number if mode is a string 
+    Returns the mode string if mode is an int or float
+
+    Previously: ID_State2Mode(which,mode)
+    """
+    try:
+        ID_mode = ID_mode.upper()
+        ID_state =ID_mode_list()[ID_mode].index(ID_mode)
+        return ID_state
+
+    except:
+        message_string='Not a valid ID mode!'+"\nValid Modes: "+str(ID_mode_list)
+        print_warning_message(message_string)
+
+def ID_state_get():
+    """
+    Returns the current ID state
+    """
+    ID_state = caget("ID29:ActualMode")
+
+def ID_mode_get(verbose=True):
+    """
+    Returns the current ID mode
+    """
+    ID_state = caget("ID29:ActualMode")
+    ID_mode = ID_mode_list()[ID_state]
+
+    if verbose:
+        print('ID mode: '+ID_mode)
+    return ID_mode
+
+def ID_mode_set(ID_mode):
+    """
+    writes the desired mode to the correct ID pv
+    """
+    caput("ID29:DesiredMode.VAL",ID_mode,wait=True,timeout=18000)     # RCP
+
+
+def ID_ready(verbose=True):
+    """
+    check both the read and busy pv every 2 seconds
+
+    Previously: ID_Ready
+    """
+    while True:
+        RBV=caget("ID29:Energy.VAL")
+        checkready=caget("ID29:feedback.VAL")
+        checkbusy=caget("ID29:BusyRecord")
+        if (checkready!="Ready") or (RBV < 3.7):
+            sleep(2)
+        elif ((checkready=="Ready") and (RBV > 3.7)) and (checkbusy=="Busy"):
+            caput("ID29:Busy.VAL",0)
+        else:
+            break
+    if verbose:
+        print("ID Ready")       
+
+def ID_stop(verbose=True):
+    """
+    waits for the ID to be in user mode and then turns it off
+
+    Previously: ID_Stop
+    """
+    ID_wait_for_permission()
+    caput("ID29:Main_on_off.VAL",1,wait=True,timeout=18000)
+
+    sleep(5)
+    if verbose:
+        print("ID is now off")
+
+
+def ID_off():
+    """
+    calls ID_stop
+    """
+    ID_stop()
+
+
+def ID_start(ID_mode='RCP'):
+    """
+    waits for ID permission and then 
+    starts ID with a specific polarization
+    mode = \"H\", \"V\", \"RCP\" or \"LCP\"
+
+    """
+    
+    ID_wait_for_permission()
+    #turning on the ID; default mode = RCP
+    print("Starting ID  -  "+dateandtime())
+    caput("ID29:EnergySet.VAL",3.8)
+    caput("ID29:Main_on_off.VAL",0,wait=True,timeout=18000)
+    ID_ready()
+    ID_mode_set(ID_mode)
+   
+    ID_wait_for_permission()
+    main_shutter_check_open()
+
+    print('ID is now on, please set your energy')
+
+def ID_switch_mode(ID_mode):
+    """
+    Change ID polarization; which = 'H', 'V', 'RCP' or 'LCP'
+        if ID_mode = current mode then does nothing
+
+    WARNING: Does not set the energy
+
+    Previously Switch_IDMode
+    """
+    ID_wait_for_permission()
+    main_shutter_check_open()
+    ID_state = ID_state_get()
+
+    try:
+        if ID_state_mode(ID_mode) != ID_state:
+            print("Turning ID off...")
+            ID_stop(verbose=True)
+            sleep(10)
+            
+            print("Switching ID mode, please wait...")
+            ID_mode_set(ID_mode) 
+            ID_ready()
+        print("ID Mode:",ID_mode)
+    except:
+        print_warning_message("Not a valid ID mode")
+
+def ID_SP_get(verbose=False):
+    """
+    returns the ID setpoint in keV
+    """
+    ID_SP = caget("ID29:EnergyScanSet.VAL")
+    if verbose:
+        print("ID_SP: ", ID_SP)
+    return ID_SP
+
+def ID_SP_get_eV(verbose=False):
+    """
+    returns the ID setpoint in eV
+    """
+    ID_SP = ID_SP_get(verbose=False)
+    if verbose:
+        print("ID_SP: ", ID_SP)
+    return ID_SP
+
+def ID_rbv_get(verbose=False):
+    """
+    returns the readback value for the 
+    """
+    ID_RBV = caget("ID29:EnergyRBV")
+    if verbose:
+        print("ID_RBV: ", ID_RBV)
+    return ID_RBV  
+
+def ID_rbv_get_eV(verbose=False):
+    """
+    returns the readback value for the 
+    """
+    ID_RBV = ID_rbv_get(verbose=False)
+    if verbose:
+        print("ID_RBV: ", ID_RBV)
+    return ID_RBV 
+
+def ID_restart():
+    """
+    turns off the ID and turns it back on with the same set point
+    
+    Previously: ID_Restart
+    """
+    ID_mode=ID_mode_list[ID_state_get()]
+    hv=ID_SP_get_eV(verbose=False)
+
+    print("Restarting ID", dateandtime())
+    ID_stop(verbose=False)
+    ID_ready(verbose=False)
+  
+    ID_start(verbose=False)
+    
+    print("ID is back ON", dateandtime())
+    ID_SP_set(hv)
+
+def ID_SP_set(hv_eV,verbose=True):
+    """
+    "Sets the ID set point to a specific value (hv(eV)) which will not likely be optimum"
+
+    Previously: SetID_Raw
+    """
+    ID_wait_for_permission()
+    main_shutter_check_open()
+
+    ID_max,ID_min = ID_energy_range()
+    ID_SP=min(max(hv_eV,ID_min),ID_max)*1.0
+    
+    if hv_eV < ID_min or hv_eV > ID_max:
+        message_string="Set point out of BL energy range \nPlease select a different energy."
+        print_warning_message(message_string)
+    else:
+        ID_SP_RBV=round(caget("ID29:EnergySet.VAL"),3)*1000
+        if ID_SP == ID_SP_RBV:                # checks if ID is already at the SP energy
+            ID_RBV=caget("ID29:EnergyRBV")
+            if verbose:
+                print("ID SET : "+"%.1f" % ID_SP, "eV")
+                print("ID RBV : "+"%.1f" % ID_RBV, "eV")
+                print(caget('ID29:TableDirection',as_string=True))
+        else:
+            caput("ID29:EnergyScanSet.VAL",ID_SP/1000,wait=True,timeout=18000)
+            sleep(0.5)
+            caput("ID29:EnergyScanSet.VAL",(ID_SP+0.001)/1000,wait=True,timeout=18000)
+            caput('ID29:StartRamp.VAL',1)
+            
+            sleep(5)
+            ID_ready(verbose=False)
+            
+            ID_RBV=caget("ID29:EnergyRBV")
+            print("\nID SET : "+"%.1f" % ID_SP, "eV") 
+            print("ID RBV : "+"%.1f" % ID_RBV, "eV")
+            print(caget('ID29:TableDirection',as_string=True))
+
+            ID_diff = abs(ID_RBV-ID_SP)
+            ID_bw = ID_SP*0.095
+            if ID_diff > ID_bw:
+                sleep(20)
+                ID_RBV=caget("ID29:EnergyRBV")
+                ID_diff = abs(ID_RBV-ID_SP)
+                print("\nID RBV : "+"%.1f" % ID_RBV, "eV")
+                if ID_diff > ID_bw:
+                    ID_restart
+
+def ID_energy_set(hv_eV):
+    """
+    Sets optimum ID set point for hv(eV) (max intensity)
+    and opens the main shutter
+
+    Note that QP is generally not calibrated
+
+    Previously: SetID
+    """
+    ID_mode = ID_mode_list[ID_state_get()]
+    mono_grating = mono_grating_get()
+    ID_SP = ID_calc_SP(mono_grating,ID_mode,hv_eV)
+   
+    ID_SP(hv_eV)
+
+    
+def ID_QP_ratio_get(verbose=True):
+    """
+    gets the read back for the QP ratio
+    calculate the QP ratio
+
+    
+    """
+    Byq=caget("ID29:ByqRdbk")
+    Vcoil=caget("ID29:ByRdbk.VAL")
+    ratio_calc=Byq/Vcoil
+    ratio_RBV=caget("ID29:QuasiRatio.RVAL")
+    if verbose:
+        print("QP ratio =", round(ratio_RBV,3)*100,"%")
+        print("QP RBV   =", ratio_RBV,"%")
+
+    if abs(ratio_RBV-ratio_calc)>1:
+        message_string="QP RBV and QP calc do not agree \nCheck Interlocks"
+        print_warning_message(message_string)
+    return ratio_RBV, ratio_calc
+
+def ID_QP_mode_set(ID_mode,QP_ratio):
+    """
+    switched to QP mode, if not currently in
+    sets the QP ratio (QP ration min is 70) and polarization (ID mode)
+
+    does not set the energy, need to use ID_SP
+
+    Previously: Switch_IDQP
+    """
+    QP_min = 70
+    if QP_ratio < QP_min:
+        message_string="QP ratio is too small, setting it to minimum allowed value ("+str(QP_min)+")"
+        print_warning_message(message_string)
+    QP_ratio=max(70,QP_ratio)
+    
+    ratio_RBV, ratio_calc=ID_QP_ratio_get()
+    if ratio_RBV != QP_ratio:
+        ID_stop()
+        caput("ID29:QuasiRatioIn.C",QP_ratio)
+    
+    ID_start(ID_mode)
+    sleep(15)
+
+    Byq=caget("ID29:ByqRdbk")
+    Vcoil=caget("ID29:ByRdbk.VAL")
+    ratio=Byq/Vcoil
+    ratio_RBV=caget("ID29:QuasiRatio.RVAL")
+    print("QP ratio =", round(ratio,3)*100,"%")
+    print("QP RBV   =", ratio_RBV,"%")
+    sleep(15)
+
+def ID_Coef(grt,ID_mode,hv_eV):    # Mode = state (0=RCP,1=LCP,2=V,3=H); 
+    
+    """Return the ID coeff for a given polarization mode and energy;
+    with Mode = 0 (RCP),1 (LCP), 2 (V), 3 (H).
+    Current coefficient dictionary:
+        /home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/Dict_IDCal.txt
+    
+    Previously: ID_Coef
+    """
+
+    def ListRange(grt,ID_mode,IDdict):  # extract the list of break pts for a given mode/grt 
+        tmp_list=[]
+        for item in (IDdict[grt][ID_mode]):
+            tmp_list.append(item[0])  
+        return tmp_list
+
+
+    def FindRange(hv_eV,range_list):         # returns the index for the corresponding range
+        B = [x - hv_eV for x in range_list]
+        #print(B)
+        index = [i for (i, x) in enumerate(B) if x > 0]
+        #print(index)
+        return(index[0])
+    
+    try:
+        ID_function=read_dict(IDcal_fpath)
+    
+    except KeyError:
+        print("Unable to read dictionary") 
+        
+    try:   
+        Lrange = ListRange(grt,ID_mode,ID_function)
+        Erange = FindRange(hv_eV,Lrange)
+        K = ID_function[grt][ID_mode][Erange][1]
+        return K
+        
+    except KeyError:
+        print("WARNING: PLease select one of the following:")
+        print("        mode 0 = RCP")
+        print("        mode 1 = LCP")
+        print("        mode 2 = V")
+        print("        mode 3 = H")
+
+def ID_scan_pvs():
+    """ 
+    returns the rbv and val for scanning 
+    """
+    val_pv="ID29:EnergyScanSeteV"
+    rbv_pv="ID29:EnergySetRBV"
+    return val_pv, rbv_pv
+
+def ID_scan_fillin(mda,scan_dim,start,stop,step,**kwargs):
+    """
+    fills in the scanRecord for scanning the ID set point
+
+    **kwargs => scanRecord.fillin kwargs
+    """
+    #Setting up the ScanRecord for ID in Table mode
+    val_pv, rbv_pv = ID_scan_pvs()
+    mda.fillin(scan_dim,val_pv,rbv_pv,start,stop,step,**kwargs)
+
+
+def ID_scan_fillin_table(mda,scan_dim,ID_array,**kwargs):
+    """
+    fills in the scanRecord for scanning the ID set point
+
+    **kwargs => scanRecord.fillin kwargs
+    """
+    #Setting up the ScanRecord for ID in Table mode
+    val_pv, rbv_pv = ID_scan_pvs()
+    mda.fillin.table(scan_dim,val_pv,rbv_pv,ID_array,**kwargs)
+
+##############################################################################################################
+##############################             ID direction table        ##############################
+##############################################################################################################
+
+def ID_Table():
+    """
+
+    Previously: ID_Table
+    """
+    table = caget("ID29:TableDirection")    # up = 1 , down = 0
+    By = caget("ID29:ByPolaritySet")        # pos = 1, neg = 0
+
+    mode = ID_mode_get()
+
+    if By > 0:
+        print("\nBy > 0")
+        if table == 1:            # By=1, table = 1     => -1    => A=B
+            print("table = up")
+            ID_direction = -1
+        elif table ==  0:        # By=1, table = 0     => +1    => A#B
+            print("table = down")
+            ID_direction = 1
+    elif By <= 0:
+        print("\nBy < 0")
+        if table == 1:            # By=0, table = 1     => +1    => A=B
+            print("table = up")
+            ID_direction = 1
+        elif table ==  0:        # By=0, table = 0     => -1    => A#B
+            print("table = down")
+            ID_direction = -1
+
+
+    if mode == "H" and mode == "RCP":
+        if By > 0 and table == 0:
+            print_warning_message("will do a long hysteresis if decreasing energy !!!")
+#    if Mode == "HN" and Mode == "LCP":
+#        if By = 0 and table == 1:
+#            print "WARNING: will do a long hysteresis if decreasing energy !!!"
+    print("ID direction", ID_direction)
+    return ID_direction
+
+def ID_table_userCalcOut(): 
+    """
+       # Work in progress
+
+    Previously:ID_Table_CalcOut
+    """
+    n=4
+    userCalcOut_clear("b",n)
+    pvstr="29idb:userCalcOut"+str(n)
+    caput(pvstr+".DESC","ID_Table")
+    table="ID29:TableDirection"    # up = 1 , down = 0
+    By="ID29:ByPolaritySet"        # pos = 1, neg = 0
+    caput(pvstr+".INPA",table+" CP NMS")
+    caput(pvstr+".INPB",By+" CP NMS")
+    caput(pvstr+".CALC$","A#B")
+    caput(pvstr+".OOPT","On Change")
+    caput(pvstr+".DOPT","Use CALC")
\ No newline at end of file
diff --git a/build/lib/iexcode/instruments/IEX_endstations.py b/build/lib/iexcode/instruments/IEX_endstations.py
new file mode 100644
index 0000000000000000000000000000000000000000..94ee6e1eb9ce4b609d49ca490ac53f24acb5cf32
--- /dev/null
+++ b/build/lib/iexcode/instruments/IEX_endstations.py
@@ -0,0 +1,131 @@
+from math import floor
+import time
+
+from epics import caput
+"""
+Endstation class is used to contain information about ioc, branch, mode
+
+it makes the default stuff work
+
+this will prompt for the endstation and will set the default parameters, look at the 
+init kwargs to see which defaults you can change.
+"""
+global BL
+BL = None
+
+class Endstation:
+    """
+    used for defining which endstation in which you are running
+    for short names and ioc info
+
+    BL = endstation('ARPES')
+        BL.ioc = "ARPES" / "Kappa" / "Test"
+        BL.mode = "User" / "Staff" / "No Xray"
+        BL.branch = 'c' / 'd'
+        BL.mda => mda scanRecord
+
+    """
+
+    def __init__(self,endstation_name,scan_ioc,xrays,BL_mode,mda_scanRecord):
+        """
+        intializes the several beamline variables 
+
+        endstation_name = 'ARPES' / 'Kappa'
+        
+        BL = Endstation()
+            BL.endstation => endstation_name
+            BL.xrays => True/False 
+            BL.mode => previously: BL_Mode_Set
+            BL.folder => 'b','c','d'
+            BL.prefix => 'ARPES_','Kappa_'
+            BL.ioc => previously: BL_ioc()
+            BL.mda_filepath
+            
+        """
+        global BL
+        endstations_list = ['ARPES','Kappa']   
+        BL_mode_list = ['user','staff']
+
+        if self.endstation_name in endstations_list:
+            self.endstation=endstation_name
+        else:
+            print('Not a valid Endstation choice')
+            print('Endstations: '+endstations_list)
+            return
+
+        if BL_mode in BL_mode_list:
+            self.mode = BL_mode
+            if BL_mode.lower == 'user':
+                if endstation_name == 'ARPES':
+                    self.folder = 'c'
+                    self.prefix = 'ARPES_'
+                elif endstation_name == 'Kappa':
+                    self.folder = 'd'
+                    self.prefix = 'Kappa_'
+                #elif endstation_name == 'Octupole':
+                    #self.folder = 'e'
+            elif BL_mode.lower == 'staff':
+                self.folder = 'b' #overwrite folder for staff mode
+        else:
+            print('Not a valid BL_mode choice')
+            print('BL_modes: '+BL_mode_list) 
+            return  
+
+        self.xrays = xrays
+        self.ioc = scan_ioc
+        self.mda = mda_scanRecord
+
+
+    def set_logfile_path():
+        """
+        sets the default logfile path
+        """
+
+##############################################################################################################
+##############################               BL commands            ##############################
+##############################################################################################################
+def BL_ioc():
+    """
+    returns the branch from the Endstation instance
+    """
+    return BL.ioc
+
+def BL_mode():
+    """
+    returns the beamline mode, User / Staff / No_Xray
+    """
+    return BL.ioc
+
+def BL_mda_prefix():
+    """
+    returns the mda file prefix
+    """
+    return BL.prefix
+
+def BL_mda_filepath():
+    """
+    returns the mda file prefix
+    """
+    return BL.filepath
+
+def scalar_cts(self,integration_time=0.1,verbose=True,**kwargs):
+    """
+    Sets the integration time for the scalers
+    kwargs:
+        mcp = True/False to sum mpa
+    Previously: cts, Kappa counts 
+    """
+
+    if BL.endstation == 'ARPES':
+        pass
+    elif BL.endstation == 'Kappa':
+        Kappa_scalar_pv = "29idMZ0:scaler1.TP"
+        mpa_Proc1_pv = "29iddMPA:Proc1:"
+
+        caput(Kappa_scalar_pv,integration_time)
+
+        if kwargs["mpa"]:
+            caput(mpa_Proc1_pv+'NumFilter',floor(time))
+
+        if verbose: 
+            print("Integration time set to:", str(time))
\ No newline at end of file
diff --git a/build/lib/iexcode/instruments/Kappa.py b/build/lib/iexcode/instruments/Kappa.py
new file mode 100644
index 0000000000000000000000000000000000000000..18c98109e657face5c89a1a35b50e2ae272c9966
--- /dev/null
+++ b/build/lib/iexcode/instruments/Kappa.py
@@ -0,0 +1,1127 @@
+import numpy as np
+from time import sleep
+from math import floor
+
+from epics import caget, caput,PV
+
+from iexcode.instruments.IEX_endstations import *
+from iexcode.instruments.staff import staff_detector_dictionary
+
+from iexcode.instruments.files_and_folders import check_run,make_user_folders,folder_mda
+from iexcode.instruments.staff import staff_detector_dictionary
+from iexcode.instruments.logfile import logfile_name_set,logfile_header
+
+from iexcode.instruments.conversions_constants import *
+from iexcode.instruments.utilities import *
+from iexcode.instruments.userCalcs import userStringSeq_clear, userStringSeq_pvs
+
+from iexcode.instruments.scanRecord import *
+from iexcode.instruments.Motors import *
+from iexcode.instruments.xrays import *
+from iexcode.instruments.current_amplifiers import *
+from iexcode.instruments.gate_valves import valve_close, branch_valves
+from iexcode.instruments.shutters import branch_shutter_close
+from iexcode.instruments.slits import slit3D_get
+
+from iexcode.instruments.Kappa_det import *
+from iexcode.instruments.spec_stuff import folders_spec
+
+
+
+#############################################################################
+def Kappa_init(set_folders=False,reset=False,**kwargs):
+    """
+
+    set_folders: sets the mda and EA folders; default => False
+    reset: resets the scanRecord (detectors,triggers...)
+    **kwargs:
+        xrays: sets global variable; default => True
+        BL_mode: 'user' / 'staff' => used for saving, detectors... 
+    """
+    kwargs.setdefault('scan_ioc','29idKappa:')
+    kwargs.setdefault('xrays',True)
+    kwargs.setdefault('BL_mode','user')
+
+    #scan
+    if kwargs['BL_mode']=='staff':
+        detector_dictionary = staff_detector_dictionary()
+    else:
+        detector_dictionary = Kappa_detector_dictionary()
+
+    mda_scanRecord = ScanRecord(kwargs['scan_ioc'],detector_dictionary,
+    Kappa_trigger_dictionary(),Kappa_scan_before_sequence(),Kappa_scan_after_sequence())
+
+    #endstation
+    global BL
+    BL=Endstation('Kappa',kwargs['scan_ioc'],kwargs['xrays'],kwargs['BL_mode'],mda_scanRecord)
+
+    #global detectors
+    global tey, d3, d4, mesh, Kappa_scaler_pv
+    tey = SRS("29idMZ0:scaler1.S2", '29idd:A1')
+    d3 = SRS("29idMZ0:scaler1.S3", '29idd:A2')
+    d4 = SRS("29idMZ0:scaler1.S4", '29idd:A3')
+    mesh = SRS("29idMZ0:scaler1.S14", '29idd:A4')
+    Kappa_scaler_pv = '29idMZ0:scaler1.CNT'
+
+    global tthdet
+    tthdet = Kappa_Detector()
+
+    #setting folders
+    if 'set_folders':
+        if BL.mode == 'staff':
+            user_name = 'staff'
+        else:
+            user_name = input('user name: ')
+        folders_Kappa(user_name,**kwargs)
+    
+    #resetting
+    if 'reset':
+        Kappa_reset()
+
+    #motors
+    global Kappa_Motors
+    physical_motors = ['x','y','z','tth','kth','kap','kphi']
+    psuedo_motors = ['th','chi','phi']
+    Kappa_Motors = Motors('Kappa',Kappa_motor_dictionary(),physical_motors,psuedo_motors)
+
+##############################################################################################################
+##############################                    detectors and motors                ##############################
+##############################################################################################################
+def Kappa_detector_list():
+    """
+    list of detectors to trigger 
+
+    Previously: part of Detector_List
+    """
+    ca_list=[]
+    return ca_list
+
+
+def Kappa_detector_dictionary(**kwargs):
+    """
+    returns a dictionary of the default detectors
+
+    **kwargs
+    add_vortex: to specifiy to add the vortex detectors to the dictionary (True/False)
+
+    Previously: Detector_Default
+    """
+    kwargs.setdefault('add_vortex',False)
+    det_dict={}
+    vortex={
+        15:"",
+        16:"",
+        17:"",
+    }
+    sample_temp={
+        23:"29idd:LS331:TC1:SampleA",
+        24:"29idd:LS331:TC1:SampleB",
+    }
+    m3r={
+        25:"29id_ps6:Stats1:CentroidX_RBV",
+        26:"29id_ps6:Stats1:SigmaX_RBV",
+        27:"29id_ps6:Stats1:CentroidTotal_RBV",
+    }
+    scalers={
+        31:"29idMZ0:scaler1.S14",
+        32:"29idMZ0:scaler1.S2",
+        33:"29idMZ0:scaler1.S3",
+        34:"29idMZ0:scaler1.S4",
+        35:"29idMZ0:scaler1.S5",
+        36:"29idMZ0:scaler1_calc1.B",
+        37:"29idMZ0:scaler1_calc1.C",
+        38:"29idMZ0:scaler1_calc1.D",
+        39:"29idMZ0:scaler1_calc1.E",
+    }
+    mpa={
+        30:"29iddMPA:det1:TotalRate_RBV",
+        41:"29iddMPA:Stats1:Total_RBV",
+        42:"29iddMPA:Stats2:Total_RBV",
+        43:"29iddMPA:Stats3:Total_RBV",
+        44:"29iddMPA:Stats4:Total_RBV",
+        45:"29iddMPA:Stats5:Total_RBV",
+    }
+    hkl={
+        46:'<H>',
+        47:'<K>',
+        48:'<L>'
+    } 
+    motors={
+        51:"29idKappa:m8.RBV",
+        52:"29idKappa:m7.RBV",
+        53:"29idKappa:m1.RBV",
+        54:"29idKappa:m9.RBV",
+        55:"29idKappa:Euler_ThetaRBV",
+        56:"29idKappa:Euler_ChiRBV",
+        57:"29idKappa:Euler_PhiRBV",
+    }
+    #hkl are listed just a place holders, they are filled in by thier scanning functions
+    det_dict.update(sample_temp)
+    det_dict.update(scalers)
+    det_dict.update(mpa)
+    det_dict.update(motors)
+    if kwargs['add_vortex']:
+        det_dict.update(vortex)
+
+    return det_dict
+
+
+def Kappa_motor_dictionary(name):
+    """
+    motor_dictionary = {name:[rbv,val,spmg,pv]} for physical and psuedo/Euler motors
+    usage:
+        KappaS_PVmotor('x') => ['29idKappa:m2.RBV', '29idKappa:m2.VAL', '29idKapp:m2.SPMG','29idKappa:m2']
+    """
+    motor_nums={
+        'x':2,
+        'y':3,
+        'z':4,
+        'tth':9,
+        'kth':8,
+        'kap':7,
+        'kphi':1,
+      }
+    Euler_motors={
+        'th':'29idKappa:Euler_Theta',
+        'chi':'29idKappa:Euler_Chi',
+        'phi':'29idKappa:Euler_Phi'
+    }
+    motor_dictionary = {}
+    for name in motor_nums.keys():
+        pv = '29idKappa:m'+str(motor_nums[name])
+        motor_dictionary.update({name:[pv+'.VAL',pv+'.SPMG',pv]})    
+    
+    for name in Euler_motors.keys():
+        pv = Euler_motors[name]
+        motor_dictionary.update({name:[pv+'RBV',pv,'',pv]})
+    
+    return motor_dictionary
+
+def Kappa_extra_pvs():
+    """
+    used to get the PV associated with a given pnuemonic
+
+    """
+    d={
+        "TA":"29idd:LS331:TC1:Control",
+        "TB":"29idd:LS331:TC1:SampleB",
+        "det_nam":'29idKappa:userStringSeq6.STR1',
+        "HV":'29idKappa:userCalcOut10.OVAL',
+        "centroid":'29id_ps6:Stats1:CentroidX_RBV'        
+    }
+    return d
+
+def Kappa_kth_offset_get():
+    caget("29idKappa:userCalcOut1.G")
+
+def Kappa_kth_offset_set(val):
+    caput("29idKappa:userCalcOut1.G",val)
+
+
+#############################################################################################################
+##############################                 setting folder                   ##############################
+##############################################################################################################
+def folders_Kappa(user_name,**kwargs):
+    """
+    Create and sets (if create_only=False) all the folders the current run and ARPES user 
+    Sets the FileName for logging to be "UserName/YYYYMMDD_log.txt using logname_Set()"
+    
+    **kwargs:
+        set_folders = True (default); set the mda and EA scanRecords
+                    = False; only makes the folders (was create_only)
+        run: run cycle e.g. 2022_1 (default => check_run() )
+        ftp = True / False (default); print what needs to be added to the ftps crontab and create additional ftp folders
+        mda_ioc: will overwrite the default ioc for mda scans
+        debug
+    """
+    kwargs.setdefault('set_folders',False)
+    kwargs.setdefault('run',check_run())
+    kwargs.setdefault('ftp',False)
+    kwargs.setdefault('debug',False)
+
+    run = kwargs['run']
+
+    if kwargs['debug']:
+        print("run,folder,user_name,ioc,ftp: ",run,BL.folder,user_name,BL.ioc,kwargs['ftp'])
+    
+    # Create User Folder:
+    make_user_folders(run,BL.folder,user_name,BL.endstation,ftp=kwargs['ftp'])
+    sleep(5)
+
+    if kwargs["set_folders"]:
+        # Set up MDA folder:
+        folder_mda(run,BL.folder,user_name,BL.prefix,BL.ioc)
+        logfile_name_set(BL.endstation)
+        logfile_header(BL.endstation,BL.ioc,Kappa_log_header())
+
+
+        # Set up SPEC folder:
+        folders_spec(run,BL.folder,user_name)
+
+        # Set up MPA folder:
+        #Folder_MPA(run,BL.folder,user_name)
+
+    #resetting
+    if 'reset':
+        Kappa_reset()
+
+def Kappa_reset():
+    """
+    resets scanRecord, current amplifiers, mono limits and lakeshore
+    """
+    #resetting the scanRecord
+    BL.mda.reset()
+
+    #resetting the current amplifiers
+    if BL.xray:
+        ca_reset_all()
+    
+    #resetting mono and anyother beamline stuff
+    if BL.xrays:
+        xrays_reset()
+
+    #reseting the Kappa Lakeshore
+
+    #motors home and sync
+    SmarAct_motors_home()
+    PI_motors_sync()
+    Euler_motors_sync()
+
+def Kappa_reminder_list(ioc):
+    """
+    resets scanRecord, current amplifiers, mono limits  and synchs motors
+    """
+    mda.reset()
+    if BL.xray:
+        ca_reset_all()
+
+
+
+
+
+##############################################################################################################
+##############################                    get all                 ##############################
+##############################################################################################################
+def Kappa_get_all(verbose=True):
+    """
+    returns a dictionary with the current status of the Kappa endstation and exit slit
+    """
+    vals = {}
+
+    #sample postion
+    motor_dictionary = Kappa_motor_dictionary()
+    for motor in motor_dictionary.keys():
+        vals[motor]=Kappa_Motors.get(motor,verbose=False)
+
+    #endstation pvs
+    extra_pvs = Kappa_extra_pvs()
+    for key in extra_pvs.keys():
+        vals.update(key,caget(extra_pvs[key]))
+
+    #beamline info
+    if BL.xray:
+        beamline_info = xrays_get_all()
+        vals.update(beamline_info) 
+
+    mesh.get()
+    vals.update({'mesh':mesh.current})
+
+    if verbose:
+        for key in vals:
+            print(key+" = "+vals[key])
+    return vals
+
+##############################################################################################################
+##############################                         logging                  ##############################
+##############################################################################################################
+def Kappa_log_header():
+    """
+    header for the log file
+    """
+    h = "scan,motor,start,stop,step,x,y,z,tth,kth,kap,kphi,TA,TB,"
+    h += "hv,exit_slit,GRT,ID_SP,ID_RBV,ID_Mode,ID_QP,TEY,mesh,det_name,mpa_HV,m3r_centroid,time,comment"
+    header_list = {'Kappa':h}
+    return header_list 
+
+def Kappa_log_entries():
+    """
+    enstation info for log file
+
+    Previously: scanlog
+    """
+    vals = Kappa_get_all(verbose=False)
+    x = vals['x']
+    y = vals['y']
+    z = vals['z']
+    tth = vals['tth']
+    kth = vals['kth']
+    kap = vals['kap']
+    kphi = vals['kphi']
+
+    TA = vals['TA']
+    TB = vals['TB']
+    mesh.get()
+    tey_current = tey.current
+    mesh_current = mesh.current
+    det_name = tthdet.name
+    mpa_HV = mpa_HV_get()
+    m3r_centroid = vals['kphi']
+
+    entry_list = ["x","y","z","tth","kth","kap","kphi","TA","TB","TEY","mesh","det_name","mpa_HV","m3r_centroid"]
+    pv_list = [ x, y, z, tth, kth, kap,kphi, TA, TB,tey_current,mesh_current,det_name,mpa_HV,m3r_centroid]  
+    format_list = [".2f",".2f",".2f",".2f",".2f",".2f",".2f",".2f",".2f","1.2e","1.2e","s",".0f",".0f"]
+
+    return entry_list,pv_list,format_list
+
+##############################################################################################################
+##############################             Kappa scanRecord           ##############################
+##############################################################################################################
+def Kappa_scan_before_sequence(**kwargs):
+    """
+    writes the user string sequence to happen at the beginning of a scan
+    returns before_scan_pv = pv for userStringSeq for before scan
+
+    **kwargs
+        seq_num: userStringSeq number in ioc => 9 (default)
+
+    Previously: BeforeScan_StrSeq
+    """
+    kwargs.setdefault(seq_num,9)
+    seq_num=kwargs['seq_num']
+
+    before_scan_pv,before_scan_proc = userStringSeq_pvs(BL.ioc, seq_num)
+
+    #clear and write the before scan user sequence
+    userStringSeq_clear(BL.ioc,seq_num)
+    caput(before_scan_pv+".DESC","Before Scan")
+
+    #This is where you'd do something if need (CA -> 'Passive', etc)
+    pv=''
+    cmd=''
+    caput(before_scan_pv+".LNK" +str(1),pv)
+    caput(before_scan_pv+".STR" +str(1),cmd)
+
+    return before_scan_proc
+
+def Kappa_scan_after_sequence(scan_dim, **kwargs):
+    """
+    writes the user string sequence to happen at the end of a scan
+    returns after_scan_pv = pv for userStringSeq for after scan
+
+    **kwargs
+        seq_num: userStringSeq number in ioc => 10 (default)
+        snake: for snake scanning => False (default)
+
+    Previously: AfterScan_StrSeq
+    """
+    kwargs.setdefault(seq_num,10)
+    kwargs.setdefault('snake',False)
+    seq_num=kwargs['seq_num']
+
+    after_scan_pv,after_scan_proc = userStringSeq_pvs(BL.ioc, seq_num)
+    
+    #clear and write the after scan user sequence
+    userStringSeq_clear(BL.ioc,seq_num)
+    caput(after_scan_pv+".DESC","After Scan")
+        
+    scan_pv = BL.ioc+"scan"+str(scan_dim)
+    ## Put scan record back in absolute mode
+    caput(after_scan_pv+".LNK2",scan_pv+".P1AR")
+    caput(after_scan_pv+".STR2","ABSOLUTE")
+
+    ## Put Positionner Settling time to 0.1s
+    caput(after_scan_pv+".LNK3",scan_pv+".PDLY NPP NMS")
+    caput(after_scan_pv+".DO3",0.1)
+
+    ## Clear DetTriggers 2 to 4:
+    caput(after_scan_pv+".LNK4",scan_pv+".T2PV NPP NMS")    #remove trigger 2 (used for EA) after scan
+
+    if kwargs['snake']:
+        snake_dim = scan_dim - 1
+        #snake_proc= Kappa_snake_pv(snake_dim,enable=True)
+        #caput(after_scan_pv+".LNK10",Kappa_snake_pv()+"PP NMS")
+        #caput(after_scan_pv+".D10",1)
+
+    return after_scan_proc
+
+def Kappa_detector_triggers_sequence(**kwargs):    # do we need to add 29idb:ca5 ???
+    """
+    """
+    kwargs.setdefault(seq_num,8)
+    seq_num=kwargs['seq_num']
+
+    detector_triggers_pv,detector_triggers_proc = userStringSeq_pvs(BL.ioc, seq_num)
+       
+    #clear the userStringSeq
+    userStringSeq_clear(BL.ioc,seq_num=kwargs['seq_num'])
+    caput(detector_triggers_pv+".DESC","Kappa_Trigger1")
+
+    scaler_pv = Kappa_scaler_pv
+
+    caput(detector_triggers_pv+".LNK" +str(1),scaler_pv)
+    caput(detector_triggers_pv+".WAIT"+str(1),"After"+str(last))
+    
+    ca_list = Kappa_detector_list
+    last = len(ca_list)
+    for i,ca in enumerate(ca_list):
+        ca_pv = Keithley_pv(ca[0], ca[1])+':read.PROC CA NMS'
+        caput(detector_triggers_pv+".LNK" +str(i+2),ca_pv)
+        caput(detector_triggers_pv+".WAIT"+str(i+2),"After"+str(last))
+
+    return detector_triggers_proc
+
+def Kappa_trigger_dictionary():
+    """
+    need to do something
+    """
+    trigger_dictionary = {
+        1:Kappa_detector_triggers_sequence(),
+    }
+    return trigger_dictionary
+
+
+
+
+##############################################################################################################
+##############################        Kappa  Motor Scan Set Up        ##############################
+##############################################################################################################
+
+
+def Kappa_sample_Euler_list():
+    """
+    returns list of motor names used by mvsample
+    """
+    motor_list = ['th','chi','phi']
+    return motor_list
+
+
+def Kappa_4c_mprint():
+    """
+    returns the dictionary of the current sample position in 4c units 
+    
+    motors=['th','chi','phi']
+
+    Previously: diffracto?
+    """
+    positions={}
+    motors=Kappa_sample_Euler_list()
+    for motor in motors:
+        positions.update(motor,Kappa_motor_dictionary()(motor)[0])
+    return positions
+
+def Kappa_4c_move(th_chi_phi_list):
+    """
+    moves the sample in 4c (Euler) units
+    Previously: mv4C
+    """
+    motor_list=Kappa_sample_Euler_list()
+    for motor,i in enumerate(motor_list):
+        Kappa_Motors.move(motor,motor_list[i],wait=True,verbose=False)
+    
+    for motor,i in enumerate(motor_list):
+        Kappa_Motors.get(motor,verbose=True)
+
+   
+
+def SmarAct_motor_list():
+    """
+    returns a list of the motor names for the SmarAct motors in the Kappa
+    """
+    return ['x','y','z']
+
+def SmarAct_motors_home():
+    """
+    Homes the piezo (x,y,z). Home position is middle of travel
+
+    Previously: Home_SmarAct_Motor
+    """
+    motor_dictionary = Kappa_motor_dictionary()
+    for motor in SmarAct_motor_list():
+        pv = motor_dictionary[motor][3]
+        caput(pv+'.HOMF',1)
+        sleep(10)
+    print('SamrAct motors VAL homed')
+
+def SmarAct_enable():
+    motor_dictionary = Kappa_motor_dictionary()
+    for motor in SmarAct_motor_list():
+        spmg = motor_dictionary[motor][2]
+        caput(spmg,3)  # 3=Go
+
+def SmarAct_disable():
+    motor_dictionary = Kappa_motor_dictionary()
+    for motor in SmarAct_motor_list():
+        spmg = motor_dictionary[motor][2]
+        caput(spmg,0)  # 1=Stop
+
+def PI_motor_list():
+    """
+    returns a list of the motor names for the SmarAct motors in the Kappa
+    """
+    return ['kap','kth','tth']
+
+def PI_motors_sync():
+    motor_dictionary = Kappa_motor_dictionary()
+    for motor in PI_motor_list():
+        val_pv = motor_dictionary[motor][1]
+        rbv_pv = motor_dictionary[motor][0]
+        current_rbv=caget(rbv_pv)
+        caput(val_pv,current_rbv)
+    print('PI motors VAL synced to RBV')
+
+def Euler_motors_sync():
+    """
+    Syncs the Euler motores
+
+    Previously: Sync_Euler_Motor
+    """
+    caput('29idKappa:Kappa_sync.PROC',1)
+    sleep(1)
+    caput('29idKappa:Kappa_sync.PROC',1)
+    print('Euler motors VAL/RBV synced to physical motors')
+
+def Kappa_kphi_reset_zero(val):
+    """
+    resets the zero for the kphi motor
+
+    """
+    kphi_pv = Kappa_motor_dictionary()['kphi'][3]
+    caput(kphi_pv+".SET",1)    # 1 = Set
+    sleep(0.5)
+    caput("kphi_pv.VAL",val)
+    sleep(0.5)
+    caput(kphi_pv+".SET",0)    # 0 = Use
+    print("\nkphi has been reset to " +str(val))
+
+def Kappa_tth_reset_zero():
+    """
+    resets the zero for the tth motor
+    """
+    tthdet.tth0_set()
+
+
+
+def Kappa_th2th_scan_sensitivity(th_table,gain_num_table,gain_unit_table,detector=tey,**kwargs):
+    """
+    Scans th2th with variable gain on SRS# (srs_num).
+    Gain is specified for a given th2th range by building tables as follow:
+
+    th_table = np.array([])
+    gain_num_table = np.array([])
+    gain_unit_table = np.array([])
+
+    Example:
+        for i in RangeUp(10,20,0.5):
+            th_table = np.append(th_table, i)
+            gn_table = np.append(gn_table, gain_dict(2))
+            gu_table = np.append(gu_table, unit_dict('mA'))
+        for i in RangeUp(20.5,40,0.5):
+            th_table = np.append(th_table, i)
+            gn_table = np.append(gn_table, gain_dict(1))
+            gu_table = np.append(gu_table, unit_dict('uA'))
+        for i in RangeUp(40.5,60,0.5):
+            th_table = np.append(th_table, i)
+            gn_table = np.append(gn_table, gain_dict(10))
+            gu_table = np.append(gu_table, unit_dict('pA'))
+    
+    kwargs:
+        scan_dim: 1  (default)
+        cts: integration time for scalers and mpa/mcp => 0.1 (default)
+        execute: True/False to start the scan => True (default)
+       
+    Previoulsy: Scan_th2th_sensitivity
+    """
+    kwargs.setdefault('cts',0.1)
+    kwargs.setdefault('execute',True)
+
+    kth_offset = Kappa_kth_offset_get()
+
+    motor_dictionary = Kappa_motor_dictionary()
+    kth_val,kth_rbv,kth_spmg,kth_pv = motor_dictionary['kth']
+    tth_val,tth_rbv,tth_spmg,tth_pv = motor_dictionary['tth']
+
+    detector_pv = detector._srs_pv
+    gain_num_pv = detector_pv + "sens_num.VAL"
+    gain_unit_pv= detector_pv + "sens_unit.VAL"
+
+    kth_table = th_table + kth_offset
+    tth_table = 2*th_table
+
+    kwargs.update("positioner_num",1)
+    mda.fillin_table(kth_val,kth_rbv,kth_table,**kwargs)
+
+    kwargs.update("positioner_num",2)
+    mda.fillin_table(tth_val,tth_rbv,tth_table,**kwargs)
+
+    kwargs.update("positioner_num",3)
+    mda.fillin_table(gain_num_pv,"",gain_num_table,**kwargs)
+
+    kwargs.update("positioner_num",4)
+    mda.fillin_table(gain_unit_pv,"",gain_unit_table,**kwargs)
+
+    print("\nDon't forget to clear extra positionners at the end of the scan if you were to abort the script using the function:")
+    print("                Clear_Scan_Positioners('Kappa',1)")
+ 
+    scaler_cts(kwargs['cts'],verbose=False)
+    if kwargs['execute']:
+        mda.go(**kwargs)
+
+        #clean up after scan
+        mda.table_reset_after(**kwargs)
+        scaler_cts(verbose=False)
+
+def Kappa_scan_th2th(tth_start,tth_stop,tth_step,th_offset,**kwargs):
+    """
+    Used for a linear (not table) scan where th =  tth /2 + th_offset
+    **kwargs
+        scan_dim: 1  (default)
+        cts: integration time for scalers and mpa/mcp => 0.1 (default) 
+        execute: True/False to start the scan => True (default)
+
+    Previously: scanth2th
+    """
+    kwargs.setdefault('scan_dim',1)
+    kwargs.setdefault('cts',0.1)
+    kwargs.setdefault('execute',True)
+    
+    th_start = (tth_start)/2+th_offset
+    th_stop = (tth_stop)/2+th_offset
+    th_step = int(tth_step/2)
+    
+    print('tth: '+str(tth_start)+"/"+str(tth_stop)+"/"+str(tth_step))
+    print('th: '+str(th_start)+"/"+str(th_stop)+"/"+str(tth_step/2.0))
+    
+    #write to the scanRecord
+    th_val,th_rbv,th_spmg,th_pv = Kappa_motor_dictionary['th']
+    tth_val,tth_rbv,tth_spmg,tth_pv = Kappa_motor_dictionary['tth']
+
+    kwargs.update("positioner_num",2)
+    BL.mda.fillin(th_val,th_rbv,th_start,th_stop,th_step,**kwargs)
+    
+    kwargs.update("positioner_num",1)
+    BL.mda.fillin(tth_val,tth_rbv,tth_start,tth_stop,tth_step,**kwargs)
+    
+    scaler_cts(kwargs['cts'],verbose=False)
+    if kwargs['execute']:
+        BL.mda.go(**kwargs)
+
+        #clean up after scan
+        scaler_cts(verbose=False)
+
+
+def scan_th2th_table(tth_table,th0,**kwargs):
+    """
+    Create a table for tth, e.g.:
+        mytable_tth=[]
+        for q in range(2,41,1):
+            mytable_tth.append(q)
+        print(mytable_tth)
+        
+    th0 = th value at grazing incidence
+    cts = counting time (default is 1s)
+    
+    **kwargs
+        scan_dim: 1  (default)
+        cts: integration time for scalers and mpa/mcp => 0.1 (default) 
+        execute: True/False to start the scan => True (default)
+
+    Previously: scanth2th_table
+
+    """
+    kwargs.setdefault('cts',0.1)
+    kwargs.setdefault('execute',True)
+  
+    tth_table=np.asarray(tth_table)
+    th_table=tth_table/2.0+th0
+
+    th_val,th_rbv,th_spmg,th_pv = Kappa_motor_dictionary['th']
+    tth_val,tth_rbv,tth_spmg,tth_pv = Kappa_motor_dictionary['tth']
+
+    #write to the scanRecord
+    kwargs.update("positioner_num",1)
+    BL.mda.fillin_table(tth_val,tth_rbv,tth_table,**kwargs)
+
+    kwargs.update("positioner_num",2)
+    BL.mda.fillin_table(th_val,th_rbv,th_table,**kwargs)
+    BL.mda.positioner_after_scan(after="STAY")
+
+
+    scaler_cts(kwargs['cts'],verbose=False,**kwargs)
+    if kwargs['execute']:
+        BL.mda.go(**kwargs)
+
+        #clean up after scan
+        BL.mda.table_reset_after()
+        scaler_cts(verbose=False)
+        BL.mda.positioner_after_scan(after="PRIOR POS",**kwargs)
+
+
+
+
+#############################################################################################################
+##############################             Preset Positions        ##############################
+##############################################################################################################
+def KappaTransfer_StrSeq():
+    #User= [    DESC,        x,        y,      z,        tth,       kth,       kap,    kphi]
+    User = ["Kappa Transfer",0, -2650, -650, 0, 57, 0, -88]
+    n=4
+    KappaPreset_StrSeq(n,User)
+
+
+def KappaGrazing_StrSeq(): #Need to determine positions and then add to the Kappa graphic
+    #Dial= [    DESC,        x,        y,      z,        tth,       kth,       kap,    kphi]
+    User = ["Kappa Grazing",0, 0, 0, 0, 57.045, 134.76,57.045]
+    n=3
+    KappaPreset_StrSeq(n,User)
+
+def Kappa_ResetPreset():
+    KappaGrazing_StrSeq()
+    KappaTransfer_StrSeq()
+
+
+
+
+
+
+
+
+
+
+##############################################################################################################
+##############################             Kappa light       ##############################
+############################################################################################################## 
+def Kappa_light(ON_OFF):
+    """
+    Previously:light
+    """
+    light_pv = '29idd:Unidig1Bo0'
+    if ON_OFF.lower() == 'on':
+        light=0
+    elif ON_OFF.lower() == 'off':
+        light=1
+    caput(light_pv,light)
+    print(("Turning light "+ON_OFF+"."))
+
+
+
+
+def Kappa_detector_triggers_strSeq(**kwargs):    # do we need to add 29idb:ca5 ???
+    """
+    """
+    kwargs.setdefault(seq_num,8)
+    seq_num=kwargs['seq_num']
+    
+    detector_triggers_pv,detector_triggers_proc = userStringSeq_pvs(BL.ioc, seq_num)
+       
+    #clear the userStringSeq
+    userStringSeq_clear(BL.ioc,seq_num=kwargs['seq_num'])
+    caput(detector_triggers_pv+".DESC","Kappa_Trigger1")
+
+    #no triggers see ARPES_detector_triggers_sequence for example
+
+    return detector_triggers_proc
+
+
+
+
+
+
+def KappaPreset_StrSeq(n,User):
+    scanIOC="Kappa"
+    motorIOC="29idKappa:"
+    motor = ["m2","m3","m4","m9","m8","m7","m1"]
+    strSeq_pv = userStringSeq_clear(mda,n)
+
+    if User[0] == "Kappa Grazing":  phi0= 0
+    if User[0] == "Kappa Transfer": phi0= 57
+    caput(strSeq_pv+".DESC",User[0])
+    caput(strSeq_pv+".LNK1", "29idKappa:userCalcOut9.A CA NMS")       # MPA HV pV
+    caput(strSeq_pv+".DO1",0)                                       # MPA HV = 0
+    caput(strSeq_pv+".WAIT1","Wait")                                # Wait for completion
+    caput(strSeq_pv+".LNK2", "29idKappa:m1.VAL CA NMS")               # phi = phi0
+    caput(strSeq_pv+".DO2",phi0)                                       
+    caput(strSeq_pv+".WAIT2","Wait")                                # Wait for completion
+    for i in range(3,10):
+        caput(strSeq_pv+".LNK"+str(i),motorIOC+motor[i-3]+".VAL CA NMS")
+        caput(strSeq_pv+".DO"+str(i),User[i-2])
+        if i < 9:
+            caput(strSeq_pv+".WAIT"+str(i),"After8")
+
+
+
+
+    
+ 
+    
+    
+def Bragg_Angle_CalcOut(d,eV,l):
+    n=7
+    userCalcOut_pv = userCalcOut_clear(mda,n)
+
+    h=4.135667516e-15
+    c=299792458
+    f=h*c*1e9*10
+    caput(userCalcOut_pv+"DESC","Bragg_Angle")
+    caput(userCalcOut_pv+"A",d)
+    caput(userCalcOut_pv+"B",l)
+    caput(userCalcOut_pv+"C",eV)
+    caput(userCalcOut_pv+"D",np.pi)
+    caput(userCalcOut_pv+"E",f)
+    caput(userCalcOut_pv+".CALC$","ASIN(B*E/(C*"+str(2)+"*A))*"+str(180)+"/D")
+
+##############################################################################################################
+########################        Scan Temp and Pressure           ##############################
+##############################################################################################################
+def Kappa_temperature_pressure_scan(scan_dim=1):
+    """
+    starts scan to monitor temperature and pressure in the kappa chamber
+
+    Previously: Kappa_ScanTempPres
+    """
+
+    pv="29id"+BL.mda.ioc+":scan"+str(scan_dim)
+    #Clear all scan pvs
+    caput(pv+".CMND",6)
+    #Set detectors
+    caput(pv+".D01PV","29idd:tc1:getVal_A.VAL")
+    caput(pv+".D02PV","29idd:tc1:getVal_B.VAL")
+    caput(pv+".D03PV","29idb:VS11D.VAL")
+    #time scan
+    BL.mda.time_go()
+
+
+
+##############################################################################################################
+##############################             Kappa safestate        ##############################
+##############################################################################################################
+def Kappa_safe_state(**kwargs):
+    """
+    puts the C-branch in a safe state, 
+    **kwargs
+        MPA_off = True; turns off EA HV
+        shutter_close = True; closes the D-shutter
+        valve_close = True; closes the D-valve
+    """
+    kwargs.setdefault("MPA_off",True)
+    kwargs.setdefault("shutter_close",True)
+    kwargs.setdefault("valve_close",True)
+    
+    if kwargs["EA_off"]:
+        try:
+            mpa_HV_off()
+        except:
+            print('MPA is not running')
+
+    if kwargs['valve_close']:
+       valve_close(branch_valves('d'), verbose=True)
+
+    if kwargs['shutter_close']:
+        branch_shutter_close('d')
+    
+##############################################################################################################
+##############################              Kappa motors       ##############################
+##############################################################################################################
+### x ###
+def mvx(val,**kwargs):
+    """ moves x motor in the endstation"""
+    Kappa_Motors.move('x',val,**kwargs)
+
+def dmvx(val):
+    """ relative x motor in the endstation"""
+    Kappa_Motors.move('x',val,relative=True)
+
+def scanx(start,stop,step,**kwargs):
+    """ scans the x motor in the endstation"""
+    Kappa_Motors.scan("x",start,stop,step,**kwargs)
+
+def dscanx(start,stop,step):
+    """relative scans of the x motor in the endstation """
+    Kappa_Motors.scan("x",start,stop,step,relative=True)
+
+### y ###
+def mvy(val,**kwargs):
+    """ moves y motor in the endstation"""
+    Kappa_Motors.move('y',val,**kwargs)
+
+def dmvy(val):
+    """ relative y motor in the endstation"""
+    Kappa_Motors.move('y',val,relative=True)
+
+def scany(start,stop,step,**kwargs):
+    """ scans the y motor in the endstation"""
+    Kappa_Motors.scan("y",start,stop,step,**kwargs)
+
+def dscany(start,stop,step):
+    """relative scans of the y motor in the endstation """
+    Kappa_Motors.scan("y",start,stop,step,relative=True)
+
+### z ###
+def mvz(val,**kwargs):
+    """ moves z motor in the endstation"""
+    Kappa_Motors.move('z',val,**kwargs)
+
+def dmvz(val):
+    """ relative z motor in the endstation"""
+    Kappa_Motors.move('z',val,relative=True)
+
+def scanz(start,stop,step,**kwargs):
+    """ scans the z motor in the endstation"""
+    Kappa_Motors.scan("z",start,stop,step,**kwargs)
+
+def dscanz(start,stop,step):
+    """relative scans of the z motor in the endstation """
+    Kappa_Motors.scan("z",start,stop,step,relative=True)
+
+### kth ###
+def mvkth(val,**kwargs):
+    """ moves kth motor in the endstation"""
+    Kappa_Motors.move('kth',val,**kwargs)
+
+def dmvkth(val):
+    """ relative kth motor in the endstation"""
+    Kappa_Motors.move('kth',val,relative=True)
+
+def scankth(start,stop,step,**kwargs):
+    """ scans the kth motor in the endstation"""
+    Kappa_Motors.scan("kth",start,stop,step,**kwargs)
+
+def dscankth(start,stop,step):
+    """relative scans of the kth motor in the endstation """
+    Kappa_Motors.scan("kth",start,stop,step,relative=True)
+
+### kphi ###
+def mvkphi(val,**kwargs):
+    """ moves kphi motor in the endstation"""
+    Kappa_Motors.move('kphi',val,**kwargs)
+
+def dmvkphi(val):
+    """ relative kphi motor in the endstation"""
+    Kappa_Motors.move('kphi',val,relative=True)
+
+def scankphi(start,stop,step,**kwargs):
+    """ scans the kphi motor in the endstation"""
+    Kappa_Motors.scan("kphi",start,stop,step,**kwargs)
+
+def dscankphi(start,stop,step):
+    """relative scans of the kphi motor in the endstation """
+    Kappa_Motors.scan("kphi",start,stop,step,relative=True)   
+
+### kap ###
+def mvkap(val,**kwargs):
+    """ moves kap motor in the endstation"""
+    Kappa_Motors.move('kap',val,**kwargs)
+
+def dmvkap(val):
+    """ relative kap motor in the endstation"""
+    Kappa_Motors.move('kap',val,relative=True)
+
+def scankap(start,stop,step,**kwargs):
+    """ scans the kap motor in the endstation"""
+    Kappa_Motors.scan("kap",start,stop,step,**kwargs)
+
+def dscankap(start,stop,step):
+    """relative scans of the kap motor in the endstation """
+    Kappa_Motors.scan("kap",start,stop,step,relative=True)
+
+### tth ###
+def mvtth(val,**kwargs):
+    """ moves tth motor in the endstation"""
+    Kappa_Motors.move('tth',val,**kwargs)
+
+def dmvtth(val):
+    """ relative tth motor in the endstation"""
+    Kappa_Motors.move('tth',val,relative=True)
+
+def scantth(start,stop,step,**kwargs):
+    """ scans the tth motor in the endstation"""
+    Kappa_Motors.scan("tth",start,stop,step,**kwargs)
+
+def dscantth(start,stop,step):
+    """relative scans of the tth motor in the endstation """
+    Kappa_Motors.scan("tth",start,stop,step,relative=True)
+
+### th ###
+def mvth(val,**kwargs):
+    """ moves th motor in the endstation"""
+    Kappa_Motors.move('th',val,**kwargs)
+
+def dmvth(val):
+    """ relative th motor in the endstation"""
+    Kappa_Motors.move('th',val,relative=True)
+
+def scanth(start,stop,step,**kwargs):
+    """ scans the th motor in the endstation"""
+    Kappa_Motors.scan("th",start,stop,step,**kwargs)
+
+def dscanth(start,stop,step):
+    """relative scans of the th motor in the endstation """
+    Kappa_Motors.scan("th",start,stop,step,relative=True)
+
+### chi ###
+def mvchi(val,**kwargs):
+    """ moves chi motor in the endstation"""
+    Kappa_Motors.move('chi',val,**kwargs)
+
+def dmvchi(val):
+    """ relative chi motor in the endstation"""
+    Kappa_Motors.move('chi',val,relative=True)
+
+def scanchi(start,stop,step,**kwargs):
+    """ scans the chi motor in the endstation"""
+    Kappa_Motors.scan("chi",start,stop,step,**kwargs)
+
+def dscanchi(start,stop,step):
+    """relative scans of the chi motor in the endstation """
+    Kappa_Motors.scan("chi",start,stop,step,relative=True)
+
+### phi ###
+def mvphi(val,**kwargs):
+    """ moves phi motor in the endstation"""
+    Kappa_Motors.move('phi',val,**kwargs)
+
+def dmvphi(val):
+    """ relative phi motor in the endstation"""
+    Kappa_Motors.move('phi',val,relative=True)
+
+def scanphi(start,stop,step,**kwargs):
+    """ scans the phi motor in the endstation"""
+    Kappa_Motors.scan("phi",start,stop,step,**kwargs)
+
+def dscanphi(start,stop,step):
+    """relative scans of the phi motor in the endstation """
+    Kappa_Motors.scan("phi",start,stop,step,relative=True)
+
+### uan moves tth and th simultaneously 
+def uan(tth,th):
+    """ Moves tth and th motors simultaneously in the in the Kappa chamber
+    """
+    #move tth and th
+    mvth(th,wait=False)
+    mvtth(tth,wait=False)
+    sleep(0.2)     
+
+    while True:
+        status = Kappa_Motors.status()
+        if status == 0:
+            sleep(0.2)
+        else:
+            tth_RBV=round(Kappa_Motors.get('tth',verbose=False),3)
+            th_RBV=round(Kappa_Motors.get('th',verbose=False),3)
+            print('tth='+str(tth_RBV)+' th='+str(th_RBV))
+            break
+
+######## mprint and mvsample ###################
+def mprint():
+    """
+    prints current position of the physical motors
+    """
+    Kappa_Motors.mprint()
+
+def mvsample(position_list):
+    """
+    moves the sample to the position sepcified by position_list
+    position_list = ['description',x,y,z,th,chi,phi]
+
+    Previously: sample
+    """
+    Kappa_Motors.mvsample(position_list)
\ No newline at end of file
diff --git a/build/lib/iexcode/instruments/Kappa_Euler.py b/build/lib/iexcode/instruments/Kappa_Euler.py
new file mode 100644
index 0000000000000000000000000000000000000000..42dfe2f1bac9ec223a1c6a78a4d20ab9f32720bf
--- /dev/null
+++ b/build/lib/iexcode/instruments/Kappa_Euler.py
@@ -0,0 +1,120 @@
+import numpy as np
+from epics import caget, caput
+
+from iexcode.instruments.userCalcs import userCalcOut_clear
+from iexcode.instruments.IEX_endstations import mda
+from iexcode.instruments.userCalcs import userCalcOut_clear
+
+#### Obsolete?
+
+def Bragg_Index_CalcOut(d,eV,th):
+    n=8
+    userCalcOut_pv = userCalcOut_clear(mda,n)
+    
+    h=4.135667516e-15
+    c=299792458
+    f=h*c*1e9*10
+
+    caput(userCalcOut_pv+".DESC","Bragg_Index")
+    caput(userCalcOut_pv+".A",d)
+    caput(userCalcOut_pv+".B",th)
+    caput(userCalcOut_pv+".C",eV)
+    caput(userCalcOut_pv+".D",np.pi)
+    caput(userCalcOut_pv+".E",f)
+    caput(userCalcOut_pv+".CALC$","SIN(B*D/"+str(180)+")*"+str(2)+"*A*C/E")
+
+
+
+def KtoE_th_CalcOut():
+    n=1
+    userCalcOut_pv = userCalcOut_clear(mda,n)
+
+    caput(userCalcOut_pv+".DESC","KtoE_th")
+    caput(userCalcOut_pv+".INPA","29idKappa:m8.RBV CP NMS")    #A=kth
+    caput(userCalcOut_pv+".INPB","29idKappa:m7.RBV CP NMS")    #B=kap
+    caput(userCalcOut_pv+".INPC","29idKappa:m1.RBV CP NMS")    #C=kphi
+    caput(userCalcOut_pv+".D",3.141592653589793)
+    caput(userCalcOut_pv+".E",180)
+    caput(userCalcOut_pv+".F",50)
+    caput(userCalcOut_pv+".H",57.045)
+    caput(userCalcOut_pv+".CALC$","((A-(G-H))*D/E-ATAN(TAN(B*D/E/2.0)*COS(F*D/E)))*E/D")
+    caput(userCalcOut_pv+".DOPT",0)           # Use CAL
+
+def KtoE_chi_CalcOut():
+    n=2
+    userCalcOut_pv = userCalcOut_clear(mda,n)
+
+    caput(userCalcOut_pv+".DESC","KtoE_chi")
+    caput(userCalcOut_pv+".INPA","29idKappa:m8.RBV CP NMS")    #A=kth
+    caput(userCalcOut_pv+".INPB","29idKappa:m7.RBV CP NMS")    #B=kap
+    caput(userCalcOut_pv+".INPC","29idKappa:m1.RBV CP NMS")    #C=kphi
+    caput(userCalcOut_pv+".D",3.141592653589793)
+    caput(userCalcOut_pv+".E",180)
+    caput(userCalcOut_pv+".F",50)
+    caput(userCalcOut_pv+".CALC$","(2*ASIN(SIN(B*D/E/2.0) * SIN(F*D/E)))*E/D")
+    caput(userCalcOut_pv+".DOPT",0)           # Use CAL
+
+def KtoE_phi_CalcOut():
+    n=3
+    userCalcOut_pv = userCalcOut_clear(mda,n)
+    
+    caput(userCalcOut_pv+".DESC","KtoE_phi")
+    caput(userCalcOut_pv+".INPA","29idKappa:m8.RBV CP NMS")    #A=kth
+    caput(userCalcOut_pv+".INPB","29idKappa:m7.RBV CP NMS")    #B=kap
+    caput(userCalcOut_pv+".INPC","29idKappa:m1.RBV CP NMS")    #C=kphi
+    caput(userCalcOut_pv+".D",3.141592653589793)
+    caput(userCalcOut_pv+".E",180)
+    caput(userCalcOut_pv+".F",50)
+    caput(userCalcOut_pv+".CALC$","(C*D/E-ATAN(TAN(B*D/E/2.0)*COS(F*D/E)))*E/D")
+    caput(userCalcOut_pv+".DOPT",0)           # Use CAL
+
+
+
+
+def EtoK_kth_CalcOut():
+    n=4
+    userCalcOut_pv = userCalcOut_clear(mda,n)
+
+    caput(userCalcOut_pv+".DESC","EtoK_kth")
+    caput(userCalcOut_pv+".INPA","29idKappa:userCalcOut1.VAL CP NMS")    #A=th
+    caput(userCalcOut_pv+".INPB","29idKappa:userCalcOut2.VAL CP NMS")    #B=chi
+    caput(userCalcOut_pv+".INPC","29idKappa:userCalcOut3.VAL CP NMS")    #C=phi
+    caput(userCalcOut_pv+".D",3.141592653589793)
+    caput(userCalcOut_pv+".E",180)
+    caput(userCalcOut_pv+".F",50)
+    caput(userCalcOut_pv+".CALC$","(A*D/E-ASIN(-TAN(B*D/E/2.0)/TAN(F*D/E)))*E/D")
+    caput(userCalcOut_pv+".DOPT",0)           # Use CAL
+
+def EtoK_kap_CalcOut():
+    n=5
+    userCalcOut_pv = userCalcOut_clear(mda,n)
+
+    caput(userCalcOut_pv+".DESC","EtoK_kap")
+    caput(userCalcOut_pv+".INPA","29idKappa:userCalcOut1.VAL CP NMS")    #A=th
+    caput(userCalcOut_pv+".INPB","29idKappa:userCalcOut2.VAL CP NMS")    #B=chi
+    caput(userCalcOut_pv+".INPC","29idKappa:userCalcOut3.VAL CP NMS")    #C=phi
+    caput(userCalcOut_pv+".D",3.141592653589793)
+    caput(userCalcOut_pv+".E",180)
+    caput(userCalcOut_pv+".F",50)
+    caput(userCalcOut_pv+".CALC$","((2*ASIN(SIN(B*D/E/2.0) / SIN(F*D/E))))*E/D")
+    caput(userCalcOut_pv+".DOPT",0)           # Use CAL
+
+def EtoK_kphi_CalcOut():
+    n=6
+    userCalcOut_pv = userCalcOut_clear(mda,n)
+    
+    caput(userCalcOut_pv+".DESC","EtoK_kphi")
+    caput(userCalcOut_pv+".INPA","29idKappa:userCalcOut1.VAL CP NMS")    #A=th
+    caput(userCalcOut_pv+".INPB","29idKappa:userCalcOut2.VAL CP NMS")    #B=chi
+    caput(userCalcOut_pv+".INPC","29idKappa:userCalcOut3.VAL CP NMS")    #C=phi
+    caput(userCalcOut_pv+".D",3.141592653589793)
+    caput(userCalcOut_pv+".E",180)
+    caput(userCalcOut_pv+".F",50)
+    caput(userCalcOut_pv+".CALC$","(C*D/E-ASIN(-TAN(B*D/E/2.0)/TAN(F*D/E)))*E/D")
+    caput(userCalcOut_pv+".DOPT",0)           # Use CAL
+
+
+
+
+
+
diff --git a/build/lib/iexcode/instruments/Kappa_det.py b/build/lib/iexcode/instruments/Kappa_det.py
new file mode 100644
index 0000000000000000000000000000000000000000..9a1a19071153d757e6dd4897cf40339b8fd4a73f
--- /dev/null
+++ b/build/lib/iexcode/instruments/Kappa_det.py
@@ -0,0 +1,77 @@
+from time import sleep
+from epics import caget, caput
+ 
+from iexcode.instruments.IEX_endstations import Motors
+
+
+##############################################################################################################
+################################            Kappa detector class             ##############################
+##############################################################################################################
+det_set_pv = '29idKappa:det:set'
+det_list = 'd3', 'd4', 'mcp', 'apd', 'yag'
+
+class Kappa_Detector:
+    """
+    class for Kappa detector
+    """
+ 
+    def __init__(self):
+        self.get()
+
+    def get(self):
+        """
+        gets the current det_name and position
+
+        det_name, tth_val
+        """
+        #det_name = caget('29idKappa:userStringSeq6.STR1')
+        det_name = caget(det_set_pv)
+        self.name = det_name
+        tth_val = Motors.get('tth')
+        return self.name, tth_val
+
+    def set(self,det_name,move=True):
+        """
+        sets the tth detector 
+        and moves the motor to tth value for the new detecotr
+        
+        det_names
+            d3: large diode
+            d4: small diode
+            mcp: for the mpa
+            apd: avalanche photodiode (not currently installed) 
+            yag: yag 'fluorescence screen'
+        """
+        #get current value for tth
+        tth_val = Motors.get('tth')
+
+        #change det 
+        if det_name in det_list:
+            caput(det_set_pv,det_name)
+            if move:
+                Motors.move('tth',tth_val,wait=True,verbose=False)
+
+    def tth0_set(move):
+        """
+        resetting the tth motor zero to correspond to direct beam
+
+        only works with d4
+        """
+        current_det=caget(det_set_pv,as_string=True)
+        tth_pv = Motors._motor_dictionary['th'][3]
+
+        if current_det != 'd4':
+            print('tth0 can only be redefined with d4')
+        else:
+            foo=input('Are you sure you want to reset tth0 (y or n)? >')
+            if foo == 'Y' or foo == 'y' or foo == 'yes'or foo == 'YES':
+                caput(tth_pv+'.SET','Set')
+                sleep(0.5)
+                caput(tth_pv+'.VAL',0)
+                caput(tth_pv+'.DVAL',0)
+                sleep(0.5)
+                caput(tth_pv+'.SET','Use')
+                print("tth position reset to 0")
+            else:
+                print("That's ok, everybody can get cold feet in tough situation...")
+
diff --git a/build/lib/iexcode/instruments/Lakeshore_335.py b/build/lib/iexcode/instruments/Lakeshore_335.py
new file mode 100644
index 0000000000000000000000000000000000000000..5acc6b95dd8ba5c3da389836f2b159966a62fd99
--- /dev/null
+++ b/build/lib/iexcode/instruments/Lakeshore_335.py
@@ -0,0 +1,448 @@
+"""
+work in progress need to redo
+"""
+from time import sleep, strftime, localtime
+
+import numpy as np
+from epics import caget, caput
+
+
+from iexcode.instruments.IEX_endstations import *
+from iexcode.instruments.utilities import read_dict
+
+def Lakeshore_reset(pv,d):
+    """
+    resets the lake short to the default paramters defind in the dictionary d
+    """
+    for key in d.keys():
+        caput(pv+key,d[key])
+
+
+#############################################################################################################
+##############################             Lakeshore 335 Diode Curves        ##############################
+##############################################################################################################
+#---Settings as of 12/04/2018---
+#DiodeCurve_Write(22,"SI435")
+#DiodeCurve_SetInput("A",22,400)
+#DiodeCurve_Write(23,"SI410")
+#DiodeCurve_SetInput("B",23,450)
+
+
+
+# =============================================================================
+# def DiodeCurves(DiodeModel):
+#      DiodeCalibration={}
+#      DiodeCalibration["SI435"]=[0.00000,1.66751,1.64531,1.61210,1.57373,1.53247,1.49094,1.45196,1.41723,1.38705,1.36089,1.33785,1.31699,1.29756,1.27912,1.26154,1.24489,1.22917,1.21406,1.19855,1.18193,1.16246,1.13841,1.12425,1.11828,1.11480,1.11217,1.10996,1.10828,1.10643,1.10465,1.10295,1.10124,1.09952,1.09791,1.09629,1.09468,1.09306,1.09145,1.08983,1.08821,1.08659,1.08497,1.08334,1.08171,1.08008,1.07844,1.07681,1.07517,1.07353,1.07188,1.07023,1.06858,1.06693,1.06528,1.06362,1.06196,1.06029,1.05863,1.05696,1.05528,1.05360,1.05192,1.05024,1.04856,1.04687,1.04518,1.04349,1.04179,1.04010,1.03839,1.03669,1.03498,1.03327,1.03156,1.02985,1.02814,1.02642,1.02471,1.02299,1.02127,1.01957,1.01785,1.01612,1.01439,1.01267,1.01093,1.00918,1.00744,1.00569,1.00393,1.00218,1.00042,0.99865,0.99687,0.99510,0.99332,0.99153,0.98975,0.98795,0.98615,0.98434,0.98254,0.98073,0.97891,0.97710,0.97527,0.97344,0.97161,0.96978,0.96794,0.96609,0.96424,0.96239,0.96053,0.95867,0.95680,0.95492,0.95304,0.95116,0.94927,0.94738,0.94549,0.94358,0.94167,0.93976,0.93785,0.93592,0.93398,0.93203,0.93008,0.92812,0.92616,0.92418,0.92221,0.92022,0.91823,0.91623,0.91423,0.91222,0.91021,0.90819,0.90617,0.90414,0.90212,0.90008,0.89805,0.89601,0.89397,0.89293,0.88988,0.88783,0.88578,0.88372,0.88166,0.87959,0.87752,0.87545,0.87337,0.87129,0.86921,0.86712,0.86503,0.86294,0.86084,0.85874,0.85664,0.85453,0.85242,0.85030,0.84818,0.84606,0.84393,0.84180,0.83967,0.83754,0.83540,0.83325,0.83111,0.82896,0.82680,0.82465,0.82249,0.82032,0.81816,0.81599,0.81381,0.81163,0.80945,0.80727,0.80508,0.80290,0.80071,0.79851,0.79632,0.79412,0.79192,0.78972,0.78752,0.78532,0.78311,0.78090,0.77869,0.77648,0.77426,0.77205,0.76983,0.76761,0.76539,0.76317,0.76094,0.75871,0.75648,0.75425,0.75202,0.74978,0.74755,0.74532,0.74308,0.74085,0.73861,0.73638,0.73414,0.73191,0.72967,0.72743,0.72520,0.72296,0.72072,0.71848,0.71624,0.71400,0.71176,0.70951,0.70727,0.70503,0.70278,0.70054,0.69829,0.69604,0.69379,0.69154,0.68929,0.68704,0.68479,0.68253,0.68028,0.67802,0.67576,0.67351,0.67124,0.66898,0.66672,0.66445,0.66219,0.65992,0.65765,0.65538,0.65310,0.65083,0.64855,0.64628,0.64400,0.64172,0.63944,0.63716,0.63487,0.63259,0.63030,0.62802,0.62573,0.62344,0.62115,0.61885,0.61656,0.61427,0.61197,0.60968,0.60738,0.60509,0.60279,0.60050,0.59820,0.59590,0.59360,0.59131,0.58901,0.58671,0.58441,0.58211,0.57980,0.57750,0.57520,0.57289,0.57059,0.56828,0.56598,0.56367,0.56136,0.55905,0.55674,0.55443,0.55211,0.54980,0.54748,0.54516,0.54285,0.54053,0.53820,0.53588,0.53356,0.53123,0.52891,0.52658,0.52425,0.52192,0.51958,0.51725,0.51492,0.51258,0.51024,0.50790,0.50556,0.50322,0.50088,0.49854,0.49620,0.49385,0.49151,0.48916,0.48681,0.48446,0.48212,0.47977,0.47741,0.47506,0.47271,0.47036,0.46801,0.46565,0.46330,0.46095,0.45860,0.45624,0.45389,0.45154,0.44918,0.44683,0.44447,0.44212,0.43976,0.43741,0.43505,0.43270,0.43034,0.42799,0.42563,0.42327,0.42092,0.41856,0.41620,0.41384,0.41149,0.40913,0.40677,0.40442,0.40206,0.39970,0.39735,0.39499,0.39263,0.39027,0.38792,0.38556,0.38320,0.38085,0.37849,0.37613,0.37378,0.37142,0.36906,0.36670,0.36435,0.36199,0.35963,0.35728,0.35492,0.35256,0.35021,0.34785,0.34549,0.34313,0.34078,0.33842,0.33606,0.33371,0.33135,0.32899,0.32667,0.32428,0.32192]
+#      DiodeCalibration["SI410"]=[0.0000,1.7191,1.7086,1.6852,1.6530,1.6124,1.5659,1.5179,1.4723,1.4309,1.3956,1.3656,1.3385,1.3142,1.2918,1.2712,1.2517,1.2333,1.2151,1.1963,1.1759,1.1524,1.1293,1.1192,1.1146,1.1114,1.1090,1.1069,1.1049,1.1031,1.1014,1.0997,1.0980,1.0964,1.0949,1.0933,1.0917,1.0902,1.0886,1.0871,1.0855,1.0839,1.0824,1.0808,1.0792,1.0776,1.0760,1.0744,1.0728,1.0712,1.0696,1.0679,1.0663,1.0646,1.0630,1.0613,1.0597,1.0580,1.0563,1.0547,1.0530,1.0513,1.0497,1.0480,1.0463,1.0446,1.0429,1.0412,1.0395,1.0378,1.0361,1.0344,1.0327,1.0310,1.0293,1.0276,1.0259,1.0242,1.0224,1.0207,1.0190,1.0172,1.0155,1.0137,1.0120,1.0102,1.0085,1.0067,1.0049,1.0032,1.0014,0.9996,0.9978,0.9960,0.9942,0.9924,0.9905,0.9887,0.9869,0.9851,0.9832,0.9814,0.9795,0.9777,0.9758,0.9740,0.9721,0.9703,0.9684,0.9665,0.9646,0.9628,0.9609,0.9590,0.9571,0.9552,0.9533,0.9514,0.9495,0.9476,0.9457,0.9437,0.9418,0.9398,0.9379,0.9359,0.9340,0.9320,0.9300,0.9281,0.9261,0.9241,0.9222,0.9202,0.9182,0.9162,0.9142,0.9122,0.9102,0.9082,0.9062,0.9042,0.9022,0.9002,0.8982,0.8962,0.8942,0.8921,0.8901,0.8881,0.8860,0.8840,0.8820,0.8799,0.8779,0.8758,0.8738,0.8717,0.8696,0.8676,0.8655,0.8634,0.8613,0.8593,0.8572,0.8551,0.8530,0.8509,0.8488,0.8467,0.8446,0.8425,0.8404,0.8383,0.8362,0.8341,0.8320,0.8299,0.8278,0.8257,0.8235,0.8214,0.8193,0.8171,0.8150,0.8129,0.8107,0.8086,0.8064,0.8043,0.8021,0.8000,0.7979,0.7957,0.7935,0.7914,0.7892,0.7871,0.7849,0.7828,0.7806,0.7784,0.7763,0.7741,0.7719,0.7698,0.7676,0.7654,0.7632,0.7610,0.7589,0.7567,0.7545,0.7523,0.7501,0.7479,0.7457,0.7435,0.7413,0.7391,0.7369,0.7347,0.7325,0.7303,0.7281,0.7259,0.7237,0.7215,0.7193,0.7170,0.7148,0.7126,0.7104,0.7082,0.7060,0.7037,0.7015,0.6993,0.6971,0.6948,0.6926,0.6904,0.6881,0.6859,0.6837,0.6814,0.6792,0.6770,0.6747,0.6725,0.6702,0.6680,0.6657,0.6635,0.6612,0.6590,0.6567,0.6545,0.6522,0.6500,0.6477,0.6455,0.6432,0.6410,0.6387,0.6365,0.6342,0.6319,0.6297,0.6274,0.6251,0.6229,0.6206,0.6183,0.6161,0.6138,0.6115,0.6092,0.6070,0.6047,0.6024,0.6001,0.5979,0.5956,0.5933,0.5910,0.5887,0.5865,0.5842,0.5819,0.5796,0.5773,0.5750,0.5727,0.5705,0.5682,0.5659,0.5636,0.5613,0.5590,0.5567,0.5544,0.5521,0.5498,0.5475,0.5452,0.5429,0.5406,0.5383,0.5360,0.5337,0.5314,0.5291,0.5268,0.5245,0.5222,0.5199,0.5176,0.5153,0.5130,0.5107,0.5084,0.5061,0.5038,0.5015,0.4992,0.4968,0.4945,0.4922,0.4899,0.4876,0.4853,0.4830,0.4806,0.4783,0.4760,0.4737,0.4714,0.4690,0.4667,0.4644,0.4621,0.4597,0.4574,0.4551,0.4528,0.4504,0.4481,0.4458,0.4435,0.4411,0.4388,0.4365,0.4341,0.4318,0.4295,0.4271,0.4248,0.4225,0.4201,0.4178,0.4154,0.4131,0.4108,0.4084,0.4061,0.4037,0.4014,0.3991,0.3967,0.3944,0.4154,0.4131,0.4108,0.4084,0.4061,0.4037,0.4014,0.3991,0.3967,0.3709,0.3685,0.3662,0.3638,0.3615,0.3591,0.3567,0.3544,0.3520,0.3497,0.3473,0.3449,0.3426,0.3402,0.3379,0.3355,0.3331,0.3308,0.3284,0.3260,0.3237,0.3213,0.3189,0.3165,0.3142,0.3118,0.3094,0.3071,0.3047,0.3023,0.2999,0.2976,0.2952,0.2928,0.2904,0.2880,0.2857,0.2833,0.2809,0.2785,0.2761,0.2738,0.2714,0.2690,0.2666,0.2642,0.2618,0.2594,0.2570,0.2547,0.2523,0.2499,0.2475,0.2451,0.2427,0.2403,0.2379,0.2355,0.2331,0.2307,0.2283,0.2259,0.2235,0.2211,0.2187,0.2163,0.2139,0.2115,0.2091,0.2067,0.2043]
+#      return DiodeModel,DiodeCalibration[DiodeModel]
+# =============================================================================
+
+def DiodeCurve_Write_backup(CRVNum,DiodeModel):
+    """
+    Writes a Diode curve to the Lakeshore 335 temperature controller
+    Diode curves are saved in the fname=Dict_TempDiode.txt
+    usage:  DiodeCurve_Write(22,"SI435") to write to curve 22 the dictionary entry "SI435"
+            DiodeCurve_SetInput("A",22,400)
+    """
+    fname="Dict_TempDiode.txt"
+    PV="29idARPES:LS335:TC1:serial.AOUT"
+
+    t=1
+    index=1
+    #Curve Header
+    DiodeDict=read_dict(fname)
+    CRVHDR,CRVList=DiodeModel,DiodeDict[DiodeModel]
+    
+    cmd="CRVHDR "+str(CRVNum)+","+CRVHDR+",SN,2,"+str(len(CRVList)-1)+",1"
+    print(cmd)
+    caput(PV,cmd,wait=True,timeout=1800)
+    while t <len(CRVList):
+        if(t>=0 and t<30):
+            countby=1
+        elif(t>=30 and t<230):
+            countby=2
+        elif(t>=230):
+            countby=5
+        cmd="CRVPT "+str(CRVNum)+","+str(index)+","+str(CRVList[t])+","+str(t)
+        #print cmd
+        caput(PV,cmd,wait=True,timeout=1800)
+        #sleep(1)
+        t=t+countby
+        index+=1
+    #write 0,0 to indicate list is done
+    cmd="CRVPT "+str(CRVNum)+","+str(index)+","+str(CRVList[0])+","+str(0)
+    caput(PV,cmd,wait=True,timeout=1800)
+    print("last point = "+str(index))
+
+def DiodeCurve_Write(CRVNum,DiodeModel,run=True): #reversing order since it seems that the curve needs to go from high to low based on the built-in
+    """
+    Writes a Diode curve to the Lakeshore 335 temperature controller
+    Diode curves are saved in the fname=Dict_TempDiode.txt
+
+    run=True to write to the Lakeshoe
+    run=False to print only
+
+    usage:  DiodeCurve_Write(22,"SI435") to write to curve 22 the dictionary entry "SI435"
+            DiodeCurve_SetInput("A",22,400)
+    """
+    fname="Dict_TempDiode.txt"
+    PV="29idARPES:LS335:TC1:serial.AOUT"
+
+
+    #Curve Header
+    CRVList=read_dict(fname)[DiodeModel]
+    cmd="CRVHDR "+str(CRVNum)+","+DiodeModel+",SN,2,"+str(len(CRVList)-1)+",1"
+    if run == True:
+        caput(PV,cmd,wait=True,timeout=1800)
+    else:    
+        print(cmd)
+    
+    #Writing the individual terms (model 335 only supports index:1-200)
+    T1=50
+    T2=230
+    T3=len(CRVList)
+
+    T=np.arange(0,T1,1)
+    V=np.array(CRVList[0:T1])
+    
+    T=np.append(T,np.arange(T1,T2,2))
+    V=np.append(V,np.array(CRVList[T1:T2:2]))
+
+    T=np.append(T,np.arange(T2,T3,5))
+    V=np.append(V,np.array(CRVList[T2:T3:5]))
+    
+    #reverse order
+    T=T[::-1]
+    V=V[::-1]
+    
+    for i,t in enumerate(T):
+        cmd="CRVPT "+str(CRVNum)+","+str(i+1)+","+str(V[i])+","+str(t)
+        #cmd="index,v,t"+str(i+1)#+","+str(V[i])+","+str(t)
+        if run == True:
+            caput(PV,cmd,wait=True,timeout=1800)
+        else:    
+            print(cmd)
+
+def DiodeCurve_SetInput(Channel,Curve,Tmax):
+    """
+    Sets the diode curve for a given channel on the Lakeshore 335 temperature controller
+        DiodeCurve_SetInput("A",22,400)
+        Channel: A or B
+        Curve: set by DiodeCurve_Write(22,"SI435")
+        Tmax: max temperature for that diode
+    (pg 118 of manual)
+    """
+    
+    PV="29idARPES:LS335:TC1:serial.AOUT"
+    #Set curve info
+    cmd="INTYPE "+Channel+","+"1,0,0,0,1"
+    caput(PV,cmd,wait=True,timeout=1800)
+    #Select curve
+    cmd="INCRV "+Channel+","+str(Curve)
+    caput(PV,cmd,wait=True,timeout=1800)
+    #Set temperature Limit
+    cmd="TLIMIT "+Channel+","+str(Tmax)
+    caput(PV,cmd,wait=True,timeout=1800)
+
+##############################################################################################################
+##############################             PID Settings            ##############################
+##############################################################################################################
+
+
+#Setting the PID
+#    Set P=10, I=0, D=0; Set T and range,
+#        if T oscilate above setpoint, P/=2
+#        if T doesn't reach setpoint, P*=2
+#        if T swings above setpoint but then settle below use this P
+#    Set I=10; smaller I, more reactive (approximately time(sec) for one full oscillation period
+#    Set D=I/4
+#Lakeshore 355 I = time in seconds for one oscilation / 1000; D=50-100 for starters
+
+
+def PID_dict(which,T): #Dictionary of PID setting to try for the ARPES chamber
+    """Dictionary for common PID setting for the ARPES system.
+    Since the PID is dependent on the cooling power, this will change with the cryogen and the flow rate:
+        - Flow = "LHe,LN" =>  LHe = needle valve = "on" and flow = 70
+    """
+    PID={}
+#    PID[which,T]=[P,I,D,Range]    Range=HIGH,MEDIUM,LOW,OFF
+    PID['RT', 378.0]=[200.0,0.0,0.0,'MEDIUM']
+    PID['RT', 375.0]=[200.0,0.0,0.0,'MEDIUM']
+    PID['RT', 338.0]=[100.0,0.0,0.0,'MEDIUM']
+    PID['RT', 298.0]=[20.0,0.0,0.0,'LOW']
+    PID['GHe', 378.0]=[210.0,0.0,0.0,'MEDIUM']
+    PID['GHe', 375.0]=[210.0,0.0,0.0,'MEDIUM']
+    PID['GHe', 338.0]=[130.0,0.0,0.0,'MEDIUM']
+    PID['GHe', 298.0]=[60.0,0.0,0.0,'MEDIUM']
+    PID['GHe', 250.0]=[10.0,0.0,0.0,'LOW']
+    PID['LHe',298.0]=[20.0,5.0,1.0,'HIGH']     # +/- 1.1 deg, over 10 min, heater power 53%
+    PID['LHe',200.0]=[10.0,5.0,1.0,'HIGH']     # +/- 1.1 deg, over 10 min, heater power 53%
+    PID['LHe',150.0]=[200.0,0.1,0,'HIGH']     # Stablized at 153, heater power 43%
+    PID['LHe',180.0]=[200.0,0.1,0,'HIGH']
+    PID['LHe',230.0]=[200.0,0.1,0,'HIGH']
+    PID['LHe',300.0]=[200.0,0.1,0,'HIGH']
+    PID['LHe',40.0]=[200.0,0.1,0,'HIGH']     #
+    PID['LN2',230]=[10.0,0.6,100,'HIGH']        #stable 237.83, needle valve=ON; flow 6 half turns from max)
+    PID['LN2',180]=[50.0,4,100,'MEDIUM']
+    return PID[which,T]
+
+def PID_set(which,T,heater='ON'):
+    """
+    Uses preset PID settings as defined in PID_dict()
+    To cool down: heater='OFF'
+
+    """
+    P,I,D,Range=PID_dict(which,T)
+    caput("29idARPES:LS335:TC1:P1",P)
+    caput("29idARPES:LS335:TC1:I1",I)
+    caput("29idARPES:LS335:TC1:D1",D)
+    if heater == 'ON':
+        caput("29idARPES:LS335:TC1:HTR1:Range",Range)
+    elif heater == 'OFF':
+        caput("29idARPES:LS335:TC1:HTR1:Range",'OFF')
+    print('\nP = ',PID_dict(which,T)[0])
+    print('I = ',PID_dict(which,T)[1])
+    print('D = ',PID_dict(which,T)[2])
+    print('Range = ',PID_dict(which,T)[3])
+
+
+def SetT_Sample(which,T,precision=5,minutes=15,offset=6):
+    """
+    Sets PID settings for a given set point as defined in PID_dict().
+    Available set points:
+        which = 'RT' : T = 298, 338, 375
+        which = 'LHe': T = 150, 200
+        which = 'GHe': T = 250, 298, 338, 370
+        which = 'LN2': T = 230, 180
+        precision is temperature in K
+    """
+    current_T=caget("29idARPES:LS335:TC1:IN1")
+    print('\nSet T to '+ str(T)+' K   @ '+ dateandtime())
+    if T>current_T:
+        PID_set(which,T,'ON')
+        Range=PID_dict(which,T)[3]
+        SetT_Up(T,offset,Range,precision,minutes)
+    else:
+        PID_set(which,T,'OFF')
+        Range=PID_dict(which,T)[3]
+        SetT_Down(T,offset,Range,precision,minutes)
+    caput("29idARPES:LS335:TC1:OUT1:SP",T)
+
+
+def SetT_Up(T,offset,Range,precision=5,minutes=15):
+    if Range=='LOW':    Range=1
+    if Range=='MEDIUM': Range=2
+    if Range=='HIGH':   Range=3
+    t=15
+    u=0
+    caput('29idARPES:LS335:TC1:OUT1:SP',T)                # set the set point to T
+    while True:                            # while TA < T
+        TA=caget('29idARPES:LS335:TC1:IN1')                # get current temperature at the sample
+        TB=caget('29idARPES:LS335:TC1:IN2')                # get current temperature (B=cold finger)
+        if TA<T-precision:                                  # if it hasn't reach SP
+            caput("29idARPES:LS335:TC1:HTR1:Range",min(Range,3))            # increase heater range to Range +1
+            while True:                                # while TB < T+offset:
+                TB=caget('29idARPES:LS335:TC1:IN2')                    # get current temperature at the cold finger
+                if (t%120)==0:
+                    print('\nTA = ',TA,'  TB = ',TB, '  @  ',dateandtime())
+                if TB<(T+offset) and t<=minutes*60:                            #if it hasn't reach the SP+offser
+                    sleep(15)
+                    t+=15
+                    #print t, TA, TB
+                elif TB<(T+offset) and t>minutes*60:
+                        heater_power=caget('29idARPES:LS335:TC1:HTR1')
+                        heater_range=caget('29idARPES:LS335:TC1:HTR1:Range')
+                        if heater_power > 90:
+                            caput("29idARPES:LS335:TC1:HTR1:Range",min(heater_range+1,3))
+                            print('Change Range to',caget('29idARPES:LS335:TC1:HTR1:Range'),'  @  ',dateandtime())
+                        elif heater_range==3 or heater_power<=90:
+                            P=caget("29idARPES:LS335:TC1:P1")
+                            caput("29idARPES:LS335:TC1:P1",P*1.5)
+                            print('Change P to',caget("29idARPES:LS335:TC1:P1"),'  @  ',dateandtime())
+                        t=0
+    
+                else:                                    #else
+                    break                                    # break
+            caput("29idARPES:LS335:TC1:HTR1:Range",'OFF')                # turn off the heater
+        elif TA>T-precision:                            # if it has reach the set point
+            break                                    # break
+    print('TA = ',TA,'  TB = ',TB, '  @  ',dateandtime())        # print temperatures
+    caput("29idARPES:LS335:TC1:HTR1:Range",Range)            # set the heater range to preset value
+
+
+
+
+
+
+def SetT_Down(T,offset,Range,precision=5,minutes=15):
+    t=0
+    caput('29idARPES:LS335:TC1:OUT1:SP',T)                # set the set point to T
+    while True:                            # while TA < T
+        TA=caget('29idARPES:LS335:TC1:IN1')
+        TB=caget('29idARPES:LS335:TC1:IN2')
+        if (t%120)==0:
+            print('\nTA = ',TA,'  TB = ',TB, '  @  ',dateandtime())
+        if TA>T+precision:
+            sleep(15)
+            t+=15
+        elif t>minutes*60:
+                P=caget("29idARPES:LS335:TC1:P1")
+                caput("29idARPES:LS335:TC1:P1",P/1.5)
+                t=0
+        else:
+            break
+    caput("29idARPES:LS335:TC1:HTR1:Range",Range)
+    print('TA = ',TA,'  TB = ',TB, '  @  ',dateandtime())
+
+
+def Get_PID(which='LHe'):
+    T=caget("29idARPES:LS335:TC1:IN1")
+    SP=caget("29idARPES:LS335:TC1:OUT1:SP")
+    P=caget("29idARPES:LS335:TC1:P1")
+    I=caget("29idARPES:LS335:TC1:I1")
+    D=caget("29idARPES:LS335:TC1:D1")
+    Range=caget("29idARPES:LS335:TC1:HTR1:Range",as_string=True)
+#    print SP,P,I,D,Range
+    print("Current T:", T,'K')
+    print("PID[\'"+which+"\',"+str(SP)+"]=["+str(P)+","+str(I)+","+str(D)+",\'"+Range+"\']")
+
+
+
+##############################################################################################################
+##############################             SI9700 Kludge         ##############################
+
+##############################################################################################################
+def ResetPID():
+    caput('29idd:tc1:SetPID_1.INPA','')
+    caput('29idd:tc1:SetPID_1.INPB','')
+    caput('29idd:tc1:SetPID_1.INPC','')
+
+def GetCurrentPID():
+    T=caget('29idd:tc1:getVal_A.VAL')
+    P=caget('29idd:tc1:SetPID_1.A')
+    I=caget('29idd:tc1:SetPID_1.B')
+    D=caget('29idd:tc1:SetPID_1.C')
+    return T,P,I,D
+
+def SetTempSetting(T,P,I,D):
+    #Change the sample temperature T with the specified PID values
+    caput('29idd:tc1:getVal_A.VAL',T)
+    caput('29idd:tc1:SetPID_1.A',P)
+    caput('29idd:tc1:SetPID_1.B',I)
+    caput('29idd:tc1:SetPID_1.C',D)
+
+# GetCurrentPID => (60.0121, 8.0, 50.0, 12.0) ## Temperature overshoots no more than 5.5 degrees
+#it takes about 3 min to stablize at any temp
+#cooling is about 10 degrees/min
+
+
+#functions use from ScanFunctions_IEX import BL_ioc
+def PVLakeshores(which):
+    """
+    which = RSXS / ARPES /Hydra / DetPool
+    usage:  P, Sample, ColdFinger, SetPoint = PVLakeshores[which]
+    """
+    # key:
+    
+    d={"Kappa":("29idd:LS331:TC1:","SampleA","SampleB","wr_SP"),
+       "ARPES":("29idARPES:LS335:TC1:","IN1","IN2","OUT1:SP"),
+       "Hydra":("29idc:LS340:TC2:","Sample","Control","wr_SP1"),
+       "DetPool":("29idc:LS340:TC1:","Sample","Control","wr_SP1") 
+    }
+    return d[which]
+    
+def dateandtime():
+    return strftime("%a %d %b %Y %H:%M:%S",localtime())
+
+def tempr(which=None):
+    """
+    reads the temperature in the current branch unless otherwise specificed
+    """
+    if which == None:
+        which=BL_ioc()
+    PVs=PVLakeshores(which)
+    sample=PVs[0]+PVs[1]
+    print(which+" Sample Temperature: {} K".format(caget(sample)))
+    
+def temps(tempset,which=None):    
+    """
+    Set sthe sample temperature set point and waits for it to stablelize for the current branch 
+    unless specified by which = Kappa / ARPES /Hydra set by PVLakeshores
+    """
+    if which == None:
+        which=BL_ioc()
+        
+    P, Sample, ColdFinger, SetPoint = PVLakeshores(which)
+    
+    print("Initial Sample Temperature:",caget(P+Sample)," K",dateandtime())
+    caput(P+SetPoint,1.0*tempset)
+    stop_var=0
+    b=0
+    sleep(0)
+    while b == 0:
+        delta=abs(caget(P+Sample)-1.0*tempset)
+        if abs(delta) < 1:
+            c=0
+            while c < 10:
+                sleep(1)
+                delta=delta+(caget(P+Sample)-1.0*tempset)
+                c=c+1
+            if abs(delta/10) < 1:
+                print("Stable Sample Temperature:",caget(P+Sample)," K",dateandtime())
+                b=1
+            else:
+                temp1=caget(P+Sample)
+                sleep(10)
+                temp2=caget(P+Sample)
+                if abs(temp1-temp2) < 0.1:
+                    sleep(30)
+                    temp2=caget(P+Sample)
+                    if abs(temp1-temp2) < .5:
+                        print("UNABLE TO STABLIZE TEMPERATURE! Stopped at T=:",caget(P+Sample)," K",dateandtime())
+                        b=1
+                        
+def ARPES_warming(Tmax,PowerMax=50,Tdiff=10):
+    """
+    Ramps the temperature up for ARPES using open loop and manual power at PowerMax with 
+    the heater on High until Tmax - Tdif is reached and then switches to 
+    closed loop with the heater on Medium
+    
+    PowerMax=50,Tdiff=10
+    PowerMax=55,Tdiff=25
+    """
+
+    P="29idARPES:LS335:TC1:"
+    #Needs modified in controller changed            
+    Tsample=P+"IN1"
+    Tcontrol=P+"IN2"
+    Tsetpoint=P+"OUT1:SP"
+    HeaterRange=P+"HTR1:Range"
+    ControlMode=P+"OUT1:Mode"
+    ManualPower=P+"OUT1:MOUT"
+
+    caput(Tsetpoint,Tmax)
+    caput(ManualPower,PowerMax)
+    caput(ControlMode,"Open Loop")
+    caput(HeaterRange,'HIGH')
+    
+    print("T", caget(Tsample)) 
+    print("Started warming:", dateandtime()) 
+    
+    while True:
+        TA=caget(Tsample)
+        TB=caget(Tsample)
+        if TB >= Tmax:
+            print ("Control is to high",TB)
+            break
+        if TA < Tmax - Tdiff:
+            sleep(60)
+        else:
+            break
+    print("T", caget(Tsample)) 
+    print("Switch to closed loop", dateandtime())  
+   
+    caput(HeaterRange,'MEDIUM');sleep(1)
+    caput(ControlMode,"Closed Loop");sleep(1)
+    caput(HeaterRange,'OFF');sleep(1)
+    caput(HeaterRange,'MEDIUM');sleep(1)
+    temps(Tmax,which='ARPES')
diff --git a/build/lib/iexcode/instruments/Motors.py b/build/lib/iexcode/instruments/Motors.py
new file mode 100644
index 0000000000000000000000000000000000000000..119b51bb725c0a065f3f6eb245b342d17eb3dad4
--- /dev/null
+++ b/build/lib/iexcode/instruments/Motors.py
@@ -0,0 +1,232 @@
+import time
+from math import floor
+
+from epics import caget, caput
+
+from iexcode.instruments.IEX_endstations import *
+
+
+class Motors:
+    """ 
+    short hand to move motors in endstation
+    usage motors = Motor('ARPES','ARPES_motor_dictionary')
+    """
+
+    def __init__(self,endstation_name,motor_dictionary,physical_motors,
+    psuedo_motors):
+        self.endstation_name = endstation_name
+        self._motor_dictionary = motor_dictionary
+        self.physical_motors = physical_motors
+        self.pseudo_motors = psuedo_motors
+           
+    def info(self):
+        print("physical motors:",self.physical_motors)
+        print("pseudo motors:",self.pseudo_motors)
+    
+    def get(self,name,verbose=False):   
+        """
+        get current position of motor name = "x","y"...
+        """   
+
+        try:
+            rbv = caget(self._motor_dictionary(name)[0])
+            if verbose:
+                print('current position: '+name+" = "+str(rbv))
+            return rbv
+        except:
+            print("Not a valid motor name") 
+    
+    def reset(self,name):
+        """
+        Reset motor if stuck in 'moving'
+        """
+        pv=self._motor_dictionary(name)[2]
+        caput(pv,'Stop')
+        time.sleep(1)
+        caput(pv,'Go')
+        
+    def status(self):
+        """
+        if status == 0 then moving
+        """
+        status = 0
+        for motor in self._motor_dictionary.keys():
+            status *= caget(self._motor_dictionary[motor][3]+".DMOV")
+        return status
+
+    def move(self,name,val,**kwargs):
+        """
+        Moves a motor in the endstation based on common name, not PV name
+        
+        name: motor name => 'x','y','z','th','chi','phi' ...
+        val: absolute position if relative=False, delta if relative=True
+        
+        **kwargs:
+            relative: move mode => True/False; default = False (absolute)
+            wait: wait for move completion before moving on => True/False; default=True
+            verbose: print old and new motor position => True/False; default=False
+
+
+        Previously: Move_ARPES_Motor or Move_ARPES_Motor or motor_move_vs_Branch
+        """
+        kwargs.setdefault('relative',False)
+        kwargs.setdefault('wait',True)
+        kwargs.setdefault('verbose',False)
+
+        try:
+            rbv_pv,val_pv,sgm_pv,pv = self._motor_dictionary[name]
+            old_position = caget(rbv_pv)
+            if kwargs['relative']:
+                val = old_position + val
+            
+            caput(val_pv,val,wait=kwargs['wait'],timeout=18000)
+            
+            new_position = caget(rbv_pv)
+            if kwargs['verbose']:
+                print('old: '+name+" = "+str(old_position))
+                print('new: '+name+" = "+str(new_position))
+        except:
+            print(name+" is not a valid motor name")
+
+
+
+    def dmove(self,name,val,**kwargs):
+        """
+        relative move of a motor in the endstation based on common name, not PV name
+        name = x,y,z,th,chi,phi ...
+
+        **kwargs:
+            wait: wait for move completion before moving on => True/False; default=True
+            verbose: print old and new motor position => True/False; default=False
+
+        Previously: motor_umove_vs_Branch
+        """
+        kwargs.setdefault('wait',True)
+        kwargs.setdefault('verbose',False)
+
+        self.move(name,val,relative=True,wait=kwargs['wait'],verbose=kwargs['verbose'])
+
+    def mprint(self):
+        """
+        prints current position of the physical motors
+        """
+        position_list = []
+        for motor in self.physical_motors():
+            position_list.append(self.get(motor,verbose=False))
+        return position_list
+
+    def mvsample(self,position_list,verbose=True):
+        """
+        moves the sample to the position sepcified by position_list
+        position_list = ['description',x,y,z,th,chi,phi]
+
+        Previously: sample
+        """
+        if not isinstance(position_list[0],str):
+            sample_name = ''
+        else:
+            sample_name = position_list[0]
+            position_list = position_list[1:]
+
+        motor_list = self.physical_motors()
+        for motor,i in enumerate(motor_list):
+            self.move(motor,position_list[i])
+
+        if verbose:
+            print("Sample now @ "+sample_name)
+
+    def scan(self,name,start,stop,step, **kwargs):
+        """
+        scans a motor
+        
+        **kwargs:
+            relative: move mode => True/False; default = False (absolute)
+            scan_dim: 1  (default)
+            execute: True/False to start the scan => True (default)
+
+            for Kappa only:
+                cts: scaler integration time in seconds (default = 0.1 s)
+                mpa: True/False to sum mpa acquisitions
+            
+            Previously Scan_ARPES_motor / Scan_Kappa_motor
+        """
+        kwargs.setdefault('relative',False)
+        kwargs.setdefault('scan_dim',1)
+        kwargs.setdefault('execute',True)
+        #for kappa only
+        kwargs.setdefault('cts',0.1)
+        kwargs.setdefault('mpa',False)
+
+        rbv_pv,val_pv,sgm_pv,pv =self._motor_dictionary()[name]
+
+        if kwargs['mode'] == "relative":
+            current_value = caget(rbv_pv)
+            abs_start = round(current_value + start,3)
+            abs_stop  = round(current_value + stop,3)
+            print("start, stop, step = "+str(abs_start)+", "+str(abs_stop)
+            +", "+str(step))
+        else:
+            abs_start = start
+            abs_stop = stop
+        
+        self._scalar_cts(kwargs['cts'],verbose=True,**kwargs)
+        BL.mda.fillin(val_pv,rbv_pv,abs_start,abs_stop,step,**kwargs)
+        
+        if kwargs['execute']:
+            BL.mda.go(**kwargs)
+
+
+    def scan_2D(self,inner_loop_list,outer_loop_list,**kwargs):
+        """
+        Fills in a the Scan Record for a 2D scan (Mesh), does NOT press go
+        InnerMotorList=[name1,start1,stop1,step1] #scanDIM=2
+        OuterMotorList=[name2,start2,stop2,step2] #scanDIM=3
+            name = 'x'/'y'/'z'/'th'...    
+        
+        **kwargs:
+            relative: scab => True/False; default = False (absolute)
+            outer_scan_dim: 2  (default)
+            execute: True/False to start the scan => True (default)
+            Snake; coming soon
+
+
+            for Kappa only:
+                cts: scaler integration time in seconds (default = 0.1 s)
+                mpa: True/False to sum mpa acquisitions
+
+        """
+        kwargs.setdefault('mode','absolute')
+        kwargs.setdefault('outer_scan_dim',2)
+        kwargs.setdefault('snake',False)
+        kwargs.setdefault('execute',True)
+        #for kappa only
+        kwargs.setdefault('cts',0.1)
+        kwargs.setdefault('mpa',False)
+
+        rbv_pv,val_pv,sgm_pv,pv = self._motor_dictionary()[inner_loop_list[0]]
+        inner_loop_list.insert(0,rbv_pv)
+        inner_loop_list.insert(0,val_pv)
+        
+        rbv_pv,val_pv,sgm_pv,pv = self._motor_dictionary()[outer_loop_list[0]]
+        outer_loop_list.insert(0,rbv_pv)
+        outer_loop_list.insert(0,val_pv)
+
+        if kwargs["mode"] == "relative":
+            current_value1 = caget(inner_loop_list[1])
+            inner_loop_list[2]=round(current_value1+inner_loop_list[2],3)
+            inner_loop_list[3]=round(current_value1+inner_loop_list[3],3)
+
+            current_value2 = caget(outer_loop_list[1])
+            outer_loop_list[2]=round(current_value1+outer_loop_list[2],3)
+            outer_loop_list[3]=round(current_value1+outer_loop_list[3],3)
+
+        scalar_cts(kwargs['cts'],verbose=True,**kwargs)
+        BL.mda.fillin_2D(inner_loop_list,outer_loop_list,
+        outer_scan_dim=kwargs['outer_scan_dim'],**kwargs)
+
+        if kwargs['execute']:
+            BL.mda.go(**kwargs)
+
+
+
+
diff --git a/build/lib/iexcode/instruments/Scienta.py b/build/lib/iexcode/instruments/Scienta.py
new file mode 100644
index 0000000000000000000000000000000000000000..f493664c17207aa84874be71aee4433e459c25f8
--- /dev/null
+++ b/build/lib/iexcode/instruments/Scienta.py
@@ -0,0 +1,578 @@
+import time
+import numpy as np
+from epics import caget,caput, PV
+
+
+
+
+#-----------------------------------------------
+#--- Beamline dependent PVs and definitions  ---
+#-----------------------------------------------
+P="29idcScienta:"
+PHV=P+'HV:'
+Pcam =P+'basler:cam1:'
+savePlugin = P+"HDF1:"
+statsPlugin = P+"Stats4:"
+dtype = "h5"
+#energy scaling
+KEpix=0.0000845#*PE
+KEwidth=0.1085#*PE
+
+
+def AllowedEnergyRange(*args):
+    """
+    KEmin, KEmax for a given PassEnergy, LensMode combination
+    *args 
+           = PassEnergy, LensMode => returns KEmin,KEmax
+           = empty => returns entire table
+ 
+    """
+    Table={}
+    Table['Transmission']={1:(0,76),2:(0,107),5:(1,237),10:(1,453),20:(3,968),50:(7,6041),100:(21,6000),200:(30,6206),500:(283,6504)}
+    Table['Angular']={1:(None,None),2:(1,52),5:(2,131),10:(2,262),20:(10,523),50:(24,1309),100:(34,6105),200:(230,6206),500:(None,None)}
+    Table['Angular_01']={1:(None,None),2:(None,None),5:(None,None),10:(None,None),20:(None,None),50:(126,2947),100:(252,1401),200:(844,1261),500:(None,None)}
+    Table['Angular_05']={1:(None,None),2:(None,None),5:(None,None),10:(None,None),20:(None,None),50:(None,None),100:(252,1323),200:(1043,1270),500:(None,None)}
+    
+    if len(args)<1:
+        return Table
+    
+    if len(args)==2:
+        try:
+            PassEnergy,LensMode=args
+            KEmin,KEmax=Table[LensMode][PassEnergy]
+            return KEmin,KEmax
+        except:
+            return None
+    else:
+        print('Not a valid argument')
+
+#############################################################
+########### Scienta python control functions ################
+#############################################################
+
+class Scienta:
+    """
+    Scienta only talks in 'KE' anything related to the binding energy happens outside of these
+    controls
+    Usage: 
+        EA=Scienta()
+        EA.get(); cagets all Scienta parameters and returns vars(EA); dictionary of variables
+        EA.PE(),EA.KE(),EA.LensMode()
+    """
+    
+    def __init__(self):
+        #High Voltage Setting
+        self.PHV = PHV
+        self._Pcam=Pcam
+        self._savePlugin=savePlugin
+        self._statsPlugin=statsPlugin
+        
+        self.dtype=dtype
+        self.wk = None
+
+        self.ElementSet = None #HV for XPS, LV for UPS
+
+        self.LensMode = None
+        self.PassEnergy = None
+        self.KineticEnergy = None
+        self.SpectraMode = None
+
+        #Camera Settings
+        self.Frames = None
+        
+        self.get()
+        return  
+
+    def get(self,q=1):
+        """ 
+        Gets the current Scienta parameters
+        returns the dictionary for q!=1
+        """
+        for key in vars(self):
+            if key not in ["PHV","_Pcam","_savePlugin","_statsPlugin","wk","Frames","dtype"]:
+                vars(self)[key]=caget(self.PHV+key+".VAL")
+            if key  in ["LensMode","SpectraMode"]:
+                vars(self)[key]=caget(self.PHV+key+".VAL",as_string=True)
+            if key == "Frames":
+                vars(self)[key]=caget(self.PHV.split(':')[0]+':'+"ExpFrames.VAL")
+            if key == "wk":
+                vars(self)[key]=caget(self.PHV+"WorkFunction")
+        if q !=1:
+            for key in vars(self):
+                print(key+" = "+str(vars(self)[key]))
+
+        return vars(self)
+
+    def counts(self):
+        """
+        returns the current intensity on the Scienta using EA.
+        """
+        return caget(self._savePlugin+"Total_RBV")
+
+    def _errorCheck(self,KineticEnergy,PassEnergy,LensMode,Frames,**kwargs):
+        """
+        check the parameters to see if they are allowed
+
+        returns list of errors
+        **kwargs:
+            debug=False
+        """
+        kwargs.setdefault('debug',False)
+        if kwargs['debug']:
+            print("\n _errorCheck")
+        error=[]
+        
+        if LensMode not in AllowedEnergyRange().keys():
+            error.append("LensMode = "+LensMode+" is not a valid")
+        elif PassEnergy not in AllowedEnergyRange()[LensMode]:
+            error.append("PassEnergy = "+str(PassEnergy)+" is not a valid")
+        try:
+            KEmin,KEmax=AllowedEnergyRange(PassEnergy,LensMode)
+            if KEmin>KineticEnergy or KineticEnergy>KEmax: 
+                 error.append("Kinetic Energy: "+str(KineticEnergy)+" is outside allowed range for this Lens Mode,Pass Energy combination")
+        except:
+            error.append("Undefined PassEnergy/LensMode Combination "+str(PassEnergy
+                                                                         )+"/"+LensMode)
+        if Frames < 1:
+            error.append("Frames must be 1 or greater")
+        return error
+
+    def put(self, KE=None, PE=None, LensMode="Angular",Frames=1,**kwargs):
+        """
+        Used to set all the SES parameters at once
+        KE = kinetic energy (None keeps the current KE)
+        PE = pass energy (None keeps the current PE)
+        LensMode = "Angular"/"Transmission"
+        
+        **kwargs
+            debug
+        """
+       
+        kwargs.setdefault('debug',False)
+        parms=self.get(q=1)
+        if kwargs['debug']:
+            print("\n EA.put")
+            print('KE,PE,LensMode,Frames = ',KE,PE,LensMode,Frames)
+        time.sleep(.1)
+        if KE != None:
+            parms.update({"KineticEnergy":KE})
+        else:
+            parms.update({"KineticEnergy":self.KineticEnergy})
+        if PE != None:
+            parms.update({"PassEnergy":PE})
+        else:
+            parms.update({"PassEnergy":self.PassEnergy})
+        parms.update({"LensMode":LensMode})
+        parms.update({"Frames":Frames})
+       
+        if kwargs['debug']:
+            print("parms:",parms)
+        
+        time.sleep(.5)
+        self._setHV(parms)
+        
+    def _setHV(self,parms,**kwargs):
+        """
+        Error checks and sets the Scienta high voltage supplies
+            parms={'LensMode':LensMode,
+               'PassEnergy':PassEnergy
+               'KineticEnergy':KineticEnergy,
+               'Frames':Frames}
+               
+        kwargs:
+            q: quiet (default = 1); to print the dictionary q!=1
+        """    
+        kwargs.setdefault('q',1)
+        kwargs.setdefault('debug',False)
+        
+        if kwargs['debug']:
+            print('\n _setHV')
+            print(parms)
+            
+        #checking for errors
+        error=self._errorCheck(parms['KineticEnergy'],parms['PassEnergy'],parms['LensMode'],parms['Frames'])
+        if kwargs['debug']:
+            print(error)
+        
+        #setting Frames
+        self._frames(parms['Frames'])
+        
+        if len(error) == 0:
+            caput(self.PHV+"LensMode",parms["LensMode"])
+            time.sleep(.25)  
+            caput(self.PHV+"PassEnergy_Set",str(int(parms["PassEnergy"])))
+            time.sleep(0.25)
+            caput(self.PHV.split(':')[0]+':'+"ExpFrames",parms["Frames"])
+            time.sleep(.25)
+            caput(self.PHV+"KineticEnergy",parms["KineticEnergy"]+0.01)
+            time.sleep(1)
+            caput(self.PHV+"KineticEnergy",parms["KineticEnergy"])
+            time.sleep(1)
+    
+            self.get()
+            if kwargs['q'] !=1:
+                for key in vars(self):print(key+" = "+str(vars(self)[key]))
+
+        else:
+            for e in error:
+                #print(e) #JM need to modify
+                x=5
+        return        
+
+    def off(self,quiet=True):
+        """
+        Zeros the high voltage supplies
+        """
+        self.zeroSupplies()
+        if quiet == False:
+            print ("EA HV is zeroed, visually confirm")
+
+    def zeroSupplies(self):
+        """
+        Zeros the Scienta HV supplies (safe-state)
+        """
+        caput(self.PHV+"ZeroSupplies.RVAL",1)
+        caput(self.PHV+"ZeroSuppliesSeq.PROC",1)
+
+
+    def KE(self,val):
+        """
+        Sets the kinetic energy of the Scienta
+        KE should be grearter than the PassEnergy 
+        """
+        self.put(KE=val)
+
+
+    def _setwk(self,val):
+        """
+        Sets the wk to the value specified
+        """
+        caput(self.PHV+"WorkFunction",val)
+
+    def PE(self,val):
+        """
+        Sets the pass energy of the Scienta
+        PassEnergy: 1, 2, 5, 10, 20, 50, 100, 200, 500
+        """
+        self.put(PE=val)
+        
+    def lensMode(self,val):
+        """
+        Sets the pass energy of the Scienta
+        LensMode: 'Transmission','Angular','Angular_01','Angular_05'
+        """
+        self.put(LensMode=val)
+
+    def _frames(self,val,q=1):
+        """
+        Sets the number of frames
+        Frames >=1
+        """
+        caput(self.PHV.split(':')[0]+':'+"ExpFrames.VAL",val)
+
+
+    def _ElementSet(self,mode,q=1):
+        """
+        Used to switch between 
+        0: High Energy (XPS) and 1:Low Energy (UPS) mode
+        Must be done in conjunction with changing the cabling on the front of the HV supply
+        mode = 0 or 1
+        """
+        caput(self.PHV+"ElementSet",mode)
+        self.get()
+        if q !=1:
+            for key in vars(self):print(key+" = "+str(vars(self)[key]))
+        return  
+
+        
+    def _BurstSupplies(self,val):
+        """
+        BurstSupplies:'Fast','Slow'
+        """
+        caput(self.PHV+"BurstSupplies",val,as_string=True)
+
+    def _AcqCalc(self,val):
+        """
+        AcqCalc:'Off','Live','Scan'
+        """
+        caput(self.PHV+"AcqCalc",val,as_string=True)
+
+    def _AcquisitionMode(self,val):
+        """
+        AcquisitionMode: 'Off','Scan','Spectra'
+        """
+        caput(self.PHV+"AcquisitionMode",val)
+
+    def _ScientaMode(self,val):
+        """
+        ScientaMode: 'BetaScan','XYScan','Fixed','BabySweep','SweepOverlapping','SweepNo'
+        """
+        caput(self.PHV+"ScientaMode",val,as_string=True)
+    
+    
+    def _babySweepSteps(self,val):
+        """
+        sets the number of steps in baby sweep
+        """
+        caput(self.PHV+"babySweepSteps.VAL",val)
+
+    def _spectraStatus(self):
+        """
+        checking the spectra status
+        returns 1=busy or 0=idle
+        """
+        status=caget(self.PHV+'ScanTrigger')
+        return status
+
+    def _spectraProgress(self):
+        """
+        Monitors the spectra status every 30 seconds
+        returns 0 when the spectra scan is idle
+        """
+        while True:
+            status=self._spectraStatus()
+            if (status==1):
+                time.sleep(30)
+            else:
+                break
+        return 0
+    
+    def _SpectraMode(self,Mode):
+        """
+        Checks that Mode exists and sets the mode 
+
+        """
+        DefinedModes=["Fixed","Baby-Sweep","Sweep"]
+        if Mode in DefinedModes:
+            caput(self.PHV+"SpectraMode", "Mode")
+        else: 
+            print("Not a defined SpectraMode")
+
+    def _spectraInfo(self):
+        """
+        returns the pertainent information for a given spectra type
+            modeNum=2; Swept=[start,stop,step]
+        """
+        modeNum=caget(self.PHV+"SpectraMode")
+        scanType=caget(self.PHV+"SpectraMode",as_string=True)
+        info=[]
+        if modeNum==2: #swept
+            info.append(caget(self.PHV+"sweepStartEnergy"))
+            info.append(caget(self.PHV+"sweepStopEnergy"))
+            info.append(caget(self.PHV+"sweepStepEnergy"))
+        elif modeNum==1: #baby-swept
+            info.append(caget(self.PHV+"babySweepCenter.VAL"))
+        elif modeNum==0: #fixed
+            info.append(caget(self.PHV+"fixedEnergy.VAL"))
+        return scanType,info
+
+    def live(self,KE=None,PE=None,LensMode="Angular"):
+        """
+        puts the Scienta back in live mode (no savinga and Fixed Mode) with PE and KE
+            if PE or KE is None then uses the current value
+        """
+        if self.spectraProgress() != 1:
+            parms=self.get()
+            caput('29idcScienta:HV:LiveSeq',1)
+            self.put(KE,PE,LensMode)
+        else:
+            print("Scienta spectra in progress")
+            
+    def _updateAttributes(self,filepath=None):
+        """
+        filepath is the full path to the xml file
+            filepath = None; to update after making changes
+            filepath='/xorApps/epics/synApps_6_1/ioc/29idcScienta/iocBoot/ioc29idcScienta/HDF5Attributes.xml'
+
+        from 29idcScienta:HDF1: screen
+            More (under process plugin)
+                NDPluginBase Full
+        """
+        if filepath is None:
+            print(caget(self._savePlugin+"NDAttributesFile",as_string=True))
+        else:
+            caput(self._savePlugin+"NDAttributesFile",filepath)
+            time.sleep(1)
+            print(caget(self._savePlugin+"NDAttributesStatus",as_string=True))
+
+        
+    def _spectraErrorCheck(self,KElist,PassEnergy,Frames,LensMode,**kwargs):
+        """
+        error checking to see if parameters are allowed
+        """
+        error=[]
+        parms={}
+        for KE in list(KElist[0:-1]):
+            error=self._errorCheck(KE,PassEnergy,LensMode,Frames,**kwargs)   
+
+        if len(error) > 0:
+            print(error)
+        return error
+    
+    def _spectra_Swept(self,KEstart,KEstop,KEstep,PE):
+        """
+        setting up for a swept spectra, does not set the LensMode, PassEnergy or Frames
+        """
+        print("setting SpectraMode")
+        caput(self.PHV+"SpectraMode", "Sweep")
+        time.sleep(1)
+        #input pass energy setpoint (doesn't change util KE is changed but needed for calcs)
+        caput(self.PHV+"PassEnergy_Set",PE)
+        time.sleep(0.25)
+        #input spectra parameters
+        caput(self.PHV+"sweepStartEnergy.VAL",KEstart);time.sleep(0.25) #added 20220317 - sweep calcs need time to process or you get weird stuff
+        caput(self.PHV+"sweepStopEnergy.VAL",KEstop);time.sleep(0.25) #added 20220317 - sweep calcs need time to process or you get weird stuff
+        caput(self.PHV+"sweepStepEnergy.VAL",KEstep)
+        time.sleep(1)
+        #Re-Calc
+        #print('Yes Re-Calc')
+        #caput(self.PHV+"SweepReCalc.PROC",1)
+        #time.sleep(1)
+        #Load spectra parameters
+        caput(self.PHV+"SweepLoadFanout.PROC",1)
+        time.sleep(1)
+
+
+    def _spectra_BabySwept(self, KEcenter):
+        """
+        setting up for a Baby-Swept
+        """
+        #setting SpectraMode
+        caput(self.PHV+"SpectraMode", "Baby-Sweep")
+        time.sleep(1)
+        #input spectra parameters
+        caput(self.PHV+"babySweepCenter.VAL",KEcenter)
+        time.sleep(1)
+        #Load spectra parameters
+        caput(self.PHV+"SweepLoadFanout.PROC",1)
+        time.sleep(1)
+        #settling time
+        #caput(self.PHV+"scan2.PDLY",0.25)
+        #caput(self.PHV+"scan2.DDLY",0.1)
+
+    def _spectra_Fixed(self,KEcenter):
+        """
+        setting up for Fixed
+        """
+        #setting SpectraMode
+        caput(self.PHV+"SpectraMode", "Fixed")
+        caput("29idcScienta:HV:SpectraMode", "Fixed")
+        time.sleep(1)
+        #input spectra parameters
+        caput(self.PHV+"fixedEnergy.VAL",KEcenter)
+        time.sleep(1)
+    
+    def _spectraSetup(self,EAlist,**kwargs):
+        """ 
+        Writes EAlist to the appropriate PVs and does error checking
+        and return scanType, scanPV, KElist, parms
+        **kwargs
+            run = True; will write the PVs (False just does error checking)
+            LensMode = "Angular"
+            debug = False
+    
+        """
+        kwargs.setdefault("debug",False)
+        kwargs.setdefault("run",True)
+        kwargs.setdefault("LensMode","Angular")
+        
+        if kwargs['debug']:
+            print("\n\n _spectraSetup")
+            print("EAlist",EAlist)
+            
+        scanType="spectra"
+        if EAlist[-1] == "BS":
+            BS=True
+            EAlist=EAlist[0:-1]
+        else: 
+            BS=False
+        Sweeps=EAlist[-1]
+        Frames=EAlist[-2]
+        PassEnergy=EAlist[-3]
+        EnergyMode=EAlist[0]
+        KElist=np.array(EAlist[1:-3])
+        LensMode=kwargs['LensMode']
+
+
+        if kwargs['debug']:
+            print("KElist: ",KElist)
+        
+        parms={'LensMode':LensMode,'PassEnergy':PassEnergy,'KineticEnergy':KElist[0],'Frames':Frames}
+                
+        #checking parameters are valid
+        error=self._spectraErrorCheck(KElist,PassEnergy,Frames,LensMode)
+        if len(error) == 0: #passed check
+            #Checking Progress
+            if self._spectraStatus() == 1:
+                print("Spectra in Progess")
+            
+            # writing scan parameters
+            else:
+                if len(EAlist)==7: #Swept Mode
+                    scanType="Sweep"
+                    self._spectra_Swept(KElist[0],KElist[1],KElist[2],PassEnergy) 
+                    parms={'LensMode':LensMode,'PassEnergy':PassEnergy,'KineticEnergy':KElist[0]-.01,'Frames':Frames}
+                elif len(EAlist)==5: #fixed or baby sweep
+                    if BS is True:
+                        scanType="Baby-Sweep"
+                        self._spectra_BabySwept(KElist[0])
+                        parms={'LensMode':LensMode,'PassEnergy':PassEnergy,'KineticEnergy':KElist[0]-.01,'Frames':Frames}
+                    else:
+                        scanType="Fixed"
+                        self._spectra_Fixed(KElist[0])
+                        parms={'LensMode':LensMode,'PassEnergy':PassEnergy,'KineticEnergy':KElist[0]-.01,'Frames':Frames}
+                else:
+                    print("not a valid number of parameters")
+                #PV to initate scan"
+            scanPV=self.PHV+"ScanTrigger"
+            return scanType, scanPV, KElist, parms
+
+    def _spectraMessage(self,scanType, scanPV, KElist):
+        """
+        prints KE range for spectra
+        """
+        message=str(scanType)+" scan  KE: "
+        for KE in KElist:
+            message+=str(KE)+" | "
+        return message[0:-2]
+    
+       
+
+    def spectra(self,EAlist,**kwargs):
+        """
+        takes a Scienta spectra based on the number or parameters in EAlist
+            Sweeps are handled by scanRecord outside of this modual (see scanEA)
+        
+        Fixed Mode:["KE",CenterEnergy,PassEnergy,Frames,Sweeps] (5)
+        Swept Mode:["KE",StartEnergy,StopEnergy,StepEnergy,PassEnergy,Frames,Sweeps] (7)
+        Baby Sweep (dither):["KE",CenterEnergy,PassEnergy,Frames,Sweeps,"BS"] (6)
+            
+        **kwargs:
+            debug=False
+            run=True (executes the scan); False for error checking only
+            LensMode = Angular (default)
+        """
+        kwargs.setdefault("debug",False)
+        kwargs.setdefault("run",True)
+        
+        #Sending Parmeters to _spectraSetup 
+        scanType, scanPV, KElist, parms =self._spectraSetup(EAlist,**kwargs)
+        
+        if kwargs['debug']:
+            print(scanType,scanPV, KElist)
+        else:
+            print(scanType, "KE: ", KElist)
+        #Getting Filename info
+        fpath=caget(self._savePlugin+"FileName_RBV",as_string=True)+"_ "
+        fnum=caget(self._savePlugin+"FileNumber",as_string=True)
+       
+        
+        if kwargs['run'] is True:
+            dateandtime=time.strftime("%a %d %b %Y %H:%M:%S",time.localtime())
+            print("\t"+fpath+fnum+" started at ",dateandtime,"\r")
+            self.put(parms['KineticEnergy'],parms['PassEnergy'],LensMode=parms['LensMode'],Frames=parms['Frames'])
+            caput(scanPV,1,wait=True,timeout=129600)#timeout=36 hours
+            dateandtime=time.strftime("%a %d %b %Y %H:%M:%S",time.localtime())
+            print("\t"+fpath+fnum+" finished at ",dateandtime,"\r")
+
+
diff --git a/build/lib/iexcode/instruments/VLS_PGM.py b/build/lib/iexcode/instruments/VLS_PGM.py
new file mode 100644
index 0000000000000000000000000000000000000000..8f7bfdc225a080961c962b0d084059f2b535f179
--- /dev/null
+++ b/build/lib/iexcode/instruments/VLS_PGM.py
@@ -0,0 +1,739 @@
+"""
+functions used for the mono
+"""
+
+import time
+import numpy as np
+
+
+from epics import caget,caput
+from iexcode.instruments.IEX_endstations import *
+from iexcode.instruments.utilities import print_warning_message,read_dict
+
+
+##############################################################################################################
+################################             mono             ##############################
+##############################################################################################################
+def mono_grating_names():
+    """
+    List of grating names 
+    
+    """
+    ext = ['C',      'D',       'E',    'F',      'G',       'H',       'I',       "J",       "K",        "L"     ]
+    GRT_names = ["MEG_Imp","HEG","MEG","Dummy",  "not used", "not used", "not used","not used","not used","not used"]
+    GRT_names=GRT_names[0:2] # only use the first 3 slots
+    return GRT_names
+
+def mono_mirror_names():
+    """
+    List of grating names 
+    
+    """
+    ext = ['C',      'D',       'E',    'F',      'G',       'H',       'I',       "J",       "K",        "L"     ]
+    MIR_names = ["Au", "Silicon", "Carbon","not used","not used","not used","not used","not used","not used","not used"]
+    MIR_names=MIR_names[0:2] # only use the first 3 slots
+    return MIR_names
+
+def mono_extensions():
+    """
+    extension used for the mono mirror and grating locations
+    """
+    ext = ['C',      'D',       'E',    'F',      'G',       'H',       'I',       "J",       "K",        "L"     ]
+    return ext
+
+def mono_energy_range(GRT=None):
+    """
+    returns hv_min,hv_max, the minimum and maxium energy achievable the the specified grating
+    """
+    if GRT == None:
+        GRT = mono_grating_get()
+
+    if GRT == 'HEG':
+        hv_min=120
+        hv_max=2200
+    elif GRT == 'MEG':
+        hv_min=120
+        hv_max=3000
+    return hv_min,hv_max
+
+def mono_get_all(verbose=False):
+    """
+    gets hv, hv_sp,grating,mirror
+
+    Previously: Mono_Optics
+    """
+    d = mono_get_all_extended(verbose=False)
+    vals = {
+       'hv':d['ENERGY_MON'],
+       'hv_sp':d['ENERGY_SP'],
+       'grating':d['GRT'],
+       'mirror':d['MIR'],
+    }
+    if verbose:
+        print(" hv: "+"%.2f" % vals['hv'], "eV, hv_sp: " % vals['hv_sp'])
+        print(" grating  : "+vals['grating']," mirror  : "+vals['mirror'])
+    return vals
+
+def mono_grating_num():
+    """returns the current grating num"""
+    return caget('29idmonoGRT_TYPE_MON')
+
+def mono_mirror_num():
+    """returns the current mirror num"""
+    return caget('29idmonoMIR_TYPE_MON')
+
+def mono_pvs(grt_num=None,mir_num=None):
+    """
+    returns a dictionary with all the mono pvs
+    """
+    if grt_num is None:
+        grt_num = mono_grating_num()
+    if mir_num is None:
+        mir_num = mono_mirror_num()
+
+    ext=mono_extensions()
+
+    d={
+        'energy':"29idmono:ENERGY_MON",
+        'energy_sp':"29idmono:ENERGY_SP",
+        'grt_density':"29idmono:GRT_DENSITY",
+        'grt_offset':'29idmonoGRT:P_OFFSETS.'+ext['grt_num'],
+        'grt_b2':'29idmonoGRT:B2_CALC.'+ext['grt_num'],
+        'grt_pos':'29idmonoGRT:X_DEF_POS.'+ext['grt_num'],
+        'grt_LD':'29idmonoGRT:TYPE_CALC.'+ext['grt_num'],
+        'grt_tun0':'29idmonoGRT:TUN0_CALC.'+ext['grt_num'],
+        'grt_tun1':'29idmonoGRT:TUN1_CALC.'+ext['grt_num'],
+        'grt_tun2':'29idmonoGRT:TUN2_CALC.'+ext['grt_num'],
+        'grt_tun3':'29idmonoGRT:TUN3_CALC.'+ext['grt_num'],
+        'grt_type_sp':"29idmonoGRT_TYPE_SP",
+        'grt_move':"29idb:'gr:move",
+        'grt_P_status':"29idmonoGRT:P_AXIS_STS",
+        'mir_P_status':"29idmonoMIR:P_AXIS_STS",
+        'grt_X_status':"29idmonoGRT:X_AXIS_STS",
+        'mir_X_status':"29idmonoMIR:X_AXIS_STS",
+        'mir_offset':'29idmonoMIR:P_OFFSETS.'+ext['mir_num'],
+        'mir_pos':'29idmonoMIR:X_DEF_POS.'+ext['mir_num'],
+        'cff':'29idmono:CC_MON',
+        'arm':'29idmono:PARAMETER.G'
+
+    }
+
+def mono_get_all_extended(verbose=False):
+    """
+    gets the mono parameters for the current grating and mirror
+    returns a dictionary with those values
+
+    Previously: Mono_Optics
+    """
+    grt_num = mono_grating_num()
+    mir_num = mono_mirror_num()
+    grt_names = mono_grating_names()
+    mir_names = mono_mirror_names()
+
+    ext=mono_extensions()
+
+    pvs = mono_pvs(grt_num=None,mir_num=None)
+    vals={
+        'grt_num':grt_num,
+        'mir_num':mir_num,
+        'grt':grt_names[grt_num],
+        'mir':mir_names[mir_num],
+        'energy':caget(pvs['energy']),
+        'energy_sp':caget(pvs['energy_sp']),
+        'grt_density':caget(pvs['energy_sp']),
+        'grt_offset':caget(pvs['grt_offset']),
+        'grt_b2':caget(pvs['grt_offset']),
+        'grt_pos':caget(pvs['grt_pos']),
+        'grt_LD':caget(pvs['grt_LD']),
+        'grt_tun0':caget(pvs['grt_tun0']),
+        'grt_tun1':caget(pvs['grt_tun1']),
+        'grt_tun2':caget(pvs['grt_tun2']),
+        'grt_tun3':caget(pvs['grt_tun3']),
+        'grt_P_status':caget(pvs['grt_P_status']),
+        'mir_P_status':caget(pvs['mir_P_status']),
+        'grt_X_status':caget(pvs['grt_X_status']),
+        'mir_X_status':caget(pvs['mir_X_status']),
+        'mir_offset':caget(pvs['mir_offset']),
+        'mir_pos':caget(pvs['mir_pos']),
+        'CFF':caget('29idmono:CC_MON'),
+        'arm':caget('29idmono:PARAMETER.G')
+        }
+
+    if verbose:
+        for key in vals.keys(): 
+            print(key,vals[key])
+
+    return vals
+
+def mono_grating_get():
+    """
+    returns the grating density and the string name for the grating
+    """
+    return mono_get_all_extended()['grt']
+
+def mono_energy_get():
+    """
+    returns the grating density and the string name for the grating
+    """
+    return mono_get_all_extended()['energy']   
+
+def mono_grating_density_get():
+    """
+    returns the grating density and the string name for the grating
+    """
+    return mono_get_all_extended()['grt_density']  
+
+def mono_energy_set(hv_eV,verbose=True):
+    """
+    sets the mono energy
+
+    Previously: SetMono
+    """
+    hv_min, hv_max = mono_energy_range()
+    pv = mono_pvs()['energy_sp']
+    if hv_min <= hv_eV <= hv_max: 
+        caput(pv,hv_eV,wait=True,timeout=60)
+    time.sleep(2.5)
+
+    mono_status = mono_status_get()
+    while True:
+        if mono_status() > 1:
+            mono_resest_pitch()
+            caput(pv,hv_eV,wait=True,timeout=60)
+            time.sleep(2.5)
+        else:
+            break
+    if verbose:
+        print("Mono set to",str(hv_eV),"eV")
+
+def mono_scan_pvs():
+    """
+    returns the pvs to be used in scanning
+    """
+    val_pv = mono_pvs()['energy_sp']
+    rbv_pv = mono_pvs()['energy']
+    return val_pv, rbv_pv
+
+def mono_status_get():
+    """
+    returns the status of the mirror (GRT * MIR)
+        1 = ready
+
+
+    Previously Mono_Status
+    """
+    pvs = mono_pvs()['energy']
+    mir_P_status = caget(pvs['mir_P_status'])
+    grt_P_status = caget(pvs['grt_P_status'])
+    mir_X_status = caget(pvs['mir_P_status'])
+    grt_X_status = caget(pvs['grt_P_status'])
+    mirror_status = mir_P_status * mir_X_status
+    grating_status = grt_P_status * grt_X_status
+    return mirror_status*grating_status
+
+
+def mono_grating_translate(grating,verbose=True):
+    """
+    Translate between the different grating positions
+
+    Warning: this does not close the shutters use XX
+
+    Previously: Move_GRT
+    """
+    current_grating=mono_grating_get()
+    hv_eV = mono_energy_get()
+
+    try:
+        grating_state = mono_grating_names().index(grating)
+
+    except:
+        print_warning_message(grating+' not a valid grating')
+
+    if current_grating != grating:
+        pvs=mono_pvs()
+        caput(pvs['grt_type_sp'],grating_state,wait=True,timeout=18000)        
+        caput(pvs['grt_move'],1,wait=True,timeout=18000)
+        while True:
+            if mono_status_get() > 1:
+                time.sleep(5)
+            else:
+                break
+        mono_energy_set(hv_eV)
+
+    else:
+        if verbose:
+            print("grating is already "+grating)
+
+    if verbose:
+        print("Mono Grating:",grating)
+
+
+def mono_resest_pitch():
+    """
+    resets the MIR and GRT pitch interlocks after a following error or limit
+    Previoulsy part of SetMono
+    """
+    caput("29idmonoMIR:P.STOP",1)
+    time.sleep(1)
+    caput("29idmonoGRT:P.STOP",1)
+    time.sleep(1)
+    print('Mono pitch was reset')
+
+def mono_kill():
+    """
+    kills the mono pitch motors
+
+    Previously: Kill_Mono
+    """
+    caput("29idmonoMIR:P_KILL_CMD.PROC",1)
+    caput("29idmonoGRT:P_KILL_CMD.PROC",1)
+#    caput("29idmonoGRT:X_KILL_CMD.PROC",1)
+    time.sleep(5)
+    caput("29idmono:STOP_CMD.PROC",1)
+#    caput("29idmonoGRT:X_HOME_CMD.PROC",1)
+
+
+def mono_stop():
+    """
+    presses the stop button on the mono motors 
+
+    Previously: Stop_Mono 
+    """
+    caput("29idmono:STOP_CMD.PROC",1)
+    time.sleep(5)
+
+def mono_enable():
+    """
+    re-enable the mono motors 
+
+    Previously: Enable_Mono
+    """
+    caput("29idmonoGRT:X_ENA_CMD.PROC",1)
+    caput("29idmonoGRT:P_ENA_CMD.PROC",1)
+    caput("29idmonoMIR:X_ENA_CMD.PROC",1)
+    caput("29idmonoMIR:P_ENA_CMD.PROC",1)
+
+def mono_limits_reset():
+    """
+    resest the mono low limit to 200 
+    was changed in the pmac to the wrong value so we need to do this
+
+    Previously: Reset_Mono_Limits
+    """
+    #    caput("29idmono_GRT_TYPE_SP.ONST", 'MEG_PA')
+    #    caput("29idmono_GRT_TYPE_SP.TWST", 'HEG_JY')
+    #    caput("29idmono_GRT_TYPE_SP.THST", 'MEG_JY')
+    caput("29idmono:ENERGY_SP.DRVL",200)
+    caput("29idmono:ENERGY_SP.LOW",200)
+    caput("29idmono:ENERGY_SP.LOLO",200)
+    caput("29idmono:ENERGY_SP.LOPR",200)
+    print("Mono limits have been reset.")
+
+def mono_cff_print():
+    """
+    print the cff tuning parameters and arm for the current grating
+
+    Previously: Get_CFF
+    """
+    d = mono_get_all_extended
+    cff = d['cff']
+    tun0 = d['grt_tun0']
+    tun1 = d['grt_tun1']
+    tun2 = d['grt_tun2']
+    tun3 = d['grt_tun3']
+    arm =  d['arm']
+    print(" cff : "+"%.4f" % cff , "          exit arm: "+"%.1f" % arm,"mm")
+    print(" tun0 : "+"%.4e" % tun0 , "    tun1: "+"%.4e" % tun1)
+    print(" tun2 : "+"%.4e" % tun2 , "    tun3: "+"%.4e" % tun3)
+
+def mono_parameters_pv(grt_num=None,mir_num=None):
+    """
+    returns dictionary with mono_parameter for current grating/mirror
+    """
+    if grt_num is None:
+        grt_num =  mono_grating_num()()
+    if mir_num is None:
+        mir_num = mono_mirror_num()()
+   
+    ext = mono_extensions()
+
+    d={
+        'mir_offset':"29idmonoMIR:P_OFFSETS."+ext[mir_num],
+        'mir_pos':"29idmonoMIR:X_DEF_POS."+ext[mir_num],
+        'grt_offset':"29idmonoGRT:P_OFFSETS."+ext[grt_num],
+        'grt_pos':"29idmonoGRT:X_DEF_POS."+ext[grt_num],
+        'grt_density':"29idmonoGRT:TYPE_CALC."+ext[grt_num],
+        'grt_b2':"29idmonoGRT:B2_CALC."+ext[grt_num]
+    }
+    return d
+
+
+def mono_parameters_get():
+    """
+    Gets the mono parameters and prints them for the History
+
+    Previously: Mono_Parameters_Get
+    """
+    date=time.strftime("%Y%m%d",time.localtime())
+    mirList = mono_mirror_names()
+    grtList = mono_grating_names()
+    pvList = mono_extensions()
+
+    #MIR
+    txt="MonoParm[\'"+date+"\']= {\n\t"
+    for i in range(0,len(mirList)):
+        d = mono_parameters_pv(mir_num=i)
+        mir = mirList[i]
+        offset = caget(d['mir_offset'])
+        position = caget(d['mir_pos'])
+        txt+="\'"+mir+"\':["+str(offset)+","+str(position)+"],"
+
+    #GRT
+    txt+="\n\t"
+    for i in range(0,len(grtList)):
+        d = mono_parameters_pv(grt_num=i)
+        grt = grtList[i]
+        offset = caget(d['grt_offset'])
+        position = caget(d['grt_pos'])
+        density = caget(d['grt_density'])
+        b2 = caget(d['grt_b2'])
+        txt+="\'"+grt+"\':["+str(offset)+","+str(position)+","+str(density)+","+str(b2)+"],"
+
+    txt+="}"
+    print(txt)
+
+def mono_parameters_history_read(date):
+    """
+    Dictionary of Mono parameters used in Mono_Parameters(date) which sets the parameters
+    #MonoParm['date']={'Au':[],Si:[],'Carbon':[],'MEG_Imp':[],'HEG_JY':[],'MEG_JY':[]}
+    Mono_Parameters_Set(date) writes the parameters from the Dictionary
+    
+    Previously: Mono_Parameters_History
+    """
+    #MonoParm['date']={'Au':[],Si:[],'Carbon':[],'MEG_Imp':[],'HEG_JY':[],'MEG_JY':[]}
+
+    MonoParm=read_dict('mono_parameters.txt')
+    return MonoParm[date]
+
+
+def mono_parameters_history_write(date):
+    """
+
+    Previously: Mono_Parameters_Set
+    """
+    hv_eV=caget("29idmono:ENERGY_SP")
+    MonoParm=mono_parameters_history_read(date)
+    pvList=['C','D','E']
+    mirList=["Au","Si","Carbon"]
+    for i in range(0,len(mirList)):
+        mir=mirList[i]
+        caput("29idmonoMIR:P_OFFSETS."+pvList[i],MonoParm[mir][0])
+        caput("29idmonoMIR:X_DEF_POS."+pvList[i],MonoParm[mir][1])
+    grtList=["MEG_Imp", "HEG_JY", "MEG_JY"]
+    for i in range(0,len(grtList)):
+        grt=grtList[i]
+        caput("29idmonoGRT:P_OFFSETS."+pvList[i],MonoParm[grt][0])
+        caput("29idmonoGRT:X_DEF_POS."+pvList[i],MonoParm[grt][1])
+        caput("29idmonoGRT:TYPE_CALC."+pvList[i],MonoParm[grt][2])
+        caput("29idmonoGRT:B2_CALC."+pvList[i],MonoParm[grt][3])
+    time.sleep (1)
+    mono_energy_set(hv_eV,verbose=True)
+
+
+
+def mono_temperature_interlock():
+    """
+    userCalcOut to monitor the temperatures on the Mono if the temperature gets too high then it closes the main shutter
+    #29idb:userCalcOut10.VAL =0 => OK; =1 => Too hot
+
+    Previously: Mono_TemperatureInterlock
+    """
+    pv='29idb:userCalcOut10'
+    caput(pv+'.DESC', 'Mono Temperature Interlock')
+    caput(pv+'.INPA','29idmono:TC1_MON CP NMS')
+    caput(pv+'.INPB','29idmono:TC2_MON CP NMS')
+    caput(pv+'.INPC','29idmono:TC3_MON CP NMS')
+    caput(pv+'.INPD','29idmono:TC4_MON CP NMS')
+    caput(pv+'.INPE','29idmono:TC5_MON CP NMS')
+    caput(pv+'.INPF','29idmono:TC6_MON CP NMS')
+    
+    caput(pv+'.H','31')
+    
+    caput(pv+'.CALC','A>H | B>H | C>H |D>H')
+    caput(pv+'OOPT','Transition To Non-zero')
+    caput(pv+'.OUT','PC:29ID:FES_CLOSE_REQUEST.VAL PP NMS')
+
+    
+
+def mono_scan_fillin(hv_start,hv_stop,hv_step,**kwargs):
+    """
+    fills in the scanRecord for scanning the mono
+
+        puts the positioner in stay after scan
+
+        **kwargs => scanRecord.fillin kwargs
+        positioner_settling_time: increased because busy record is too fast => 0.2 (default)
+    """
+    kwargs.setdefault('positioner_settling_time',0.2)
+
+
+    #Setting up the ScanRecord for Mono in Table mode
+    val_pv, rbv_pv = mono_scan_pvs()
+    BL.mda.fillin(val_pv,rbv_pv,hv_start,hv_stop,hv_step,**kwargs)
+
+    #mono needs to stay and have a longer settling time
+    BL.mda.positioner_after_scan("STAY")
+
+    
+def mono_scan_fillin_table(hv_array,**kwargs):
+    """
+    fills in the scanRecord for scanning the mono
+
+    puts the positioner in stay after scan
+
+    **kwargs => scanRecord.fillin kwargs
+    positioner_settling_time: increased because busy record is too fast => 0.2 (default)
+
+    """
+    kwargs.setdefault('positioner_settling_time',0.2)
+
+    #Setting up the ScanRecord for Mono in Table mode
+    val_pv, rbv_pv = mono_scan_pvs()
+    BL.mda.fillin.table(val_pv,rbv_pv,hv_array,**kwargs)
+
+    #mono needs to stay and have a longer settling time
+    BL.mda.positioner_settling_time(kwargs['positioner_settling_time'])
+    BL.mda.positioner_after_scan("STAY")
+
+def mono_scan_after(**kwargs):
+    """
+    resets mda after scanning the mono
+    """
+    after_scan_pv = BL.mda.default_after_scan_seq
+    caput(after_scan_pv+".PROC",1)
+    BL.mda.positioner_after_scan("PRIOR POS")
+
+
+##############################################################################################################
+################################             aligmnent and commissioning             ##############################
+##############################################################################################################
+def mono_motor_move(motor,value):
+    """
+    for pitch motor => MIR:P or GRT:P
+    for translation motor => MIR:X or GRT:X
+
+    Previously: Move_FMBMono
+    """
+    val_pv,rbv_pv = mono_motor_scan_pvs()
+    caput(val_pv+".PREC",3)
+    caput(val_pv,value,wait=True,timeout=18000)
+
+def mono_motor_scan_pvs(motor):
+    """
+    returns the rbv and val for scanning 
+    """
+    val_pv = "29idmono"+motor+"_SP"
+    rbv_pv = "29idmono"+motor+"_MON"
+    return val_pv,rbv_pv
+
+def mono_motor_scan_fillin(motor,start,stop,step,**kwargs):
+    """
+    for pitch motor => MIR:P or GRT:P
+    for translation motor => MIR:X or GRT:X
+
+    Previously: Scan_FMBMono
+    """
+    val_pv,rbv_pv = mono_motor_scan_pvs(motor)
+    caput(val_pv+".PREC",3) # database sets .PREC==0.  We want more digits than that.
+
+    BL.mda.fillin(val_pv,rbv_pv,start,stop,step,**kwargs)
+
+def mono_zero_order(angle):
+    """
+    puts the beam in zero order => grating/mirror are parallel
+    range ~1 - 5 degrees
+
+    Previously: Mono_zero
+    """
+    angle=angle*1.0
+    caput("29idmonoMIR:P_POS_SP",angle,wait=True,timeout=18000)
+    caput("29idmonoMIR:P_MOVE_CMD.PROC",1,wait=True,timeout=18000)
+    caput("29idmonoGRT:P_POS_SP",angle,wait=True,timeout=18000)
+    caput("29idmonoGRT:P_MOVE_CMD.PROC",1,wait=True,timeout=18000)
+    print("Mono set to zero order: MIR_pitch = "+str(angle)+", GRT_pitch = "+str(angle))
+
+def mono_angles_set(alpha,beta): #JM modified to monitor the ready, moving sequentialy ended up in crash sometimes
+    """
+    Sets the mirror pitch (alpha) and grating pitch (beta) angles
+    
+    Previously: Mono_angle
+    """
+    alpha=alpha*1.0
+    beta=beta*1.0
+    #Putting Setpoints Go
+    caput("29idmonoGRT:P_SP",alpha)
+    caput("29idmonoMIR:P_SP",beta)
+    ready=0
+    while ready != 1:
+        time.sleep(0.1)
+        ready=caget('29idmono:ERDY_STS')
+    print("Mono set to zero order: MIR_pitch = "+str(alpha)+", GRT_pitch = "+str(beta))
+
+def mono_pink_beam():
+    """
+    moves grating and mirror out of beam
+    x-rays will hit the pink beamstop
+
+    Previously: Mono_pinkbeam
+    """
+    caput("29idmonoMIR:P_POS_SP",0,0)
+    caput("29idmonoMIR:P_MOVE_CMD.PROC",0)
+    time.sleep(3)
+    caput("29idmonoGRT:P_POS_SP",0.0)
+    caput("29idmonoGRT:P_MOVE_CMD.PROC",0)
+    time.sleep(3)
+    caput("29idmonoMIR:X_POS_SP",-52)
+    caput("29idmonoMIR:X_MOVE_CMD.PROC",0)
+    time.sleep(3)
+    caput("29idmonoGRT:X_POS_SP",210)
+    caput("29idmonoGRT:X_MOVE_CMD.PROC",0,wait=True,timeout=18000)
+
+def mono_CC(): 
+    """
+    ##used for commissioning
+
+    Previously: Mono_CC
+    """
+    caput("29idmonoMIR_TYPE_SP",3)
+    caput("29idmonoMIR:X_DCPL_CALC.PROC",0)
+    caput("29idmonoGRT_TYPE_SP", 10)
+    caput("29idmonoGRT:X_DCPL_CALC.PROC",0)
+
+    caput("29idmono:ENERGY_SP", 440)
+
+def mono_grating_offset_set(val,grt_num=None):
+    """
+    sets the grating offset for the grating 
+
+    Previously: Mono_Set_GRT0
+    """
+    pvs=mono_pvs(grt_num,None)
+    caput(pvs['grt_offset'],val)
+    mono_get_all_extended(verbose=True)
+
+def mono_mirror_offset_set(val,mir_num=None):
+    """
+    sets the mirror offset for the grating 
+
+    Previously: Mono_Set_MIR0
+    """
+    pvs=mono_pvs(None,mir_num)
+    caput(pvs['mir_offset'],val)
+    mono_get_all_extended(verbose=True)
+
+def mono_grating_mirror_offsets_set(mirror_offset):
+    """
+    changes the mirror and grating offsets to  maintain parallelism
+    After determining parallelism (zero order a=b)
+    Get the correct take-off angle delta, equivalent to scan ExitSlit_Vcenter
+    
+    Previously: Mono_Set_MIR0_GRT0,MIR_GRT_Offset,Mono_Set_MIR0_GRT0_all
+    """  
+    current_vals = mono_get_all_extended(verbose=False)
+    energy_sp = current_vals['energy_sp']
+    mirror_offset_old = current_vals['mir_offset']
+    
+    #get current grating offsets
+    grating_offsets=[]
+    for grt_num in range(0,3):
+        grating_offsets.append(mono_parameters_pv(grt_num=grt_num,mir_num=None)['grt_offset'])
+
+    #calc mirror_offset - grating_grating    
+    mir_grt_offsets = mirror_offset_old-np.array(grating_offsets)    # list of MIR-GRT for all 3 gratings
+
+    #set mirror_offset
+    mono_mirror_offset_set(mirror_offset)
+
+    #set grating_offsets
+    for grt_num in range(0,3):
+        mono_grating_offset_set(mirror_offset - mir_grt_offsets[grt_num],grt_num)
+
+    time.sleep (1)
+    mono_energy_set(energy_sp)
+    mono_get_all_extended(verbose=True)
+
+
+def mono_grating_b2_set(val,grt_num=None):
+    """
+    sets the grating offset for the grating 
+    Previously: Mono_Set_b2
+    """
+    hv = mono_energy_get()
+    pvs = mono_pvs(grt_num,None)
+    caput(pvs['grt_b2t'],val)
+    time.sleep(1)
+    
+    mono_energy_set(hv)
+    mono_get_all_extended(verbose=True)
+
+def mono_cff_set(val,tune_num):
+    """
+    sets the tuning parameters for the cff calculation 
+    tune_num = order
+
+    Previously: Mono_Set_cff
+    """
+    hv = mono_energy_get()
+    pvs = mono_pvs()
+
+    #get current info
+    current_vals = mono_get_all_extended(verbose=False)
+    grt_pitch = current_vals['grt_pitch']
+    mir_pitch = current_vals['mir_pitch']
+    print ('Pitch grating, mirror: ',grt_pitch,mir_pitch)
+    
+    #set the tuning coeffient
+    tun='tun'+str(tune_num)
+    caput(pvs[tun],val)
+    time.sleep(1)
+
+    #set then energy
+    mono_energy_set(hv)
+
+    #print differences in pitch
+    mono_get_all_extended(verbose=False)
+    grt_dif = grt_pitch-current_vals['grt_pitch']
+    mir_dif = mir_pitch-current_vals['mir_pitch']
+
+    print('Pitch grating, mirror: ',current_vals['grt_pitch'],current_vals['mir_pitch'])
+    print('Differences          : ',grt_dif,mir_dif)
+
+def mono_arm_set(distance_mm):
+    """
+    sets the exit arm for the grating 
+
+    Previously: Mono_Set_ExitArm
+    """
+    hv = mono_energy_get()
+    pvs = mono_pvs()
+
+    #get current info
+    current_vals = mono_get_all_extended(verbose=False)
+    grt_pitch = current_vals['grt_pitch']
+    mir_pitch = current_vals['mir_pitch']
+    print ('Pitch grating, mirror: ',grt_pitch,mir_pitch)
+    
+    #set the exit arm
+    caput("29idmono:PARAMETER.G",distance_mm)
+    time.sleep(1)
+
+    #set then energy
+    mono_energy_set(hv)
+
+    #print differences in pitch
+    mono_get_all_extended(verbose=False)
+    grt_dif = grt_pitch-current_vals['grt_pitch']
+    mir_dif = mir_pitch-current_vals['mir_pitch']
+
+    print('Pitch grating, mirror: ',current_vals['grt_pitch'],current_vals['mir_pitch'])
+    print('Differences          : ',grt_dif,mir_dif)
\ No newline at end of file
diff --git a/build/lib/iexcode/instruments/__init__.py b/build/lib/iexcode/instruments/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e244a3c105e5bc09da608c5fd6134ba1ef425528
--- /dev/null
+++ b/build/lib/iexcode/instruments/__init__.py
@@ -0,0 +1,42 @@
+
+""" from iexcode.instruments.AD_utilites import *
+from iexcode.instruments.ARPES import *
+from iexcode.instruments.bakeout import * 
+from iexcode.instruments.beamline import * 
+from iexcode.instruments.cameras import * 
+from iexcode.instruments.conversions_constants import * 
+from iexcode.instruments.current_amplifiers import * 
+from iexcode.instruments.diagnostics import * 
+from iexcode.instruments.electron_analyzer import * 
+from iexcode.instruments.encoders import * 
+from iexcode.instruments.files_and_folders import * 
+from iexcode.instruments.FMB_mirrors import * 
+from iexcode.instruments.gate_valves import * 
+from iexcode.instruments.hxp_mirrors import * 
+from iexcode.instruments.IEX_endstations import * 
+from iexcode.instruments.IEX_VPU import * 
+from iexcode.instruments.Kappa import * 
+from iexcode.instruments.Kappa_det import * 
+from iexcode.instruments.Kappa_Euler import * 
+from iexcode.instruments.Lakeshore_335 import * 
+from iexcode.instruments.logfile import * 
+from iexcode.instruments.m3r import * 
+from iexcode.instruments.Motors import * 
+from iexcode.instruments.mpa import * 
+from iexcode.instruments.remote_controlers import * 
+from iexcode.instruments.resolution import * 
+from iexcode.instruments.s29_temp_cntl import * 
+from iexcode.instruments.scalers import * 
+from iexcode.instruments.Scienta import * 
+from iexcode.instruments.shutters import * 
+from iexcode.instruments.slits import * 
+from iexcode.instruments.spec_stuff import * 
+from iexcode.instruments.staff import * 
+from iexcode.instruments.storage_ring import * 
+from iexcode.instruments.userCalcs import * 
+from iexcode.instruments.utilities import * 
+from iexcode.instruments.VLS_PGM import * 
+from iexcode.instruments.vortexs29 import * 
+from iexcode.instruments.xrays import * 
+
+ """
diff --git a/build/lib/iexcode/instruments/bakeout.py b/build/lib/iexcode/instruments/bakeout.py
new file mode 100644
index 0000000000000000000000000000000000000000..94dfd1a00e1173fabb280bf94cd6090258599878
--- /dev/null
+++ b/build/lib/iexcode/instruments/bakeout.py
@@ -0,0 +1,193 @@
+from time import sleep
+from os import mkdir
+from os.path import exists
+
+from epics import caget,caput
+
+from iexcode.instruments.files_and_folders import get_next_fileNumber, check_run
+from iexcode.instruments.scanRecord import *
+
+##############################################################################################################
+##############################             Scan Bakeout            ##############################
+##############################################################################################################
+
+def bakout_scan(scan_ioc_name,chamber):
+    """
+    sets up the scan record to record temperature  and pressures
+
+    scan_ioc_name = 'ARPES', 'Kappa','Test'
+        chamber = "Beamline"; Yokawgawa + all beamline ion pumps and vacuum gauges
+        chamber = "Mono"; Beamline + mono thermocouples
+        chamber = "ARPES"; Beamline + ARPES pressures and temperatures
+        chamber = "Kappa"; Beamline + Kappa pressures and temperatures
+        chamber = "Stinger"; Stinger temperatures + ARPES and Kappa temperatures and pressures
+
+    Previously: Scan_Bakeout
+    """
+    #setting the folders and save datat
+    run = check_run()
+    folder='/net/s29data/export/data_29idb/Bakeout/'
+    subfolder='/'+chamber+'/'+run
+    prefix='mda_'
+
+    scan_ioc = '29id'+scan_ioc_name+":"
+    
+    caput(scan_ioc+'saveData_fileSystem',folder)
+    caput(scan_ioc+'saveData_subDir',subfolder)
+    caput(scan_ioc+'saveData_baseName',prefix)
+
+    MyPath="/net/s29data/export/data_29idb/Bakeout/"+chamber+"/"+run
+    print("\nBakeout folder: " + MyPath)
+    if not (exists(MyPath)):
+        mkdir(MyPath)
+        sleep(1)
+        FileNumber=1
+    else:
+        FileNumber=get_next_fileNumber(MyPath,prefix[:-1])
+    caput(scan_ioc+'saveData_scanNumber',FileNumber)
+    
+    sleep(5)
+    SaveStatus=caget(scan_ioc+'saveData_status',as_string=True)
+    SaveMessage=caget(scan_ioc+'saveData_message',as_string=True)
+    print("\nSave Status "+scan_ioc+" "+SaveStatus+" - "+SaveMessage)
+
+    #setting up scan record
+    detector_dictionary = bakeout_detector_dictionary(chamber)
+
+    #caput("29idb:ca1:read.SCAN",0)  
+    #trigger_dictionary = {1:"29idb:ca1:read"}
+    trigger_dictionary = {1:""}
+    
+    before_scan_pv = ""
+    after_scan_pv = ""
+
+    mda_scan = ScanRecord(scan_ioc,detector_dictionary,trigger_dictionary,before_scan_pv,after_scan_pv)
+
+    mda_scan.time_scan(99999,60)
+
+
+
+def bakeout_detector_dictionary(chamber):    
+    """
+    returns a dictionary of the default detectors
+
+    """
+    thermocouples={
+    1:"29iddau1:dau1:001:ADC",
+    2:"29iddau1:dau1:002:ADC",
+    3:"29iddau1:dau1:003:ADC",
+    4:"29iddau1:dau1:004:ADC",
+    6:"29iddau1:dau1:006:ADC",
+    7:"29iddau1:dau1:007:ADC",
+    8:"29iddau1:dau1:008:ADC",
+    9:"29iddau1:dau1:009:ADC",
+    10:"29iddau1:dau1:010:ADC",
+    }
+    ion_gauges={  
+    21:"29idb:VS1A.VAL",
+    22:"29idb:VS2A.VAL",
+    23:"29idb:VS3AB.VAL",
+    24:"29idb:VS4B.VAL",
+    25:"29idb:VS5B.VAL",
+    26:"29idb:VS6B.VAL",
+    27:"29idb:VS7B.VAL",
+    28:"29idb:VS8C.VAL",
+    29:"29idb:VS8CSP.VAL",
+    30:"29idb:VS9C.VAL",
+    31:"29idb:VS10C.VAL",
+    32:"29idb:VS8D.VAL",
+    33:"29idb:VS9D.VAL",
+    34:"29idb:VS10D.VAL",
+    }
+    ion_pumps={
+    41:"29idb:IP1A.VAL",
+    42:"29idb:IP2A.VAL",
+    43:"29idb:IP3A.VAL",
+    44:"29idb:IP3B.VAL",
+    45:"29idb:IP4B.VAL",
+    46:"29idb:IP5B.VAL",
+    47:"29idb:IP6B.VAL",
+    48:"29idb:IP7B.VAL",
+    49:"29idb:IP7C.VAL",
+    51:"29idb:IP8C1.VAL",
+    52:"29idb:IP8C2.VAL",
+    53:"29idb:IP9C.VAL",
+    54:"29idb:IP10C1.VAL",
+    55:"29idb:IP10C2.VAL",
+    56:"29idb:IP7D.VAL",
+    57:"29idb:IP8D1.VAL",
+    58:"29idb:IP8D2.VAL",
+    59:"29idb:IP9D.VAL",
+    60:"29idb:IP10D1.VAL",
+    61:"29idb:IP10D2.VAL",
+    }
+
+    mono = {
+    11:"29idmono:TC1_MON",
+    12:"29idmono:TC2_MON",
+    13:"29idmono:TC3_MON",
+    14:"29idmono:TC4_MON",
+    15:"29idmono:TC5_MON",
+    16:"29idmono:TC6_MON",
+    }
+
+    ARPES = {
+    11:"29idc:VS11C.VAL",
+    12:"29idc:VSCUBE.VAL",
+    13:"29idc:IP11C1.VAL",
+    14:"29idc:IP11C2.VAL",
+    15:"29idc:IPCUBE.VAL",
+    16:"29idARPES:LS335:TC1:IN1",
+    17:"29idARPES:LS335:TC1:IN2",
+    }
+
+    Kappa = {
+    11:"29idb:VS11D.VAL",
+    12:"29idb:VS12D.VAL",
+    13:"29idd:LS331:TC1:SampleA",
+    14:"29idd:LS331:TC1:SampleB",
+    }
+
+    Stinger = {
+    1:"29idc:LS340:TC2:Control",
+    2:"29idc:LS340:TC2:Sample",
+
+    3:"29idARPES:LS335:TC1:IN1",
+    4:"29idARPES:LS335:TC1:IN2",
+
+    5:"29idd:LS331:TC1:SampleA",
+    6:"29idd:LS331:TC1:SampleB",
+
+    7:"29idc:VS11C.VAL",
+    8:"29idc:IP11C1.VAL",
+    9:"29idc:IP11C2.VAL",
+
+    10:"29idb:VS11D.VAL",
+    }
+    d={}
+    if chamber.lower() == "Beamline".lower():
+        d.update(thermocouples)
+        d.update(ion_gauges)
+        d.update(ion_pumps)
+        print("ScanRecord ready")
+
+    if chamber.lower() == "Mono".lower():
+        d.update(thermocouples)
+        d.update(ion_gauges)
+        d.update(ion_pumps)
+        d.update(mono)
+        print('Setting up Mono temperatures')
+
+    if chamber.lower() == "ARPES".lower():
+        d.update(ARPES)
+        print('Setting up ARPES temperatures')
+        
+    if chamber.lower() == "Kappa".lower():
+        d.update(Kappa)
+        print('Setting up Kappa temperatures')
+
+    if chamber.lower() == "Stinger".lower():
+        d.update(Stinger)
+        print('Setting up Stinger temperatures')
+
+    return d
diff --git a/build/lib/iexcode/instruments/beamline.py b/build/lib/iexcode/instruments/beamline.py
new file mode 100644
index 0000000000000000000000000000000000000000..6817162fdad3533041139170c96a0fa810e51958
--- /dev/null
+++ b/build/lib/iexcode/instruments/beamline.py
@@ -0,0 +1,94 @@
+
+"""
+short name for functions used with or without x-rays
+
+"""
+
+import numpy as np
+from time import sleep
+
+from epics import PV
+from iexcode.instruments.IEX_endstations import *
+
+
+##############################################################################################################
+###########################                      Scan stuff                     ######################
+##############################################################################################################
+def scan_fillin(VAL,RBV,start,stop,steps_points,**kwargs):
+    """
+    fills in the scan record for the curretn beamline ioc
+    """
+    BL.mda.fillin(VAL,RBV,start,stop,steps_points,**kwargs)
+
+def scan_fillin_table(VAL,RBV,my_table,**kwargs):
+    """
+    fills in the scan record for the curretn beamline ioc
+    """
+    BL.mda.fillin_table(VAL,RBV,my_table,**kwargs)
+
+def scan_go(**kwargs):
+    """
+    Starts a scan 
+    by default: scanDIM=1  
+    Logging is automatic: use **kwargs or the optional logging arguments see scanlog() for details
+    kwargs:
+        X-ray = True (default), does shutter checks
+             = False no shutter checks
+    """
+    BL.mda.go(verbose=True,**kwargs)
+
+
+def last_mda():
+    """
+    returns the last mda file number in the ioc defined by BL_ioc
+    Previously: LastMDA
+    """
+    filenum = BL.mda.lastFileNum()
+    return filenum
+
+
+
+##############################################################################################################
+##############################               Beeper          ##############################
+##############################################################################################################
+
+
+
+def print_beeper(scanDIM=1):
+    """
+    Prints pv to copy/paste into the beeper
+
+    Previously: Print_Beeper
+    """
+    branch=BL.branch
+    if branch == "c":
+        print("29idcEA:det1:Acquire")
+    pv=BL.ioc()+":scan"+str(scanDIM)+".FAZE"
+    print(pv)
+    print("ID29:BusyRecord")
+
+
+def branch_cams_enable(branch=BL.branch):
+    """
+    """
+    cam_dict={'c':[0,1,2],'c':[3,4,6]}  # index of cam_list 
+    pvcam1=PV("29id_ps1:cam1:Acquire")
+    pvcam2=PV("29id_ps2:cam1:Acquire")
+    pvcam3=PV("29id_ps3:cam1:Acquire")
+    pvcam4=PV("29id_ps4:cam1:Acquire")
+    pvcam6=PV("29id_ps6:cam1:Acquire")
+    pvcam7=PV("29id_ps7:cam1:Acquire")
+    cam_list=[pvcam1,pvcam2,pvcam3,pvcam4,pvcam6,pvcam7]
+    sleep(0.1)
+    for pvcam in cam_list:                  # turn OFF all cam
+        try:
+            if pvcam.connected:  pvcam.put(0)
+        except:
+            pass
+    for i in cam_dict[branch]:                 # turn ON relevant cam
+        try:
+            if cam_list[i].connected: cam_list[i].put(1)
+            else: print(cam_list[i].pvname+' not connected')
+        except:
+            pass
+
diff --git a/build/lib/iexcode/instruments/cameras.py b/build/lib/iexcode/instruments/cameras.py
new file mode 100644
index 0000000000000000000000000000000000000000..1436d9b1a71c4892faa97870f1835e1003bc1bd9
--- /dev/null
+++ b/build/lib/iexcode/instruments/cameras.py
@@ -0,0 +1,52 @@
+
+from epics import caget, caput
+
+from iexcode.instruments.userCalcs import userStringSeq_clear
+from iexcode.instruments.AD_utilities import *
+from iexcode.instruments.IEX_endstations import *
+
+
+def cam_pv_dictionary(cam_num):
+    """
+    dictionary of pv names for the beamline cameras
+    """
+    d={
+        1:"29id_ps1:",
+        2:"29id_ps2:",
+        3:"29id_ps3:",
+        4:"29id_ps4:",
+        5:"29idarv5:",
+        6:"29id_ps6:",
+    }
+    return d[cam_num]
+
+def cam_scan_setup(cam_num,ADtype='TIFF',**kwargs):
+    """
+    sets up the BL scanRecord to trigger the camera (trigger - 2)
+    """
+    ADplugin = cam_pv_dictionary(cam_num)+ADtype+":"
+    ADplugin_ScanSetup(ADplugin,BL.mda, **kwargs)  
+
+def cam_snap(cam_num,ADtype='TIFF',**kwargs):
+    """
+    takes a camera image and saves it in the user folder
+    
+    **kwargs:
+    ExposureTime: changes both the exposure time and the acquire time for the snapshot
+                    resets after acquisition
+    FreeRun: True => disable setting and go back to continuous acquision 
+                False => leave saving enabled and camera in single acquision
+
+    """
+    ADplugin = cam_pv_dictionary(cam_num)+ADtype+":"
+    AD_SaveFileSetup(ADplugin,BL.mda,**kwargs)
+    AD_snap(ADplugin,**kwargs)
+
+def cam_live(cam_num,ADtype='TIFF',**kwargs):
+    """
+    puts camera in no save and continuous
+    a.k.a free run
+
+    """
+    ADplugin = cam_pv_dictionary(cam_num)+ADtype+":"
+    AD_FreeRun(ADplugin,**kwargs)
diff --git a/build/lib/iexcode/instruments/conversions_constants.py b/build/lib/iexcode/instruments/conversions_constants.py
new file mode 100644
index 0000000000000000000000000000000000000000..45f1aea59c570ce29108135e34ade471f665f24b
--- /dev/null
+++ b/build/lib/iexcode/instruments/conversions_constants.py
@@ -0,0 +1,109 @@
+import numpy as np
+
+from epics import caget
+
+##############################################################################################################
+##############################            conversions         ##############################
+##############################################################################################################
+h=4.135667516e-15
+c=299792458
+
+def deg2rad(angle_deg):
+    angle_rad=angle_deg*np.pi/180
+    return angle_rad
+
+def rad2deg(angle_rad):
+    angle_deg=angle_rad*180/np.pi
+    return angle_deg
+    
+def eV2Lambda(eV):
+    """ 
+    Converts energy (eV) into wavelenght (Angstrom)
+    """
+
+    Angstrom = h*c/eV*1e9*10
+    return Angstrom
+
+def Lambda2eV(Angstrom):
+    """ 
+    Converts wavelenghth (Angstrom) into energy (eV)
+    """
+
+    eV = h*c/Angstrom*1e9*10
+    return eV
+
+##############################################################################################################
+##############################             Kappa to Euler Conversion        ##############################
+##############################################################################################################
+def Kappa2Fourc(ang1,ang2,ang3,conversion,k_arm=50):
+
+    a,b,c=0,0,0
+    if conversion=='Kappa':
+        a,b,c=EtoK(ang1,ang2,ang3,k_arm)
+        print(("\n"+"th  = "+str(ang1)))
+        print(("chi = "+str(ang2)))
+        print(("phi = "+str(ang3)))
+        print("~~~~~~~~")
+        print(("kth  = "+str(a)))
+        print(("kap  = "+str(b)))
+        print(("kphi = "+str(c)+"\n"))
+    elif    conversion=='fourc':
+        a,b,c=KtoE(ang1,ang2,ang3,k_arm)
+        print(("\n"+"kth  = "+str(ang1)))
+        print(("kap  = "+str(ang2)))
+        print(("kphi = "+str(ang3)))
+        print("~~~~~~~~")
+        print(("th  = "+str(a)))
+        print(("chi = "+str(b)))
+        print(("phi = "+str(c)+"\n"))
+    else:
+        print('2nd argument invalid; please choose one of the following:')
+        print('"Kappa" or  "fourc"')
+    return a,b,c
+
+
+
+def EtoK(e_theta,e_chi,e_phi,k_arm=50):
+    conv = np.pi/180.0
+    kth_offset=caget('29idKappa:userCalcOut1.G')
+    if(abs(e_chi)> 2.0*k_arm):
+        print("Chi should be no more than twice the Kappa arm offset angle.")
+        kth,kap,kphi=0,0,0
+    else:
+        print(("Calculating Kappa angles using kth0 = "+str(kth_offset)))
+        k_ang = k_arm*conv
+        delta = np.asin( - np.tan(e_chi*conv/2.0) / np.tan(k_ang) )
+        k_theta = e_theta*conv - delta
+        k_kappa = 2.0 * np.asin( np.sin(e_chi*conv/2.0) / np.sin(k_ang))
+        k_phi   = e_phi*conv - delta
+        #print k_theta, k_kappa,k_phi
+        kth = rounder(k_theta)-(57.045-kth_offset)
+        kap = rounder(k_kappa)
+        kphi  = rounder(k_phi)
+        #print delta
+    return (kth,kap,kphi)
+
+
+
+
+def KtoE(k_theta,k_kappa,k_phi,k_arm=50):
+    conv = np.pi/180.0
+    kth_offset=caget('29idKappa:userCalcOut1.G')
+    print(("Calculating Euler angles using kth0 = "+str(kth_offset)))
+    k_ang = k_arm*conv
+    delta = np.atan( np.tan(k_kappa*conv/2.0) * np.cos(k_ang) )
+    e_theta = k_theta*conv - delta
+    e_chi   = 2.0 * np.asin( np.sin(k_kappa*conv/2.0) * np.sin(k_ang) )
+    e_phi   = k_phi*conv - delta
+    #print round(e_theta,1),round(e_phi,1),round(e_chi,1)
+    theta = rounder(e_theta)+(57.045-kth_offset)
+    chi   = rounder(e_chi)        # convert from rad to deg
+    phi   = rounder(e_phi)
+    #print round(delta,1)
+    return (theta,chi,phi)
+
+
+def rounder(val):        # convert from rad to deg
+    conv = np.pi/180.0
+    roundVal=round(1000.0*val/conv)/1000.0
+    return roundVal
diff --git a/build/lib/iexcode/instruments/current_amplifiers.py b/build/lib/iexcode/instruments/current_amplifiers.py
new file mode 100644
index 0000000000000000000000000000000000000000..5df2d30e8f19252ea87e2abba7c42b3f4427c3a1
--- /dev/null
+++ b/build/lib/iexcode/instruments/current_amplifiers.py
@@ -0,0 +1,367 @@
+import numpy as np
+from time import sleep
+
+from epics import caget, caput
+from iexcode.instruments.userCalcs import userStringSeq_pvs, userStringSeq_clear
+from iexcode.instruments.VLS_PGM import mono_energy_get
+
+
+def ca_detector_list(branch):
+    """
+    returns the list of keithley current amplifiers based on key
+    key: 'ARPES' / 'Staff'
+    """
+    ca_list = list(ca_dictionary()[branch].keys())
+    
+    return ca_list
+
+def ca_dictionary():
+    """
+    dictionary of connected Kiethlys and thier names
+
+    Previously: CA_Name
+    """
+    ca={}
+    ca["b"] = {
+        1: 'W-mesh',
+        2: 'H-wire',
+        3: 'V-wire',
+        4: 'Slit1A',
+        5: 'Slit1A',
+        9: 'D2B',
+        10: 'B-branch',
+        12: '',
+        13: 'Slit3C',
+        14: 'MeshD',
+        15: 'DiodeC',
+        }
+
+    ca["c"] = {
+        1:'TEY',
+        }
+    return ca
+
+##############################################################################################################
+################################            Keithley             ##############################
+##############################################################################################################
+def Keithley_pv(ca_ioc, ca_num):
+    return "29id"+ca_ioc+":ca"+str(ca_num)+":"
+
+class Keithley:
+    """
+    class for Keithley current amplifiers
+    """
+    def __init__(self,ca_ioc, ca_num):
+        self._pv = Keithley_pv(ca_ioc, ca_num)
+        try:
+            self.name = ca_dictionary()[ca_ioc][ca_num]
+        except:
+            self.name = 'CA'+ca_ioc+str(ca_num)
+
+        self.current
+        self.rate
+        self.filter_num
+        self.range
+
+    def get(self):
+        """
+        reads the current SRS and corresponding scaler values
+        """
+        self.current = caget(self.pv+"read")
+        self.range = 'Autoscale' if caget(self.pv+"rangeAuto",as_string=True)=='On' else caget(self.pv+"range",as_string=True)
+        self.rate = caget(self.pv+"rate")
+        digital_filter = (self.pv+'digitalFilter')
+        self.filter_num = 1 if digital_filter == 'On' else (self.pv+'digitalFilterCount')
+
+
+    def reset(self,rate="Slow"):
+        """
+        
+        Previously: Reset_CA
+        """
+
+        pv = self.pv
+        caput(pv+":reset.PROC",1)
+        caput(pv+":digitalFilterSet","Off")
+        caput(pv+":medianFilterSet","Off")
+        caput(pv+":zeroCheckSet",0)
+        caput(pv+":rangeAuto",1)
+        caput(pv+":rateSet",rate)
+        caput(pv+":rangeAutoUlimit","20mA")
+        caput(pv+":read.SCAN",".5 second")
+
+    def autoscale(self,On_Off='On',gain=7):
+        """
+        ca_ioc = 'b' / 'c'
+        ca_num = 2
+
+        On_Off= 'On' => Turns On the Autoscale; gain is irrelevant.
+        On_Off= 'Off' => Turns Off the Autoscale with gain below:
+                0 = 2nA
+                1 = 20nA
+                2 = 200nA
+                3 = 2uA
+                4 = 20uA
+                5 = 200uA
+                6 = 2mA
+                7 = 20mA
+
+        Previously: CA_Autoscale
+        """
+        pv = self.pv
+        caput(pv+":rangeAutoSet",On_Off)
+        sleep(0.5)
+        caput(pv+":rangeSet",gain)
+        print(pv,"Autoscale",On_Off)
+
+        if On_Off == 'Off':
+                sleep(1)
+                print("Gain set to:",caget(pv+":range",as_string=True))
+
+
+
+    def avg(self,num_averages,rate='Slow',verbose=True):
+        """
+        Turns on the filtering for the Keithlys for average during a scan
+
+        rate: Keithley sampling rate
+            'Slow' / 'Medium' / 'Fast'
+
+        num_averages: number of points to average
+
+        returns the settling_time
+
+        Previously: CA_Filter
+        """
+
+        pv = self.pv
+        name=self.name
+        t=0.1
+        if rate == "Slow":
+            t=6/60.0
+        elif rate == "Medium":
+            t=1/60.0
+        elif rate == "Fast":
+            t=0.1/60.0
+
+        settling_time=round(max(0.15,num_averages*t+0.1),2)
+
+        if num_averages  <= 1: # no averaging
+            self.reset(rate)    
+            settling_time = None
+            if verbose:
+                print("Average disabled: "+name+" - "+pv)
+
+        else:
+            caput(pv+"read.SCAN","Passive",wait=True,timeout=500)
+            caput(pv+"rateSet",rate)
+            sleep(1)
+            caput(pv+"digitalFilterCountSet",num_averages,wait=True,timeout=500)
+            caput(pv+"digitalFilterControlSet","Repeat",wait=True,timeout=500)
+            caput(pv+"digitalFilterSet","On",wait=True,timeout=500)
+            
+            if verbose:
+                print("Average enabled: "+name+" - "+pv)
+                print("Detector settling time: "+str(settling_time)+"s")
+
+        return settling_time
+
+
+    
+def ca_reset_all(rate="Slow"):
+    """"
+    
+    Previously: Reset_CA_all
+    """
+    ca_dict = ca_dictionary()
+    for ca_ioc in ca_dict.keys():
+        for ca_num in ca_dict[ca_ioc].keys(): 
+            CA = Keithley(ca_ioc,ca_num)
+            CA.reset()
+
+    caput("29idb:ca5:read.SCAN","Passive")    # CA5 in passive
+    print("\nAll the current amplifiers have been reset; ca5 set to passive.")
+
+def ca_live_sequence(ioc,seq_num,detector_list):    
+    """
+    creates a string sequence to put keithleys back in live mode
+
+    ca_list = list of ca to go in live
+
+    Previously: CA_Live_StrSeq
+    """   
+    userStringSeq_pv, userStringSeq_proc = userStringSeq_pvs(ioc, seq_num)       # do we need to add 29idb:ca5 ???
+ 
+    userStringSeq_clear(ioc,seq_num)
+
+    caput(userStringSeq_pv+".DESC","CA Live "+ioc)
+
+    for (i,ca) in enumerate(detector_list):
+        pv = "29id"+ca[0]+":ca"+str(ca[1])+":"
+        ca_read_pv = pv+'read.SCAN CA NMS'
+        ca_avg_pv = pv+'digitalFilterSet PP NMS'
+
+        caput(userStringSeq_pv+".LNK"+str(i+1),ca_avg_pv)
+        caput(userStringSeq_pv+".STR" +str(i+1),"Off")
+
+        n=len(detector_list)
+        if n+1+i < 10:
+            caput(userStringSeq_pv+".LNK" +str(n+1+i),ca_read_pv)
+            caput(userStringSeq_pv+".STR" +str(n+1+i),".5 second")
+            caput(userStringSeq_pv+".WAIT"+str(n+1+i),"After"+str(n))
+        elif n+1+i == 10:
+            caput(userStringSeq_pv+".LNKA",ca_read_pv)
+            caput(userStringSeq_pv+".STRA",".5 second")
+            caput(userStringSeq_pv+".WAITA","After"+str(n))
+
+    return userStringSeq_proc
+
+def ca_average(avg_pts,ca_list,rate="Slow",verbose=True):
+    """
+    Average reading of the relevant current amplifiers for the current scanIOC/branch.
+
+    Previously: CA_average
+    """
+    print("\nAverage set to:   "+str(max(avg_pts,1)))
+    for i in range(0,len(ca_list)):
+        ca = Keithley(ca_list[i][0],ca_list[i][1])
+        ca.avg(avg_pts,rate=rate,verbose=verbose)
+
+
+def load_responsivity_curve():
+    """
+    Loads the responsivity curve for the AUX100 photo diode, used to convert 
+    current to flux at a given photon energy
+
+    Previously: loadResponsivityCurve
+    """
+    FilePath='/home/beams/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/'
+    FileName="DiodeResponsivityCurve"
+    data = np.loadtxt(FilePath+FileName, delimiter=' ', skiprows=1)
+    return data
+
+def current2flux(current,hv=None,verbose=True):
+    """
+    Converts the current to flux for of an AUX 100 diode using the responisity curves
+
+    hv = None; gets the current mono energy; otherwise you will need to specify
+
+    Previously CA2flux
+    """
+    try: 
+        curve=load_responsivity_curve()
+    except:
+        print('responsivity curve not loaded')
+        return
+    responsivity=curve[:,0]
+    energy=curve[:,1]
+    charge = 1.602e-19
+    if hv is None:
+        try: 
+            hv = mono_energy_get()
+        except:
+            print('specify hv')
+            return
+    eff=np.interp(hv,energy,responsivity)
+    flux = current/(eff*hv*charge)
+    if verbose:
+        print("\nCalculating flux for:")
+        print("   hv = %.1f eV" % hv)
+        print("   current = %.3e Amp" % current)
+        print("Flux = %.3e ph/s\n" % flux)
+    return flux
+
+
+def flux2current(flux,hv=None,verbose=True):
+    """
+    Converts the specified flux to a current for of an AUX 100 diode using the responisity curves
+
+    hv = None; gets the current mono energy; otherwise you will need to specify
+    """
+    try:
+        curve=load_responsivity_curve()
+    except:
+        print('responsivity curve not loaded')
+        return
+    responsivity=curve[:,0]
+    energy=curve[:,1]
+    charge = 1.602e-19
+    if hv is None:
+        try:
+            hv = mono_energy_get()
+        except:
+            print('specify hv')
+            return
+    eff=np.interp(hv,energy,responsivity)
+    current = flux*(eff*hv*charge)
+    if verbose:
+        print("\nCalculating current for:")
+        print("   hv = %.1f eV" % hv)
+        print("   flux = %.3e ph/s" % flux)
+        print("Current = %.3e Amp/n" % current)
+    return current
+
+    
+
+##############################################################################################################
+################################            SRS             ##############################
+##############################################################################################################
+class SRS:
+    """
+    SRS current amplifier and corresponding scalers
+    """
+
+    def __init__(self,scaler_pv,srs_pv):
+        self._scaler_pv = scaler_pv
+        self._srs_pv = srs_pv
+        
+        self.scaler_value 
+        self.gain
+        self.unit
+        self.current
+        self.get()
+
+    def get(self):
+        """
+        reads the current SRS and corresponding scaler values
+        """
+        self.scaler_value = caget(self._scaler_pv)
+        self.gain = float(caget(self._scaler_pv+'sens_num.VAL',as_string=True))
+        self.unit = caget(self._scaler_pv+'sens_unit.VAL',as_string=True)
+        CA = {'pA':1e-12, 'nA':1e-9, 'uA':1e-6, 'mA':1e-3}
+        self.current = self.scaler_value * self.gain * CA[self.unit]
+
+    def setgain(self,gain,unit):
+        """
+        gain = 1,2,5,10,20,50,100,200,500
+        unit = 'pA, 'nA', 'uA', 'mA'
+        """
+        caput(self._srs_pv+'sens_num.VAL',str(gain))
+        caput(self._srs_pv+'sens_unit.VAL',str(unit))
+  
+
+    def srs_print_all(self, long=False):
+        """
+        prints  SRS setting
+        """
+
+        invert=caget(self._srs_pv+'invert_on.VAL',as_string=True)
+        currentUnit=caget(self._srs_pv+'sens_unit.VAL',as_string=True)
+        currentValue=caget(self._srs_pv+'sens_num.VAL',as_string=True)
+        offsetValue=caget(self._srs_pv+"offset_num.VAL",as_string=True)
+        offsetUnit=caget(self._srs_pv+"offset_unit.VAL",as_string=True)
+        offsetSign=caget(self._srs_pv+"offset_sign.VAL",as_string=True)
+        offsetFactor=caget(self._srs_pv+"off_u_put.VAL",as_string=True)
+        print('Gain: '+currentValue+' '+currentUnit+'  (invert '+invert+')')
+        print('Baseline: '+offsetSign+' '+offsetFactor+' x '+offsetValue+" "+offsetUnit)
+        if long:
+            filterType=caget(self._srs_pv+'filter_type.VAL',as_string=True)
+            filterLow=caget(self._srs_pv+'low_freq.VAL',as_string=True)
+            filterHigh=caget(self._srs_pv+'high_freq.VAL',as_string=True)
+            blank=caget(self._srs_pv+'blank_on.VAL',as_string=True)
+            biasOnOff=caget(self._srs_pv+'bias_on.VAL',as_string=True)
+            biasValue=caget(self._srs_pv+'bias_put.VAL',as_string=True)
+            print('Filter: '+filterType+' - Low/High: '+filterLow+'  -'+filterHigh)
+            print('Bias: '+biasOnOff+'- '+biasValue)
+            print('Blank: '+blank)
+        
diff --git a/build/lib/iexcode/instruments/diagnostics.py b/build/lib/iexcode/instruments/diagnostics.py
new file mode 100644
index 0000000000000000000000000000000000000000..50814ae88854f644fb99cd2b62123794f6428fac
--- /dev/null
+++ b/build/lib/iexcode/instruments/diagnostics.py
@@ -0,0 +1,225 @@
+from numpy import nan
+
+from epics import caput, caget
+from iexcode.instruments.IEX_endstations import *
+
+##############################################################################################################
+################################            default positions             ##############################
+##############################################################################################################
+
+###### We should make pvs in the 29idb ioc to hold these values:
+def diagnostics_dict():
+    """
+    Dictionary of Diagnostic positions In and Out by either motor number or name
+    WARNING: When updating motor values, also update the following screens:
+        - 29id_BL_Layout.ui               (for MeshD and DiodeC)
+        - 29id_Diagnostic.ui
+        - 29idd_graphic
+    usage:       
+        diagnostics_dict()['name'] returns dictionary motor:name
+        diagnostics_dict()['motor'] returns dictionary name:motor   
+        diagnostics_dict()['In'] returns dictionary motor:In position  (where val can be a list for multiple position)  
+        diagnostics_dict()['Out'] returns dictionary motor:In position  
+                motor=diagnostics_dict()['motor']['gas-cell']
+                pos_in=diagnostics_dict()['In'][motor]
+                
+    WARNING: When updating MeshD (D5D) value: update value in the dictionnary + caQtdM (29id_BL_Diag.ui + 29idd_graphic.ui + Diagnostic.ui)
+    
+    Previously: AllDiag_dict
+    """
+    diag={}
+    diag["In"]  = {                5:-55, 6:-46,          17:-56, 20:-30, 25:-56, 28:[-3,-3]}
+                                                                                    
+    diag["Out"] = {1:-4, 2:-10, 3:-4, 4:-4, 5:-20, 6:-20, 7:-20, 17:-20, 20:-21, 25:-20, 28:-3}    
+    diag["name"]= {1:"H-wire", 2:"V-wire", 3:"H-Diagon", 4:"V-Diagon", 5:"W-mesh",
+     6:"D2B", 7:"D3B", 17:"D4C/pre-slit", 20:"gas-cell", 25:"D4D/pre-slit", 28:"D5D/pre-RSXS"}
+    diag["motor"]= {"H-wire":1, "V-wire":2, "H-Diagon":3, "V-Diagon":4,"W-mesh":5,
+     "D2B":6, "D3B":7, "D4C":17, "gas-cell":20,"D4D":25,"D5D":28}
+    return diag
+
+def diagnostic_CA_dict():
+    CA_dict={
+        'diode_c':'29idb:ca15:'
+    }
+    return CA_dict
+
+
+def diagnostic(diagnostic_name,in_out):
+    "Inserts/retracts a diagnostic(motor number or name) either = \"In\" or \"Out\""
+    diag=diagnostics_dict()
+    if type(diagnostic_name) is int:
+        motor=diagnostic_name
+        name=diag['name'][motor]
+    else:
+        name=diagnostic_name
+        motor=diag["motor"][name]
+    position=diag[in_out][motor]
+
+    caput("29idb:m"+str(motor)+".VAL",position,wait=True,timeout=18000)
+    print("\n"+name+": "+ in_out)
+
+def diagnostics_all_out(diode_stay_in=False):
+    """
+    Retracts all diagnostic
+    diode_to_stay_in = True / False (checks beamline)
+
+    Previously: AllDiagOut
+    """
+    diag=diagnostics_dict()
+    text=""
+
+    #which motor is Diode of interest
+    if diode_stay_in:
+        branch = BL.branch
+
+    if branch == 'c':
+        diode_motor=diag["motor"]["gas-cell"]
+    elif branch == 'd':
+        diode_motor=diag["motor"]["D5D"]
+    else:
+        diode_motor=None
+
+    #Taking out the diagnostic
+    for motor in list(diag["Out"].keys()):
+        if motor is diode_motor:
+            text=' except Diode-'+BL.branch
+            #putting Diode In if not already in -JM
+            position=diag["In"][motor]
+            caput("29idb:m"+str(motor)+".VAL",position,wait=True,timeout=18000)
+        else:
+            position=diag["Out"][motor]
+            caput("29idb:m"+str(motor)+".VAL",position,wait=True,timeout=18000)
+    text="All diagnostics out"+text
+    print("\n",text)
+
+def diagnostics_all_in():
+    """
+    Inserts all diagnostic (meshes and diodes) for pinhole scans
+    
+    Previously: AllDiagIn and AllMeshIn()
+    """
+    diag=diagnostics_dict()
+    for motor in list(diag["In"].keys()):
+        position=diag["In"][motor]
+        if type(position) == list:
+            position=position[0]
+        caput("29idb:m"+str(motor)+".VAL",position,wait=True,timeout=18000)
+        print('m'+str(motor)+' = '+str(position))
+    print("All diagnostics in (meshes and diodes) for pinhole scans")
+
+def mesh_W(In_Out):
+    """
+    Inserts/retracts RSXS mesh (post-slit); arg = \"In\" or \"Out\"
+
+    Previously MeshW
+    """
+    diag=diagnostics_dict()
+    motor=5; position=diag[In_Out][motor]
+    caput("29idb:m"+str(motor)+".VAL",position,wait=True,timeout=18000)
+    print("\nD1A mesh_W: "+ In_Out)
+
+
+def diodeC(In_Out):
+    """
+    Inserts/retracts ARPES (gas-cell) diode; arg = \"In\" or \"Out\"
+    
+    Previously: DiodeC
+    """
+    diag=diagnostics_dict()
+    motor=20; position=diag[In_Out][motor]
+    caput("29idb:m"+str(motor)+".VAL",position,wait=True,timeout=18000)
+    print("\nARPES Diode: "+ In_Out)
+
+
+def diodeD(In_Out):
+    """
+    Inserts/retracts RSXS diode; arg = \"In\" or \"Out\"
+
+    Previously:DiodeD
+    """
+    diag=diagnostics_dict()
+    motor=28; position=position=diag[In_Out][motor]
+    if type(position) == list:
+        position=position[1]
+    caput("29idb:m"+str(motor)+".VAL",position,wait=True,timeout=18000)
+    print("\nRSXS Diode: "+ In_Out)
+
+
+
+def meshC(In_Out,which="postSlit"):
+    """
+    Inserts/retracts ARPES mesh (preSlit or postSlit); arg = \"In\" or \"Out\"
+    
+    Previously: MeshC
+    """
+    diag=diagnostics_dict()
+    if which == "postSlit":
+        motor=20; position=-31
+    elif which == "preSlit":
+        motor=17; position=diag[In_Out][motor]
+
+    caput("29idb:m"+str(motor)+".VAL",position,wait=True,timeout=18000)
+    print("\nD4C Au-Mesh: "+ In_Out)
+
+def meshD(In_Out):
+    """
+    Inserts/retracts RSXS mesh (post-slit); arg = \"In\" or \"Out\"
+    
+    Previoulsy: MeshD
+    """
+    diag=diagnostics_dict()
+    motor=28; position=position=diag[In_Out][motor]
+    if type(position) == list:
+        position=position[0]
+    caput("29idb:m"+str(motor)+".VAL",position,wait=True,timeout=18000)
+    print("\nD5D Au-Mesh: "+ In_Out)
+
+def diagnostic_read(diode_d, quiet=True):
+    """
+    reads the current amplifier and returns the value
+    quiet = False to pring
+    """ 
+    try:
+        diode_pv = diagnostic_CA_dict['diode_d']
+        val=caget(diode_pv+'read')
+    except:
+        diode_pv="not connected"
+        val = nan
+        print('pv not defined')
+
+    if not quiet:
+        print('Diode-D ',val, "(pv = "+diode_pv+")")
+    return val
+
+def diodeC_read(quiet=True):
+    """
+    reads the current amplifier and returns the value
+    quiet = False to pring
+    """ 
+    val = diagnostic_read('diode_d',quiet)
+    return val
+
+def diodeD_read(quiet=True):
+    """
+    reads the current amplifier and returns the value
+    quiet = False to pring
+    """ 
+    val = diagnostic_read('diode_d',quiet)
+    return val
+
+def meshD_read(quiet=True):
+    """
+    reads the current amplifier and returns the value
+    quiet = False to pring
+    """ 
+    val = diagnostic_read('diode_d',quiet)
+    return val
+
+
+###############################################################################################
+####################################### FLUX CONVERSION #######################################
+###############################################################################################
+
+
+
+
diff --git a/build/lib/iexcode/instruments/electron_analyzer.py b/build/lib/iexcode/instruments/electron_analyzer.py
new file mode 100644
index 0000000000000000000000000000000000000000..8cfbb778c92dd9ce36f68ab6a062d44c5b9814af
--- /dev/null
+++ b/build/lib/iexcode/instruments/electron_analyzer.py
@@ -0,0 +1,797 @@
+#############################################################
+###################### Imports ##############################
+#############################################################
+
+from os.path import join, isfile, exists, dirname
+from os import mkdir
+from operator import itemgetter
+import time
+from datetime import timedelta
+from math import ceil,floor,modf
+
+import numpy as np
+from scipy.interpolate import interp1d
+
+from epics import caput,caget
+from iexcode.instruments.IEX_endstations import *
+
+from iexcode.instruments.scanRecord import *
+from iexcode.instruments.conversions_constants import *
+from iexcode.instruments.xrays import energy, scanXAS_BL, BL_energy_tables
+from iexcode.instruments.shutters import branch_shutter_close
+from iexcode.instruments.VLS_PGM import mono_energy_get
+from iexcode.instruments.files_and_folders import get_next_fileNumber
+from iexcode.instruments.logfile import *
+from iexcode.instruments.ARPES import ARPES_motor_dictionary, ARPES_motor_scan, ARPES_mvsample,ARPES_scan_2D
+from iexcode.instruments.Scienta import *
+
+def __main__():
+    global EA
+    EA = Scienta()
+    
+mda = BL.mda
+###########################################################################
+
+def EA_ioc_init(**kwargs):
+    """
+    run after restarting the 29idcScienta IOC
+    kwargs:
+        Close_CShutter="Close" default, if something else then it doesn't close the shutter
+    """
+    kwargs.setdefault("close_shutter",True)
+    if kwargs['close_shutter']==True:
+        branch_shutter_close('c')
+    #Addding HDF5 atttributes
+    filepath='/xorApps/epics/synApps_6_1/ioc/29idcScienta/iocBoot/ioc29idcScienta/HDF5Attributes.xml'
+    EA._updateAttributes(filepath)
+    #Allow EA to make directories
+    caput('29idcScienta:HDF1:CreateDirectory',-1)
+    #Enabling User CalcOut, needed for BE 
+    caput("29idcScienta:userCalcOutEnable.VAL","Enable")
+    #Enabling User StringCalc for caQtDM 
+    ioc="29idcScienta:"
+    pv=ioc+"userStringCalc2"
+    caput(pv+".DESC","scan1 trigger2 calc")
+    caput(pv+".INAA",ioc+"scan1.T2PV CP NMS")
+    caput(pv+".BB",ioc+"HV:ScanTrigger")
+    caput(pv+".CALC$","AA==BB")
+    caput(ioc+"userStringCalcEnable.VAL","Enable")
+    
+    #clipping and other processing
+    caput("29idcScienta:Proc1:EnableLowClip","Enable")
+    caput("29idcScienta:Proc1:LowClip",1)
+    caput("29idcScienta:Proc1:EnableHighClip",'Disable')
+    caput("29idcScienta:Proc1:EnableOffsetScale","Enable")
+    caput("29idcScienta:Proc1:Scale",10)
+    caput("29idcScienta:Proc1:Offset",-1)
+    
+    #Global Detector Setting
+    caput('29idcScienta:HV:AngularROImin.VAL',290)
+    caput('29idcScienta:HV:AngularROImax.VAL',830) 
+    caput('29idcScienta:HV:AngularBinning','Off')   
+    
+    ### Add here
+    #Setting ExpFrames
+    caput("29idcScienta:ExpFrames.VAL",1)
+    #setting save default lens values
+    EA._AcquisitionMode('Spectra')
+    time.sleep(0.25)
+    try:
+        KE = mono_energy_get()
+    except:
+        KE = 2000
+    EA.put(KE, PE=50, LensMode="Angular")
+    caput(EA.PHV+"KineticEnergy:TWV.VAL",1)
+    caput(EA._Pcam+"Acquire","Acquire")
+    
+    print("C-Shutter is closed for initialization ")
+
+def getSESslit():
+    SES=caget("29idc:m8.RBV")
+    return SES
+
+def folders_EA(userPath,filePrefix="EA",**kwargs):
+    """
+    For Staff: folder='b', userName='Staff'
+    For ARPES: folder ='c'
+
+    setFolders = True; creates the data folder and sets scanRecords/AreaDetectors 
+               = False: only creates the data folders; does NOT set 
+    """
+    kwargs.setdefault('set_folders',True)
+    kwargs.setdefault('debug',False)
+    try:
+        ADplugin=EA._savePlugin 
+        dtype=EA.dtype  
+        if dtype == "nc":
+            df="netCDF"
+        else:
+            df=EA.dtype  
+    except:
+        df="h5"
+
+    fpath=join(userPath,df)
+    print("\nFolder: " + fpath)
+
+    if exists(fpath):
+        if kwargs['debug']==True:
+            print("exists")
+        try:
+            fileNumber=get_next_fileNumber(fpath,filePrefix, debug=False)
+        except:
+            kwargs['create_only']=True
+            print("fileNumber not set, EA not connected, create_only=True")
+    else:
+        if kwargs['debug']==True:
+            print("making")
+        mkdir(fpath)
+        fileNumber=1
+    try:
+        if kwargs['set_folders']:
+            caput(ADplugin+"FilePath",fpath)
+            caput(ADplugin+"FileName",filePrefix)
+            caput(ADplugin+"FileNumber",fileNumber)
+
+            #setup AD
+            caput(ADplugin+"FileTemplate","%s%s_%4.4d."+dtype)
+            caput(ADplugin+"AutoIncrement","Yes")
+            caput(ADplugin+"AutoSave","Yes")
+
+        print("EA path: "+fpath)    
+        print("Next "+filePrefix+" file: "+str(fileNumber))  
+    except:
+        df='h5'
+        fpath=join(userPath,df)
+    
+def EA_log_update():
+    """
+    spectra entries for the log file
+    """
+    spectra_info = {
+        'PE':[EA.PassEnergy,".0f"],
+        'lens_mode':[EA.LensMode,"s"],
+        "scan_mode":[EA.scan_mode,"s"],
+        "KE":[str(EA.KE),"s"],
+        "sweeps":[EA.Sweeps,".0f"],
+        "frames":[EA.ExpFrames,".0f"]
+    }
+
+    try:
+        entry_list=[]
+        pv_list=[]
+        format_list=[]
+        for key in spectra_info:
+            entry_list.append(key)
+            pv_list.append(spectra_info[key][0])
+            format_list.append(spectra_info[key][1])
+        logfile_update("ARPES",BL.ioc,entry_list,pv_list,format_list)
+    except:
+        print("EAlog did not write to file, check for errors.")
+
+def log_headerEA():##JM - need to update so that we get the keys from log_EA
+    s="\nscan    x   y   z   th   chi   phi   T   scan_mode   E1   E2   step   i   f   PE   lens_mode   SES slit #    ID_mode   hv   exit_slit   GRT   TEY1   TEY2   time\n"
+    kwargs={'comment': s}
+    logfile_print("ARPES",BL.ioc,comment='')
+
+def EAsweptTime_estimate(EAlist,overhead=[60,.22]):
+    """
+    estimates the time for spectra with the current analyzer settings
+    overhead[0] = intiating scan (seconds)
+    overhead[1] = per point (seconds)
+    """
+    E=1392#image width
+    HVscanDIM=2
+
+    B=EAlist[4]*0.000078# PixelEnergy=PassEnergy*0.000078
+
+    C=EAlist[1]# Estart
+    A=ceil(EAlist[3]/B)*B # Estep
+    D=C+ceil((EAlist[2]-C)/A)*A # Estop
+
+    E0=ceil((D-C)/(ceil(A/B)*B))
+    E1=E/min(floor(ceil(A/B)+0.001),E)
+    E2=(E/min(floor(ceil(A/B)+0.001),E))%2
+    numPnts=E0+E1-E2+1 
+    print(numPnts)
+    
+    PDLY=caget(EA.PHV+"scan"+str(HVscanDIM)+".PDLY")
+    DDLY=caget(EA.PHV+"scan"+str(HVscanDIM)+".PDLY")
+    time_seconds=overhead[0]+numPnts*(1/17+PDLY+DDLY+overhead[1])  
+    print(C,D,B, EAlist[4])
+    return str(timedelta(seconds=time_seconds))
+
+
+def _scanEATrigger(EAlist,before_after,**kwargs):
+    """
+    before_after="before" sets up scanIOC scanRecord for EA scan and sets prefix to "MDAscan0000"
+    before_after="after" clears up scanIOC scanRecord of EA scan and resets prefix to "EA"
+        Trigger EA
+        Det20 = EA scanNum
+
+        set the EA._savePlugin Prefix to be 'MDAscan0045_'
+        **kwargs:
+            scan_dim=1
+            detTrig=2
+    """ 
+    kwargs.setdefault("scan_dim",1)
+    kwargs.setdefault("detTrig",2)
+    kwargs.setdefault("dtype",EA.dtype)
+    kwargs.setdefault("detNum",20)
+    kwargs.setdefault("prefix","EA")# if not None then over rides the auto
+    kwargs.setdefault("debug",False)
+
+    scanPV=BL.ioc+"scan"+str(kwargs["scan_dim"])
+    triggerPV=scanPV+".T"+str(kwargs["detTrig"])+"PV"
+    
+    if kwargs["debug"]:
+        print("scanPV: "+scanPV)
+        print("before_after: "+before_after)
+        
+    #setting EA._savePlugin FilePath, FileName,FileNumber
+    if before_after == "before":
+        _scanEAPrefix("mda",**kwargs)
+        scantype, HVscanPV, KElist, parms =EA._spectraSetup(EAlist,**kwargs)
+        caput(triggerPV,HVscanPV)
+        
+    if before_after == "after":
+        _scanEAPrefix(kwargs["prefix"],**kwargs)
+        caput(triggerPV,"")
+        
+    if kwargs["debug"]:
+        print(triggerPV,caget(triggerPV, as_string=True))
+    return
+ 
+
+def _scanEAPrefix(ptype,**kwargs):
+    """
+    sets the EA file prefix based on 
+    ptype = "mda" -> for "MDAscan"+current MDA file
+        else prefix = ptype
+    kwargs:
+        debug = False (default)
+        prefix
+    """
+    kwargs.setdefault("debug",False)
+    kwargs.setdefault("nzeros",4)
+    kwargs.setdefault("debug",False)
+    
+    prefix=""
+    if kwargs["debug"]:
+        print(ptype)
+
+    if ptype == "mda":
+        fpath = mda.filepath[0:-3]+EA.dtype
+        nextMDA = mda.fileNum 
+        prefix = "MDAscan"+str.zfill(str(nextMDA),kwargs["nzeros"])
+    else:
+        prefix = ptype
+    
+    if kwargs["debug"]==kwargs["debug"]:
+        print("_scanEAPrefix prefix: ",prefix)
+
+    
+    #setting the file path for the EA saving
+    fpath=caget(EA._savePlugin +"FilePath",as_string=True)
+    caput(EA._savePlugin+"FileName",prefix)
+    nextNum=get_next_fileNumber(fpath,prefix,**kwargs)
+    caput(EA._savePlugin+"FileNumber",nextNum)
+    time.sleep(.5)
+    if kwargs["debug"]:
+        print("FilePath: ",caget(EA._savePlugin +"FilePath", as_string=True))
+        print("FileName: ",caget(EA._savePlugin +"FileName", as_string=True))
+        print("FileNumber: ",caget(EA._savePlugin +"FileNumber", as_string=True))
+
+def _BE2KE_setupCalc(BE,DESC,CalcOutNum,OutputPV):
+    """
+    used by scanEA for talking in BE
+    """
+    pvCalcOut="29idcScienta:userCalcOut"+str(CalcOutNum)
+    if len(OutputPV)==0:
+        caput(pvCalcOut+"Enable","D")
+    else:
+        caput(pvCalcOut+"Enable","E")
+    caput(pvCalcOut+".DESC", DESC)
+    caput(pvCalcOut+".A",BE)
+    caput(pvCalcOut+".INPB","29idmono:ENERGY_MON CP NMS")
+    caput(pvCalcOut+".INPC","29idcScienta:HV:WorkFunction  CP NMS")
+    caput(pvCalcOut+".CALC$","B-A-C")
+    caput(pvCalcOut+".OUT",OutputPV+" PP")
+    return pvCalcOut
+    
+def scanEA_reset(**kwargs):
+    """resets the IOC after a forced stop
+    """
+    kwargs.setdefault("scan_dim",1)
+
+    _scanEATrigger([],"after",**kwargs)
+    mda.positioners_clear(kwargs["scan_dim"])
+    
+def scanEA(EAlist,**kwargs):
+    """
+    Uses the scanRecord (mda) to take multiple Scienta spectra
+    EAlist=
+        Fixed Mode:["KE"/"BE",CenterEnergy,PassEnergy,Frames,Sweeps] (5)
+        Swept Mode:["KE"/"BE",StartEnergy,StopEnergy,StepEnergy,PassEnergy,Frames,Sweeps] (7)
+        Baby Sweep (dither):["KE"/"BE",CenterEnergy,PassEnergy,Frames,Sweeps,"BS"] (6)
+
+            (+) BE is positive below Ef
+            (-) BE is negative above Ef
+            
+    **kwargs
+        scanIOC=BL_ioc()
+        scan_dim=1
+        execute: True/False to start the scan => True (default)
+        debug=False
+        
+    """
+
+    kwargs.setdefault('scanIOC',BL.ioc())
+    kwargs.setdefault('scan_dim',1)
+    kwargs.setdefault('execute',True)
+    kwargs.setdefault("debug",False)
+    
+    if EAlist[0]=="KE" or EAlist[0]=="BE":
+        pass
+    else:
+        print("need to specify BE or KE")
+
+    if EAlist[-1]=='BS':
+        sweeps=EAlist[-2]
+    else:
+        sweeps=EAlist[-1]
+        
+    if kwargs['debug']:
+        print("sweeps: "+str(sweeps))
+        
+    if EAlist[0]=="BE":
+        if len(EAlist)==5: #Fixed
+            pvCalcOut1=_BE2KE_setupCalc(EAlist[1],"BE_center",10,"29idcScienta:HV:fixedEnergy.VAL")
+            EAlist[1]=caget(pvCalcOut1+'.VAL')
+            arrayP1=list(np.full(sweeps,  EAlist[1]))
+            mda.fillin_table(pvCalcOut1+'.PROC',"",kwargs["scanIOC"],kwargs["scan_dim"],arrayP1,1)
+            EAlist[1]=arrayP1[0]
+            if kwargs['debug']:
+                print('\npvCalcOut1: ',pvCalcOut1)
+                print('Pos1 table:',arrayP1)
+        elif len(EAlist)==6: #Baby-Swept
+            pvCalcOut1=_BE2KE_setupCalc(EAlist[1],"BE_center",10,"29idcScienta:HV:babySweepCenter.VAL")
+            EAlist[1]=caget(pvCalcOut1+'.VAL')
+            arrayP1=list(np.full(sweeps, EAlist[1]))
+            mda.fillin_table(pvCalcOut1+'PROC',"",kwargs["scanIOC"],kwargs["scan_dim"],arrayP1,1)
+            print('\npvCalcOut1: ',pvCalcOut1)
+            print('Pos1 table:',arrayP1)
+        elif len(EAlist)==7: #Sweep
+            pvCalcOut1=_BE2KE_setupCalc(EAlist[1],"BE_start",9,"29idcScienta:HV:sweepStartEnergy.VAL")
+            pvCalcOut2=_BE2KE_setupCalc(EAlist[2],"BE_stop",10,"29idcScienta:HV:sweepStopEnergy.VAL")
+            EAlist[1]=caget(pvCalcOut1+'.VAL')
+            EAlist[2]=caget(pvCalcOut2+'.VAL')
+            arrayP1=list(np.full(sweeps, EAlist[1]))
+            arrayP2=list(np.full(sweeps, EAlist[2]))
+            mda.fillin_table(pvCalcOut1+'.PROC',"",kwargs["scanIOC"],kwargs["scan_dim"],arrayP1,1)
+            mda.fillin_table(pvCalcOut2+'.PROC',"",kwargs["scanIOC"],kwargs["scan_dim"],arrayP2,2)
+            if kwargs['debug']:
+                print("\npvCalcOut1",pvCalcOut1)
+                print("\npvCalcOut2",pvCalcOut2)
+                print('Pos1 table:',arrayP1)
+                print('Pos2 table:',arrayP2)
+        EAlist[0]=='KE'
+    else:
+        _BE2KE_setupCalc(0,"",9,"")
+        _BE2KE_setupCalc(0,"",10,"")  
+        
+    if kwargs['debug']:
+        print('/n EAlist => ',EAlist)
+
+    #set up name and add HV trigger and FileNum as det scan1 (sweeps)
+    _scanEATrigger(EAlist,"before",**kwargs)
+    
+    if kwargs['debug']:
+        print("Clearing scan positioners and filling in sweeps")  
+    #Fill in Sweeps scan
+    mda.positioners_clear(**kwargs)
+    VAL=""
+    RBV=""
+    mda.fillin(VAL,RBV,1,sweeps,1,**kwargs)
+    if kwargs['debug']:
+        scanPV="29id"+kwargs["scanIOC"]+":scan"+str(kwargs["scan_dim"])
+        print("scanPV: "+scanPV)     
+    
+    
+        
+    #Writing EA parameters
+    EAscanType, EAscanPV, KElist, EAparms =EA._spectraSetup(EAlist,**kwargs)    
+    
+    if kwargs['debug']:
+        print("EA._spectraSetup: ")
+        print(EAscanType,EAscanPV, KElist)
+    
+    print(EA._spectraMessage(EAscanType, EAscanPV, KElist))
+    #print(EA._EAspectraTime())
+    
+    #executing the scan
+    if kwargs['execute']:
+        EA.put(EAparms['KineticEnergy'],EAparms['PassEnergy'],LensMode="Angular",Frames=EAparms['Frames'],**kwargs)
+        time.sleep(10)
+        EA.put(EAlist[1]-.05,EAlist[-3],LensMode="Angular")
+        time.sleep(2)
+        mda.go(**kwargs)
+        #After scan
+        EA_log_update()
+        scanEA_reset(**kwargs)
+        mda.table_reset_after(**kwargs)
+    else:
+        return EAparms
+
+
+        
+def scanFM(RoughPositions,thList,EAlist,**kwargs):
+    """
+    New FermiMap using ScanRecord table scans to move motors
+    RoughPositions is a List rough positions from which to interpolate (use RoughPositions_Find())
+    thList=[th_start,th_stop,th_step]
+    EAlist  to be finish only one scan at the moment[can be a single list if you are only taking a single scan or a list of lists to take multiple scans]
+        **kwargs
+            scanIOC = BL_ioc()
+            scan_dim = 1
+        
+            logfile(**kwargs)
+    """
+    kwargs.setdefault("scan_dim",2)
+    kwargs.setdefault("debug",False)
+    kwargs.setdefault('execute',True)
+
+    # Making Tables and Filling positioners
+    x,y,z,th,chi,phi=interpRoughPositions(RoughPositions,thList[0],thList[1],thList[2])
+    if kwargs['debug']:
+        print(x,y,z,th,chi,phi)
+    
+    mda.fillin_table(ARPES_motor_dictionary("th")[1],ARPES_motor_dictionary("th")[0],th,positioner_num=1)
+    mda.fillin_table(ARPES_motor_dictionary("x")[1],ARPES_motor_dictionary("x")[0],x,positioner_num=2)
+    mda.fillin_table(ARPES_motor_dictionary("y")[1],ARPES_motor_dictionary("y")[0],y,positioner_num=3)
+    mda.fillin_table(ARPES_motor_dictionary("z")[1],ARPES_motor_dictionary("z")[0],z,positioner_num=4)
+
+    #setting up EA
+    EAkwargs={
+    'execute':False,
+    'scan_dim':1
+    }
+    EAparms=scanEA(EAlist,**EAkwargs)
+    
+    #executing the scan
+    if kwargs["execute"]==True:
+        print(EAparms)
+        EA.put(EAparms['KineticEnergy'],EAparms['PassEnergy'],LensMode="Angular",Frames=EAparms['Frames'],**kwargs)
+        mda.go(**kwargs)
+        EA_log_update()
+        scanEA_reset(**kwargs)
+
+
+def interpRoughPositions(RoughPositions,thStart,thStop,thStep,**kwargs):
+    """
+    Interpolate sample position as a function of theta, based on RoughPosition, 
+    a list of motor position lists and returns x,y,z,th,chi,phi
+
+    **kwargs:
+        kind="cubic" by default, interpolation type ("linear","cubic","quadratic")
+
+    Usage:  
+        x,y,z,th,chi,phi=interpRoughPositions(RoughPositions,3,-8,0.5) 
+
+    (direction to minimize backlash)
+        RoughPositions=[
+                    [x,y,z,th,chi,phi],
+                    [x,y,z,th,chi,phi]
+                    ]
+    """
+    kwargs.setdefault('kind','cubic')
+    kwargs.setdefault('debug',False)
+
+    #Puts Rough Position in increasing theta order
+    RoughPositions=sorted(RoughPositions, key=itemgetter(3))[::-1] 
+    RoughPositions=np.array(RoughPositions)
+    if kwargs['debug']:
+        print('RoughPositions: ',RoughPositions)
+
+    #thlist
+    if kwargs['debug']:
+        print('ths: ',thStart,thStop,thStep)
+    th=np.arange(np.max([thStart,thStop]),np.min([thStart,thStop])-1.0*abs(thStep),-1.0*abs(thStep),dtype=float)
+    if kwargs['debug']:
+        print('th: ',th)
+        
+    #interpolating
+    def func(th,th_col,m_col,**kwargs):
+        f=interp1d(th_col,m_col)
+        m=f(th)
+        return m
+    x=func(th,RoughPositions[:,3], RoughPositions[:,0])
+    y=func(th,RoughPositions[:,3], RoughPositions[:,1])
+    z=func(th,RoughPositions[:,3], RoughPositions[:,2])
+    chi=func(th,RoughPositions[:,3], RoughPositions[:,4])
+    phi=func(th,RoughPositions[:,3], RoughPositions[:,5])
+
+    return x,y,z,th,chi,phi
+
+def mvth_interp(RoughPositions, thVal,**kwargs):
+    """
+    Moves to the interpolated position for a give theta and RoughPosition list
+    uses interpRoughPositions
+    """
+    x,y,z,th,chi,phi=interpRoughPositions(RoughPositions,thVal,thVal-.1,1,**kwargs)
+    Pos=[x[0],y[0],z[0],th[0],chi[0],phi[0]]
+    #print("Pos = ",Pos)
+    ARPES_mvsample(Pos)
+
+def scanEA_hv(hv_start_stop_step_lists,EAlist=[],**kwargs):    
+    """
+    triggers and EAscan for each photon energy in *hvs
+    
+    hv_start_stop_step_lists, listoflist ... see scanXAS for more info
+    
+    EAlist = 
+        Fixed Mode: EAlist=["KE/BE",CenterEnergy,PassEnergy,Frames,Sweeps] (5)
+        Swept Mode: EAlist=["KE/BE",StartEnergy,StopEnergy,StepEnergy,PassEnergy,Frames,Sweeps] (7)
+        Baby Sweep (dither): EAlist=["KE"/"BE",CenterEnergy,PassEnergy,Frames,Sweeps,"BS"] (6)
+            KE => Auger
+            BE => Core levels
+            (+) BE is positive below Ef
+            (-) BE is negative above Ef
+   
+    usage:
+        scanEA_hv([400,500,1200],EAlist=["BE",-5,200,17*60,1])
+        NOTE that EAlist = needs to be written explicitly
+        
+    **kwargs
+        execute: True/False to start the scan => True (default)
+        debug: default => False
+
+        (Note: scan_dim=2 is hardcoded for photon energy) 
+        
+    """
+    kwargs.setdefault("average",None)
+    kwargs.setdefault("execute",True)
+    kwargs.setdefault("debug",False)
+
+    if(kwargs['debug']):
+        print('EAlist: ',EAlist)
+
+    #setting up EA
+    EAkwargs={
+    'execute':False,
+    'scan_dim':1
+    }
+    EAparms=scanEA(EAlist,**EAkwargs)
+
+    scanGo = kwargs['execute']
+    #Setting up the ScanRecord for Mono and ID in Table mode
+    kwargs["scan_dim"]=2
+    kwargs["execute"]=False
+    mono_array,ID_array = BL_energy_tables(hv_start_stop_step_lists)
+    scanXAS_BL(hv_start_stop_step_lists,**kwargs)
+   
+    if scanGo == True:
+        #Setting the beamline energy to the first point, and EA at first KE
+        energy(mono_array[0])
+        #Scanning            
+        EA.put(mono_array[0]-EAlist[1],EAparms['PassEnergy'],LensMode="Angular",Frames=EAparms['Frames'],**kwargs)
+        mda.go(**kwargs)
+        #After scan
+        scanEA_reset(**kwargs)
+        mda.table_reset_after(**kwargs)
+
+def scanEA_y(EAlist, start,stop,step,mode='absolute',**kwargs):
+    scanEA_motor(EAlist,'y',start,stop,step,mode=mode,**kwargs)
+
+def scanEA_z(EAlist, start,stop,step,mode='absolute',**kwargs):
+    scanEA_motor(EAlist,'z',start,stop,step,mode=mode,**kwargs)
+
+    
+def scanEA_motor(EAlist, motor,start,stop,step,mode='absolute',**kwargs):
+    """
+    scans an ARPES motor (scan_dim=2) while triggering the EA (scan_dim=1)
+       
+    EAlist = 
+        Fixed Mode:["BE",CenterEnergy,PassEnergy,Frames,Sweeps] (5)
+        Swept Mode:["BE",StartEnergy,StopEnergy,StepEnergy,PassEnergy,Frames,Sweeps] (7)
+        Baby Sweep (dither):["KE"/"BE",CenterEnergy,PassEnergy,Frames,Sweeps,"BS"] (6)
+
+            (+) BE is positive below Ef
+            (-) BE is negative above Ef
+        
+    **kwargs
+        execute: True/False to start the scan => True (default)
+        debug=False
+        (Note: scan_dim=2 is hardcoded) 
+   """
+    kwargs.setdefault("execute",True)
+    kwargs.setdefault("debug",False)
+    
+    #setting up EA
+    EAkwargs={
+    'execute':False,
+    'scan_dim':1
+    }
+    EAparms=scanEA(EAlist,**EAkwargs)
+    
+    #Setting up the ScanRecord for motor scans
+    scan_dim=2 #hard coded
+    kwargs.update({'scan_dim':scan_dim})
+
+    ARPES_motor_scan(motor,start,stop,step,**kwargs)
+    
+    if kwargs['debug']:
+        print("ScanGo scan_dim = ",scan_dim)
+    
+    if kwargs["execute"]==True:
+        #Scanning            
+        EA.put(EAlist[1],EAparms['PassEnergy'],LensMode="Angular",Frames=EAparms['Frames'],**kwargs)
+        BL.mda.go(kwargs["scanIOC"],scan_dim)
+        EA_log_update()
+        #After scan
+        scanEA_reset(**kwargs)
+
+def scanEA_Mesh(EAlist,y_start_stop_step,z_start_stop_step,**kwargs):
+    """
+    2D scan mesh (y/z) while triggering the EA: scan_dim=1
+    y_start_stop_step=[start1,stop1,step1] #y: scan_dim=2
+    z_start_stop_step=[start2,stop2,step2] #z: scan_dim=3
+    
+       
+    EAlist = 
+        Fixed Mode:["BE",CenterEnergy,PassEnergy,Frames,Sweeps] (5)
+        Swept Mode:["BE",StartEnergy,StopEnergy,StepEnergy,PassEnergy,Frames,Sweeps] (7)
+        Baby Sweep (dither):["KE"/"BE",CenterEnergy,PassEnergy,Frames,Sweeps,"BS"] (6)
+1205
+            (+) BE is positive below Ef
+            (-) BE is negative above Ef
+        
+    **kwargs
+        execute: True/False to start the scan => True (default)
+        debug=False
+        (Note: scan_dims are hardcoded) 
+   """
+    kwargs.setdefault("execute",True)
+    kwargs.setdefault("debug",False)
+    
+    #setting up EA
+    EAkwargs={
+    'execute':False,
+    'scan_dim':1
+    }
+    EAparms=scanEA(EAlist,**EAkwargs)
+
+    #Setting up the ScanRecord for motor scans
+    outer_scan_dim=3 #hard coded 
+    inner_loop_list = y_start_stop_step.insert(0,"y")
+    outer_loop_list = z_start_stop_step.insert(0,"z")
+    ARPES_scan_2D(inner_loop_list,outer_loop_list,outer_scan_dim,**kwargs)
+    
+    if kwargs['debug']:
+        print("ScanGo scan_dim = ",outer_scan_dim)
+
+    if kwargs['execute']:
+        #Scanning            
+        EA.put(EAlist[1],EAparms['PassEnergy'],LensMode="Angular",Frames=EAparms['Frames'],**kwargs)
+        mda.go(scan_dim=outer_scan_dim)
+        EA_log_update()
+
+        #After scan
+        scanEA_reset(**kwargs)
+
+        
+        
+        
+    
+def hv2kz(lattice,V0,hv):
+    """
+    Converts a hv value for the nth zone had returns corresponding kz values 
+    [0]for zone  boundary and [1] for zone center in inverse angstroms
+    lattice = c; assuming kz orthoganal to a-b plane (i.e. 2np.pi/c = GZ distance)
+    and at zone center (kx,ky)=0 /cos(th=0)=1
+    V0 = the inner potential
+    """
+    work_fct=EA.wk
+    Ek=hv-work_fct
+    k_z=0.5124*np.sqrt(Ek+V0)    # Kz at (kx,ky)=0 i.e. cos(th)=1
+    c_star=2*np.pi/lattice    # 2pi/c = GZ distance
+    GZ_n=round((k_z/c_star*2),2)
+    G_n=round((k_z/c_star),2)
+    print("  kz = "+str(round(k_z,2))+" A^(-1) = " +str(GZ_n)+" * pi/c = " +str(G_n)+" * 2pi/c")
+    return GZ_n,G_n
+    
+def kz2hv(lattice,V0,n):
+    """
+    Converts a kz value for the nth zone had returns corresponding hv
+    lattice = c; assuming kz orthoganal to a-b plane (i.e. 2pi/c = GZ distance)
+    and at zone center (kx,ky)=0 /cos(th=0)=1
+    V0 = the inner potential
+    """
+    work_fct=EA.wk
+    c_star=2*np.pi/lattice        # 2pi/c = GZ distance
+    Ek=(n*c_star/0.5124)**2-V0    # Ek at (kx,ky)=0 i.e. cos(th)=1
+    hv=Ek+work_fct
+    mono=round(hv,1)
+    print("\n")
+    print("  hv = Ek + Phi = "+str(round(hv,2))+" eV")
+    print("  kz = n*2pi/c   with  n = "+str(n))
+    return mono
+
+
+def Print_Gamma_n(lattice,V0,n1,n2):
+    work_fct=EA.wk
+    c_star=2*np.pi/lattice                # 2pi/c = GZ distance
+    for n in range(n1,n2+1,1):
+        Ek_Gn=(n*c_star/0.5124)**2-V0        # Ek at G
+        Ek_Zn=((n+0.5)*c_star/0.5124)**2-V0    # Ek at Z
+        hv_Gn=round(Ek_Gn+work_fct,2)
+        hv_Zn=round(Ek_Zn+work_fct,2)
+        print("\n G["+str(n)+"]:  hv = Ek + Phi = "+str(round(hv_Gn,2))+" eV ")
+        print(" Z["+str(n)+"]:  hv = Ek + Phi = "+str(round(hv_Zn,2))+" eV")
+
+def Print_Gamma_hv(lattice,V0,hv1,hv2):
+    work_fct=EA.wk
+    c_star=2*np.pi/lattice                # 2pi/c = GZ distance
+    Ek1=hv1-work_fct
+    Ek2=hv2-work_fct
+    k_z1=0.5124*np.sqrt(Ek1+V0)    # Kz at (kx,ky)=0 i.e. cos(th)=1
+    k_z2=0.5124*np.sqrt(Ek2+V0)    # Kz at (kx,ky)=0 i.e. cos(th)=1
+    GZ_n1=round((k_z1/c_star*2),1)
+    G_n1=round((k_z1/c_star),1)
+    GZ_n2=round((k_z2/c_star*2),1)
+    G_n2=round((k_z2/c_star),1)
+    if modf(G_n1)[0]>=0.5:
+        n1=modf(G_n1)[1]+1,0
+    else:
+        n1=modf(G_n1)[1]
+    n2=modf(G_n2)[1]
+    print("\n hv1 = "+str(hv1)+" eV:  " +str(GZ_n1)+" * pi/c = " +str(G_n1)+" * 2pi/c")
+    if type(n1) == tuple: n1 = n1[0]
+    if type(n2) == tuple: n2 = n2[0]
+    Print_Gamma_n(lattice,V0,n1,n2)
+    print("\n hv2 = "+str(hv2)+" eV:  " +str(GZ_n2)+" * pi/c = " +str(G_n2)+" * 2pi/c")
+    return n1,n2
+
+def kx2deg(lattice,hv):
+    a=np.pi/lattice
+    b=0.5124*np.sqrt(hv)
+    c=a/b
+    theta_rad=np.asin(c)
+    theta_deg=rad2deg(theta_rad)
+    print(" 1/2-BZ (GX) = "+str(round(theta_deg,1))+" deg")
+    
+def resolution_EA(PE,slit_SES):    # updated 10/30/17: straight slits scaled to slit width not area
+    SES_Table={}
+    SES_Table[2]   = {1: 1.6, 2:2,   3:2,   4:4,   5:4,   6:6,    7:12,   8:20,   9:32}
+    SES_Table[5]   = {1: 2.7, 2:4,   3:4,   4:7,   5:7,   6:11,   7:20,   8:34,   9:54}
+    SES_Table[10]  = {1: 5.7, 2:9,   3:9,   4:14,  5:14,  6:23,   7:43,   8:71,   9:114}
+    SES_Table[20]  = {1:10.8, 2:16,  3:16,  4:27,  5:27,  6:43,   7:81,   8:135,  9:216}
+    SES_Table[50]  = {1:34.6, 2:52,  3:52,  4:87,  5:87,  6:138,  7:260,  8:433,  9:692}
+    SES_Table[100] = {1:49.5, 2:74,  3:74,  4:124, 5:124, 6:198,  7:371,  8:619,  9:990}
+    SES_Table[200] = {1:88.9, 2:133, 3:133, 4:222, 5:222, 6:356,  7:667,  8:1111, 9:1778}
+    SES_Table[500] = {1:250,  2:375, 3:375, 4:625, 5:625, 6:1000, 7:1875, 8:3125, 9:5000}
+    try:
+        SES=SES_Table[PE][slit_SES]
+    except KeyError:
+        print("WARNING: Not a valid PE/Slit combination")
+        SES=0
+    return SES
+
+
+def SES_slit(val):
+    """
+    Set the Scienta Slit
+    val    w_mm    l_mm    Shape
+    1    0.2        25    Curved
+    2    0.3        30    Straight
+    3    0.3        25    Curved
+    4    0.5        30    Straight
+    5    0.5        25    Curved
+    6    0.8        25    Curved
+    7    1.5        30    Straight
+    8    2.5        30    Straight
+    8.5            open apperture
+    9    4.0        30    Straight    
+    """
+    caput("29idc:m8.VAL",val,wait=True,timeout=18000)
+
+
diff --git a/build/lib/iexcode/instruments/encoders.py b/build/lib/iexcode/instruments/encoders.py
new file mode 100644
index 0000000000000000000000000000000000000000..ef7cb08aceb1e1e7a0ec92ecf5915498cdf357bf
--- /dev/null
+++ b/build/lib/iexcode/instruments/encoders.py
@@ -0,0 +1,62 @@
+from epics import caput,caget
+
+def encoder_dictionary_entry(name):
+    """
+    returns a dictionary with the encoder pvs
+    encoder_dictionary_entry(name) = encoder_ioc, motor_ioc, encoder_list
+
+    """
+    d={
+        'slit2B':("29idMini1:",[13,14,15,16]),
+        'slit3D':("29idMini2:",[26,27]),
+        'ARPES':("ARPES:",[1,2,3,4]),
+    }
+    return d[name]
+
+def encoder_sync(name):
+    """
+    sync all the encoders for name
+    """
+    encoder_ioc, motor_ioc, encoder_list = encoder_dictionary_entry(name)
+    for encoder_num in encoder_list:
+        pv = motor_ioc+":m"+str(encoder_num)+".SYNC"
+        caput(pv,1)
+
+def encoders_reset(name,Hcenter,Vcenter):
+    """
+    Resetting Slit 2B encoders to 0 for a given position (Hcenter,Vcenter).
+    Slit size need to be set to 0.
+
+    Previously: Reset_Slit2B_Encoders
+    """
+    encoder_sync('name')  
+    encoder_ioc, motor_ioc, encoder_list = encoder_dictionary_entry(name)
+
+    print('\nCurrent Position:')
+    for e_num in encoder_list:
+        pv = encoder_ioc+'e'+(e_num)+'Pos'
+        print('e'+(e_num)+' = '+str(caget(pv)))
+    
+    print('\nSetting all Offsets to 0:')
+    for e_num in encoder_list:
+        pv = encoder_ioc+'e'+(e_num)+'Pos.EOFF'
+        caput(pv,0)
+    
+    print('\nCurrent Position:')
+    for e_num in encoder_list:
+        pv = encoder_ioc+'e'+(e_num)+'Pos'
+        print('e'+(e_num)+' = '+str(caget(pv)))
+
+    print('\nSetting back Offsets:')
+    for e_num in encoder_list:
+        pos_pv = encoder_ioc+'e'+(e_num)+'Pos' 
+        offset_pv = encoder_ioc+'e'+(e_num)+'Pos.EOFF' 
+        caput(offset_pv,-caget(pos_pv))
+
+    print('\nCurrent Position:')
+    for e_num in encoder_list:
+        pv = encoder_ioc+'e'+(e_num)+'Pos'
+        print('e'+(e_num)+' = '+str(caget(pv)))
+
+    encoder_sync(name)
+    print('sync '+name)
diff --git a/build/lib/iexcode/instruments/files_and_folders.py b/build/lib/iexcode/instruments/files_and_folders.py
new file mode 100644
index 0000000000000000000000000000000000000000..9710c1bd6907b1f7340147aad3a073d28daf1c82
--- /dev/null
+++ b/build/lib/iexcode/instruments/files_and_folders.py
@@ -0,0 +1,268 @@
+from os import listdir,mkdir,chmod
+from os.path import join, isfile, exists
+import datetime
+from time import sleep
+import re
+
+from epics import caget, caput
+
+
+##############################################################################################################
+################################             Standard Paths              ##############################
+##############################################################################################################
+
+
+path_User_Folders='/home/beams/29IDUSER/Documents/User_Folders/'
+
+def path_dserv(folder,run,user_name):
+    """
+    Returns the path to a user folder
+            dataFolder='/net/s29data/export/data_29id'+folder+'/'+run+'/'+user_name
+
+    previously: _userDataFolder
+    """
+                    
+    dataFolder='/net/s29data/export/data_29id'+folder+'/'+run+'/'+user_name
+    return dataFolder
+
+
+
+
+
+
+
+##############################################################################################################
+################################                     Folders                    ##############################
+##############################################################################################################
+def check_run():
+    """
+    gets the current date and determines the run number from that
+    run = year_cycle
+        cycle 1 => Jan - April
+        cycle 2 => May - September
+        cycle 1 => October - December
+
+    previously: Check_run
+    """
+    todays_date = datetime.date.today()
+
+    date1 = ( 1, 1)   # start date run_1
+    date2 = ( 5, 1)   # start date run_2
+    date3 = (10, 1)   # start date run_3
+
+    datex = (todays_date.month,todays_date.day)
+
+    if date1 <= datex < date2:
+        run=str(todays_date.year)+'_1'
+    elif date2 <= datex < date3:
+        run=str(todays_date.year)+'_2'
+    else:
+        run=str(todays_date.year)+'_3'
+
+    return(run)
+
+def make_ftp(folder,run,user_name):
+    """
+    Creates the folders on kip (ftp server) and prints what is needed for the cronjob
+
+    folder = 'c' /'d'
+
+    Previously: was part of Make_DataFolder
+    """
+    crontime={
+        'mda2ascii':'0,30 * * * * ',
+        'chmod':'1,31 * * * * ',
+        'data_other':'2,32 * * * * ',
+        'notebook':'*/3 * * * * ',
+        }
+
+    #making the crontab text
+    print('-------------------------------------------------------------')
+    #mda2ascii
+    MyPath_kip_run='/net/kip/sftp/pub/29id'+folder+'ftp/files/'+run+'/'
+    MyPath_kip='/net/kip/sftp/pub/29id'+folder+'ftp/files/'+run+'/'+user_name+'/'
+    cmd_mda2ascii=crontime['mda2ascii']+' /net/s29dserv/APSshare/bin/mda2ascii -d '+MyPath_kip+'ascii '+MyPath_kip+'mda/*.mda'
+    print(cmd_mda2ascii)
+    #chmode
+    cmd_chmod=crontime['chmod']+' chmod 664  '+MyPath_kip+'ascii/*.asc'
+    print(cmd_chmod)
+    #notebooks
+    cmd_notebook=crontime['notebook']+' /usr/bin/rsync -av --exclude=core /home/beams22/29IDUSER/Documents/User_Folders/'+user_name+'/* kip:'+MyPath_kip+'notebook >  /home/beams22/29ID/cronfiles/cptoftp-currrun-d-User.log 2>&1'
+    print(cmd_notebook)
+    print('-------------------------------------------------------------\n\n')
+    
+    #making folders 
+    print("\n\n")
+    print(MyPath_kip)
+    print(MyPath_kip+"ascii")
+    if not (exists(MyPath_kip_run)):
+        mkdir(MyPath_kip_run)
+        chmod(MyPath_kip_run, 0o775)
+    if not (exists(MyPath_kip)):
+        mkdir(MyPath_kip)
+        chmod(MyPath_kip, 0o775)
+    if not (exists(MyPath_kip+"ascii")):
+        mkdir(MyPath_kip+'ascii')
+        chmod(MyPath_kip+'ascii', 0o775)
+    if not (exists(MyPath_kip+"notebook")):
+        mkdir(MyPath_kip+"notebook")
+        chmod(MyPath_kip+"notebook", 0o775)
+    
+def make_user_folders(run,folder,user_name,endstation_name,ftp=False):
+    """
+    if user_name is not a folder in path_User_Folders, then it creates a new folder
+    
+    if ftp = True / False (default) creates the folders on kip (ftp server) and modifies the cronjob
+    
+    previously: Make_DataFolder
+    """
+    
+    if (folder == 'c'or folder == 'd'):
+       if ftp:
+            make_ftp(folder,run,user_name)
+    else:
+            print("To create ftp folders & update contrab, you need to run the following as 29id:")
+            print("\tFolder_"+str(endstation_name)+"('"+str(run)+"','"+str(user_name)+"',ftp=True)") 
+
+        #create user folder for saving log files
+    path_user=join(path_User_Folders,user_name)
+    user_name = "/"+user_name
+    if not (exists(path_user)):
+        mkdir(path_user)
+
+
+def folder_mda(run,folder,user_name,file_prefix,ioc,verbose=True):
+    """
+    sets the folder, prefix and file number for the scan record
+    ioc is the full ioc, e.g. '29idb', or '29idARPES'
+
+    For Staff: folder='b', user_name=''
+    For ARPES: folder ='c'
+    For Kappa: folder = 'd'
+
+    mda_path="/net/s29data/export/data_29id"+folder+"/"+run+"/"+user_name+"mda"
+    """
+    
+    if user_name == 'Staff':
+        user_name=""
+    else:
+        user_name=user_name+"/"
+
+    mda_path="/net/s29data/export/data_29id"+folder+"/"+run+"/"+user_name+"/mda"
+    print("\nMDA folder: " + mda_path)
+    if not (exists(mda_path)):
+        mkdir(mda_path)
+        FileNumber=1
+    else:
+        FileNumber=get_next_fileNumber(mda_path,file_prefix)
+
+    if ioc in ['29idb','29idc','29idd']: #VME iocs
+        caput(ioc+"saveData_fileSystem","//s29data/export/data_29id"+folder+"/"+run)
+        sleep(0.25)
+        caput(ioc+"saveData_subDir",user_name+"mda")
+
+    else: #soft iocs
+        caput(ioc+"saveData_fileSystem","/net/s29data/export/data_29id"+folder+"/"+run)
+        sleep(0.25) #needed so that it has time to write        
+        caput(ioc+"saveData_subDir","/"+user_name+"mda")
+
+    caput(ioc+"saveData_baseName",file_prefix+"_")
+    caput(ioc+"saveData_scanNumber",FileNumber)
+
+    print("\nioc set to:", ioc)
+    sleep(5)
+
+    if verbose:
+        SaveStatus=caget(ioc+'saveData_status',as_string=True)
+        SaveMessage=caget(ioc+'saveData_message',as_string=True)
+        print("\nSave Status "+ioc+": "+SaveStatus+" - "+SaveMessage)
+       
+
+def folder_SPEC(run,folder,user_name):
+    if folder == "b":
+        user_name = "Staff"
+    else:
+        user_name = user_name+"/"
+    MyPath="/home/beams22/29IDUSER/spec/data/"+run+"/"+user_name
+    print("\nSPEC folder: " + MyPath)
+    print("You will need to create folder and set up the path manually in SPEC:")
+    print("    cd "+MyPath)
+    print("    newfile FileName")
+    print("To start SPEC fresh: ./bin/kappa29ID -f")
+    #if not (exists(MyPath)):
+    #    mkdir(MyPath)
+
+
+def folder_MPA(run,folder,user_name,file_prefix="mpa"):
+    if folder == "b":
+        windows_ioc = "X"
+        user_name = ""
+        windows_path = windows_ioc+':\\'+run+"\\mpa"
+    else:
+        windowsIOC = "Z"
+        user_name = user_name+"/"
+        windows_path=windows_ioc+':\\'+run+"\\"+user_name[:-1]+"\\mpa"
+    mpa_path="/net/s29data/export/data_29id"+folder+"/"+run+"/"+user_name+"mpa"
+    print("\nMPA folder: " + mpa_path)
+    if not (exists(mpa_path)):
+        mkdir(mpa_path)
+        FileNumber=1
+    else:
+        FileNumber=get_next_fileNumber(mpa_path,file_prefix)
+    caput("29iddMPA:det1:MPAFilename",windows_ioc+":/"+run+"/"+user_name+"mpa/mpa_")
+
+    save_plugin='TIFF1'
+    caput("29iddMPA:"+save_plugin+":FilePath",windows_path)
+    print("\nMPA folder on Crabby: "+windows_path)
+    caput("29iddMPA:"+save_plugin+":FileName",file_prefix)
+    caput("29iddMPA:"+save_plugin+":FileNumber",FileNumber)
+
+def _filename_key(filename):
+    return (len(filename), filename)
+
+def get_next_fileNumber(data_dir, file_prefix,**kwargs):
+    """
+    gets the next file number for the pattern 
+    data_dir/file_prefix_filenum
+    
+    kwargs:
+        debug = False (default); if True then print lo
+        q = True (default); if False then prints next file number
+
+    Previously: getNextFileNumber
+    """
+    kwargs.setdefault("debug",False)
+    kwargs.setdefault("q",True)
+    
+    onlyfiles = [f for f in listdir(data_dir) if isfile(join(data_dir, f)) and f[:len(file_prefix)] == file_prefix]
+    sortedfiles = sorted(onlyfiles, key=_filename_key)
+    pattern = re.compile('(.*)_(.*)\.(.*)')
+    try:
+        lastFile = sortedfiles[-1]
+    except IndexError as errObj:
+        nextFileNumber = 1
+        if kwargs["debug"]:
+            print("Data directory = ", data_dir)
+            print("File prefix =", file_prefix)
+            print("File number =", None)
+            print("File extension =", "TBD")
+            print("Next File number =", nextFileNumber)
+    else:
+        matchObj = pattern.match(lastFile)
+        nextFileNumber = int(matchObj.group(2)) + 1
+        if kwargs["debug"]:
+            print("Data directory = ", data_dir)
+            print("File prefix =", matchObj.group(1))
+            print("File number =", matchObj.group(2))
+            print("File extension =", matchObj.group(3))
+            print("Next File number =", nextFileNumber)
+    if kwargs["q"] == False:
+        print("Next File Number: ",nextFileNumber)
+    return nextFileNumber
+
+
+
+
+
+
+
diff --git a/build/lib/iexcode/instruments/gate_valves.py b/build/lib/iexcode/instruments/gate_valves.py
new file mode 100644
index 0000000000000000000000000000000000000000..1e122c526975534f743216fa16ae2f089094db2d
--- /dev/null
+++ b/build/lib/iexcode/instruments/gate_valves.py
@@ -0,0 +1,35 @@
+from epics import caget, caput
+
+def branch_valves():
+    """
+    returns a dictionary of the gate valves for a given branch
+
+    used by close_valve and safe_state
+    """
+    
+    GVs={
+        'c':('GV10'),
+        'd':('GV14'),
+        'e':()
+        }
+    return GVs
+    
+def valve_close(GV, verbose=True):
+    """
+    closes the gate valve ('GV10', 'GV14'), EPS nomenclature
+
+    Previously: Close_DValve,Close_DValve
+    """
+    caput("29id:BLEPS:"+GV+":CLOSE.VAL",1,wait=True,timeout=18000)
+    if verbose:
+        print("Closing gate valve: "+GV+"...")
+
+def valve_open(GV, verbose=True):
+    """
+    closes the gate valve ('GV10', 'GV14'), EPS nomenclature
+
+    Previously: Close_DValve,Close_DValve
+    """
+    caput("29id:BLEPS:"+GV+":OPEN.VAL",1,wait=True,timeout=18000)
+    if verbose:
+        print("Opening gate valve: "+GV+"...")
\ No newline at end of file
diff --git a/build/lib/iexcode/instruments/hxp_mirrors.py b/build/lib/iexcode/instruments/hxp_mirrors.py
new file mode 100644
index 0000000000000000000000000000000000000000..0eb90509f2784ff042fbcb4ef78235ec102d02fd
--- /dev/null
+++ b/build/lib/iexcode/instruments/hxp_mirrors.py
@@ -0,0 +1,64 @@
+from re import M
+from epics import caput, caget
+from iexcode.instruments.utilities import print_warning_message
+from iexcode.instruments.m3r import m3r_branch
+
+def hxp_ioc(mirror_name):
+    """
+    returns the ioc for a given 
+    mirror_name: 'm3a' / 'm4a' / 'm4r'
+    """
+    hxp_namelist={
+        'm4r':'hxp2',
+        'm3a':'hxp1',
+        'm4a':'hxp3',
+    }
+    if mirror_name not in hxp_namelist:
+        print("not a valid mirror name ("+list(hxp_namelist.keys())+")")
+    else:
+        ioc = '29idHXP:'+hxp_namelist[mirror_name]+":"
+        return ioc
+
+
+def HXP_synch(mirror_name):
+    """
+    synchs the rbv and sp for all axes
+
+    mirror_name: 'm3a' / 'm4a' / 'm4r'
+
+    Previously: Sync_m4r
+    """
+    pv = hxp_ioc(mirror_name)
+    try:
+        for m in range(1,7):
+            caput(pv+'m'+str(m)+'.SYNC',1) 
+    except:
+        print_warning_message("Check if ioc is running")
+                
+            
+def hxp_print(mirror_name):
+    """
+
+    Previously: Get_HXP
+    """
+    pv = hxp_ioc(mirror_name)
+ 
+    Tx=caget(pv+"m1.RBV")
+    Ty=caget(pv+"m2.RBV")
+    Tz=caget(pv+"m3.RBV")
+    Rx=caget(pv+"m4.RBV")
+    Ry=caget(pv+"m5.RBV")
+    Rz=caget(pv+"m6.RBV")
+    print("\n"+mirror_name+" @ "+"%.3f" % Tx, "/","%.3f" % Ty, "/","%.3f" % Tz, "/","%.3f" % Rx, "/","%.3f" % Ry, "/","%.3f" % Rz)
+
+def hxp_get():
+    """
+
+    Previously: Get_HXP
+    """
+    branch = m3r_branch()
+    if branch == 'c':
+        hxp_print('m3a')
+        hxp_print('m4a')
+    else:
+         hxp_print('m4r')
\ No newline at end of file
diff --git a/build/lib/iexcode/instruments/logfile.py b/build/lib/iexcode/instruments/logfile.py
new file mode 100644
index 0000000000000000000000000000000000000000..dec2ce2547f2096f5ebeda2597e496a1723b44d4
--- /dev/null
+++ b/build/lib/iexcode/instruments/logfile.py
@@ -0,0 +1,169 @@
+from os.path import join,isfile
+
+from epics import caget, caput
+from iexcode.instruments.IEX_endstations import *
+from iexcode.instruments.utilities import today
+from iexcode.instruments.ARPES import ARPES_log_entries
+from iexcode.instruments.Kappa import Kappa_log_entries
+
+
+##############################################################################################################
+##############################             logging           ##############################
+##############################################################################################################
+def log_print(**kwargs):
+    """
+    prints a comment to the logfile
+    """
+    logfile_print(BL.endstation_name,BL.ioc,kwargs['comment'])
+
+def log_update():
+    """
+    updates the log file with the last scan info
+    """
+    if BL.endstation_name == 'ARPES':
+        entry_list,pv_list, format_list = ARPES_log_entries()
+    elif BL.endstation_name == 'Kappa':
+        entry_list,pv_list, format_list = Kappa_log_entries()
+    logfile_update(BL.endstation_name,BL.ioc,entry_list,pv_list,format_list)
+
+
+##############################################################################################################
+##############################            general   logfile functions          ##############################
+##############################################################################################################
+
+
+def logfile_name_pv(endstation_name):
+    """
+    Dictionary to get the PV in which the FileName for logging is stored
+    
+    endstation: 'ARPES' / 'Kappa' / 'Test
+
+    Previously: logname_pv
+    """
+    pv_dict={
+        'Test':'29idb:userStringSeq10.STR1',
+        'ARPES':'29idb:userStringSeq10.STR2',
+        'Kappa':'29idb:userStringSeq10.STR3',
+        'RSoXS':'29idb:userStringSeq10.STR4',
+        }
+    if endstation_name in pv_dict.keys():
+        pv=pv_dict[endstation_name]
+    else:
+        pv='29idb:userStringSeq10.STR10'
+    return pv
+
+def logfile_name_set(endstation_name,**kwargs):
+    """
+    Sets the string used for the FileName in scanlog and EAlog
+    uses logname_PV to reference PV associated with a particular ioc
+    **kwargs:
+        filename = to set a specific filename, default => YYYYMMDD_log.txt
+
+    Previously: logname_set
+    """
+    kwargs.setdefault('filename_suffix','_log')
+    kwargs.setdefault('filename',today()+kwargs['filename_suffix']+'.txt')
+
+    filename = kwargs['filename']
+
+    try:
+        caput(logfile_name_pv(endstation_name),filename)
+        print("\nLog filename = \'"+filename+"\' @ "+logfile_name_pv(endstation_name))
+        print('To change filename, use logname_set(endstation_name,new_name)')
+    except:
+        print("Error: was not able to set the filename, check that 29idb ioc is running")
+
+        
+def logfile_name_get(endstation_name):
+    """
+    Gets the string used for the FileName in scanlog and EAlog for the given scanIOC.
+
+    Previously: logname
+    """
+
+    return caget(logfile_name_pv(endstation_name))
+       
+def logfile_fpath(endstation_name,mda_ioc):
+    """
+    returns the full path to the logfile based on the current user in the mda scanRecord
+
+
+    Previously: logname, logname_generate
+    """
+ 
+    try: 
+        filename = logfile_name_get(endstation_name)
+        user_name = BL.mda.scanRecord_user(mda_ioc)
+        fpath_with_subfolder = join(user_name,filename)
+    except:
+        fpath_with_subfolder = "logfile.txt"
+        print("Couldn't read log file path, using: "+fpath_with_subfolder)
+        
+    return fpath_with_subfolder
+
+
+def logfile_print(endstation_name,mda_ioc,comment=''):
+    """
+    Writes comments to the logfile on a new line
+    comment is a string of what you want to add to the file 
+        e.g. comment = "------- New Sample--------"
+    
+    Previously: logprint
+    """
+
+    logfile_name = logfile_name_get(endstation_name)
+    
+    try:
+        fpath_with_subfolder=logfile_fpath(endstation_name,mda_ioc) 
+        if not isfile(fpath_with_subfolder):
+            logfile_header(fpath_with_subfolder,entry=None)
+        with open(fpath_with_subfolder,'a') as myfile:
+            myfile.write(comment)
+            myfile.write('\n')
+        #print(comment,FileNameWithSubFolder)
+    except:
+        print("Logprint failed")
+
+
+def logfile_header(endstation_name,mda_ioc,header_list): 
+    """
+    file path = path to where file_name lives
+    file_name = name of the logfile
+    entry is a list
+
+    Previously: SaveFile_Header
+    """  
+    version = '1.4'
+
+    fpath_with_subfolder=logfile_fpath(endstation_name,mda_ioc) 
+    with open(fpath_with_subfolder, "w+") as f:
+        f.write('@Log version: '+ version+'\n\n')
+        file_path  = BL.mda.scanRecord_filepath(mda_ioc)
+        f.write('FilePath '+endstation_name+': '+file_path+'\n')
+
+        for key in header_list.keys():
+            f.write(key+' Header:  '+ header_list[key]+'\n\n')
+
+
+   
+def logfile_update(endstation_name,mda_ioc,entry_list,pv_list,format_list):
+    """ 
+    To be used for scanlog and scanEA functions.
+    Update SaveFile_Header version number when changing the structure of the file (indexing).
+
+    Previously: SaveFile
+    """
+    fpath_with_subfolder=logfile_fpath(endstation_name,mda_ioc) 
+    
+    if not isfile(fpath_with_subfolder):
+        logfile_header(endstation_name,mda_ioc,entry_list)
+
+    with open(fpath_with_subfolder, "a+") as f:
+        for i in range(len(format_list)):
+            pv_format = "{0:"+format_list[i]+"},"
+            f.write(pv_format.format(pv_list[i]))
+        last_entry=len(format_list)-1
+        pv_format="{0:"+format_list[last_entry]+"}\n"
+        f.write(pv_format.format(pv_list[last_entry]))
+
+
diff --git a/build/lib/iexcode/instruments/m3r.py b/build/lib/iexcode/instruments/m3r.py
new file mode 100644
index 0000000000000000000000000000000000000000..54bb5ec77693a6857ce71dd5b87d6b4aeffd3386
--- /dev/null
+++ b/build/lib/iexcode/instruments/m3r.py
@@ -0,0 +1,126 @@
+from cgi import print_arguments
+
+from epics import caget, caput
+
+from iexcode.instruments.utilities import print_warning_message
+from iexcode.instruments.FMB_mirrors import *
+
+##############################################################################################################
+################################             M3R             ##############################
+##############################################################################################################
+M3R_RY_POS_SP_initial = -16.52
+M3R_camera = '29id_ps6:'
+M3R_cam1  = M3R_camera+"cam1:"
+M3R_stats = M3R_camera+"Stats1:"
+M3R_pitch = "29id_m3r:RY_MON"
+M3R_align_pv = "29idKappa:align_m3r:"
+
+##############################################################################################################
+################################             M3R  default positions           ##############################
+##############################################################################################################
+def m3r_get(verbose=True):    
+    position = FMB_mirror_get(3,verbose)
+    return position
+    
+def m3r_RY_pos_sp():
+    return M3R_RY_POS_SP_initial
+
+def m3r_RY_pos_sp_get():
+    RY_SP = caget('29id_m3r:RY_POS_SP')
+    return RY_SP
+
+def m3R_tweak (axis,val):
+    """
+        \"TX\" = lateral                 \"RX\" = Yaw
+        \"TY\" = vertical                \"RY\" = Pitch
+        \"TZ\" = longitudinal            \"RZ\" = Roll
+
+    Previously: Tweak_M3R
+    """
+    mirror_num = 3
+    FMB_mirror_tweak(mirror_num,axis,val,verbose=True)
+
+def m3r_tweak_pitch(sign,val=0.005):
+    """
+    Previously: Tweak_M3R_Pitch
+    """
+    axis="RY"
+    if sign == "+":
+        m3R_tweak(axis,val)
+    elif sign == "-":
+        m3R_tweak(axis,-val)
+
+
+def m3r_table(branch):   
+    """
+    Defines the positions used by switch_branch() form M3R
+    WARNING: branch_pv uses: D => (Tx <= 0) and (Ry < 0) - Make sure this remains true or change it
+    """
+    branch = branch.lower()
+    positions={
+        "c":[10,0,0,0,0,0],
+        "d":[-2.5,0,0,-13.955,-16.450,-5.15],
+        "e":[-2.000,0,0,-13.960,-16.614,-7.500] 
+    }
+    # d => optimized for MEG @ 500 eV on 2/29/def start
+    # e => 2018_3-- JM changed for RSoXS alignment max diode current
+
+    try:
+        position = positions[branch]
+    except KeyError:
+        print_warning_message("not a valid branch")
+        position = FMB_mirror_get(3,verbose=False)
+    return position
+
+def m3r_branch():
+    """
+    get which branch based on the mirror position and returns the branch
+    """
+    PV="29id_m3r:"
+    TX=caget(PV+"TX_MON")
+    if TX > 6:
+        branch = 'c'
+    elif TX < -1: 
+        branch = 'd'
+    else:
+        print('M3R is not in a default position')
+    return branch
+
+def m3r_switch_branch(branch):
+    """
+    switches the mirror to the position defined in m3r_table
+    """
+    position = m3r_table(branch)
+    FMB_mirror_move_all(3,position,verbose=False)
+    # Relax bellows by doing large Z translation:
+    FMB_mirror_move_all(3,"TY",5,verbose=False)
+    FMB_mirror_move_all(3,"TY",5,verbose=False)
+
+    FMB_mirror_get(3,verbose=True)
+
+##############################################################################################################
+################################             M3R alignment             ##############################
+##############################################################################################################
+
+def centroid(t=None,q=1): 
+    '''
+    Return position of centroid, sigma, m3r:RY (mirror pitch)
+    Optional argument t to set camera intergration time.
+    '''
+    if t is not None:
+        caput(M3R_cam1+'AcquireTime',t)
+    else:
+        t=caget(M3R_cam1+'AcquireTime')
+    position =  round(caget(M3R_stats+'CentroidX_RBV'),2)
+    sigma = round(caget(M3R_stats+'SigmaX_RBV'),2)
+    intensity = round(caget(M3R_stats+'CentroidTotal_RBV'),2)
+    m3rRY = round(caget(M3R_pitch),4)
+    if q != None:
+        print('(position, sigma, total intensity, integration time (s), mirror pitch):')
+    return position,sigma,intensity,t,m3rRY
+
+def m3r_align(pxl=None):
+    if pxl == None:
+        pxl = caget(M3R_align_pv+'desired_pixel')
+    caput(M3R_align_pv+'desired_pixel',pxl)
+    caput(M3R_align_pv+'startAlign',1,wait=True,timeout=180)
diff --git a/build/lib/iexcode/instruments/mpa.py b/build/lib/iexcode/instruments/mpa.py
new file mode 100644
index 0000000000000000000000000000000000000000..6408b462eb1ab840d591207d7a6d0ec37d3794d7
--- /dev/null
+++ b/build/lib/iexcode/instruments/mpa.py
@@ -0,0 +1,440 @@
+from time import sleep
+from os.path import dirname, join
+import socket
+
+from epics import caget, caput
+from iexcode.instruments.userCalcs import userCalcOut_clear,userStringSeq_clear
+from iexcode.instruments.Kappa import Kappa_motor_dictionary,Kappa_cts, mda
+from iexcode.instruments.AD_utilities import AD_ROI_setup
+from iexcode.instruments.scalers import scaler_cts
+from iexcode.instruments.scanRecord import *
+
+
+"""
+To do, get busy record in the mpa ioc, get user calcs in the mpa ioc
+
+
+"""
+##############################################################################################################
+##############################                PVs             ##############################
+##############################################################################################################
+mpa_pv = "29iddMPA:"
+mpaDet_pv = mpa_pv + "det1:"
+mpa_busy = "29idcScienta:mybusy2"
+userCalc_pv = "29idTest"
+DAC_pv = '29iddau1:dau1:011:DAC'
+max_HV = 2990
+ratio = 500
+tth_dLLM=13.73
+tth_dHLM=23.73
+
+
+def mpa_reset_pv():
+    """
+    returns the pv used for resetting the mpa
+    "writing a 1 resets"
+    """
+    return mpa_pv+'C1O'
+
+def mpa_on_off_pv():
+    """
+    returns the pv used for turning on/off  the mpa
+    on => caput 1
+    off => caput0
+    """
+    return mpa_pv+'C0O'
+
+def mpa_HV_pvs():
+    """
+    returns the pvs for the userCalcout which hold the pvs for the mpa high voltage
+    """
+    val_pv = "29idKappa:userCalcOut9.A"
+    rbv_pv ="29idKappa:userCalcOut10.OVAL"
+    return val_pv, rbv_pv
+
+##############################################################################################################
+##############################                HV Control              ##############################
+##############################################################################################################
+
+def mpa_HV_set(volt,verbose=True):
+    """
+    sets the high voltage for the mpa
+
+    Previously: MPA_HV_Set
+    """
+    val_pv, rbv_pv = mpa_HV_pvs()
+    volt=min(volt,2990)
+
+    caput(val_pv,volt,wait=True,timeout=18000)
+    sleep(1)
+    HV_rbv=caget(rbv_pv)
+
+    if verbose:
+        print("HV = "+str(HV_rbv)+" V")
+
+
+def mpa_HV_get():
+    """
+    sets the high voltage for the mpa
+    """
+    val_pv, rbv_pv = mpa_HV_pvs()
+
+    return caget(rbv_pv)
+
+
+def mpa_HV_on():
+    """
+    turns the mpa high voltage on
+
+    Previously: MPA_HV_ON
+    """
+    n_on=1
+    tth_pv = Kappa_motor_dictionary('tth')[3]
+    tth_dial = caget(tth_pv+'.DRBV')
+    if 13.73<= tth_dial <=23.73:
+        print('MPA OFF: detector in direct beam (-5 < tth for mcp < 5); move away before turning HV ON.')
+    else:
+        caput(mpa_reset_pv,1,wait=True,timeout=18000)
+        caput(mpa_reset_pv,0,wait=True,timeout=18000)
+        caput(mpa_on_off_pv,n_on,wait=True,timeout=18000)
+        print("MPA - HV On")
+
+def mpa_HV_off():
+    """
+    turns the mpa high voltage off
+
+    Previously: MPA_HV_OFF
+    """
+    n_off=0
+    caput(mpa_on_off_pv,wait=True,timeout=18000)
+    print("MPA - HV Off")
+
+
+def mpa_HV_reset():
+    """
+    resets the mpa high voltage
+
+    Previously: MPA_HV_Reset
+    """
+    caput(mpa_reset_pv,1)
+    print("MPA - Reset")
+    
+    
+def mpa_HV_scan(start=2400,stop=2990,step=10,**kwargs):
+    """
+
+    Previously: MPA_HV_scan
+    """
+    kwargs.setdefault('positioner_settling_time',1)
+    Kappa_cts(1)
+    val_pv, rbv_pv = mpa_HV_pvs()
+    mda.fillin(val_pv, rbv_pv,start,stop,step,**kwargs)
+    mda.go(**kwargs)
+
+##############################################################################################################
+##############################                MCP Scripts              ##############################
+##############################################################################################################
+def mpa_ROI_setup(ROI_num=1,xcenter=535,ycenter=539,xsize=50,ysize=50,binX=1,binY=1):  
+    """
+    usage:
+        center of MCP, roiNum = 1 => MPA_ROI_SetUp(1,535,539,50,50)
+        to set up all use: mpa_ROI_setup_all(xcenter,ycenter)
+    """
+    AD_ROI_setup('29iddMPA',ROI_num,xcenter,ycenter,xsize,ysize,binX,binY)
+    ROI_pv = mpa_pv+"ROI"+str(ROI_num)+':'
+    mpa_ROI_stats(ROI_num)
+    
+def mpa_ROI_setup_all(xcenter=535,ycenter=539):
+    """
+    setup up ROI 
+        1 => size = 50 x 50
+        2 => size = 100 x 100
+        3 => size = 150 x 150
+        4 => size = 200 x 200
+
+    """
+    mpa_ROI_setup(1,xcenter,ycenter,xsize=50,ysize=50)
+    mpa_ROI_setup(2,xcenter,ycenter,xsize=100,ysize=100)
+    mpa_ROI_setup(3,xcenter,ycenter,xsize=150,ysize=150)
+    mpa_ROI_setup(4,xcenter,ycenter,xsize=200,ysize=200)
+    
+    
+def mpa_ROI_stats(ROI_num):
+    """
+    sequence to enable stats for mpa ROI
+    """
+    ROI_pv=mpa_pv+"ROI"+str(ROI_num)+':'
+    stats_pv=mpa_pv+"Stats"+str(ROI_num)+':'
+    caput(stats_pv+'NDArrayPort','ROI'+str(ROI_num))
+    caput(stats_pv+'EnableCallbacks','Enable')
+    caput(stats_pv+'ArrayCallbacks','Enable')
+    caput(stats_pv+'ComputeStatistics','Yes')
+    caput(stats_pv+'ComputeCentroid','Yes')
+    caput(stats_pv+'ComputeProfiles','Yes')
+
+def _mpa_trigger_calcOut(**kwargs):
+    """
+    writes strSeq and calcOut for MPA this should go into the IOC
+
+    **kwargs:
+        ADplugin = 'TIFF1:' (default)
+    """
+
+    kwargs.setdefault("ADplugin","TIFF1:")
+    kwargs.setdefault("save_image",False)
+
+    ADplugin = mpa_pv + kwargs["ADplugin"]
+    Proc1 = mpa_pv + "Proc1:"
+
+    #All this should moved into the MPA IOC    
+    Calcs_mda = ScanRecord("29idTest:")
+    
+    desc = "MPA busy"
+    n=9
+    busy_CalcOut = userCalcOut_clear(Calcs_mda,n)
+    caput(busy_CalcOut+".DESC",desc)
+    caput(busy_CalcOut+".INPA",mpa_busy+" CP")
+    caput(busy_CalcOut+".OOPT",'Transition to non-zero')
+    caput(busy_CalcOut+".OUT",start_strSeq+".PROC PP")
+
+    desc = "MPA start"
+    n=1
+    start_strSeq = userStringSeq_clear(Calcs_mda,n)
+    caput(start_strSeq+".DESC",desc)
+    caput(start_strSeq+".LNK1", Proc1+"ResetFilter PP")
+    caput(start_strSeq+".STR1","Yes")
+
+    desc = "MPA wait"
+    n=10
+    wait_CalcOut = userCalcOut_clear(Calcs_mda,n)
+    caput(wait_CalcOut+".DESC",desc)
+    caput(wait_CalcOut+".INPA",Proc1+"NumFilter_RBV")
+    caput(wait_CalcOut+".INPB",Proc1+"NumFiltered_RBV")
+    caput(wait_CalcOut+".OOPT",'Transition to non-zero')
+    caput(wait_CalcOut+".OUT",done_strSeq+".PROC PP")
+
+    desc = "MPA writeDone"
+    n=1
+    done_strSeq = userStringSeq_clear(Calcs_mda,n)
+    caput(done_strSeq+".DESC","MPA writeDone")
+    caput(done_strSeq+".LNK1", ADplugin+"WriteFile PP")
+    caput(done_strSeq+".STR1","Write")
+    caput(done_strSeq+".LNK1", mpa_busy+" PP")
+    caput(done_strSeq+".STR1","Done")
+        
+    
+
+def _mpa_trigger_callback(trigger,saveImg=False,**kwargs):
+    """
+    used for triggering the MPA in the scanRecord, reset Proc1 and waits for finish
+    
+    trigger: adds/removes trigger to mda (True/False)      
+        
+    **kwargs:
+        save_image = False used for appropriate trigger of ROIs
+                = True also saves an image based on ADplugin type  
+        ADplugin = 'TIFF1:' (default
+    
+    by default ADplugin = 29iddMPA:TIFF1: 
+        can use 29iddMPA:HDF1:
+    """
+
+    kwargs.setdefault("ADplugin","TIFF1:")
+    kwargs.setdefault("save_image",False)
+
+    ADplugin = mpa_pv + kwargs['ADplugin']
+
+    _mpa_trigger_calcOut(**kwargs)
+           
+    if trigger==True:
+        caput(ADplugin+"AutoResetFilter","Yes")
+        if saveImg:
+            caput(ADplugin+"AutoSave", "No")
+            caput(ADplugin+"EnableCallbacks", "Enable")
+        
+    if trigger==False:
+        caput(ADplugin+"AutoResetFilter","No")
+        if saveImg:
+            caput(ADplugin+"EnableCallbacks", "Disable")
+            caput(ADplugin+"AutoSave", "Yes")
+
+    return mpa_busy
+
+def _mpa_prefix(**kwargs):
+    """
+    """
+    kwargs.setdefault("debug",False)
+    
+    fpath=join(dirname(dirname(mda.filepath)),"mpa",'')
+    nextMDA = mda.fileNum
+    prefix="mda"+str.zfill(str(nextMDA),4)+"_mpa"
+    return prefix
+
+def mpa_trigger(trigger, **kwargs):
+    """
+    Sets up / Cleans up the ScanRecord to trigger the MPA 
+
+    trigger: adds/removes trigger to mda (True/False)
+          
+        
+    **kwargs:
+        save_image = False used for appropriate trigger of ROIs
+                = True also saves an image based on ADplugin type  
+        detTrigNum = 2 (default)
+        scan_dim = 1 (default)
+        ADplugin = "TIFF1" / "HDF1"
+
+    Previously: MPA_Trigger
+    """
+    kwargs.setdefault("detTrigNum",2)
+    kwargs.setdefault("save_image",False)
+    kwargs.setdefault('scan_dim',1)
+    kwargs.setdefault("ADplugin","TIFF1:")
+    
+    mpa_busy = _mpa_trigger_callback(trigger, **kwargs)
+                    
+    #adding the MPA to the scanRecord trigger
+    if trigger == True:
+        _mpa_prefix(**kwargs)
+        mda.triggers_set(kwargs['scan_dim'],{2:mpa_busy})
+
+    if trigger == False:
+        mda.triggers_set(kwargs['scan_dim'],{2:''})
+        
+   
+
+def mpa_save_strSeq(**kwargs):
+    """
+    **kwargs:
+        ADplugin: "TIFF1:"
+    """
+    kwargs.setdefault("ADplugin","TIFF1:")
+
+    ADplugin = mpa_pv + kwargs["ADplugin"]
+
+    desc = "MCP datamode"
+    n=2
+    strSeq_pv = userStringSeq_clear(mda,n)
+    caput(strSeq_pv+".DESC",desc)
+    caput(strSeq_pv+".LNK1",mpaDet_pv+"Acquire CA NMS")
+    caput(strSeq_pv+".STR1","Done")
+    caput(strSeq_pv+".WAIT1","Wait")
+    caput(strSeq_pv+".LNK2",mpaDet_pv+"RunTimeEnable PP NMS")
+    caput(strSeq_pv+".STR2","1")
+    caput(strSeq_pv+".WAIT2","Wait")
+    caput(strSeq_pv+".LNK3",ADplugin+"EnableCallbacks PP NMS")
+    caput(strSeq_pv+".STR3","1")
+
+def mpa_freerun_strSeq():
+    """
+    """
+    desc = "MCP freerun"
+    n=1
+    strSeq_pv = userStringSeq_clear(mda,n)
+    caput(strSeq_pv+".DESC",desc)
+    caput(strSeq_pv+".LNK1",mpaDet_pv+"Acquire PP NMS")
+    caput(strSeq_pv+".WAIT1","Wait")
+    caput(strSeq_pv+".STR1","Done")
+    caput(strSeq_pv+".LNK2","29iddMPA:TIFF1:EnableCallbacks PP NMS")
+    caput(strSeq_pv+".STR2","0")
+    caput(strSeq_pv+".WAIT2","Wait")
+    caput(strSeq_pv+".LNK3",mpaDet_pv+"RunTimeEnable PP NMS")
+    caput(strSeq_pv+".STR3","0")
+    caput(strSeq_pv+".WAIT3","Wait")
+    caput(strSeq_pv+".LNK4",mpaDet_pv+"Acquire PP NMS")
+    caput(strSeq_pv+".STR4","Acquire")
+
+
+def mpa_HV_sp_calcOut():
+    """
+    """
+
+    desc = "MPA HV SP"
+    n=9
+    calcOut_pv = userCalcOut_clear(mda,n)
+
+    caput(calcOut_pv+".DESC",desc)
+    caput(calcOut_pv+".A",0)
+    caput(calcOut_pv+".B",ratio)
+    caput(calcOut_pv+".C",max_HV)
+    caput(calcOut_pv+".CALC$","A")
+    caput(calcOut_pv+".OCAL$","MIN(A/B,C/B)")
+    caput(calcOut_pv+".OOPT",1)        # On Change
+    caput(calcOut_pv+".DOPT",1)        # Use 0CALC
+    caput(calcOut_pv+".IVOA",0)        # Continue Normally
+    caput(calcOut_pv+".OUT",DAC_pv+" PP NMS")
+
+def mpa_HV_rbv_calcOut():
+    """
+    """
+    desc = "MPA HV RBV"
+    n=10
+    calcOut_pv = userCalcOut_clear(mda,n)
+
+    caput(calcOut_pv+".DESC",desc)
+    caput(calcOut_pv+".INPA",DAC_pv+' CP NMS')
+    caput(calcOut_pv+".B",ratio)
+    caput(calcOut_pv+".CALC$","A*B")
+
+def mpa_interlock_mpa():
+    """
+    """
+    desc = "MPA Interlock mpa"
+    n=7
+    calcOut_pv = userCalcOut_clear(mda,n)
+
+    caput(calcOut_pv+".DESC",desc)
+    tth_pv = Kappa_motor_dictionary('tth')[3]
+    caput(calcOut_pv+".INPA",tth_pv+".DRBV CP NMS")
+    caput(calcOut_pv+".B",1)
+    caput(calcOut_pv+".CALC$","ABS((("+str(tth_dLLM)+"<A && A<"+str(tth_dHLM)+") && (B>0))-1)")
+    caput(calcOut_pv+".OCAL$",'A')
+    caput(calcOut_pv+".OOPT",2)    # When zero
+    caput(calcOut_pv+".DOPT",0)    # Use CALC
+    caput(calcOut_pv+".IVOA",0)    # Continue Normally
+    caput(calcOut_pv+".OUT",mpa_on_off_pv()+"PP NMS")
+
+    
+def mpa_interlock_DAC():
+    """
+    """
+    desc = "MPA Interlock DAC"
+    n=8
+    calcOut_pv = userCalcOut_clear(mda,n)
+
+    caput(calcOut_pv+".DESC",desc)
+    tth_pv = Kappa_motor_dictionary('tth')[3]
+    caput(calcOut_pv+".INPA",tth_pv+".DRBV CP NMS")
+    caput(calcOut_pv+".B",1)
+    caput(calcOut_pv+".CALC$","ABS((("+str(tth_dLLM)+"<A && A<"+str(tth_dHLM)+") && (B>0))-1)")
+    caput(calcOut_pv+".OCAL$",'A')
+    caput(calcOut_pv+".OOPT",2)    # When zero
+    caput(calcOut_pv+".DOPT",0)    # Use CALC
+    caput(calcOut_pv+".IVOA",0)    # Continue Normally
+    caput(calcOut_pv+".OUT",DAC_pv+"_Se PP NMS") 
+
+def reset_mpa_HV():
+    """
+    resetting the SRS which controls the MPA HV
+    Model: SRS PS350
+    ip = "164.54.118.57"
+    """
+    ip = "164.54.118.57"
+    # Open TCP connect to poet 1234 of GPIB-ETHERNET
+    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
+    sock.settimeout(0.1)
+    sock.connect((ip, 1234))
+
+    # Set mode as CONTROLLER
+    sock.send(b'++mode 1\n')
+
+    # specify GPIB address of device being controlled
+    addr = "14"
+    str1="++addr"+addr+'\n'
+    sock.send(bytes(str1,'utf-8'))
+
+    # reset SRS PS350
+    #sock.send("*RST\n")
+
+    # turn the high voltage on, clearing any current or voltage trips
+    sock.send(b"HVON\n")
\ No newline at end of file
diff --git a/build/lib/iexcode/instruments/remote_controlers.py b/build/lib/iexcode/instruments/remote_controlers.py
new file mode 100644
index 0000000000000000000000000000000000000000..2c65239be40dcfcbbbc0a218203d49a0a2a08562
--- /dev/null
+++ b/build/lib/iexcode/instruments/remote_controlers.py
@@ -0,0 +1,356 @@
+from epics import caget,caput
+
+##############################################################################################################
+##############################             RSXS Remote control        ##############################
+##############################################################################################################
+
+# To start ioc for ARPES(RSXS) Surly(Sneezy)
+# cd /net/s29dserv/xorApps/epics/synApps_5_8/ioc/29idSurlySoft/iocboot/iocLinux
+# 29idSurlySoft start
+
+# to bring up epics screen
+# cd /net/s29dserv/xorApps/epics/synApps_5_8/ioc/29idSurlySoft/
+# start_epics_29idSurlySoft
+
+def ARPES_Controller():
+    """
+    Button={} with Button[][0]=PV name and Button[][1]=value (for tweaks or other procs value=1)
+    ".TWF -> (+)tweak"
+    ".TWR -> (-)tweak"
+    """
+    Controller="29idSurlySoft"
+    ioc="29idc:"
+
+    Triggers={}    #['LTSeq','RTSeq','LBSeq','RBSeq']
+    Triggers[0]=ioc+"allstop.VAL",1
+    Triggers[1]=ioc+"allstop.VAL",1
+    Triggers[2]=ioc+"allstop.VAL",1
+    Triggers[3]=ioc+"allstop.VAL",1
+
+    DPad={}        #['UpSeq','DownSeq','LeftSeq','RightSeq']
+    DPad[0]=ioc+"m1.TWF",1            #x
+    DPad[1]=ioc+"m1.TWR",1
+    DPad[2]=ioc+"m4.TWR",1            #th
+    DPad[3]=ioc+"m4.TWF",1
+
+    Buttons={}    #['YSeq','ASeq','XSeq','BSeq']
+    Buttons[0]=ioc+"m3.TWF",1        #z
+    Buttons[1]=ioc+"m3.TWR",1
+    Buttons[2]=ioc+"m2.TWR",1        #y
+    Buttons[3]=ioc+"m2.TWF",1
+
+    Ljoy={}        #['LSUpSeq','LSDownSeq','LSLeftSeq','LSRightSeq']
+    Ljoy[0]="",0
+    Ljoy[1]="",0
+    Ljoy[2]=ioc+"m6.TWR",1            #phi
+    Ljoy[3]=ioc+"m6.TWF",1            #phi
+    Lclick={}    #['L3Seq']
+    Lclick[0]=ioc+"m1.TWV",.25        #x
+    Lclick[1]=ioc+"m2.TWV",.25        #y
+    Lclick[2]=ioc+"m3.TWV",.25        #z
+    Lclick[3]=ioc+"m4.TWV",1        #th
+    Lclick[4]=ioc+"m5.TWV",1        #chi
+    Lclick[5]=ioc+"m6.TWV",1        #phi
+    Lclick[6]="",0
+    Lclick[7]="",0
+    Lclick[8]="",0
+
+    Rjoy={}        #['RSUpSeq','RSDownSeq','RSLeftSeq','RSRightSeq']
+    Rjoy[0]="",0
+    Rjoy[1]="",0
+    Rjoy[2]=ioc+"m5.TWR",1            #chi
+    Rjoy[3]=ioc+"m5.TWF",1            #chi
+    Rclick={}    #['R3Seq']
+    Rclick[0]=ioc+"m1.TWV",.5        #x
+    Rclick[1]=ioc+"m2.TWV",.5        #y
+    Rclick[2]=ioc+"m3.TWV",.5        #z
+    Rclick[3]=ioc+"m4.TWV",5        #th
+    Rclick[4]=ioc+"m5.TWV",5        #chi
+    Rclick[5]=ioc+"m6.TWV",5        #phi
+    Rclick[6]="",0
+    Rclick[7]="",0
+    Rclick[8]="",0
+
+    Controller_setup(Controller,Triggers,DPad,Buttons,Ljoy,Lclick,Rjoy,Rclick)
+
+
+def RSXS_Kappa_Controller_backup(): #Keep JM modified below when kth broke
+    """
+    Button={} with Button[][0]=PV name and Button[][1]=value (for tweaks or other procs value=1)
+    ".TWF -> (+)tweak"
+    ".TWR -> (-)tweak"
+    """
+    Controller="29idSneezySoft"
+    ioc="29idKappa:"
+
+    Triggers={}    #['LTSeq','RTSeq','LBSeq','RBSeq']
+    Triggers[0]=ioc+"m9.TWR",1        #tth
+    Triggers[1]=ioc+"m9.TWF",1
+    Triggers[2]=ioc+"allstop.VAL",1
+    Triggers[3]=ioc+"allstop.VAL",1
+
+    DPad={}        #['UpSeq','DownSeq','LeftSeq','RightSeq']
+    DPad[0]=ioc+"m4.TWF",1            #z
+    DPad[1]=ioc+"m4.TWR",1
+    DPad[2]=ioc+"m1.TWR",1            #phi
+    DPad[3]=ioc+"m1.TWF",1
+
+    Buttons={}    #['YSeq','ASeq','XSeq','BSeq']
+    Buttons[0]=ioc+"m3.TWF",1        #y
+    Buttons[1]=ioc+"m3.TWR",1
+    Buttons[2]=ioc+"m2.TWR",1        #x
+    Buttons[3]=ioc+"m2.TWF",1
+
+    Ljoy={}        #['LSUpSeq','LSDownSeq','LSLeftSeq','LSRightSeq']
+    Ljoy[0]="",0
+    Ljoy[1]="",0
+    Ljoy[2]=ioc+"m8.TWR",1            #th
+    Ljoy[3]=ioc+"m8.TWF",1
+    Lclick={}    #['L3Seq']
+    Lclick[0]=ioc+"m2.TWV",50        #x
+    Lclick[1]=ioc+"m3.TWV",50        #y
+    Lclick[2]=ioc+"m4.TWV",50        #z
+    Lclick[3]=ioc+"m1.TWV",0.5        #phi (0.5 deg)
+    Lclick[4]=ioc+"m7.TWV",0.5        #kappa
+    Lclick[5]=ioc+"m8.TWV",0.5        #th
+    Lclick[6]=ioc+"m9.TWV",0.5        #tth
+    Lclick[7]="",0
+    Lclick[8]="",0
+
+    Rjoy={}        #['RSUpSeq','RSDownSeq','RSLeftSeq','RSRightSeq']
+    Rjoy[0]="",0
+    Rjoy[1]="",0
+    Rjoy[2]=ioc+"m7.TWR",1            #kappa
+    Rjoy[3]=ioc+"m7.TWF",1
+    Rclick={}    #['R3Seq']
+    Rclick[0]=ioc+"m2.TWV",250        #x
+    Rclick[1]=ioc+"m3.TWV",250        #y
+    Rclick[2]=ioc+"m4.TWV",250        #z
+    Rclick[3]=ioc+"m1.TWV",5        #phi (45 deg)
+    Rclick[4]=ioc+"m7.TWV",5        #kappa
+    Rclick[5]=ioc+"m8.TWV",5        #th
+    Rclick[6]=ioc+"m9.TWV",5        #tth
+    Rclick[7]="",0
+    Rclick[8]="",0
+
+    Controller_setup(Controller,Triggers,DPad,Buttons,Ljoy,Lclick,Rjoy,Rclick)
+
+def RSXS_Kappa_Controller():
+    """
+    Button={} with Button[][0]=PV name and Button[][1]=value (for tweaks or other procs value=1)
+    ".TWF -> (+)tweak"
+    ".TWR -> (-)tweak"
+    """
+    Controller="29idSneezySoft"
+    ioc="29idKappa:"
+
+    Triggers={}    #['LTSeq','RTSeq','LBSeq','RBSeq']
+    Triggers[0]=ioc+"m9.TWR",1        #tth
+    Triggers[1]=ioc+"m9.TWF",1
+    Triggers[2]=ioc+"allstop.VAL",1
+    Triggers[3]=ioc+"allstop.VAL",1
+
+    DPad={}        #['UpSeq','DownSeq','LeftSeq','RightSeq']
+    DPad[0]=ioc+"m4.TWF",1            #z
+    DPad[1]=ioc+"m4.TWR",1
+    DPad[2]=ioc+"m1.TWR",1            #phi
+    DPad[3]=ioc+"m1.TWF",1
+
+    Buttons={}    #['YSeq','ASeq','XSeq','BSeq']
+    Buttons[0]=ioc+"m3.TWF",1        #y
+    Buttons[1]=ioc+"m3.TWR",1
+    Buttons[2]=ioc+"m2.TWR",1        #x
+    Buttons[3]=ioc+"m2.TWF",1
+
+    Ljoy={}        #['LSUpSeq','LSDownSeq','LSLeftSeq','LSRightSeq']
+    Ljoy[0]="29idd:Unidig1Bo0",0        #light on
+    Ljoy[1]="29idd:Unidig1Bo0",1        #light off
+    Ljoy[2]=ioc+"",0            #th
+    Ljoy[3]=ioc+"",0
+    Lclick={}    #['L3Seq']
+    Lclick[0]=ioc+"m2.TWV",250        #x
+    Lclick[1]=ioc+"m3.TWV",250        #y
+    Lclick[2]=ioc+"m4.TWV",250        #z
+    Lclick[3]=ioc+"m1.TWV",0.5        #phi (0.5 deg)
+    Lclick[4]=ioc+"m7.TWV",0.5        #kappa
+    Lclick[5]=ioc+"m8.TWV",0.5        #th
+    Lclick[6]=ioc+"m9.TWV",0.5        #tth
+    Lclick[7]="",0
+    Lclick[8]="",0
+
+    Rjoy={}        #['RSUpSeq','RSDownSeq','RSLeftSeq','RSRightSeq']
+    Rjoy[0]="",0
+    Rjoy[1]="",0
+    Rjoy[2]=ioc+"",0            #kappa
+    Rjoy[3]=ioc+"",0
+    Rclick={}    #['R3Seq']
+    Rclick[0]=ioc+"m2.TWV",500        #x
+    Rclick[1]=ioc+"m3.TWV",500        #y
+    Rclick[2]=ioc+"m4.TWV",500        #z
+    Rclick[3]=ioc+"m1.TWV",5        #phi (45 deg)
+    Rclick[4]=ioc+"m7.TWV",5        #kappa
+    Rclick[5]=ioc+"m8.TWV",5        #th
+    Rclick[6]=ioc+"m9.TWV",5        #tth
+    Rclick[7]="",0
+    Rclick[8]="",0
+
+    Controller_setup(Controller,Triggers,DPad,Buttons,Ljoy,Lclick,Rjoy,Rclick)
+
+
+def RSoXS_Controller():
+    """
+    Button={} with Button[][0]=PV name and Button[][1]=value (for tweaks or other procs value=1)
+    ".TWF -> (+)tweak"
+    ".TWR -> (-)tweak"
+    """
+    Controller="29idSneezySoft"
+    ioc="29idRSoXS:"
+
+    Triggers={}    #['LTSeq','RTSeq','LBSeq','RBSeq']
+    Triggers[0]=ioc+"allstop.VAL",1
+    Triggers[1]=ioc+"allstop.VAL",1
+    Triggers[2]=ioc+"allstop.VAL",1
+    Triggers[3]=ioc+"allstop.VAL",1
+
+    DPad={}        #D-Pad:['UpSeq','DownSeq','LeftSeq','RightSeq']
+    DPad[0]=ioc+"m10.TWF",1            #Det-V
+    DPad[1]=ioc+"m10.TWR",1
+    DPad[2]=ioc+"m11.TWR",1            #Det-Q
+    DPad[3]=ioc+"m11.TWF",1
+
+    Buttons={}    #Buttons:['YSeq','ASeq','XSeq','BSeq']
+    Buttons[0]=ioc+"m2.TWF",1        #y
+    Buttons[1]=ioc+"m2.TWR",1
+    Buttons[2]=ioc+"m1.TWR",1        #x
+    Buttons[3]=ioc+"m1.TWF",1
+
+    Ljoy={}        #Left Joystick:['LSUpSeq','LSDownSeq','LSLeftSeq','LSRightSeq']
+    Ljoy[0]=ioc+"m5.TWF",1            #phi
+    Ljoy[1]=ioc+"m5.TWR",1
+    Ljoy[2]=ioc+"m9.TWR",1            #tth
+    Ljoy[3]=ioc+"m9.TWF",1
+    Lclick={}    #['L3Seq']
+    Lclick[0]="",0
+    Lclick[1]="",0
+    Lclick[2]="",0
+    Lclick[3]="",0
+    Lclick[4]="",0
+    Lclick[5]="",0
+    Lclick[6]="",0
+    Lclick[7]="",0
+    Lclick[8]="",0
+
+    Rjoy={}        #Right Joystick:['RSUpSeq','RSDownSeq','RSLeftSeq','RSRightSeq']
+    Rjoy[0]=ioc+"m3.TWF",1            #z
+    Rjoy[1]=ioc+"m3.TWF",1
+    Rjoy[2]=ioc+"m8.TWR",1            #th
+    Rjoy[3]=ioc+"m8.TWF",1
+    Rclick={}    #['R3Seq']
+    Rclick[0]=ioc+"m2.TWV",1        #x
+    Rclick[1]=ioc+"m3.TWV",1        #y
+    Rclick[2]=ioc+"m4.TWV",1        #z
+    Rclick[3]=ioc+"m1.TWV",1        #th
+    Rclick[4]=ioc+"m7.TWV",1        #phi
+    Rclick[5]=ioc+"m8.TWV",1        #tth
+    Rclick[6]=ioc+"m9.TWV",1        #Det-V
+    Rclick[7]=ioc+"m9.TWV",1        #Det-Q
+    Rclick[8]="",0
+
+    Controller_setup(Controller,Triggers,DPad,Buttons,Ljoy,Lclick,Rjoy,Rclick)
+
+def Controller_setup(Controller,Triggers,DPad,Buttons,Ljoy,Lclick,Rjoy,Rclick):
+    """ -------- Standard set up for the Logitech controllers --------------
+    Controller -> controller ioc name
+
+    Button={}
+    Button[][0]=PV name
+    Button[][1]=value (for tweaks or other procs value=1)
+    ".TWF -> (+)tweak"
+    ".TWR -> (-)tweak"
+
+        Trigger[0,3]     -> PVs for link 1 of the 4 buttons (bottoms are typically the allstop)
+        DPad[0,3]     -> PVs for link 1 of the 4 buttons (order: Top/Bottom/Left/Right)
+        Buttons[0,3]     -> PVs for link 1 of the 4 buttons (order: Top/Bottom/Left/Right)
+        Ljoy[0,3]     -> PVs for link 1 of the 4 buttons (order: Top/Bottom/Left/Right)
+        Lclick[0,8]    -> PVs for Link 1-9 of the center click (typically coarse tweak values)
+        RJoy[0,3]     -> PVs for link 1 of the 4 buttons (order: Top/Bottom/Left/Right)
+        Rclick[0,8]    -> PVs for Link 1-9 of the center click (typically fine tweak values)
+    """
+
+    #Triggers
+    Ctrl_button(Controller,"LTSeq",1,Triggers[0][0],Triggers[0][1])
+    Ctrl_button(Controller,"RTSeq",1,Triggers[1][0],Triggers[1][1])
+    Ctrl_button(Controller,"LBSeq",1,Triggers[2][0],Triggers[2][1])#All Stop
+    Ctrl_button(Controller,"RBSeq",1,Triggers[3][0],Triggers[3][1])#All Stop
+
+    # D-Pad
+    Ctrl_button(Controller,"UpSeq",1,   DPad[0][0],DPad[0][1])
+    Ctrl_button(Controller,"DownSeq",1, DPad[1][0],DPad[1][1])
+    Ctrl_button(Controller,"LeftSeq",1, DPad[2][0],DPad[2][1])
+    Ctrl_button(Controller,"RightSeq",1,DPad[3][0],DPad[3][1])
+
+
+    #Buttons
+    Ctrl_button(Controller,"YSeq",1,Buttons[0][0],Buttons[0][1])
+    Ctrl_button(Controller,"ASeq",1,Buttons[1][0],Buttons[1][1])
+    Ctrl_button(Controller,"XSeq",1,Buttons[2][0],Buttons[2][1])
+    Ctrl_button(Controller,"BSeq",1,Buttons[3][0],Buttons[3][1])
+
+
+    #Left Joystick
+    Ctrl_button(Controller,"LSUpSeq",1,   Ljoy[0][0],Ljoy[0][1])
+    Ctrl_button(Controller,"LSDownSeq",1, Ljoy[1][0],Ljoy[1][1])
+    Ctrl_button(Controller,"LSLeftSeq",1, Ljoy[2][0],Ljoy[2][1])
+    Ctrl_button(Controller,"LSRightSeq",1,Ljoy[3][0],Ljoy[3][1])
+    #Left Click                    Coarse Tweak Values
+    Ctrl_button(Controller,"L3Seq",1,Lclick[0][0],Lclick[0][1])
+    Ctrl_button(Controller,"L3Seq",2,Lclick[1][0],Lclick[1][1])
+    Ctrl_button(Controller,"L3Seq",3,Lclick[2][0],Lclick[2][1])
+    Ctrl_button(Controller,"L3Seq",4,Lclick[3][0],Lclick[3][1])
+    Ctrl_button(Controller,"L3Seq",5,Lclick[4][0],Lclick[4][1])
+    Ctrl_button(Controller,"L3Seq",6,Lclick[5][0],Lclick[5][1])
+    Ctrl_button(Controller,"L3Seq",7,Lclick[6][0],Lclick[6][1])
+    Ctrl_button(Controller,"L3Seq",8,Lclick[7][0],Lclick[7][1])
+    Ctrl_button(Controller,"L3Seq",9,Lclick[8][0],Lclick[8][1])
+
+    #Right Joystick
+    Ctrl_button(Controller,"RSUpSeq",1,   Rjoy[0][0],Rjoy[0][1])
+    Ctrl_button(Controller,"RSDownSeq",1, Rjoy[1][0],Rjoy[1][1])
+    Ctrl_button(Controller,"RSLeftSeq",1, Rjoy[2][0],Rjoy[2][1])
+    Ctrl_button(Controller,"RSRightSeq",1,Rjoy[3][0],Rjoy[3][1])
+    #Right Click                    Fine Tweak Values
+    Ctrl_button(Controller,"R3Seq",1,Rclick[0][0],Rclick[0][1])
+    Ctrl_button(Controller,"R3Seq",2,Rclick[1][0],Rclick[1][1])
+    Ctrl_button(Controller,"R3Seq",3,Rclick[2][0],Rclick[2][1])
+    Ctrl_button(Controller,"R3Seq",4,Rclick[3][0],Rclick[3][1])
+    Ctrl_button(Controller,"R3Seq",5,Rclick[4][0],Rclick[4][1])
+    Ctrl_button(Controller,"R3Seq",6,Rclick[5][0],Rclick[5][1])
+    Ctrl_button(Controller,"R3Seq",7,Rclick[6][0],Rclick[6][1])
+    Ctrl_button(Controller,"R3Seq",8,Rclick[7][0],Rclick[7][1])
+    Ctrl_button(Controller,"R3Seq",9,Rclick[8][0],Rclick[8][1])
+
+
+def Ctrl_reset(Controller):
+    PV=""
+    val=0
+    CtrlButtonList  = ['LTSeq','RTSeq','LBSeq','RBSeq','UpSeq','DownSeq','LeftSeq','RightSeq','YSeq','ASeq','XSeq','BSeq']
+    CtrlButtonList.extend(['LSUpSeq','LSDownSeq','LSLeftSeq','LSRightSeq','L3Seq','RSUpSeq','RSDownSeq','RSLeftSeq','RSRightSeq','R3Seq'])
+    for button in CtrlButtonList:
+        for link in range(1,10):
+            Ctrl_button(Controller,button,link,PV,val)
+
+def Ctrl_button(Controller,button,link,PV,val):#writes to specified link (controller has 1 to 9)
+    ctlpv=Controller+":ctl1:"+button
+    caput(ctlpv+".LNK"+str(link),PV+" NPP NMS")
+    caput(ctlpv+".DO"+str(link),val)
+
+def Ctrl_print(Controller):
+    CtrlButtonList  = ['LTSeq','RTSeq','LBSeq','RBSeq','UpSeq','DownSeq','LeftSeq','RightSeq','YSeq','ASeq','XSeq','BSeq']
+    CtrlButtonList.extend(['LSUpSeq','LSDownSeq','LSLeftSeq','LSRightSeq','L3Seq','RSUpSeq','RSDownSeq','RSLeftSeq','RSRightSeq','R3Seq'])
+    for button in CtrlButtonList:
+        print("---"+button+"---")
+        for link in range(1,10):
+            ctlpv=Controller+":ctl1:"+button
+            PV=caget(ctlpv+".LNK"+str(link))
+            val=caget(ctlpv+".DO"+str(link))
+            print("     "+PV+", "+str(val))
diff --git a/build/lib/iexcode/instruments/resolution.py b/build/lib/iexcode/instruments/resolution.py
new file mode 100644
index 0000000000000000000000000000000000000000..a34f8919c7df6eca028e3216ec5b13e3d5973da2
--- /dev/null
+++ b/build/lib/iexcode/instruments/resolution.py
@@ -0,0 +1,106 @@
+import numpy as np
+
+from iexcode.instruments.electron_analyzer import resolution_EA
+#############################################################################################################
+##############################             Resolution              ##############################
+#############################################################################################################
+def resolution_calculate_beamline(grt,hv_eV,slit_size):
+    """
+    
+    Previously: Calc_BL_Resolution
+    """
+    res_function={}
+    res_function[10]  = {"MEG":(-0.000800494,2.56761e-05,1.83724e-08,-1.69223e-12,0),          "HEG":(-0.000414482,1.07456e-05,8.79034e-09,-8.42361e-13,0)}
+    res_function[20]  = {"MEG":(-0.00156643, 3.16894e-05,2.72121e-08,-2.63642e-12,0),          "HEG":(-0.00054591, 1.35647e-05,2.01775e-08,-4.30789e-12,5.70112e-16)}
+    res_function[50]  = {"MEG":(-0.00251543, 4.89022e-05,7.70055e-08,-1.66358e-11,2.21272e-15),"HEG":(-0.00173081, 2.97625e-05,4.90646e-08,-1.0706e-11, 1.43011e-15)}
+    res_function[100] = {"MEG":(-0.00545563, 9.14928e-05,1.51335e-07,-3.30332e-11,4.41314e-15),"HEG":(-0.00360316, 5.83265e-05,9.76881e-08,-2.13767e-11,2.85877e-15)}
+    res_function[200] = {"MEG":(-0.0111658,  0.000179785,3.01277e-07,-6.59309e-11,8.81755e-15),"HEG":(-0.00728107, 0.000116055,1.95149e-07,-4.27331e-11,5.71638e-15)}
+    try:
+        a,b,c,d,e = res_function[slit_size][grt]
+        resolution = a + b*hv_eV + c*hv_eV**2 + d*hv_eV**3 + e*hv_eV**4
+
+    except KeyError:
+        print("WARNING: Slit size not listed, please choose one of the following:")
+        print("        10, 20, 50, 100, 200 um.")
+        resolution=0
+
+    return resolution*1000
+
+
+def resolution_mono_noise(grt,hv_eV):
+    """
+    jitter/noise in the mono contribution to the resolution 
+
+    Previoulsy: Resolution_Mono
+    """
+    if grt == "MEG":
+        K0=-2.3836
+        K1=0.02083
+        K2=7.8886e-06
+    if grt == "HEG":
+        K0=-2.0984
+        K1=0.011938
+        K2=3.6397e-06
+    noise = K0 + K1*hv_eV + K2*hv_eV**2
+    return noise
+
+
+def resolution_beamline(grt,hv_eV,slit_size,verbose=True):
+    """
+    resolution of the beamline optics
+    
+    Resolution_BL
+    """
+    mono_noise = resolution_mono_noise(grt,hv_eV)
+    theortical = resolution_calculate_beamline(grt,hv_eV,slit_size)
+    resolution=np.sqrt(theortical**2 + mono_noise**2)
+    if verbose:
+        print("BL   : "+"%.0f" % theortical, "meV")
+        print("Mono : "+"%.0f" % mono_noise, "meV")
+        print("Total: "+"%.0f" % resolution, "meV")
+    return resolution 
+
+
+def resolution_ARPES(grt,hv_eV,slit_size,PE,slit_SES,T,verbose=True):
+    """
+    resolution of the ARPES
+    """
+    bl = resolution_beamline(grt,hv_eV,slit_size,verbose=False)
+    KbT = T*25/300
+    SES = resolution_EA(PE,slit_SES)
+    
+    resolution = np.sqrt(bl**2 + KbT**2 + SES**2)
+
+    if verbose:
+        print("BL + mono  : "+"%.0f" % bl, "meV")
+        print("SES  : "+"%.0f" % SES, "meV")
+        print("KbT  : "+"%.0f" % KbT, "meV")
+        print("Total: "+"%.0f" % resolution, "meV")
+
+    return resolution
+
+def Resolution_BL_eff(grating,hv,slit_3C,PE,slit_SES,T,Ef):
+    M = resolution_mono_noise(grating,hv)
+    KbT = T*25/300
+    BL = resolution_calculate_beamline(grating,hv,slit_3C)
+    SES = resolution_EA(PE,slit_SES)
+    resolution = np.sqrt(BL**2+SES**2+KbT**2+M**2)
+    effective = np.sqrt(Ef**2-SES**2-KbT**2-M**2)
+    print("BL_th : "+"%.0f" % BL, "meV            SES   : "+"%.0f" % SES, "meV")
+    print("Mono  : "+"%.0f" % M, "meV            KbT   : "+"%.0f" % KbT, "meV")
+    print("Total : "+"%.0f" % resolution, "meV            Fermi : "+"%.0f" % Ef, "meV")
+    print("BL_eff: "+"%.0f" % effective, "meV")
+
+
+def Resolution_BL_eff2(grating,hv,slit_3C,PE,slit_SES,T,Ef,Dirty_Au):
+    M = resolution_mono_noise(grating,hv)
+    KbT = T*25/300
+    BL = resolution_calculate_beamline(grating,hv,slit_3C)
+    SES = resolution_EA(PE,slit_SES)
+    resolution = np.sqrt(BL**2+SES**2+KbT**2+M**2+Dirty_Au**2)
+    effective = np.sqrt(Ef**2-SES**2-KbT**2-M**2-Dirty_Au**2)
+    print("BL_th : "+"%.0f" % BL, "meV            SES   : "+"%.0f" % SES, "meV")
+    print("Mono  : "+"%.0f" % M, "meV            KbT   : "+"%.0f" % KbT, "meV")
+    print("Total : "+"%.0f" % resolution, "meV            Fermi : "+"%.0f" % Ef, "meV")
+    print("BL_eff: "+"%.0f" % effective, "meV            Sample : "+"%.0f" % Dirty_Au, "meV")
+
diff --git a/build/lib/iexcode/instruments/s29_temp_cntl.py b/build/lib/iexcode/instruments/s29_temp_cntl.py
new file mode 100644
index 0000000000000000000000000000000000000000..4bffcdae02016ef54eeb3e51bff3f8d9b26c390d
--- /dev/null
+++ b/build/lib/iexcode/instruments/s29_temp_cntl.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+from epics import caget, caput
+from time import sleep, gmtime, strftime, localtime
+
+#Define caput with wait function
+def caputw(PVname,PVinput):
+    return caput(PVname,PVinput,wait=True, timeout = 100000)
+
+def dateandtime():
+    return strftime("%a %d %b %Y %H:%M:%S",localtime())
+
+def tempr():
+	print("RSXS Sample Temperature: {} K".format(caget("29idd:LS331:TC1:SampleA")))
+	
+def temps(tempset):
+	print("Initial Sample Temperature:",caget("29idd:LS331:TC1:SampleA")," K",dateandtime())
+	caput("29idd:LS331:TC1:wr_SP",1.0*tempset)
+	stop_var=0
+	b=0
+	sleep(10)
+	while b == 0:
+		delta=abs(caget("29idd:LS331:TC1:SampleA")-1.0*tempset)
+		if abs(delta) < 1:
+			c=0
+			while c < 10:
+				sleep(1)
+				delta=delta+(caget("29idd:LS331:TC1:SampleA")-1.0*tempset)
+				c=c+1
+			if abs(delta/10) < 1:
+				print("Stable Sample Temperature:",caget("29idd:LS331:TC1:SampleA")," K",dateandtime())
+				b=1
+		else:
+			temp1=caget("29idd:LS331:TC1:SampleA")
+			sleep(10)
+			temp2=caget("29idd:LS331:TC1:SampleA")
+			if abs(temp1-temp2) < 0.1:
+				sleep(30)
+				temp2=caget("29idd:LS331:TC1:SampleA")
+				if abs(temp1-temp2) < .5:
+					print("UNABLE TO STABLIZE TEMPERATURE! Stopped at T=:",caget("29idd:LS331:TC1:SampleA")," K",dateandtime())
+					b=1
+	
+
diff --git a/build/lib/iexcode/instruments/scalers.py b/build/lib/iexcode/instruments/scalers.py
new file mode 100644
index 0000000000000000000000000000000000000000..89be3dbabd0b813aa88d6e5088354e5aa049ee33
--- /dev/null
+++ b/build/lib/iexcode/instruments/scalers.py
@@ -0,0 +1,31 @@
+from math import floor
+
+from epics import caput,PV
+
+from iexcode.instruments.IEX_endstations import BL
+
+def scaler_cts(time_seconds=0.1,verbose=True):
+    """
+    sets the scalers counting for the endstation defined in BL
+    """
+    if BL.ioc == 'Kappa':
+        Kappa_scaler(time_seconds,verbose=verbose)
+
+
+def Kappa_scaler(time_seconds=0.1,verbose=True):
+    """
+    Sets the integration time for the scalers in the Kappa chamber
+    and mpa filter num if mpa is running
+    """
+    scaler_pv="29idMZ0:scaler1.TP"
+    mpa_NumFilter = '29iddMPA:Proc1:NumFilter'
+    
+    caput(pv,time_seconds)
+    
+    pv=PV(mpa_NumFilter)
+    if pv.connected():
+        caput(mpa_NumFilter,floor(time_seconds))
+
+    if verbose: 
+        print("Integration time set to:", str(time_seconds))
+
diff --git a/build/lib/iexcode/instruments/scanRecord.py b/build/lib/iexcode/instruments/scanRecord.py
new file mode 100644
index 0000000000000000000000000000000000000000..2e01a97a40feb0cabc45a2affce438fa7ef800d9
--- /dev/null
+++ b/build/lib/iexcode/instruments/scanRecord.py
@@ -0,0 +1,688 @@
+
+from os.path import join
+import time
+
+from epics import caget, caput, PV
+
+from iexcode.instruments.utilities import dateandtime, print_warning_message
+from iexcode.instruments.logfile import log_update
+from iexcode.instruments.userCalcs import userStringSeq_pvs,userStringSeq_clear
+
+
+def saveData_get_all(ioc_pv):
+    """
+    returns saveData info: 
+    """
+    saveData_info = {
+        'fileSystem':caget(ioc_pv+":saveData_fileSystem",as_string=True),
+        'subDir':caget(ioc_pv+":saveData_subDir",as_string=True),
+        'scanNumber':caget(ioc_pv+":saveData_scanNumber"),
+        'baseName':caget(ioc_pv+":saveData_baseName",as_string=True),
+    }
+
+    filepath = join(saveData_info['fileSystem'],saveData_info['subDir'])
+    filepath=filepath.replace('//','/') 
+    
+
+default_positioner_settling_time = 0.05
+default_detector_settling_time = 0.1
+
+class ScanRecord:
+    """
+    used for short hand scanning and to get info related to a scanRecord
+    """
+
+    def __init__(self,scan_ioc,detector_dictionary,trigger_dictionary,before_scan_pv,after_scan_pv,**kwargs):
+        """
+        scan_ioc: full pv for the ioc, "29idARPES:", "29idc:"
+        detector_dictionary: dictionary corresponding to detector num and pv to proc => {det_num:'det_pv'}
+        trigger_dictionary: dictionary corresponding to trigger num and trigger pv => {trigger_num:'trigger_pv'}
+        before_scan_pv: pv to be proc'ed be for the start of a scan
+        after_scan_pv: pv to be proc'ed be for the start of a scan
+
+        **kwargs
+            reset: resets the scanRecord (True / False) => default = True
+
+        """
+        kwargs.setdefault('reset',True)
+        self.ioc = scan_ioc
+
+        if kwargs['reset']:
+            self.reset_all(detector_dictionary,trigger_dictionary,before_scan_pv,after_scan_pv)
+
+        pass
+
+##############################################################################################################
+################################            MDA (ScanRecord) files and folders               ##############################
+##############################################################################################################
+
+    def fileNum(self): 
+        """
+        returns the current fileNum in the SaveData of ioc is scanning 
+        or next if idle
+        
+        """
+        
+        return saveData_get_all(self.ioc)['scanNumber']
+
+    def lastFileNum(self): 
+        """
+        returns the last saved fileNum in the SaveData of ioc
+
+        previously: MDA_GetLastFileNum
+        """
+
+        fileNum = self.fileNum(self)
+        return fileNum - 1
+
+
+    def filepath(self):
+        """
+        returns the full filepath for the SaveData of ioc
+
+        previously: MDA_CurrentDirectory
+        """
+        return saveData_get_all(self.ioc)['filepath']   
+
+    def prefix(self):
+        """
+        returns the prefix for the SaveData of ioc
+
+        previously: MDA_CurrentPrefix
+        """
+        return saveData_get_all(self.ioc)['baseName']   
+   
+    def scanRecord_run(self):
+        """
+        returns the current run by parsing the filepath in the SaveData for ioc
+
+        previously: MDA_CurrentRun
+        """
+        filepath = self.filepath()
+        m=filepath.find('data_29id')+len('data_29id')+2
+        current_run=filepath[m:m+6]
+        return current_run
+    
+    def scanRecord_user(self):
+        """
+        returns the current user by parsing the filepath in the SaveData for ioc
+
+        previously: MDA_CurrentUser
+        """
+        subdir=caget(self.ioc+":saveData_subDir",as_string=True)
+        m=subdir.find('/mda')
+        if m == 0 : 
+            current_user='Staff'
+        elif m > 0: 
+            current_user=subdir[1:m]
+        else: 
+            current_user=""
+            print_warning_message("mda_user is empty string")
+        return current_user   
+
+
+##############################################################################################################
+#############################          filling in the scan record               ##############################
+##############################################################################################################
+
+
+    ### before and after scans
+    def _before_after_scan(self,**kwargs):
+        """
+        Fills in the before and after user sequences into the scan record
+        **kwargs
+            before_scan_pv => '' 
+            after_scan_pv => self.default_after_scan_seq() 
+        """
+        kwargs.setdefault('scan_dim',1)
+        kwargs.setdefault('before_scan_pv','')
+        kwargs.setdefault('after_scan_pv',self._default_after_scan_seq())
+        
+        scan_pv = self.ioc+"scan"+str(kwargs['scan_dim'])
+
+        #Clearing all Before/Afters in all dims
+        for dim in [1,2,3,4]:
+            caput(self.ioc+"scan"+str(dim)+".BSPV","")
+            caput(self.ioc+"scan"+str(dim)+".ASPV","")
+
+        caput(scan_pv+".BSPV",kwargs['before_scan_pv'])
+        caput(scan_pv+".BSCD",1)
+        caput(scan_pv+".BSWAIT","Wait")
+
+        caput(scan_pv+".ASPV",kwargs['after_scan_pv'])
+        caput(scan_pv+".ASCD",1)
+        caput(scan_pv+".ASWAIT","Wait")
+
+    def default_after_scan_seq(self,**kwargs):
+        """
+        writes the user string sequence to happen at the end of a scan
+        returns after_scan_pv = pv for userStringSeq for after scan
+
+        uses links 1-4, link 10 is reserved for snake scans
+
+        **kwargs
+            seq_num: userStringSeq number in ioc => 10 (default)
+            positioner_settling_time
+            detector_settling_time
+
+
+        Previously: AfterScan_StrSeq
+        """
+        kwargs.setdefault(seq_num,10)
+        kwargs.setdefault('positioner_settling_time',default_positioner_settling_time)
+        kwargs.setdefault('detector_settling_time',default_detector_settling_time)
+        
+        scan_dim = 1
+        scan_pv = self.ioc+"scan"+str(scan_dim)
+
+        seq_num=kwargs['seq_num']
+        after_scan_pv = userStringSeq_pvs(self.ioc, seq_num)
+
+        #clear and write the after scan user sequence
+        userStringSeq_clear(self.ioc,seq_num)
+        caput(after_scan_pv+".DESC","After Scan")
+
+        #link 1 - clears positioners
+        caput(after_scan_pv+".LNK1",scan_pv+'.P1AR'+" PP NMS")
+        caput(after_scan_pv+".DO1","Clear pos&rdbk PV's, etc")
+
+        #link 2 - sets positioner mode to to abosolute 
+        caput(after_scan_pv+".LNK2",scan_pv+'.CMND'+" PP NMS")
+        caput(after_scan_pv+".DO2","ABSOLUTE")
+
+        #link 3 - sets positioner delay time to default 
+        settling_time = kwargs['positioner_settling_time']
+        caput(after_scan_pv+".LNK3",scan_pv+'.PDLY'+" PP NMS")
+        caput(after_scan_pv+".DO3",settling_time)
+
+        #link 4 - sets detector delay time to default 
+        settling_time = kwargs['detector_settling_time']
+        caput(after_scan_pv+".LNK4",scan_pv+'.DDLY'+" PP NMS")
+        caput(after_scan_pv+".DO4",settling_time)
+
+        return after_scan_pv
+    
+    ### Resetting:
+    def reset_scan_dim(self,scan_dim,detector_dictionary,trigger_dictionary,before_scan_pv,after_scan_pv):
+        """
+        Resets all the scanRecords (scanDIM=1,2,3,4) for a given IOC 
+            uses Reset_Scan()
+        **kwargs
+            scaler='y', only for Kappa ioc
+
+        Previously: Reset_ScanAll
+        """
+        self.detectors_clear(scan_dim)
+        self.triggers_clear(scan_dim)
+        self.positioners_clear(scan_dim)
+
+        self.detectors_set(scan_dim,detector_dictionary)
+        self.triggers_set(scan_dim,trigger_dictionary)
+        self.before_after_sequences_set(scan_dim,before_scan_pv,after_scan_pv)
+
+        self.detector_settling_time(scan_dim)
+        self.positioner_settling_time(scan_dim)
+
+    def reset_all(self,detector_dictionary,trigger_dictionary,before_scan_pv,after_scan_pv):
+        """
+        Resets all the scanRecords (scanDIM=1,2,3,4) for a given IOC 
+            uses Reset_Scan()
+        **kwargs
+            scaler='y', only for Kappa ioc
+
+        Previously: Reset_ScanAll
+        """
+
+        for scan_dim in range(4,1):
+            self.reset_scan_dim(scan_dim,{},{},'','')
+        self.reset_scan_dim(1,detector_dictionary,trigger_dictionary,before_scan_pv,after_scan_pv)
+
+    ### default setting    
+    def settings_defaults(self,scan_dim,verbose=True,**kwargs):
+        """
+        Reset scan settings to default: ABSOLUTE, STAY, 0.05/0.1 positioner/detector settling time
+        
+        Previous: Reset_Scan
+        """
+        scan_pv = self.ioc+"scan"+str(scan_dim)
+
+        self.positioner_absolute_mode(absolute=True,**kwargs)      # Absolute position
+        self.positioner_after_scan(after="PRIOR POS",**kwargs)   # After scan: prior position  
+        self.positioner_settling_time(**kwargs)# Positioner Settling time => default
+        self.detector_settling_time(**kwargs)# Detector Settling time => default
+        self.triggers_reset(verbose=False,**kwargs)
+
+        if verbose:
+            print("Scan record "+self.ioc+" reset to default settings.")
+
+    ### positioners 
+    def positioners_clear(self,scan_dim,verbose=True):
+        """
+        Clear all extra scan positioners
+
+        Previously: Clear_Scan_Positioners
+        """
+        scan_pv = self.ioc+"scan"+str(scan_dim)
+        caput(scan_pv+".CMND",3)        # Clear all Positionners
+        
+        if verbose:
+            print("\nAll extra positionners cleared")
+
+    def positioner_settling_time(self,**kwargs):
+        """
+        sets the positioner settling time
+        """
+        kwargs.setdefault('scan_dim',1)
+        kwargs.setdefault('positioner_settling_time',self.default_positioner_settling_time())
+
+        scan_pv = self.ioc+"scan"+str(kwargs['scan_dim'])
+
+        caput(scan_pv+".PDLY",kwargs['positioner_settling_time'])     # Positioner Settling time
+        return scan_pv+".PDLY",kwargs['positioner_settling_time']
+
+    def positioner_after_scan(self,after="PRIOR POS",**kwargs):
+        """
+        sets the positioner after scan
+        after = "PRIOR POS"
+                "STAY"
+
+        """
+        kwargs.setdefault('scan_dim',1)
+        scan_pv = self.ioc+"scan"+str(kwargs['scan_dim'])
+        caput(scan_pv+".PASM",after)
+
+    def positioner_absolute_mode(self,absolute=True,**kwargs):
+        """
+        absolute = True
+                 = False => relative 
+
+        """
+        kwargs.setdefault('scan_dim',1)
+
+        scan_pv = self.ioc+"scan"+str(kwargs['scan_dim'])
+        if absolute:
+            ab_state = 0
+        else:
+            ab_state = 1
+
+        caput(scan_pv+".P1AR",ab_state)        # Absolute position
+
+    def fillin(self,val_pv,rbv_pv,start,stop,steps_points,**kwargs):
+        """
+        Fills in the scanRecord for the positionner
+            dim: scan dim
+            val_pv: drive pv 
+            rbv_pv: readback pv
+            start: first point
+            stop: last point
+            step: step size (only used for positioner_num = 1, otherwise ignored)
+        kwargs:
+            num_points: False (default) => steps_points is the step size
+                        True => steps_points is the number of points
+            positioner_num: default => 1
+            positioner_settling_time: default => 0.1
+            detector_settling_time: default => 0.1
+
+        Previously: Scan_FillIn
+        """
+        kwargs.setdefault('scan_dim',1)
+        kwargs.setdefault("positioner_num",1)
+        kwargs.setdefault('detector_settling_time',default_detector_settling_time)
+        kwargs.setdefault('positioner_settling_time',default_positioner_settling_time)
+
+        scan_dim = kwargs['scan_dim']
+        self.progress(scan_dim)
+    
+        scan_pv = self.ioc+"scan"+str(scan_dim)
+        posNum = kwargs['positioner_num']
+
+        caput(scan_pv+".P"+str(posNum)+"PV",val_pv)
+        caput(scan_pv+".R"+str(posNum)+"PV",rbv_pv)
+        caput(scan_pv+".P"+str(posNum)+"SP",start*1.0)
+        caput(scan_pv+".P"+str(posNum)+"EP",stop*1.0)
+        if kwargs['positioner_num'] == 1:
+            if kwargs['num_points'] :
+                caput(scan_pv+".NPTS",steps_points)
+            else:
+                caput(scan_pv+".P1SI",steps_points*1.0)
+        
+        self.detector_settling_time(scan_dim,kwargs['detector_settling_time'])
+        self.positioner_settling_time(scan_dim,kwargs['positioner_settling_time'])
+
+        #checking that PVs and positioner limits are good
+        self._check(scan_dim)
+
+
+    ### detectors and detector settling time
+    def detectors_clear(self,scan_dim,verbose=True):
+        """
+        Clear all scan detectors
+
+        Previously: Clear_Scan_Detectors
+        """
+        scan_pv = self.ioc+"scan"+str(scan_dim)
+        for i in range(1,10):
+            caput(scan_pv+".D0"+str(i)+"PV","")
+        for i in range(10,71):
+            caput(scan_pv+".D"+str(i)+"PV","")
+        if verbose:
+            print("\nAll detectors cleared")
+
+    def detectors_set(self,scan_dim,detector_dictionary):
+        """
+        sets the detectors
+        detector_dictionary = {detNum:pv}
+        """
+        scan_pv = self.ioc+"scan"+str(scan_dim)
+        for det_num in detector_dictionary.keys():
+            det_pv=caget(scan_pv+".D"+det_num+"PV")
+            caput(det_pv,detector_dictionary[det_num])
+
+    def detector_settling_time(self,**kwargs):
+        """
+        set the detector settling time
+        """
+        kwargs.setdefault('scan_dim',1)
+        kwargs.setdefault('detector_settling_time',self.default_detector_settling_time())
+
+        scan_pv = self.ioc+"scan"+str(kwargs['scan_dim'])
+
+        caput(scan_pv+".DDLY",kwargs['detector_settling_time'])
+        return scan_pv+".DDLY",kwargs['detector_settling_time']
+
+    ### triggers
+    def triggers_set(self,scan_dim,trigger_dictionary):
+        """
+        Clear all scan detectors triggers
+        
+        trigger_dictionary = {trigger_num:pv}
+        Previously: Clear_Scan_Triggers
+        """
+        scan_pv = self.ioc+"scan"+str(scan_dim)
+        if len(trigger_dictionary.keys())>0:
+            for tigger_num in  trigger_dictionary.keys():
+                    caput(scan_pv+".T"+str(tigger_num)+"PV",trigger_dictionary[tigger_num])  
+
+    def triggers_clear(self,scan_dim,trigger_dictionary,verbose=True):
+        """
+        Clear all scan detectors triggers
+        
+        Previously: Clear_Scan_Triggers
+        """
+        scan_pv = self.ioc+"scan"+str(scan_dim)
+        inner_scan_trigger = self.ioc+"scan"+str(scan_dim-1)+".EXSC"
+
+        if len(trigger_dictionary.keys())>0:   
+            for dim in range(1,5):
+                if dim==1 and scan_dim>1:
+                    caput(scan_pv+".T1PV",inner_scan_trigger)
+                else:
+                    caput(scan_pv+'.T'+str(dim)+'PV',"")    
+
+    def triggers_reset(self,verbose=True,**kwargs):
+        """
+        sets the  trigger1 to be the lower dim execute, does not change the other triggers
+        does nothing if scan_dim = 1
+        """
+        kwargs.setdefault('scan_dim',1)
+        scan_pv = self.ioc+"scan"+str(kwargs['scan_dim'])
+
+        inner_scan_trigger = self.ioc+"scan"+str(kwargs['scan_dim']-1)+".EXSC"
+        if kwargs['scan_dim'] > 1:
+            caput(scan_pv+".T1PV",inner_scan_trigger)  #Resets the higher dimensional scans to trigger the inner scan
+
+        if verbose:
+            print("Scan record "+self.ioc+"Trigger 1 is reset")
+
+
+    ### checks
+    def check(self,scan_dim):
+        """
+        checks pvs connects and that positioners are within limits
+        """
+        self._check_pvs(scan_dim)
+        if not self._check_limits(scan_dim):
+            print("check positioner limits")
+
+    def _check_pvs(self,scan_dim):
+        """
+        Check if any of the detectors or positions pvs are not connected
+
+        Previously: Scan_Check
+        """
+        print('Checking if all detectors & positioners are connected...')
+        scan_pv = self.ioc+"scan"+str(scan_dim)
+
+        #Detectors
+        for i in range(1,71):
+            det_num=(str(i).zfill(2))
+            det_pv=caget(scan_pv+".D"+det_num+"PV")
+            if det_pv !='': 
+                det=PV(det_pv); time.sleep(0.1)#smallest sleep to allow for PV traffic
+                if not det.connected:
+                    print("Detector "+det_num+" has a bad PV:  "+det.pvname+" not connected")
+        #Positioners
+        for i in range(1,5):
+            pos_num=str(i)
+            pos_pv=caget(scan_pv+".P"+pos_num+"PV")
+            if pos_pv != '': 
+                pos=PV(pos_pv)
+                if not pos.connected:
+                    print("Positioner "+pos_num+" has a BAD PV:  "+pos.pvname+" not connected")
+
+    def _check_limits(self,scan_dim):
+        """
+        checks if the scan parameters are within the limits
+        returns limits_ok (True / False)
+        """
+        scan_pv = self.ioc+"scan"+str(scan_dim)
+        caput(scan_pv+'.CMND',1)
+        time.sleep(.5)
+        SMSG = caget(scan_pv+'SMSG',as_string=True)
+        if len(SMSG) > 0:
+            print_warning_message('Positioner out of limits \n     '+SMSG)
+            limits_ok = False
+        else:
+            limits_ok = True
+    
+
+    ##############################################################################################################
+    #############################          table scans               ##############################
+    ##############################################################################################################  
+    def fillin_table(self,scan_dim,val_pv,rbv_pv,myarray,**kwargs):
+        """
+        Fills in the scan record for table scans given positioner=posNum
+        myarray can be generated by myarray=Scan_MakeTable(StartStopStepLists)
+
+        kwargs:
+            positioner_num: default => 1
+            detector_settling_time: 
+            positioner_settling_time
+
+        Previously: Scan_FillIn_Table
+        """
+        kwargs.setdefault("positioner_num",1)
+        kwargs.setdefault('detector_settling_time',default_detector_settling_time)
+        kwargs.setdefault('positioner_settling_time',default_positioner_settling_time)
+
+        self.progress(scan_dim)
+
+        scan_pv = self.ioc+"scan"+str(scan_dim)
+        posNum = kwargs['positioner_num']
+
+        caput(scan_pv+".P"+str(posNum)+"SM","TABLE") 
+        caput(scan_pv+".P"+str(posNum)+"PV",val_pv)         #Drive
+        caput(scan_pv+".R"+str(posNum)+"PV",rbv_pv)         #Read  
+        caput(scan_pv+".P"+str(posNum)+"PA",myarray)
+        caput(scan_pv+'.NPTS',len(myarray))    
+
+        self.detector_settling_time(scan_dim,kwargs['detector_settling_time']) 
+        self.positioner_settling_time(scan_dim,kwargs['positioner_settling_time'])
+        
+        #checking that PVs and positioner limits are good
+        self.check(scan_dim)
+  
+    def table_reset_after(self,scan_dim):
+        """
+        resets positioner settling time 0.1
+        sets all positionitonser to linear
+        clears positioners
+
+        Previously: Scan_Reset_AfterTable
+        """
+        #Setting everything back
+        scan_pv = self.ioc+"scan"+str(scan_dim)
+
+        self.detector_settling_time(self.ioc,scan_dim) 
+
+        for i in range(1,5):
+            caput(scan_pv+".P"+str(i)+"SM","LINEAR") 
+
+        self.positioners_clear(self.ioc,scan_dim)
+
+    ##############################################################################################################
+    #############################         progress, go and abort             ##############################
+    ##############################################################################################################
+    def progress(self,scan_dim,verbose=True):
+        """
+        Checks if a scan is in progress, and sleeps until it is done
+        
+        pv now includes the full 29idARPES:
+        Previously: Scan_Progress
+        """
+        pv = self.ioc+"scan"+str(scan_dim)
+        check=caget(pv+".FAZE")
+        while (check!=0):
+            if verbose:
+                print(pv+" in progress - please wait...")
+            time.sleep(30)
+            check=caget(pv+".FAZE")
+
+    def abort(self):
+        """
+        aborts a scan for the command line
+
+        Previously: Scan_Abort
+        """
+        caput(self.ioc+"AbortScans.PROC",1)
+
+    def go(self,verbose=True,**kwargs):
+        """
+        checks limits and then starts a scan for a given ioc and scan_dim
+        
+        Previously: part of Scan_Go
+        """
+        kwargs.setdefault('scan_dim',1)
+        scan_dim = kwargs['scan_dim']
+
+        self.progress(scan_dim)
+
+        if verbose:
+            for i in range(1,scan_dim+1):
+                drive = caget(self.ioc+"scan"+str(i)+".P1PV")
+                start = caget(self.ioc+"scan"+str(i)+".P1SP")
+                stop  = caget(self.ioc+"scan"+str(i)+".P1EP")
+                step  = caget(self.ioc+"scan"+str(i)+".P1SI")
+                print('Scan'+str(i)+': '+drive+'= '+str(start)+' / '+str(stop)+' / '+str(step))
+        
+        if self._check_limits(scan_dim):
+            filename = self.prefix(self.ioc)
+            fileNum  = self.fileNum(self.ioc)
+            print(filename+str(fileNum)+" started at ", dateandtime())
+            scan_pv = self.ioc+"scan"+str(scan_dim)
+            caput(scan_pv+".EXSC",1,wait=True,timeout=900000)  #pushes scan button
+            log_update() # writes the log file
+            print(filename+str(fileNum)+" finished at ", dateandtime())
+            print('\n')
+            
+
+    ##############################################################################################################
+    #############################          empty and time scans               ##############################
+    ##############################################################################################################
+ 
+
+    def empty_scan(self,**kwargs):
+        """
+        starts a scan with out a drive
+
+        Previously: Scan_Empty_Go
+        """
+        kwargs.setdefault('execute',True)
+        self.fillin("","",0,1,1,**kwargs)   
+        if kwargs['execute']:
+            self.go(**kwargs)
+ 
+    def time_scan(self,duration_min,step_sec,**kwargs):
+        """
+        starts a scan with the readback as time in seconds
+
+        **kwargs
+            trigger_dictionary = {1:'29idb:ca5:read'} (default)
+        
+        Previously: Scan_Time_Go
+        """
+
+        stop=duration_min*60.0/step_sec
+        self.fillin("","time",1,stop,1,**kwargs)
+
+        print("Time scan - Settling time : "+str(step_sec))
+        if kwargs['execute']:
+            self.go(**kwargs)
+
+    ##############################################################################################################
+    #############################    2D scans typewriter/snake scans               ##############################
+    ##############################################################################################################
+    def fillin_2D(self,inner_loop_list,outer_loop_list,outer_scan_dim=2,**kwargs):
+        """
+        Fills in a the Scan Record for a 2D scan (Mesh),
+        InnerMotorList=[val_pv1,rbv_pv1,start1,stop1,step1] #scanDIM=1
+        OuterMotorList=[val_pv2,rbv_pv2,start2,stop2,step2] #scanDIM=2
+        kwargs:
+            num_points: False (default) => steps_points is the step size
+                        True => steps_points is the number of points
+            positioner_num: default => 1
+            detector_settling_time: default => 0.1
+            snake: coming soon            
+        """
+        kwargs.setdefault("snake",False)
+        
+        #fillin inner loop
+        kwargs.update({'scan_dim':outer_scan_dim-1})
+        self.fillin(inner_loop_list[0],inner_loop_list[1],inner_loop_list[2],inner_loop_list[3],inner_loop_list[4],**kwargs)
+        #fillin outer loop
+        kwargs.update({'scan_dim':outer_scan_dim})
+        self.fillin(outer_loop_list[0],outer_loop_list[1],outer_loop_list[2],outer_loop_list[3],outer_loop_list[1],**kwargs)
+
+
+
+    def snake_pv(self,snake_dim,enable=True):
+        """
+        used for snake scans (as opposed to typewriter scans)
+        """
+        snake_proc = self.snake_scan_userCalcOut(self.ioc,snake_dim=snake_dim,calc_num=1,enable=enable)
+        return snake_proc
+
+
+    def snake_scan_userCalcOut(self,snake_dim=1,calc_num=1,enable=False):
+        """
+        for snake scans you need to add this userCalcOut to the after scan
+        it multiplies the step of the inner scan by -1 
+
+        return the userCalcOut.PROC pv
+        """
+        snake_calc_pv = self.ioc+"userCalcOut"+str(calc_num) #Snake userCalc
+        caput(self.ioc+"userCalcOutEnable.VAL",1) #global enable for userCalcs
+        
+        step_pv  = self.ioc+"scan"+str(snake_dim)+".P1SI"
+        ### Setting up the user
+        caput(snake_calc_pv+".DESC","Snake Calc")
+        caput(snake_calc_pv+".INPA",step_pv+" NPP NMS")
+        caput(snake_calc_pv+".CALC$","A*-1*B")
+        caput(snake_calc_pv+".OUT",step_pv+" PP NMS")
+
+        if enable:
+            caput(snake_calc_pv+".B",1)
+        else:
+            caput(snake_calc_pv+".B",0)
+
+        return snake_calc_pv+".PROC"
\ No newline at end of file
diff --git a/build/lib/iexcode/instruments/scratch.py b/build/lib/iexcode/instruments/scratch.py
new file mode 100644
index 0000000000000000000000000000000000000000..ded5e799532a9f085e7e81f233ff0d2a7e4267a8
--- /dev/null
+++ b/build/lib/iexcode/instruments/scratch.py
@@ -0,0 +1,44 @@
+##############################################################################################################
+##############################                 setting folder          from ARPES         ##############################
+##############################################################################################################
+def folders_ARPES(user_name,**kwargs):
+    """
+    Create and sets (if create_only=False) all the folders the current run and ARPES user 
+    Sets the FileName for logging to be "UserName/YYYYMMDD_log.txt using logname_Set()"
+    
+    **kwargs:
+        set_folders = True (default); set the mda and EA scanRecords
+                    = False; only makes the folders (was create_only)
+        run: run cycle e.g. 2022_1 (default => check_run() )
+        ftp = True / False (default); print what needs to be added to the ftps crontab and create additional ftp folders
+        mda_ioc: will overwrite the default ioc for mda scans
+        debug
+           
+    """
+    kwargs.setdefault('set_folders',True)
+    kwargs.setdefault('run',check_run())
+    kwargs.setdefault('ftp',False)
+    kwargs.setdefault('debug',False)
+
+    run = kwargs['run']
+
+    if kwargs['debug']:
+        print("run,folder,user_name,ioc,ftp: ",run,BL.folder,user_name,BL.ioc,kwargs['ftp'])
+
+    # Create User Folder:
+    make_user_folders(run,BL.folder,user_name,BL.endstation,ftp=kwargs['ftp'])
+    sleep(5)
+
+    if kwargs["set_folders"]:
+        # Set up MDA folder:
+        folder_mda(run,BL.folder,user_name,BL.prefix,BL.ioc)
+        logfile_name_set(BL.endstation)
+        logfile_header(BL.endstation,BL.ioc,ARPES_log_header())
+
+        
+        #Set up Scienta folders:
+        try:
+            userPath = "/net/s29data/export/data_29id"+BL.folder+"/"+run+"/"+user_name+"/"
+            folders_EA(userPath,filePrefix="EA")
+        except:
+            print_warning_message("EA ioc is not running, cannot set folder")
\ No newline at end of file
diff --git a/build/lib/iexcode/instruments/shutters.py b/build/lib/iexcode/instruments/shutters.py
new file mode 100644
index 0000000000000000000000000000000000000000..2afd8422a141b6b3b7b8467d8a6ef7b50ecc94e7
--- /dev/null
+++ b/build/lib/iexcode/instruments/shutters.py
@@ -0,0 +1,112 @@
+"""
+main shutter and branch shutter functions
+"""
+from time import sleep
+from epics import caget, caput
+
+from iexcode.instruments.utilities import dateandtime, print_warning_message
+
+
+##############################################################################################################
+################################             main shutter             ##############################
+##############################################################################################################
+
+def main_shutter_open():
+    """
+    opens the main shutter
+
+    Previously: Open_MainShutter 
+    """
+    caput("PC:29ID:FES_OPEN_REQUEST.VAL",1, wait=True,timeout=180000)
+    print("Opening Main Shutter...")
+
+def main_shutter_close():
+    """
+    closes the main shutter
+
+    Previously: Close_MainShutter
+    """
+    caput("PC:29ID:FES_CLOSE_REQUEST.VAL",1,wait=True,timeout=18000)
+    print("Closing Main Shutter...")
+
+def main_shutter_status():
+    """
+    checks on the status of the main shutter
+    and returns shutter_open = True / False
+
+    """
+    SS1=caget("EPS:29:ID:SS1:POSITION")
+    SS2=caget("EPS:29:ID:SS2:POSITION")
+    PS2=caget("EPS:29:ID:PS2:POSITION")
+    check=SS1*SS2*PS2
+
+    if check == 8:
+        shutter_open = True
+    else:
+        shutter_open = False
+    
+    return shutter_open
+
+
+def main_shutter_check_open():
+    """
+    Checks main shutter is open, if not opens it"
+    
+    Previously: Check_MainShutter
+    """
+    while True:
+        shutter_open = main_shutter_status()
+        if shutter_open == False:
+            print("MAIN SHUTTER CLOSED !!!" , dateandtime())
+            main_shutter_open()
+            sleep(10)
+        else:
+            print("Shutter is now open" , dateandtime())
+            break
+##############################################################################################################
+################################             branch shutters            ##############################
+##############################################################################################################
+
+def branch_shutter_status(branch,verbose=False):
+    """
+    checks on the status of the main shutter
+    and returns shutter_open = True / False
+    """
+    pvA="PA:29ID:S"+branch+"S_BLOCKING_BEAM.VAL"
+    pvB="PB:29ID:S"+branch+"S_BLOCKING_BEAM.VAL"
+    #"ON" = 1 => shutter open
+    status=caget(pvA)+caget(pvA)
+    if status == 2:
+        shutter_open=True
+    else:
+        shutter_open=False
+
+    if verbose:
+        status = 'Open' if shutter_open else 'Closed'
+        print(branch+"-shutter is "+status)
+    return shutter_open
+
+def branch_shutter_close(branch):
+    """
+    closes current branch shutter
+
+    Previously: Close_BranchShutter
+    """
+    caput("PC:29ID:S"+branch+"S_CLOSE_REQUEST.VAL",1,wait=True,timeout=18000)
+    print("Closing "+branch+"-Shutter...")
+
+
+def branch_shutter_open(branch):
+    """
+    Opens current branch shutter 
+
+    Previoulsy: Open_BranchShutter
+
+    """
+    shutter_status = branch_shutter_status
+    if shutter_status:
+        print(branch+"-Shutter already open...")
+    else:
+        caput("PC:29ID:S"+branch+"S_OPEN_REQUEST.VAL",1,wait=True,timeout=18000)
+        print("Opening "+branch+"-Shutter...")
+        
\ No newline at end of file
diff --git a/build/lib/iexcode/instruments/slits.py b/build/lib/iexcode/instruments/slits.py
new file mode 100644
index 0000000000000000000000000000000000000000..1b323e3ead9d82e35929bd013f277f8cfc7b3bd3
--- /dev/null
+++ b/build/lib/iexcode/instruments/slits.py
@@ -0,0 +1,509 @@
+from numpy import inf,nan
+
+from epics import caget, caput
+from .IEX_endstations import *
+
+
+from iexcode.instruments.shutters import main_shutter_close
+from iexcode.instruments.utilities import print_warning_message, read_dict
+from iexcode.instruments.VLS_PGM import mono_get_all
+from iexcode.instruments.encoders import encoders_reset
+
+slit_ioc="29idb:"
+
+def slits_dictionary():
+    """
+    dictionary of slit pv names for two and four blade slit assemblies
+
+    slit_name = slit1A, slit2B, slit3D
+    """
+    #'slit3C' : (None, "uses a flexure stage so is different"),
+    
+    d = {
+        'slit1A' : ('Slit1H','Slit1V'),
+        'slit2B' : ('Slit2H','Slit2V'),
+        'slit3D' : ('Slit4V')
+        }
+    return d
+
+def slits_pvs(slit_name):
+    """
+    returns the rbv and drive for the size,center
+    (rbv_size,val_size),(rvb_center,val_center)
+    """
+    slit_pv = slit_ioc + slit_name
+    size_rbv = slit_pv +'t2.D'
+    size_val = slit_pv +'center.VAL'
+    center_rbv = slit_pv +'t2.C'
+    center_val = slit_pv +'center.VAL'
+
+    return (size_rbv,size_val),(center_rbv,center_val)
+
+def slits_synch(slit_name):
+    """
+    synch the motor position and the slit table for all the beamline slits
+    """
+    slit_pv = slit_ioc + slit_name+'sync.PROC'
+    caput(slit_pv,1)
+
+def slits_sync_all():
+    """
+    synch the motor position and the slit table for all the beamline slits
+    Slit-1A, slit-2B, slit-3C, slit-3D
+
+    Previously: SyncAllSlits
+    """
+    slit_list = slits_dictionary()
+    for slit_name in slit_list.keys():
+        slits_synch(slit_name)
+
+def slits_print_all():
+    """
+    gets the current position of slit-1A, slit-2B, slit-3C, slit-3D
+
+    Previously Get_Slits
+    """
+    slits_sync_all()
+    slit1A_get(verbose=True)
+    slit2B_get(verbose=True)
+
+    slit3C_get(verbose=True)
+    slit3D_get(verbose=True)
+
+def slits_get_all(verbose=False):
+    """
+    returns a dictionary with the current slit status
+    """
+    vals = {}
+    vals['slit1A_size'], vals['slit1A_center'] = slit1A_get(verbose=False)
+    vals['slit2B_size'], vals['slit2B_center'] = slit2B_get(verbose=False)
+    vals['slit3C_size'] = slit3C_get(verbose=False)
+    vals['slit3D_size'],vals['slit3D_center'] = slit3D_get(verbose=False)
+
+    if verbose:
+        slits_print_all()
+    return vals
+
+def slits_set(slit_name,size,center,verbose=True):
+    """
+    synchs the slit motors and the slit table and then sets the center and size
+    
+    slit_name is key in slits_dictionary
+    size = (H_size, V_size) 
+    center = (H_center, V_center)
+    
+    Previously: SetSlit
+    """
+    d = slits_dictionary()
+    #syncing
+    slits_synch(slit_name)
+
+    for i,slit_HV in enumerate(d[slit_name]): #H and V
+        (size_rbv,size_val),(center_rbv,center_val) = slits_pvs(slit_HV)
+        caput(size_val, size[i],timeout=180)
+        caput(center_val, center[i],timeout=180)
+
+    if verbose:
+        if (d[slit_name])>1:
+            print(slit_name + " = ("+str(round(size[0],3))+"x"+str(round(size[1],3))+") @ ("+str(center[0])+","+str(center[1])+")")
+        else:
+            print(slit_name + " = ("+str(round(size[0],3))+") @ ("+str(center[0])+")")
+
+    return size,center
+
+
+def slits_get(slit_name,verbose=True):
+    """
+    returns the current H_size,V_size,H_center,V_center
+    
+    """
+    d=slits_dictionary()
+    size = []
+    center = []
+
+    #syncing
+    slits_synch(slit_name)
+
+    for slit_HV in d[slit_name]: #H and V
+        (size_rbv,size_val),(center_rbv,center_val) = slits_pvs(slit_HV)
+        size.append(caget(size_rbv))
+        center.append(caget(center_rbv))
+
+    if verbose:
+        if (d[slit_name])>1:
+            print(slit_name + " = ("+str(round(size[0],3))+"x"+str(round(size[1],3))+") @ ("+str(center[0])+","+str(center[1])+")")
+        else:
+            print(slit_name + " = ("+str(round(size[0],3))+") @ ("+str(center[0])+")")
+
+    return tuple(size),tuple(center)
+
+def slits_set_size(slit_name,size):
+    """
+    sets the slit size with the current slit center
+
+    size = (H,V) for slit1A, slit2B
+    size = V for slit3D
+    """
+    size_current,center = slits_get(slit_name,verbose=False)
+    slits_set(size,center)
+
+def slits_set_center(slit_name,center):
+    """
+    sets the slit size with the current slit center
+
+    center = (H,V) for slit1A, slit2B
+    center = V for slit3D
+    """
+    size,center_current = slits_get(slit_name,verbose=False)
+    slits_set(size,center)
+
+def slits_scan_size(slit_name,direction,start,stop,step,**kwargs):
+    """
+    slit_name = 'slit1A','slit2B','slit3D'
+    direction = 'H', 'V'
+    **kwargs
+        center: slits center,  if not specified then uses current center position
+    """
+    kwargs.setdefault('center',slits_get(slit_name,verbose=False)[1])
+    kwargs.setdefault('execute',True) 
+
+    slit_H,slit_V = slits_dictionary()[slit_name]
+       
+    if direction == 'H':
+        (size_rbv,size_val),(center_rbv,center_val) = slits_pvs(slit_H)
+    if direction == 'V':
+        (size_rbv,size_val),(center_rbv,center_val) = slits_pvs(slit_V)
+
+    #set slit center
+    slits_set_center(slit_name,kwargs['center'])
+    #scan
+    BL.mda.fillin(size_rbv,size_val,start,stop,step,**kwargs)
+    if kwargs['execute']:
+        BL.mda.go(**kwargs)
+
+def slits_scan_center(slit_name,direction,start,stop,step,**kwargs):
+    """
+    slit_name = 'slit1A','slit2B','slit3D'
+    direction = 'H', 'V'
+    **kwargs
+        size: slits size, if not specified then uses current size
+    """
+    kwargs.setdefault('size',slits_get(slit_name,verbose=False)[0])
+    kwargs.setdefault('execute',True) 
+
+    slit_H,slit_V = slits_dictionary()[slit_name]
+
+    if direction == 'H':
+        (size_rbv,size_val),(center_rbv,center_val) = slits_pvs(slit_H)
+    if direction == 'V':
+        (size_rbv,size_val),(center_rbv,center_val) = slits_pvs(slit_V)
+    
+    #set slit center
+    slits_set_size(slit_name,kwargs['size'])
+    #scan
+    BL.mda.fillin(center_rbv,center_val,start,stop,step,**kwargs)
+    if kwargs['execute']:
+        BL.mda.go(**kwargs)
+
+def slit1A_scribe_marks():
+    """
+    moves slit1A to the position which corresponds to the scribe marks
+    used to check if we have lost steps
+    
+    Dial values should be 0 on when on the scribe marks
+    User values are set to correspond to the center of the beam
+
+    Previously: GoToSlit1AScribe
+    """
+    main_shutter_close()
+    for m in range(9,13):
+        caput('29idb:m'+str(m)+'.DVAL',0) 
+    
+def slit1A_set(H_size,V_size,verbose=True,**kwargs):
+    """
+    sets the first aperture / slit to the specificed size
+    if Hsize / Vsize = inf then goes to maximim 4.5 / 4.5
+    **kwargs
+        center = slit center, by default => (0,0)
+
+    Previously: SetSlit1A
+    """
+    kwargs.setdefault('center',(0,0))
+    slit_name = 'slit1A'
+
+    if H_size in [inf,nan,None]: 
+        H_size=4.5
+    if V_size in [inf,nan,None]: 
+        V_size=4.5
+
+    size = (H_size,V_size)
+    center = kwargs['center']
+    slits_set(slit_name,size,center, verbose=verbose)
+ 
+def slit1A_get(verbose=True):
+    """
+    returns the current (H_size,V_size),(H_center,V_center)
+    """
+    slit_name = "slit1A"
+ 
+    return  slits_get(slit_name,verbose=verbose)
+
+def slit2B_set(H_size,V_size,verbose=True,**kwargs):
+    """
+    sets the clean up aperture / slit downstream of the mono to the specificed size
+    if Hsize / Vsize = inf then goes to maximim 6 / 8
+    
+    **kwargs
+        center = slit center, by default => (0,0)
+
+    Previously: SetSlit2B
+    """   
+    kwargs.setdefault('center',(0,0))
+    slit_name = "slit2B"
+
+    if H_size in [inf,nan,None]: 
+        H_size=6
+    if V_size in [inf,nan,None]: 
+        V_size=8
+
+    size = (H_size,V_size)
+    center = kwargs['center']
+    slits_set(slit_name,size,center, verbose=verbose)
+
+def slit2B_set_small(Hsize,Vsize,coef,verbose=True,**kwargs):
+    """
+    Used to scale the aperature size by coef
+        Hsize = Hsize * coef
+        Vsize = Vsize * coef
+    """
+    Hsize = Hsize * coef
+    Vsize = Vsize * coef
+    print_warning_message("closing Slit-2B down by a factor of", coef, "!!!")
+    slit2B_set(Hsize,Vsize,verbose=True,**kwargs)
+  
+def slit2B_get(verbose=True):
+    """
+    returns the current (H_size,V_size),(H_center,V_center)
+    """
+    slit_name = "slit2B"   
+    return  slits_get(slit_name,verbose=verbose)
+
+def slit2B_encoders_reset(Hcenter,Vcenter):
+    """
+    Resetting Slit 2B encoders to 0 for a given position (Hcenter,Vcenter).
+    Slit size need to be set to 0.
+
+    Previously: Reset_Slit2B_Encoders
+    """
+    encoders_reset('slit2B',Hcenter,Vcenter)
+    slits_synch('slit2B')
+
+
+def slit3C_set(size,verbose=True):
+    """
+    sets slit-3C (ARPES resolution defining slit)
+
+    Previously SetSlit3C
+    """
+    position=round(slit_3C_fit(size),1)
+    caput("29idb:Slit3CFit.A",size,wait=True,timeout=18000)
+    
+    if verbose:
+        print("Slit-3C =",size,"um  -  ( m24 =",position,")")
+
+def slit3C_get(size,verbose=True):
+    """
+    gets slit-3C (ARPES resolution defining slit)
+    returns size, position
+    """
+    size, position = slit_3C_rbv()
+    
+    if verbose:
+        print("Slit-3C =",size,"um  -  ( m24 =",position,")")
+
+    return size, position
+
+def slit3D_set(V_size,verbose=True,**kwargs):
+    """
+    sets the clean up aperture / slit downstream of the mono to the specificed size
+    if Hsize / Vsize = inf then goes to maximim 6 / 8
+
+    **kwargs
+        center = slit center, by default => current value
+
+    Previously: SetSlit3D
+    """
+    kwargs.setdefault('center',slit3D_get(verbose=False)[1])           
+    slit_name = "slit3D"
+
+    if V_size in [inf,nan,None]: 
+        V_size=2000
+
+    size = (V_size)
+    center = kwargs['center']
+    slits_set(slit_name,size,center,verbose=verbose)
+
+
+def slit3D_get(verbose=True):
+    """
+    returns the current V_size,V_center
+    """
+    slit_name = "slit1A"
+    (V_size),(V_center) = slits_get(slit_name)
+    V_size = round(V_size,3)
+    V_center = round(V_center,3)
+
+    return  V_size,V_center
+
+def slit3D_encoders_reset(Hcenter,Vcenter):
+    """
+    Resetting Slit 2B encoders to 0 for a given position (Hcenter,Vcenter).
+    Slit size need to be set to 0.
+
+    Previously: Reset_Slit2B_Encoders
+    """
+    encoders_reset('slit3D',Hcenter,Vcenter)
+    slits_synch('slit3D')
+
+def exit_slit(branch, size, verbose=True):
+    """
+    verbose used to supress printing
+
+    Previously: SetExitSlit
+    """
+    if branch == "c":
+        slit3C_set(size, verbose)
+    elif branch == "d":
+        slit3D_set(size, verbose)
+    elif branch == "e":
+        slit3D_set(size, verbose)
+
+
+
+
+
+##############################################################################################################
+################################             slit fits             ##############################
+##############################################################################################################
+
+
+def aperture_fit(hv,slit_num):
+    """
+    used close the beamline apertures/slits to only take the center of the beam, 
+        i.e. no heat bump (determined emperically by looking at the the shift in energy vs slit position)
+
+    Previously Aperture_Fit
+    """
+    K=slit_Coef(slit_num)[1]
+    sizeH=K[0]+K[1]*hv+K[2]*hv*hv
+    sizeV=K[3]+K[4]*hv+K[5]*hv*hv
+    return [round(sizeH,3),round(sizeV,3)]
+
+def slit_Coef(slit_num):
+    """
+    3rd order polynomials coeffients for closing slit1A / slit2B to minimize heat bump effects
+    slit_num = 1 / 2 for slit1A / slit2B
+    """
+    if slit_num == 1:
+        pv='29id:k_slit1A'
+        #Redshifted x (H):
+        H0=2.3325
+        H1=-.000936
+        H2=2.4e-7
+         #Redshifted z (V):
+        V0=2.3935
+        V1=-.0013442
+        V2=3.18e-7
+    if slit_num == 2:
+        pv='29id:k_slit2B'
+        #Redshifted x (H):
+        H0=3.61
+        H1=-0.00186
+        H2=5.2e-7
+        #Redshifted z (V):
+        V0=6.8075
+        V1=-0.003929
+        V2=9.5e-7
+    K=H0,H1,H2,V0,V1,V2
+    return pv,K
+
+
+def slit_3C_fit(size):
+    """
+    used to convert slit size to motor position for slit 3C - flexure stage
+
+    empirically determine offline with a camera
+
+    Previously: Slit3C_Fit
+    """
+    K0=-36.383
+    K1=0.16473
+    K2=-0.00070276
+    K3=8.4346e-06
+    K4=-5.6215e-08
+    K5=1.8223e-10
+    K6=-2.2635e-13
+    motor=K0+K1*size+K2*size**2+K3*size**3+K4*size**4+K5*size**5+K6*size**6
+    return motor
+
+def slit_3C_rbv():
+    """
+    used to convert slit motor position to size
+    
+    Previously: Slit3C_RBV
+    """
+    position=caget("29idb:m24.RBV")
+    K0=299.66
+    K1=16.404
+    K2=1.5572
+    K3=0.14102
+    K4=0.0064767
+    K5=0.00014501
+    K6=1.2617e-06
+    size=round(K0+K1*position+K2*position**2+K3*position**3+K4*position**4+K5*position**5+K6*position**6,0)
+    return size, position
+
+##############################################################################################################
+################################             beamline slits            ##############################
+############################################################################################################## 
+
+def slits_set_BL(c_2B=1,c_1A=1,verbose=True):
+    """
+    Sets slit-1A and slit-2B for the current 
+    grating and photon energy to remove the heat bump
+
+    c_1A and c_2B are used to take a different ratio of the beam 
+    (1 = normal ops, < 1 to reduce flux)
+
+    Previously: SetSlit_BL
+    """
+    mono_vals=mono_get_all()
+    hv_rbv = mono_vals['ENERGY_MON']
+    grt  = mono_vals['GRT']
+    
+    # slit were defined for the range: 500 - 2000
+    hv = max(hv_rbv,500)
+    hv = min(hv_rbv,2000)
+    c = 4.2/2.2 # to account for the magnification difference between gratings
+
+    if grt == 'MEG':
+        V=0.65        #  set to 65% of RR calculation for both grt => cf 2016_2_summary
+    elif grt=='HEG':
+        V=0.65*c        #  set to 65% of RR calculation (no longer 80%) => cf 2016_2_summary
+
+    try:
+        slit_position = read_dict(FileName='Dict_Slit.txt')
+    except KeyError:
+        print_warning_message("Unable to read dictionary")
+        return
+
+    V2_center= slit_position[grt]['S2V']
+    H2_center= slit_position[grt]['S2H']
+    V1_center= slit_position[grt]['S1V']
+    H1_center= slit_position[grt]['S1H']
+
+    Size1A=( aperture_fit(hv,1)[0]*c_1A,       aperture_fit(hv,1)[1]*c_1A )
+    Size2B=( aperture_fit(hv,2)[0]*c_2B, round(aperture_fit(hv,2)[1]*c_2B*V,3))
+    slit1A_set(Size1A[0],Size1A[1],H1_center,V1_center,verbose)    # standard operating
+    slit1A_set(Size2B[0],Size2B[1],H2_center,V2_center,verbose)
+
diff --git a/build/lib/iexcode/instruments/spec_stuff.py b/build/lib/iexcode/instruments/spec_stuff.py
new file mode 100644
index 0000000000000000000000000000000000000000..61cc85925755a39d9b1fa2395e72d18b22c30cf8
--- /dev/null
+++ b/build/lib/iexcode/instruments/spec_stuff.py
@@ -0,0 +1,14 @@
+
+def folders_spec(run,folder,UserName):
+    if folder == "b":
+        UserName = "Staff"
+    else:
+        UserName = UserName+"/"
+    MyPath="/home/beams22/29IDUSER/spec/data/"+run+"/"+UserName
+    print("\nSPEC folder: " + MyPath)
+    print("You will need to create folder and set up the path manually in SPEC:")
+    print("    cd "+MyPath)
+    print("    newfile FileName")
+    print("To start SPEC fresh: ./bin/kappa29ID -f")
+    #if not (exists(MyPath)):
+    #    mkdir(MyPath)
diff --git a/build/lib/iexcode/instruments/staff.py b/build/lib/iexcode/instruments/staff.py
new file mode 100644
index 0000000000000000000000000000000000000000..b9d6eef6b0732753a2c5c190dd1903e2f2d2652c
--- /dev/null
+++ b/build/lib/iexcode/instruments/staff.py
@@ -0,0 +1,82 @@
+from os import listdir,mkdir,chmod
+from os.path import join, isfile, exists
+
+#from .ARPES import folders_ARPES
+#from .Kappa import folders_Kappa
+
+
+def folders_startup(run):
+    """
+    Creates the run directories for the following:
+    data_29idb
+    data_29idc
+    data_29idd
+
+    calls folder_ARPES('Staff');folder_Kappa('Staff')
+
+    print text required to modify the rsynch crontab
+
+    previously: Folders_Startup
+    """
+    data_directories=['data_29idb','data_29idc','data_29idd']
+    dserv="/net/s29data/export/"
+    for dataDir in data_directories:
+        path=join(dserv,dataDir,run)
+        print(path)
+        if not (exists(path)):
+            mkdir(path)
+
+    #folders_ARPES('Staff',create_only=True)
+    #folders_Kappa('Staff',create_only=True)
+
+    txt="\n\n\nupdate the rsync portion the 29id@nerdy crontab\n"
+    txt+="*/1 * * * * /usr/bin/rsync -av --exclude=core /net/s29data/export/data_29idd/"+run+" kip:/net/kip/sftp/pub/29iddftp/files >  /home/beams22/29ID/cronfiles/cptoftp-currrun-d.log 2>&1"
+    txt+=("\n")
+    txt+="*/1 * * * * /usr/bin/rsync -av --exclude=core /net/s29data/export/data_29idd/"+run+" kip:/net/kip/sftp/pub/29iddftp/files >  /home/beams22/29ID/cronfiles/cptoftp-currrun-d.log 2>&1"
+    print(txt)
+
+##############################################################################################################
+##############################                 staff detectors                ##############################
+##############################################################################################################
+
+
+def staff_detector_dictionary(xrays=True):
+    """
+    returns a dictionary of the default detectors
+
+    Previously: Detector_Default
+    """
+    det_dict={}
+    diodes={
+        15:"29idb:ca15:read"
+        }
+    slits_apertures={
+        58:"29idb:Slit1Ht2.C",
+        59:"29idb:Slit1Ht2.D",
+        60:"29idb:Slit1Vt2.C",
+        61:"29idb:Slit1Vt2.D",
+        62:"29idb:Slit2Ht2.C",
+        63:"29idb:Slit2Ht2.D",
+        64:"29idb:Slit2Vt2.C",
+        65:"29idb:Slit2Vt2.D",
+        66:"29idb:Slit3CRBV",
+        67:"29idb:Slit4Vt2.C"
+        }
+    vacuum_shutters={
+        61:"29idb:VS1A.VAL",
+        62:"29idb:VS2A.VAL",
+        63:"29idb:VS3AB.VAL",
+        64:"29idb:VS4B.VAL",
+        65:"29idb:IP4B.VAL",
+        66:"PA:29ID:SCS_BLOCKING_BEAM.VAL",
+        67:"PA:29ID:SDS_BLOCKING_BEAM.VAL"
+        }
+    mono_details={
+        68:"29idmono:ENERGY_SP",
+        69:"29idmonoMIR:P.RBV",
+        70:"29idmonoGRT:P.RBV"
+        }
+    det_dict.update(diodes)
+    det_dict.update(slits_apertures)
+    det_dict.update(mono_details)
+    return det_dict
\ No newline at end of file
diff --git a/build/lib/iexcode/instruments/storage_ring.py b/build/lib/iexcode/instruments/storage_ring.py
new file mode 100644
index 0000000000000000000000000000000000000000..a2269b8e853b181f4efacb0c0be43d4316c028e8
--- /dev/null
+++ b/build/lib/iexcode/instruments/storage_ring.py
@@ -0,0 +1,23 @@
+
+
+"""
+Functions dealing with the storage ring pvs
+
+"""
+from epics import caget
+from time import sleep
+
+from iexcode.instruments.utilities import dateandtime
+
+def wait_for_beam():
+    """
+    Monitors the storage ring current and breaks when the ring current is above 60 mA
+    Checks the status every 30 seconds
+    """
+    while True:
+        SR=caget("S:SRcurrentAI.VAL")
+        if (SR<80):
+            sleep(30)
+        else:
+            print("Beam is back -"+dateandtime())
+            break
\ No newline at end of file
diff --git a/build/lib/iexcode/instruments/userCalcs.py b/build/lib/iexcode/instruments/userCalcs.py
new file mode 100644
index 0000000000000000000000000000000000000000..367ceec1dc83cdd175e6f4547c8021f6d09d117d
--- /dev/null
+++ b/build/lib/iexcode/instruments/userCalcs.py
@@ -0,0 +1,177 @@
+from epics import caget, caput
+##############################################################################################################
+###########################            String Sequences       ######################
+##############################################################################################################
+def userStringSeq_pvs(ioc, seq_num):     
+    """
+    returns the proc pv for a given userStringSeq
+    userStringSeq, proc_pv  
+
+    Previously: BeforeScan_StrSeq, AfterScan_StrSeq
+    """
+    userStringSeq_pv = ioc+"userStringSeq"+str(seq_num)
+    userStringSeq_proc = userStringSeq_pv+".PROC"
+    return userStringSeq_pv, userStringSeq_proc
+
+
+def userStringSeq_clear(ioc,seq_num):
+    """
+    clears the nth suserStringSeq in the specified ioc    
+    
+    Previously: ClearStringSeq
+    """
+    pv=ioc+"userStringSeq"+str(seq_num)
+    caput(pv+".DESC","")
+    for i in range(1,10):
+        caput(pv+".STR"+str(i),"")  
+        caput(pv+".LNK"+str(i),"")
+        caput(pv+".DOL"+str(i),"")
+        caput(pv+".DO"+str(i),0.0)
+        caput(pv+".DLY"+str(i),0.0)
+        caput(pv+".WAIT"+str(i),"NoWait")
+    caput(pv+".STRA","")
+    caput(pv+".LNKA","")
+    caput(pv+".DOLA","")
+    caput(pv+".DOA",0.0)
+    caput(pv+".DLYA",0.0)
+    caput(pv+".WAITA","NoWait")
+    caput(pv+".FLNK","")
+    return pv
+
+##############################################################################################################
+###########################      User CalcsOut         ######################
+##############################################################################################################
+def userCalcOut_clear(ioc,calcOut_num):
+    """
+    clears the nth userCalcOut in the specified ioc
+
+    Previously:ClearCalcOut
+    """
+    pv=ioc+"userCalcOut"+str(calcOut_num)
+    caput(pv+".DESC","")
+
+    for i in ["A","B","C","D","E","F","G","H","I","J","K","L"]:
+        caput(pv+".INP"+i,"")
+        caput(pv+"."+i,0)
+
+    caput(pv+".CALC$","A")
+    caput(pv+".OCAL$","A")
+    caput(pv+".OUT","")
+    caput(pv+".OOPT","On Change")
+    return pv
+
+
+##############################################################################################################
+###########################      User Calcs, User  Average        User  Average         ######################
+##############################################################################################################
+def userAvg_clear(ioc,userAvg_num):
+    """
+    clears the nth userAvg in the specified ioc    
+    
+    Previously: ClearUserAvg
+    """
+    pv = ioc+"userAve"+str(userAvg_num)
+    caput(pv+".DESC","")
+    caput(pv+".INPB","")
+    return pv
+
+def userAvg_pvs(ioc, userAve_num):     
+    """
+    returns the proc pv for a given userStringSeq
+    userStringSeq, proc_pv  
+
+    """
+    userAve_pv = ioc+"userAve"+str(userAve_num)
+    userAve_proc = userAve_pv+".PROC"
+    return userAve_pv, userAve_proc
+
+
+def userAvg_trigger_strSeq(ioc,num,userAvg_num=8):
+    """
+    num = number of userAvg
+    """
+    userAvg_num = 8
+    userAvg_clear(ioc,userAvg_num)
+    str_pv="29id"+ioc+":userStringSeq"+str(userAvg_num)
+    caput(str_pv+".DESC","Average Triggers_"+ioc)
+    if num < 10:
+        str_num = str(num)
+    else:
+        str_num = "A"
+    for userAve_num in range(1,userAve_num+1,1):
+        if userAve_num < 10:
+            userAve_num = str(userAve_num)
+        else:
+            userAve_num = "A"
+        userAve_pv, userAve_proc = userAvg_pvs(ioc, userAve_num)
+        caput(str_pv+".LNK"+userAve_num,userAve_proc+" CA NMS")
+        caput(str_pv+".WAIT"+userAve_num,"After"+str_num)
+
+
+def UserAvg_setup(ioc,userAvg_num,det_num,average_pts,UserAvg_trigger_strSeq_pv,scan_dim=1):
+    """
+    kappa 
+    userAv_num 1->10
+    det_num 61 -> 70
+    Previously:UserAvg
+    """
+    userAvg_pv = ioc+"userAve"+str(userAvg_num)
+    scan_pv = ioc+"scan"+str(scan_dim)
+    det_pv = scan_pv+".D"+str(det_num)+"PV"
+
+    trigger_strSeq_pv,trigger_strSeq_proc = userAvg_trigger_strSeq(ioc)
+
+    if average_pts > 0:
+        caput(scan_pv+".T2PV",trigger_strSeq_proc)     #set all Avg as Det
+        caput(userAvg_pv+".A",average_pts)
+        caput(det_pv,userAvg_pv+".VAL")
+        print("User Average enabled")
+    elif average_pts == 0:
+        caput(scan_pv+".T2PV","")
+        caput(det_pv,"")
+        print("User Average disabled")
+
+
+def userAvg_setup(ioc,pv,userAvg_num,name,average_pts=10,mode="ONE-SHOT"):
+    """
+    
+    Previously: UserAvg_PV
+    """
+    trigger_strSeq_pv,trigger_strSeq_proc = userAvg_trigger_strSeq(ioc)
+    
+    # Fill User Average:
+    userAvg_clear(ioc,userAvg_num)
+    userAve_pv, userAve_proc = userAvg_pvs(ioc, userAvg_num)
+
+    caput(userAve_pv+".SCAN","Passive")
+    caput(userAve_pv+".INPB",trigger_strSeq_pv+" CP NMS")
+    caput(userAve_pv+".A",average_pts)
+    caput(userAve_pv+".PREC",9)
+    caput(userAve_pv+"_mode.VAL",mode)
+    caput(userAve_pv+"_algorithm.VAL","AVERAGE")
+    caput(userAve_pv+".DESC",name)    
+
+
+def userAvg_trigger_strSeq(ioc,num, seq_num=8):
+    """
+    
+    Previously: UserAvg_Trigger_StrSeq
+    """
+    userStringSeq_clear(ioc,seq_num)
+    trigger_strSeq_pv,trigger_strSeq_proc = userStringSeq_pvs(ioc, seq_num)
+    caput(trigger_strSeq_pv+".DESC",ioc+" Average Triggers")
+
+    if num < 10:
+        str_num=str(num)
+    else:
+        str_num="A"
+    for i in range(1,num+1,1):
+        if i < 10:
+            i=str(i)
+        else:
+            i="A"
+        avg_pv="29id"+ioc+":userAve"+i
+        caput(trigger_strSeq_pv+".LNK"+i,avg_pv+"_acquire.PROC CA NMS")
+        caput(trigger_strSeq_pv+".WAIT"+i,"After"+str_num)
+
+    return trigger_strSeq_pv,trigger_strSeq_proc
\ No newline at end of file
diff --git a/build/lib/iexcode/instruments/utilities.py b/build/lib/iexcode/instruments/utilities.py
new file mode 100644
index 0000000000000000000000000000000000000000..3e4b739171c309dee52bff4b64bcfba7f6fedf8d
--- /dev/null
+++ b/build/lib/iexcode/instruments/utilities.py
@@ -0,0 +1,213 @@
+"""
+useful functions
+
+"""
+import time
+import datetime
+import select
+import sys
+import ast
+import os
+import numpy as np
+from numpy import inf
+
+from epics import caget, caput
+
+def dateandtime():
+    return time.strftime("%a %d %b %Y %H:%M:%S",time.localtime())
+ 
+def today(which='default'):
+    dt=datetime.date.today()
+    today_year = dt.year
+    today_month = dt.month
+    today_day = dt.day
+    if which == 'slash':
+        today_str=("{:02d}/{:02d}/{:04d}".format(today_month,today_day,today_year))
+    elif which == 'int':
+        today_str=int(("{:04d}{:02d}{:02d}".format(today_year,today_month,today_day)))
+    else: # 'default':
+        today_str=("{:04d}{:02d}{:02d}".format(today_year,today_month,today_day))
+    return today_str 
+
+
+def print_warning_message(message_string):
+     print('\n==================================')
+     print("WARNING: " +message_string+ " !!!!! ")
+     print('==================================\n')
+
+
+def wait_for_it(D,H,M):
+    """
+    D = how many days from now
+    H,M = what time that day in 24h clock
+
+    e.g.: if today is           Wed Nov 21 at 14:00
+        WaitForIt(2,9,0) => Fri Nov 23 at  9:00
+    """
+    t = datetime.datetime.now()()
+    day = datetime.timedelta(days=D)
+    future = t + day
+    returnTime = datetime.datetime(future.year, future.month, future.day, int(H), int(M))
+    timeToWait = returnTime - t
+    s=round(timeToWait.total_seconds(),1)
+    m=round(timeToWait.total_seconds()/60.0,1)
+    h=round(timeToWait.total_seconds()/3600.0,1)
+    print("Now is:      "+str(t))
+    print("Target date: "+str(returnTime))
+    print("Sleeping for "+str(s)+" s = "+str(m)+" m = "+str(h)+" h")
+    print("Waaaaaaaait for it...")
+    time.sleep(timeToWait.total_seconds())
+    print(dateandtime())
+
+    
+def input_timeout(question,t):
+    print("You have "+str(t)+" seconds to answer!")
+    i, o, e = select.select( [sys.stdin], [], [], t )
+    if (i):
+        print("You said", sys.stdin.readline().strip())
+    else:
+        print("You said nothing!")
+
+def playsound(sound='FF'):
+    """
+    plays a sound when run
+    'FF' Final Fantasy victory sound
+    'ding' a subtle ding noise
+    'hallelujah' hallelujah chorus
+    """
+    if sound == 'FF':
+        sounds = '/home/beams/29IDUSER/Documents/User_Macros/Macros_29id/Sound_Files/VictoryFF.wav'
+    elif sound == 'ding':
+        sounds = '/home/beams/29IDUSER/Documents/User_Macros/Macros_29id/Sound_Files/ding.wav'
+    elif sound == 'hallelujah':
+        sounds = '/home/beams/29IDUSER/Documents/User_Macros/Macros_29id/Sound_Files/hallelujah.wav'
+    os.system('aplay ' + sounds)
+
+def RangeUp(start,end,step):
+    while start <= end:
+        yield start
+        start += abs(step)
+
+def RangeDown(start,end,step):
+    while start >= end:
+        yield start
+        start -= abs(step)
+
+def EgForLoop():
+    for hv in RangeDown(2000,500,-500):
+        print(hv)
+    for hv in RangeUp(500,2000,500):
+        print(hv)
+
+def take_closest_value(my_list,my_number):
+    """
+    Given a list of integers, I want to find which number is the closest to a number x.
+    
+    Previously: TakeClosest
+    """
+    return min(my_list, key=lambda x:abs(x-my_number))
+
+def read_dict(filename,**kwargs):
+    """
+    filename = name with extension of dictionary to read
+        **kwargs:
+            path = path to folder containing dictionary file (default: .IEX_dictionaries)
+    """ 
+    if 'path' in kwargs:
+        path = kwargs['path']
+    else:
+        path = os.path.join(os.path.dirname(__file__),'IEX_dictionaries')
+    fpath = os.path.join(path,filename)
+    with open(fpath) as f:
+        for c,line in enumerate(f.readlines()):
+            if line[0] == '=':
+                lastdate=line[8:16]
+            lastline=line
+        mydict=ast.literal_eval(lastline)
+    return mydict
+
+    
+def make_table(start_stop_step_lists):
+    """
+    Creates and returns a np.array with values based on StartStopStepList
+    StartStopStepList is a list of lists defining regions for a table array
+              StartStopStepList[[start1,stop1,step1],[start1,stop1,step1],...]
+    Automatically removes duplicates and sorts into ascending order
+    if you want descending
+               myarray=XAS_Table(StartStopStepLists)[::-1]
+
+    Previously: Scan_MakeTable           
+    """
+    table_array=np.array([])
+    if type(start_stop_step_lists) is not list:
+        start = start_stop_step_lists[0]
+        stop = start_stop_step_lists[1]
+        step = start_stop_step_lists[2]
+        j = start
+        while j<=stop:
+            table_array=np.append(table_array, j)
+            j+=step
+    else:
+        for i in range(0,len(start_stop_step_lists)):
+            start=start_stop_step_lists[i][0]
+            stop=start_stop_step_lists[i][1]
+            step=start_stop_step_lists[i][2]
+            j=start
+            while j<=stop:
+                table_array=np.append(table_array, j)
+                j+=step
+    table_array=np.unique(table_array)#removing duplicate
+    table_array=np.sort(table_array) #sort into ascending order    
+    return table_array
+
+
+
+def SendText(msg,which='user'):
+    """
+    
+    which = 'user' or 'staff'
+    
+    Edit the following file with the correct email/phone number:
+        [sleepy /home/beams22/29ID/bin] pvMailSomething        # for staff
+        [sleepy /home/beams22/29IDUSER/bin] pvMailUser        # for user
+        
+    Use the following website to figure out carriers email:
+        https://20somethingfinance.com/how-to-send-text-messages-sms-via-email-for-free/
+    
+    In a terminal, run the screen session:
+        pvMailUser (or pvMailSomething)
+        
+    To kill the screen session:
+        screen -ls                         #show list of screen session
+        screen -r screen#              #reattached to a given screen session
+        screen -XS screen# kill         #kill a given screen session
+        
+
+    """
+    if which == 'staff':n='6'
+    elif which == 'user':n='7'
+    caput('29idb:userCalcOut'+n+'.DESC',msg)
+    caput('29idb:userCalcOut'+n+'.A',0)
+    time.sleep(1)
+    caput('29idb:userCalcOut'+n+'.A',1)
+    print('Sending text/email')
+
+
+def AbortScript():
+    """
+    Example:
+        while True:
+                try:
+                print 'do something'
+                sleep(5)
+                except KeyboardInterrupt:
+                if AbortScript() == 'y':
+                        break
+    """
+    try:
+        print('\n\nWARNING: Do you want to abort?')
+        print('Type y to ABORT, anything else to CONTINUE >')
+        foo = input()
+        return foo
+    except KeyboardInterrupt as e:
+        raise e
diff --git a/build/lib/iexcode/instruments/vortexs29.py b/build/lib/iexcode/instruments/vortexs29.py
new file mode 100644
index 0000000000000000000000000000000000000000..81deb7330942fbeaeb31d6e092c9fbceeb878a78
--- /dev/null
+++ b/build/lib/iexcode/instruments/vortexs29.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+
+from epics import caget, caput
+from time import sleep, gmtime, strftime, localtime
+
+#Define caput with wait function
+def caputw(PVname,PVinput):
+    return caput(PVname,PVinput,wait=True, timeout = 100000)
+
+def dateandtime():
+    return strftime("%a %d %b %Y %H:%M:%S",localtime())
+
+def vortex(energy,time=1):
+    cen, wid = vortex_Ecal(energy)
+    set_roi1(cen,wid)
+     
+def set_roi1(cen,wid):
+    caput('29idVORTEX:mca1.R0LO',round(cen-wid/2))
+    caput('29idVORTEX:mca1.R0HI',round(cen+wid/2))
+    
+def set_roi2(cen,wid):
+    caput('29idVORTEX:mca1.R1LO',round(cen-wid/2))
+    caput('29idVORTEX:mca1.R1HI',round(cen+wid/2))
+    
+def vortex_Ecal(energy):
+    cen = 12.8 + 0.72*energy
+    wid = 120
+    return cen, wid
+
+def mcacounttime(time):
+    caput('29idVORTEX:mca1.PRTM',time)
+    
+def runmca(time):
+    caput('29idVORTEX:mca1.PRTM',time)
+    sleep(0.1)
+    caputw('29idVORTEX:mca1EraseStart',1)
+    
+def mcaoff():
+    caput('29idd:Unidig1Bo1',1)
+    
+def mcaon():
+    caput('29idd:Unidig1Bo1',0)
+
+def savemca():
+    caput('29idKappa:scan1.T2PV','29idVORTEX:scanH.EXSC')
+    caput('29idKappa:scan1.D16PV','29idVORTEX:mca1.R0')
+    caput('29idKappa:scan1.D17PV','29idVORTEX:mca1.R1')
+    caput('29idKappa:scan1.D49PV','29idd:userTran1.D')
+    caput('29idKappa:scan1.D50PV','29idd:userTran1.E')
+    sleep(1)
+    
+def nosavemca():
+    caput('29idKappa:scan1.T2PV','29idVORTEX:mca1EraseStart')
+    caput('29idKappa:scan1.D16PV','29idVORTEX:mca1.R0')
+    caput('29idKappa:scan1.D17PV','29idVORTEX:mca1.R1')
+    caput('29idKappa:scan1.D49PV','29idd:userTran1.D')
+    caput('29idKappa:scan1.D50PV','29idd:userTran1.E')
+    sleep(1)
+    
+def nomca():
+    caput('29idKappa:scan1.T2PV','')
+    caput('29idKappa:scan1.D16PV','')
+    caput('29idKappa:scan1.D17PV','')
+    caput('29idKappa:scan1.D49PV','')
+    caput('29idKappa:scan1.D50PV','')
+    sleep(1)
+    
+    
+def scan_num():
+    scan = caget('29idKappa:saveData_message')
+    loc = scan.find('.')
+    if (loc==-1):
+        scannum=0
+    else:
+        scannum =int(scan[loc-4:loc])
+    return scannum
+    
+def mcafileinit():
+   # mainpath = '/net/s4data/export/sector4/4idc/mda'
+     scanrecpath = caget('29idKappa:saveData_subDir')
+     scan = scan_num()+1
+     caput('4idcVORTEX:saveData_subDir', '/'+ scanrecpath+'/S'+str(scan))
+     caput('4idcVORTEX:saveData_scanNumber',1)
+
+    
+def chkmcasave():
+    if (caget('29idKappa:scan1.T2PV')=='29idVORTEX:scanH.EXSC'):
+        print('Saving mca files')
+        mcafileinit()
+
+    
diff --git a/build/lib/iexcode/instruments/xrays.py b/build/lib/iexcode/instruments/xrays.py
new file mode 100644
index 0000000000000000000000000000000000000000..aa029404a075cb0b00ddbf7f9878598afc57032b
--- /dev/null
+++ b/build/lib/iexcode/instruments/xrays.py
@@ -0,0 +1,700 @@
+"""
+functions related to using x-rays
+
+"""
+import numpy as np
+from time import sleep
+
+from epics import caget,caput
+from iexcode.instruments.IEX_endstations import BL
+
+from iexcode.instruments.resolution import *
+from iexcode.instruments.IEX_VPU import *
+from iexcode.instruments.VLS_PGM import *
+from iexcode.instruments.slits import *
+from iexcode.instruments.shutters import *
+from iexcode.instruments.gate_valves import *
+from iexcode.instruments.diagnostics import *
+from iexcode.instruments.m3r import *
+from iexcode.instruments.logfile import *
+from iexcode.instruments.utilities import print_warning_message,make_table, take_closest_value
+from iexcode.instruments.mpa import *
+from iexcode.instruments.current_amplifiers import ca_average
+from iexcode.instruments.beamline import branch_cams_enable
+
+from iexcode.instruments.ARPES import ARPES_mprint,ARPES_extra_pvs
+from iexcode.instruments.Kappa import Kappa_mprint
+from iexcode.instruments.electron_analyzer import getSESslit, EA
+##############################################################################################################
+##############################            resets and detector lists         ##############################
+##############################################################################################################
+def test_function():
+    print('hello world')
+    
+def xrays_reset():
+    mono_limits_reset()
+    xray_motor_encoder_sync()
+
+
+def xrays_detector_list():
+    """
+    defualt detectors for the APRES endstation
+    used by: 
+         CA_Live_StrSeq()
+        Detector_Triggers_StrSeq()
+        BeforeScan_StrSeq() => puts everybody in passive
+        CA_Average()
+    WARNING: can't have more than 5 otherwise CA_Live_StrSeq gets angry.
+
+    Previously: part of Detector_List
+    """
+    ca_list=[["b",4],["b",13]]
+
+    return ca_list
+
+
+def xrays_detector_dictionary():
+    """
+    returns a dictionary of the default detectors
+    
+    Previously: Detector_Default
+    """
+    det_dict={}
+    sr_main_shutter={
+        1:"S:SRcurrentAI.VAL",
+        2:"EPS:29:ID:SS1:POSITION"
+        }
+    bl_energy={
+        3:"29idmono:ENERGY_MON",
+        4:"ID29:EnergySet.VAL",
+        5:"ID29:Energy.VAL"
+        }
+    bl_keithleys={
+        6:"29idb:ca1:read",
+        7:"29idb:ca2:read",
+        8:"29idb:ca3:read",
+        9:"29idb:ca4:read",
+        10:"29idb:ca5:read",
+        11:"29idb:ca9:read",
+        12:"29idb:ca12:read",
+        13:"29idb:ca13:read"
+        }
+    det_dict.update(sr_main_shutter)
+    det_dict.update(bl_energy)
+    det_dict.update(bl_keithleys)
+    return det_dict
+
+##############################################################################################################
+##############################            get beamline info         ##############################
+##############################################################################################################
+
+def xrays_get_all(verbose=False):
+    """
+    gets info about current beamline setting
+    returns a dictionary
+
+    """
+    vals={}
+    print("\n===========================================================")
+    vals.update(ID_get_all(verbose=True))
+    vals.update(mono_get_all(verbose=True))
+    print("-----------------------------------------------------------")
+    vals.update(slits_get_all(verbose=True))
+    vals.update(FMB_mirror_get(0,verbose=True))
+    vals.update(FMB_mirror_get(1,verbose=True))
+    vals.update(FMB_mirror_get(3,verbose=True))
+    print("-----------------------------------------------------------")
+    vals.update({'ARPES':ARPES_mprint()})
+    print("ARPES = ",ARPES_mprint())
+    vals.update({'Kappa':Kappa_mprint()})
+    print("Kappa = ",Kappa_mprint())
+    print("===========================================================")
+    return vals
+
+def xrays_log_entries(**kwargs):
+    """
+    Writes CSV file for the MDA scans with the following default parameters:
+    FilePath='/home/beams/29IDUSER/Documents/User_Folders/UserName/'
+    Filename is set by logname_set(FileName=None), default:YYYYMMDD_log.txt, where YYYYMMDD is when folders were set
+        (FileName=None,FileSuffix=None) is they are specified then it will use those values instead
+
+    comment="Additional comments, last column"
+
+    Previously: scanlog
+    """
+    #default parameters
+    kwargs.setdefault('comment','')
+
+    ioc = BL.ioc
+
+    #scan Num
+    scan = BL.mda.prefix(ioc)+str(BL.mda.fileNum(ioc))
+    entry_list=["scan"]
+    pv_list=[scan]
+    format_list=["s" ]
+    #scan info
+    drive = caget(ioc+"scan1.P1PV")
+    start = caget(ioc+"scan1.P1SP")
+    stop  = caget(ioc+"scan1.P1EP")
+    step  = caget(ioc+"scan1.P1SI")
+    entry_list.append('drive','start','stop' ,'step')
+    pv_list.append(drive,start,stop ,step)
+    format_list.append("s",".3f",".3f",".3f")
+
+    #endstation info
+    if BL.endstation_name == 'ARPES':
+        endstation_entry, endstation_pv, endstation_format = ARPES_log_entries(**kwargs)
+        entry_list.append(endstation_entry)
+        pv_list.append(endstation_pv)
+        format_list.append(endstation_format)
+    elif BL.endstation_name == 'Kappa':
+        endstation_entry, endstation_pv, endstation_format = Kappa_log_entries(**kwargs)
+        entry_list.append(endstation_entry[:-7])
+        pv_list.append(endstation_pv[:-7])
+        format_list.append(endstation_format[:-7])
+
+    #beamline info
+    ID_mode = ID_mode_get(verbose=False) if BL.xrays else "no_xrays"
+    ID_QP_ratio = ID_QP_ratio_get (verbose=False) if BL.xrays else "no_xrays"
+    ID_sp  = round(ID_SP_get_eV()) if BL.xrays else 0
+    ID_rbv = round(ID_rbv_get_eV,4) if BL.xrays else 0
+    hv = mono_energy_get() if BL.xrays else 0
+    grt = mono_grating_get() if BL.xrays else 0
+    slit_size = slit_get()[0] if BL.xrays else 0
+    entry_list.append("hv","exit_slit","GRT", "ID_SP", "ID_RBV", "ID_Mode", "ID_QP")
+    pv_list.append(hv,slit_size,grt, ID_sp, ID_rbv,ID_mode, ID_QP_ratio)
+    format_list.append(".2f",".0f","s",".1f",".1f","s", ".0f")
+
+    #endstation info 2: Fanny can I change to order to get rid of this complication?
+    if BL.endstation_name == 'Kappa':
+        endstation_entry, endstation_pv, endstation_format = Kappa_log_entries(**kwargs)
+        entry_list.append(endstation_entry[-7:])
+        pv_list.append(endstation_pv[-7:])
+        format_list.append(endstation_format[-7:])
+
+    #timestamp and comments
+    t = time.strftime("%D-%H:%M:%S")
+    comment = kwargs["comment"]
+    entry_list.append('time','comment')
+    pv_list.append(t,comment)
+    format_list.append("s","s")
+
+    try:
+        logfile_update(BL.endstation,BL.ioc,entry_list,pv_list,format_list)
+    except:
+        print("scanlog did not write to file, check for errors.")
+        
+##############################################################################################################
+##############################            beamline encoders         ##############################
+##############################################################################################################
+
+def xray_motor_encoder_sync():
+    ioc = "29idb:"
+    for motor in [13,14,15,16,26,27]:
+        pv = ioc+"m"+str(motor)+".SYNC"
+        caput(pv,1)
+        print("synch encoder: "+pv)
+
+##############################################################################################################
+##############################               energy : ID + mono           ##############################
+##############################################################################################################
+def energy_get_all(verbose=True):
+    """
+    returns ID_mode,ID_QP_ratio,ID_sp,ID_rbv,hv,grt 
+
+    """
+    d = ID_get_all(verbose=False)
+    d.update(mono_get_all(verbose=False))
+    keylist = ['ID_Mode', 'ID_QP_ratio', 'ID_SP', 'ID_RBV','hv','grating']
+    values = []
+    for key in keylist:
+        values.append(d[key])
+        if verbose:
+            print(key,d[key])
+
+    return tuple(values)
+    
+def energy_get():
+    hv = getE()
+    return hv
+
+def energy(hv_eV,slit_coeff=1,m3r=True,verbose=True):
+    """
+    sets the ID for optimal flux based on calibration
+    sets the mono
+    sets the beamline aperture/slits
+
+    slit_coeff < 1 is used to kill flux by closing the aperature after the mono (slit-2B)
+    
+    m3r => if True optimizes the mirror for the d-branch only
+    Previously: Set_BL, energy
+    """
+    if BL.xrays:
+        if hv_eV != energy_range_check(hv_eV):
+            message_string = 'request photon energy '+str(hv_eV)+' not with the allowed range'
+            message_string = '\n closest allowed energy is '+str(energy_range_check(hv_eV))
+            print_warning_message(message_string)
+
+
+        ID_energy_set(hv_eV,verbose=verbose)
+        mono_energy_set(hv_eV,verbose=verbose)
+        slits_set_BL(c_2B=slit_coeff,c_1A=1,verbose=verbose)
+
+        if m3r == True:
+            if BL.branch() == 'd':
+                print('\nalign_m3r()')
+                try:
+                    m3r_align()
+                    sleep(1)
+                    if m3r_RY_pos_sp_get() == m3r_RY_pos_sp():
+                        m3r_align()
+                except:
+                    print('Unable to align; check camera settings.')
+    else:
+        message_string = 'BL.xrays = False, energy is not set'
+        print_warning_message(message_string)
+
+def energy_range_min_max():
+    """
+    returns the min,max energies for the current grating/ID setting
+    """
+    ID_min, ID_max = ID_energy_range()
+    mono_min, mono_max = mono_energy_range()
+    hv_max = np.min(ID_max, mono_max)
+    hv_min = np.max(ID_min, mono_min)
+    return hv_min,hv_max
+
+def energy_range_check(hv):
+    """
+    checks if the energy is within the allowed range for both the mono
+    and the ID. If outside the ranges set it to the closest allowed value
+
+    Previously: SetRange()
+    """
+    hv_min,hv_max = energy_range_min_max()
+    hv = np.min(hv_max,hv)
+    hv = np.max(hv_min,hv)
+    return hv
+
+def mvid(val):
+    """
+    Sets the ID absolute set point (not optimized , mono & apertures stay fixed).
+    
+    to go to most flux use energy
+    """
+    ID_SP_set()
+
+def scan_ID(ID_sp_start,ID_sp_stop,ID_sp_step,**kwargs):
+    """
+    scan the ID set point
+    """
+    val_pv,rbv_pv = ID_scan_pvs()
+    mda.fillin(val_pv,rbv_pv,ID_sp_start,ID_sp_stop,ID_sp_step,**kwargs)
+
+
+def mvmono(val):
+    """
+    Sets the mono energy (insertion device & apertures stay fixed).
+    """
+    mono_energy_set(val)
+
+def getE():
+    """ 
+    Returns current mono set point.
+    """
+    return mono_energy_get()
+
+def switch_gratings(grating):
+    """
+    used to switch between gratings
+        grating = 'HEG' / 'MEG'
+
+        check current grating 
+        closes the main shutter 
+        sets the mono energy 
+
+    Previously: Switch_Grating
+    """
+    current_grt = mono_grating_get()
+    if grating != current_grt:
+        shutter_open = main_shutter_status()
+        main_shutter_close()
+        print("Switching grating, please wait...")
+        mono_grating_translate(grating,quiet=True)
+        slits_set_BL()
+
+        if shutter_open:
+            main_shutter_open()
+    
+        print(dateandtime()," grating: "+grating)
+    else: 
+        print("grating: "+grating)
+
+def mvgrating(grating):
+    """
+    Change mono grating: 
+        HEG = high resolution, low flux
+        MEG = medium resolution, high flux
+    """
+    switch_gratings(grating)
+
+def polarization(ID_mode):
+    """
+    Change beam polarization: ID_mode = 'H', 'V', 'RCP' or 'LCP'
+    """
+    ID_switch_mode(ID_mode)
+
+def polarization_get():
+    """
+    gets the current polarization
+    """
+    ID_mode_get()
+
+def scanhv(start,stop,step,average_pnts=1,**kwargs):
+    """
+    scans the mono at the current ID value
+
+    """
+    ca_average(average_pnts)
+
+    mono_scan_fillin(mda,start,stop,step,**kwargs)
+
+    mono_energy_set(start)
+    mda.go(**kwargs)
+
+    mono_scan_after(mda)
+
+
+def scanE(start,stop,step,ID_offset=0,mesh='stay',average_pnts=1,scan_dim=1,**kwargs):
+    """ 
+    sets the ID and then scans the mono
+    
+    hv_start,hv_stop,hv_step: are the mono start, stop, step energies
+    ID_offset: used to position the ID
+        None => the ID does not move
+        otherwise ID_energy_set = (stop-start)/2 + ID_offset
+    mesh: used to specifiy mesh status (for normalization)
+        => mesh='y': drops in the mesh for normalization (D branch only); retracts it at the end.
+        => mesh='stay': to leave the mesh in after the scan is finished
+        => mesh='n': no mesh.
+    **kwargs
+        scan_dim
+        positioner_settling_time = 0.2
+    """
+    mda = BL.mda
+    ca_average(average_pnts)
+
+    if ID_offset != None:
+        ID_energy_set = (start+stop)/2.0 + ID_offset
+        
+    slits_set_BL()
+
+    mono_scan_fillin(mda,scan_dim,start,stop,step,**kwargs)
+    
+    mono_energy_set(start)
+    BL.mda.go(scan_dim)
+    
+    mono_scan_after(mda,scan_dim)
+
+
+def scanXAS(ID_eV,start_stop_step_lists,**kwargs):
+    """
+    Sets the beamline to ID_eV and then scans the mono for XAS scans
+
+    start_stop_step_lists is a list of lists for the different scan ranges
+        start_stop_step_lists = [[start1,stop1,step1], [start1,stop1,step1],...]
+        Note duplicates are removed and the resulting array is sorted in ascending order
+
+    **kwargs:
+        scan_dim = 1 (default)
+        average_pnts: if using Keithlys this set the averaging; None for no averaging
+        m3r: if True the mirror is optimized before the start of the scan
+        mcp
+        execute: True/False to start the scan => True (default)
+    
+    Normalization:
+        - If in the D-branch the Mesh is put in but is not removed
+        - If in the C-branch we use the slit blades for normalization (ca13)
+    """
+    kwargs.setdefault("scan_dim",1)
+    kwargs.setdefault("average_pnts",1)
+    kwargs.setdefault("m3r",True)
+    kwargs.setdefault("mcp",True)    
+    kwargs.setdefault('execute',True)   
+
+    scan_dim=kwargs['scan_dim']
+    
+    #Setting up the ScanRecord for Mono in Table mode
+    hv_array = make_table(start_stop_step_lists)
+    mono_scan_fillin_table(BL.mda,scan_dim,hv_array,**kwargs)
+
+    #Averaging and Normalization
+    ca_average(kwargs['average_pnts'])
+    if BL.branch=="d":
+        meshD("In")
+     
+    #Setting the beamline energy
+    energy(ID_eV,m3r=kwargs["m3r"])
+
+    #mpa
+    if BL.branch == "d" and kwargs["mcp"]:
+        mpa_HV_on()
+
+    #Scanning
+    if kwargs['execute']:
+        mono_energy_set(hv_array[0])
+        BL.mda.go(scan_dim)
+    
+        #Setting everything back
+        mono_energy_set(ID_eV)
+        mono_scan_after(mda,scan_dim)
+        mda.table_reset_after(scan_dim)
+
+        if BL.branch == "d": 
+            if kwargs["mcp"]: 
+                mpa_HV_off()
+            print("WARNING: Mesh"+BL.branch+" is still In")        
+
+def scanXAS_BL(start_stop_step_lists,**kwargs):
+    """
+    scans the mono and the ID for XAS scans
+        Note: this is slow, but required in if the c-branch
+
+    start_stop_step_lists is a list of lists for the different scan ranges
+        start_stop_step_lists = [[start1,stop1,step1], [start1,stop1,step1],...]
+        Note duplicates are removed and the resulting array is sorted in ascending order
+
+    **kwargs:
+        scan_dim = 1 (default)
+        average_pnts: if using Keithlys this set the averaging; None for no averaging
+        m3r: if True the mirror is optimized before the start of the scan
+        mcp
+        execute: True/False to start the scan => True (default)
+    
+    Normalization:
+        - If in the D-branch the Mesh is put in but is not removed
+        - If in the C-branch we use the slit blades for normalization (ca13)
+    """
+    kwargs.setdefault("scan_dim",1)
+    kwargs.setdefault("average_pnts",1)
+    kwargs.setdefault("m3r",True)
+    kwargs.setdefault("mcp",True)    
+    kwargs.setdefault('execute',True)
+
+    scan_dim=kwargs['scan_dim']
+        
+    #Setting up the ScanRecord for Mono and ID in Table mode
+    mono_array,ID_array = BL_energy_tables(start_stop_step_lists)
+
+    kwargs.update('positioner_num',1)
+    mono_scan_fillin_table(mda,scan_dim,mono_array,**kwargs)
+
+    kwargs.update('positioner_num',2)
+    ID_scan_fillin_table(mda,scan_dim,ID_array,**kwargs)
+    
+    #Averaging and Normalization
+    ca_average(kwargs['average_pnts'])
+    if BL.branch=="d":
+        meshD("In")
+     
+    #Setting the beamline energy
+    slits_set_BL(mono_array[0],m3r=kwargs["m3r"])
+
+    #mpa
+    if BL.branch == "d" and kwargs["mcp"]:
+        mpa_HV_on()
+        
+    #Scanning
+    if kwargs['execute']:
+        mono_energy_set(mono_array[0])
+        ID_SP_set(ID_array[0])
+        BL.mda.go(scan_dim)
+
+        #Setting everything back
+        mono_energy_set(mono_array[0])
+        mono_scan_after(mda,scan_dim)
+        mda.table_reset_after(scan_dim)
+
+        if BL.branch == "d": 
+            if kwargs["mcp"]: 
+                mpa_HV_off()
+            print("WARNING: Mesh"+BL.branch+" is still In")  
+
+def BL_energy_tables(start_stop_step_lists):
+    """
+    returns mono_array and ID_array for BL energy scans
+    *energies:
+        start,stop,step
+        ListofLists, e.g.{[400,420,1],[420,425,0.25]...}
+
+    Previously: Tables_BLenergy
+    """
+    mono_array = make_table(start_stop_step_lists)
+    ID_array=np.array([])
+    ID_mode,ID_QP_ratio,ID_sp,ID_rbv,hv,grt = energy_get_all(verbose=False)
+    for hv_eV in mono_array:
+        ID_array=np.append(ID_array,ID_calc_SP(grt,ID_mode,hv_eV))
+    return mono_array,ID_array
+
+
+##############################################################################################################
+###########################               branch shutter, valves, safe_state                    ######################
+##############################################################################################################
+def get_branch(verbose=True):
+    """
+    gets the branch based on the position of m3r
+    """
+    branch = m3r_branch(verbose)
+    return branch
+
+
+def open_branch(branch=None,valve=False):
+    """
+        Opens the branch shutter, if branch is none, then uses the position of m3r to determine branch
+        
+        Previously: Check_BranchShutter
+    """
+    branch = get_branch(verbose=False)
+    
+    if branch_shutter_status(branch):
+        print(dateandtime(), +branch+" shutter already open..." ,)
+    else:
+        while True:
+            if branch_shutter_status(branch) == False :
+                print(dateandtime(), "Opening "+branch+" shutter ..." ,)
+                branch_shutter_open(branch,verbose=False)
+                sleep(30)
+            else:
+                print(dateandtime(), +branch+" shutter is now open..." ,)
+                break
+    if valve:
+        GVs = branch_valves()
+        for GV in GVs:
+            valve_open(GV)
+
+def close_shutter(branch=None):
+    """
+        Closes the branch shutter, if branch is none, then uses the position of m3r to determine branch
+        
+        Previously: Close_CShutter,Close_DShutter
+    """
+    if branch is None:
+        branch = get_branch()
+    caput("PC:29ID:S"+branch+"S_CLOSE_REQUEST.VAL",1,wait=True,timeout=18000)
+    print("Closing "+branch+"-Shutter...")
+
+def switch_branch(branch, force=False, shutter=True,scan_reset=True,enable_cams=True):
+    """Switch beam into which = \"c\" or \"d\" branch (by retracting/inserting deflecting mirror)
+        Optionnal keyword argument:
+            force: change m3r even if the beamline think it is already there (default=False)
+            shutter: open the branch shutter, does not open the valve (default=False) 
+            reset: resets the scanRecord and the global BL for the selected branch
+            enable_cams: to turn on/off branch camera  
+
+    Previously: Switch_Branch
+    """
+    branch = branch.lower()
+    if branch in ["c","d","e"]:
+
+    # Check current branch:
+        if get_branch() == branch and not force:
+            m3r_position = FMB_mirror_get(3,verbose=False)
+            if np.sum(np.array(m3r_position)):
+                print("\nMirror homed...")
+                print("...Try again using: Switch_Branch(which, forced=True)")
+            else:
+                print("\nWell, looks like the beam is already in this branch...")
+                print("...if you want to force the mirror motion, use the argument: forced=True")
+        else:
+            # Close both shutters:
+            print("\n")
+            print("Switching branch, please wait...")
+            if shutter:
+                branch_shutter_close('c')
+                branch_shutter_close('d')
+    
+            #Move M3R:
+            m3r_switch_branch(branch)
+            print(dateandtime()," -  In "+branch+"-Branch")
+            sleep(2)
+
+        # Open branch shutters:
+            if shutter:
+                open_branch(branch,valve=False)
+
+            if scan_reset:
+                BL.mda.reset()
+
+            if enable_cams:
+                branch_cams_enable(branch)
+
+    else:
+        print_warning_message(branch+' is not a valid branch selection')
+#             if not nocam:
+
+##############################################################################################################
+###########################                      mirrors                    ######################
+##############################################################################################################
+def get_mirrors():
+    for mirror_num in [0,1,3]:
+        FMB_mirror_get(mirror_num,verbose=True)
+
+
+##############################################################################################################
+###########################                  slits and resolution                    ######################
+##############################################################################################################
+def slit(size):
+    """
+    sets the exit slit based on BL.endstation
+
+        ARPES = 0 < x < 300  um
+        Kappa  = 0 < x < 1000 um
+    """
+    branch = BL.branch
+    if branch == "c":
+        slit3C_set(size, quiet=False)
+    elif branch == "d":
+        slit3D_set(size, quiet=False)
+
+
+def slit_get(verbose=True):
+    """
+    sets the exit slit based on BL.endstation
+
+        ARPES = 0 < x < 300  um
+        Kappa  = 0 < x < 1000 um
+    """
+    branch = BL.branch
+    if branch == "c":
+        slit_size = slit3C_get(verbose=False)
+        slit_center = np.nan
+    elif branch == "d":
+        slit_size,slit_center = slit3D_get(verbose=False)
+
+    if verbose:
+        message = BL.branch+' exit slit: '+str(slit_size)
+        message += ", @ "+str(slit_center) if BL.branch is not 'c' else ''
+        print(message)    
+    return slit_size,slit_center
+
+def resolution():
+    """
+    Calculate the theoretical resolution for the current beamline settings:
+        ARPES: total resolution i.e. sqrt(kbT^2 + analyzer^2 + BL^2); default SES slit = 5.
+        Kappa:  beamline contribution only
+    """
+    branch = get_branch()
+    grt = mono_grating_get()
+    hv_eV = getE()
+    slit_size = take_closest_value([10,20,50,100,200],round(slit_get(),0))
+
+    if branch == "c":
+        slit_SES = getSESslit()
+        PE = int(EA.PassEnergy)
+        T = caget(ARPES_extra_pvs['TA'])
+        resolution_ARPES(grt,hv_eV,slit_size,PE,slit_SES,T,verbose=True)
+    else:
+        resolution_beamline(grt,hv_eV,slit_size,verbose=True)
+
+
+
diff --git a/build/lib/iexcode/macros/ARPES_macros.py b/build/lib/iexcode/macros/ARPES_macros.py
new file mode 100644
index 0000000000000000000000000000000000000000..240e6d80e466ef7ca34fc6bff6eae7cd8d249a51
--- /dev/null
+++ b/build/lib/iexcode/macros/ARPES_macros.py
@@ -0,0 +1,96 @@
+import numpy as np
+
+from epics import caget,caput
+
+from .ScanFunctions_plot import mda_1D,fit_gauss
+
+from ..instruments.electron_analyzer import scanEA
+from ..instruments.slits import slit3C_set
+from ..instruments.xrays import energy
+from ..instruments.ARPES import mvth,scanx,mvx,mprint
+
+
+##############################################################################################################
+##############################             SES Work Function          ##############################
+##############################################################################################################
+
+def WorkFunction_Measure(PE,KE=409,**kwargs):
+    '''
+    Takes data with 1st and 2nd order light of core level with KE at @ hv=500eV
+    **kwargs
+    
+    '''
+    frames=round(17*60*200/PE,0)
+    energy(500)
+    
+    #Fermi Level
+    slit3C_set(150)
+    kwargs.update({'comment': 'EF1'}) 
+    EAlist=['KE',495,PE,frames,1]
+    scanEA(EAlist,**kwargs)
+    
+    #Core level first order
+    slit3C_set(50)
+    kwargs.update({'comment': 'KE1'})     
+    EAlist=['KE',KE,PE,frames/10,1]
+    scanEA(EAlist,**kwargs)
+    
+    #Core level second order
+    slit3C_set(150)
+    kwargs.update({'comment': 'KE2'}) 
+    EAlist=['KE',KE+500,PE,frames*10,1]
+    scanEA(EAlist,**kwargs)
+    print("""Fit the data :
+          - EF1 = EF in first order light (scan #1)
+          - KE1 = Au_3/2 in first order light (scan #2)
+          - KE2 = Au_3/2 for 2nd order light (scan #3)
+          => wk = KE2-2*KE1-(EF1-KE1)`
+    Details of the math is page 16 of commissionning book IV
+    Now if you know what you are doing you can: 
+          caput('29idcEA:det1:ENERGY_OFFSET',new_wk_value)""")
+    
+def WorkFunction_Calc(EF1,KE1,KE2):
+    """Fit the data :
+          - EF1 = EF in first order light (scan #1)
+          - KE1 = Au_3/2 in first order light (scan #2)
+          - KE2 = Au_3/2 for 2nd order light (scan #3)
+          => wk = KE2-2*KE1-(EF1-KE1)`
+    Details of the math is page 16 of commissionning book IV"""
+    wk = KE2-2*KE1-(EF1-KE1)
+    print("wk = KE2-2*KE1-(EF1-KE1) = ",wk)
+    print("Now if you know what you are doing you can:") 
+    print("EA._setwk("+str(round(wk,2))+")")
+
+def WorkFunction(KE1,KE2,Ef):
+    Phi=round(KE2-2*KE1-(Ef-KE1),3)
+    print(('Phi = '+str(Phi)+' eV'))
+    return Phi
+
+def RoughPositions_Find(th_start,th_stop, th_step,**kwargs):
+    """automatically scans and creates the RoughPosition list used in FermiMap for 
+    relatively uniform samples by:
+        1) scanx(-0.5,0.5,.05,mode='relative')
+        2) does a gaussian fits the mda EAV intesnity to determine center of the fit x_center
+        3) mv(x_center)
+        4) mprint() and appends current position to list
+        5) moves to the next theta value and repeats
+        
+    Note: before starting move to the first theta position and adjust the focus leaving the EA is Live Mode
+    
+    **kwargs
+        scanDet=17
+    """
+    kwargs.setdefault("scanDet",17)
+    if caget("29idcEA:det1:Acquire") !=1:
+        print("Turn on the EA!!! EALive(PE,KE,Lens=\'Transmission\')")
+    else:
+        RefinedPositions=[]
+        for th in (th_start,th_stop+th_step,th_step):
+            mvth(th)
+            scanx(-0.5,0.5,.05,mode='relative')
+            scanNum=caget("29idARPES:saveData_scanNumber")-1
+            x,y,x_name,y_name=mda_1D(scanNum,kwargs["scanDet"])
+            results=fit_gauss(np.array(x),np.array(y))
+            mvx(results[2][1])  
+            RefinedPositions.append(mprint())
+        print("RefinedPositions=",RefinedPositions) 
diff --git a/build/lib/iexcode/macros/BL_shutdown.py b/build/lib/iexcode/macros/BL_shutdown.py
new file mode 100644
index 0000000000000000000000000000000000000000..800bf0c93902b720273eb0e63ef5d15fba729d02
--- /dev/null
+++ b/build/lib/iexcode/macros/BL_shutdown.py
@@ -0,0 +1,47 @@
+from epics import caget,caput
+
+from ..instruments.electron_analyzer import EA
+from ..instruments.shutters import main_shutter_close,branch_shutter_close
+from ..instruments.diagnostics import diagnostics_all_out
+
+##############################################################################################################
+############################################          Shut down      #################################################
+##############################################################################################################
+
+def BL_Shutdown():
+    BL_CloseAllShutters()
+    BL_Valve_All(state="CLOSE")
+    diagnostics_all_out()
+    try:
+        EA.off()
+    except:
+        print('EA is not running, visually confirm HV is off')
+        
+    caput("29iddau1:dau1:011:DAC_Set",0)    #RSXS HV = "OFF"
+
+def BL_CloseAllShutters():
+    main_shutter_close()
+    branch_shutter_close('c')
+    branch_shutter_close('d')
+
+def BL_Valve_All(state="CLOSE"):
+    ValveList=["V1A","V2A","V3B","V4B","V5B","V6B","V7C","V8C","V9C","V10C","V7D","V8D","V9D","V10D"]
+    for Vname in ValveList:
+        pv=BL_Valve2pv(Vname)+state+".VAL"
+        caput(pv,1)
+
+def BL_Valve(Vname,state="CLOSE"):
+    pv=BL_Valve2pv(Vname)+state+".VAL"
+    caput(pv,1)
+
+def BL_Valve2pv(Vname):
+    Valve={
+        "V1A":"GV01","V2A":"GV02",                #A-Hutch
+        "V3B":"GV03","V4B":"GV04","V5B":"GV05","V6B":"GV15",    #B-Branch
+        "V7C":"GV06","V8C":"GV08","V9C":"GV09","V10C":"GV10",    #C-Branch
+        "C-Turbo":"GV16",                    #ARPES
+        "V7D":"GV11","V8D":"GV12","V9D":"GV13","V10D":"GV14",    #D-Branch
+        "D-Turbo":"GV17","D-TES":"GV18"                #RSXS
+    }
+    pv="29id:BLEPS:"+Valve[Vname]+":"
+    return pv
\ No newline at end of file
diff --git a/build/lib/iexcode/macros/Kappa_optimization.py b/build/lib/iexcode/macros/Kappa_optimization.py
new file mode 100644
index 0000000000000000000000000000000000000000..378f9c598983c35739c1894748dbd5275e9b1b80
--- /dev/null
+++ b/build/lib/iexcode/macros/Kappa_optimization.py
@@ -0,0 +1,100 @@
+import matplotlib.pyplot as plt
+
+from epics import caget,caput
+from ..instruments.Kappa import *
+from ..instruments.Motors import *
+
+from .ScanFunctions_plot import fit_mda, mda_1D
+
+##### Kappa Optimization scans #####
+def Opt_d4(iteration,moveZ,graph='y',srs=None,start=-0.5,stop=0.5,step=0.04):
+    tth_w=0.1
+    if srs==None: det=21
+    else: det=34
+    z=caget('29idKappa:m4.RBV')
+    current_det=caget('29idKappa:userStringSeq6.STR1',as_string=True)
+    if current_det != 'd4':
+        print('Switching detector to d4')
+        tthdet.set('d4',move=False)
+        mvtth(0)
+    if moveZ is not None:
+        mvz(z-1000)
+    for i in range(iteration):
+        scantth(start,stop,step,'relative')
+        scannum = mda.lastFileNum()
+        tth0=fit_mda(scannum,det,tth_w,'gauss',graph=graph)
+        mvtth(tth0)
+    mvz(z)
+    return tth0,scannum
+
+def Opt_z0(iteration,movetth,movekth,det='d4',srs=None,graph='y'):
+    z_w=400
+    current_det=caget('29idKappa:userStringSeq6.STR1',as_string=True)
+    if current_det != det:
+        print('Switching detector to '+det)
+        tthdet.set(det,move=False)
+    if det=='d3' and srs==None: det=20
+    if det=='d3' and srs!=None: det=33
+    if det=='d4' and srs==None: det=21
+    if det=='d4' and srs!=None: det=34
+    if movetth is not None:
+        mvtth(movetth)  
+    if movekth is not None:
+        mvkth(movekth)
+    if iteration>1:
+        scanz(-2000,2000,250,'relative')
+        scannum=mda.fileNum()
+        z0=fit_mda(scannum,det,z_w,'erf',graph=graph)
+        mvz(z0)
+    scanz(-700,700,50,'relative')
+    scannum = mda.lastFileNum()
+    z0=fit_mda(scannum,det,z_w,'erf',graph=graph)
+    mvz(z0)
+    return z0,scannum
+
+def Opt_kth(kth_0,theta,det='d4',srs=None,graph='y'):
+    current_det=caget('29idKappa:userStringSeq6.STR1',as_string=True)
+    if current_det != det:
+        print('Switching detector to '+det)
+        tthdet.set(det,move=False)
+    if det == 'd4': 
+        if srs==None: det=21
+        else: det=34
+        i=1
+    elif det == 'd3': 
+        if srs==None: det=20
+        else: det=33
+        i=5
+    mvtth(theta*2)
+    mvkth(kth_0+theta)
+    scankth(-0.5*i,0.5*i,0.05*i,'relative')
+    new_kth=fit_mda(mda.lastFileNum(),det,0.1,'gauss',graph=graph)
+    mvkth(new_kth)
+    scankth(-0.2*i,0.2*i,0.02*i,'relative')
+    new_kth=fit_mda(mda.lastFileNum(),det,0.1,'gauss',graph=graph)
+    mvkth(new_kth)
+    scannum=mda.lastFileNum
+    kth0=round(new_kth-theta,3)
+    print('\nkth0 = ',kth0)
+    print('To plot use:') 
+    print('     fit_mda('+str(scannum)+',21,0.2,"gauss",mytitle=\'theta ='+str(theta)+'\')')
+    print('If you are happy with that, you can set this value as kth0 using:')
+    print('     kth0_set('+str(kth0)+')')
+
+    return kth0,scannum
+
+def plot_opt(opt_scan_list,energy_list,det,mytitle=''):
+    fig,(ax1)=plt.subplots(1,1)
+    fig.set_size_inches(5,4)
+
+    for i,j in zip(opt_scan_list,energy_list):
+        x,y,x_name,y_name=mda_1D(i,det,1,0)
+        xdata = np.array(x)
+        ydata = np.array(y)
+        Imax=np.max(ydata)    
+        ax1.plot(x,y/Imax,label=str(j)+" eV")
+    ax1.set(ylabel='Intensity')
+    ax1.set(xlabel=x_name)
+    ax1.ticklabel_format(style='sci', axis='y', scilimits=(0,0))
+    ax1.grid(color='lightgray', linestyle='-', linewidth=0.5)
+    ax1.legend(bbox_to_anchor=[1.2, 1],ncol=2,shadow=True, title=mytitle, fancybox=True)    
diff --git a/build/lib/iexcode/macros/ScanFunctions_plot.py b/build/lib/iexcode/macros/ScanFunctions_plot.py
new file mode 100644
index 0000000000000000000000000000000000000000..c4ca21637d4ca36a0b2bec68618036e5544fd27d
--- /dev/null
+++ b/build/lib/iexcode/macros/ScanFunctions_plot.py
@@ -0,0 +1,2787 @@
+"""
+#ScanFunctions_plot.py
+how to copy tabs in stabs and not spaces jupyter
+
+For Fanny:    Converting spaces to tabs from the terminal
+cp ScanFunctions_IEX.py ScanFunctions_IEXbackup.py
+sed -e 's/    /\t/g' ScanFunctions_IEXbackup.py > ScanFunctions_IEX.py
+"""
+
+#### Other utilities:
+import csv
+from os import listdir
+from os.path import join, isfile, dirname
+from scipy.optimize import curve_fit
+from scipy.special import erf
+import numpy.polynomial.polynomial as poly
+import ast
+
+### Data analysis:
+from inspect import CO_ASYNC_GENERATOR
+from sre_constants import CATEGORY_DIGIT
+import matplotlib.pyplot as plt
+import matplotlib.image as mpimg
+import numpy as np
+from math import *
+
+from netCDF4 import Dataset
+
+
+##### APS / 29ID-IEX:
+from IEX_plotting_and_analysis.mda import readMDA,scanDim
+from IEX_plotting_and_analysis.IEX_nData import * 
+
+try:
+    from epics import caget
+    from ..instruments.IEX_endstations import BL
+    from ..instruments.utilities import read_dict,today
+    from ..instruments.slits import slits_set_BL
+    from IEXcode.iexcode.current_amplifiers import current2flux
+except:
+    print("EPICS package and dependent functions are not installed")
+
+
+
+##############################################################################################################
+##############################                  JM Curves and Curve Fitting               ##############################
+##############################################################################################################
+
+def gauss(x, *p):
+    """
+    Function for a guassian where p=[A,x0,sigma]
+    f(x)=A*numpy.exp(-(x-x0)**2/(2.*sigma**2)
+    fwhm=2.355*sigma
+    """
+    A, x0, sigma = p
+    return A*np.exp(-(x-x0)**2/(2.*sigma**2))
+
+def gauss_p0(y,x):
+    """
+    Inital guesses for guassian fit
+    x and y are np.arrays
+    returns p0=[A,x0,sigma]
+    """
+    A=max(y)
+    x0=x[np.where(y == max(y))][0]
+    sigma=0.2
+    return [A,x0,sigma]
+
+def fit_gauss(x,y,xrange=None):
+    """
+    x,y=EA_Spectrum(ScanNum, EnergyAxis,FilePath,Prefix)
+    x,y,x_name,y_name=mda_1D(ScanNum,DetectorNum)
+    
+    xrange = None to fit the full range 
+                = [x1,x2] to fit a subrange
+    returns input_x,fit_y,coeff,var_matrix
+    where input_x and fit_y are the sub range x and the fitted data respectivley
+    coeff=[A,x0,sigma]
+    var_matrix is the fit variance
+    """
+    if xrange is None:
+        input_y=y
+        input_x=x
+    else:
+        index1=np.where(x == x.flat[np.abs(x - xrange[0]).argmin()])[0][0]
+        index2=np.where(x == x.flat[np.abs(x - xrange[1]).argmin()])[0][0]
+        input_x=x[index1:index2]
+        input_y=y[index1:index2]
+    coeff, var_matrix = curve_fit(gauss, input_x, input_y, p0=gauss_p0(input_y,input_x))
+    fit_y= gauss(input_x, *coeff)
+    return input_x,fit_y,coeff,var_matrix
+
+
+##############################################################################################################
+##############################                  Plot Tiff,JPEG,PNG               ##############################
+##############################################################################################################
+
+#  filepath='/home/beams/29IDUSER/Documents/User_Folders/Topp/S089.tif'
+def plot_image(filepath,h=20,v=10,**kwargs):
+    """
+    filepath = '/home/beams/29IDUSER/Documents/User_Folders/UserName/TifFile.tif'
+    ** kwargs are imshow kwargs:
+        cmap = colormap; examples => 'gray','BuPu','Inferno'
+        vmin,vmax, adjust max and min of colormap
+    """
+    
+    image = mpimg.imread(filepath)
+    plt.figure(figsize=(h,v))
+    plt.imshow(image,**kwargs)
+    plt.axis('off')
+    plt.show()
+    
+
+
+def plot_image2(Filepath1,Filepath2,h=20,v=10):
+    """
+    filepath = '/home/beams/29IDUSER/Documents/User_Folders/UserName/TifFile.tif'
+    """
+    print(Filepath1)
+    print(Filepath2)
+    image1 = mpimg.imread(Filepath1)
+    image2 = mpimg.imread(Filepath2)
+    plt.figure(figsize=(h,v))
+    plt.subplot(1,2,1), plt.imshow(image1,cmap='gray')
+    plt.axis('off')
+    plt.subplot(1,2,2), plt.imshow(image2,cmap='gray')
+    plt.axis('off')
+#    fig.subplots_adjust(wspace=0.5,hspace=0.5,left=0.125,right=0.9,top=0.85,bottom=0.15)
+    plt.tight_layout()
+    plt.show()
+
+
+##############################################################################################################
+##############################                  Extract mda Data               ##############################
+##############################################################################################################
+
+## mda_1D(1691,44,1,0,'/net/s29data/export/data_29idb/2018_1/mda_b')???
+
+def mda_unpack(ScanNum,filepath=None,prefix=None):
+    """ Return data file + dictionary D##:("pv",index##)
+    filepath: by default plot scans for the current data folder (as defined in BL_ioc() ScanRecord SaveData)
+    or specified folder path:
+        e.g. filepath='/net/s29data/export/data_29idb/2018_1/mda_b/'
+    prefix: by default, uses prefix as defined in ScanRecord
+            "mda_" for users, "Kappa_" or "ARPES_" for staff (sometimes)
+    """
+    try:
+        if filepath is None:
+            filepath = BL.mda.filepath
+        if prefix is None:
+            prefix = BL.mda.prefix
+    except:
+        print('Please specify filepath and prefix, BL is not defined')
+
+    mdaFile=filepath + prefix+'{:04}.mda'.format(ScanNum)
+    data_file = readMDA(mdaFile)
+    try:
+        D={}
+        n=len(data_file)-1
+        for i in range(0,data_file[n].nd):
+            detector=data_file[n].d[i].fieldName
+            D[int(detector[1:])]=(data_file[n].d[i].name,i)
+        return (data_file,D)
+    except:
+        pass
+
+def mda_1D(ScanNum,DetectorNum,coeff=1,bckg=0,filepath=None,prefix=None):
+    """ Return x=positionner and y=detector(DetectorNum)
+    for a given detector number DYY (as shown in dview). """
+    try:
+        (data_file,det)=mda_unpack(ScanNum,filepath,prefix)
+        index=det[DetectorNum][1]
+        x = data_file[1].p[0].data
+        y = data_file[1].d[index].data
+        x_name = data_file[1].p[0].name
+        y_name = data_file[1].d[index].name
+        if type(x_name) == bytes:
+             x_name=x_name.decode("utf-8")
+        if type(y_name) == bytes:
+             y_name=y_name.decode("utf-8")
+        n=list(zip(x,y))
+        d=[n[i] for i, e in enumerate(n) if e != (0.0,0.0)]
+        if len(d)<len(n):
+            x=x[:len(d)]
+            y=y[:len(d)]
+        y=[(y[i]+bckg)*coeff for i, e in enumerate(y)]
+        #y=[(y[i]*coeff)+bckg for i, e in enumerate(y)]
+        return x,y,x_name,y_name
+    except:
+        print('error')
+        pass
+
+
+def mda_1D_unscaled(ScanNum,DetectorNum,filepath=None,prefix=None):
+    """ Return x=positionner and y=detector(DetectorNum)
+    for a given detector number DYY (as shown in dview). """
+    try:
+        (data_file,det)=mda_unpack(ScanNum,filepath,prefix)
+        if (data_file,det) == (None,None):
+            return(None)
+        else:
+            index=det[DetectorNum][1]
+            x = data_file[1].p[0].data
+            y = data_file[1].d[index].data
+            x_name = data_file[1].p[0].name
+            y_name = data_file[1].d[index].name
+            if type(x_name) == bytes:
+                 x_name=x_name.decode("utf-8")
+            if type(y_name) == bytes:
+                 y_name=y_name.decode("utf-8")
+            n=list(zip(x,y))
+            d=[n[i] for i, e in enumerate(n) if e != (0.0,0.0)]
+            if len(d)<len(n):
+                x=x[:len(d)]
+                y=y[:len(d)]
+            bckg=min(y)
+            coeff=max(y)-min(y)
+            y=[(y[i]-bckg)/coeff for i, e in enumerate(y)]
+            return x,y,x_name,y_name
+    except:
+        pass
+
+def mda_1D_Xindex(ScanNum,DetectorNum,coeff=1,bckg=0,filepath=None,prefix=None):
+    """ Return x=index and y=detector(DetectorNum)
+    for a given detector number DYY (as shown in dview). """
+    try:
+        (data_file,det)=mda_unpack(ScanNum,filepath,prefix)
+        index=det[DetectorNum][1]
+        x = data_file[1].d[0].data
+        y = data_file[1].d[index].data
+        x_name = data_file[1].d[0].name
+        y_name = data_file[1].d[index].name
+        if type(x_name) == bytes:
+             x_name=x_name.decode("utf-8")
+        if type(y_name) == bytes:
+             y_name=y_name.decode("utf-8")
+        n=list(zip(x,y))
+        d=[n[i] for i, e in enumerate(n) if e != (0.0,0.0)]
+        if len(d)<len(n):
+            y=y[:len(d)]
+        x=list(range(1,len(y)+1))
+        y=[(y[i]*coeff)+bckg for i, e in enumerate(y)]
+        return x,y,x_name,y_name
+    except:
+        pass
+
+def mda_1D_vsDet(ScanNum,DetectorNum,DetectorNum2,coeff=1,bckg=0,filepath=None,prefix=None):
+    """ Return x=index and y=detector(DetectorNum)
+    for a given detector number DYY (as shown in dview). """
+    try:
+        #print(ScanNum,filepath,prefix,scanIOC)
+        (data_file,det)=mda_unpack(ScanNum,filepath,prefix)
+        index=det[DetectorNum][1]
+        index2=det[DetectorNum2][1]
+        x = data_file[1].d[0].data
+        x2 = data_file[1].d[index2].data
+        y = data_file[1].d[index].data
+        x_name = data_file[1].d[0].name
+        x2_name = data_file[1].d[index2].name
+        y_name = data_file[1].d[index].name
+        x = data_file[1].p[0].data
+        x2= data_file[1].d[index2].data
+        y= data_file[1].d[index].data
+        if type(x_name) == bytes:
+             x_name=x_name.decode("utf-8")
+        if type(y_name) == bytes:
+             y_name=y_name.decode("utf-8")
+        if type(x2_name) == bytes:
+             x2_name=x2_name.decode("utf-8")
+        n=list(zip(x,y))
+        d=[n[i] for i, e in enumerate(n) if e != (0.0,0.0)]
+        if len(d)<len(n):
+            y=y[:len(d)]
+            x2=x2[:len(d)]
+        y=[(y[i]*coeff)+bckg for i, e in enumerate(y)]
+        return x2,y,x2_name,y_name
+    except:
+        pass
+
+def mda_Flux(ScanNum,DetectorNum,EnergyNum,filepath=None,prefix=None):
+    """ Return x=positionner and y=Flux(DetectorNum)
+    for a given diode recorded as detector number DYY (see ## in dview).
+    EnergyNum is the detector number for the mono RBV.
+
+    """
+    try:
+        (data_file,det)=mda_unpack(ScanNum,filepath,prefix)
+        index=det[DetectorNum][1]
+        Eindex=det[EnergyNum][1]
+        x = data_file[1].p[0].data
+        y = data_file[1].d[index].data
+        energy = data_file[1].d[Eindex].data
+        x_name = data_file[1].p[0].name
+        y_name = data_file[1].d[index].name
+        if type(x_name) == bytes:
+             x_name=x_name.decode("utf-8")
+        if type(y_name) == bytes:
+             y_name=y_name.decode("utf-8")
+        n=list(zip(x,y))
+        d=[n[i] for i, e in enumerate(n) if e != (0.0,0.0)]
+        if len(d)<len(n):
+            x=x[:len(d)]
+            y=y[:len(d)]
+        y=[current2flux(y[i],energy[i],p=None) for (i, e) in enumerate(y)]
+        return x,y,x_name,y_name
+    except:
+        pass
+
+
+
+def mda_NormDet(ScanNum,DetectorNum,NormNum,coeff=1,bckg=0,filepath=None,prefix=None):
+    """ Return x=positionner and y=detector(DetectorNum)
+    for a given detector number DYY (as shown in dview). """
+    try:
+        (data_file,det)=mda_unpack(ScanNum,filepath,prefix)
+        index=det[DetectorNum][1]
+        index_Norm=det[NormNum][1]
+        x = data_file[1].p[0].data
+        y= data_file[1].d[index].data
+        y_Norm=data_file[1].d[index_Norm].data
+        x_name = data_file[1].p[0].name
+        y_name = data_file[1].d[index].name#+"_norm:"+str(NormNum)
+        if type(x_name) == bytes:
+             x_name=x_name.decode("utf-8")
+        if type(y_name) == bytes:
+             y_name=y_name.decode("utf-8")
+
+        n=list(zip(x,y))
+        d=[n[i] for i, e in enumerate(n) if e != (0.0,0.0)]
+        if len(d)<len(n):
+            x=x[:len(d)]
+            y=y[:len(d)]
+        y=[y[i]/y_Norm[i] for i, e in enumerate(y)]
+        return x,y,x_name,y_name
+    except:
+        pass
+
+def mda_DivScan(ScanNum1,DetectorNum1,ScanNum2,DetectorNum2,coeff=1,bckg=0,filepath=None,prefix=None):
+    """ Return x=positionner and y=detector(DetectorNum)
+    for a given detector number DYY (as shown in dview). """
+    try:
+        (data_file1,det1)=mda_unpack(ScanNum1,filepath,prefix)
+        index1=det1[DetectorNum1][1]
+        (data_file2,det2)=mda_unpack(ScanNum2,filepath,prefix)
+        index2=det2[DetectorNum2][1]
+        x1 = data_file1[1].p[0].data
+        y1= data_file1[1].d[index1].data
+        y2= data_file2[1].d[index2].data
+        x_name = data_file1[1].p[0].name
+        y_name = data_file1[1].d[index1].name+"_norm:"+str(ScanNum2)
+        if type(x_name) == bytes:
+             x_name=x_name.decode("utf-8")
+        if type(y_name) == bytes:
+             y_name=y_name.decode("utf-8")
+
+        n=list(zip(x1,y1))
+        d=[n[i] for i, e in enumerate(n) if e != (0.0,0.0)]
+        if len(d)<len(n):
+            x1=x1[:len(d)]
+            y1=y1[:len(d)]
+        y=[y1[i]/y2[i] for i, e in enumerate(y1)]
+        return x1,y,x_name,y_name
+    except:
+        pass
+
+
+
+def mda_2D(ScanNum,DetectorNum,filepath=None,prefix=None):
+    """ Return x=positionner and y=detector(DetectorNum)
+    for a given detector number DYY (as shown in dview). """
+    try:
+        (data_file,det)=mda_unpack(ScanNum,filepath,prefix)
+        index=det[DetectorNum][1]
+        x_temp = data_file[2].p[0].data
+        y_temp = data_file[1].p[0].data
+        z_temp = data_file[2].d[index].data
+        x_name = data_file[2].p[0].name
+        y_name = data_file[1].p[0].name
+        z_name = data_file[2].d[index].name
+        if type(x_name) == bytes:
+             x_name=x_name.decode("utf-8")
+        if type(y_name) == bytes:
+             y_name=y_name.decode("utf-8")
+        if type(z_name) == bytes:
+             z_name=z_name.decode("utf-8")
+
+        n=list(zip(x_temp,y_temp,z_temp))
+        d=[n[i] for i, e in enumerate(n) if e != (0.0,0.0,0.0)]
+        if len(d)<len(n):
+            x_temp=x_temp[:len(d)]
+            y_temp=y_temp[:len(d)]
+            z_temp=z_temp[:len(d)]
+        x = x_temp[0]
+        y = y_temp
+        z = np.asarray(z_temp)     #2-D array
+        return x,y,z,x_name,y_name,z_name
+    except:
+        pass
+
+
+###############################################################################################
+####################################         PLOT MDA        ###################################
+###############################################################################################
+
+
+
+
+def plot_mda2D(ScanNum,DetectorNum,title=None,color=None,filepath=None,prefix=None):
+    try:
+        x,y,z,xName,yName,zName=mda_2D(ScanNum,DetectorNum,filepath,prefix)
+        fig, ax0 = plt.subplots()
+        if color is None:
+            color='gnuplot'
+        img = ax0.imshow(z, cmap=color, interpolation = 'nearest', extent = [min(x), max(x), max(y), min(y)], aspect = 'auto')
+        fig.colorbar(img)
+        if title is None:
+            plt.title(zName)
+        else:
+            plt.title(title)
+        ax0.set_xlabel(xName)
+        ax0.set_ylabel(yName)
+    #    ax0.set_ylim(y.max(),y.min())
+        plt.show()
+    except:
+        pass
+
+
+
+def plot_mda_series(*ScanDet,**kwArg):
+    """plot_mda_series(1217, 1226,   1,   39 ,0.025, **kwArg)
+                    (first,last,countby,det,offset,**kwArg)
+    Optional data analysis keywords arguments:
+        Flux conversion (for diode only): flux= 3(User) or 25(Staff).
+        Norm option: norm = 'yes' normalizes all the scans to 1 (default: None)
+        NormDet= 1 for SR current, 14  for Mesh (D-branch); Normalize by the mesh does not work with norm='yes'
+    Optional graphical keywords arguments:
+        sizeH = 1,1.5,... increase horizontal figure size
+        sizeV = 1,1.5,... increase vertical figure size
+        marker = 'x','+','o','v','^','D',...    (default:None)
+        markersize = 1,2,3,...        (default: 5)
+        linewidth = 0.5,1,2...         (default: 1)
+        linestyle = '-','--','-.',':'     (default: solid '-')
+        color = 'r','b','m','c','g','y'...    (default: jupyter colors series)
+        legend = 'best',Supper left', 'lower right'...        (default: None)
+        log = 'log'   (default: None = linear)
+        xrange = [x1,x2]   (default: None = Autoscale)
+        yrange = [y1,y2]   (default: None = Autoscale)
+        xlabel = 'mxLabel'        (default: pv name)
+        ylabel = 'myLabel'        (default: pv name)
+        ytickstyle = 'sci' for y axes    (default: 'plain')
+        xtickstyle = 'sci' for y axes    (default: 'plain')
+    filepath: by default plot scans for the current data folder (as defined in BL_ioc() ScanRecord SaveData)
+    or specified folder path:
+        e.g. user : filepath='/net/s29data/export/data_29idc/2018_2/UserName/mda/'
+        e.g. staff: filepath='/net/s29data/export/data_29idb/2018_2/mda/'
+    prefix: by default, uses prefix as defined in ScanRecord ("mda_")
+    scanIOC: by default, uses the IOC for the current branch as define in BL_IOC()
+    """
+
+    if type(ScanDet[0]) is not tuple:
+        ScanDet=(tuple(ScanDet),)
+        m=1
+    else: m= len(ScanDet)
+
+    scanlist=""
+    j=0
+    offset=0
+    for n in range(m):
+        print(n)
+        print(m)
+        print(ScanDet)
+        det=ScanDet[n][3]
+        if len(ScanDet)>4 and isinstance(ScanDet[n][3],str)== False:
+            offset=ScanDet[n][4]
+        for scanNum in range(ScanDet[n][0],ScanDet[n][1]+ScanDet[n][2],ScanDet[n][2]):
+            scanlist+=str(scanNum)+',(det,1,'+str(offset)+'),'
+            j+=offset
+        cmd="plot_mda("+scanlist
+    if kwArg is not None:
+        for key, value in list(kwArg.items()):
+            if type(value) == str:
+                cmd=cmd+(key+'=\"'+value+'\",')
+            else:
+                cmd=cmd+(key+'='+str(value)+',')
+    if cmd[-1]==",":
+        cmd=cmd[:-1]
+    cmd=cmd+")"
+    if kwArg is not None:
+        for key, value in list(kwArg.items()):
+            if key=='q':
+                print('det=',det)
+                print(cmd)
+    exec(cmd)
+
+
+
+def plot_mda(*ScanDet,**kwArg):
+
+    """
+    Plot mda scans: *ScanDet = (scan,det,scan,det...),(scan,det,scan,det...),title=(subplot_title1,subplot_title2)
+                             =            subplot1,                subplot2
+    Optional data analysis keywords arguments:
+        Flux conversion (for diode only): flux= 3(D## for mono rbv, typically 3).
+        Norm option: norm = 'yes' normalizes all the scans to 1 (default: None)
+        NormDet = 1 for SR current, 14  for Mesh (D-branch); Normalize by the mesh does not work with norm='yes'
+        DivScan = ?
+    Optional graphical keywords arguments:
+        sizeH = 1,1.5,... increase horizontal figure size
+        sizeV = 1,1.5,... increase vertical figure size
+        marker = 'x','+','o','v','^','D',...    (default:None)
+        markersize = 1,2,3,...        (default: 5)
+        linewidth = 0.5,1,2...         (default: 1)
+        linestyle = '-','--','-.',':'     (default: solid '-')
+        color = 'r','b','m','c','g','y'...    (default: jupyter colors series)
+        legend = 'best',Supper left', 'lower right'...        (default: None)
+        log = 'log'   (default: None = linear)
+        xrange = [x1,x2]   (default: None = Autoscale)
+        yrange = [y1,y2]   (default: None = Autoscale)
+        xlabel = 'mxLabel'        (default: pv name)
+        ylabel = 'myLabel'        (default: pv name)
+        ytickstyle = 'sci' for y axes    (default: 'plain')
+        xtickstyle = 'sci' for y axes    (default: 'plain')
+    filepath: by default plot scans for the current data folder (as defined in BL_ioc() ScanRecord SaveData)
+    or specified folder path:
+        e.g. user : filepath='/net/s29data/export/data_29idc/2018_2/UserName/mda/'
+        e.g. staff: filepath='/net/s29data/export/data_29idb/2018_2/mda/'
+    prefix: by default, uses prefix as defined in ScanRecord ("mda_")
+    scanIOC: by default, uses the IOC for the current branch as define in BL_IOC()
+    """
+
+    args={
+        'marker':None,
+        'markersize':5,
+        'linewidth':1,
+        'linestyle':'-',
+        'color':None,
+        'nticks':None,
+        'sizeH':1,
+        'sizeV':1,
+        'title':'',
+        'filepath':None,
+        'prefix':None,
+        'norm':None,
+        'flux':None,
+        'NormDet':None,
+        'scanIOC':None,
+        'legend':None,
+        'vs_index':None,
+        'vs_det':None,
+        'xrange':[None,None],
+        'yrange':[None,None],
+        'save':True
+    }
+    
+    args.update(kwArg)
+    
+    mkr=args['marker']
+    ms=args['markersize']
+    lw=args['linewidth']
+    ls=args['linestyle']
+    c=args['color']
+    path=args['filepath']
+    prefix=args['prefix']
+    scanIOC=args['scanIOC']
+    save=args['save']
+    
+    if 'legend' in args:
+        if args['legend'] == 'center left':
+            hsize=7
+            
+    if type(ScanDet[0]) is not tuple:
+        ScanDet=(tuple(ScanDet),)
+        m=1
+    else: m= len(ScanDet)
+
+    def SubplotsLayout(m):
+        if m >1:
+            ncols=2
+        else:
+            ncols=1
+        nrows=max(sum(divmod(m,2)),1)
+        hsize=ncols*5*args['sizeH']
+        vsize=nrows*4*args['sizeV']
+        if nrows==1: vsize=nrows*3.5*args['sizeV']
+        return nrows,ncols,hsize,vsize
+
+    try:
+        nrows,ncols,hsize,vsize=SubplotsLayout(m)
+
+        fig, axes = plt.subplots(nrows,ncols,figsize=(hsize,vsize))    # HxV
+        axes=np.array(axes)
+
+        for (n,ax) in zip(list(range(m)),axes.flat):
+            for (i,j) in zip(ScanDet[n][0::2],ScanDet[n][1::2]):
+                if type(j) is tuple:
+                    p,k,l=j
+                    x,y,x_name,y_name=mda_1D(i,p,k,l,path,prefix)
+                elif args['flux'] is not None:
+                    x,y,x_name,y_name=mda_Flux(i,j,args['flux'],path,prefix,scanIOC)
+                elif args['norm'] is not None:
+                    x,y,x_name,y_name=mda_1D_unscaled(i,j,path,prefix,scanIOC)
+                elif args['NormDet'] is not None:
+                    x,y,x_name,y_name=mda_NormDet(i,j,args['NormDet'],1,0,path,prefix,scanIOC)
+                elif args['vs_index'] is not None:
+                    x,y,x_name,y_name=mda_1D_Xindex(i,j,1,0,path,prefix)
+                elif args['vs_det'] is not None:
+                    x,y,x_name,y_name=mda_1D_vsDet(i,j,args['vs_det'],1,0,path,prefix)
+                #elif DivScan is not None:
+                #    x,y,x_name,y_name=mda_DivScan(i,j,DivScan,DivDet,1,0,path,prefix,scanIOC)
+                else:
+                    x,y,x_name,y_name=mda_1D(i,j,1,0,path,prefix,scanIOC)
+                ax.plot(x,y,label="mda_"+str(i),color=c,marker=mkr,markersize=ms,linewidth=lw,linestyle=ls)
+                ax.grid(color='lightgray', linestyle='-', linewidth=0.5)
+                
+                #modifying graph
+                if args['legend'] != None:
+                    if args['legend'] == 'center left':
+                        box = ax.get_position()
+                        ax.set_position([box.x0, box.y0, box.width * 0.6, box.height])
+                        ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
+                        myleft=0.1
+                        myright=0.55
+                    else:
+                        ax.legend(args['legend'], frameon=True)
+                if 'ytickstyle' in args:
+                    ax.ticklabel_format(style=args['ytickstyle'], axis='y', scilimits=(0,0))
+                if 'xtickstyle' in args:
+                    ax.ticklabel_format(style=args['xtickstyle'], axis='x', scilimits=(0,0))
+                if 'log' in args:
+                    ax.set_yscale('log')
+                if args['xrange'] != [None,None]:
+                    ax.set_xlim(args['xrange'][0],args['xrange'][1])
+                if args['yrange'] != [None,None]:
+                    ax.set_ylim(args['yrange'][0],args['yrange'][1])
+                if 'xlabel' in args:
+                    x_name=args['xlabel']
+                if 'ylabel' in args:
+                    y_name=args['ylabel']
+                if args['nticks'] != None: 
+                    tck=args['nticks']-1
+                    ax.locator_params(tight=None,nbins=tck)
+
+
+            if 'title' in args:
+                mytitle=args['title']
+                if type(mytitle) is not tuple:
+                    ax.set(xlabel=x_name,ylabel=y_name,title=mytitle)
+                else:
+                    p=len(mytitle)
+                    if n == p:
+                        ax.set(xlabel=x_name,ylabel=y_name,title='')
+                    else:
+                        ax.set(xlabel=x_name,ylabel=y_name,title=mytitle[n])
+        #        ax.text(0.5, 1.025,mytitle,horizontalalignment='center',fontsize=14,transform = ax.transAxes)
+            ax.grid(color='lightgray', linestyle='-', linewidth=0.5)
+                
+        if ncols==1 and nrows==1 and kwArg.get('legend')!='center left':
+            fig.subplots_adjust(wspace=0.5,hspace=0.5,left=0.25,right=0.88,top=0.85,bottom=0.22)
+        elif ncols==1 and kwArg.get('legend')=='center left':
+            fig.subplots_adjust(wspace=0.5,hspace=0.5,left=myleft,right=myright,top=0.85,bottom=0.22)
+        else:
+            fig.subplots_adjust(wspace=0.5,hspace=0.5,left=0.125,right=0.9,top=0.85,bottom=0.15)
+
+        plt.tight_layout()
+        if save:
+            try:
+                fname=join('/home/beams/29IDUSER/Documents/User_Folders/','lastfigure.png')
+                print(fname)
+                plt.savefig(fname)
+            except:
+                pass
+        plt.show()
+    except:
+        pass
+
+
+
+def plot_mda_lists(*ScanDet,**kwArg):
+    """
+    Plot mda scans: *ScanDet = (scanNum_list,detNum_list),(scanNum_list,detNum_list)
+                             =            subplot1,                subplot2
+    Optional data analysis keywords arguments:
+        Flux conversion (for diode only): flux= 3(User) or 25(Staff).
+        Norm option: norm = 'yes' normalizes all the scans to 1 (default: None)
+        NormDet= 1 for SR current, 14  for Mesh (D-branch); Normalize by the mesh does not work with norm='yes'
+    Optional graphical keywords argudef plot_mdaments:
+        sizeH = 1,1.5,... increase horizontal figure size
+        sizeV = 1,1.5,... increase vertical figure size
+        marker = 'x','+','o','v','^','D',...    (default:None)
+        markersize = 1,2,3,...        (default: 5)
+        linewidth = 0.5,1,2...         (default: 1)
+        linestyle = '-','--','-.',':'     (default: solid '-')
+        color = 'r','b','m','c','g','y'...    (default: jupyter colors F)
+        legend = 'best',Supper left', 'lower right'...        (default: None)
+        log = 'log'   (default: None = linear)
+        xrange = [x1,x2]   (default: None = Autoscale)
+        yrange = [y1,y2]   (default: None = Autoscale)
+        xlabel = 'mxLabel'        (default: pv name)
+        ylabel = 'myLabel'        (default: pv name)
+        ytickstyle = 'sci' for y axes    (default: 'plain')
+        xtickstyle = 'sci' for y axes    (default: 'plain')
+    filepath: by default plot scans for the current data folder (as defined in BL_ioc() ScanRecord SaveData)
+    or specified folder path:
+        e.g. user : filepath='/net/s29data/export/data_29idc/2018_2/UserName/mda/'
+        e.g. staff: filepath='/net/s29data/export/data_29idb/2018_2/mda/'
+    prefix: by default, uses prefix as defined in ScanRecord ("mda_")
+    scanIOC: by default, uses the IOC for the current branch as define in BL_IOC()
+    """
+    
+    args={
+        'marker':None,
+        'markersize':5,
+        'linewidth':1,
+        'linestyle':'-',
+        'color':None,
+        'nticks':None,
+        'sizeH':1,
+        'sizeV':1,
+        'title':'',
+        'filepath':None,
+        'prefix':None,
+        'norm':None,
+        'flux':None,
+        'NormDet':None,
+        'scanIOC':None,
+        'legend':None,
+        'vs_index':None,
+        'xrange':[None,None],
+        'yrange':[None,None]
+    }
+    
+    args.update(kwArg)
+    
+    mkr=args['marker']
+    ms=args['markersize']
+    lw=args['linewidth']
+    ls=args['linestyle']
+    c=args['color']
+    path=args['filepath']
+    prefix=args['prefix']
+    scanIOC=args['scanIOC']
+
+
+    
+    if 'legend' in args:
+        if args['legend'] == 'center left':
+            hsize=7
+            
+    #setting up the subplot
+    if type(ScanDet[0]) is not tuple:
+        ScanDet=(tuple(ScanDet),)
+        m=1
+    else: m= len(ScanDet)
+        
+    def SubplotsLayout(m):
+        if m >1:
+            ncols=2
+        else:
+            ncols=1
+        nrows=max(sum(divmod(m,2)),1)
+        hsize=ncols*5*args['sizeH']
+        vsize=nrows*4*args['sizeV']
+        if nrows==1: vsize=nrows*3.5*args['sizeV']
+        return nrows,ncols,hsize,vsize
+    
+    try:
+        nrows,ncols,hsize,vsize=SubplotsLayout(m)
+        fig, axes = plt.subplots(nrows,ncols,figsize=(hsize,vsize))    # HxV
+        axes=np.array(axes)
+
+
+        for (n,ax) in zip(list(range(m)),axes.flat): #n=subplot tuple
+            scanNum_list=ScanDet[n][0]
+            detNum_list=ScanDet[n][1]
+
+            if type(scanNum_list) is int:
+                scanNum_list=[scanNum_list]
+            if type(detNum_list) is int:
+                detNum_list=[detNum_list]
+                for i in range(1,len(scanNum_list)):
+                    detNum_list.append(detNum_list[0])
+            if type(args['filepath']) is not list:
+                filepath_list=[args['filepath']]
+                for i in range(1,len(scanNum_list)):
+                    filepath_list.append(filepath_list[0])
+            else: filepath_list=args['filepath']
+            if type(args['prefix']) is not list:
+                prefix_list=[args['prefix']]
+                for i in range(1,len(scanNum_list)):
+                    prefix_list.append(prefix_list[0]) 
+            else: prefix_list=args['prefix']
+            if type(args['scanIOC']) is not list:
+                scanIOC_list=[args['scanIOC']]
+                for i in range(1,len(scanNum_list)):
+                    scanIOC_list.append(scanIOC_list[0]) 
+            else: scanIOC_list=args['scanIOC']
+            #loading the data
+            for index in range(0,len(scanNum_list)):
+                i=scanNum_list[index]
+                j=detNum_list[index]
+                path=filepath_list[index]
+                prefix=prefix_list[index]
+                scanIOC=scanIOC_list[index]
+                #print(i)
+                if type(j) is tuple:
+                    p,k,l=j
+                    x,y,x_name,y_name=mda_1D(i,p,k,l,path,prefix)
+                elif args['flux'] is not None:
+                    x,y,x_name,y_name=mda_Flux(i,j,args['flux'],path,prefix,scanIOC)
+                elif args['norm'] is not None:
+                    x,y,x_name,y_name=mda_1D_unscaled(i,j,path,prefix,scanIOC)
+                elif args['NormDet'] is not None:
+                    x,y,x_name,y_name=mda_NormDet(i,j, args['NormDet'],1,0,path,prefix,scanIOC)
+                else:
+                    x,y,x_name,y_name=mda_1D(i,j,1,0,path,prefix,scanIOC)
+                #adding to graph
+                ax.grid(color='lightgray', linestyle='-', linewidth=0.5)
+                ax.plot(x,y,label="mda_"+str(i),color=c,marker=mkr,markersize=ms,linewidth=lw,linestyle=ls)
+
+            #modifying graph
+            if args['legend'] != None:
+                if args['legend'] == 'center left':
+                    box = ax.get_position()
+                    ax.set_position([box.x0, box.y0, box.width * 0.6, box.height])
+                    ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
+                    myleft=0.1
+                    myright=0.55
+                else:
+                    ax.legend(args['legend'], frameon=True)
+            if 'ytickstyle' in args:
+                ax.ticklabel_format(style=args['ytickstyle'], axis='y', scilimits=(0,0))
+            if 'xtickstyle' in args:
+                ax.ticklabel_format(style=args['xtickstyle'], axis='x', scilimits=(0,0))
+            if 'log' in args:
+                ax.set_yscale('log')
+            if args['xrange'] != [None,None]:
+                ax.set_xlim(args['xrange'][0],args['xrange'][1])
+            if args['yrange'] != [None,None]:
+                ax.set_ylim(args['yrange'][0],args['yrange'][1])
+            if 'xlabel' in args:
+                x_name=args['xlabel']
+            if 'ylabel' in args:
+                y_name=args['ylabel']
+            if args['nticks'] != None: 
+                tck=args['nticks']-1
+                ax.locator_params(tight=None,nbins=tck)
+
+            if 'title' in args:
+                if type(args['title']) is not str:
+                    mytitle=args['title'][n]
+                else:
+                    mytitle=args['title']
+            ax.set(xlabel=x_name,ylabel=y_name,title=mytitle)
+        #adjusting subplots
+        if ncols==1 and nrows==1 and kwArg.get('legend')!='center left':
+            fig.subplots_adjust(wspace=0.5,hspace=0.5,left=0.25,right=0.88,top=0.85,bottom=0.22)
+        elif ncols==1 and kwArg.get('legend')=='center left':
+            fig.subplots_adjust(wspace=0.5,hspace=0.5,left=myleft,right=myright,top=0.85,bottom=0.22)
+        else:
+            fig.subplots_adjust(wspace=0.5,hspace=0.5,left=0.125,right=0.9,top=0.85,bottom=0.15)
+        #show plot
+        plt.tight_layout()
+        plt.show()
+
+    except:
+        pass
+
+
+
+
+###############################################################################################
+####################################         PLOT netCDF        ###################################
+###############################################################################################
+
+
+
+
+def nc_unpack(ScanNum,FilePath=None,Prefix=None):
+    """
+    Returns the full netCDF data file
+        meta data (Attributes/Exta PVs) 
+            c.variables['Attr_EnergyStep_Swept'][:][0]
+        data array is accessed
+            nc.variables['array_data'][:][0]
+            
+    FilePath: by default plot scans for the current data folder (as shown on detector panel)
+    or specified folder path ending with '/':
+        e.g. user : FilePath='/net/s29data/export/data_29idc/2018_2/UserName/netCDF/'
+        e.g. staff: FilePath='/net/s29data/export/data_29idb/2018_2/netCDF/'
+    Prefix: by default, uses prefix as shown on detector panel ("EA_")
+    """
+    def GetFileName():
+        SubFolder= caget('29idcEA:netCDF1:FilePath',as_string=True)
+        if SubFolder[0]=='X': drive='b'
+        elif SubFolder[0]=='Y': drive='c'
+        FilePath='/net/s29data/export/data_29id'+drive+SubFolder[2:]+'/'
+        Prefix = caget("29idcEA:netCDF1:FileName_RBV",as_string=True)
+        return FilePath, Prefix
+
+    if FilePath is None:
+        FilePath=GetFileName()[0]
+    if Prefix is None:
+        Prefix= GetFileName()[1]
+    myFile=FilePath+Prefix+'{:04}.nc'.format(ScanNum)
+    nc = Dataset(myFile,mode='r')
+    return nc
+
+def EA_data(nc):
+    """ Returns: x,xname,ycrop,yname,img,ActualPhotonEnergy,WorkFunction,PE
+    """
+    
+    LowEnergy=nc.variables['Attr_LowEnergy'][:][0]
+    HighEnergy=nc.variables['Attr_HighEnergy'][:][0]
+    ActualPhotonEnergy=nc.variables['Attr_ActualPhotonEnergy'][:][0]
+    EnergyStep_Swept=nc.variables['Attr_EnergyStep_Swept'][:][0]
+    EnergyStep_Swept_RBV=nc.variables['Attr_EnergyStep_Swept_RBV'][:][0]
+    EperChannel=nc.variables['Attr_EnergyStep_Fixed_RBV'][:][0]
+    GratingPitch=nc.variables['Attr_GratingPitch'][:][0]
+    MirrorPitch=nc.variables['Attr_MirrorPitch'][:][0]
+
+    WorkFunction=nc.variables['Attr_Energy Offset'][:][0]
+
+    DetMode=nc.variables['Attr_DetectorMode'][:][0]         # BE=0,KE=1
+    AcqMode= nc.variables['Attr_AcquisitionMode'][:][0]        # Swept=0, Fixed=1, BS=2
+    LensMode=nc.variables['Attr_LensMode'][:][0]
+
+    PassEnergyMode=nc.variables['Attr_PassEnergy'][:][0]
+    PEdict={0:1,1:2,2:5,3:10,4:20,5:50,6:100,7:200,8:500}
+    PE=PassEnergyMode
+
+    #ActualPhotonEnergy,WorkFunction,PE=EA_metadata(nc)[0:3]
+    data = nc.variables['array_data'][:][0]
+
+    def SelectValue(which,x1,x2):
+        if which == 0: value=x1
+        if which == 1: value=x2
+        return value
+
+    ### Energy Scaling:
+    Edelta = SelectValue(DetMode,-EnergyStep_Swept,EnergyStep_Swept)
+    if AcqMode == 0:  # Swept
+        Ehv=ActualPhotonEnergy
+        Estart = SelectValue(DetMode, Ehv-LowEnergy, LowEnergy)
+        #Estop  = SelectValue(DetMode, Ehv-HighEnergy, HighEnergy)
+    if AcqMode >= 1:  # Fixed or Baby Swept
+        Ecenter=nc.variables['Attr_CentreEnergy_RBV'][:][0]
+        #print nc.variables#JM was here
+        #print Ecenter,Edelta#JM was here
+        Estart=Ecenter-(data.shape[1]/2.0)*Edelta
+    Eunits=SelectValue(DetMode,"Binding Energy (eV)","Kinetic Energy (eV)")
+
+    x=[Estart+Edelta*i for i,e in enumerate(data[0,:])]
+    xname=Eunits
+
+    ### Angular Scaling:
+    if LensMode>-1: # Angular Modes  RE changed from >0 (Angular) to >-1 (all mode)
+        CenterChannel=571
+        FirstChannel=0
+        Ddelta =0.0292717
+        Dstart = (FirstChannel-CenterChannel)*Ddelta
+        y=[Dstart+Ddelta*i for i,e in enumerate(data[:,0])]
+        #getting rid of edges with no data
+        data=nc.variables['array_data']
+        #x1=338;x2=819 #old
+        x1=338-100;x2=819-10
+        datacrop=data[:,x1:x2]
+        ycrop=y[x1:x2]
+        yname='Degrees'
+    else:
+        ycrop,yname=None,'mm'
+    return x,xname,ycrop,yname,datacrop,ActualPhotonEnergy,WorkFunction,PE
+
+
+
+
+def EA_Image(ScanNum,EnergyAxis='KE',FilePath=None,Prefix=None):
+    """
+    Returns
+        x = KE or BE energy scale; BE is calculated based on the wk in the SES and the mono energy
+        y = Integrated intensity
+        
+    FilePath: by default plot scans for the current data folder (as shown on detector panel)
+    or specified folder path ending with '/':
+        e.g. user : FilePath='/net/s29data/export/data_29idc/2018_2/UserName/netCDF/'
+        e.g. staff: FilePath='/net/s29data/export/data_29idb/2018_2/netCDF/'
+    Prefix: by default, uses prefix as shown on detector panel ("EA_")
+    
+    x,y,img=EA_Image(1)
+    plt.imshow(img,extent = [min(x), max(x), min(y), max(y)], aspect = 'auto')
+    plt.show())
+    """
+    nc=nc_unpack(ScanNum,FilePath,Prefix)
+    x,xname,y,yname,img,hv,wk,PE=EA_data(nc)
+    y=np.array(y)
+    img=img[0]
+    if EnergyAxis == 'KE':
+        x=np.array(x)
+    else:
+        x=hv-wk-np.array(x)
+    return x, y, img
+
+def EA_Spectrum(ScanNum,EnergyAxis='KE',FilePath=None,Prefix=None):
+    """
+    Returns
+        x = KE or BE energy scale; BE is calculated based on the wk in the SES and the mono energy
+        y = Integrated intensity
+    FilePath: by default plot scans for the current data folder (as shown on detector panel)
+    or specified folder path ending with '/':
+        e.g. user : FilePath='/net/s29data/export/data_29idc/2018_2/UserName/netCDF/'
+        e.g. staff: FilePath='/net/s29data/export/data_29idb/2018_2/netCDF/'
+    Prefix: by default, uses prefix as shown on detector panel ("EA_")
+    
+    Simple plot:   x,y=EA_Spectrum(ScanNum);plt.plot(x,y);plt.xlim(min(x),xmax(x));plt.show()
+"""
+    x, ang, img = EA_Image(ScanNum, EnergyAxis,FilePath,Prefix)
+    y = np.asarray([sum(img[:,i]) for i in range(img.shape[1])])
+    return x, y
+
+def EA_metadata(ScanNum,FilePath=None,Prefix=None):
+    """ Returns: ActualPhotonEnergy,WorkFunction,GratingPitch,MirrorPitch
+    """
+    nc=nc_unpack(ScanNum,FilePath,Prefix)
+    # SES parameters
+    LowEnergy=nc.variables['Attr_LowEnergy'][:][0]
+    HighEnergy=nc.variables['Attr_HighEnergy'][:][0]
+    EnergyStep_Swept=nc.variables['Attr_EnergyStep_Swept'][:][0]
+    EnergyStep_Swept_RBV=nc.variables['Attr_EnergyStep_Swept_RBV'][:][0]
+    EperChannel=nc.variables['Attr_EnergyStep_Fixed_RBV'][:][0]
+    WorkFunction=nc.variables['Attr_Energy Offset'][:][0]
+    DetMode=nc.variables['Attr_DetectorMode'][:][0]         # BE=0,KE=1
+    AcqMode= nc.variables['Attr_AcquisitionMode'][:][0]        # Swept=0, Fixed=1, BS=2
+    LensMode=nc.variables['Attr_LensMode'][:][0]
+    PassEnergyMode=nc.variables['Attr_PassEnergy'][:][0]
+    PEdict={0:1,1:2,2:5,3:10,4:20,5:50,6:100,7:200,8:500}
+    PE=PassEnergyMode
+
+    TEY=nc.variables['Attr_TEY'][:][0]
+
+    # Mono parameters
+    ActualPhotonEnergy=nc.variables['Attr_ActualPhotonEnergy'][:][0]
+    GratingPitch=nc.variables['Attr_GratingPitch'][:][0]
+    MirrorPitch=nc.variables['Attr_MirrorPitch'][:][0]
+    Grating_Density=nc.variables['Attr_Grating_Density'][:][0]
+    Grating_Slot=nc.variables['Attr_Grating_Slot'][:][0]
+    GRT_Offset_1=nc.variables['Attr_GRT_Offset_1'][:][0]
+    GRT_Offset_2=nc.variables['Attr_GRT_Offset_2'][:][0]
+    GRT_Offset_3=nc.variables['Attr_GRT_Offset_3'][:][0]
+    MIR_Offset_1=nc.variables['Attr_MIR_Offset_1'][:][0]
+    b2_GRT1=nc.variables['Attr_b2-GRT1'][:][0]
+    b2_GRT2=nc.variables['Attr_b2-GRT2'][:][0]
+    b2_GRT3=nc.variables['Attr_b2-GRT3'][:][0]
+
+    offset=[MIR_Offset_1,GRT_Offset_1,GRT_Offset_2,GRT_Offset_3]
+    b2=[0,b2_GRT1,b2_GRT2,b2_GRT3]
+
+    return WorkFunction,ActualPhotonEnergy,MirrorPitch,GratingPitch,Grating_Density,Grating_Slot,offset,b2
+
+
+def Get_EDCmax(ScanNum,EnergyAxis='KE',FilePath=None,Prefix=None):
+    x,y=EA_Spectrum(ScanNum, EnergyAxis,FilePath,Prefix)
+    maxY= max(y)
+    maxX=round(x[np.where(y == max(y))][0],3)
+    return maxX,maxY  # energy position, intensity of the peak
+
+
+
+def EDC_Series(first,last,countby, EnergyAxis='BE',title="",norm=None,FilePath=None,Prefix=None):
+    """
+    Plots a seriew of EA_Spectrum
+    """
+    if title == "":
+        title="Scans: "+str(first)+"/"+str(last)+"/"+str(countby)
+    fig = plt.figure(figsize=(6,6))
+    a1 = fig.add_axes([0,0,1,1])
+    for ScanNum in range(first,last+countby,countby):
+        x,y=EA_Spectrum(ScanNum, EnergyAxis,FilePath,Prefix)
+        if norm is not None: maxvalue=max(y)
+        else: maxvalue=1
+        plt.plot(x,y/maxvalue,label='#'+str(ScanNum))
+        plt.legend(ncol=2, shadow=True, title=title, fancybox=True)    
+        plt.grid(color='lightgray', linestyle='-', linewidth=0.5)
+    a1.plot
+    if EnergyAxis == 'BE':
+        a1.set_xlim(max(x),min(x))
+    plt.show()
+    
+
+    
+
+def plot_nc(*ScanNum,**kwgraph):
+    """
+    ScanNum = Scan number to be plotted: single scan, or range (first,last,countby) to average.
+    kwgraph = EDC / FilePath / Prefix
+        - Transmission mode: angle integrated EDC.
+        - Angular mode:
+            default: band map only
+            EDC = 'y' : angle integrated EDC only
+            EDC = 'both': angle integrated EDC + band map
+            EnergyAxis = KE (default) or BE (BE uses work function from SES)
+    FilePath: by default plot scans for the current data folder (as shown on detector panel)
+    or specified folder path ending with '/':
+        e.g. user : FilePath='/net/s29data/export/data_29idc/2018_2/UserName/netCDF/'
+        e.g. staff: FilePath='/net/s29data/export/data_29idb/2018_2/netCDF/'
+    Prefix: by default, uses prefix as shown on detector panel ("EA_")
+
+    """
+    FilePath,Prefix,EDC,EnergyAxis,avg=None,None,None,'KE',None
+    if kwgraph is not None:
+        for key, value in list(kwgraph.items()):
+            if key=='FilePath': FilePath=value
+            if key=='Prefix':   Prefix=value
+            if key=='EDC':   EDC=value
+            if key=='EnergyAxis':   EnergyAxis=value
+            if key=='avg':  avg=1
+    #Get lens mode
+    nc=nc_unpack(ScanNum[0],FilePath,Prefix)
+    LensMode=nc.variables['Attr_LensMode'][:][0]        
+    #Loading Scans ()
+    first=ScanNum[0]
+    if len(ScanNum)==1:
+        last =ScanNum[0]
+        countby=1
+    else:
+        last=ScanNum[1]
+        countby=ScanNum[2]
+    for n in range(first,last+countby,countby):
+        x,intensity=EA_Spectrum(n,EnergyAxis,FilePath,Prefix)
+        x,y,img =EA_Image(n,EnergyAxis,FilePath,Prefix)
+        if n == first:
+            Spectra=intensity
+            Img=img
+        else:
+            if avg == 1: #Summing the Scans
+                print('averaging')
+                Spectra=np.add(Spectra, intensity)
+                Img=np.add(Img,img)
+
+    #Getting plot size
+    if LensMode == 0 or EDC != None and EDC != 'both': #Integrated Angle only
+        hsize,vsize=6,3.5
+    elif LensMode >0 and EDC == None:
+        hsize,vsize=6,4
+    elif LensMode >0 and EDC == 'both':
+        hsize,vsize=6,8
+    if kwgraph is not None:
+        for key, value in list(kwgraph.items()):
+            if key=='hsize': hsize=value
+            if key=='vsize': vsize=value
+    #plotting\
+    if LensMode == 0 or EDC != None and EDC != 'both': #Integrated Angle only
+        #print('p-DOS only')
+        fig, ax = plt.subplots(figsize=(hsize,vsize))    # HxV
+        ax.plot(x,Spectra)
+        if EnergyAxis == "BE":
+            ax.set_xlim(max(x),min(x))
+        else:
+            ax.set_xlim(min(x),max(x))
+        ax.set(xlabel=EnergyAxis,ylabel='Intensity')
+        ax.ticklabel_format(style='sci', axis='y', scilimits=(0,0))
+        ax.grid(color='lightgray', linestyle='-', linewidth=0.5)
+    elif LensMode >0 and EDC is None: #Imgage Only
+        #print('Image Only')
+        fig, ax = plt.subplots(figsize=(hsize,vsize))    # HxV
+        if EnergyAxis == 'BE':
+            fig=ax.imshow(Img,extent = [max(x), min(x), min(y), max(y)], aspect = 'auto')
+        else:
+            fig=ax.imshow(Img,extent = [min(x), max(x), min(y), max(y)], aspect = 'auto')
+        ax.set(xlabel=EnergyAxis,ylabel="Angle")
+    elif LensMode >0 and EDC == 'both':
+        #print('both')
+        fig, axes = plt.subplots(2,1,figsize=(hsize,vsize))    # HxV
+        axes=np.array(axes)
+        for (n,ax) in zip(list(range(2)),axes.flat):
+            if n == 0:
+                ax.ticklabel_format(style='sci', axis='y', scilimits=(0,0))
+                ax.grid(color='lightgray', linestyle='-', linewidth=0.5)
+                ax.plot(x,Spectra)
+                if EnergyAxis == "BE":
+                    ax.set_xlim(max(x),min(x))
+                else:
+                    ax.set_xlim(min(x),max(x))
+                ax.set(xlabel=EnergyAxis,ylabel='Intensity')
+            if n == 1:
+                if EnergyAxis == 'BE':
+                    ax.imshow(Img,extent = [max(x), min(x), min(y), max(y)], aspect = 'auto')
+                else:
+                    ax.imshow(Img,extent = [min(x), max(x), min(y), max(y)], aspect = 'auto')
+                ax.set(xlabel=EnergyAxis,ylabel='Angle')
+    plt.tight_layout()
+    plt.show()
+
+
+def plot_nc_Sum(first,last,**kwgraph):
+
+    FilePath,Prefix=None,None
+    if kwgraph is not None:
+        for key, value in list(kwgraph.items()):
+            if key=='FilePath': FilePath=value
+            if key=='Prefix':   Prefix=value
+    for n in range(first,last+1):
+        print(n)
+        nc=nc_unpack(n,FilePath,Prefix)
+        x,xname,ycrop,yname,img,hv,wk,PE=EA_data(nc)
+        LensMode=nc.variables['Attr_LensMode'][:][0]
+        if n == first:
+            datasum = nc.variables['array_data']
+            x,xname,ycrop,yname,img,hv,wk,PE=EA_data(nc)
+        else:
+            data = nc.variables['array_data']
+            tmp=datasum
+            datasum=np.add(tmp,data)
+    crop_data=data[:,338:819]
+    fig, ax = plt.subplots(figsize=(6,4))    # HxV
+    fig=ax.imshow(crop_data.squeeze(),extent = [min(x), max(x), min(ycrop), max(ycrop)], aspect = 'auto')
+    plt.show()
+
+
+
+
+
+
+
+
+
+
+
+###############################################################################################
+##################################### FR curves fitting #######################################
+###############################################################################################
+
+
+def fit_mda(scannum,det,FWHM_or_PolyOrder,fct,hkl_positionner=False,xrange=None,title='',marker='x',graph=True, filepath=None,prefix=None):
+    """
+    fct= 'gauss','lorz','erf','poly','box'
+    hkl_positionner = 'H','K','L','tth','th','chi','phi'
+    """
+
+    if hkl_positionner == False:
+        x,y,x_name,y_name=mda_1D(scannum,det,1,0,filepath,prefix)
+    if hkl_positionner:
+        d={'h':46,'k':47,'l':48,'tth':54,'th':55,'chi':56,'phi':57}
+        x,y,x_name,y_name=mda_1D_vsDet(scannum,det,d[hkl_positionner.lower()],1,0,filepath,prefix)
+
+    
+
+    if BL.endstation == 'Kappa' and fct != 'poly':
+        try:
+            title=title + ' centroid = '+str(centroid_avg(scannum))
+        except:
+            pass
+
+    def closest(lst, K):
+        return lst[min(range(len(lst)), key = lambda i: abs(lst[i]-K))] 
+
+    def gaussian(x,*p):
+        amp, cen, wid, bkgd = p
+        return bkgd+amp*np.exp(-np.power(x - cen, 2.) / (2 * np.power(wid, 2.)))
+
+    def lorentzian( x, *p):
+        amp, x0, gam, bkgd =p
+        return bkgd+amp * gam**2 / ( gam**2 + ( x - x0 )**2)
+
+    def step(z,amp=1,bkgd=0,z0=0,width=1):
+        return (amp*erf((z-z0)/width))+bkgd
+
+    def box(x, *p):
+        height, center, width ,bkgd = p
+        return bkgd+height*(center-width/2 < x)*(x < center+width/2)
+
+
+
+    if xrange is not None:
+        x1=closest(x,xrange[0])
+        x2=closest(x,xrange[1])
+        xrange=[x.index(x1),x.index(x2)]
+        xmin=min(xrange)
+        xmax=max(xrange)
+        xcrop=x[xmin:xmax]
+        ycrop=y[xmin:xmax]
+        xdata = np.array(xcrop)
+        ydata = np.array(ycrop)
+    else:
+        xdata = np.array(x)
+        ydata = np.array(y)
+
+
+    Imax=np.max(ydata)
+    #print(xdata)
+    #print(ydata)
+    x0=xdata[np.where(ydata==Imax)][0]
+    A0=xdata[0]
+    
+    nPt_fit=200
+    xfit =  np.linspace(min(x),max(x), nPt_fit)
+    
+
+    if fct == 'gauss':
+        FWHM=FWHM_or_PolyOrder
+        best_vals, covar = curve_fit(gaussian, xdata, ydata, p0=[Imax, x0, FWHM, A0]) #5 p0=[amp,cen,wid]
+        yfit=gaussian(xfit,*best_vals) 
+        FWHM=2.355*best_vals[2]
+        center=best_vals[1]
+        print('Amplitude: ',best_vals[0])
+    elif fct == 'lorz':
+        FWHM=FWHM_or_PolyOrder
+        best_vals, covar = curve_fit(lorentzian, xdata, ydata, p0=[Imax, x0, FWHM, A0]) #5 p0=[amp,cen,wid]
+        yfit=lorentzian(xfit,*best_vals) 
+        FWHM=2.355*best_vals[2]
+        center=best_vals[1]
+        print('Amplitude: ',best_vals[0])
+    elif fct == 'erf' or fct == 'box':
+        FWHM=FWHM_or_PolyOrder
+        xmax=np.max(xdata)
+        xmin=np.min(xdata)
+        amp=np.mean(ydata)
+        x0=np.mean(xdata)
+        ymin=np.min(ydata)
+        if fct == 'erf':
+            yfirst=ydata[np.where(xdata == xmin)][0]
+            ylast =ydata[np.where(xdata == xmax)][0]
+            if yfirst-ylast >0: amp=-abs(amp) #amp <0 step down
+            else: amp = abs(amp)  #amp >0 step up
+            p0=[amp, ymin, x0, FWHM]
+            popt,pcor = curve_fit(step, xdata, ydata, p0=p0)
+            yfit=step(xfit,*popt) 
+            FWHM=popt[3]
+            center=popt[2]
+        elif fct == 'box':
+            p0=[amp, x0, FWHM, A0]
+            popt,pcor = curve_fit(box, xdata, ydata, p0=p0)
+            yfit=box(xfit,*popt) 
+            FWHM=popt[2]
+            center=popt[1]
+    elif fct == 'poly':
+        PolyRank=FWHM_or_PolyOrder
+        coefs = poly.polyfit(xdata, ydata, PolyRank)
+        yfit = poly.polyval(xfit, coefs)
+        result=''
+        for i in list(range(len(coefs))):
+            result=result+'a'+str(i)+' = '+str(round(coefs[i],3))+'\n'
+        print(result)
+        center=coefs
+    
+    if fct != 'poly':
+        print('Center: ',center)
+        print('FWHM: ',FWHM)
+        print('\n')
+    
+
+    if graph == True:
+        center=round(center,4)
+        fig,(ax1)=plt.subplots(1,1)
+        fig.set_size_inches(5,4)
+        ax1.plot(xdata,ydata,label='mda #'+str(scannum),marker=marker)
+        ax1.plot(xfit,yfit,label='fit @ '+str(center)[0:6])
+        ax1.set(ylabel=y_name)
+        ax1.set(xlabel=x_name)
+        ax1.ticklabel_format(style='sci', axis='y', scilimits=(0,0))
+        ax1.grid(color='lightgray', linestyle='-', linewidth=0.5)
+        ax1.legend(shadow=True, title=title, fancybox=True)
+    
+    return center
+
+
+def fit_centroid(n):
+    fit_mda(n,25,0,'poly',graph=False)
+
+def centroid_avg(scannum,det=25):   # det = detector number for centroid position
+    avg=round(fit_mda_poly(scannum,det,0,graph=None)[0],2)
+    return avg
+
+
+def fit_mda_gauss(scannum,det,FWHM,xrange=None,title='',marker='x',graph=1, filepath=None,prefix=None,scanIOC=None):
+    fct='gauss'
+    fit_mda(scannum,det,FWHM,fct,xrange,title,marker,graph, filepath,prefix,scanIOC)
+
+
+def fit_mda_lorz(scannum,det,FWHM,xrange=None,title='',marker='x',graph=1, filepath=None,prefix=None,scanIOC=None):
+    fct='lorz'
+    fit_mda(scannum,det,FWHM,fct,xrange,title,marker,graph, filepath,prefix,scanIOC)
+
+
+def fit_mda_erf(scannum,det,FWHM,xrange=None,title='',marker='x',graph=1, filepath=None,prefix=None,scanIOC=None):
+    fct='erf'
+    fit_mda(scannum,det,FWHM,fct,xrange,title,marker,graph, filepath,prefix,scanIOC)
+
+def fit_mda_poly(scannum,det,PolyRank,xrange=None,title='',marker='x',graph=1, filepath=None,prefix=None,scanIOC=None):
+    fct='poly'
+    fit_mda(scannum,det,PolyRank,fct,xrange,title,marker,graph, filepath,prefix,scanIOC)
+
+
+def fit_mda_box(scannum,det,FWHM,xrange=None,title='',marker='x',graph=1, filepath=None,prefix=None,scanIOC=None):
+    fct='box'
+    fit_mda(scannum,det,FWHM,fct,xrange,title,marker,graph, filepath,prefix,scanIOC)
+
+
+    
+    
+    
+    
+    
+    
+###############################################################################################
+######################################### hkl ###################################
+###############################################################################################
+
+
+
+def plot_hkl(mydata,n,x,y,title='',nlabel=''):
+    """mydata = instance of mdaFile object
+    n = scan number or [scan number1, ..., scan number N]
+    x = h, k or l index (D##)
+    d = detector index (D##)
+    """
+    if type(n) == int:
+        maxpts=mydata.dim1[n].curr_pt
+        x_index=mydata.dim1[n].kappaDet()[x][0]
+        y_index=mydata.dim1[n].kappaDet()[y][0]
+        x_name =mydata.dim1[n].d[x_index].desc
+        y_name =mydata.dim1[n].kappaDet()[y][2]
+        plt.plot(mydata.dim1[n].d[x_index].data[:maxpts],mydata.dim1[n].d[y_index].data[:maxpts],label='scan #'+str(n)+' '+nlabel)
+    elif type(n) == list:
+        for i,j in enumerate(n): 
+            maxpts=mydata.dim1[j].curr_pt
+            x_index=mydata.dim1[j].kappaDet()[x][0]
+            y_index=mydata.dim1[j].kappaDet()[y][0]
+            x_name =mydata.dim1[j].d[x_index].desc
+            y_name =mydata.dim1[j].kappaDet()[y][2]
+            try:
+                curve_label='scan #'+str(j)+' '+nlabel[i]
+            except:
+                curve_label='scan #'+str(j)
+            plt.plot(mydata.dim1[j].d[x_index].data[:maxpts],mydata.dim1[j].d[y_index].data[:maxpts],label=curve_label)
+    else:
+        print('n must be a single scan (int) or a list of scan')
+        return
+    plt.xlabel(x_name)
+    plt.ylabel(y_name)
+    plt.locator_params(tight=None,nbins=5,axis='x')
+    plt.legend(ncol=1, shadow=True, title=title, fancybox=True,loc='center left', bbox_to_anchor=(1, 0.5))
+    plt.grid(color='lightgray', linestyle='-', linewidth=0.5)
+    plt.show()
+
+    
+def fit_hkl(mydata,n,pos,det,FWHM,fct='gauss',xrange=None,title='',marker='x',graph=1):
+    """
+    mydata = instance of the class mdaFile
+         n = scan number
+       pos = D## for positioner
+       det = D## for detector
+      FWHM = width estimate
+       fct = 'gauss' or 'lorz'
+    xrange = [x1,x2] subrange for fit 
+    """
+
+
+    x_index=mydata.dim1[n].kappaDet()[pos][0]
+    y_index=mydata.dim1[n].kappaDet()[det][0]
+    x_name =mydata.dim1[n].d[x_index].desc
+    y_name =mydata.dim1[n].kappaDet()[det][2]
+
+    x=mydata.dim1[n].d[x_index].data
+    y=mydata.dim1[n].d[y_index].data
+
+    def closest(lst, K):
+        return lst[min(range(len(lst)), key = lambda i: abs(lst[i]-K))] 
+
+    if xrange is not None:
+        x1=closest(x,xrange[0])
+        x2=closest(x,xrange[1])
+        xrange=[np.where(x==x1),np.where(x==x2)]
+        xmin=min(xrange)
+        xmax=max(xrange)
+        xmin=min(xrange[0][0])
+        xmax=max(xrange[1][0])
+        xcrop=x[xmin:xmax]
+        ycrop=y[xmin:xmax]
+        xdata = np.array(xcrop)
+        ydata = np.array(ycrop)
+    else:
+        xdata = np.array(x)
+        ydata = np.array(y)
+    
+    Imax=np.max(ydata)
+    x0=xdata[np.where(ydata==Imax)][0]
+    
+    nPt_gaus=200
+    xfit =  np.linspace(min(x),max(x), nPt_gaus)
+
+
+    def lorentzian( x, amp, x0, gam ):
+        return amp * gam**2 / ( gam**2 + ( x - x0 )**2)
+    
+    def gaussian(x, amp, cen, wid):
+        return amp*np.exp(-np.power(x - cen, 2.) / (2 * np.power(wid, 2.)))
+    
+    if fct == 'gauss':
+        best_vals, covar = curve_fit(gaussian, xdata, ydata, p0=[Imax, x0, FWHM]) #5 p0=[amp,cen,wid]
+        yfit=gaussian(xfit,*best_vals) 
+    elif fct == 'lorz':
+        best_vals, covar = curve_fit(lorentzian, xdata, ydata, p0=[Imax, x0, FWHM]) #5 p0=[amp,cen,wid]
+        yfit=lorentzian(xfit,*best_vals)
+    else:
+        print('Not a valid function: fct = "gauss" or fct = "lorz"')
+        return
+
+    FWHM=2.355*best_vals[2]
+    center=best_vals[1]
+    print('Amplitude: ',best_vals[0])
+    print('Center: ',center)
+    print('FWHM: ',FWHM)
+    
+    if graph is not None:
+        fig,(ax1)=plt.subplots(1,1)
+        fig.set_size_inches(5,4)
+        ax1.plot(xdata,ydata,label='data',marker=marker)
+        ax1.plot(xfit,yfit,label='fit @ '+str(center)[0:6])
+        ax1.set(ylabel=y_name)
+        ax1.set(xlabel=x_name)
+        ax1.locator_params(tight=None,nbins=5,axis='x')
+        ax1.ticklabel_format(style='sci', axis='y', scilimits=(0,0))
+        ax1.grid(color='lightgray', linestyle='-', linewidth=0.5)
+        ax1.legend(shadow=True, title=title, fancybox=True)
+    
+    return center
+
+
+def fit_d4(n=BL.mda.lastFileNum()):    
+    d4=fit_mda(n,34,0.1,'gauss',title='mda_'+str(n).zfill(4))  
+    return round(d4,3)
+
+def fit_d3(n=BL.mda.lastFileNum()):
+    d3=fit_mda(n,33,3,'gauss',title='mda_'+str(n).zfill(4))  
+    return round(d3,3)
+
+def fit_z(n=BL.mda.lastFileNum(),d=33):
+    z=fit_mda(n,d,500,'erf',title='mda_'+str(n).zfill(4))  
+    return round(z,0)
+    
+def plotd():
+    dets=[34,33,35]
+    n=BL.mda.lastFileNum()
+    d=dets[caget('29idKappa:det:set')]
+    plot_mda(n,d,title='mda_'+str(n).zfill(4))  
+
+    
+     
+def Find_kth_zero(th_0,th_180):
+    """
+    th_0 is the motor position for specular near zero 
+    th_180 is motor position for spectular near 180 
+    """
+    
+    Offset =0.5*(180 - th_180 - th_0)
+
+    print("with motor at 0, the actual value is ",Offset)
+    
+
+# def read_hkl_old(n,user=None,run=None):
+#     h=[]
+#     k=[]
+#     l=[]
+#     if user is None: user=MDA_CurrentUser()
+#     if run is None: run=MDA_CurrentRun()
+#     with open('/home/beams/29IDUSER/Documents/User_Folders/'+user+'/hkl/scan_'+str(n)+'.txt') as csv_file:    
+#         csv_f=csv.reader(csv_file,delimiter=',')
+#         for row in csv_f:
+#             if not row[0]=='h':
+#                 h.append(float(row[0]))
+#                 k.append(float(row[1]))
+#                 l.append(float(row[2]))
+#     return np.array(h), np.array(k), np.array(l)
+
+# def plot_hkl_old(mydata,n1,n2=None,which='h',det=39,cropMin=None,cropMax=None,title=''):
+#     D=mydata.kappaDet(n1)
+#     d=D[det][1]
+#     if which == 'h':
+#         m = 0
+#     if which == 'k':
+#         m = 1
+#     if which == 'l':
+#         m = 2
+
+#     plt.figure(num=None, figsize=(6, 6), dpi=80, facecolor='w', edgecolor='k')
+#     if n2 == None:
+#         n=n1
+#         #dif=len(read_hkl(n)[m])-mydata.dim1[n].curr_pt
+#         if cropMax is not None:
+#             x=read_hkl(n)[m][cropMin:-cropMax]
+#         else:
+#             x=read_hkl(n)[m][cropMin:]
+
+#         plt.plot(x,mydata.dim1[n].d[d].data,label='scan #'+str(n),marker='+')
+#     else:
+#         for n in range(n1,n2+1): 
+#             #dif=len(read_hkl(n)[m])-mydata.dim1[n].curr_pt
+#             if cropMax is not None:
+#                 x=read_hkl(n)[m][cropMin:-cropMax]
+#             else:
+#                 x=read_hkl(n)[m][cropMin:]
+
+#             plt.plot(x,mydata.dim1[n].d[d].data,label='scan #'+str(n),marker='+')
+#     plt.xlabel(which)
+#     plt.ylabel(D[det][-1])
+#     plt.legend(ncol=1, shadow=True, title=title, fancybox=True,loc='center left', bbox_to_anchor=(1, 0.5))
+#     #plt.title(title)
+#     plt.grid(color='lightgray', linestyle='-', linewidth=0.5)
+#     plt.show()
+
+
+
+# def fit_hkl_gauss_old(scannum,det,FWHM,which='l',cropMin=None,cropMax=None,xrange=None,title='',marker='x',graph=1):
+#     motor,y,motor_name,y_name=mda_1D(scannum,det,1,0)
+#     if which == 'h':
+#         m = 0
+#     if which == 'k':
+#         m = 1
+#     if which == 'l':
+#         m = 2
+#     if cropMax is not None:
+#         x=read_hkl(scannum)[m][cropMin:-cropMax]
+#     else:
+#         x=read_hkl(scannum)[m][cropMin:]
+#     def closest(lst, K):
+#         return lst[min(range(len(lst)), key = lambda i: abs(lst[i]-K))] 
+
+#     if xrange is not None:
+#         x1=closest(x,xrange[0])
+#         x2=closest(x,xrange[1])
+#         xrange=[np.where(x==x1),np.where(x==x2)]
+#         xmin=min(xrange)
+#         xmax=max(xrange)
+#         xmin=min(xrange[0][0])
+#         xmax=max(xrange[1][0])
+#         xcrop=x[xmin:xmax]
+#         ycrop=y[xmin:xmax]
+#         xdata = np.array(xcrop)
+#         ydata = np.array(ycrop)
+#     else:
+#         xdata = np.array(x)
+#         ydata = np.array(y)
+    
+#     Imax=np.max(ydata)
+#     x0=xdata[np.where(ydata==Imax)][0]
+    
+#     nPt_gaus=200
+#     xfit =  np.linspace(min(x),max(x), nPt_gaus)
+    
+#     def gaussian(x, amp, cen, wid):
+#         return amp*np.exp(-np.power(x - cen, 2.) / (2 * np.power(wid, 2.)))
+    
+#     best_vals, covar = curve_fit(gaussian, xdata, ydata, p0=[Imax, x0, FWHM]) #5 p0=[amp,cen,wid]
+#     yfit=gaussian(xfit,*best_vals) 
+#     FWHM=2.355*best_vals[2]
+#     center=best_vals[1]
+#     print('Amplitude: ',best_vals[0])
+#     print('Center: ',center)
+#     print('FWHM: ',FWHM)
+    
+#     if graph is not None:
+#         fig,(ax1)=plt.subplots(1,1)
+#         fig.set_size_inches(5,4)
+#         ax1.plot(xdata,ydata,label='data',marker=marker)
+#         ax1.plot(xfit,yfit,label='fit @ '+str(center)[0:6])
+#         ax1.set(ylabel=y_name)
+#         ax1.set(xlabel=which)
+#         ax1.ticklabel_format(style='sci', axis='y', scilimits=(0,0))
+#         ax1.grid(color='lightgray', linestyle='-', linewidth=0.5)
+#         ax1.legend(shadow=True, title=title, fancybox=True)
+    
+#     return center
+    
+    
+###############################################################################################
+######################################### Start Of The Week ###################################
+###############################################################################################
+
+def plot_StartOfTheWeek_DetDict(branch):
+    """
+    returns the detectors for a given branch
+    
+    """
+    DetDict={'c':(9,7,8,15),'d':(9,7,8,14)}
+    return DetDict[branch]
+
+def StartOfTheWeek_plot(branch,FirstScanNum,**kwargs):
+    """
+    Plots the data from StartOfTheWeek
+    
+    branch is used to set the detectors
+        detCA4,detH,detV,detDiode=plot_StartOfTheWeek_Det(branch)
+        
+    FirstScanNum is based on slit1A
+        slit1A-H = FirstScanNum
+        slit1A-V = FirstScanNum + 1
+        wire1-H = FirstScanNum + 2
+        wire1-V = FirstScanNum + 3
+        monoVslit = FirstScanNum + 4/5/6/7
+        flux = FirstScanNum + 8
+        
+    Slit 1A and Wire scans: determine ID steering and Slit1A position
+    Scan_MonoVsSlit: determine the steering from M0/M1 
+        by default the full range is plotted (pnt_first=0, pnt_last=inf)
+        refine the plot via
+            plot_StartOfTheWeek_mono(branch,FirstScanNum,pnt_first,pnt_last)
+
+    kwargs: 
+        filepath = None,  uses current mda filepath unless specified
+              e.g. user : filepath='/net/s29data/export/data_29idc/2018_2/UserName/mda/'
+              e.g. staff: filepath='/net/s29data/export/data_29idb/2018_2/mda/'
+        prefix = None, uses current mda prefix unless specified 
+        scanIOC = None, uses BL_ioc() unless specified
+        
+        scanType = ['slit1','wire','flux','monoVslit'], full set by default
+        
+        ref_firstScanNum to plot reference spectra
+        ref_branch = branch, unless specified
+        ref_filepath = filepath, unless specified
+        ref_prefix = prefix, unless specified
+
+    steering out => moves beam more positive (20 urad ~ 0.5 mm)
+    steering up  => moves beam more positive (20 urad ~ 0.5 mm)
+    
+figure, axes = plt.subplots(nrows=2, ncols=2)
+axes[0, 0].plot(x, y)
+    """
+    
+    kwargs.setdefault('filepath',BL.mda.filepath())
+    kwargs.setdefault('prefix',BL.mda.prefix())
+    
+    kwargs.setdefault('scanType',['slit1','wire','flux','monoVslit'])
+    
+    kwargs.setdefault('ref_firstScanNum',None)
+    kwargs.setdefault('ref_fpath',None)
+    kwargs.setdefault('ref_branch',branch)
+    kwargs.setdefault('ref_filepath',BL.mda.filepath())
+    kwargs.setdefault('ref_prefix',BL.mda.prefix())
+    
+    kwargs.setdefault('debug',False)
+
+    
+    scanNum=FirstScanNum
+    ref_firstScanNum=kwargs['ref_firstScanNum']
+    detCA4,detH,detV,detDiode=plot_StartOfTheWeek_DetDict(branch)
+    
+
+    if 'slit1' in kwargs['scanType']:
+        if kwargs['debug']:
+            print('slit1')
+        plot_StartOfTheWeek_slit1A(branch,scanNum,**kwargs)
+        scanNum+=2
+        if kwargs['ref_firstScanNum'] is not None:
+            kwargs.update({'ref_firstScanNum':ref_firstScanNum+2})
+            
+            
+    if 'wire' in kwargs['scanType']:
+        if kwargs['debug']:
+            print('wire')
+        plot_StartOfTheWeek_wire(branch,scanNum,**kwargs)
+        scanNum+=2
+        if kwargs['ref_firstScanNum'] is not None:
+            ref_firstScanNum+=2
+            kwargs.update({'ref_firstScanNum':ref_firstScanNum+2})
+            
+    if 'monoVslit' in kwargs['scanType']:
+        d=IEXdata(scanNum,path=kwargs['filepath'],prefix=kwargs['prefix'],q=1)
+        if d.mda[scanNum].header.all['rank']<2:  #quick
+            print(scanNum, detDiode)
+            V2=fit_mda(scanNum,detDiode,1,'gauss',filepath=kwargs['filepath'],prefix=kwargs['prefix'],scanIOC=kwargs['scanIOC'],title='2V - mda_'+str(scanNum))
+            H2=fit_mda(scanNum+1,detDiode,1,'gauss',filepath=kwargs['filepath'],prefix=kwargs['prefix'],scanIOC=kwargs['scanIOC'],title='2H - mda_'+str(scanNum+1))
+            V1=fit_mda(scanNum+2,detDiode,1,'gauss',filepath=kwargs['filepath'],prefix=kwargs['prefix'],scanIOC=kwargs['scanIOC'],title='1V - mda_'+str(scanNum+2))
+            H1=fit_mda(scanNum+3,detDiode,1,'gauss',filepath=kwargs['filepath'],prefix=kwargs['prefix'],scanIOC=kwargs['scanIOC'],title='1H - mda_'+str(scanNum+3))
+            plt.show()
+            print('\nFit positions:')
+            print(f"V2={round(V2,3)}")
+            print(f"H2={round(H2,3)}")
+            print(f"V1={round(V1,3)}")
+            print(f"H1={round(H1,3)}")
+            
+        else:  #MonoVsSlit
+            print('\n# To plot the Mono vs Slit data use:\n')
+            print('\tplot_MonoVsSlit(\"'+branch+'\",'+str(scanNum)+','+str(detDiode)+',0,inf)'+'\t#2V')
+            print('\tplot_MonoVsSlit(\"'+branch+'\",'+str(scanNum+1)+','+str(detDiode)+',0,inf)'+'\t#2H')
+            print('\tplot_MonoVsSlit(\"'+branch+'\",'+str(scanNum+2)+','+str(detDiode)+',0,inf)'+'\t#1V')
+            print('\tplot_MonoVsSlit(\"'+branch+'\",'+str(scanNum+3)+','+str(detDiode)+',0,inf)'+'\t#1H')
+            print('\n#  (pnt_first,pnt_last0=(0,inf) => plots all')
+            print('#  select specific first/last to refine.')
+
+        print('\nREMEMBER to update slit center using: \tupdate_slit_dict()' )
+        scanNum+=4
+        if kwargs['ref_firstScanNum'] is not None:
+            kwargs.update({'ref_firstScanNum':ref_firstScanNum+4})
+        
+    if 'flux' in kwargs['scanType']:
+        if kwargs['debug']:
+            print('flux')
+        plot_StartOfTheWeek_flux(branch,scanNum,**kwargs)
+
+def plot_StartOfTheWeek_slit1A(branch,scanNum,**kwargs):
+    """
+    plots the slit1A scans
+    scanNum = slit1A-H scanNum
+    """   
+    kwargs.setdefault('filepath',BL.mda.filepath())
+    kwargs.setdefault('prefix',BL.mda.prefix())
+    kwargs.setdefault('plotType',['slit1','wire','flux','monoVslit'])
+    kwargs.setdefault('ref_firstScanNum',None)
+    kwargs.setdefault('ref_fpath',None)
+    kwargs.setdefault('ref_branch',branch)
+    kwargs.setdefault('ref_filepath',BL.mda.filepath())
+    kwargs.setdefault('ref_prefix',BL.mda.prefix())
+    kwargs.setdefault('debug',False)
+
+    detCA4,detH,detV,detDiode=plot_StartOfTheWeek_DetDict(branch)
+    ref_detCA4,ref_detH,ref_detV,ref_detDiode=plot_StartOfTheWeek_DetDict(kwargs['ref_branch']) 
+    
+    figure, axes = plt.subplots(nrows=1, ncols=2,figsize=(10,3))
+    for i,t in enumerate(['1H center scan','1V center scan']):
+        d=IEXdata(scanNum,path=kwargs['filepath'],prefix=kwargs['prefix'],q=1)
+        axes[i].plot(d.mda[scanNum].det[detCA4].scale['x'], d.mda[scanNum].det[detCA4].data,marker='x',label=str(scanNum))
+        scanNum+=1
+        if kwargs['ref_firstScanNum'] is not None:
+            ref_scanNum=kwargs['ref_firstScanNum']+i
+            ref_d=IEXdata(ref_scanNum,path=kwargs['ref_filepath'],prefix=kwargs['ref_prefix'],q=1)
+            axes[i].plot(ref_d.mda[ref_scanNum].det[ref_detCA4].scale['x'], ref_d.mda[ref_scanNum].det[ref_detCA4].data,marker='x',label=str(ref_scanNum))
+        axes[i].grid(color='lightgray', linestyle='-', linewidth=0.5)
+        axes[i].title.set_text(t)
+        axes[i].legend()
+    plt.show()
+    print("\nsteering out => move beam more positive (10 urad ~ 0.25 mm)")
+    print("steering up  => move beam more positive (10 urad ~ 0.25 mm)")
+    print("\nTo fit beam position use:\n")
+    print("detCA4,detH,detV,detDiode=plot_StartOfTheWeek_DetDict('"+kwargs['ref_branch']+"')")
+    print("fit_mda("+str(scanNum-2)+",detCA4,1,'gauss',xrange=(-1,1))")
+    print("fit_mda("+str(scanNum-1)+",detCA4,1,'gauss',xrange=(-1,1))\n")
+
+    
+def plot_StartOfTheWeek_wire(branch,scanNum,**kwargs):
+    """
+    plots the wire scans
+    scanNum = wire-H scanNum
+    """   
+    kwargs.setdefault('filepath',BL.mda.filepath())
+    kwargs.setdefault('prefix',BL.mda.prefix())
+    kwargs.setdefault('plotType',['slit1','wire','flux','monoVslit'])
+    kwargs.setdefault('ref_firstScanNum',None)
+    kwargs.setdefault('ref_fpath',None)
+    kwargs.setdefault('ref_branch',branch)
+    kwargs.setdefault('ref_filepath',BL.mda.filepath())
+    kwargs.setdefault('ref_prefix',BL.mda.prefix())
+    kwargs.setdefault('debug',False)
+
+    detCA4,detH,detV,detDiode=plot_StartOfTheWeek_DetDict(branch)
+    ref_detCA4,ref_detH,ref_detV,ref_detDiode=plot_StartOfTheWeek_DetDict(kwargs['ref_branch']) 
+    
+    figure, axes = plt.subplots(nrows=1, ncols=2,figsize=(10,3))
+    for i,t in enumerate(['H-wire','V-wire']):
+        d=IEXdata(scanNum,path=kwargs['filepath'],prefix=kwargs['prefix'],q=1)
+        #niceplot(d.mda[scanNum].det[DetDict[branch][1+i]],marker='x',label=str(scanNum))
+        detNum=plot_StartOfTheWeek_DetDict(branch)[1+i]
+        axes[i].plot(d.mda[scanNum].det[detNum].scale['x'], d.mda[scanNum].det[detNum].data,marker='x',label=str(scanNum))
+        scanNum+=1
+        if kwargs['ref_firstScanNum'] is not None:
+            ref_scanNum=kwargs['ref_firstScanNum']+i
+            ref_d=IEXdata(ref_scanNum,path=kwargs['ref_filepath'],prefix=kwargs['ref_prefix'],q=1)
+            #niceplot(ref_d.mda[ref_scanNum].det[DetDict[kwargs["ref_branch"]][1+i]],marker='x',label=str(ref_scanNum))
+            detNum=plot_StartOfTheWeek_DetDict(kwargs["ref_branch"])[1+i]
+            axes[i].plot(ref_d.mda[ref_scanNum].det[detNum].scale['x'], ref_d.mda[ref_scanNum].det[detNum].data,marker='x',label=str(ref_scanNum))
+        axes[i].grid(color='lightgray', linestyle='-', linewidth=0.5)
+        axes[i].title.set_text(t)
+        axes[i].legend()
+    plt.show()    
+        
+def plot_StartOfTheWeek_flux(branch,scanNum,**kwargs):
+    """
+    plots the wire scans
+    scanNum = wire-H scanNum
+    """   
+    kwargs.setdefault('filepath',BL.mda.filepath())
+    kwargs.setdefault('prefix',BL.mda.prefix())
+    kwargs.setdefault('plotType',['slit1','wire','flux','monoVslit'])
+    kwargs.setdefault('ref_firstScanNum',None)
+    kwargs.setdefault('ref_fpath',None)
+    kwargs.setdefault('ref_branch',branch)
+    kwargs.setdefault('ref_filepath',BL.mda.filepath())
+    kwargs.setdefault('ref_prefix',BL.mda.prefix())
+    kwargs.setdefault('debug',False) 
+
+    detCA4,detH,detV,detDiode=plot_StartOfTheWeek_DetDict(branch)
+    ref_detCA4,ref_detH,ref_detV,ref_detDiode=plot_StartOfTheWeek_DetDict(kwargs['ref_branch'])     
+    
+    for t in ['ID peak @ 500eV']:
+        d=IEXdata(scanNum,path=kwargs['filepath'],prefix=kwargs['prefix'],q=1)
+        niceplot(d.mda[scanNum].det[detDiode],marker='x',label=str(scanNum))
+        scanNum+=1
+        if kwargs['ref_firstScanNum'] is not None:
+            ref_scanNum=kwargs['ref_firstScanNum']+2
+            ref_d=IEXdata(ref_scanNum,path=kwargs['ref_filepath'],prefix=kwargs['ref_prefix'],q=1)
+            niceplot(ref_d.mda[ref_scanNum].det[ref_detDiode],marker='x',label=str(ref_scanNum))
+            ref_scanNum+=1
+        plt.grid(color='lightgray', linestyle='-', linewidth=0.5)
+        plt.title(t)
+        plt.legend()
+        plt.show()
+    
+def plot_MonoVsSlit(branch,ScanNum,detDiode,pnt_first,pnt_last,norm=True,filepath=None,prefix=None,scanIOC=None):
+    """
+    Plots Scan_MonoVsSlit to determine the steering from M0/M1 
+        To plot the full range (pnt_first=0, pnt_last=inf)
+    plot_StartofWeek_mono(branch,FirstScanNum+4,pnt_first,pnt_last)
+    
+    filepath: by default plot scans for the current data folder (as defined in BL_ioc() ScanRecord SaveData)
+    or specified folder path ending with '/':
+        e.g. user : filepath='/net/s29data/export/data_29idc/2018_2/UserName/mda/'
+        e.g. staff: filepath='/net/s29data/export/data_29idb/2018_2/mda/'
+    prefix: by default, uses prefix as defined in ScanRecord ("mda_")
+    """
+    x,y,z,x_name,y_name,z_name=mda_2D(ScanNum,detDiode,filepath,prefix,scanIOC)
+    Which=str(y_name)[10:12]
+    if pnt_last is inf:
+        pnt_last=len(z)-1
+    for i in range(pnt_first,pnt_last+1):
+        maxvalue=max(z[i])
+        if norm == True:
+            plt.plot(x,z[i]/maxvalue,label='#'+str(i)+': '+str(round(y[i],2)))
+        else:
+            plt.plot(x,z[i],label='#'+str(i)+': '+str(round(y[i],2)))
+        plt.legend(bbox_to_anchor=(1, 0), loc='lower left', ncol=2,shadow=True, title="ScanNum: "+str(ScanNum)+"\nSlit-"+Which+" position", fancybox=True)
+        #plt.legend(loc='lower left',ncol=2, shadow=True, title="ScanNum: "+str(ScanNum)+"\nSlit-"+Which+" position", fancybox=True) 
+        plt.grid(color='lightgray', linestyle='-', linewidth=0.5)
+    plt.show()
+    
+    
+###############################################################################################
+######################################### IDCalibration New ###################################
+###############################################################################################
+
+
+
+def id_calibration_fit(first_scan,last_scan,det,PolyRank,**kwargs):
+    
+    
+    #id_calibration_fit(FirstLast[0],FirstLast[1],det,poly_order,mytitle=mytitle,countby=countby,plotMin=plt_min,plotMax=plt_max,plotType=plotType,filepath=filepath,prefix=prefix)
+    """
+    Fits calibration curves fpr each GRTs and modes included in the data set. Creates 3 dictionnaries:
+    
+        coefs={[GRT][mode][[breakpoint1,[coefs]],[breakpoint2,[coefs]...}
+        xdata= {[GRT][mode][[breakpoint1,[flux curve x axis]],[breakpoint2,[flux curve x axis]...}
+        fdata= {[GRT][mode][[breakpoint1,[flux curve y axis]],[breakpoint2,[flux curve y axis]...}
+        
+    kwargs:
+        countby = 1 by default
+        mytitle = '' by default
+        plotMin =  min x range for plotting (default 250)
+        plotMax =  max x range for plotting (default 3000)
+        plotType = ['dif,'fit,'flux'], full set by default
+        filepath = None,  uses current mda filepath unless specified
+              e.g. user : filepath='/net/s29data/export/data_29idc/2018_2/UserName/mda/'
+              e.g. staff: filepath='/net/s29data/export/data_29idb/2018_2/mda/'
+        prefix = None, uses current mda prefix unless specified 
+        scanIOC = None, uses BL_ioc() unless specified
+    """
+
+    kwargs.setdefault('countby',1)
+    kwargs.setdefault('mytitle','')
+    #kwargs.setdefault('plotMin',2000)
+    kwargs.setdefault('plotMin',225)
+    kwargs.setdefault('plotMax',3000)
+    kwargs.setdefault('plotType',['fit','dif','flux'])
+    kwargs.setdefault('filepath',BL.mda.filepath())
+    kwargs.setdefault('prefix',BL.mda.prefix())
+
+    countby=kwargs['countby']
+    mytitle=kwargs['mytitle']
+    plotMin=kwargs['plotMin']
+    plotMax=kwargs['plotMax']
+    filepath=kwargs['filepath']
+    prefix=kwargs['prefix']
+    
+
+    def calibration_curve(first,last,det,countby,filepath,prefix):
+        mono_list=[]
+        ID_list=[]
+        max_list=[]
+        flux_list=[]
+        print("filepath = ",filepath)
+        print("prefix = ",prefix)
+        print("First scan = ",first)
+        print("Last scan  = ",last)
+        for i in range(first,last,countby):
+            x,y,x_name,y_name=mda_1D(i,det,1,0,filepath,prefix)   #mda_1D(ScanNum,DetectorNum,coeff=1,bckg=0,filepath=None,prefix=None,scanIOC=None):
+            v,w,v_name,w_name=mda_1D(i, 4 ,1,0,filepath,prefix)
+            if y != []:
+                n=y.index(max(y))        # finds the peak max intensity index
+                e=round(x[n],2)            # finds the corresponding mono energy
+                sp=round(w[2]*1000,0)   # reads the ID set point
+                mono_list.append(e)
+                max_list.append(max(y))
+                ID_list.append(sp)
+                flux_list.append(current2flux(max(y),e,p=None))
+        return mono_list,ID_list,max_list,flux_list
+    
+    Mono_max,ID_SP,int_max,flux=calibration_curve(first_scan,last_scan+1,det,countby,filepath,prefix)
+    nPt_gaus=200
+    x_HR =  np.linspace(Mono_max[0], Mono_max[-1], nPt_gaus)
+    
+    # Data
+    xdata = np.array(Mono_max)
+    ydata = np.array(ID_SP)
+    zdata = np.array(int_max)
+    fdata = np.array(flux)
+    # Fitting
+    coefs = poly.polyfit(xdata, ydata, PolyRank)
+    ffit_HR = poly.polyval(x_HR, coefs)
+    ffit_Coarse = poly.polyval(xdata, coefs)
+    # Residual
+    Dif=np.array(ID_SP)-np.array(ffit_Coarse)
+    ratio=(np.array(ID_SP)-np.array(ffit_Coarse))/(np.array(ID_SP)/100)
+    # Plot differences
+    #print('plotMin = ',str(plotMin))
+    if 'dif' in kwargs['plotType']:
+        fig = plt.figure(figsize=(12,6))
+        plt.plot(Mono_max,ID_SP,marker='x',markersize=5,color='g',linewidth=0,label='data')
+        plt.plot(x_HR,ffit_HR,color='b',label='SP-fit')
+        plt.plot(xdata,Dif*100,marker='x',color='r',label='Dif x100')
+        plt.plot(xdata,ratio*1000,marker='x',color='g',label='Difx1000/ID')
+        plt.ylabel('ID SP')
+        plt.xlabel('Mono')
+        plt.xlim(plotMin,plotMax)
+        plt.legend(ncol=2, shadow=True, title=mytitle, fancybox=True)
+        plt.grid(linestyle='-', linewidth='0.5', color='grey')
+        plt.show()
+    # Plot raw data + fit
+    if 'fit' in kwargs['plotType']:
+        fig = plt.figure(figsize=(12,6))
+        a1 = fig.add_axes([0,0,1,1])
+        a1.plot(xdata+Dif,zdata,marker='*',markersize=10,color='r',linewidth=0,label='Interpolated ID SP')
+        for i in range(first_scan,last_scan+1):
+            x,y,x_name,y_name=mda_1D(i,det,1,0,filepath,prefix)
+            a1.plot(x,y,color='b')
+        a1.set_xlim(plotMin,plotMax)
+        a1.set(xlabel='Mono')
+        a1.set(ylabel='ID SP')
+        a1.ticklabel_format(style='sci', axis='y', scilimits=(0,0))
+        a1.grid(linestyle='-', linewidth='0.5', color='grey')
+        plt.legend(ncol=2, shadow=True, title=mytitle, fancybox=True)
+        plt.show()
+    # Plot flux curves:
+    fdata_x=xdata+Dif
+    if 'flux' in kwargs['plotType']:
+        fig = plt.figure(figsize=(12,6))
+        a1 = fig.add_axes([0,0,1,1])
+        a1.plot(fdata_x,fdata,color='r',linewidth=1,label='Flux curves')
+        a1.set_xlim(plotMin,plotMax)
+        a1.set(xlabel='Mono')
+        a1.set(ylabel='ID SP')
+        a1.set_yscale('log')
+        #a1.ticklabel_format(style='sci', axis='y', scilimits=(0,0))
+        a1.grid(linestyle='-', linewidth='0.5', color='grey')
+        plt.legend(ncol=2, shadow=True, title=mytitle, fancybox=True)
+        plt.show()
+    return coefs, fdata_x,fdata 
+
+
+
+
+
+
+def read_id_files(first,last,filepath=None,prefix=None,q=True):
+    """
+    Reads extra PVs
+    Return a list of [[ScanNum,ID_SP,grt,mode],...] for mda files between first and last.
+    """
+    if filepath == None:
+        filepath=BL.mda.filepath()
+    if prefix == None:
+        prefix=BL.mda.prefix()[:-1]
+    elif prefix[-1] == "_":
+        prefix=prefix[:-1]
+    mydata=mdaFile(first,last,filepath=filepath,prefix=prefix,q=q)
+    value=[]
+    modeDict={'CW,  RCP':'RCP','CCW, LCP':'LCP','H':'H','V':'V'}
+    grtDict={1200:'MEG',2400:'HEG'}
+    for mdaNum in mydata.scanList:
+        if first<=mdaNum<=last:
+            extraPVs=mydata.header[mdaNum].all
+            try:
+                ID=round(extraPVs['ID29:EnergySet.VAL'][2][0]*1000,2)
+                mode=modeDict[extraPVs['ID29:ActualMode'][2]]                # extraPVs return 'CW, RCP'
+                grt=grtDict[extraPVs['29idmono:GRT_DENSITY'][2][0]]        # extraPVs return 1200
+            except KeyError:
+                ID=round(extraPVs[b'ID29:EnergySet.VAL'][2][0]*1000,2)
+                mode=modeDict[str(extraPVs[b'ID29:ActualMode'][2])[2:-1]]
+                grt=grtDict[extraPVs[b'29idmono:GRT_DENSITY'][2][0]]        # extraPVs return 1200
+            if len(value)>0 and value[-1][1:] == [ID,grt,mode]:
+                pass
+            else:
+                value.append([mdaNum,ID,grt,mode])
+    return value
+
+
+
+def id2num(ID,grt,mode,first=0,last=inf,ignore=[],filepath=None,prefix=None,q=True):   # Not efficient - requires to read all 600 files everytime
+    """
+    Return ScanNum corresponding to a given ID_SP from ExtraPVs (using mdaFile)
+    """
+    if filepath == None:
+        filepath=BL.mda.filepath()
+    if prefix == None:
+        prefix=BL.mda.prefix()[:-1]
+    elif prefix[-1] == "_":
+        prefix=prefix[:-1]
+    ScanNum = 0
+    data_list = read_id_files(first,last,filepath,prefix,q)
+    data_short=[x for x in data_list if x[2:]==[grt,mode] and x[0] not in ignore]
+    step=data_short[1][1]-data_short[0][1]
+    precision=int(step/2)
+    ID1=ID-precision
+    ID2=ID+precision
+    ScanNum=[x[0] for x in data_short if ID1<= x[1]<= ID2]
+    if len(ScanNum)==0: result=None
+    else: result=ScanNum[0]
+    return result
+
+
+
+def num2id(ScanNum,grt,mode,first=0,last=inf,ignore=[],filepath=None,prefix=None,q=True):  # Not efficient - requires to read all 600 files everytime
+    """
+    Return ID SP corresponding to a given ScanNum from ExtraPVs (using mdaFile)
+    """
+    if filepath == None:
+        filepath=BL.mda.filepath()
+    if prefix == None:
+        prefix=BL.mda.prefix()[:-1]
+    elif prefix[-1] == "_":
+        prefix=prefix[:-1]
+    ID = 0
+    data_short=[]
+    data_list = read_id_files(first,last,filepath,prefix,q)
+    data_short=[x for x in data_list if x[2:]==[grt,mode] and x[0] not in ignore]
+    ID=[x[1] for x in data_short if x[0] == ScanNum]
+    return ID[0]
+
+
+
+def extract_id(first,last,ignore=[],breakpts={'RCP':[600],'H':[400,600],'V':[600],'LCP':[600],'HEG':[],'MEG':[2200,2475]},filepath=None,prefix=None,q=True):
+    """
+    Breaksdown the info from a calibration files into grt & mode with the corresponding breakpoints (hardcoded):
+        [[first, last, 'HEG', 'RCP', [600]],
+         [first, last, 'HEG', 'H', [400, 600]]...]  
+    """
+    if filepath == None:
+        filepath=BL.mda.filepath()
+    if prefix == None:
+        prefix=BL.mda.prefix()[:-1]
+    elif prefix[-1] == "_":
+        prefix=prefix[:-1]
+    IDlog=read_id_files(first,last,filepath,prefix,q)
+    #breakpts={'RCP':[600],'H':[400,600],'V':[600],'LCP':[600],'HEG':[],'MEG':[2200]}
+    #breakpts={'RCP':[600],'H':[400,600],'V':[600],'LCP':[600],'HEG':[],'MEG':[2200]}
+    #breakpts={'RCP':[600],'H':[600],'V':[600],'LCP':[600],'HEG':[],'MEG':[2200,2475]}  # FR changed H breakpoints, missing low energy scans 06/14/2021
+    data=[]
+    for grt in ['HEG','MEG']:
+        for mode in ['RCP','H','V','LCP']:
+            tmp=[x for x in IDlog if x[2:]==[grt,mode] and x[0] not in ignore]
+            #print(tmp)
+            if len(tmp)>0:
+                tmp=[tmp[0][0],tmp[-1][0],grt,mode,breakpts[mode]+breakpts[grt]]
+            data.append(tmp)
+    return data
+
+
+
+def update_id_dict(first,last,det,update_file,ignore,**kwargs):
+    
+    
+
+    """
+    Calculate new calibration curve for a full set of data.'
+    But what if the set is not complete? To be addressed by Future Me
+    If update_file == True (ONLY):
+    \tupdate the ID dictionary '/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/Dict_IDCal.txt'
+    """ 
+
+    if update_file == True:
+        foo=input('\nAre you sure you want to update the ID calibration dictionary?\n>')
+        if foo == 'Y' or foo == 'y' or foo == 'yes'or foo == 'YES' or foo == 'Yes':
+            foo = 'yes'
+            print('\nWill save new dictionary to: \'/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/Dict_IDCal.txt\'\n')
+        else:
+            print('\nCalibration curves will not be saved.\n')
+    else:
+        print('\nCalibration curves will not be saved.\n')
+
+    kwargs.setdefault('countby',1)
+    kwargs.setdefault('mytitle','')
+    kwargs.setdefault('plotMin',225)
+    kwargs.setdefault('plotMax',3000)
+    kwargs.setdefault('plotType',['fit','dif','flux'])
+    kwargs.setdefault('filepath',BL.mda.filepath())
+    kwargs.setdefault('prefix',BL.mda.prefix())
+    kwargs.setdefault('q',True)
+    kwargs.setdefault('breakpts',{'RCP':[600],'H':[400,600],'V':[600],'LCP':[600],'HEG':[],'MEG':[2200,2475]})
+
+
+    breakpts=kwargs['breakpts']
+    plotType=kwargs['plotType']
+    filepath=kwargs['filepath']
+    prefix=kwargs['prefix']
+    q=kwargs['q']
+
+    ID_data=extract_id(first,last,ignore,breakpts,filepath,prefix,q)
+
+    ##### Extract parameters:
+
+    mode_dict ={'RCP':0,'LCP':1,'V':2,'H':3}
+    id_coef={}
+    new_id_function={}
+    id_flux={}
+    flux_dict={}
+    id_energy={}
+    energy_dict={}
+    for mylist in ID_data:
+        if len(mylist) > 0:         # in case of incomplete data set
+            tmp0,tmp1,tmp2=[],[],[]
+            first_scan=mylist[0]
+            last_scan=mylist[1]
+            scan_list=[[first_scan,last_scan]]
+            countby=1
+            #det=15
+            #det=33
+            poly_order=4
+            grt=mylist[2]
+            mode=mylist[3]
+            breakpts_energy=mylist[4]
+            breakpts_scan=[]
+            mytitle=mode+' - '+grt 
+            
+            ## generating list of scans depending on breakpoints:
+            if breakpts_energy != []:
+                scan_list=[]
+                for x in breakpts_energy:
+                    breakpts_scan.append(id2num(x,grt,mode,first,last,ignore,filepath,prefix,q))
+                breakpts_scan = [i for i in breakpts_scan if i]
+                print(breakpts_scan)
+                for c,x in  enumerate(breakpts_scan):              # can get the number by extracting step size then /2
+                    if c == 0:
+                        if x == first_scan: pass
+                        else: scan_list.append([first_scan,x])
+                    if 0 < c < len(breakpts_scan)-1:
+                        scan_list.append([breakpts_scan[c-1],x])
+                        scan_list.append([x,breakpts_scan[c+1]])
+                    if c == len(breakpts_scan)-1 and (c-1) == 0:
+                        scan_list.append([breakpts_scan[c-1],x])
+                    if c == len(breakpts_scan)-1:
+                        scan_list.append([x,last_scan])
+            final_list = [i for n, i in enumerate(scan_list) if i not in scan_list[:n]]     # remove doubles
+            energy_list=[]
+            for x in final_list:
+                ID1=num2id(x[0],grt,mode,first,last,ignore,filepath,prefix,q)
+                ID2=num2id(x[1],grt,mode,first,last,ignore,filepath,prefix,q)
+                energy_list.append([ID1,ID2])
+            energy_list_2=energy_list           # we need the final value for plot purposes (max value)
+            if grt == 'HEG':
+                energy_list_2[-1][-1]=2500          # but we don't want it to be a cutoff for ID_Calc in dict 
+            for (FirstLast,ID,cutoff) in zip(final_list,energy_list,energy_list_2):   
+                    plt_min=ID[0]-200
+                    plt_max=ID[1]+100
+                    if grt=='MEG' and ID[1]>2900:
+                        poly_order=5
+                        plt_min=ID[0]-200
+                    print('det =',det)
+                    print('poly_order =',poly_order)
+                    
+                    subkwargs=kwargs # kwargs contains plotType, filepath, prefix and q
+                    newkwargs={'mytitle':mytitle,'countby':countby,"plotMin":plt_min,'plotMax':plt_max}
+                    subkwargs.update(newkwargs)
+                    #print(newkwargs)
+                    #print(FirstLast[0],FirstLast[1])
+                    #result,energy_data,flux_data=id_calibration_fit(FirstLast[0],FirstLast[1],det,poly_order,subkwargs)
+                    result,energy_data,flux_data=id_calibration_fit(FirstLast[0],FirstLast[1],det,poly_order,mytitle=mytitle,countby=countby,plotMin=plt_min,plotMax=plt_max,plotType=['fit','dif'],filepath=filepath,prefix=prefix)
+                    tmp0.append([cutoff[1],result.tolist()])
+                    tmp1.append([cutoff[1],energy_data])
+                    tmp2.append([cutoff[1],flux_data])
+            
+            if 2900<tmp0[-1][0]<3000: tmp0[-1][0]=3000
+            id_coef[mode_dict[mode]]=tmp0      # dictionary that
+            new_id_function[grt]=id_coef      # dictionary containing all the calibration curves forthe data set
+            id_energy[mode_dict[mode]]=tmp1      # dictionary that
+            energy_dict[grt]=id_energy    
+            id_flux[mode_dict[mode]]=tmp2      # dictionary that
+            flux_dict[grt]=id_flux
+
+    ##### Read & update old dictionary:
+
+    try:
+        id_function=read_dict('Dict_IDCal.txt')
+        print(id_function)
+        id_function.update(new_id_function)
+
+    except KeyError:
+        print("Unable to read previous dictionary")
+
+
+    if update_file == True and foo == 'yes':
+        filepath = "/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/"
+        filename = 'Dict_IDCal.txt'
+
+        with open(join(filepath, filename), "a+") as f:   
+            f.write('\n======= '+today()+': \n')
+            f.write(str(id_function))  
+            f.write('\n')
+            print('\nWriting dictionary to:',join(filepath, filename))
+
+    if update_file == True and foo == 'yes':
+        filepath = "/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/"
+        filename = 'Flux_Curves.txt'
+
+        with open(join(filepath, filename), "a+") as f:   
+            f.write('\n======= '+today()+': \n')
+            f.write('\n----- flux_x:\n')
+            f.write(str(energy_dict))  
+            f.write('\n----- flux_y:\n')
+            f.write(str(flux_dict))  
+            f.write('\n')
+            print('\nWriting flux curves to:',join(filepath, filename))
+
+    return id_function,energy_dict,flux_dict
+
+
+def update_slit_dict(**kwargs):
+    """
+    Interactive function to update the slit position dictionary (Dict_Slit.txt)
+    
+    **kwargs
+        readOnly == False, if true just pring the current slit dictionary
+    """
+    filepath = "/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/"
+    filename ='Dict_Slit.txt'
+    
+    kwargs.setdefault("readOnly",False)
+
+    print('\n\nWARNING: 2V slit should always be centered at zero ie steer M1 center beam on the grating')
+    print('Increasing the roll moves the beam more positive: +0.05 pitch => ~ +0.04 slit position; Use:\n')
+    print("Get_Mirror(1);Move_M1('RZ',x)")
+    print("energy(500);mono(505);slit(200)")
+    print("Scan_NarrowSlit_Go(which='2V',slit_parameters=[0.25, -2, 2, 0.25]) #for MEG; slit_parameters=[0.5, -2, 2, 0.25] for HEG")
+    print("Scan_NarrowSlit_Go(which='2V',slit_parameters=[0.50, -2, 2, 0.25]) #for HEG")
+    print('Once steering is completed, check 2H position:')
+    print("Scan_NarrowSlit_Go(which='2H',slit_parameters=[0.25, -6, 6, 0.25]) ")
+    
+    try:
+        slit_position=read_dict(filename)
+        print('\nCurrent dictionary:\n')
+        print(slit_position)
+
+    except KeyError:
+        print("Unable to read previous dictionary")
+        return
+    
+    if kwargs['readOnly']== True:
+        return slit_position
+        
+    else:
+        grt=input('\nWhich grating do you want to update (HEG or MEG) >')
+        s2v=input('New Slit 2B-V center >')
+        s2h=input('New Slit 2B-H center >')
+        s1v=input('New Slit 1A-V center >')
+        s1h=input('New Slit 1A-H center >')
+
+        if grt == '' or s1h == '' or s1v == '' or s2h == '' or s2v == '':
+            print('\nMissing input. No changes made in file.')
+            return
+
+        if grt[0] == '"' or grt[0]=="'": grt = grt[1:4]
+
+    #    new_slit_position={grt.upper():{'S1H':float(s1h),'S1V':float(s1v),'S2H':float(s2h),'S2V':float(s2v)}}   # change order to match scan/fit order
+        new_slit_position={grt.upper():{'S2V':float(s2v),'S2H':float(s2h),'S1V':float(s1v),'S1H':float(s1h)}}
+        slit_position.update(new_slit_position)
+
+
+        with open(join(filepath, filename), "a+") as f:
+            f.write('\n======= '+today()+': \n')
+            f.write(str(slit_position))
+            f.write('\n')
+            print('\nWriting dictionary to:',join(filepath, filename))
+
+        slits_set_BL()
+        return slit_position
+
+
+
+
+
+
+def read_flux(FileName='Flux_Curves.txt',FilePath="/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/"):
+    print('test')
+    with open(join(FilePath, FileName)) as f:
+        for c,line in enumerate(f.readlines()):
+            if line[0] == '=':
+                lastdate=line[8:16]
+                print(lastdate)
+            if line[0] == '-' and line[-2] == 'x':
+                axis='x'
+                print(axis)
+            line_x=line
+            if line[0] == '-' and line[-2] == 'y':
+                axis='y'
+                print(axis)
+            line_y=line
+        mydict_x=ast.literal_eval(line_x)
+        mydict_y=ast.literal_eval(line_y)
+    return mydict_x,mydict_y
+
+
+
+
+
+
+###############################################################################################
+######################################### Object Oriented #####################################
+###############################################################################################
+
+class _mdaData(scanDim):
+    
+    def __init__(self):
+        scanDim.__init__(self)
+        self.poslist = None
+        self.detlist = None
+        
+    
+    def _getDetIndex(self,d):
+        """ 
+            d = det Num
+        """
+        D=self.detlist
+        if D==[]:
+            print('Data contains no detectors. Try higher dimensions: mydata.dim2[n]')
+            index=[None]
+        else:
+            index=[x for x, y in enumerate(D) if y[1] == 'D'+str(d).zfill(2)]
+            if index == []:
+                print('Detector '+str(d)+' not found.')
+                index=[None]
+        return index[0]
+        
+
+    
+    def plt(self,d):
+        d=self._getDetIndex(d)
+        if d== None:
+            return
+        x=self.p[0]
+        y=self.d[d]
+        if self.dim == 2:
+            print('This is a 2D scan; use method mydata.img(n,d)')
+            for i in range(len(y.data)):
+                plt.plot(x.data[i], y.data[i],label=y.fieldName,marker='+')            # crop aborted scans (curr_pt<npts)
+        else:   plt.plot(x.data[:self.curr_pt], y.data[:self.curr_pt],label=y.fieldName,marker='+')            # crop aborted scans (curr_pt<npts)
+        plt.xlabel(x.name)
+        plt.ylabel(y.name)
+        plt.legend()
+        plt.grid(color='lightgray', linestyle='-', linewidth=0.5)
+        
+        
+        
+    def kappaDet(self,q=None):
+        if q is not None:
+            print('\nUse detIndex for plot: mydata.dim1[n].d[detIndex].data\nIf D=mydata.dim1[n].kappaDet => detIndex=D[detNum][1]\n')
+            print('key = (detIndex, detNum, description, pv)')
+        det={}
+        D=self.detlist
+        for (i,j) in zip([32,33,34,35,31,36,37,38,39,41,42,43,44,45,46,47,48,54,55,56,57],['TEY','D3','D4','MCP','mesh','TEY / mesh','D3 / mesh','D4 / mesh','MCP / mesh','ROI1','ROI2','ROI3','ROI4','ROI5','<H>','<K>','<L>','tth','th','chi','phi']):
+            d=self._getDetIndex(i)
+            if d != None:
+                det[i]=(d,D[d][1],j,D[d][2])
+            else:
+                det[i]=None
+        return det        
+    
+
+
+        
+    
+class _mdaHeader:
+    def __init__(self):
+        self.all = None
+        self.sample = None
+        self.mono = None
+        self.ID = None
+        self.energy = None
+        self.det = None
+        self.motor = None
+        self.mirror = None
+        self.centroid = None
+        self.slit=None
+        self.comment=None
+        
+        
+
+
+class mdaFile:
+    
+    
+    '''mydata=mdaFile(first=0,last=None,name=datasetName,filepath=None,prefix=None)
+    
+    /net/s29data/export/data_29idb/2020_3/mda/Kappa_0107.mda is a 1-D file; 1 dimensions read in.
+    
+    mydata.header[n] = dictionary of 163 scan-environment PVs
+    
+       usage: mydata.header[n]['sampleEntry'] -> ('description', 'unit string', 'value', 'EPICS_type', 'count')
+    
+    mydata.dim1[n] = 1D data from '29idKappa:scan1' acquired on Oct 20, 2020 19:06:23:
+                    33/33 pts; 1 positioners, 65 detectors
+    
+       usage: mydata.dim1[n].p[2].data -> 1D array of positioner 1 data
+     
+    Each scan dimension (i.e., dim1, dim2, ...) has the following fields: 
+          time      - date & time at which scan was started: Oct 20, 2020 19:06:23
+          name      - name of scan record that acquired this dimension: 29idKappa:scan1
+          curr_pt   - number of data points actually acquired: 33
+          npts      - number of data points requested: 33
+          nd        - number of detectors for this scan dimension: 65
+          d[]       - list of detector-data structures
+          np        - number of positioners for this scan dimension: 1
+          p[]       - list of positioner-data structures
+          nt        - number of detector triggers for this scan dimension: 1
+          t[]       - list of trigger-info structures
+     
+    Each detector-data structure (e.g., dim[1].d[0]) has the following fields: 
+          desc      - description of this detector
+          data      - data list
+          unit      - engineering units associated with this detector
+          fieldName - scan-record field (e.g., 'D01')
+     
+    Each positioner-data structure (e.g., dim[1].p[0]) has the following fields: 
+          desc          - description of this positioner
+          data          - data list
+          step_mode     - scan mode (e.g., Linear, Table, On-The-Fly)
+          unit          - engineering units associated with this positioner
+          fieldName     - scan-record field (e.g., 'P1')
+          name          - name of EPICS PV (e.g., 'xxx:m1.VAL')
+          readback_desc - description of this positioner
+          readback_unit - engineering units associated with this positioner
+          readback_name - name of EPICS PV (e.g., 'xxx:m1.VAL')
+    '''
+
+    def __init__(self,first=1,last=None,name='mydata',filepath=None,prefix=None,q=False):
+        if filepath == None:
+            filepath = BL.mda.filepath()
+        self.path  = filepath
+        self._name  = name
+        self._first = first
+        self._last  = last
+        if prefix != None and prefix[-1]=='_':
+            self._prefix= prefix[:-1]
+        else:
+            self._prefix= prefix
+            
+        self._allFiles = None
+        self._allPrefix  = None
+        self.loadedFiles = None
+        self.scanList  = None
+        self.dim1  = None
+        self.dim2  = None
+        self.dim3  = None
+        self.header  = None
+
+        self._extractFiles()
+        self._extractData(q)
+
+
+    #def __str__(self):
+
+
+
+    def _extractFiles(self):
+        allFiles   = [f for f in listdir(self.path) if isfile(join(self.path, f))]
+        loadedFiles= [x for (i,x) in enumerate(allFiles) if allFiles[i].split('.')[-1]=='mda']
+        allPrefix = [loadedFiles[i][:loadedFiles[i].find('_')] for (i,x) in enumerate(loadedFiles)]
+        scanList = [int(loadedFiles[i][loadedFiles[i].find('_')+1:loadedFiles[i].find('_')+5]) for (i,x) in enumerate(loadedFiles)]
+        if self._prefix != None:
+            allPrefix=[s for s in allPrefix if s == self._prefix]
+            scanList = [int(loadedFiles[i][loadedFiles[i].find('_')+1:loadedFiles[i].find('_')+5]) for (i,x) in enumerate(loadedFiles) if loadedFiles[i][:loadedFiles[i].find('_')] == self._prefix]
+            loadedFiles   = [s for s in loadedFiles if s[:s.find('_')] == self._prefix]
+        else:
+            self._prefix=allPrefix[-1]
+            if allPrefix[0]!=allPrefix[-1]:
+                print('\nWARNING: Found more than one file prefix: {}, {}.\n\nData with the same scan number will be overwriten in the order they are loaded. \nPlease specify the one you want to load with arg prefix="which".\n\n'.format(allPrefix[0],allPrefix[-1]))
+        if self._last == None:
+            self._last = self._first
+        shortlist  = [i for (i,x) in enumerate(scanList) if self._first<=x<=self._last]  
+        self._allFiles = allFiles
+        self.loadedFiles = [loadedFiles[i] for i in shortlist]  
+        self.scanList  = [scanList[i] for i in shortlist]
+        self._allPrefix=[allPrefix[i] for i in shortlist]
+        
+        
+    def _extractData(self,q):
+        
+        allheader = {}
+        alldata1 = {}
+        alldata2 = {}
+        alldata3 = {}
+        
+        for (i,mda) in enumerate(self.loadedFiles):
+            
+            ##### File info:
+            
+            filename=mda
+            filepath=self.path
+            #print(filepath)
+            num=self.scanList[i]
+            #print(num)
+            fullpath=join(filepath,filename)
+            #print(fullpath)
+            data=readMDA(fullpath,useNumpy=True)    # data = scanDim object of mda module
+            
+            ###### Extract header:
+
+            D0 = _mdaHeader()   # initiate D0 = mdaHeader object
+            D1 = _mdaData()
+            D2 = _mdaData()
+            D3 = _mdaData()
+            
+            D=[]
+            
+            for d in range(0,4):
+                if d in range(0,len(data)): D.append(data[d])
+                else: D.append(None)
+            
+            # D[0]=data[0]
+            # D[1]=data[1]
+            # D[2]=None if 1D data, data[2] if 2D data
+            # D[3]=None if 2D data, data[3] if 3D data
+                
+            
+            D0.all=D[0]
+            
+            
+            if filename[:5] == 'Kappa':
+                try:
+                    D0.sample={**{key:value[:3] for key, value in D[0].items() if '29idKappa:m' in key},**{key:value[:3] for key, value in D[0].items() if '29idKappa:Euler' in key},**{key:value[:3] for key, value in D[0].items() if 'LS331' in key}}
+                    D0.mirror = {key:value[:3] for key, value in D[0].items() if '29id_m3r' in key}
+                    D0.centroid={key:value[:3] for key, value in D[0].items() if 'ps6' in key.lower()}
+                    D0.det = {key:value[:3] for key, value in D[0].items() if '29idd:A' in key}
+                    detkeys=['29idMZ0:scaler1.TP','29idKappa:m9.RBV','29idKappa:userCalcOut10.OVAL','29iddMPA:C0O','29idKappa:userStringSeq6.STR1','29idd:Unidig1Bo0']
+                    for k in detkeys: 
+                        if k in D[0]: D0.det[k]=D[0][k][:3]
+                    D0.ID={key:value[:3] for key, value in D[0].items() if 'ID29' in key}
+                    D0.UB={key:value[:3] for key, value in D[0].items() if 'UB' in key}
+                    D0.mono={key:value[:3] for key, value in D[0].items() if 'mono' in key}
+                    D0.energy={key:value[:3] for key, value in D[0].items() if 'energy' in key.lower()}
+                    D0.motor = {key:value[:3] for key, value in D[0].items() if '29idb:m' in key}
+                    D0.slit={key:value[:3] for key, value in D[0].items() if 'slit3d' in key.lower()}
+                except:
+                    pass
+            if filename[:5] == 'ARPES':
+                try:
+                    #D0.sample={**{key:value[:3] for key, value in D[0].items() if '29idKappa:m' in key},**{key:value[:3] for key, value in D[0].items() if '29idKappa:Euler' in key},**{key:value[:3] for key, value in D[0].items() if 'LS331' in key}}
+                    #D0.mirror = {key:value[:3] for key, value in D[0].items() if '29id_m3r' in key}
+                    #D0.centroid={key:value[:3] for key, value in D[0].items() if 'ps6' in key.lower()}
+                    #D0.det = {key:value[:3] for key, value in D[0].items() if '29idd:A' in key}
+                    #detkeys=['29idMZ0:scaler1.TP','29idKappa:m9.RBV','29idKappa:userCalcOut10.OVAL','29iddMPA:C0O','29idKappa:userStringSeq6.STR1','29idd:Unidig1Bo0']
+                    #for k in detkeys: 
+                    #    if k in D[0]: D0.det[k]=D[0][k][:3]
+                    D0.ID={key:value[:3] for key, value in D[0].items() if 'ID29' in key}
+                    #D0.UB={key:value[:3] for key, value in D[0].items() if 'UB' in key}
+                    D0.mono={key:value[:3] for key, value in D[0].items() if 'mono' in key}
+                    D0.energy={key:value[:3] for key, value in D[0].items() if 'energy' in key.lower()}
+                    D0.motor = {key:value[:3] for key, value in D[0].items() if '29idb:m' in key}
+                    D0.slit={key:value[:3] for key, value in D[0].items() if 'slit3c' in key.lower()}
+                except:
+                    pass
+
+                try:
+                    cmt1=D[0]['29id'+self._prefix+':saveData_comment1'][2]
+                    cmt2=D[0]['29id'+self._prefix+':saveData_comment2'][2]
+                    if cmt2 != '': D0.comment = cmt1+' - '+cmt2
+                    else: D0.comment = cmt1
+                except:
+                    D0.comment = ''
+            
+            
+            ###### Extract data:
+            
+            DIMS=[D1,D2,D3]
+            
+            for counter, value in enumerate(DIMS):
+                c=counter+1
+                if D[c] is not None:
+                    value.rank=D[c].rank
+                    value.dim=D[c].dim
+                    value.npts=D[c].npts
+                    value.curr_pt=D[c].curr_pt
+                    value.plower_scans=D[c].plower_scans
+                    value.name=D[c].name #
+                    value.time=D[c].time
+                    value.np=D[c].np
+                    value.p=D[c].p
+                    value.nd=D[c].nd
+                    value.d=D[c].d
+                    value.nt=D[c].nt
+                    value.t=D[c].t
+                    value.detlist=[(i,D[c].d[i].fieldName,D[c].d[i].name,D[c].d[i].desc) for i in range(0,D[c].nd)]
+                    value.poslist=[(i,D[c].p[i].fieldName,D[c].p[i].name,D[c].p[i].desc) for i in range(0,D[c].np)]
+                else:
+                    value=None
+            
+            allheader[num] = D0
+            alldata1[num]  = D1
+            alldata2[num]  = D2
+            alldata3[num]  = D3
+            
+            d=D.index(None)-1
+            if q is False:
+                print('Loading {}  as  {}.dim{}[{}]:\n\t\t...{}D data, {}/{} pts; {} positioners, {} detectors'.format(
+                    filename,self._name,d,self.scanList[i],D[d].dim,D[d].curr_pt, D[d].npts, D[d].np, D[d].nd))
+        
+        self.header=allheader
+        self.dim1=alldata1
+        self.dim2=alldata2
+        self.dim3=alldata3
+        
+
+
+
+
+    def updateFiles(self,first=0,last=inf,name=None,filepath=None,prefix=None):
+        new=mdaFile(first,last,name,filepath,prefix)
+        self.loadedFiles=list(dict.fromkeys(self.loadedFiles+new.loadedFiles))
+        self._allFiles=list(dict.fromkeys(self._allFiles+new._allFiles))              # merging the 2 list and removing duplicates
+        self.scanList=list(dict.fromkeys(self.scanList+new.scanList))
+        self._allPrefix=list(dict.fromkeys(self._allPrefix+new._allPrefix))
+        self.dim1.update(new.dim1)
+        self.dim2.update(new.dim2)
+        self.dim3.update(new.dim3)
+        self.header.update(new.header)
+        return self
+    
+    
+
+    def plt(self,*argv):
+        if self.dim2[argv[0]].dim == 0:              #1D scan
+            for index,arg in enumerate(argv):
+                if index %2 !=0:
+                    pass
+                else:
+                    n=arg
+                    d=argv[index+1]
+                    d=self.dim1[n]._getDetIndex(d)
+                    x=self.dim1[n].p[0]
+                    y=self.dim1[n].d[d]
+                    plt.plot(x.data[:self.dim1[n].curr_pt], y.data[:self.dim1[n].curr_pt],label='mda #'+str(n)+' - '+y.fieldName,marker='+')
+            plt.xlabel(x.name)
+            plt.ylabel(y.name+' - ('+y.fieldName+')')
+            plt.legend()
+            plt.grid(color='lightgray', linestyle='-', linewidth=0.5)
+            plt.show()
+        elif self.dim2[argv[0]].dim == 2:              # 2D scan 
+            for index,arg in enumerate(argv):
+                if index %2 !=0:
+                    pass
+                else:
+                    n=arg
+                    d=argv[index+1]
+                    d=self.dim2[n]._getDetIndex(d)
+                    if d == None:
+                        return
+                    x=self.dim2[n].p[0]
+                    y=self.dim1[n].p[0]
+                    z=self.dim2[n].d[d]
+                    zlim=self.dim2[n].curr_pt
+                    fig, ax0 = plt.subplots()
+                    img = ax0.imshow(z.data[:zlim],cmap='gnuplot', interpolation = 'nearest', extent = [min(x.data[0]), max(x.data[0]), min(y.data),max(y.data)], aspect = 'auto')
+                    fig.colorbar(img)
+                    plt.title(z.name+' - ('+z.fieldName+')')
+                    ax0.set_xlabel(x.name)
+                    ax0.set_ylabel(y.name)
+                    plt.show()
+
+
+
+
+
+
+
diff --git a/build/lib/iexcode/macros/__init__.py b/build/lib/iexcode/macros/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc
--- /dev/null
+++ b/build/lib/iexcode/macros/__init__.py
@@ -0,0 +1 @@
+
diff --git a/build/lib/iexcode/macros/commissioning.py b/build/lib/iexcode/macros/commissioning.py
new file mode 100644
index 0000000000000000000000000000000000000000..675889f949a341e87f8a5b9886768e49fef05040
--- /dev/null
+++ b/build/lib/iexcode/macros/commissioning.py
@@ -0,0 +1,944 @@
+"""
+Functions for commissioning, alignment and start of the week
+
+"""
+from os.path import join, isfile, exists, dirname
+from time import sleep
+
+from epics import caget, caput
+
+
+from ..instruments.files_and_folders import check_run, folder_mda
+from ..instruments.scanRecord import scanRecord_run,scanRecord_filepath
+from ..instruments.xrays import energy
+from ..instruments.m3r import M3R_branch
+
+from ..instruments.IEX_VPU import ID_switch_mode
+from ..instruments.diagnostics import diagnostics_all_out, diagnostics_all_in,diodeC,diodeD
+from ..instruments.current_amplifiers import current2flux
+from ..instruments.slits import set_exit_slit
+from ..instruments.logfile import *
+from ..instruments.cameras import *
+
+from ..instruments.ARPES import *
+from ..instruments.electron_analyzer import *
+from ..instruments.Kappa import *
+
+
+from .ScanFunctions_plot import fit_mda, mda_1D
+
+##############################################################################################################
+################################            setting  the mda folder             ##############################
+##############################################################################################################
+
+def staff_init(endstation_name=None,set_folders=True,reset=True):
+    """
+    endstation_name : sets the scan record and BL
+    set_folders: sets the mda and EA folders; default => False
+    reset: resets the scanRecord (detectors,triggers...)
+
+    **kwargs:
+        xrays: sets global variable; default => True
+        BL_mode: 'user' / 'staff' => used for saving, detectors
+
+    Previously: folders_staff
+    """
+    if endstation_name is None:
+        endstation_name = BL.endstation
+    
+    if endstation_name == 'ARPES':
+        ARPES_init(set_folders,reset,BL_mode='staff')
+    if endstation_name == 'Kappa':
+        Kappa_init(set_folders,reset,BL_mode='staff')
+
+
+
+def check_staff_directory(BL, **kwargs):
+    """
+    Switchs to the staff directory
+
+    **kwargs for folder_ARPES
+
+    Previously: Check_Staff_Directory
+    """
+    
+    ioc = BL.ioc()
+    run = check_run()
+    
+    directory = scanRecord_filepath(ioc)
+    current_run = scanRecord_run(ioc)
+    
+    if directory.find('data_29idb') < 1 or current_run != run:
+        print('You are not currently saving in the Staff directory and/or the desired run.')
+        # foo=input('\nAre you ready to switch to the '+run+' Staff directory (y or n)? >')  
+        # if foo.lower() == 'y' or foo.lower() == 'yes':
+        if not (exists(directory)):
+            print('Staff directory does not exist for this run.')
+            print('Open ipython as 29id to create a new run directory using:\n\tFolder_'+ioc+'(run,"Staff")')
+            foo=input('\nPress enter when done >')
+            if foo == '': pass   
+        print('Switching directory...') 
+        if ioc=='ARPES':
+            folders_ARPES('Staff',mdaOnly=True,**kwargs)
+        elif ioc=='Kappa':
+            folders_Kappa('Staff',create_only=False)
+        else:
+            print('\nFolder not set.')
+    else:
+        print('Staff directory OK.')
+    directory = scanRecord_filepath(ioc)
+    print('\nCurrent directory: '+directory)    
+    
+
+
+##############################################################################################################
+################################            checking alignment             ##############################
+##############################################################################################################
+
+def check_flux(hv=500,ID_mode='RCP',stay=False):
+    """
+    puts the diode in
+    measures flux at energy ID_mode specified
+    stay: diode position after the scan
+
+    Previously: CheckFlux
+    """
+    ID_switch_mode(ID_mode)
+    energy(hv)
+    diagnostics_all_out(diode_to_stay_in=m3r_branch())
+    SR=round(caget("S:SRcurrentAI.VAL"),2)
+    if m3r_branch() == "c":
+        current_slit=caget('29idb:Slit3CFit.A')
+        diodeC('In')
+        set_exit_slit(50)
+        sleep(10)
+        diode=diodeC_read()
+    elif m3r_branch() == "d":
+        current_slit=caget('29idb:Slit4Vsize.VAL')
+        sleep(10)
+        diodeD("In")
+        set_exit_slit(50)
+        diode=caget('29idb:ca14:read')
+    flux=current2flux(diode)
+    print("\n----- Current on diode   : %.3e" % diode, "A")
+    print("----- Corresponding flux: %.3e" % flux, "ph/s \n")
+    print("----- Storage ring current: %.2f" % SR, "mA")
+    print("\nFlux at hv=500 as off Feb 2019 for RCP and HEG:  ~3.3e-06 A = ~1.5e+11 ph/s")
+    
+    if not stay:
+        diagnostics_all_out()
+    set_exit_slit(current_slit)
+
+def check_m0m1(hv=500,stay=True,wire=True,**kwargs):
+    """
+    Prints Flux in C-branch
+    stay = 'yes' => Leaves diagnostics in the beam
+    wire ='yes'=> Does wire scans to determine M0M1 alignment
+    Logging is automatic: use **kwargs or the optional logging arguments see scanlog() for details
+    
+    Previously: CheckM0M1
+    """
+    
+    switch_branch('c')
+    switch_gratings('HEG')
+    print("\nFlux at hv=500 as off Feb 2019:  ~3.3e-06 A = ~1.5e+11 ph/s")
+    branch_shutter_open()
+    check_flux(hv=hv,stay=stay)
+    if wire is not None:
+        scan_wire('H',**kwargs)
+        scan_wire('V',**kwargs)
+
+def scan_wire(direction,all_diag=True,**kwargs):
+    """
+    Scans the wires located just downstream of M0/M1, 
+         which = 'H' for the horizontal, typically CA2
+         which = 'V' for the vertical, typically CA3
+    all_diag =True -> AllDiagIn(), otherwise you have to put any diagnostics in by hand
+    Logging is automatic: use **kwargs or the optional logging arguments see scanlog() for details    
+    **kwargs:
+        execute
+    
+    Previously: WireScan
+    """
+    kwargs.setdefault('execute',True)
+    if all_diag:
+        diagnostics_all_in()
+    
+    
+    if direction == 'H':
+        name = "H-wire"
+
+    elif direction == 'V':
+        name = "V-wire"
+
+    diag = diagnostics_dict()
+    pv = "29idb:m"+str(diag["motor"][name])
+    print("\n================== "+name+" scan (29idb:ca2):")
+    BL.mda.fillin(pv+".VAL",pv+".RBV",1,-17,-30,-0.25,**kwargs)
+
+    if kwargs['execute']:
+        BL.mda.go(**kwargs)
+
+    if all_diag:
+        diagnostics_all_out()
+
+
+##############################################################################################################
+###########################                    Beam Profile               ######################
+##############################################################################################################
+def scan_narrow_slit(slit='2V',slit_parameters=[0.25,-2,2,0.5],**kwargs):
+    """
+        slit = '1V','1H','2V','2H'
+        slit_parameters = [SlitSize,start,stop,step]
+  
+    Typical slit sizes/start/stop/step are (for full range): 
+        1H/1V : [0.50, -4.5, 4.5, 0.2]
+        2H    : [0.25, -3.0, 3.0, 0.2]
+        2V-MEG: [0.25, -4.0, 4.0, 0.2]    
+        2V-HEG: [0.50, -8.0, 8.0, 0.2] 
+
+    **kwargs:
+        scan_dim = 1
+        execute = True
+
+    Previously: Scan_NarrowSlit
+    """
+    kwargs.setdefault('scan_dim',1)
+    kwargs.setdefault('execute',True)
+
+    size,start,stop,step = slit_parameters
+      
+    direction = slit[1]
+    if direction == "V":
+        size = (inf, size) 
+        center = (0, 0)
+    elif direction == "H":
+        size = (size, inf) 
+        center = (0, 0)
+
+    if slit[0] == '1':
+        slit_name = "slit1A"
+        slit1A_set(size,center)
+        slit2B_set((inf,inf),(0,0))
+
+    elif slit[0] == '2':
+        slit_name = "slit2B"
+        slit1A_set((3,3),(0,0))
+        slit2B_set(size,center)
+  
+    slits_scan_center(slit_name,direction,start,stop,step,**kwargs)
+    if kwargs['execute']:
+        BL.mda.go(kwargs['scan_dim'])
+
+
+def scan_mono_vs_slit(slit='2V',slit_parameters=[0.25,-2,2,0.5],energy_parameters=[470,530,2],**kwargs):
+    """
+    This can be used to find the center of the resonant beam i.e. the slit value for the most blue shifted curve: 
+        slit='1V','1H','2V','2H'
+        slit_parameters = [SlitSize,start,stop,step]
+        energy_parameters = [eVstart,eVstop,eVstep]= [470,530,2]
+        
+    Typical slit sizes/start/stop/step are (for full range): 
+        1H/1V : [0.50, -4.5, 4.5, 0.2]
+        2H    : [0.25, -3.0, 3.0, 0.2]
+        2V-MEG: [0.25, -4.0, 4.0, 0.2]    
+        2V-HEG: [0.50, -8.0, 8.0, 0.2] 
+
+    Previously: Scan_MonoVsSlit
+    """
+    hv_start,hv_stop,hv_step = energy_parameters  
+    # Filling Scans:
+    mono_scan_fillin(hv_start,hv_stop,hv_step)
+    scan_narrow_slit(slit='2V',slit_parameters=[0.25,-2,2,0.5],**kwargs)
+
+    # Resetting everybody to normal:
+    mono_energy_set((hv_start+hv_stop)/2.0)
+    slits_set_BL()
+
+
+##############################################################################################################
+################################            mono alignment             ##############################
+##############################################################################################################
+def mono_MIR_GRT_find_offset(grating,slit_list,**kwargs):    
+    """ 
+    Find MIR-GRT offset by scanning 0 order through exit slit
+        **kwargs:
+            detNum = 15
+
+    Previously: MIR_GRT_Offset
+    """
+    kwargs.setdefault("detNum",15)
+
+    switch_gratings(grating)
+    exit_slit(50)
+    diodeC('In')
+    slit2B_set(2,0.5,0,0)
+    
+    #set zero order, scan grating pitch
+    for ang in RangeUp(1.5,5,0.5):
+        print("\r")
+        mono_zero_order(ang)
+        print("Mirror pitch: "+str(ang)+"\r")
+        for s in slit_list:
+            exit_slit(s)
+            print("\r")
+
+            mono_motor_scan_fillin("GRT:P",ang-0.0005*s, ang+0.0005*s ,0.00002*s)
+            BL.mda.go(**kwargs)
+
+            sleep(1)
+            print("\r")
+            grating_ang = fit_mda(mda.fileNum(),kwargs['detNum'],.1,'gauss')
+            print("Peak: ",grating_ang)
+            print("\r")
+            print("-------------------------")
+
+##################### mono slit scans => Energy calibration #####################
+def exit_slit_vs_hv(hv,c=3):
+    '''
+    Adjust slit size to keep reasonable count vs hv
+          c=3 for nominal slit2B size
+          c=10 for apertured slit2B (e.g 0.25 or 0.5)
+
+    Previously: Mono_Set_Slitvshv
+    '''
+    slit(hv/100.0*c)
+
+
+def scan_energy_along_grating(hv,peakBE=84,pts=11,r=0.75,i=1,**kwargs):
+    """
+    Takes a Slit-2V map for a range of photon energies 
+        peakBE=84; fixed mode
+        pts = number of pts in slit positions, default: 11
+        r = % of range in slit size,  default: 0.75
+        i = scanEA time in minute (default:1 for MEG, 2 for HEG?)
+        Takes 2.5h with default parameters (i=1)
+
+    Previously: Mono_Scan_Slit2BV  
+    """
+    grt_density = mono_grating_density_get()
+    c=grt_density/1200                # c = 1 for MEG, 2 for HEG
+
+    # Getting EA parameters vs hv:
+    PE=200
+    
+    #Getting Slit-2B parameters
+    Vsize=0.25*c
+    n=(4.5-hv/500)
+    Vstart=-((floor((2*n)/Vsize/2)+1)*Vsize*c)*r
+    Vstep=-round(Vstart*2/pts,2)
+
+    #Setting energy:
+    energy(hv)
+    exit_slit_vs_hv(hv,c=10)
+
+    #Aperturing slit 2V (note that we have the nominal size horizontally)
+    (size_rbv,size_val),(center_rbv,center_val) = slits_pvs('slit2B')
+    caput(size_val,Vsize)
+    
+    print("\n--------------- Starting core level vs Slit-2B(V) map ---------------")
+
+    #Take XPS for each Slit-2V position
+    for V_center in RangeUp(Vstart,-Vstart,Vstep):
+        caput(center_val,V_center,wait=True,timeout=18000)
+        kwargs.update({'comment': "2-V center ="+str(V_center)[0:6]})
+        EAlist=["BE",peakBE,PE,17*60*i,1]
+        scanEA(EAlist,**kwargs)
+    
+    #reset the slits
+    slits_set_BL()
+
+
+
+def scan_mono_energy_drift(start,stop,step,peakBE=84,EF=None,**kwargs):
+    '''
+    Measure core level (by default Au 4f) in fixed mode vs energy while maintaining resonable count rate
+    If EF='y' (by default None) takes the Fermi edge as well.
+    kwargs:
+        c=3 is the default slit2B size
+    
+    Used for grating calibration (changing grating_offset and b2 effects this - use grating_offset since b2 was measured)
+    
+    Previously: Mono_Scan_hv_drift
+    '''
+    kwargs.setdefault('c','3')
+
+    for hv in RangeUp(start,stop,step):
+        energy(hv)
+        c=int(kwargs['c'])
+        exit_slit_vs_hv(hv,c)
+        kwargs.update({'comment': "Core level @ hv = "+str(hv)})      
+        scanEA(["BE",peakBE,200,17*60*1,1],**kwargs) 
+        if EF is not None:
+            kwargs.update({'comment': "EF @ hv = "+str(hv)})                
+            scanEA(["BE",0,200,17*60*10,1],**kwargs) 
+
+
+    
+##############################################################################################################
+###########################                    Pinhole Scripts               ######################
+##############################################################################################################
+def scan_pinhole_full():
+    """
+    Does a pinhole with .1 mm step with AllDiagIn and then with only branch diode in
+    
+    Previously: FullPinhole
+    """
+    diagnostics_all_in()
+    scan_pinhole([-3, 3, .5, .1], [-3, 3, .1, .5])
+    diagnostics_all_out(diode_stay_in=True)
+    scan_pinhole([-3, 3, .5, .1], [-3, 3, .1, .5])
+
+
+def scan_pinhole(H_list,V_list,**kwargs):
+    """
+    Sets up the pinhole scan for slit1A
+    Make sure that you have the appropriate Diagnostics in can use AllDiagIn()
+
+    H_list = [Hstart, Hstop, Hstep, Hsize] => [-3, 3, .1, .5]
+    V_list = [Vstart, Vstop, Vstep, Vsize] => [-3, 3, .1, .5]
+    
+    *kwargs:
+        H_scan_dim => 1
+        V_scan_dim => 2
+        execute => True
+
+    Previously: Scan_Pinhole_Go, Scan_Pinhole
+    """
+    kwargs.setdefault('H_scan_dim',1)
+    kwargs.setdefault('V_scan_dim',2)
+    kwargs.setdefault('execute',True)
+
+    #Synching slits
+    slits_synch("slit1A")
+
+    #Getting initial slit size
+    (Hsize0,Vsize0),(Hcenter0,Vcenter0) = slit1A_get(verbose=False)
+
+    #Filling in the ScanRecord
+    slits_scan_center("slit1A","H",H_list[0],H_list[1],H_list[2],scan_dim=kwargs['H_scan_dim'],execute=False)
+    slits_scan_center("slit1A","V",V_list[0],V_list[1],V_list[2],scan_dim=kwargs['V_scan_dim'],execute=False)
+
+    #Set the slit size
+    slit1A_set((H_list[2],V_list[2]),(0,0),verbose=True)
+
+    if kwargs['execute']:
+        print("\rPinhole scan: ("+str(kwargs['H_scan_dim'])+","+str(kwargs['V_scan_dim'])+") "
+        +str(H_list[0])+"/"+str(H_list[1])+"/"+str(H_list[2])+"/"+str(H_list[3])+"/"
+        +str(V_list[0])+"/"+str(V_list[1])+"/"+str(V_list[2])+"/"+str(V_list[3]))
+
+        BL.mda.go(max(kwargs['H_scan_dim'],kwargs['V_scan_dim']))
+        print("\rNow setting the slits back to:")
+        slits_set_BL()
+
+        print("\r")
+        print_warning_message("Don't forget to pull all of the diagnostics out.")
+   
+
+
+##############################################################################################################
+##################             Slit Calibration & Beam Steering scripts                 ##################
+##############################################################################################################
+
+
+def Notes_from_20191212():
+    print(""" looking at diode 3 in scattering chamber, open 3D all the way (2000)
+        WARNING: 10% energy detune is enough to see the 2 lobes with 2B but not for 1A => 20% 
+        Red shifted  (485eV) = edges give center of the grating
+        Blue shifted (510eV) = gaussian center gives center of the beam
+        => we want the slit centered on the grating center and the beam centered on the slits/grating
+        => 5 urad down = 1 mm negative motion on 2B-V with HEG""")
+
+
+def procedure_alignment_M1():
+    print("""\n-Start with a very red shifted line cut to localize the edges of the grating:
+                Set_IDraw(510)
+                mono(485)
+                Scan_NarrowSlit('2V',[0.25,-8,8,0.5])
+                Scan_NarrowSlit('2H',[0.25,-4,4,0.5])
+    => Verticaly: The edges/center of the grating define the center of 2V 
+    => Horizontaly: The edges are defined by the aperture upstream. 
+        As long as the beam makes it through the pipe to the next mirror, we are good. 
+        Each M1 pitch will have its own slit-2H zero
+        It can be a good idea to check that GRT or M2 translation does not change anything.
+\n-Once the slits are centered on the grating, center resonant beam on the grating (zero slit):
+                Get_Mirror(1)   # to get current values
+                for roll in RangeUp(3,4,0.2):
+                    print('\\n')
+                    Move_M1('RZ',roll)
+                    sleep(5)
+                    scan_mono_vs_slit('2V',[0.25,-0.5,0.5,0.25],[490,530,2])
+                for pitch in RangeUp(8.5,8.7,0.05):
+                    print('\\nMove_M1('RY',pitch)')
+                    Move_M1('RY',pitch)
+                    sleep(5)
+                    scan_mono_vs_slit('2H',[0.25,-0.5,0.5,0.25],[490,530,2])
+    => The resonant beam is the slit value for the most blue shifted curve.
+    
+    WARNING: It is more accurate (and easier) to compare the leading edge of the ID peak 
+    than trying to look at the perpendicular direction (slit line cut) because of the 
+    asymetry in the beam intensity (uneven carbon strip along the grating?)
+""")
+
+
+    # 2017_3 - HEG after opitmization:  mba_b_0241-0244
+    # 2018_1 - HEG before opitmization: mba_b_0005-0008
+    
+    
+def beamsteering_2B(v_position):
+    vroll=round(v_position*0.05/0.04,3)
+    if v_position<0: v_direction=' +'
+    else: v_direction=' -'
+    v_steering=v_direction+str(vroll)+' urad'
+    return v_steering
+
+def beamsteering_1A(h_position,v_position):
+    hrad=round(h_position*10/0.25,0)
+    vrad=round(v_position*10/0.25,0)
+    if h_position<0: h_direction=' urad outboard'
+    else: h_direction=' urad inboard'
+    if v_position<0: v_direction=' urad up'
+    else: v_direction=' urad down'
+    h_steering=str(hrad)+h_direction
+    v_steering=str(vrad)+v_direction
+    return h_steering,v_steering
+
+    
+
+    
+
+#####################################################################################
+### Slit-1A Procedures
+#####################################################################################
+
+def check_slit1A(step=0.1):
+    """
+    Checks that Slit1A is centered on the fixed aperature/theoretical optic axis
+        top='m9' -> CA5
+        inboard='m10' -> CA4
+        
+    Scans the top blade - CA4 sees an step function
+           top_center = midpoint of motor position for zero current and when current saturates
+    Scans the inner blade - CA4 sees box fuction convoluted with gaussian beam position 
+           inner_center - midpoint bewteen box edges
+           
+    SetSlit1A(0,0,inner_center,top_center)
+    for m in range(9,13):
+        Reset_Motor_User(m,'b',0)
+    SyncAllSlits()  
+    
+    If data makes no sense then Reset_Slit1A_Procedure()
+ 
+    """
+   #scanning top-blade
+    slit1A_set(8,8,0,0)         # aperture wide open
+    caput('29idb:m10.VAL',0)   # Inboard blade centered-ish in the beam
+    m=9
+    VAL='29idb:m'+str(m)+'.VAL'
+    RBV='29idb:m'+str(m)+'.RBV'
+    BL.mda.fillin(VAL,RBV,-4,4.0,step)
+    BL.mda.go()
+    FileNum1  = BL.mda.lastFileNum()
+
+    #scanning inboard-blade
+    slit1A_set(8,8,0,0)         # aperture wide open
+    caput('29idb:m9.VAL',0)    # top blade centered-ish  in the beam
+    m=10
+    VAL='29idb:m'+str(m)+'.VAL'
+    RBV='29idb:m'+str(m)+'.RBV' 
+    BL.mda.fillin(VAL,RBV,-4,4.0,step)
+    BL.mda.go()
+    FileNum2  = BL.mda.lastFileNum()
+
+    return FileNum1, FileNum2
+
+
+def procedure_reset_slit1A():
+    """
+    Prints the procedure for Resetting Slit1A
+    """
+    print("\n#------- Checking and Resetting the Dial -------")
+    print("    GoToSlit1AScribe()")
+    print("# if not on the scribe marks tweek the position until the scribe marks are aligned")
+    print("    for m in [9,10,11,12]: Reset_Motor_Dial(m,\'b\',0);SyncAllSlits()")
+    print("\n#------- Resetting the User -------")
+    print("# SetSlit1A by hand such that you have some beam coming through")
+    print("    Scan_SlitSize(\"1H\",start,stop,step) #looking at CA4")
+    print("    Scan_SlitSize(\"1V\",start,stop,step) #looking at CA4")
+    print("# Then SetSlit1A(1Hsize,1Vsize,0,0); where 1Hsize and 1Vsize are the size where CA4 = 0")
+    print("    for m in [9,10,11,12]: Reset_Motor_User(m,'b',0);SyncAllSlits()")
+    
+  
+def check_ID_steering(hv=2000):
+    """
+    Scans Slit1A center (set to a (0.25,0.25) pinhole) while looking at the back blade:
+        - slit center vs fixed aperture: given by the position of the edges
+        - beam center vs fixed aperture: given by the position of the bump in the middle
+    """
+    slit1A_set(0.25,0.25,0,0)
+    ID_SP_set(hv)
+    scan_slit_center('1H',-3,3,0.1)
+    scan_slit_center('1V',-3,3,0.1)
+        
+def scan_slit_center(slit,start,stop,step,size=0.25):
+    """
+    slit = '1H','1V','2H' or '2V'
+
+    Previously: Scan_SlitCenter
+    """
+    if slit[0] == '1':
+        slit_name = "slit1A"
+    elif slit[0] == '2':
+        slit_name = "slit2B"
+    direction = slit[1]
+    slits_scan_center(slit_name,direction,start,stop,step,size=size)
+
+
+def scan_slit_size(slit,start,stop,step,center=(0,0)):
+    """
+    slit = '1H','1V','2H' or '2V'
+
+    Previously: Scan_SlitSize
+    """
+    if slit[0] == '1':
+        slit_name = "slit1A"
+    elif slit[0] == '2':
+        slit_name = "slit2B"
+    direction = slit[1]
+    slits_scan_center(slit_name,direction,start,stop,step,center=center)
+
+
+
+#####################################################################################
+# Checking the beam steering uses the gas-cell to see if the beam is centered on the grating
+# and that the slits are centered
+#####################################################################################
+
+def ID_beam_profile(grt,slit_list,c_slit=1,c_energy=1,**kwargs):
+    """
+        Makes a nice 2D image of the energy distribution of the beam across the grating at ID=500
+        Does NOT put the diagnostics into the beam you need to run the following if you haven't already (AllDiagOut(); DiodeCIn())
+        SlitList=["2H","2V","1H","1V"]
+        c_slit  = scaling of step size (c=1   Slit-1: step = 0.25. Slit-2: step = 0.5)
+        c_energy = scaling of mono step size ( c=1   eV step = 2)
+        with c_slit=1 and c_energy = 1   Each slit ~ 1:10 min
+
+        Previously
+    """
+    switch_gratings(grt)
+    grt_density = mono_grating_density_get()
+    c=grt_density/1200
+    ID=500
+    eVstart,eVstop,eVstep=460,540,4
+    for slit in slit_list:
+        if slit=="1H":
+            #Hsize,Vsize,Hstart,Hstop,Hstep = 0.50,2,-2,2,0.25*c_slit      # => 35 min
+            #MonoVsSlit1AH_Go(ID,eVstart,eVstop,eVstep*c_energy,Hstart,Hstop,Hstep,Hsize,Vsize,scanIOC,**kwargs)
+            scan_mono_vs_slit('1H',[0.5,-2,2,0.25*c_slit],[eVstart,eVstop,eVstep],comment='Mono/Slit - 1H')
+        elif slit == "1V":
+            #Hsize,Vsize,Vstart,Vstop,Vstep = 2,0.50,-2,2,0.25*c_slit
+            #MonoVsSlit1AV_Go(ID,eVstart,eVstop,eVstep*c_energy,Vstart,Vstop,Vstep,Hsize,Vsize,scanIOC,**kwargs)
+            scan_mono_vs_slit('1V',[0.5,-2,2,0.25*c_slit],[eVstart,eVstop,eVstep],comment='Mono/Slit - 1V')
+        elif slit =="2H":
+            #Hsize,Vsize,Hstart,Hstop,Hstep = 0.50,8,-3,3,0.5*c_slit
+            #MonoVsSlit2BH_Go(ID,eVstart,eVstop,eVstep*c_energy,Hstart,Hstop,Hstep,Hsize,Vsize,scanIOC,**kwargs)
+            scan_mono_vs_slit('2H',[0.5,-3,3,0.5*c_slit],[eVstart,eVstop,eVstep],comment='Mono/Slit - 2H')
+        elif slit =="2V":
+            #Hsize,Vsize,Vstart,Vstop,Vstep = 6,0.25*c,-4*c,4*c,0.5*c_slit
+            #MonoVsSlit2BV_Go(ID,eVstart,eVstop,eVstep*c_energy,Vstart,Vstop,Vstep,Hsize,Vsize,scanIOC,**kwargs)
+            scan_mono_vs_slit('2V',[0.5,-4,4,0.5*c_slit],[eVstart,eVstop,eVstep],comment='Mono/Slit - 2V')
+
+
+def CheckAllSlits_long(hv_list=[500],slit_list=["1H","1V","2H","2V"],**kwargs):
+    """
+    For each photon energy in hvList, takes 3 slit curves @ mono below / resonance / above
+    For given SlitList
+    For both gratings
+    """
+    for grt in ["HEG","MEG"]:    # One full loop for a given grating and 3 energies takes 5h for average 20
+        switch_gratings(grt)
+        for hv in hv_list:
+            slits_set_BL(hv)
+            step=hv/100.0
+            start=hv-step
+            stop=hv+step
+            for slit in slit_list:
+                for hv in range(start,stop,step):
+                    print("\r")
+                    mono_energy_set(hv)
+                    check_ID_beam_steering(slit)
+
+
+def CheckSlitCalibration(slit_list,BL=500,hvList=[485,510],scanIOC=None,**kwargs):
+    """
+    Slit scan for red shifted and blue shifted mono values
+    used to determine in the beam is centered on the grating (gaussian)
+    and if the slits are centered on the grating (humped)
+                 hv=500; hvList=[485,510]
+                 hv=1500;hvList=[hv*0.97,hv*1.01]
+    Note: sets the exit slit to 50
+    """
+    if scanIOC is None:
+        scanIOC=BL_ioc()
+    exit_slit(50)
+    slits_set_BL(BL)
+    for hv in hvList:
+        mono_energy_set(hv)
+        for slit in slit_list:
+            check_ID_beam_steering(slit)
+        print("\n")
+
+def check_ID_beam_steering(slit):   #here
+    """
+    checks the ID beam steering by scanning the slit with the ID detuned
+    if there is carbon on the mirror you might need to do the full ID_beam_profile to
+    find the red shifted beam
+
+    slit = '1V','1H','2V','2H'
+
+    Previously: CheckBeamPosition
+    """
+             
+    grt_density = mono_grating_density_get()    # can be plotted directly on dview using the buffer. That should
+    c=grt_density/1200                # be fairly quick and not require any data loading/analysis
+    
+    slit1A_set((3.5,3.5),(0,0),verbose=False)
+    slit2B_set((6.0,8.0),(0,0),verbose=False)        # Open up all the slits to make sure we scan the full beam
+    
+    if slit == "1H":
+        size,start,stop,step = 0.50,-4.5,4.5,0.2
+    elif slit == "1V":
+        size,start,stop,step = 0.50,-4.5,4.5,0.2
+    elif slit == "2H":
+        size,start,stop,step = 0.25,-8.0,8.0,0.2
+    elif slit == "2V":
+        size,start,stop,step = 0.25*c,-4*c,4*c,0.2*c
+
+    scan_slit_center(slit,start,stop,step,size=size)    
+    slits_set_BL()
+
+
+##############################################################################################################
+##################                 Commissioning paper curves                     ##################
+##############################################################################################################
+def FermiEdges(Energy,Slit):
+    EF_Table={}
+    EF_Table[500]  = {10:20,  20:20,  50:20,  100:20,  200:20}
+    EF_Table[1000] = {10:50,  20:50,  50:50,  100:50,  200:50}
+    EF_Table[1500] = {10:100, 20:100, 50:100, 100:100, 200:100}
+    PE = EF_Table[Energy][Slit]
+    return PE
+
+
+
+
+def QP_curves(ID_energy,ID_mode_list,hv_start,hv_stop,hv_step):
+    """
+    """
+    exit_slit(200)
+    #Switch_Grating("MEG")
+    #print "\r"
+    #print "****************  QP OFF  ****************"
+    #for mode in list_mode:
+    #    Switch_IDMode(mode)
+    #    SetID_Raw(hv)
+    #    SetSlit_BL()
+    #    SetMono(250)
+    #    Scan_Mono(1,start,stop,step)
+    #    Scan_Go("b",1)
+    #print "\r"
+    #print "****************  QP ON  ****************"
+    #Switch_IDQP("on")
+    for ID_mode in ID_mode_list:
+        polarization(ID_mode)
+        ID_SP_set(ID_energy)
+        slits_set_BL()()
+        mono_energy_set(250)
+        mono_scan_fillin(hv_start,hv_stop,hv_step)
+        BL.mda.go()
+    #Switch_IDQP("off")
+    #Switch_Grating("HEG")
+    #Switch_IDMode("RCP")
+
+
+##############################################################################################################
+################################          ID calibration scripts        ##############################
+##############################################################################################################
+
+######  Energy range follows ID ########
+
+def ID_calibration_scan(ID_start,ID_stop,ID_step,bandwidth=10,QP=None,Harm=1,scanIOC=None):
+    """
+    Sets the ID_SP and scans the mono:
+        start,stop,step are for ID
+    if QP is not None adjusts the mono range to offset accordingly
+    !!! DOES NOT CHANGE QP VALUE !!!!
+    !!! Doesn't put diodes in !!!
+    """
+    
+    print("""
+             !!! DOES NOT CHANGE QP VALUE !!!!
+             !!! Doesn't put diodes in !!!""")
+    
+    logfile_name_set(BL.endstation,filename_suffix='IDCalibration')
+
+    #Getting mono max range based on grating
+    grt_density = mono_grating_density_get()
+    c=grt_density/1200            # c = 1 for MEG, 2 for HEG
+    if c == 1: 
+        maxhv = 3000
+    elif c == 2: 
+        maxhv = 2000
+   
+    log_print(comment="====== Starting Mono Scan vs ID ======")
+
+    for ID_energy in RangeUp(ID_start,ID_stop,ID_step):
+        print("\n------------------  ID-SP @ "+str(ID_energy)+"   ------------------")
+        mono_energy_set(ID_energy)
+        ID_SP_set(ID_energy)
+        slits_set_BL()
+        branch = m3r_branch()
+        if branch == 'd':
+            m3r_align()
+        if QP is None:
+            start_hv=min(ID_energy-ID_energy/(bandwidth*1.0)*Harm,maxhv)  # FR update range 11/20/2019
+            stop_hv=min(ID_energy+ID_energy/(bandwidth*2.0)*Harm,maxhv)
+            step_hv=round(ID_energy/300.0,1)
+#            start_hv=min(ID_energy-ID_energy/(bandwidth*2.0)*Harm,maxhv)  # shift the window by doing -BW*2/+BW*1 instead of -BW*1'/'+BW*2
+#            stop_hv=min(ID_energy+ID_energy/(bandwidth*1.0)*Harm,maxhv)
+#            step_hv=round(ID_energy/500.0,1)
+        else:
+            start_hv=min(ID_energy-ID_energy/(bandwidth*2.5)*Harm,maxhv)
+            stop_hv=min(ID_energy+ID_energy/(bandwidth*0.7)*Harm,maxhv)
+            step_hv=round(ID_energy/300.0,1)
+
+        mono_scan_fillin(start_hv,stop_hv,step_hv)
+        BL.mda.go()
+        sleep(1)
+
+        FileNum  = BL.mda.lastFileNum
+        if ID_energy == ID_start:
+            FirstFileNum = FileNum     # Record First Scan Number
+    
+    LastFileNum = FileNum              # Record Last Scan Number
+
+    print("Use:  update_id_dict("+str(FirstFileNum)+","+str(LastFileNum)+"ignore=[] ,update_file,path=None,prefix='ARPES',q=True)")
+
+
+
+
+def ID_calibration_mode(ID_mode,start=None,stop=None,step=25,Harm=1):
+    '''
+    Runs full calibration with a 25 eV step (by default) for a given mode:
+            which = 'RCP','LCP', 'V','H'
+    Better to run each mode in a separated cell (print statement at the end helps with calibration) 
+    '''
+    branch = m3r_branch()
+    diagnostics_all_out(diode_stay_in=True)
+
+    polarization(ID_mode)
+
+    grt = mono_grating_get() 
+
+    QP_ratio = ID_QP_ratio_get()
+    
+    hv_min,hv_max = energy_range_min_max()
+    if start == None:
+        start = hv_min
+    if stop == None:
+        stop=hv_max-50
+
+    if QP_ratio <100:
+        stop=min(stop,1500)
+        QP_ratio=1
+    else: 
+        QP_ratio=None
+
+    ID_calibration_scan(start,stop,step,QP=QP_ratio,Harm=Harm)
+
+
+##############################################################################################################
+##############################             Beam Motion            ##############################
+##############################################################################################################
+def scan_cam_motor(motor_name,start,stop,step,cam_num,ExposureTime):
+    """   
+    motor_name = 'x','y','z'...
+    cam_num = 1,2,3... uses cam_pv to get the pv
+
+    Previously: Pixel_Calibration
+    """    
+    cam_scan_setup(cam_num,ADtype='TIFF')
+
+    if BL.branch == 'ARPES':
+        ARPES_Motors.scan(motor_name,start,stop,step)
+    if BL.branch == 'Kappa':
+        Kappa_Motors.scan(motor_name,start,stop,step)
+    
+    cam_live()
+
+
+
+def scan_cam_hv(start,stop,step,cam_num,**kwargs):
+    """   
+    takes and image as a function of photon energy
+    **kwargs:
+        ExposureTime
+    Previously: BeamMotion_Vs_BL_Go
+    """
+    cam_scan_setup(cam_num,ADtype='TIFF')
+    scanhv(start,stop,step,**kwargs)
+
+    cam_live()
+
+
+
+def scan_cam_mono_zero_order(start,stop,step,cam_num,iterations=1,**kwargs):
+    """
+    Previously: BeamMotion_Vs_MonoZero_Go
+    """
+    i = 0
+    while i < iterations:
+        for angle in range(start,stop+step,step):
+            mono_zero_order(angle)
+            sleep(5)
+            cam_snap(cam_num,ADtype='TIFF',**kwargs)
+        i+=1
+    
+    cam_live()
+
+def scan_cam_mono_pitch(motor,angle,delta,cam_num,iterations=1,**kwargs):
+    """
+    takes image at zero order (alpha = beta = angle)
+    takes image at zeror order with delta 
+
+    motor = 'grating' or 'mirror
+        if 'grating': 
+            alpha = angle
+            beta = angle + delta 
+        if 'mirror': 
+            alpha = angle + delta 
+            beta = angle
+
+    Previously:BeamMotion_Vs_MirPitch_Go
+    """
+    if motor == 'grating': 
+        alpha = angle
+        beta = angle + delta 
+    if motor == 'mirror': 
+        alpha = angle + delta 
+        beta = angle
+    i=0
+    while i<iterations:
+        mono_angles_set(angle,angle)
+        sleep(5)
+        cam_snap(cam_num,ADtype='TIFF',**kwargs)
+        
+        mono_angles_set(alpha,beta)
+        sleep(5)
+        cam_snap(cam_num,ADtype='TIFF',**kwargs)
+        i+=1
+
+    cam_live()
+
+
+
diff --git a/build/lib/iexcode/macros/start_of_the_week.py b/build/lib/iexcode/macros/start_of_the_week.py
new file mode 100644
index 0000000000000000000000000000000000000000..ce69923b1f444649ca4fef215592bb4872e9a601
--- /dev/null
+++ b/build/lib/iexcode/macros/start_of_the_week.py
@@ -0,0 +1,303 @@
+import matplotlib.pyplot as plt
+
+from ..instruments.diagnostics import diodeC
+from ..instruments.files_and_folders import check_run
+from ..instruments.utilities import wait_for_it
+from ..instruments.current_amplifiers import Keithley
+from ..instruments.IEX_VPU import *
+from ..instruments.VLS_PGM import *
+from ..instruments.xrays import *
+from ..instruments.shutters import *
+from ..instruments.slits import *
+
+from ..instruments.Kappa import *
+from ..instruments.ARPES import *
+
+from .commissioning import *
+from .ScanFunctions_plot import *
+
+def start_of_the_week(grt,branch,wait=False,**kwargs):
+    """
+    This should be run every at the start of every week; 50 min total.
+    Switch to C-branch,.
+    If wait=True, wait for next day a 8:05.
+    
+    kwargs defaults:
+        run = None: used today's date to set run appropriatetly 
+        repeat = False: sets everything: switches branch, sets BL_Mode to Staff, resets scan/CAs/mono
+        scanType = ['slit1','wire','flux','monoVslit']
+        sound = False; no sounds
+              = True => plays sound after Slit1A scans and when script is complete
+    }
+    ID steering: (slit1A)
+        steering out => move beam more positive (10 urad ~ 0.25 mm)
+        steering up  => move beam more positive (10 urad ~ 0.25 mm)
+        
+    M1 steering: (monoVslit-2V and 2H)
+        Roll:  Rz more positive => 2V more positive (0.25 => .25 mm)
+        Pitch: Ry more positive => 2H more positive (0.03 => .5 mm
+
+    Previously: StartOfTheWeek
+    """
+    kwargs.setdefault('repeat',False)
+    kwargs.setdefault('run',check_run())
+    kwargs.setdefault('quick',True)    
+    kwargs.setdefault('interactive',True)    
+    kwargs.setdefault('scanType',['slit1','wire','flux','monoVslit'])
+    kwargs.setdefault('sound',True)
+    kwargs.setdefault('extended_range',False)
+    
+    for scan in kwargs['scanType']: 
+        if scan not in ['slit1','wire','flux','monoVslit']:
+            print(scan+" is not a valid scan scanType=['slit1','wire','flux','monoVslit']")
+            return
+
+        
+    ### checking diode settings:
+    if branch == 'c': 
+        diode = Keithley('b',15)
+        diode.autoscale()
+        diodeC('In')
+    else:
+        foo=input('Do you have a diode in direct beam (y or n)? >')
+        if foo.lower() == 'y' or foo.lower() == 'yes':
+            print('Resuming...')
+    
+    
+    ### checking QP ratio:
+    QP_ratio = ID_QP_ratio_get()
+    if QP_ratio != 100:
+        foo=input('QP on!!! Continue (y or n)? >')
+        if foo.lower() == 'y' or foo.lower() == 'yes':
+            print('Resuming...')
+        
+    ### Stuff that doesn't need beam & does not need to be run if repeating SoTW:
+    print("\n\n================== Sets Beamline & Scans:")
+    switch_gratings(grt)
+
+    if not kwargs['repeat']: 
+        switch_branch(branch)
+
+        print("\n\n================== Sets Directory:")
+
+    if branch=='c':
+        ARPES_init(BL_mode='staff')
+
+    fname='StartOfTheWeek_log.txt'
+    logfile_name_set(BL.endstation,filename=fname)
+
+        
+    ### checking branch shutter:
+    if branch_shutter_status() == False:
+        branch_shutter_open()
+    
+
+    ### Wait for next 8AM:
+    if wait:
+        t = datetime.today()
+        if 0 <= t.hour <= 8:
+            wait_for_it(0,8,5)
+        else:    
+            wait_for_it(1,8,5)
+
+    ### checking ID:
+    print("\n\n================== Start ID:")
+    polarization('RCP')
+    
+        
+    ### Ready to start:
+    FirstScan=BL.mda.fileNum+1
+
+
+    if not kwargs['repeat']:    
+        log_print("\n\n================== Start Of The Week @ "+today('slash')+':\n')
+        
+        
+    def interactive_fct(comment='scans'): 
+        foo=input('\nRepeat '+comment+' (y or n)? >')
+        if foo.lower() == 'y' or foo.lower() ==  'yes': 
+            print('\nRepeating...\n');flag=True
+            
+        else: 
+            print('\nResuming...\n'); flag=False
+        return flag
+    
+    DetDict={'c':(9,7,8,15),'d':(9,7,8,14)}
+    detCA4,detH,detV,detDiode=DetDict[branch]
+
+    ###### Scan front-end slit center:
+    if 'slit1' in kwargs['scanType']:
+        print("\n\n================== Slit 1A scans:")
+        ID_SP_set(2000)
+        flag=True
+        while flag:
+            
+            #Scan_SlitCenter('1H',-3,3,0.1,comment='Slit center - 1H')
+            #Scan_SlitCenter('1V',-3,3,0.1,comment='Slit center - 1V')
+            scan_narrow_slit('1H',[0.25,-3,3,0.1],comment='Slit center - 1H')
+            scan_narrow_slit('1V',[0.25,-3,3,0.1],comment='Slit center - 1V')
+            #SetSlit1A(4.5,4.5,0,0)
+            slit1A_set((4.5,4.5),(0,0))
+            m=BL.mda.lastFileNum()
+            print('\nsteering out => move beam more positive (10 urad ~ 0.25 mm)')
+            print('steering up  => move beam more positive (10 urad ~ 0.25 mm)')
+            try:
+                h_position=fit_mda(m-1,detCA4,1,'gauss',xrange=[-1,1]);plt.show()
+                v_position=fit_mda(m  ,detCA4,1,'gauss',xrange=[-1,1]);plt.show()
+                print('\nBeam position:')
+                print('   - horizontal: '+str(h_position))
+                print('   - vertical:   '+str(v_position))
+                h_steering,v_steering=beamsteering_1A(h_position,v_position)
+                print('\nBeam steering:')
+                print('   - horizontal: '+h_steering)
+                print('   - vertical:   '+v_steering)
+                print('\n')       
+            except:
+                print('Unable to fit position; try to tweak xrange or FWHM:')
+                print('fit_mda('+str(m)+','+str(detCA4)+',1,"gauss",xrange=[-1,1])')
+                print('fit_mda('+str(m+1)+','+str(detCA4)+',1,"gauss",xrange=[-1,1])')
+                print('\n')
+            if kwargs['sound']:playsound()
+            if kwargs['interactive']: flag=interactive_fct()
+            else: break
+
+    ###### Wire scans: 
+    if 'wire' in kwargs['scanType']:
+        ID_SP_set(2000)
+        slit1A_set(4.5,4.5,0,0)
+        scan_wire('H',comment='Wire scan - H',all_diag=False)     # by default puts all meshes in + DiodeC
+        scan_wire('V',comment='Wire scan - V',all_diag=False)
+        m=BL.mda.lastFileNum()
+        try:
+            plot_mda(m-1,detH,m,detV,title='wire-H (blue) & wire-V (orange)');plt.show()
+        except:
+            print('Unable to plot.')
+        if kwargs['sound']:playsound()
+        
+
+    ###### Mono/slit scans: 
+    list_position=[]
+    if 'monoVslit' in kwargs['scanType']:      
+        if grt=="HEG":
+            slit(300)
+            c=2
+        else:
+            slit(200)
+            c=1
+        print("\n\n================== Mono/slit scans:")     
+        if 'quick' in kwargs:
+            energy(500)
+            mono_energy_set(505)
+            print('\n---------- Scanning slit 2B:\n') 
+            flag=True
+            while flag:
+                scan_narrow_slit('2V',[0.25*c, -8, 8, 0.25])
+                sleep(1)
+                scan_narrow_slit('2H',[0.25, -6, 6, 0.25])
+                sleep(1)
+                m=BL.mda.lastFileNum()
+                try:
+                    V2=fit_mda(m-1,detDiode,1*c,'gauss')
+                    plt.show()
+                    H2=fit_mda(m  ,detDiode,1,'gauss')
+                    plt.show()
+                    list_position.append(V2)
+                    list_position.append(H2)
+                    #print(f"V2 = {round(V2,3)}")
+                    #print(f"H2 = {round(H2,3)}")
+                      
+                    print('\nBeam position:')
+                    print(f"   - vertical:   V1 = {round(V2,3)}")
+                    print(f"   - horizontal: H1 = {round(H2,3)}")
+                    v_steering=beamsteering_2B(V2)
+                    print('\nM1 roll (RZ) steering:')
+                    print('   - vertical: ~ '+v_steering)
+                    print('   - horizontal: reset slit 2BH center to ',str(H2))
+                    print('\n')         
+                      
+                    print('\n\nWARNING: 2V slit should always be centered at zero')
+                    print('Increasing M1 roll moves the beam more positive on 2V:')
+                    print('\t+0.05 pitch => ~ +0.04 slit position')
+                    print('To steer M1, use:')
+                    print("\tGet_Mirror(1);Move_M1('RZ',x)")
+                except:
+                    print('Unable to fit position.')
+                if kwargs['sound']:playsound()
+                if kwargs['interactive']: flag=interactive_fct('slit 2B')
+                else: break
+            print('\n---------- Scanning slit 1A:\n') 
+            flag=True
+            while flag:
+                scan_narrow_slit('1V',[0.25, -4, 4, 0.1])
+                sleep(1)
+                scan_narrow_slit('1H',[0.25, -3, 3, 0.1])
+                sleep(1)
+                slits_set_BL()
+                m=BL.mda.lastFileNum()
+                try:
+                    V1=fit_mda(m-1,detDiode,1,'gauss');plt.show()
+                    H1=fit_mda(m  ,detDiode,1,'gauss');plt.show()
+                    list_position.append(V1)
+                    list_position.append(H1)
+                    print('\nBeam position:')
+                    print(f"   - vertical:   V1 = {round(V1,3)}")
+                    print(f"   - horizontal: H1 = {round(H1,3)}")
+                except:
+                    print('Unable to fit position.')
+                if kwargs['sound']:playsound()
+                if kwargs['interactive']: flag=interactive_fct('slit 1A')
+                else: break
+            print('\nBeam center fit @ [2V,2H,1V,1H]:',list_position)
+            print('\nTo update slit center using:     update_slit_dict()\n')
+        else:    # longer full slit scans
+            ID_SP_set(500)
+            flag=True
+            while flag:
+                mono_energy_set(500)
+                slits_set_BL()
+                n=2 if 'extended_range' in kwargs  else 1
+                scan_mono_vs_slit('2V',[0.25*c,-2*c*n,2*c*n,0.5],[475,515,2],comment='Mono/Slit - 2V')    #10/20 min for MEG/HEG
+                scan_mono_vs_slit('2H',[0.25,-2*n,2*n,0.5],[475,515,2],comment='Mono/Slit - 2H')    #10min
+                scan_mono_vs_slit('1V',[0.5,-0.75*n,0.75*n,0.25*c],[475,515,2],comment='Mono/Slit - 1V')    #10min
+                scan_mono_vs_slit('1H',[0.5,-0.75*n,0.75*n,0.25],[475,515,2],comment='Mono/Slit - 1H')    #10min
+                #interactive
+                if kwargs['interactive']: flag=interactive_fct()
+                else: break
+                    
+    ###### Check flux: 
+    if 'flux' in kwargs['scanType']:
+        if m3r_branch == 'c':
+            diodeC('In')
+        print("\n\n================== Check Flux:")
+        flag=True
+        while flag:
+            check_flux(stay=True)
+            exit_slit(50)
+            energy(500)
+            scanhv(475,525,1,comment='Mono Scan @ 500eV')
+            try:
+                m=BL.mda.lastFileNum()
+                plot_mda(m,detDiode,flux=3);plt.show()
+            except:
+                print('Unable to fit position.')    
+            ### interactive
+            if kwargs['interactive']: flag=interactive_fct()
+            else: break
+
+    diagnostics_all_out()
+
+    print("\n\n================== All done:")
+    print("\nDon't forget to put back the user folder !!!!")
+    
+    ###### Plotting instructions and return first scan number 
+    if FirstScan is not None:
+        log_print(comment="\nFirstScan = "+str(FirstScan))
+        print('StartOfTheWeek_plot("'+branch+'",'+str(FirstScan)+')' )
+        print('Beam center fit @ [2V,2H,1V,1H]:',list_position)
+    print('\nREMEMBER to update slit center using:     update_slit_dict()')
+    
+    if kwargs['sound']:
+        playsound()
+        
+    return list_position
+    
diff --git a/iexcode.egg-info/PKG-INFO b/iexcode.egg-info/PKG-INFO
new file mode 100644
index 0000000000000000000000000000000000000000..c7569a8a5f1231b768831c7a738f3efe0558c8b3
--- /dev/null
+++ b/iexcode.egg-info/PKG-INFO
@@ -0,0 +1,12 @@
+Metadata-Version: 2.1
+Name: iexcode
+Version: 0.0.1
+Summary: python scripts to run 29id of the APS
+Home-page: https://github.com/xxx
+Maintainer: Jessica McChesney
+Maintainer-email: jmcchesn@anl.gov
+License: UNKNOWN
+Platform: UNKNOWN
+
+UNKNOWN
+
diff --git a/iexcode.egg-info/SOURCES.txt b/iexcode.egg-info/SOURCES.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e22a33a508fd45a06267a30d008faaffa8c624a0
--- /dev/null
+++ b/iexcode.egg-info/SOURCES.txt
@@ -0,0 +1,57 @@
+README.md
+setup.py
+iexcode/__init__.py
+iexcode.egg-info/PKG-INFO
+iexcode.egg-info/SOURCES.txt
+iexcode.egg-info/dependency_links.txt
+iexcode.egg-info/requires.txt
+iexcode.egg-info/top_level.txt
+iexcode/instruments/AD_utilities.py
+iexcode/instruments/ARPES.py
+iexcode/instruments/FMB_mirrors.py
+iexcode/instruments/IEX_VPU.py
+iexcode/instruments/IEX_endstations.py
+iexcode/instruments/Kappa.py
+iexcode/instruments/Kappa_Euler.py
+iexcode/instruments/Kappa_det.py
+iexcode/instruments/Lakeshore_335.py
+iexcode/instruments/Motors.py
+iexcode/instruments/Scienta.py
+iexcode/instruments/VLS_PGM.py
+iexcode/instruments/__init__.py
+iexcode/instruments/bakeout.py
+iexcode/instruments/beamline.py
+iexcode/instruments/cameras.py
+iexcode/instruments/conversions_constants.py
+iexcode/instruments/current_amplifiers.py
+iexcode/instruments/diagnostics.py
+iexcode/instruments/electron_analyzer.py
+iexcode/instruments/encoders.py
+iexcode/instruments/files_and_folders.py
+iexcode/instruments/gate_valves.py
+iexcode/instruments/hxp_mirrors.py
+iexcode/instruments/logfile.py
+iexcode/instruments/m3r.py
+iexcode/instruments/mpa.py
+iexcode/instruments/remote_controlers.py
+iexcode/instruments/resolution.py
+iexcode/instruments/s29_temp_cntl.py
+iexcode/instruments/scalers.py
+iexcode/instruments/scanRecord.py
+iexcode/instruments/scratch.py
+iexcode/instruments/shutters.py
+iexcode/instruments/slits.py
+iexcode/instruments/spec_stuff.py
+iexcode/instruments/staff.py
+iexcode/instruments/storage_ring.py
+iexcode/instruments/userCalcs.py
+iexcode/instruments/utilities.py
+iexcode/instruments/vortexs29.py
+iexcode/instruments/xrays.py
+iexcode/macros/ARPES_macros.py
+iexcode/macros/BL_shutdown.py
+iexcode/macros/Kappa_optimization.py
+iexcode/macros/ScanFunctions_plot.py
+iexcode/macros/__init__.py
+iexcode/macros/commissioning.py
+iexcode/macros/start_of_the_week.py
\ No newline at end of file
diff --git a/iexcode.egg-info/dependency_links.txt b/iexcode.egg-info/dependency_links.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc
--- /dev/null
+++ b/iexcode.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/iexcode.egg-info/requires.txt b/iexcode.egg-info/requires.txt
new file mode 100644
index 0000000000000000000000000000000000000000..52556943b71432c57250dc0ac297d318372c7967
--- /dev/null
+++ b/iexcode.egg-info/requires.txt
@@ -0,0 +1,5 @@
+matplotlib
+numpy
+scipy
+h5py
+netCDF4
diff --git a/iexcode.egg-info/top_level.txt b/iexcode.egg-info/top_level.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3dc2072e0b7c51426134239fbc2e3afd8f41a12f
--- /dev/null
+++ b/iexcode.egg-info/top_level.txt
@@ -0,0 +1 @@
+iexcode
diff --git a/iexcode/__pycache__/__init__.cpython-37.pyc b/iexcode/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..e2d0eaad8087d6fedb2ad12bc304ce79bc95a05c
Binary files /dev/null and b/iexcode/__pycache__/__init__.cpython-37.pyc differ
diff --git a/iexcode/instruments/AD_utilities.py b/iexcode/instruments/AD_utilities.py
new file mode 100644
index 0000000000000000000000000000000000000000..f8d43d23aed84bf5a1ee86d46cefdbb81f5d1ffa
--- /dev/null
+++ b/iexcode/instruments/AD_utilities.py
@@ -0,0 +1,347 @@
+"""
+General functions for dealing with Area Detectors and Cameras at 29ID
+
+work in progress need to redo
+"""
+##############################################################################################################
+##############################     General Area Detector            ##############################
+##############################################################################################################
+import datetime
+import re
+from os import listdir,mkdir,chown,system,chmod
+from os.path import join, isfile, exists, dirname
+from time import sleep
+
+from epics import caget, caput
+from iexcode.instruments.IEX_endstations import *
+from iexcode.instruments.files_and_folders import get_next_fileNumber
+
+
+def AD_CurrentDirectory(ADplugin):
+    """
+    returns the current directory for area detector SavePlugin
+    handles both Winodws and linux IOCs
+    ADplugin = "29idc_ps1:TIFF1:"; $(P)$(SavePlugin)
+    """
+    SubDir=caget(ADplugin+"FilePath",as_string=True)
+    if SubDir[0] == 'X':
+        Dir='/net/s29data/export/data_29idb/'
+        SubDir=SubDir.split('\\')[1:]
+    elif SubDir[0] == 'Y':
+        Dir='/net/s29data/export/data_29idc/'
+        SubDir=SubDir.split('\\')[1:]
+    elif SubDir[0] == 'Z':
+        Dir='/net/s29data/export/data_29idd/'    
+        SubDir=SubDir.split('\\')[1:]
+    else: 
+        Dir = SubDir
+        SubDir=[]
+    FilePath=join(Dir,*SubDir,'')
+    return FilePath 
+
+def AD_prefix(ADplugin):
+    """
+    returns the prefix for AreaDetector plugin based on ADplugin 
+    """
+    prefix = caget(ADplugin+"FileName_RBV",as_string=True)
+    return prefix
+
+def AD_EnableStats(ADplugin):
+    """
+    Enabling the statistics in an AreaDector
+    ADplugin = "29idc_ps1:Stats1:"; (ADplugin=$(P)$(StatsPlugin))
+    """
+    caput(ADplugin+"EnableCallbacks","Enable")
+    caput(ADplugin+"ComputeStatistics","Yes")
+    caput(ADplugin+"ComputeCentroid","Yes")
+    
+
+def AD_SaveFileSetup(ADplugin,mda,**kwargs):
+    """    
+    ADplugin = "29id_ps1:TIFF1:" which IOC and which filesaving plugin
+            (ADplugin=$(P)$(SavePlugin))
+    uses to get the current MDA directory and then set the path to one up + /dtype
+    MDA_CurrentDirectory(scanIOC=None)
+    
+    **kwargs (defaults)
+        scanIOC = BL_ioc()
+        userpath = extracted from ScanRecord unless specified
+        subfolder = taken from ADplugin unless specified
+            filepath = userpath/subfolder
+        
+        prefix = default same as subfolder
+        ext = file extension is extracted for ADplugin unless specified
+            (TIFF -> tif, HDF -> h5, ...)
+        FileTemplate="%s%s_%4.4d."+ext; format for filename first %s = filepath, second %s = prefix
+        
+    """
+    kwargs.setdefault("userpath",dirname(dirname(mda.filepath)))
+    kwargs.setdefault("subfolder",ADplugin.split(":")[-2][:-1])
+
+    kwargs.setdefault("prefix",ADplugin.split(":")[-2][:-1])
+    extDict={"TIFF":".tif","HDF":"h5"}
+    kwargs.setdefault("ext",ADplugin.split(":")[-2][:-1])
+    kwargs.setdefault("FileTemplate","%s%s_%4.4d."+kwargs["ext"])
+    
+    kwargs.setdefault("debug",False)
+    
+    if kwargs['debug']:
+        print("kwargs: ",kwargs)
+
+    fpath=join(kwargs['userpath'],kwargs['subfolder'],'')
+    print("\nFolder: " + fpath)
+    if not (exists(fpath)):
+        fileNumber=1
+    else:
+        fileNumber=get_next_fileNumber(fpath,kwargs["prefix"])
+    print("NextFile: "+str(fileNumber))
+    caput(ADplugin+"CreateDirectory",-1) #allows IOC to create directories    
+    caput(ADplugin+"FilePath",fpath)
+    caput(ADplugin+"FileName",kwargs["prefix"])
+    caput(ADplugin+"FileNumber",fileNumber)
+    
+    #setup AD
+    caput(ADplugin+"FileTemplate",kwargs["FileTemplate"])
+    caput(ADplugin+"AutoIncrement","Yes")
+    caput(ADplugin+"AutoSave","Yes")
+    
+def AD_CurrentPrefix(ADplugin):
+    """
+    returns the prefix (without _) for area detector SavePlugin
+    ADplugin = "29id_ps1:TIFF1:"; $(P)$(SavePlugin)
+    """
+    Prefix=caget(ADplugin+'FileName',as_string=True)
+    return Prefix
+   
+def AD_CurrentRun(ADplugin):
+    """
+    returns the curent run specified in the filepath for area detector SavePlugin
+    ADplugin = "29id_ps1:TIFF1:"; $(P)$(SavePlugin)
+    """
+    fpath=caget(ADplugin+"FilePath",as_string=True)
+    current_run=re.findall("\d\d\d\d_\d", fpath)[0]
+    return current_run
+   
+def AD_CurrentUser(ADplugin):
+    """
+    returns the curent user specified in the filepath for area detector SavePlugin
+    ADplugin = "29id_ps1:TIFF1:"; $(P)$(SavePlugin)
+    """
+    folder_name = ADplugin.split(":")[1]
+    folder_name[:-1]
+    SubDir=caget(ADplugin+":FilePath",as_string=True)
+    if SubDir[0] == 'X':
+        current_user='Staff'
+    elif SubDir[0] == 'Y':
+        m=SubDir.find(AD_CurrentRun(ADplugin))
+        n=SubDir.find(folder_name)
+        current_user=SubDir[m+7:n]
+    else: current_user=None
+    return current_user
+
+def AD_DoneSingleSave(ADplugin,**kwargs):
+    """
+    sets and AD up ready to save images
+        Acquire -> Done
+        ImageMode -> Single
+        Save -> Enable
+        e.g. ADplugin="29id_ps2:TIFF1:"
+        
+        **kwargs:
+        P=first part of ADplugin if not specified
+        R="cam1:"; other AD have "det1:"
+    """
+    kwargs.setdefault("P",ADplugin.split(":")[0]+":")
+    kwargs.setdefault("R","cam1:")
+    caput(kwargs["P"]+kwargs["R"]+"Acquire","Done",wait=True,timeout=5*60);sleep(.1)
+    caput(kwargs["P"]+kwargs["R"]+"ImageMode","Single");sleep(.5)
+    caput(ADplugin+"EnableCallbacks","Enable");sleep(.1)
+        
+def AD_FreeRun(ADplugin,**kwargs):
+    """
+    sets and AD to disable saving and free run
+        Saving -> Disable
+        Acquire -> Done
+        ImageMode -> Single
+
+        e.g. ADplugin="29id_ps2:TIFF1:"
+        
+        **kwargs:
+        P=first part of ADplugin if not specified
+        R="cam1:"; other AD have "det1:"
+    """
+    kwargs.setdefault("P",ADplugin.split(":")[0]+":")
+    kwargs.setdefault("R","cam1:")
+    caput(kwargs["P"]+kwargs["R"]+"Acquire","Done",wait=True,timeout=5*60)
+    caput(ADplugin+"EnableCallbacks","Disable");sleep(.1)
+    caput(kwargs["P"]+kwargs["R"]+"ImageMode","Continuous");sleep(.1)
+    caput(kwargs["P"]+kwargs["R"]+"Acquire","Acquire");sleep(.1)
+        
+
+def AD_snap(ADplugin,**kwargs):
+    """
+    takes an image and save the image for ADplugin
+        e.g. ADplugin="29id_ps2:TIFF1:"
+        
+    use AD_SaveFileSetup to set filepath, prefix etc.
+    use AD_CurrentDirectory to see current directory
+    use AD_prefix to see current prefix
+    
+    **kwargs:
+        P=first part of ADplugin if not specified
+        R="cam1:"; other AD have "det1:"
+        
+        ExposureTime: changes both the exposure time and the acquire time for the snapshot
+                      resets after acquisition
+        FreeRun: True => disable setting and go back to continuous acquision 
+                 False => leave saving enabled and camera in single acquision
+    """
+    kwargs.setdefault("P",ADplugin.split(":")[0]+":")
+    kwargs.setdefault("R","cam1:")
+    kwargs.setdefault("FreeRun",True)
+
+    expT=caget(kwargs["P"]+kwargs["R"]+"AcquireTime_RBV")
+    acqT=caget(kwargs["P"]+kwargs["R"]+"AcquirePeriod_RBV")
+    
+    AD_DoneSingleSave(ADplugin,**kwargs)
+    
+    if "ExposureTime" in kwargs:
+        caput(kwargs["P"]+kwargs["R"]+"AcquireTime",kwargs["ExposureTime"])
+        caput(kwargs["P"]+kwargs["R"]+"AcquireTime",kwargs["ExposureTime"]+.01)
+        
+    caput(kwargs["P"]+kwargs["R"]+"Acquire","Acquire",wait=True,timeout=5*60)
+    
+    if "ExposureTime" in kwargs:
+        caput(kwargs["P"]+kwargs["R"]+"AcquireTime",expT)
+        caput(kwargs["P"]+kwargs["R"]+"AcquireTime",acqT) 
+
+    if kwargs["FreeRun"]:
+        sleep(.1)
+        AD_FreeRun(ADplugin,**kwargs)
+        
+
+
+def AD_ScanTrigger(ADplugin,mda,**kwargs):
+    """
+    Add Triggering of AreaDetector to scanIOC
+    ADplugin = "29idc_ps1:TIFF1:" (ADplugin=$(P)$(SavePlugin))
+    
+    **kwargs
+        scanIOC = "29id"+BL_ioc() if not specified
+        scanDIM = 1
+        P=first part of ADplugin if not specified
+        R="cam1:"; other AD have "det1"
+        detTrig = 2; detectorTrigger number
+    """
+    kwargs.setdefault("scanDIM",1)
+    kwargs.setdefault("P",ADplugin.split(":")[0]+":")
+    kwargs.setdefault("R","cam1:")
+    kwargs.setdefault("detTrig",2)
+    
+    scanPV=mda.ioc+"scan"+str(kwargs["scanDIM"])    
+    trigger=".T"+str(kwargs["detTrig"])+"PV"
+    caput(scanPV+trigger,kwargs["P"]+kwargs["R"]+"Acquire",wait=True,timeout=5*60)
+    
+def ADplugin_ScanSetup(ADplugin,mda, **kwargs):
+    """
+    stop the acquisition, puts in ImageMode=Single
+    enables saving
+    add to detector trigger
+    Does not press go
+    
+    ADplugin = "29idc_ps1:TIFF1:"; (ADplugin=$(P)$(SavePlugin))
+    **kwargs
+        # AD_ScanTrigger
+        scanIOC = "29id"+BL_ioc() if not specified
+        scanDIM = 1
+        P=first part of ADplugin if not specified
+        R="cam1:"; other AD have "det1:"
+        detTrig = 2; detectorTrigger number
+        
+        # AD_SaveFileSetup
+        filepath=userpath (from BL_ioc scanRecord)+"/dtype"
+         (e.g. filepath="/net/s29data/export/data_29id"+folder+"/"+run+"/"+userName+"/"+df)
+        dtype = taken from ADplugin
+        FileTemplate="%s%s_%4.4d."+dtype; format for filename first %s = filepath, second %s = prefix
+        prefix = dtype by default
+    
+    """
+    #from AD_ScanTrigger
+    kwargs.setdefault("P",ADplugin.split(":")[0]+":")
+    kwargs.setdefault("R","cam1:")
+
+    AD_DoneSingleSave(ADplugin,**kwargs)
+    
+    AD_SaveFileSetup(ADplugin,**kwargs)
+    AD_ScanTrigger(ADplugin, **kwargs)
+    trigger=".T"+str(kwargs["detTrig"])+"PV"
+    scanPV=mda.ioc+"scan"+str(kwargs["scanDIM"])  
+    print("WARNING: you need to need to disable saving and clear the trigger by hand after the scan")
+    print("\tAD_FreeRun("+ADplugin+"); caput("+scanPV+trigger+",'')")
+
+def AD_ROI_setup(AD,ROInum,xcenter=500,ycenter=500,xsize=50,ysize=50,binX=1,binY=1):  
+    """
+    AD = "29id_ps4"
+    AD = "29iddMPA"
+    """
+    # roiNUM=1  MPA_ROI_SetUp(535,539,50,50)  center of MCP
+    
+    ADplugin=AD+':ROI'+str(ROInum)+':'
+    xstart=xcenter-xsize/2.0
+    ystart=ycenter-ysize/2.0
+    caput(ADplugin+'MinX',xstart)
+    caput(ADplugin+'MinY',ystart)
+    caput(ADplugin+'SizeX',xsize)
+    caput(ADplugin+'SizeY',ysize)
+    caput(ADplugin+'BinX',binX)
+    caput(ADplugin+'BinY',binY)
+    caput(ADplugin+'EnableCallbacks','Enable')
+    print(ADplugin+' - '+caget(ADplugin+'EnableCallbacks_RBV',as_string=True))
+    #MPA_ROI_Stats(roiNUM)
+    
+def AD_OVER_SetUp(AD,ROInum,OVERnum,linewidth=5,shape='Rectangle'):
+    """
+    AD = "29id_ps4"
+    AD = "29iddMPA"
+    shape= 'Cross', 'Rectangle', 'Ellipse','Text'
+    """
+    OVER1=AD+":Over1:"+str(OVERnum)+":"
+    ROI=AD+":ROI"+str(ROInum)+":"
+    
+    caput(ROI+'EnableCallbacks','Enable')
+    caput(OVER1+"Name","ROI"+str(ROInum))
+    caput(OVER1+"Shape",shape)
+    caput(OVER1+"Red",0)
+    caput(OVER1+"Green",255)
+    caput(OVER1+"Blue",0)
+    caput(OVER1+'WidthX',linewidth)
+    caput(OVER1+'WidthY',linewidth)
+    
+    caput(OVER1+"PositionXLink.DOL",ROI+"MinX_RBV CP")
+    caput(OVER1+"SizeXLink.DOL",ROI+"SizeX_RBV CP")
+    caput(OVER1+"PositionYLink.DOL",ROI+"MinY_RBV CP")
+    caput(OVER1+"SizeYLink.DOL",ROI+"SizeY_RBV CP")
+   
+    caput(OVER1+"Use","Yes")
+
+    
+def AD_OverLayCenter(x,y,AD,OverLay=1,Num=1):
+    """
+    Sets CenterX and CenterY for  AD:Over(OverLay):Num:
+    eg. 29id_ps2:Over1:1: AD='29id_ps2',Overlay=1, Num=1
+    """
+    caput(AD+":Over"+str(OverLay)+":"+str(Num)+":CenterX",x)
+    caput(AD+":Over"+str(OverLay)+":"+str(Num)+":CenterY",y)
+    
+def AD_OverLayCenter_get(AD,OverLay=1,Num=1):
+    """
+    Sets CenterX and CenterY for  AD:Over(OverLay):Num:
+    eg. 29id_ps2:Over1:1: AD='29id_ps2',Overlay=1, Num=1
+    """
+    print('x = '+str(caget(AD+":Over"+str(OverLay)+":"+str(Num)+":CenterX")))
+    print('y = '+str(caget(AD+":Over"+str(OverLay)+":"+str(Num)+":CenterY")))
+
+
+
+
+
diff --git a/iexcode/instruments/ARPES.py b/iexcode/instruments/ARPES.py
index b07a8c491f0306e935ab1eba28c10e828811b2b1..90f825f9fa07a93d36c82263dbf7404f0ea79efd 100644
--- a/iexcode/instruments/ARPES.py
+++ b/iexcode/instruments/ARPES.py
@@ -2,27 +2,28 @@ import numpy as np
 from time import sleep
 
 from epics import caget,caput,PV
-from .IEX_endstations import *
-from .staff import staff_detector_dictionary
-
-from .files_and_folders import check_run,make_user_folders,folder_mda
-from .staff import staff_detector_dictionary
-from .logfile import logfile_name_set,logfile_header
-
-from .conversions_constants import *
-from .utilities import *
-from .userCalcs import userStringSeq_clear, userStringSeq_pvs
-
-from .scanRecord import *
-from .Motors import *
-from .xrays import *
-from .current_amplifiers import *
-from .gate_valves import valve_close, branch_valves
-from .shutters import branch_shutter_close
-from .slits import slit3C_get
-
-from .Lakeshore_335 import Lakeshore_reset
-from .electron_analyzer import folders_EA,EA
+
+from iexcode.instruments.IEX_endstations import *
+from iexcode.instruments.staff import staff_detector_dictionary
+
+from iexcode.instruments.files_and_folders import check_run,make_user_folders,folder_mda
+from iexcode.instruments.staff import staff_detector_dictionary
+from iexcode.instruments.logfile import logfile_name_set,logfile_header
+
+from iexcode.instruments.conversions_constants import *
+from iexcode.instruments.utilities import *
+from iexcode.instruments.userCalcs import userStringSeq_clear, userStringSeq_pvs
+
+from iexcode.instruments.scanRecord import *
+from iexcode.instruments.Motors import *
+from iexcode.instruments.xrays import *
+from iexcode.instruments.current_amplifiers import *
+from iexcode.instruments.gate_valves import valve_close, branch_valves
+from iexcode.instruments.shutters import branch_shutter_close
+from iexcode.instruments.slits import slit3C_get
+
+from iexcode.instruments.Lakeshore_335 import Lakeshore_reset
+from iexcode.instruments.electron_analyzer import folders_EA,EA
 
 
 #############################################################################
diff --git a/iexcode/instruments/FMB_mirrors.py b/iexcode/instruments/FMB_mirrors.py
index c7c0069713de70bca39173e5fa7265b05c95e32d..888d9b9425b99a75ac9d39dcac6447fafe0680f7 100644
--- a/iexcode/instruments/FMB_mirrors.py
+++ b/iexcode/instruments/FMB_mirrors.py
@@ -2,9 +2,9 @@ from time import sleep
 
 from epics import caget, caput
 
-from .IEX_endstations import *
-from .utilities import read_dict, print_warning_message
-from .m3r import m3r_branch
+from iexcode.instruments.IEX_endstations import *
+from iexcode.instruments.utilities import read_dict, print_warning_message
+from iexcode.instruments.m3r import m3r_branch
 
 M0M1_fpath="/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/Dict_IDCal.txt"
 
diff --git a/iexcode/instruments/IEX_VPU.py b/iexcode/instruments/IEX_VPU.py
index 10274c00e35def08a4b8ea7f5bd777cfb61f812c..6678eb16903a7372b42583b5b4cfae682fa56a56 100644
--- a/iexcode/instruments/IEX_VPU.py
+++ b/iexcode/instruments/IEX_VPU.py
@@ -6,10 +6,10 @@ import numpy.polynomial.polynomial as poly
 
 from epics import caget, caput
 
-from .utilities import dateandtime, print_warning_message, read_dict
-from .shutters import main_shutter_check_open
-from .VLS_PGM import mono_grating_get
-from .userCalcs import userCalcOut_clear
+from iexcode.instruments.utilities import dateandtime, print_warning_message, read_dict
+from iexcode.instruments.shutters import main_shutter_check_open
+from iexcode.instruments.VLS_PGM import mono_grating_get
+from iexcode.instruments.userCalcs import userCalcOut_clear
 
 IDcal_fpath="/home/beams22/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/Dict_IDCal.txt"
 
diff --git a/iexcode/instruments/IEX_endstations.py b/iexcode/instruments/IEX_endstations.py
index 5c3fd1895611de62aa2c47eb62225feae413d52e..94ee6e1eb9ce4b609d49ca490ac53f24acb5cf32 100644
--- a/iexcode/instruments/IEX_endstations.py
+++ b/iexcode/instruments/IEX_endstations.py
@@ -10,6 +10,8 @@ it makes the default stuff work
 this will prompt for the endstation and will set the default parameters, look at the 
 init kwargs to see which defaults you can change.
 """
+global BL
+BL = None
 
 class Endstation:
     """
diff --git a/iexcode/instruments/Kappa.py b/iexcode/instruments/Kappa.py
index 6fcb40d23ba58d30f716673b87569d6cb4f4c838..18c98109e657face5c89a1a35b50e2ae272c9966 100644
--- a/iexcode/instruments/Kappa.py
+++ b/iexcode/instruments/Kappa.py
@@ -3,27 +3,28 @@ from time import sleep
 from math import floor
 
 from epics import caget, caput,PV
-from .IEX_endstations import *
-from .staff import staff_detector_dictionary
-
-from .files_and_folders import check_run,make_user_folders,folder_mda
-from .staff import staff_detector_dictionary
-from .logfile import logfile_name_set,logfile_header
-
-from .conversions_constants import *
-from .utilities import *
-from .userCalcs import userStringSeq_clear, userStringSeq_pvs
-
-from .scanRecord import *
-from .Motors import *
-from .xrays import *
-from .current_amplifiers import *
-from .gate_valves import valve_close, branch_valves
-from .shutters import branch_shutter_close
-from .slits import slit3D_get
-
-from .Kappa_det import *
-from .spec_stuff import folders_spec
+
+from iexcode.instruments.IEX_endstations import *
+from iexcode.instruments.staff import staff_detector_dictionary
+
+from iexcode.instruments.files_and_folders import check_run,make_user_folders,folder_mda
+from iexcode.instruments.staff import staff_detector_dictionary
+from iexcode.instruments.logfile import logfile_name_set,logfile_header
+
+from iexcode.instruments.conversions_constants import *
+from iexcode.instruments.utilities import *
+from iexcode.instruments.userCalcs import userStringSeq_clear, userStringSeq_pvs
+
+from iexcode.instruments.scanRecord import *
+from iexcode.instruments.Motors import *
+from iexcode.instruments.xrays import *
+from iexcode.instruments.current_amplifiers import *
+from iexcode.instruments.gate_valves import valve_close, branch_valves
+from iexcode.instruments.shutters import branch_shutter_close
+from iexcode.instruments.slits import slit3D_get
+
+from iexcode.instruments.Kappa_det import *
+from iexcode.instruments.spec_stuff import folders_spec
 
 
 
diff --git a/iexcode/instruments/Kappa_Euler.py b/iexcode/instruments/Kappa_Euler.py
index cd2dbfba809e9dd872a3dbbd3429210cf57ff883..42dfe2f1bac9ec223a1c6a78a4d20ab9f32720bf 100644
--- a/iexcode/instruments/Kappa_Euler.py
+++ b/iexcode/instruments/Kappa_Euler.py
@@ -1,9 +1,9 @@
 import numpy as np
 from epics import caget, caput
 
-from .userCalcs import userCalcOut_clear
-from .IEX_endstations import mda
-from .userCalcs import userCalcOut_clear
+from iexcode.instruments.userCalcs import userCalcOut_clear
+from iexcode.instruments.IEX_endstations import mda
+from iexcode.instruments.userCalcs import userCalcOut_clear
 
 #### Obsolete?
 
diff --git a/iexcode/instruments/Kappa_det.py b/iexcode/instruments/Kappa_det.py
index 14b2f04beb839662c0cc883b804fbd1656527838..9a1a19071153d757e6dd4897cf40339b8fd4a73f 100644
--- a/iexcode/instruments/Kappa_det.py
+++ b/iexcode/instruments/Kappa_det.py
@@ -1,7 +1,7 @@
 from time import sleep
 from epics import caget, caput
  
-from .IEX_endstations import Motors
+from iexcode.instruments.IEX_endstations import Motors
 
 
 ##############################################################################################################
diff --git a/iexcode/instruments/Lakeshore_335.py b/iexcode/instruments/Lakeshore_335.py
index 080c578697c5042e8d578d2805c132f837261847..5acc6b95dd8ba5c3da389836f2b159966a62fd99 100644
--- a/iexcode/instruments/Lakeshore_335.py
+++ b/iexcode/instruments/Lakeshore_335.py
@@ -7,8 +7,8 @@ import numpy as np
 from epics import caget, caput
 
 
-from .IEX_endstations import *
-from .utilities import read_dict
+from iexcode.instruments.IEX_endstations import *
+from iexcode.instruments.utilities import read_dict
 
 def Lakeshore_reset(pv,d):
     """
diff --git a/iexcode/instruments/Motors.py b/iexcode/instruments/Motors.py
index 24085c5a29908b4789a68ab03e4a8979504fd9ac..119b51bb725c0a065f3f6eb245b342d17eb3dad4 100644
--- a/iexcode/instruments/Motors.py
+++ b/iexcode/instruments/Motors.py
@@ -3,7 +3,7 @@ from math import floor
 
 from epics import caget, caput
 
-from IEX_endstations import *
+from iexcode.instruments.IEX_endstations import *
 
 
 class Motors:
diff --git a/iexcode/instruments/VLS_PGM.py b/iexcode/instruments/VLS_PGM.py
index 4ca6dd8164e2089ba1132de1861e722a0674ec6e..8f7bfdc225a080961c962b0d084059f2b535f179 100644
--- a/iexcode/instruments/VLS_PGM.py
+++ b/iexcode/instruments/VLS_PGM.py
@@ -7,8 +7,8 @@ import numpy as np
 
 
 from epics import caget,caput
-from .IEX_endstations import *
-from .utilities import print_warning_message,read_dict
+from iexcode.instruments.IEX_endstations import *
+from iexcode.instruments.utilities import print_warning_message,read_dict
 
 
 ##############################################################################################################
diff --git a/iexcode/instruments/__init__.py b/iexcode/instruments/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e244a3c105e5bc09da608c5fd6134ba1ef425528
--- /dev/null
+++ b/iexcode/instruments/__init__.py
@@ -0,0 +1,42 @@
+
+""" from iexcode.instruments.AD_utilites import *
+from iexcode.instruments.ARPES import *
+from iexcode.instruments.bakeout import * 
+from iexcode.instruments.beamline import * 
+from iexcode.instruments.cameras import * 
+from iexcode.instruments.conversions_constants import * 
+from iexcode.instruments.current_amplifiers import * 
+from iexcode.instruments.diagnostics import * 
+from iexcode.instruments.electron_analyzer import * 
+from iexcode.instruments.encoders import * 
+from iexcode.instruments.files_and_folders import * 
+from iexcode.instruments.FMB_mirrors import * 
+from iexcode.instruments.gate_valves import * 
+from iexcode.instruments.hxp_mirrors import * 
+from iexcode.instruments.IEX_endstations import * 
+from iexcode.instruments.IEX_VPU import * 
+from iexcode.instruments.Kappa import * 
+from iexcode.instruments.Kappa_det import * 
+from iexcode.instruments.Kappa_Euler import * 
+from iexcode.instruments.Lakeshore_335 import * 
+from iexcode.instruments.logfile import * 
+from iexcode.instruments.m3r import * 
+from iexcode.instruments.Motors import * 
+from iexcode.instruments.mpa import * 
+from iexcode.instruments.remote_controlers import * 
+from iexcode.instruments.resolution import * 
+from iexcode.instruments.s29_temp_cntl import * 
+from iexcode.instruments.scalers import * 
+from iexcode.instruments.Scienta import * 
+from iexcode.instruments.shutters import * 
+from iexcode.instruments.slits import * 
+from iexcode.instruments.spec_stuff import * 
+from iexcode.instruments.staff import * 
+from iexcode.instruments.storage_ring import * 
+from iexcode.instruments.userCalcs import * 
+from iexcode.instruments.utilities import * 
+from iexcode.instruments.VLS_PGM import * 
+from iexcode.instruments.vortexs29 import * 
+from iexcode.instruments.xrays import * 
+
+ """
diff --git a/iexcode/instruments/__pycache__/AD_utilites.cpython-37.pyc b/iexcode/instruments/__pycache__/AD_utilites.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..8a370ff2b8c85e414b0f9ab7954b00e977d81b09
Binary files /dev/null and b/iexcode/instruments/__pycache__/AD_utilites.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/AD_utilities.cpython-37.pyc b/iexcode/instruments/__pycache__/AD_utilities.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..763286c8ddcdce49fed5d93a0cf42c0560f773e6
Binary files /dev/null and b/iexcode/instruments/__pycache__/AD_utilities.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/ARPES.cpython-37.pyc b/iexcode/instruments/__pycache__/ARPES.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..062ed0acd605454bc28bed0f3204edf64921a4eb
Binary files /dev/null and b/iexcode/instruments/__pycache__/ARPES.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/FMB_mirrors.cpython-37.pyc b/iexcode/instruments/__pycache__/FMB_mirrors.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..cc28ad732f71f5749fe7379b7c1c41463fa49469
Binary files /dev/null and b/iexcode/instruments/__pycache__/FMB_mirrors.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/IEX_VPU.cpython-37.pyc b/iexcode/instruments/__pycache__/IEX_VPU.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..48fdfabc4675e10f548048eafc93655f24cb372c
Binary files /dev/null and b/iexcode/instruments/__pycache__/IEX_VPU.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/IEX_endstations.cpython-37.pyc b/iexcode/instruments/__pycache__/IEX_endstations.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b4ef735bafb06232202d431f08609321d27de902
Binary files /dev/null and b/iexcode/instruments/__pycache__/IEX_endstations.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/Kappa.cpython-37.pyc b/iexcode/instruments/__pycache__/Kappa.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b280eebee6bb33b0a5a9ee70a1958a91420d40e9
Binary files /dev/null and b/iexcode/instruments/__pycache__/Kappa.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/Kappa_Euler.cpython-37.pyc b/iexcode/instruments/__pycache__/Kappa_Euler.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..d7e5066528a6d569653c3be9a202fe97ce5d86f4
Binary files /dev/null and b/iexcode/instruments/__pycache__/Kappa_Euler.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/Kappa_det.cpython-37.pyc b/iexcode/instruments/__pycache__/Kappa_det.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..64a16ee6fa9eb6ab0e825aeb9dc61f7afccee3c6
Binary files /dev/null and b/iexcode/instruments/__pycache__/Kappa_det.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/Lakeshore_335.cpython-37.pyc b/iexcode/instruments/__pycache__/Lakeshore_335.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..8fe68e9b0219fe031f8768107e920399efdadc2c
Binary files /dev/null and b/iexcode/instruments/__pycache__/Lakeshore_335.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/Motors.cpython-37.pyc b/iexcode/instruments/__pycache__/Motors.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c3ada008630f4d6119799aa0b66f9b538493f799
Binary files /dev/null and b/iexcode/instruments/__pycache__/Motors.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/Scienta.cpython-37.pyc b/iexcode/instruments/__pycache__/Scienta.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9008e02435a9fc2c2c5df84e805f720754feb2a6
Binary files /dev/null and b/iexcode/instruments/__pycache__/Scienta.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/VLS_PGM.cpython-37.pyc b/iexcode/instruments/__pycache__/VLS_PGM.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b24f7623fd135e0ec917cb7d239a015d5dc153ef
Binary files /dev/null and b/iexcode/instruments/__pycache__/VLS_PGM.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/__init__.cpython-37.pyc b/iexcode/instruments/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4c3c008b246ea4aaf58e2d55d10549b1f5dd589b
Binary files /dev/null and b/iexcode/instruments/__pycache__/__init__.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/bakeout.cpython-37.pyc b/iexcode/instruments/__pycache__/bakeout.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ed7fa33afb66085ab5615af80990bfae05fdd2fe
Binary files /dev/null and b/iexcode/instruments/__pycache__/bakeout.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/beamline.cpython-37.pyc b/iexcode/instruments/__pycache__/beamline.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..bb16662015007d4b73929f7a716b9331a54537d8
Binary files /dev/null and b/iexcode/instruments/__pycache__/beamline.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/cameras.cpython-37.pyc b/iexcode/instruments/__pycache__/cameras.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..314916561858f01cd5b932833b4edd3f4acfa988
Binary files /dev/null and b/iexcode/instruments/__pycache__/cameras.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/conversions_constants.cpython-37.pyc b/iexcode/instruments/__pycache__/conversions_constants.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..2eaf10078a2d3ae7767b79bdbca730a979c03442
Binary files /dev/null and b/iexcode/instruments/__pycache__/conversions_constants.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/current_amplifiers.cpython-37.pyc b/iexcode/instruments/__pycache__/current_amplifiers.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..17f97f1549d6930c4f0d1af030b664f4227c3664
Binary files /dev/null and b/iexcode/instruments/__pycache__/current_amplifiers.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/diagnostics.cpython-37.pyc b/iexcode/instruments/__pycache__/diagnostics.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..bc05a7a8e2024e0b4a86b65d0f8a0ca36bdad5f6
Binary files /dev/null and b/iexcode/instruments/__pycache__/diagnostics.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/electron_analyzer.cpython-37.pyc b/iexcode/instruments/__pycache__/electron_analyzer.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..91ff70dc60fd8a66b8eb2c045939a252083917e3
Binary files /dev/null and b/iexcode/instruments/__pycache__/electron_analyzer.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/encoders.cpython-37.pyc b/iexcode/instruments/__pycache__/encoders.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3b073fe79b3370736b5f54c0b7df04e2a5372cc9
Binary files /dev/null and b/iexcode/instruments/__pycache__/encoders.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/files_and_folders.cpython-37.pyc b/iexcode/instruments/__pycache__/files_and_folders.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..d07f6e1e79cca22aff31195d4481cfe94d9ffbaa
Binary files /dev/null and b/iexcode/instruments/__pycache__/files_and_folders.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/gate_valves.cpython-37.pyc b/iexcode/instruments/__pycache__/gate_valves.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b226d256630f6017a49ca7160868608128964e54
Binary files /dev/null and b/iexcode/instruments/__pycache__/gate_valves.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/hxp_mirrors.cpython-37.pyc b/iexcode/instruments/__pycache__/hxp_mirrors.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..8747a50a2eed658297f8b7cb72d64d78f027bda7
Binary files /dev/null and b/iexcode/instruments/__pycache__/hxp_mirrors.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/logfile.cpython-37.pyc b/iexcode/instruments/__pycache__/logfile.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b49542070a25057382ecc6276ee31b7fe9f44a17
Binary files /dev/null and b/iexcode/instruments/__pycache__/logfile.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/m3r.cpython-37.pyc b/iexcode/instruments/__pycache__/m3r.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..bc9f6764e739a8d6050c03f89d8ed03dc58736b8
Binary files /dev/null and b/iexcode/instruments/__pycache__/m3r.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/mpa.cpython-37.pyc b/iexcode/instruments/__pycache__/mpa.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..706901ac024918e144fc9eece5186afcac389293
Binary files /dev/null and b/iexcode/instruments/__pycache__/mpa.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/remote_controlers.cpython-37.pyc b/iexcode/instruments/__pycache__/remote_controlers.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..6af0c322f5a4b610f11108737fbae1bc8057e3ec
Binary files /dev/null and b/iexcode/instruments/__pycache__/remote_controlers.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/resolution.cpython-37.pyc b/iexcode/instruments/__pycache__/resolution.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ff69f443a3bdb693d5a4a10a67e75ff819044f0a
Binary files /dev/null and b/iexcode/instruments/__pycache__/resolution.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/s29_temp_cntl.cpython-37.pyc b/iexcode/instruments/__pycache__/s29_temp_cntl.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..fb69f7e781be3eb592bbd3fe33c50cba8a604c99
Binary files /dev/null and b/iexcode/instruments/__pycache__/s29_temp_cntl.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/scalers.cpython-37.pyc b/iexcode/instruments/__pycache__/scalers.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..66dfe7809dd855ff40fe37bc83daf9b7275f17a3
Binary files /dev/null and b/iexcode/instruments/__pycache__/scalers.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/scanRecord.cpython-37.pyc b/iexcode/instruments/__pycache__/scanRecord.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4a2f063245c768dd7a2f4c18e550b51ae6fa01c5
Binary files /dev/null and b/iexcode/instruments/__pycache__/scanRecord.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/shutters.cpython-37.pyc b/iexcode/instruments/__pycache__/shutters.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..63ecf2bc4e4cee714175f614eaa967f2b1e6e58c
Binary files /dev/null and b/iexcode/instruments/__pycache__/shutters.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/slits.cpython-37.pyc b/iexcode/instruments/__pycache__/slits.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..1d3c0b6595d26512aaace68743436f4a86bc9707
Binary files /dev/null and b/iexcode/instruments/__pycache__/slits.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/spec_stuff.cpython-37.pyc b/iexcode/instruments/__pycache__/spec_stuff.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..233507689e4b15634113b3e21e2bbb3cc81c6e5a
Binary files /dev/null and b/iexcode/instruments/__pycache__/spec_stuff.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/staff.cpython-37.pyc b/iexcode/instruments/__pycache__/staff.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c323fc27e5c18ca6a135a8417e28121eee33a507
Binary files /dev/null and b/iexcode/instruments/__pycache__/staff.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/storage_ring.cpython-37.pyc b/iexcode/instruments/__pycache__/storage_ring.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..efa0198e6e77c11ece2df7d1e27b632650dc0c14
Binary files /dev/null and b/iexcode/instruments/__pycache__/storage_ring.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/userCalcs.cpython-37.pyc b/iexcode/instruments/__pycache__/userCalcs.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..580ff6a9df83ae20d6aa1f0833e6156dee94d33f
Binary files /dev/null and b/iexcode/instruments/__pycache__/userCalcs.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/utilities.cpython-37.pyc b/iexcode/instruments/__pycache__/utilities.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..5d801bc7a5477c18181ad534cbc761ccf908fe29
Binary files /dev/null and b/iexcode/instruments/__pycache__/utilities.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/vortexs29.cpython-37.pyc b/iexcode/instruments/__pycache__/vortexs29.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ac73f08f263bedd80815a13b5b4a6dae8cf422fb
Binary files /dev/null and b/iexcode/instruments/__pycache__/vortexs29.cpython-37.pyc differ
diff --git a/iexcode/instruments/__pycache__/xrays.cpython-37.pyc b/iexcode/instruments/__pycache__/xrays.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..6d7ea418488f9414d9abefdb6532e7066cd55956
Binary files /dev/null and b/iexcode/instruments/__pycache__/xrays.cpython-37.pyc differ
diff --git a/iexcode/instruments/backups.py b/iexcode/instruments/backups.py
deleted file mode 100644
index 05d3c3aa0baf555372cbc61939de622a85ec0e5a..0000000000000000000000000000000000000000
--- a/iexcode/instruments/backups.py
+++ /dev/null
@@ -1,339 +0,0 @@
-def ARPES_scan_before_sequence(**kwargs):
-    """
-    writes the user string sequence to happen at the beginning of a scan
-    returns before_scan_pv = pv for userStringSeq for before scan
-
-    **kwargs
-        seq_num: userStringSeq number in ioc => 9 (default)
-
-    Previously: BeforeScan_StrSeq
-    """
-    kwargs.setdefault(seq_num,9)
-    seq_num=kwargs['seq_num']
-
-    before_scan_pv,before_scan_proc = userStringSeq_pvs(BL.ioc, seq_num)
-
-    #clear and write the before scan user sequence
-    userStringSeq_clear(BL.ioc,seq_num)
-    caput(before_scan_pv+".DESC","Before Scan")
-
-    #sequence put CAs in passive
-    ca_list = ARPES_detector_list()
-    for (i,ca) in enumerate(ca_list):
-        ca_pv = Keithley_pv(ca[0], ca[1])+':read.SCAN PP NMS'
-        caput(before_scan_pv+".LNK" +str(i+1),ca_pv)
-        caput(before_scan_pv+".STR" +str(i+1),"Passive")
-
-    return before_scan_proc
-
-
-def ARPES_after_scan_clear_sequence(**kwargs):
-    """
-    writes the user string sequence to clean up after a scan
-    returns clear_scan_pv = pv for userStringSeq for before scan
-
-    **kwargs
-        ioc: ioc where the string sequence lives => ARPES_ioc (default)
-        seq_num: userStringSeq number in ioc => 6 (default)
-    
-    Previously: ARPES_Scan_Clear_StringSeq
-    """
-
-    kwargs.setdefault(seq_num,6)
-    seq_num=kwargs['seq_num']
-    
-    
-    #clear the userStringSeq
-    userStringSeq_clear(BL.ioc,seq_num=kwargs['seq_num'])
-
-    clear_scan_userStringSeq = BL.ioc+"userStringSeq"+str(seq_num)
-
-    caput(clear_scan_userStringSeq+".DESC","ARPES_Scan_Clear")
-    caput(clear_scan_userStringSeq+".LNK1",BL.ioc+"scan1.T2PV PP")
-    caput(clear_scan_userStringSeq+".STR1","")
-
-    ca_live_sequence_pv = ARPES_ca_live_sequence(**kwargs)
-    caput(clear_scan_userStringSeq+".LNK2",ca_live_sequence_pv+" PP")
-
-    caput(clear_scan_userStringSeq+".STR2","1")
-    caput(clear_scan_userStringSeq+".LNK3",BL.ioc+"scan1.CMND PP")
-    caput(clear_scan_userStringSeq+".STR3","6")
-    caput(clear_scan_userStringSeq+".LNK4",BL.ioc+"scan2.CMND PP")
-    caput(clear_scan_userStringSeq+".STR4","6")
-    caput(clear_scan_userStringSeq+".LNK5",BL.ioc+"scan3.CMND PP")
-    caput(clear_scan_userStringSeq+".STR5","6")
-    caput(clear_scan_userStringSeq+".LNK6",BL.ioc+"scan4.CMND PP")
-    caput(clear_scan_userStringSeq+".STR6","6")
-
-    clear_scan_userStringSeq_pv = clear_scan_userStringSeq+".PROC"
-    return clear_scan_userStringSeq_pv
-
-    from IEX_beamline.IEX_beamline.instruments.IEX_VPU import ID_SP
-
-def scan2D(InnerMotorList,OuterMotorList,mode="absolute",settling_time=0.1,**kwargs):
-    """ Scans two motors.using the motor name (e.g. x,y,z,th).
-        InnerMotorList=[name1,start1,stop1,step1](x in the plot)
-        OuterMotorList=[name2,start2,stop2,step2](y in the plot)
-        name = 'x'/'y'/'z'/'th'...  
-    Logging is automatic: use **kwargs or the optional logging arguments see scanlog() for details      
-        """
-    mybranch=CheckBranch()
-    if mybranch == "c":
-        Scan_ARPES_2D_Go(InnerMotorList,OuterMotorList,**kwargs)
-    elif mybranch == "d":
-        Scan_Kappa_2D_Go(InnerMotorList,OuterMotorList,**kwargs)
-    else:
-        print("Not yet implemented")
-
-def scan3D(list1,list2,list3,mode="absolute",settling_time=0.1,**kwargs):
-    """ Scans two motors.using the motor name (e.g. x,y,z,th).
-        listn=[name,start,stop,step]
-        list1 is for the inner loop -> fast (x in the plot)
-        list2 is for the middle loop -> slow (y in the plot)
-        list3 is for the outer loop -> slow (y in the plot)
-        """
-    scanIOC=BL_ioc()
-    mybranch=CheckBranch()
-    if mybranch == "c":
-        m1_RBV=ARPES_PVmotor(list1[0])[0]
-        m1_VAL=ARPES_PVmotor(list1[0])[1]
-        m2_RBV=ARPES_PVmotor(list2[0])[0]
-        m2_VAL=ARPES_PVmotor(list2[0])[1]
-        m3_RBV=ARPES_PVmotor(list3[0])[0]
-        m3_VAL=ARPES_PVmotor(list3[0])[1]
-    elif mybranch == "d":
-        m1_RBV=Kappa_PVmotor(list1[0])[0]
-        m1_VAL=Kappa_PVmotor(list1[0])[1]
-        m2_RBV=Kappa_PVmotor(list2[0])[0]
-        m2_VAL=Kappa_PVmotor(list2[0])[1]
-        m3_RBV=Kappa_PVmotor(list3[0])[0]
-        m3_VAL=Kappa_PVmotor(list3[0])[1]
-    else:
-        print("Not yet implemented")
-    if mode == "relative":
-        current_value1=caget(m1_RBV)
-        abs_start1=round(current_value1+list1[1],3)
-        abs_stop1 =round(current_value1+list1[2],3)
-        current_value2=caget(m2_RBV)
-        abs_start2=round(current_value2+list2[1],3)
-        abs_stop2 =round(current_value2+list2[2],3)
-        current_value3=caget(m3_RBV)
-        abs_start3=round(current_value3+list3[1],3)
-        abs_stop3 =round(current_value3+list3[2],3)
-    else:
-        abs_start1=list1[1]
-        abs_stop1 =list1[2]
-        abs_start2=list2[1]
-        abs_stop2 =list2[2]
-        abs_start3=list3[1]
-        abs_stop3 =list3[2]
-    step1=list1[3]
-    step2=list2[3]
-    step3=list3[3]
-    Scan_FillIn(m1_VAL, m1_RBV, scanIOC, 1, abs_start1, abs_stop1, step1, point=None)
-    Scan_FillIn(m2_VAL, m2_RBV, scanIOC, 2, abs_start2, abs_stop2, step2, point=None)
-    Scan_FillIn(m3_VAL, m3_RBV, scanIOC, 3, abs_start3, abs_stop3, step3, point=None)
-
-    Scan_Go(scanIOC,scanDIM=3,**kwargs)
-
-  
-
-
-
-##############################################################################################################
-##############################              Move Sample        ##############################
-##############################################################################################################
-
-
-def Print_Motor():
-    mybranch=CheckBranch()
-    if mybranch == "c":
-        x=round(caget(ARPES_PVmotor('x')[0]),2)
-        y=round(caget(ARPES_PVmotor('y')[0]),2)
-        z=round(caget(ARPES_PVmotor('z')[0]),2)
-        th=round(caget(ARPES_PVmotor('th')[0]),2)
-        chi=round(caget(ARPES_PVmotor('chi')[0]),2)
-        phi=round(caget(ARPES_PVmotor('phi')[0]),2)
-        return [x,y,z,th,chi,phi]
-    #    print "x="+str(x), " y="+str(y)," z="+str(z), " theta="+str(th)
-        print("\nx,y,z,th = ["+str(x)+","+str(y)+","+str(z)+","+str(th)+","+str(chi)+","+str(phi)+"]")
-    elif mybranch == "d":
-        x=round(caget("29idKappa:m2.RBV"),0)
-        y=round(caget("29idKappa:m3.RBV"),0)
-        z=round(caget("29idKappa:m4.RBV"),0)
-        tth= round(caget("29idKappa:m9.RBV"),2)
-        kth= round(caget("29idKappa:m8.RBV"),2)
-        kap= round(caget("29idKappa:m7.RBV"),2)
-        kphi=round(caget("29idKappa:m1.RBV"),2)
-        th= round(caget("29idKappa:Euler_ThetaRBV"),3)
-        chi= round(caget("29idKappa:Euler_ChiRBV"),3)
-        phi=round(caget("29idKappa:Euler_PhiRBV"),3)
-        #(th,chi,phi)=KtoE(kth,kap,kphi)
-        print("\nx,y,z,tth,th,chi,phi   = ["+str(x)+","+str(y)+","+str(z)+","+str(tth)+","+str(th)+","+str(chi)+","+str(phi)+"]")
-        print("x,y,z,tth,kth,kap,kphi = ["+str(x)+","+str(y)+","+str(z)+","+str(tth)+","+str(kth)+","+str(kap)+","+str(kphi)+"]")
-        #print "\ntth,th,chi,phi = ["+str(round(tth,1))+","+str(round(th,1))+","+str((round(chi,1)))+","+str((round(phi,1)))+"]"
-        pos=[x,y,z,tth,kth,kap,kphi]
-        return pos
-    #elif mybranch == "e":
-    #    print(Get_mRSoXS()[1])
-
-
-
-
-
-def Move_Kappa_Sample(ListPosition):
-    """ListPosition = ["Sample Name", x, y, z, tth, kth, kap, kphi]
-    keeps tth fixes
-     """
-    if not isinstance(ListPosition[0],str):
-        ListPosition.insert(0,"")
-    #tth=round(caget("29idHydra:m1.RBV"),2)
-    name,x,y,z,tth,kth,kap,kphi=ListPosition
-    print("\nx="+str(x), " y="+str(y)," z="+str(z), " tth="+str(tth), " kth="+str(kth), " kap="+str(kap), " kphi="+str(kphi),"\n")
-    caput("29idKappa:m2.VAL",x,wait=True,timeout=18000)
-    caput("29idKappa:m3.VAL",y,wait=True,timeout=18000)
-    caput("29idKappa:m4.VAL",z,wait=True,timeout=18000)
-    caput("29idKappa:m8.VAL",kth,wait=True,timeout=18000)
-    caput("29idKappa:m7.VAL",kap,wait=True,timeout=18000)
-    caput("29idKappa:m1.VAL",kphi,wait=True,timeout=18000)
-    print("Sample now @:",name)
-    
-cts: integration time for scalers and mpa/mcp => 0.1 (default) 
-kwargs.setdefault('cts',0.1)
-Kappa_cts(kwargs['cts'],verbose=False)
-
-kwargs:
-        mode: "absolute" (default) / "relative"
-        scan_dim: 1  (default)
-        cts: integration time for scalers and mpa/mcp => 0.1 (default) 
-
-    kwargs.setdefault('mode',"absolute")
-    kwargs.setdefault('scan_dim',1)
-    kwargs.setdefault('cts',0.1)
-    scan_dim = kwargs['scan_dim']
-    
-    if kwargs['mode'] == "relative":
-
-
-
-kwargs.setdefault('run',True)
-
-if kwarg['run']:
-        BL.mda.go(kwargs['scan_dim'])
-
-run: True/False to start the scan => True (default)
-
-
-
-
-    kth_val,kth_rbv,kth_spmg,kth_pv = motor_dictionary['kth']
-    tth_val,tth_rbv,tth_spmg,tth_pv = motor_dictionary['tth']
-
-
-    kwargs.update("positioner_num",1)
-    BL.mda.fillin_table(scan_dim,kth_val,kth_rbv,kth_table,**kwargs)
-
-    kwargs.update("positioner_num",2)
-    BL.mda.fillin_table(scan_dim,tth_val,tth_rbv,tth_table,**kwargs)
-
-    tthdet
-
-
-
-def scan_reset(scan_dim=1,**kwargs):
-    """
-    kwargs:
-        scaler='y', for Kappa IOC only, ARPES ignors this keyword
-        detTrig=2, for ARPES/Kappa IOC, used to clear SES/MPA trigger
-    
-    Previously:  Reset_Scan  
-    """
-    print("\nResetting "+BL.ioc)
-
-    #Clear Scan Settings
-    for dim in range(1,5):
-        scanRecord.clear_reset(BL.ioc,dim,verbose=True)    
-    
-    #Setting Detectors
-    detector_dictionary = ARPES_detector_list()
-    scanRecord.detectors_set(BL.ioc,scan_dim,detector_dictionary)
-    ARPES_detectors=ARPES_detector_dictionary()
-    if BL.xrays:
-        ARPES_detectors.update(xray_detector_dictionary())
-    scanRecord.detectors_set(BL.ioc,scan_dim,ARPES_detectors)
-    
-    #Set the Detector Triggers
-  
-        
-    if scanIOC == 'Kappa':
-        caput('29idKappa:UBmatrix',[0,0,0,0,0,0,0,0,0])
-        caput('29idKappa:UBsample','')
-        caput('29idKappa:UBlattice',[0,0,0,0,0,0])
-        caput('29idKappa:UBenergy',0)
-        caput('29idKappa:UBlambda',0)
-        caput(pv+".T1PV",'')
-        caput(pv+".T2PV",'')
-        caput(pv+".T3PV",'')
-        caput(pv+".T4PV",'')
-        caput("29id"+scanIOC+":scan1.CMND",7)
-        caput("29id"+scanIOC+":scan2.CMND",7)
-        caput("29id"+scanIOC+":scan3.CMND",7)
-        caput("29id"+scanIOC+":scan4.CMND",7)             
-        if scaler == 'y':
-            caput(pv+".T1PV",'29idMZ0:scaler1.CNT')
-            caput('29idMZ0:scaler1.TP',0.1)        
-            print('Kappa scalers are triggered. Counting time set to 0.1s')
-            #Reset_CA_all(); Reset_MonoMPA_ROI_Trigger()
-        else:
-            caput(pv+".T1PV",Detector_Triggers_StrSeq(scanIOC))
-            print('Kappa scalers are NOT triggered. Triggering StrSeq Kappa #8 instead (empty, to be filled).')
-            #print("\nDetector triggered:", Detector_List(scanIOC))
-#     if scanIOC=='Kappa' and scaler is not None:
-#         print('\nDo you want to use the scalers as detector trigger? (Note to self: to be modified  (FR))>')
-#         foo = input()
-#         if foo in ['yes','y','Y','YES']:
-#             caput(pv+".T1PV",'29idMZ0:scaler1.CNT')
-#             caput('29idMZ0:scaler1.TP',0.1)
-#             print('Scalers added as trigger 2')
-#             print('Counting time set to 0.1s')
-#     else:
-#         print('\nScalers not triggered. To trigger use: \n\n       Reset_Scan(\'Kappa\',scaler=\'y\')')
-    caput(pv+".BSPV",BeforeScan_StrSeq(scanIOC))
-    caput(pv+".ASPV",AfterScan_StrSeq(scanIOC,scanDIM))
-    caput(pv+".BSCD",1)
-    caput(pv+".BSWAIT","Wait")
-    caput(pv+".ASCD",1)
-    caput(pv+".ASWAIT","Wait")
-    #SaveData
-    caput("29id"+scanIOC+":saveData_realTime1D",1)
-    #Check that detector and positioner PVs are good
-    sleep(10)
-    Scan_Check(scanIOC,scanDIM)
-##############################################################################################################
-##############################               ARPES & Kappa scan            ##############################
-##############################################################################################################
-
-def scanMesh(InnerMotorList,OuterMotorList,**kwargs):
-    """
-        InnerMotorList=[startH,stopH,stepH](x in the plot)
-        OuterMotorList=[startV,stopV,stepV](y in the plot)
-    
-    Raster/maps the sample with outer/inner loop being the vertical/horizontal direction:
-        - yz scan for ARPES
-        - yx scan for Kappa (sample is assumed to be normal to the beam i.e kth/ksap/kphi = 147/134.7/57)
-    
-    **kwargs defaults
-        mode='Absolute'
-        settling_time=0.1,
-        scanIOC=BL_ioc
-        Snake; coming soon
-    """
-    branch = BL.branch
-    startH,stopH,stepH=InnerMotorList
-    startV,stopV,stepV=OuterMotorList
-    if branch == "c":
-        ARPES_scan_2D(["y",startH,stopH,stepH],["z",startV,stopV,stepV],**kwargs)
-    elif branch == "d":
-        Kappa_scan_2D(["y",startH,stopH,stepH],["x",startV,stopV,stepV],**kwargs)
-    else:
-        print("Not yet implemented")
\ No newline at end of file
diff --git a/iexcode/instruments/bakeout.py b/iexcode/instruments/bakeout.py
index 979393cd2c9225aaed88070ec53faeab737a9896..94dfd1a00e1173fabb280bf94cd6090258599878 100644
--- a/iexcode/instruments/bakeout.py
+++ b/iexcode/instruments/bakeout.py
@@ -4,8 +4,8 @@ from os.path import exists
 
 from epics import caget,caput
 
-from .files_and_folders import get_next_fileNumber, check_run
-from .scanRecord import *
+from iexcode.instruments.files_and_folders import get_next_fileNumber, check_run
+from iexcode.instruments.scanRecord import *
 
 ##############################################################################################################
 ##############################             Scan Bakeout            ##############################
diff --git a/iexcode/instruments/beamline.py b/iexcode/instruments/beamline.py
index c4d045ac683cff917e1cce371f88e4216b6463b5..6817162fdad3533041139170c96a0fa810e51958 100644
--- a/iexcode/instruments/beamline.py
+++ b/iexcode/instruments/beamline.py
@@ -8,14 +8,7 @@ import numpy as np
 from time import sleep
 
 from epics import PV
-from .IEX_endstations import *
-#from .logfile import *
-#from .ARPES import ARPES_log_entries
-#from .Kappa import Kappa_log_entries
-#from .IEX_VPU import *
-#from .VLS_PGM import *
-#from .slits import *
-#from .m3r import *
+from iexcode.instruments.IEX_endstations import *
 
 
 ##############################################################################################################
diff --git a/iexcode/instruments/cameras.py b/iexcode/instruments/cameras.py
index 56ac0ceca7b67ad16356c8d3cb7b08c439e27def..1436d9b1a71c4892faa97870f1835e1003bc1bd9 100644
--- a/iexcode/instruments/cameras.py
+++ b/iexcode/instruments/cameras.py
@@ -1,9 +1,9 @@
 
 from epics import caget, caput
 
-from .userCalcs import userStringSeq_clear
-from .AD_utilites import *
-from .IEX_endstations import *
+from iexcode.instruments.userCalcs import userStringSeq_clear
+from iexcode.instruments.AD_utilities import *
+from iexcode.instruments.IEX_endstations import *
 
 
 def cam_pv_dictionary(cam_num):
diff --git a/iexcode/instruments/current_amplifiers.py b/iexcode/instruments/current_amplifiers.py
index 6a72551a16e7f25a5faa4041738fcbe17a10da74..5df2d30e8f19252ea87e2abba7c42b3f4427c3a1 100644
--- a/iexcode/instruments/current_amplifiers.py
+++ b/iexcode/instruments/current_amplifiers.py
@@ -2,8 +2,8 @@ import numpy as np
 from time import sleep
 
 from epics import caget, caput
-from .userCalcs import userStringSeq_pvs, userStringSeq_clear
-from .VLS_PGM import mono_energy_get
+from iexcode.instruments.userCalcs import userStringSeq_pvs, userStringSeq_clear
+from iexcode.instruments.VLS_PGM import mono_energy_get
 
 
 def ca_detector_list(branch):
diff --git a/iexcode/instruments/diagnostics.py b/iexcode/instruments/diagnostics.py
index d22bca803ed3c14414eecf05389ff3dccdc026ae..50814ae88854f644fb99cd2b62123794f6428fac 100644
--- a/iexcode/instruments/diagnostics.py
+++ b/iexcode/instruments/diagnostics.py
@@ -1,7 +1,7 @@
 from numpy import nan
 
 from epics import caput, caget
-from IEX_endstations import *
+from iexcode.instruments.IEX_endstations import *
 
 ##############################################################################################################
 ################################            default positions             ##############################
diff --git a/iexcode/instruments/electron_analyzer.py b/iexcode/instruments/electron_analyzer.py
index 4427551dd4ada4e365e7d77052ff1e5b5919c554..8cfbb778c92dd9ce36f68ab6a062d44c5b9814af 100644
--- a/iexcode/instruments/electron_analyzer.py
+++ b/iexcode/instruments/electron_analyzer.py
@@ -13,17 +13,17 @@ import numpy as np
 from scipy.interpolate import interp1d
 
 from epics import caput,caget
-from .IEX_endstations import *
-
-from .scanRecord import *
-from .conversions_constants import *
-from .xrays import energy, scanXAS_BL, BL_energy_tables
-from .shutters import branch_shutter_close
-from .VLS_PGM import mono_energy_get
-from .files_and_folders import get_next_fileNumber
-from .logfile import *
-from .ARPES import ARPES_motor_dictionary, ARPES_motor_scan, ARPES_mvsample,ARPES_scan_2D
-from .Scienta import *
+from iexcode.instruments.IEX_endstations import *
+
+from iexcode.instruments.scanRecord import *
+from iexcode.instruments.conversions_constants import *
+from iexcode.instruments.xrays import energy, scanXAS_BL, BL_energy_tables
+from iexcode.instruments.shutters import branch_shutter_close
+from iexcode.instruments.VLS_PGM import mono_energy_get
+from iexcode.instruments.files_and_folders import get_next_fileNumber
+from iexcode.instruments.logfile import *
+from iexcode.instruments.ARPES import ARPES_motor_dictionary, ARPES_motor_scan, ARPES_mvsample,ARPES_scan_2D
+from iexcode.instruments.Scienta import *
 
 def __main__():
     global EA
diff --git a/iexcode/instruments/encoders.py b/iexcode/instruments/encoders.py
index e45ab7f7e1b56991740af37e3e0dd33c1d1086f4..ef7cb08aceb1e1e7a0ec92ecf5915498cdf357bf 100644
--- a/iexcode/instruments/encoders.py
+++ b/iexcode/instruments/encoders.py
@@ -9,7 +9,7 @@ def encoder_dictionary_entry(name):
     d={
         'slit2B':("29idMini1:",[13,14,15,16]),
         'slit3D':("29idMini2:",[26,27]),
-        'ARPES':("ARPES:"),[1,2,3,4])
+        'ARPES':("ARPES:",[1,2,3,4]),
     }
     return d[name]
 
diff --git a/iexcode/instruments/files_and_folders.py b/iexcode/instruments/files_and_folders.py
index 6f1e48d1b6e5a4f5b4d379c4123bb719c44ddaab..9710c1bd6907b1f7340147aad3a073d28daf1c82 100644
--- a/iexcode/instruments/files_and_folders.py
+++ b/iexcode/instruments/files_and_folders.py
@@ -1,26 +1,3 @@
-"""
-Utilities to set beamline folders
-
-# to caget path:  caget("29idc:saveData_fileSystem",as_string=True)
-
-# Data folder structure:
-#
-#   STAFF:    data_29idb  / 2017_2 / mda
-##                                   h5
-#                                   mpa
-#                                   g5
-#                                   SES
-#                                   tif
-#                                   mpa
-#
-#   USERS (C):   data_29idc / 2017_2 / user_name / mda
-#                                                 h5
-#                                                 
-#
-#   USERS (D):   data_29idd / 2017_2 / user_name / mda
-#     
-
-"""
 from os import listdir,mkdir,chmod
 from os.path import join, isfile, exists
 import datetime
@@ -29,9 +6,6 @@ import re
 
 from epics import caget, caput
 
-from .utilities import dateandtime
-from .ARPES import folders_ARPES
-from .Kappa import folders_Kappa
 
 ##############################################################################################################
 ################################             Standard Paths              ##############################
@@ -51,35 +25,7 @@ def path_dserv(folder,run,user_name):
     dataFolder='/net/s29data/export/data_29id'+folder+'/'+run+'/'+user_name
     return dataFolder
 
-def folders_startup(run):
-    """
-    Creates the run directories for the following:
-    data_29idb
-    data_29idc
-    data_29idd
-
-    calls folder_ARPES('Staff');folder_Kappa('Staff')
 
-    print text required to modify the rsynch crontab
-
-    previously: Folders_Startup
-    """
-    data_directories=['data_29idb','data_29idc','data_29idd']
-    dserv="/net/s29data/export/"
-    for dataDir in data_directories:
-        path=join(dserv,dataDir,run)
-        print(path)
-        if not (exists(path)):
-            mkdir(path)
-
-    folders_ARPES('Staff',create_only=True)
-    folders_Kappa('Staff',create_only=True)
-
-    txt="\n\n\nupdate the rsync portion the 29id@nerdy crontab\n"
-    txt+="*/1 * * * * /usr/bin/rsync -av --exclude=core /net/s29data/export/data_29idd/"+run+" kip:/net/kip/sftp/pub/29iddftp/files >  /home/beams22/29ID/cronfiles/cptoftp-currrun-d.log 2>&1"
-    txt+=("\n")
-    txt+="*/1 * * * * /usr/bin/rsync -av --exclude=core /net/s29data/export/data_29idd/"+run+" kip:/net/kip/sftp/pub/29iddftp/files >  /home/beams22/29ID/cronfiles/cptoftp-currrun-d.log 2>&1"
-    print(txt)
 
 
 
diff --git a/iexcode/instruments/hxp_mirrors.py b/iexcode/instruments/hxp_mirrors.py
index a757fc55ae0c44a5e3cb7ac79ea4995cdd1aa20b..0eb90509f2784ff042fbcb4ef78235ec102d02fd 100644
--- a/iexcode/instruments/hxp_mirrors.py
+++ b/iexcode/instruments/hxp_mirrors.py
@@ -1,7 +1,7 @@
 from re import M
 from epics import caput, caget
-from utilities import print_warning_message
-from m3r import m3r_branch
+from iexcode.instruments.utilities import print_warning_message
+from iexcode.instruments.m3r import m3r_branch
 
 def hxp_ioc(mirror_name):
     """
diff --git a/iexcode/instruments/logfile.py b/iexcode/instruments/logfile.py
index 2f158f66e1d8aa14426121604666d0448bfcbc7c..dec2ce2547f2096f5ebeda2597e496a1723b44d4 100644
--- a/iexcode/instruments/logfile.py
+++ b/iexcode/instruments/logfile.py
@@ -1,10 +1,10 @@
-from os.path import join,open,isfile
+from os.path import join,isfile
 
 from epics import caget, caput
-from .IEX_endstations import *
-from .utilities import today
-from .ARPES import ARPES_log_entries
-from .Kappa import Kappa_log_entries
+from iexcode.instruments.IEX_endstations import *
+from iexcode.instruments.utilities import today
+from iexcode.instruments.ARPES import ARPES_log_entries
+from iexcode.instruments.Kappa import Kappa_log_entries
 
 
 ##############################################################################################################
diff --git a/iexcode/instruments/m3r.py b/iexcode/instruments/m3r.py
index 903ed76680384b85c7073612c5d2a61d783cf6d8..54bb5ec77693a6857ce71dd5b87d6b4aeffd3386 100644
--- a/iexcode/instruments/m3r.py
+++ b/iexcode/instruments/m3r.py
@@ -2,8 +2,8 @@ from cgi import print_arguments
 
 from epics import caget, caput
 
-from .utilities import print_warning_message
-from .FMB_mirrors import *
+from iexcode.instruments.utilities import print_warning_message
+from iexcode.instruments.FMB_mirrors import *
 
 ##############################################################################################################
 ################################             M3R             ##############################
diff --git a/iexcode/instruments/mpa.py b/iexcode/instruments/mpa.py
index f941431c5f1d437bcc0a65e60ee471d32bde1784..6408b462eb1ab840d591207d7a6d0ec37d3794d7 100644
--- a/iexcode/instruments/mpa.py
+++ b/iexcode/instruments/mpa.py
@@ -3,11 +3,11 @@ from os.path import dirname, join
 import socket
 
 from epics import caget, caput
-from .userCalcs import userCalcOut_clear,userStringSeq_clear
-from .Kappa import Kappa_motor_dictionary,Kappa_cts, mda
-from .AD_utilites import AD_ROI_setup
-from .scalers import scaler_cts
-from scanRecord import *
+from iexcode.instruments.userCalcs import userCalcOut_clear,userStringSeq_clear
+from iexcode.instruments.Kappa import Kappa_motor_dictionary,Kappa_cts, mda
+from iexcode.instruments.AD_utilities import AD_ROI_setup
+from iexcode.instruments.scalers import scaler_cts
+from iexcode.instruments.scanRecord import *
 
 
 """
diff --git a/iexcode/instruments/resolution.py b/iexcode/instruments/resolution.py
index 9b2e864b5c4a7697ee1f8d5d05da3a8a13991efd..a34f8919c7df6eca028e3216ec5b13e3d5973da2 100644
--- a/iexcode/instruments/resolution.py
+++ b/iexcode/instruments/resolution.py
@@ -1,6 +1,6 @@
 import numpy as np
 
-from electron_analyzer import resolution_EA
+from iexcode.instruments.electron_analyzer import resolution_EA
 #############################################################################################################
 ##############################             Resolution              ##############################
 #############################################################################################################
diff --git a/iexcode/instruments/scalers.py b/iexcode/instruments/scalers.py
index 33da16e9605f0975a140f87140b866febd837e78..89be3dbabd0b813aa88d6e5088354e5aa049ee33 100644
--- a/iexcode/instruments/scalers.py
+++ b/iexcode/instruments/scalers.py
@@ -2,7 +2,7 @@ from math import floor
 
 from epics import caput,PV
 
-from .IEX_endstations import BL
+from iexcode.instruments.IEX_endstations import BL
 
 def scaler_cts(time_seconds=0.1,verbose=True):
     """
diff --git a/iexcode/instruments/scanRecord.py b/iexcode/instruments/scanRecord.py
index c2719c45e49a4d414620130d64f5be5ee89a28fe..2e01a97a40feb0cabc45a2affce438fa7ef800d9 100644
--- a/iexcode/instruments/scanRecord.py
+++ b/iexcode/instruments/scanRecord.py
@@ -4,9 +4,9 @@ import time
 
 from epics import caget, caput, PV
 
-from .utilities import dateandtime, print_warning_message
-from .logfile import log_update
-from .userCalcs import userStringSeq_pvs,userStringSeq_clear
+from iexcode.instruments.utilities import dateandtime, print_warning_message
+from iexcode.instruments.logfile import log_update
+from iexcode.instruments.userCalcs import userStringSeq_pvs,userStringSeq_clear
 
 
 def saveData_get_all(ioc_pv):
diff --git a/iexcode/instruments/scratch.py b/iexcode/instruments/scratch.py
new file mode 100644
index 0000000000000000000000000000000000000000..ded5e799532a9f085e7e81f233ff0d2a7e4267a8
--- /dev/null
+++ b/iexcode/instruments/scratch.py
@@ -0,0 +1,44 @@
+##############################################################################################################
+##############################                 setting folder          from ARPES         ##############################
+##############################################################################################################
+def folders_ARPES(user_name,**kwargs):
+    """
+    Create and sets (if create_only=False) all the folders the current run and ARPES user 
+    Sets the FileName for logging to be "UserName/YYYYMMDD_log.txt using logname_Set()"
+    
+    **kwargs:
+        set_folders = True (default); set the mda and EA scanRecords
+                    = False; only makes the folders (was create_only)
+        run: run cycle e.g. 2022_1 (default => check_run() )
+        ftp = True / False (default); print what needs to be added to the ftps crontab and create additional ftp folders
+        mda_ioc: will overwrite the default ioc for mda scans
+        debug
+           
+    """
+    kwargs.setdefault('set_folders',True)
+    kwargs.setdefault('run',check_run())
+    kwargs.setdefault('ftp',False)
+    kwargs.setdefault('debug',False)
+
+    run = kwargs['run']
+
+    if kwargs['debug']:
+        print("run,folder,user_name,ioc,ftp: ",run,BL.folder,user_name,BL.ioc,kwargs['ftp'])
+
+    # Create User Folder:
+    make_user_folders(run,BL.folder,user_name,BL.endstation,ftp=kwargs['ftp'])
+    sleep(5)
+
+    if kwargs["set_folders"]:
+        # Set up MDA folder:
+        folder_mda(run,BL.folder,user_name,BL.prefix,BL.ioc)
+        logfile_name_set(BL.endstation)
+        logfile_header(BL.endstation,BL.ioc,ARPES_log_header())
+
+        
+        #Set up Scienta folders:
+        try:
+            userPath = "/net/s29data/export/data_29id"+BL.folder+"/"+run+"/"+user_name+"/"
+            folders_EA(userPath,filePrefix="EA")
+        except:
+            print_warning_message("EA ioc is not running, cannot set folder")
\ No newline at end of file
diff --git a/iexcode/instruments/shutters.py b/iexcode/instruments/shutters.py
index 909009f0acbf272454b93353d567dc75801ab7fa..2afd8422a141b6b3b7b8467d8a6ef7b50ecc94e7 100644
--- a/iexcode/instruments/shutters.py
+++ b/iexcode/instruments/shutters.py
@@ -4,7 +4,7 @@ main shutter and branch shutter functions
 from time import sleep
 from epics import caget, caput
 
-from .utilities import dateandtime, print_warning_message
+from iexcode.instruments.utilities import dateandtime, print_warning_message
 
 
 ##############################################################################################################
diff --git a/iexcode/instruments/slits.py b/iexcode/instruments/slits.py
index 5a1ead3b31292e05bb4de2e8f775ef7b106d41ec..1b323e3ead9d82e35929bd013f277f8cfc7b3bd3 100644
--- a/iexcode/instruments/slits.py
+++ b/iexcode/instruments/slits.py
@@ -4,10 +4,10 @@ from epics import caget, caput
 from .IEX_endstations import *
 
 
-from .shutters import main_shutter_close
-from .utilities import print_warning_message, read_dict
-from .VLS_PGM import mono_get_all
-from .encoders import encoders_reset
+from iexcode.instruments.shutters import main_shutter_close
+from iexcode.instruments.utilities import print_warning_message, read_dict
+from iexcode.instruments.VLS_PGM import mono_get_all
+from iexcode.instruments.encoders import encoders_reset
 
 slit_ioc="29idb:"
 
diff --git a/iexcode/instruments/staff.py b/iexcode/instruments/staff.py
index 8ff6206d5d3e2609f6398ca0b24b73f169f56527..b9d6eef6b0732753a2c5c190dd1903e2f2d2652c 100644
--- a/iexcode/instruments/staff.py
+++ b/iexcode/instruments/staff.py
@@ -1,3 +1,39 @@
+from os import listdir,mkdir,chmod
+from os.path import join, isfile, exists
+
+#from .ARPES import folders_ARPES
+#from .Kappa import folders_Kappa
+
+
+def folders_startup(run):
+    """
+    Creates the run directories for the following:
+    data_29idb
+    data_29idc
+    data_29idd
+
+    calls folder_ARPES('Staff');folder_Kappa('Staff')
+
+    print text required to modify the rsynch crontab
+
+    previously: Folders_Startup
+    """
+    data_directories=['data_29idb','data_29idc','data_29idd']
+    dserv="/net/s29data/export/"
+    for dataDir in data_directories:
+        path=join(dserv,dataDir,run)
+        print(path)
+        if not (exists(path)):
+            mkdir(path)
+
+    #folders_ARPES('Staff',create_only=True)
+    #folders_Kappa('Staff',create_only=True)
+
+    txt="\n\n\nupdate the rsync portion the 29id@nerdy crontab\n"
+    txt+="*/1 * * * * /usr/bin/rsync -av --exclude=core /net/s29data/export/data_29idd/"+run+" kip:/net/kip/sftp/pub/29iddftp/files >  /home/beams22/29ID/cronfiles/cptoftp-currrun-d.log 2>&1"
+    txt+=("\n")
+    txt+="*/1 * * * * /usr/bin/rsync -av --exclude=core /net/s29data/export/data_29idd/"+run+" kip:/net/kip/sftp/pub/29iddftp/files >  /home/beams22/29ID/cronfiles/cptoftp-currrun-d.log 2>&1"
+    print(txt)
 
 ##############################################################################################################
 ##############################                 staff detectors                ##############################
diff --git a/iexcode/instruments/storage_ring.py b/iexcode/instruments/storage_ring.py
index 3e71edda0bc85d3032c585205a2fc27de1fdbc5a..a2269b8e853b181f4efacb0c0be43d4316c028e8 100644
--- a/iexcode/instruments/storage_ring.py
+++ b/iexcode/instruments/storage_ring.py
@@ -7,7 +7,7 @@ Functions dealing with the storage ring pvs
 from epics import caget
 from time import sleep
 
-from .utilities import dateandtime
+from iexcode.instruments.utilities import dateandtime
 
 def wait_for_beam():
     """
diff --git a/iexcode/instruments/xrays.py b/iexcode/instruments/xrays.py
index fdf2e7f0b95bc788e646204729f5afdf588c6051..aa029404a075cb0b00ddbf7f9878598afc57032b 100644
--- a/iexcode/instruments/xrays.py
+++ b/iexcode/instruments/xrays.py
@@ -6,25 +6,25 @@ import numpy as np
 from time import sleep
 
 from epics import caget,caput
-from .IEX_endstations import BL
-
-from .resolution import *
-from .IEX_VPU import *
-from .VLS_PGM import *
-from .slits import *
-from .shutters import *
-from .gate_valves import *
-from .diagnostics import *
-from .m3r import *
-from .logfile import *
-from .utilities import print_warning_message,make_table, take_closest_value
-from .mpa import *
-from .current_amplifiers import ca_average
-from .beamline import branch_cams_enable
-
-from .ARPES import ARPES_mprint,ARPES_extra_pvs
-from .Kappa import Kappa_mprint
-from .electron_analyzer import getSESslit, EA
+from iexcode.instruments.IEX_endstations import BL
+
+from iexcode.instruments.resolution import *
+from iexcode.instruments.IEX_VPU import *
+from iexcode.instruments.VLS_PGM import *
+from iexcode.instruments.slits import *
+from iexcode.instruments.shutters import *
+from iexcode.instruments.gate_valves import *
+from iexcode.instruments.diagnostics import *
+from iexcode.instruments.m3r import *
+from iexcode.instruments.logfile import *
+from iexcode.instruments.utilities import print_warning_message,make_table, take_closest_value
+from iexcode.instruments.mpa import *
+from iexcode.instruments.current_amplifiers import ca_average
+from iexcode.instruments.beamline import branch_cams_enable
+
+from iexcode.instruments.ARPES import ARPES_mprint,ARPES_extra_pvs
+from iexcode.instruments.Kappa import Kappa_mprint
+from iexcode.instruments.electron_analyzer import getSESslit, EA
 ##############################################################################################################
 ##############################            resets and detector lists         ##############################
 ##############################################################################################################