From 24f3022f4e4b8b32245960cbd8579699105ccc85 Mon Sep 17 00:00:00 2001
From: jmcchesn <jmcchesn@aps.anl.gov>
Date: Tue, 12 Jul 2022 11:59:20 -0500
Subject: [PATCH] fixed all imports paths

---
 build/lib/iexcode/__init__.py                 |    1 +
 .../lib/iexcode}/instruments/AD_utilites.py   |    4 +-
 build/lib/iexcode/instruments/AD_utilities.py |  347 ++
 build/lib/iexcode/instruments/ARPES.py        |  769 +++++
 build/lib/iexcode/instruments/FMB_mirrors.py  |  174 +
 build/lib/iexcode/instruments/IEX_VPU.py      |  528 ++++
 .../iexcode/instruments/IEX_endstations.py    |  131 +
 build/lib/iexcode/instruments/Kappa.py        | 1127 +++++++
 build/lib/iexcode/instruments/Kappa_Euler.py  |  120 +
 build/lib/iexcode/instruments/Kappa_det.py    |   77 +
 .../lib/iexcode/instruments/Lakeshore_335.py  |  448 +++
 build/lib/iexcode/instruments/Motors.py       |  232 ++
 build/lib/iexcode/instruments/Scienta.py      |  578 ++++
 build/lib/iexcode/instruments/VLS_PGM.py      |  739 +++++
 build/lib/iexcode/instruments/__init__.py     |   42 +
 build/lib/iexcode/instruments/bakeout.py      |  193 ++
 build/lib/iexcode/instruments/beamline.py     |   94 +
 build/lib/iexcode/instruments/cameras.py      |   52 +
 .../instruments/conversions_constants.py      |  109 +
 .../iexcode/instruments/current_amplifiers.py |  367 +++
 build/lib/iexcode/instruments/diagnostics.py  |  225 ++
 .../iexcode/instruments/electron_analyzer.py  |  797 +++++
 build/lib/iexcode/instruments/encoders.py     |   62 +
 .../iexcode/instruments/files_and_folders.py  |  268 ++
 build/lib/iexcode/instruments/gate_valves.py  |   35 +
 build/lib/iexcode/instruments/hxp_mirrors.py  |   64 +
 build/lib/iexcode/instruments/logfile.py      |  169 +
 build/lib/iexcode/instruments/m3r.py          |  126 +
 build/lib/iexcode/instruments/mpa.py          |  440 +++
 .../iexcode/instruments/remote_controlers.py  |  356 +++
 build/lib/iexcode/instruments/resolution.py   |  106 +
 .../lib/iexcode/instruments/s29_temp_cntl.py  |   44 +
 build/lib/iexcode/instruments/scalers.py      |   31 +
 build/lib/iexcode/instruments/scanRecord.py   |  688 ++++
 build/lib/iexcode/instruments/scratch.py      |   44 +
 build/lib/iexcode/instruments/shutters.py     |  112 +
 build/lib/iexcode/instruments/slits.py        |  509 +++
 build/lib/iexcode/instruments/spec_stuff.py   |   14 +
 build/lib/iexcode/instruments/staff.py        |   82 +
 build/lib/iexcode/instruments/storage_ring.py |   23 +
 build/lib/iexcode/instruments/userCalcs.py    |  177 ++
 build/lib/iexcode/instruments/utilities.py    |  213 ++
 build/lib/iexcode/instruments/vortexs29.py    |   91 +
 build/lib/iexcode/instruments/xrays.py        |  700 +++++
 build/lib/iexcode/macros/ARPES_macros.py      |   96 +
 build/lib/iexcode/macros/BL_shutdown.py       |   47 +
 .../lib/iexcode/macros/Kappa_optimization.py  |  100 +
 .../lib/iexcode/macros/ScanFunctions_plot.py  | 2787 +++++++++++++++++
 build/lib/iexcode/macros/__init__.py          |    1 +
 build/lib/iexcode/macros/commissioning.py     |  944 ++++++
 build/lib/iexcode/macros/start_of_the_week.py |  303 ++
 iexcode.egg-info/PKG-INFO                     |   12 +
 iexcode.egg-info/SOURCES.txt                  |   57 +
 iexcode.egg-info/dependency_links.txt         |    1 +
 iexcode.egg-info/requires.txt                 |    5 +
 iexcode.egg-info/top_level.txt                |    1 +
 iexcode/__pycache__/__init__.cpython-37.pyc   |  Bin 0 -> 147 bytes
 iexcode/instruments/AD_utilities.py           |  347 ++
 iexcode/instruments/ARPES.py                  |   43 +-
 iexcode/instruments/FMB_mirrors.py            |    6 +-
 iexcode/instruments/IEX_VPU.py                |    8 +-
 iexcode/instruments/IEX_endstations.py        |    2 +
 iexcode/instruments/Kappa.py                  |   43 +-
 iexcode/instruments/Kappa_Euler.py            |    6 +-
 iexcode/instruments/Kappa_det.py              |    2 +-
 iexcode/instruments/Lakeshore_335.py          |    4 +-
 iexcode/instruments/Motors.py                 |    2 +-
 iexcode/instruments/VLS_PGM.py                |    4 +-
 iexcode/instruments/__init__.py               |   42 +
 .../__pycache__/AD_utilites.cpython-37.pyc    |  Bin 0 -> 11481 bytes
 .../__pycache__/AD_utilities.cpython-37.pyc   |  Bin 0 -> 11482 bytes
 .../__pycache__/ARPES.cpython-37.pyc          |  Bin 0 -> 22012 bytes
 .../__pycache__/FMB_mirrors.cpython-37.pyc    |  Bin 0 -> 5479 bytes
 .../__pycache__/IEX_VPU.cpython-37.pyc        |  Bin 0 -> 13342 bytes
 .../IEX_endstations.cpython-37.pyc            |  Bin 0 -> 3164 bytes
 .../__pycache__/Kappa.cpython-37.pyc          |  Bin 0 -> 30320 bytes
 .../__pycache__/Kappa_Euler.cpython-37.pyc    |  Bin 0 -> 3978 bytes
 .../__pycache__/Kappa_det.cpython-37.pyc      |  Bin 0 -> 2325 bytes
 .../__pycache__/Lakeshore_335.cpython-37.pyc  |  Bin 0 -> 11833 bytes
 .../__pycache__/Motors.cpython-37.pyc         |  Bin 0 -> 6871 bytes
 .../__pycache__/Scienta.cpython-37.pyc        |  Bin 0 -> 16246 bytes
 .../__pycache__/VLS_PGM.cpython-37.pyc        |  Bin 0 -> 19637 bytes
 .../__pycache__/__init__.cpython-37.pyc       |  Bin 0 -> 1954 bytes
 .../__pycache__/bakeout.cpython-37.pyc        |  Bin 0 -> 4491 bytes
 .../__pycache__/beamline.cpython-37.pyc       |  Bin 0 -> 2570 bytes
 .../__pycache__/cameras.cpython-37.pyc        |  Bin 0 -> 1804 bytes
 .../conversions_constants.cpython-37.pyc      |  Bin 0 -> 3048 bytes
 .../current_amplifiers.cpython-37.pyc         |  Bin 0 -> 10455 bytes
 .../__pycache__/diagnostics.cpython-37.pyc    |  Bin 0 -> 6664 bytes
 .../electron_analyzer.cpython-37.pyc          |  Bin 0 -> 23058 bytes
 .../__pycache__/encoders.cpython-37.pyc       |  Bin 0 -> 1790 bytes
 .../files_and_folders.cpython-37.pyc          |  Bin 0 -> 7213 bytes
 .../__pycache__/gate_valves.cpython-37.pyc    |  Bin 0 -> 1193 bytes
 .../__pycache__/hxp_mirrors.cpython-37.pyc    |  Bin 0 -> 1740 bytes
 .../__pycache__/logfile.cpython-37.pyc        |  Bin 0 -> 4639 bytes
 .../__pycache__/m3r.cpython-37.pyc            |  Bin 0 -> 3609 bytes
 .../__pycache__/mpa.cpython-37.pyc            |  Bin 0 -> 11343 bytes
 .../remote_controlers.cpython-37.pyc          |  Bin 0 -> 9051 bytes
 .../__pycache__/resolution.cpython-37.pyc     |  Bin 0 -> 3831 bytes
 .../__pycache__/s29_temp_cntl.cpython-37.pyc  |  Bin 0 -> 1487 bytes
 .../__pycache__/scalers.cpython-37.pyc        |  Bin 0 -> 1015 bytes
 .../__pycache__/scanRecord.cpython-37.pyc     |  Bin 0 -> 19907 bytes
 .../__pycache__/shutters.cpython-37.pyc       |  Bin 0 -> 2889 bytes
 .../__pycache__/slits.cpython-37.pyc          |  Bin 0 -> 13354 bytes
 .../__pycache__/spec_stuff.cpython-37.pyc     |  Bin 0 -> 599 bytes
 .../__pycache__/staff.cpython-37.pyc          |  Bin 0 -> 2083 bytes
 .../__pycache__/storage_ring.cpython-37.pyc   |  Bin 0 -> 719 bytes
 .../__pycache__/userCalcs.cpython-37.pyc      |  Bin 0 -> 4471 bytes
 .../__pycache__/utilities.cpython-37.pyc      |  Bin 0 -> 6980 bytes
 .../__pycache__/vortexs29.cpython-37.pyc      |  Bin 0 -> 3759 bytes
 .../__pycache__/xrays.cpython-37.pyc          |  Bin 0 -> 18992 bytes
 iexcode/instruments/backups.py                |  339 --
 iexcode/instruments/bakeout.py                |    4 +-
 iexcode/instruments/beamline.py               |    9 +-
 iexcode/instruments/cameras.py                |    6 +-
 iexcode/instruments/current_amplifiers.py     |    4 +-
 iexcode/instruments/diagnostics.py            |    2 +-
 iexcode/instruments/electron_analyzer.py      |   22 +-
 iexcode/instruments/encoders.py               |    2 +-
 iexcode/instruments/files_and_folders.py      |   54 -
 iexcode/instruments/hxp_mirrors.py            |    4 +-
 iexcode/instruments/logfile.py                |   10 +-
 iexcode/instruments/m3r.py                    |    4 +-
 iexcode/instruments/mpa.py                    |   10 +-
 iexcode/instruments/resolution.py             |    2 +-
 iexcode/instruments/scalers.py                |    2 +-
 iexcode/instruments/scanRecord.py             |    6 +-
 iexcode/instruments/scratch.py                |   44 +
 iexcode/instruments/shutters.py               |    2 +-
 iexcode/instruments/slits.py                  |    8 +-
 iexcode/instruments/staff.py                  |   36 +
 iexcode/instruments/storage_ring.py           |    2 +-
 iexcode/instruments/xrays.py                  |   38 +-
 133 files changed, 16456 insertions(+), 525 deletions(-)
 create mode 100644 build/lib/iexcode/__init__.py
 rename {iexcode => build/lib/iexcode}/instruments/AD_utilites.py (98%)
 create mode 100644 build/lib/iexcode/instruments/AD_utilities.py
 create mode 100644 build/lib/iexcode/instruments/ARPES.py
 create mode 100644 build/lib/iexcode/instruments/FMB_mirrors.py
 create mode 100644 build/lib/iexcode/instruments/IEX_VPU.py
 create mode 100644 build/lib/iexcode/instruments/IEX_endstations.py
 create mode 100644 build/lib/iexcode/instruments/Kappa.py
 create mode 100644 build/lib/iexcode/instruments/Kappa_Euler.py
 create mode 100644 build/lib/iexcode/instruments/Kappa_det.py
 create mode 100644 build/lib/iexcode/instruments/Lakeshore_335.py
 create mode 100644 build/lib/iexcode/instruments/Motors.py
 create mode 100644 build/lib/iexcode/instruments/Scienta.py
 create mode 100644 build/lib/iexcode/instruments/VLS_PGM.py
 create mode 100644 build/lib/iexcode/instruments/__init__.py
 create mode 100644 build/lib/iexcode/instruments/bakeout.py
 create mode 100644 build/lib/iexcode/instruments/beamline.py
 create mode 100644 build/lib/iexcode/instruments/cameras.py
 create mode 100644 build/lib/iexcode/instruments/conversions_constants.py
 create mode 100644 build/lib/iexcode/instruments/current_amplifiers.py
 create mode 100644 build/lib/iexcode/instruments/diagnostics.py
 create mode 100644 build/lib/iexcode/instruments/electron_analyzer.py
 create mode 100644 build/lib/iexcode/instruments/encoders.py
 create mode 100644 build/lib/iexcode/instruments/files_and_folders.py
 create mode 100644 build/lib/iexcode/instruments/gate_valves.py
 create mode 100644 build/lib/iexcode/instruments/hxp_mirrors.py
 create mode 100644 build/lib/iexcode/instruments/logfile.py
 create mode 100644 build/lib/iexcode/instruments/m3r.py
 create mode 100644 build/lib/iexcode/instruments/mpa.py
 create mode 100644 build/lib/iexcode/instruments/remote_controlers.py
 create mode 100644 build/lib/iexcode/instruments/resolution.py
 create mode 100644 build/lib/iexcode/instruments/s29_temp_cntl.py
 create mode 100644 build/lib/iexcode/instruments/scalers.py
 create mode 100644 build/lib/iexcode/instruments/scanRecord.py
 create mode 100644 build/lib/iexcode/instruments/scratch.py
 create mode 100644 build/lib/iexcode/instruments/shutters.py
 create mode 100644 build/lib/iexcode/instruments/slits.py
 create mode 100644 build/lib/iexcode/instruments/spec_stuff.py
 create mode 100644 build/lib/iexcode/instruments/staff.py
 create mode 100644 build/lib/iexcode/instruments/storage_ring.py
 create mode 100644 build/lib/iexcode/instruments/userCalcs.py
 create mode 100644 build/lib/iexcode/instruments/utilities.py
 create mode 100644 build/lib/iexcode/instruments/vortexs29.py
 create mode 100644 build/lib/iexcode/instruments/xrays.py
 create mode 100644 build/lib/iexcode/macros/ARPES_macros.py
 create mode 100644 build/lib/iexcode/macros/BL_shutdown.py
 create mode 100644 build/lib/iexcode/macros/Kappa_optimization.py
 create mode 100644 build/lib/iexcode/macros/ScanFunctions_plot.py
 create mode 100644 build/lib/iexcode/macros/__init__.py
 create mode 100644 build/lib/iexcode/macros/commissioning.py
 create mode 100644 build/lib/iexcode/macros/start_of_the_week.py
 create mode 100644 iexcode.egg-info/PKG-INFO
 create mode 100644 iexcode.egg-info/SOURCES.txt
 create mode 100644 iexcode.egg-info/dependency_links.txt
 create mode 100644 iexcode.egg-info/requires.txt
 create mode 100644 iexcode.egg-info/top_level.txt
 create mode 100644 iexcode/__pycache__/__init__.cpython-37.pyc
 create mode 100644 iexcode/instruments/AD_utilities.py
 create mode 100644 iexcode/instruments/__init__.py
 create mode 100644 iexcode/instruments/__pycache__/AD_utilites.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/AD_utilities.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/ARPES.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/FMB_mirrors.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/IEX_VPU.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/IEX_endstations.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/Kappa.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/Kappa_Euler.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/Kappa_det.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/Lakeshore_335.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/Motors.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/Scienta.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/VLS_PGM.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/__init__.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/bakeout.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/beamline.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/cameras.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/conversions_constants.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/current_amplifiers.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/diagnostics.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/electron_analyzer.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/encoders.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/files_and_folders.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/gate_valves.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/hxp_mirrors.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/logfile.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/m3r.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/mpa.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/remote_controlers.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/resolution.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/s29_temp_cntl.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/scalers.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/scanRecord.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/shutters.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/slits.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/spec_stuff.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/staff.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/storage_ring.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/userCalcs.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/utilities.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/vortexs29.cpython-37.pyc
 create mode 100644 iexcode/instruments/__pycache__/xrays.cpython-37.pyc
 delete mode 100644 iexcode/instruments/backups.py
 create mode 100644 iexcode/instruments/scratch.py

diff --git a/build/lib/iexcode/__init__.py b/build/lib/iexcode/__init__.py
new file mode 100644
index 0000000..8b13789
--- /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 19de023..f8d43d2 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 0000000..f8d43d2
--- /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 0000000..90f825f
--- /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 0000000..888d9b9
--- /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 0000000..6678eb1
--- /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 0000000..94ee6e1
--- /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 0000000..18c9810
--- /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 0000000..42dfe2f
--- /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 0000000..9a1a190
--- /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 0000000..5acc6b9
--- /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 0000000..119b51b
--- /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 0000000..f493664
--- /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 0000000..8f7bfdc
--- /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 0000000..e244a3c
--- /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 0000000..94dfd1a
--- /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 0000000..6817162
--- /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 0000000..1436d9b
--- /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 0000000..45f1aea
--- /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 0000000..5df2d30
--- /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 0000000..50814ae
--- /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 0000000..8cfbb77
--- /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 0000000..ef7cb08
--- /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 0000000..9710c1b
--- /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 0000000..1e122c5
--- /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 0000000..0eb9050
--- /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 0000000..dec2ce2
--- /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 0000000..54bb5ec
--- /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 0000000..6408b46
--- /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 0000000..2c65239
--- /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 0000000..a34f891
--- /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 0000000..4bffcda
--- /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 0000000..89be3db
--- /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 0000000..2e01a97
--- /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 0000000..ded5e79
--- /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 0000000..2afd842
--- /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 0000000..1b323e3
--- /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 0000000..61cc859
--- /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 0000000..b9d6eef
--- /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 0000000..a2269b8
--- /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 0000000..367ceec
--- /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 0000000..3e4b739
--- /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 0000000..81deb73
--- /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 0000000..aa02940
--- /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 0000000..240e6d8
--- /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 0000000..800bf0c
--- /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 0000000..378f9c5
--- /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 0000000..c4ca216
--- /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 0000000..8b13789
--- /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 0000000..675889f
--- /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 0000000..ce69923
--- /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 0000000..c7569a8
--- /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 0000000..e22a33a
--- /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 0000000..8b13789
--- /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 0000000..5255694
--- /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 0000000..3dc2072
--- /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
GIT binary patch
literal 147
zcmZ?b<>g`kf`|!ck{E&XV-N=hKmraxT+9L_QW%06G#UL?G8BP?5yUSW{m|mnqGJ85
z+~nkp)Z#q-g36MN{Ji+`{G#mQg2d!heNWej<ouLW{mj$~FdZMCnU`4-AFo$Xd5gm)
RH$SB`C)EyQ>SrKk003mmBt`%L

literal 0
HcmV?d00001

diff --git a/iexcode/instruments/AD_utilities.py b/iexcode/instruments/AD_utilities.py
new file mode 100644
index 0000000..f8d43d2
--- /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 b07a8c4..90f825f 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 c7c0069..888d9b9 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 10274c0..6678eb1 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 5c3fd18..94ee6e1 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 6fcb40d..18c9810 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 cd2dbfb..42dfe2f 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 14b2f04..9a1a190 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 080c578..5acc6b9 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 24085c5..119b51b 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 4ca6dd8..8f7bfdc 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 0000000..e244a3c
--- /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
GIT binary patch
literal 11481
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
Ng#Qc0iQ-hT@V}DV0}ucJ

literal 0
HcmV?d00001

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
GIT binary patch
literal 11482
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
IQ^msn0*urtegFUf

literal 0
HcmV?d00001

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
GIT binary patch
literal 22012
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
P^gZXj7}=BW&Sm~T@Z~(e

literal 0
HcmV?d00001

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
GIT binary patch
literal 5479
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
DV|)e}

literal 0
HcmV?d00001

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
GIT binary patch
literal 13342
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
F{oi>tC;b2b

literal 0
HcmV?d00001

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
GIT binary patch
literal 3164
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

literal 0
HcmV?d00001

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
GIT binary patch
literal 30320
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
BsY3t&

literal 0
HcmV?d00001

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
GIT binary patch
literal 3978
zcmdT{&2!sC6xZs*k(2l<N$Zx<A(?WJoW`Q*0m^hBvf|P-!O4)2>3Ep&2(9Y4^@nC9
zL*j{Nm<gQW#DN3Di5c$v1>Exw=)i@Ok8t1s7v7U1*-le(pdAu<p5FfUt>oSP{q%OX
zluAu<aIr6rKfRITxZe;&7Y~IMFn1qrl%u4{RS9^$$+v{6&=RX6!Fr)7wG!1tP!^jL
zEx9V6s+VZuORk!v6I2F2Nt1LE{1ly{)8MCRil)J*XohCNr)iGPfX`5}&8f2k_;;?N
z^1fu5b=yPdbUl^$xvpz7!)#icU9V;}ZIeNz(4wX#;3II!U=o-C=KcsbO8SDwdE`(y
z;`<`y`w|uUi9_iyF~?C6Oq%2R6CQsk(nOx46GuGZ0wm|TLoP;1KzxiQ0g)I@<vCAy
zD#mykqQm#3;H_y-qM0KCr7X0SXf7zv<b(H94#!*>VAt#K|NiZF*MIoqe&f;puemzZ
zaQ5-BK0wNPQgOAsZB(a9%&gaIYi(-p_xPd?Rsu7?R>8`>MA6VUj5mAo_F6?L6;`#u
z&-gg676wRgFHz77hE`S+Oa#bqx){!%&$k_)cN)IndQ6plLVe!e^?7g4Cv87HI`__J
zK7m@xCr^Ij*cEvAuXXKXAjj37wk&JUcH5eB;O%wVwa+{3nd_LAt*w<GTODd^4SPTI
zZTO#V%WiwFwr)C(Su1y&HY+*@{_MyYYbS)`9Jtru#u1TB@*>=`e42#6EO?fOn1v1S
z!lB}*0wsJ81yBMPC;?`@Pk>`Wd0+%|5im}u2uO<2s2T_bHPB=n1ODk$jDT;NicuO+
zCPu(FupRvaFivM<GzaJkqCf#xD+2<(j98vn_d4a8w+DEwvZeR(%l8^In5B1H?-V~O
z?amup^OX;`!+2>d{`PZmV=R7WG!Ck%Ut3z;`FkO`g7RUgLnu5LEQf`M^*@zQzW(K_
zjg?qgcNIlnQa)IEsHz~Z@{+!zR}?f<TUlE!zNHq7&28lYLKPa7wN)J0=GG3wL8`(j
z>8U)+LOp|o6v`>k6uS!0&z#Ieq=VO?azqD_0*0Qw1})Ck!8Z`ONID3ZpR2GW^ebXs
z4#sQkHU2;9*>&tslt)x$xu9b%iSkLv@O)t&D_#o6*=WoW$&1hd7wHc__93}piQRz6
zrJ{I%xoDhX=i*Sjs2H#QLk>xXQAZ@-gDLqpl5bu*l5s(eNiKVx_1d#x3SSte@R7Cj
zPH|V?IF-!LZn^wiOQUyo%e$j3Uzp&>zw+CP9!dZ|>ZS2yt|5FmA9^$?kp>=}qk%Ur
zod$3}bxH%K6Xo)=`MM|?SX5q+>b0>{|KHa0Y$yTKi6rp&90@F3Ite63B#;b;JCf`#
zwgzrTOTjD61G#usA{9J2M+LVau4a9y-EBDs3=adoWIGMZWw_H14=^`Rjuyqn@Muwt
za;+QeIjgtMY6C};n%$<ZXL^lJ+YQe|c$^6KlEH3+;cCP%9WfLn!~TT3R6PES>{sRc
ftqz5Q%zL=g4VE_<4l2_Gexf`hXXLb;155t{!G28R

literal 0
HcmV?d00001

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
GIT binary patch
literal 2325
zcmZuyOK%iM5bmDWj@N60Nx(wNp~D4MLN)>vDHei2AQ4L9i=8OUWi*~{d&i!gnRNHs
z+0}B1xpK}S7q~>qH9u#hNRe{lFXWW3dcA8N8L7K#`cd^&^;gx8R#v(U-(SD|x_7d~
z*gy0$|9l8vpqWSLB$K>kL!NL>vR8UTKk<h_65!vLK^YFCB!V0!9T_F@*GzU~{DR5&
z)JvA+(hlo)-#`!R^ENc4Qcd4$!#q1smWF0z-|*RL^j&RhZ6<5CKQH7rS<_@&QrRt|
zY(Gpqd8hT{U0BYW#LpU;_~Yy#C&lw`0sA&)6ic{dIK~rSdeVQvl0XJB#2Ct+gUFLe
zF3B!tI&v8>SK3u)HGQnC$^m6^tt;^5WoC@nueET?0-)UTY>~jzN27=KC7S7>o3dBz
zHKrwlZoUooefW$aFsj`DgXv{#`uFMP_eN>6c{t4Tfil%*Gq!`eN>6HiWST5jn@^wo
znAcKm7V78OSQ)EFLseO`Il~J;8_l?l)3m4xo2Hit0%2i%vi`118}mK+95+Rcn!|k!
zf@PMU^5=ZYr!4iX|0<CDHGl3+*`YV}_C0vxO?I5~6dm|vgdHf6kF*9T3Qt;PLnX3G
zil#P&E$XVf*gs#sDXbl&$62{pX?@J}LrrMfF73nBr_FI2kUAY<T7#;r?`z_28_!j>
zoikM~q_d80!0o;a!NllTC*~3F^2w$5LIMwVb23U_fJT;FI6i}5*(>e>;7_^rjv{^A
z`Zk#IQ;)N$hd*{0N<MWYlfg^MiVz`+vPX#U!Z&y_ixQA72qYHE6slo;tY&+Lln27r
z6d{2Kjg(^_1-Viuv*WeZi_;5X9uTvbp&OESwnUlf10`euBE7qIcT1RIR+j&>hD_U9
z7#=p+I|q@0TOtFvtO9REGXQ3%Ufif^J10Xq76s@E{Yv)F-6d4W-Yx3H_5E^GYh`j(
z<w}@bD^*=z*wU-GgWa!CGlG+>ux;m9>Al*h?S6F5h#3{i0*OKQr!Syu0}5zAa9q)A
zG<}6SN{;t<()zfbPcd&?O<d{vF?bSu$P{c_<P903=7{nq1j-x9rT5Z%4x$|T(!a`N
zaFro*xD1bcebWXqI^~>Izt~WAkYhe*6CZhI7vs{|*gYGUk39Xmji#RLtuwhobh90~
zO6T3|1<YP_v$SVz@%Q!~I(f<M3FJr4atsU~lO!*Lq*o>f=Ydx6&KA{yOJ-u;jD{1X
zLBv|*HPYKOHJFM&S!mQiv8S@(d1}`c?%NeEaZ(V^?=H0OqV6qaCdCcGMC;kX8_GD{
zK{vSuYqvz6Rl;f5Q$j1L_KQl%xuVJDL#@QP9tkr#6HYP|8$ban1%XuD7z-p$)qf!F
zxBOYl$9N=^N&II|b|%5b&Xe8N-%<7eHu3%a0CPV){8m#XoP-;XAtyen@noI6pI5HA
z{#x9c+}j;w_PP=E(M_R1#PMD&#|}7Z2qIKUv9BN%6@ZNn1_H%zlu`ZL*x1<a$F8(F
zb~^4RYpIKIDvO*pWqRC(4FZIhv8eDe&e%+q96ToWCd+44Hbtr@5pbeDCjNe1zfb9y
z0zw6pYMA*19gBK=)dRE91YhMb+N|$-A3PKD(|ERa`!PK&RD;vB?WVviM<vO<H2rCm
zm1irRG?jIprg{aoT<O*8Bnj&1t$V9;)tQPi?R8lf`+*nxaj$z>)BJY7+Xl8k*(dMY
zP&GwvX5pixYcJqcOjRXOTPSj7RtqTaH5GiP<1Ks6JQ;1{do%d=>DHa)9>3`IqJRh9
Ef4^5icmMzZ

literal 0
HcmV?d00001

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
GIT binary patch
literal 11833
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
Zopg`5Z@Y)w1CH&aoe^i$F<sX^{l6o`p#J~>

literal 0
HcmV?d00001

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
GIT binary patch
literal 6871
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
ND2s83{?2M;{Xg<brv(52

literal 0
HcmV?d00001

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
GIT binary patch
literal 16246
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

literal 0
HcmV?d00001

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
GIT binary patch
literal 19637
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
E2g7!XeE<Le

literal 0
HcmV?d00001

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
GIT binary patch
literal 1954
zcmb7F&1w`u5T4CJ!$RI+uE}8sTs#OO8eM-dD~n5lcqw{&YG&H>AJskUZXU%q@L_y`
zTzv#RiHJ4vZ!ZaDLk~Uh_19JP)z9(4!MNb{<HM)b_gh8rdHDIWMtpe4JMHtQF5VXP
zXjvTYsjmzy8w##8xY41;iSa2@@6hKodGrMOY^=$cO5<XnTpo?DN55XomIB;Lonz?p
zUu1bb<qDOv#-jwQl|xeh484I?2fs#2Cinz=PFb<HqBnXXjtnRlt!WH%NN&|ewLYY5
zv<QwCb*A7!d1bd3NRl_u59-P6X^h3h>@_sON-sT~AA>VQLH0(gGQwKf^-k*Cph&lg
z|HJ-b_6E?`EL<K$lmuwFa<({?KwqjDl^6&$igNji6=uDa33|d+lDa?$)9GD_F*dY=
zuo9@7igIcmvQTX&ix;5_oEBVioZlP=k#K}5SZ+hXOI%BL?m<QuLHle)7qpUEvebr)
zUz8cC>vI-5n7F};B9S6$NV#tskz-j&fq_(uK*qNc;yxigR#w)`e$5Xf>jGydOISRc
zON?0aFv1P1Edg&xZFeI)E?*svE^h<WK?8g&Xpg7j)#uyu>Xh9})jOwkhsjrQn>+5s
s?*pBus5DmGNQPEh{T`Ur&cLhyj5irz61SK8_g$#D+8-P-`4`^BPe8!MX8-^I

literal 0
HcmV?d00001

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
GIT binary patch
literal 4491
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

literal 0
HcmV?d00001

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
GIT binary patch
literal 2570
zcmb_eOK%iM5bmDYnSFTujKPqH)Ka8~MZ^vUfmnqQZwv{FaS#w7D@CK(>E89&vok|?
zkMXX?$^p)~hD15QG5;X>5%~jiOin&Wx#SR~s%H%b`IsJcS9SGc>+x0fcBZEr1lr%<
z{oeZvxIb}n*lb`vg|4<>;G|19<yJ(y7En8~hm~%HqO1}*L$~W1-ifOB2zPn)De2aD
zjn{$Jd4o>@ZSW?a20F#x;<J42DeX4J^!7}j@_D`hvsrH4C9TEr<%Zfyq-L={6s(^}
z*3aTVhe@nhrUYk?L%qd7j5NtK+xt-ZBh_defSP2pMGHqoLZrZ0x9`J9&jt=IL31bl
zOQ7mq7&O_Y+g46;np?S@SNcxwd{5C7P{kTwYcOd2Fp3llW2UzRQ-L2dDS||Dqa4bD
zOiH0+))W3P3S+^-Brqp8TXtb}HVS*l{ldk2!noxY_Wd=G-Ray1Rkbg5QBgWci>A^d
zRbHBeu~vn<^VpXI^$U?Rpy)qetbDD6R4d!VAlMQrUP(t_e(XI?<c>=HK&;%n{xC?m
zSP8{mNn@pDHWYB#%Asb<>8O}O6TDKHd31yY1F6V47y}GCw#uX%Po09vQBU>l-2Q*P
zBr!q~!&5X%%{=Y*BGIbI8m`n~=+=g#QYxoWhHfc`S>THKBW9J`mOy-H+yd|cbkit|
zXrM9fZD2~{`Uc@4&B+gzG0z4NRL1|BP~OErDdv{|Frwawanbj)NVko2{pPK!=NU6=
z8_8f0#se0@kxVB;Uxz^(@ypJhEdz@XM(`vlV%v{cG&urMFQdkkDDeg>XIchrTxdUx
zl=+GBnzrE)rVlX>*j08<W`doWXx2K%cp?;2Tbb5EGQdu-Q=Z2&rd?$>{0KCQljF7(
z)m<Tbi4yk!%}3&74U!f;HWF16i9zxnc((L^U7i5`HUA^%KEn+dM)d!4>jl{-IRT&3
zv1hD;q{<|uJ-R9Km1dAen2n%nHtc~llbnQf!$?5paRx!@Y<PzWcw36yFv(OjYO@Wv
z;nw<^x%o9qrtt0?aP4L`Y|(BNe*u2rO@P&Kn+GbiP;JByaT-)2$_@}w0S?&gNjK(o
zV1nlD)0}d;W66`+;?@&NLHgW&LAbp{bR{QG=n~<TC9-d6D=*hA?%+P|f=jC7uZ-fi
zB^C#k?lPUQAW26nDQE>1Cx$utsRyM`$i`&zE9=ccuT!pK*b5qr7gw)@Jh;Br23(zQ
zuLX~?P>QkB#sH3;<r{0=>*Lv*>#JAVolK4Hn5wtgatsOzw<rBL*eaY9bt-J|d0|7z
zftqI!0O=qxxe6=YebbjsbH*!`y#kw569(eCv<BZP=#s(wrAwz^QiX0@`Uf!h7IAxE
z^9pyk3$*&PwNEwSwI>u@NO&En4YUEY0(1(f1GEX$1v(A1S{D7>$=$p<aQADP@)>mb
z-f~`BC*OXsUmq>z^=(Uz^ZIj}(-*MzfIQ-q;P(x151~IGdz<ipkkbUtboLvgkMdgH
zI8ET(uO$a(Ej$}9K&Z<#htDoS(9M0%Uf%Z%?tAut@Hq(i{Mae80C6R;1|MM393Z?7
z5Pk<(FI$#84a5xN6Bth~Rp;A*KYSI?L-FeI;tR)%FCH(xbiDZTYvRFAKVtjs+IR-a
ziUy>{u?V!_n=MzO0TN9q>M!Mmon~6TgF-jm#izeDWzf^Dfhisj1KouMG;2avC-lOE
zUYyWN6MDHk8HGxB9dojv;hQ*IC^788y~-0YJ~^L*4(c2X#6D@zh={~*4tj%H)Fm_2
z1#SlT2AQKLVJ5LAKsm%HwdRVd=kX-)yuyJx0#B|Lr$t4FLs6RTh%^k8@k8<c<hfoB
zUp?2$@RWl#9R3`b|2^humiUC3I%-Oe$&a!eW0DyKj#y_NNAoV$J{~4Ki^M1R#HvLY
TDprj)ttPFx=4;mG8Z-X^$M1@R

literal 0
HcmV?d00001

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
GIT binary patch
literal 1804
zcmb7EOOM+&5EdmrwBDCDeQZ;-1%dVuFA%%kK7bf)(0#-~&|nYowg`MNXpy!ROO!%V
zPIlp(nsfUH`Um<qdhZ|5wI~0DoH|4Kv1ttyrNALILk?#?e#6t<-I@bU{rczNkFw+Z
zg+I&Y!Q^}B`X><F;Uscm(j&3ka|!;tkr$VGB|G<`@+IoLr~+e&mtQ-*D&ON(?!P8I
zpYQW6UW3^duk&rb1G5_6?K+KvIrw%OZe9-9NEjT_%rr>;PNs$G8WqY>S3K_rkzfkc
z<R~Dx1DXrH3jGYa{tyHw+~pn~&MUn7Tjdp*k(qPbfn)sZdo>D;hk*$b$<!51hBTd0
z$zq}DFj3Tu1sw<$N1+rn0JUP;?z!GNz8CU-s=sKjrpN2)m+R?Qiz!pnuh-gd+KtK_
zgPvo=b3}DsLIHR?^9qRH5r8V3*_T<I6RvhZX~mm|tsemg-Fg-W!B}Y7O0Uc~k^L8m
zn&^}TqV?#((;(rZ6^fU|D78^pETqw`MH<cYDnCH?>9oH_U<(e>dmx;$OO~JSsyb-$
z(&eL0C%}NQVYnFg576~zAdE9}eg=3C0rW%Xm1oGzGww5Q=+4|<2r$A0(7o%27C<eG
zrdetcK7CAez~mDVB#Kj$P`KgINEGlF;nF)x-CcUzupZu!_C=#qM0V@sJdLtZDEnP-
z)D<R6bNBRd?!}zJnq7!4ubiBlt5oEb$qS}NI`@}**2t=TT)2m*U_gBcGD{CJKTOss
z)rq<d<7Nmx2g`p!U`jJ@NN&QxVqk&I$FK>ojxA_L!x*?vndDTnDHuXSLuui{A^>(q
zTqwKIild_<t+xGp@G?zwro?3!i#83$Opd_CATeX>K`hMFfZd*fL}$VCEL5UUF4?ao
zOZ7N0)-6`c&8CFCMm97Mk=?FCEG4_Rql9>p$u_-InV{d@hdR@25D5x<3{<c^ca+cp
z3nqB!K_Wq&B^iK#k!Wy4|8;DKMcR6U+Mj|iHbqxLqGxVhE(il)X)wWgD{nRHP2GZv
zx@eRO=G0Hl`(5zV2_s>7quvFxdJjZi1smqSV32wrEl3CT0g6>Y7PRp#ZD9E)VANQ`
z&UT#uWj=!0X39{oY@*ED6uCaLal;d+SLBdXCYBgQ$}8yXO4gh-865)tRAut5tQVDB
zgUlB9^FNY{!l}3mAs5w9fz&Y7iw02#F#coM&dVYV1Fi7AQ20>vK3+UW&2ar3HIdC{
zEP{ntV?DZQ4MdxnFamA~oqxJ%1w43tA-OgT`KRsO+FG^f+c<CBm%TY#>;AWK!m~)+
V$0+T?S9f=aPkhhct5s|Je*@+r#-soM

literal 0
HcmV?d00001

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
GIT binary patch
literal 3048
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

literal 0
HcmV?d00001

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
GIT binary patch
literal 10455
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
D{1ngV

literal 0
HcmV?d00001

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
GIT binary patch
literal 6664
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

literal 0
HcmV?d00001

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
GIT binary patch
literal 23058
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
Rj%F?*buiPNIflH!{|$7eKsf*a

literal 0
HcmV?d00001

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
GIT binary patch
literal 1790
zcmbtU&5j#I5bmBId+c31OR~gCkfK(E&>F4mU~&K}M6jEU!hy{y76e8h%RAln4zXt@
z-EC(*8gnrZz=;dI058ECa7Vs!@+)wns>k+j7KsZZx%$V|UsZkeb5N<234FiL{y4o+
zB;+qVtUn7jpTbY=gW!bIAsJDhjx67zgj?MHk@z-uxC^Vp3%m%c%e@Y%mzMB?)UAaZ
z^pdg0Wgv7w@fJP=24mz9e(C`TP7w~F22S5XDDDj`*p+yhZ}DwjG56J9?HSEzMs5=@
zaxML#%;1wkk7cA-kMS_jVI1}3l)Vo18PjKii71G<kSv)fqrEzJFLb*i(sH^N^+ux3
zK3PBLhH<dZMzM}%zFj{YhDw(WR9bF*9P%&1DEy$ktUwscDvE0;c0gSG-)b-K;O#qj
zTlnnx$x)}hL^hU4#nMLMfT-JkK@CIQI>^@#AN#J+{td}=(8UGi63rO#_tWN=N=ViG
zeiQ^}LPgDFs?Xx6`#P2{RniMY^Yf#xk$`3>&hs@=T8>8$vudtFQjKJ~xV4V&DlzDs
z@<5Pcm6qwQC9lJNlgk1e&~=l`N3hW(BXjyKWNK#3?DO|C`!V_M-pt7?PHRNd%$dW=
zts0rR+R9vR&!L=N?Y<z~fvmdeo*`FFqk#2>!^=rjtRG8;Ead!K?NRDBI^P^0O044J
zx@~-0*bt&bX6prs*;s6?gM*|lN}HrEw%7NVRDYutjYkVBnOyKJ-$Im)Hu{DM&S`NB
zEmYoun*iCu5B))E3@t-QwT2>}Q;G!S^w={83E&pqo`00NK-2wMA+xz%BUu3`a)6>D
zXxQfD0(rJ}vf><YYJdTxz59Z|{{@5ao<X?#213ywxEZvQA-Qk#|BuC=4MNFSd}u5_
zc*7$4>|KfhJt%26D}m?UoNf{0$Dfz{Xd9H)zfk@&@}KCdyMSRz4LG%UIU_kId<%+b
zJN?B}$aA5D)?qYY9q207I#_qNVmfB`O*!@0Ae@MZC9w)|da%8x0d$9u`(Nd2y<xBn
zf(lc?A|W`wKNSq%4N@bY2q#iZ!g#EP(>61<yZEYg&^^khP(Ff8O{Uk&hhr(h5<6L0
zZZD|tZ8)Vi%%Sv7xwCQ}+u&Kh55{u8+o=ayjiYBzo=BV`>CKJmX)k!W)@`S*>7rw3
z11!$GIow2sFz{~R1y*a`C}rc6UtGoR7gxc{T~v7+#Z3^tE4t7fvWEKtP}WT*eknG-
z!S-s$R9F3_x)L*S8(ygv2vYQD)$(AR>`=B^uby{c)Z`lXV3jyJArNpN2?J%E&fUjp
gl!u2Zmpm|2(loC3a1`_LP&`7i6t?A#<yE}WKasJgV*mgE

literal 0
HcmV?d00001

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
GIT binary patch
literal 7213
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

literal 0
HcmV?d00001

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
GIT binary patch
literal 1193
zcmds$&2G~`5XX0ICvlwyid3mcT=rHhMM*)u5FrFDp+ZD$q?QQf5;@*&V(^!C*D0~e
ziC#H#fEVDEEOFx0SK!3VhKh&-55Ooh`{CK~`uCq4v|1hk`~KzgbYK(m0~a?2Yw{Fa
z?Lpv#)0iZ5OcQHtQNk^5Uy-rRJznGWD>`;~lQ*~vvl`zxCI03$oFcwe)xuyVG!A*8
zL)=88;12j9xY~liDVF5USNj9GBv7DM#vTKcLKiYsEMPneb(E!nT(az(>A7IDKnu1A
z;)PJ`Jd=<!ixwhfQyHY;+%xA3B{-WdSr}(ZOiVHhQqELxE+$Gt1(P;*jz$mmOx*uQ
ze7mAyMR`Sq#B2I=Y#)u3nVazQRrj?LQgz=ZVK^5m?dD58&(g_7Cf}(%2u1g0|4o>2
z(T&9W)tD+Ri$tVab@Ae>yQogStXiuJ|K72Yi3@?a7PY8r$qksFg%)ms;aCSZ>`)vH
z^e)K`hyo4_QIby%C6`pTHRTQS%-ta$DF}z+cx7Tf+AvXnp=9@W5yfts;kdu+w^@I9
z%F+z39>xKvAy#CEQY@mZQ1P<I4h`MsBh;e3zA*18n-3pFymv5wLcP-K9S%-T`<>CV
z!8P{5Su}iMTE)2tB3(6fl!&a*<u=xd(%G8KJyzPCPUqOSBvPtsxr|Z`U1lAPs>VXd
zDTw?>C5aTPrV)K&KK2f5D1=Aqcd0`qw%&gOcB6MP>>ndniGS-GuCfUWxe1}%KFLM;
zPo%O1d4Ts8p1F+y`+pS-O>adrgF^S<$vRAgd+gIQ{MD<P$fHn6>{cU|>0$$1V&Ym|
Y^9EDgeVk;xh{Y4^3sZW_a&LLwFA!}UF#rGn

literal 0
HcmV?d00001

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
GIT binary patch
literal 1740
zcma)7TW=dh6rP#AczsEma*35nR4Wh!OO>t0p%M{7Ra0(4jjE*3)Dp5bJCk^ccWq|Y
zX}q!}r0^4X<N+S}G5mpj;Dx9Bg*@@iu|oq?f?dry-^|XA&wl4S#}8LlY7Ez-?|(b|
z-DB(zJGr_9zyl0(03(^?LzeO$=N5~hNS&UOx;>ZX&d^K!o=?~vR??ss0DIE^f%U4g
zA_MrEtjZdEUDjm-z9CokS?k6HPG>D%^2aSvdT}(K<klUl9E)#`b&}=%7m?1A?6{vQ
zWAFqIYH3&Z4|SBqgP7YBa5)(G2)2V^K82B73h7AqCuh!QY{pM2x}77eoX_~r;um(#
zn@svmc+RpnWMzh3>kMl_lg-6U>@!(Kh_&KzEySf&KGB&8^MMMJQ5+tPbQp!l$*Iah
z+K?t%k90qaQnej!q}^yE?7(kbdA&i~dhXzCyh-*R*>1}zopejXbR&zRVm%w>IQ%pk
zCNf-{8`^Wj_b+*?2sS@V<mU%ZwlDeiE?)MCrqUfICNJF+H8ohQUkj(#z)w<Ow8cUA
zzcPIb99@3d`N}A5I^U*oJWwX<jHmfvl=WYX^obcqvFd#B$w54ls*|X*h0jc`C#lME
z)3L`ce#f-O)3RdcINY}>xB<g_!37UQz;BCHu3yK>-|}TQQof!7<ZOmq%=vWl>~79&
z_Rhs4_RXES$i<9Hr^#|>CMatzvc%5?XWy+oW6zL1&g`AL(zDro&N6X;+#-9GA|uw#
z6k1s%PamF!Q6@t(UgU5%45Kq;YX3KhwC{;lr^#qyhSTkEA7}TGKzeXt^>|T%DS29W
z?fvJwJ4JJ6pyHD-IU?mGCe)M6N_w~D5h<kyEgviG*w-BJtF4k-j=pIZ#Q0RN0Z_&k
z<~6%sg$DZcVNFa;1BL|w2w&xIbD!(mnEyq0fXNC5(fuR972UQRBuW9)3&Mi1Ll~rE
z-6agtfvJ3?N7$!zDxrBL7bu}+`N--_tXYhzpE+v_?=HQ!^#0OU*4TL+{i2R^HHtfn
zJY47ZGnM!8sYGw#r}x@>55I=rT>9?PZ!P@?OMl<`lGh3+d=M7yyY24LCGVhMh;r?M
z18q5L1w^x62QJ0aGmI%lQHnj_J>b3KU({QrQ`v3cEwc*4yg)Sg%Ui#Lwb(wemsN#r
zsYL%>fSjGPITSDXiO?bR4rN2Z&^h&^0LZmSdZ5MsFIq|-Ynx$RwZ^J%w<WYKFA4)K
z(_gg9e|`v+EV}J|Y&G<6;Q2hjT@(5}I%cI5T4@`5>8WuN8&WCJSH87u3hm@&Q)o}}
zWSHcMG9==%`KmqW-;3yMOCX_Aob;2|LbNSPlh%We(vh4D)yI}d>Mae(9Bhl=R<Ih}
F{1aG=kdOcX

literal 0
HcmV?d00001

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
GIT binary patch
literal 4639
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

literal 0
HcmV?d00001

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
GIT binary patch
literal 3609
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
F{|BB%T<rh=

literal 0
HcmV?d00001

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
GIT binary patch
literal 11343
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
C!VNS4

literal 0
HcmV?d00001

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
GIT binary patch
literal 9051
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

literal 0
HcmV?d00001

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
GIT binary patch
literal 3831
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

literal 0
HcmV?d00001

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
GIT binary patch
literal 1487
zcmZ`(&2Jk;6rY*>@Wytc9MTV{K+C~Md#Op<ORcsctt>SnF;UiO%U-PY&NSU-zdAc1
zsj*K++>okXD&SI%{0T^iKV&5&Bu<eK;>?Nn#!2d;FsqsO=FPtMe(z)E-r{1N!1(Ql
z*TX+eLjJ(b*<iqY3bWjTg%eH_lG1>tEMOG(EHP3uFjFhAQaiBIT2KSI!OgEp;BbrE
zKo@w8J3#Avf!BdHc*7@N^8_psk5yI_?hA#aI8>flS!E(bQQ7;cic?WJrIJrHw~*vf
zm>?S=EF4H}nD=3p%djXiCS%GeXWaPK1UF`{AHVsAq9gMtj8#=b137r2(f|dI1@_Lv
zEKEgE+j$sgfZ-=1F(LnKxA#gR%l5N0ik^xxYZoun(>xm-<?^5`!br3?yN{!si*_uI
zXEXz_hpEU^*)G>^4U|ZWL6oWFdhw#Nb$~}TgsSmV*#tg<c|H)4js;H?q+8J`nKFoj
z^+qeL&~0(IHFR5FxUC1B)^?}mdrV>iB%0N*=avS@ss<002s4ghV_0Xt7lD7rw*><2
z`!X=-`wdl$vnl<NPAL`}P#C?@2fO}b-}S?^NQB#m0EG<Ip%fkWtBL#B=*rrynDfq-
zf8)k#r+<I7Gy8MHGb*c)ai%K!NiNe+NzB0<Si~kZVhhtI5#JeBtZYPK!GV#UWBnMU
zvpgYEZYT!%GAU8eg4`OD704c7w<i=PQzoxrEXRM18MhDEODbJuDd-l^)qh_lQ#vt}
zH8w!v91!^{=$Xf#j6oB2ufT$X7RJWAT35)#fPWmI=5zjtpaovL2G+EdUjXC6sm3`*
z?o8P8n=|ReI>UClx50unwh<4ngXf!Y-ayY6oHzA3;foi0cr>fsQg3u^GmBLmCKr|O
ze=9d)P}WQTE$fjS_&fW$Ams0LiN!g=5}qJ8df!*!5c=bSHrfCFI~+f+pL_^^o?7^Q
zeRO@Vw{dT)>-Il){XTG;0r1`Jo$l^Ne{Z+@k?X6xC<J#y<@WD%JX<b-{;Z3zSM+U`
z@P3iX2#2KyFA?@pDO3PYNL~!S3}r=!mBmG(!iq+f?z7cEleM`{eA|TjNh#OBCZQ{I
ziJI^^v<Z9@xH|C2EyHRv2X+qdvvq~a_du)XH7iRLaa7KL;{C2nyowsB#6F(8zj*6)
g<4f##ZD9`A+Z*ECPIG>kh`VU7MENqkYB>7)7wut7@Bjb+

literal 0
HcmV?d00001

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
GIT binary patch
literal 1015
zcmZ8g&2AGh5VpO$`Pn9=;(#hnmN?~-wA_d)egYI#v{9rMg!U3`ZKv6G*SpwGp;0O!
zl`9VbCphv5JOnSWCnOGtSK!3h`6*%~dpw@mna|(M_L|KQf&6&){W$ax`e}`&fQ=r)
z(stvB;}m5$!q}ckN-{6<GC%U2?WI9hi7Iej;}u?gkE1GY@EWhfsm8-Y)N1~QEU1Oc
zV3g*$YLPNvaWOF^8N7sB(%b*_>7$iz4~`hIu^?9aupYzGw_!8r6mxt=)Gb41XoflY
zK%l4x1^nrgkb-DoG&N&EHH%ZBG-dfjnna$^QLdarNUlw6l3Y?QMu`-hCX)8{-REWS
zJT8hDAXU$WI?lD|w>%X<?b1tfRyLe_I8P3*XqY4uLoHYiSyc_<z9Q8C_2*gVg@*c_
z(~PmP(6Uopm~k$LZ*p~}i<pVd-qTks=c1E{w{tDEQIkwaqdN=q?c$;g=jS0ax(bQ4
zWd!*lR_mZwTv>=Ku6DuT_>ypP=@~ThXXpxeGI-`);Y)w!e<oj$+5(SfJn&)bonh58
zKKD$pyx~6Z8cbh1Vh)$QCenx#HRsPhe#PsOa3It2?}(yo9B0QuxfHSFG%I2{N>U>f
zm6MDnBX^T%swPrGmt5fV=G}V<KZv%v^PJo5qrr63-tmLMqwYZEY`fc^WV<fWbaU^2
zNH7G{<lTO&qU;zeOH5gZ9!bHB;K~kG859cMQhGpoD^P1T&i1dYFZeFbqb9%|t_qc;
zICs6BZ%zA!{eN!2(i^a$z{frbNe$QVI`Ogd_FF_%z<0FL_0rE`GhUz&MZ)wo%;?Ty
w9NNkCIJ99@hSzhe-9WnjyAuC^vZJRgva+_5<$RKg`xq>3U)CTSq(Q>kUrUw+&;S4c

literal 0
HcmV?d00001

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
GIT binary patch
literal 19907
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

literal 0
HcmV?d00001

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
GIT binary patch
literal 2889
zcmb`J-EJF27=~y6*N&4WaT*tBr42_|w6+Km5>Y|Ku1zCS$J8!Ad(f4$vu&2zYcn%$
znw2dfxu;wRXWRi-zzysvM>*jFIO6+e*N&4ER3X;#{O|0{Gw-}Jwbj);f#=Vken0-T
zK*%4MnLipNzJNcEAfUu0RH15L8K|zRU|Q>I1KrgJhHJ>Y-Zux9YYlAIhP*+|*Tl_H
zi`o$9X^!S0UZE?r0C9odq-*rXYsFoq>vRK3*61cJLVSa6bx3(T{xCo2g^|Ng#zF+l
z=|$8zX1&NiSrk1RN4^M$5zn8)07+R%4BiidQCUq4zxO;47>&jP@+-6_0_Z}7gCMy%
zVqqk_(;kb$=(#rtIEU6g_A!4<NYvraZ$lvD#HmJgYW%D#L@3mpDKJF~25QIkyaUg0
z6hzz+CxNp(?7XaNv*2Yo9P|F!o^u54yhkvzPBt;wBEH?O@9lni@L;dm=y*r%M$3EL
z`1(ns)2)27e|WCID7vBZn@V6V`e`o|iG@=cjzwI;9$_91cIsrkRw|WNS!FuBml$%o
zzYw+pIT`%*u=<1tj8}gc`2I=2qw45PoD3uHbjV)tQO^&m2aWIiAq}cw@G6ZXF4%Yw
zM1ohdCE=CPS+aq%^|BHVA*{hyIDVLz>k3<i_&<|<Aldl+ArIaLZ5<mfvrW<7Sw>qw
zJnA%-*)j`8*bUoF5Rl4j$gms)aS40-7px5T%>~jl1v`i&o0pKt(U+k7f(a5@Ffkyb
z!e6Rw4-%-hnKH##g;;@DgIJxAiLyl|>K2)56VT!dmF-evsz*9Cr}{((En2ac5<3a}
z7u*>}Qjc8p#29kVuB#J;iyMmtV$49k%j@WT=5*OOaH>wT*XKd1<aoQ$?toDDK&hS1
zM|<s~&O!I!sCBt~_l@Q4&PDk-g6=lU3ezA_He3yQ!(i9dpdD;noI+Aq9?%kO$+>um
zb2dxpjjuyMOk2TULA4cA)m63$Wee!IpYX#HdJPh<?h7&_Q!)Yg0QN3yaaE`@G6Sa*
z+KfP`<1#4ZM-}Syd0iXw--6cxd^3J3;n!36IJh}aCj|VkHSRj$Gbb8~%q&9jzI;Ol
z%N`-SxF+OgTza&B&~iEtpLDy8$BvZp17~Mv=Nz>d7dx4wz}KSTsr*Q*Y{;3XYDKNd
z9m!B}0Dl7u7Pi17*3u=cavkKp{utV3XjR2Tv=HXig2J|-rs-ps_@H$z*gk~}RVJha
zVlI)XO0`8=6Cmap$Qwhb0|`q}e*&U5q^OOF!rY0$n$(I^YEN|mJ<(i=O!N}LwU{9H
ze8ydl^#2w;Zjd<F-cP-`1B|`e;ZgmogVvW`t+D?I-5Kg@S^YUe=r&y)J=ry-A<?*S
zFOxCq089qy$OS2ziJ6{hiS;sI$6#NsHhQ^_K`k*;NxyNCZl<p-j5lox9!5B>1~Cet
z{B>9))V>Z&1y=kHl>4ZBd@x=da(5wvwliOw^r)j|cGy|6+)kO(oMe8O8ck}={+Ka1
z8Lphq*U!Gxplk9J&%`Rb0fO1-Ckel`N859cj#utw{Vg4QDPo0f!|bk#eCrB7>C)dr
z!_1{`DePUyEpXwwE^yT#Bgj+%d2UNdf_zbq(Fa1M;L{*>4gPRjpeD64h_);T@yeS+
z9w4s7DMZu?cizm<xdgG#=NE{}3{!}=<_w%(p9MX7CLI8PEaTn0e!KXm6VS$i;R$$!
zt|pa~ItrfiplC$wu4O9sGTmPBmEslTXox<%$K?go(iL4<Q-S+?P}V9d&GLF;c^)15
zo|ou&*^#D|7{Ms?dAf(>_2y1?MX7`rSCq<Fg#A#20cX<laOqOx!?QPaMBFFoOmL;;
mXO~nW2QU55zCRe!aX<JRx2@b=azCl-mYsuN(JtnTcK&Z&Lc6s9

literal 0
HcmV?d00001

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
GIT binary patch
literal 13354
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
DfQ5o3

literal 0
HcmV?d00001

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
GIT binary patch
literal 599
zcmYjO&59F25bmD*jUl^;2zxD0l7rijn?Xd}jj)1YF)nB>p)*~>jG5^fx_gKjW>5MK
z9()2{X~5Gyg10?cokZAz@2jtVs4lACo}3IB*`HrO*LR$;J0JYFfW#Yu9T6#}_z$*Z
zDp;^_C+bkjTbJPV1;H+f8m{;zFsCZG4RqK9s&mF}1J!NV8S}acDDF6>dJRS2IcKE%
zM?ZLw3y--+-YZ704(BajFMA6o<M^J7`k6?I9K{-CZYL8ld3kktvzUDpw!}y%>7=Mn
zhl}gk1;j<B&`hDe{8Ch~O|uL%q5@YyWKcRhc7W6hEIO!4a0x;wT>`n(mCUjoq#FFR
zX*~e4NJ0J73ys@2%@E!Z&1H`D^G^j>Cym>;Lu}9{Q#cpvREv!)OX)X-7x9?4z0#!G
zjk|5fRJ!dS_FRTH7L6aZ?0?u@(+<Cx>C<iR-wR){;%gp730f`6ol6S6+7@PGOBtcK
znthH6g(Ago2d}L&RgT)({asepRdIY??%L7eF}w2T@?UMA5HTL|eh~7<d_>B_gp{3+
Y4}QPK0~%1R4PWJjsxo}-r~D<be~m4g!2kdN

literal 0
HcmV?d00001

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
GIT binary patch
literal 2083
zcmZuyPjk~o6qhW?HX<Q`8UoC8MxD+8rjw{~=yWiU;>3n#AZaG1Y0*qaRkZ6^pnvSH
zg6*+S@G&@)V?Rv4fUZ5|+*?n5Z)K9WK^nc?_j`Z#Y4v`qjrn;~f$R3izYexx_BSe@
zE)6D+;o<8bh(gp*iBw08N=_-#98E>66zY-T7*W|NM-`_6m`3#Xic=*QNSRdLtIh>d
z?J9Ni7;-3eEw6+D7bIZ05xtg!-;WXk2K`kM#CbX3y&$A{nGV2@`znUPRfflaXA>Si
z06|nzBHE!gQHee&4Za<#ZRNK+6HO@N(pVcS@3e_7)Up0fRTWXfk=KM)=x=JjD8!f;
zV}q2(%927VOUn0()T`5R28TQb<{=mGO-BEi7F?T*dV+FG^r^+N*n*d#zDQUASTA7`
z?<HZFyba>RrVJsT@Z84zfE>)K{;Wz&srz0SVyci(=C<~BJKa0CyTa@BZr2}7(Pv(o
zdM9WRma-rgmY@S+G5RKhs)!{L3pP3E4U1~|F!uYF&yrYp2cM$oQIKRj95$^da!KyO
zVoYSIEXFZUi$62>&&<iFX2(?6ym23WZ8}I3ChXCgX_{FI5ItSpLQ{~$62TpL98*Sy
zCpC?>@7k-@-RW&-oY@CKY%{FfTK0~t<z+hX!;H{Je!{5rxrI*(Cidue>vfPer58+W
z-V>>vW(PJdO;Ew6<JP)m+5IG<_5t-G-e`b*t8L>(NxSW*A_4DZKVuBO`7&7vlS8Yq
zerq*X&7Hc=utjr2egam3IYSQB%ee;L&Z4a7OrJOg;glUY6*RPg6ME{2ey)ju_)}r?
z5c+S&{ux}j{VMYPKIO5U4n;qS-M0yQ%~Q{(_EzUtKOxi(U_;~>bHTER#)8`%+hrvk
z<_kr`a2F8#rd7zzuY*wLO;uM-bxy6qJ!k0ZB8-bFTL9aO8TwrWMAEMhlRyFD0R;nf
z0yHE#0V<ISLE4+-BAFxeAIynHE|CSYNG_8r<O@<GS3guHI=M!c$aQk#g9e0C{{Xsv
z1Zv5db}}=H8PM(K=%s8xMn%SAZh1g7A6v&`Lo4aY1|qcQWudSL6_SFy=;>W{+SBc+
z$!!<DGUqYA<Y+-Mvgv!P-!*~LWVBcS-7pZVKZ?f6<~gK2gY2L4L1f0KaW0QUW_`}(
zX%u;;1!6sGn|mAkXBWRGgWz~=!mAuVK=Ba8BNTXUAOC>jF^U$74HWnpN0*A%-0!Zo
zR`y%ZPxVHjPnX^AuC+F19q!HOTf0;J%iUHJ3DfLucHNEVKW#qS+Ii}3bXwao{M6k3
zjJaN6HK>YRMR5(q5(?~5b_2yt5Th$tbCkqMv$NCLd-~Gt?v5^h!nU{en!78wK_}4D
zy%z;k*N)qe;JAb035dFymy1&g=xGd?H{^L08py@=a>^tCE^%jp!=`iBODV91A#mjR
zSr)mxp9ulPbmp)c7XrN?<dU<6xCCqDHzWbkD*ICAE?V~+F!OsLl(Jr`Y9;mm_bgUu
z)shKRHC6T%#O>787j-i)C7hK&l_w3;VU|}CzJdpdJdGIsIg7IhyIqE!DH9JFCTp!e
VgkMA!(slgha*V2}wQ}|A{{WDAH3a|w

literal 0
HcmV?d00001

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
GIT binary patch
literal 719
zcmZXSO>Yx15Qc4MHwjBpi4zw<zUIJgB@hRMD$)w1N~NkA@u9t}Hulgp*)MD-X(Bj4
z_%r+%{=i;2<;ay2<4r1%n8>s5SfiQem2*5C1_Z<Z@?-jo67tg(H^ERm$73F2k|ZXQ
zN|w`t#f&=L$vcG?d#(0zzv#wY)V}O~BXLjmCS=rKhr!EvDXgkW!zHA-DzErb*^Ju^
zxUrQ^uYhZJTQ5uyY;hAA(Z&~eZ=EnXK#k(IOf96Pw5kB%x?CVJ>EJoR(^6iC7RfgB
zGx<a$n-P7_BIkxu@{w64J=@ukyTsKOc=Hx%k+Qq~8gPtPRjH83{Ld!lT0?0$?&nht
z>CEtD24&mW!rwF~!_#TC0RH5V7vpy7Nd^M@cYaelHyjqASNzc-Hz2A~nzn6yXYzD%
zxt}vW4d0B<wijq?`vBAW;26?^<Me4NX8hs#$kXn1v@_rMH8NQ3p&rqgO)kF^-N)kh
zS@ha~HqnPdhzv{_)hnA-WwNaF%+#rX==8-qQAvmtT<^Z6v3g#hR}<}DCvgVDdesb<
zsj|uYN+(l<8Q=or67d=B<1b(bRJ%XZ`KaIYl0;S_Ng5w&B}@z3c<$|X$oKaPL-luI
oIJYWSR)J})w6j_t|D;<uzv(|KDml;LsEd_xPCYuH12$lP0GvF&O#lD@

literal 0
HcmV?d00001

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
GIT binary patch
literal 4471
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

literal 0
HcmV?d00001

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
GIT binary patch
literal 6980
zcmb_h%X1sad7mdR03WLd_1w+66|O>IizFmQ_FBwRmR1sXS!-d}B6q2Utb&K=0WsuY
z2I_8*1OoVAt;@MMxuhzGT*yNXNu?@P$-m$~z?I`v<&=|rO-??<`F%YA$R%y>#e<rD
z&)47g_4jOiG&NN;@ch?5{=?R<t{KLEQ)l$pXgt6x{}Tl_ss=Z?6`562*H+ciwOzG!
z?Nl9IyH!`$xoS?=`KpK7j`FQSwO|qqCn~lksuQir>LmIu&wXuFr}%r^<Atxy>NGF%
z35>kOC;1fWb9|b=h59_d$<Ol(SaE@0<TDt#$S?8BsAu>Ueiij4evMy8eVM<_-$8wa
z{~3Q5^;P~Cobem@@*4khK8um-+*&tEbG?hjjtm-|h&4KKU4=<3i^Vq})~J-s)DGiD
z$x7Y2za1#5+8tG=$<gDY@d&Rxhe8>L;0sFY$T%YCR;4#{(`Pq1ySc?~e#LHnvV8OD
z^3C;<ojNLP1*s>MXy{fUO6q<@&3`t82VlDR?OOQ@83<Y4Y1Qk^K*r^ES2dHkwx5Vy
z+4k!}dF{#bdcuQp7#w7E449o(5Gz^ks4xmu7|6wTH=W?V3jCPU9)zv5P#C75!%y=(
zX!xB-)lC}2lN-L8xGi*)v11Zp1G8`L*aHitGq6#*1E-H8-L=GBZXM?OcHik+NA|#t
z-^aL(@y}JBJD9O(?#O;^Vs856$iVHpV3%8|x-#-*vp4hC%eR;KpnP22<pVkm)w_T(
zbh4SOEP1I%#A!x4)Jk2IaKD>6-M|;A+e%{9Ol=y;H4@SCm6!xcrCjRnH^X`}wYaJl
z^(Qs@qB@ba^>@`m*1^}KCOCY2Mxp>v;w=;x@yZz#hFLUo`sbPFOwXLLrcJ$K%wA$M
z>6T{iduS-I@U>}DZS{>SVB8gB*mtPrhGtN2wz%@GPp`1~@L6T8^6@h3<=G8-Sa0@Q
zKU*n6;@!3YmrKyWRv;zBz6N5$c>5H+=_S3cw(pA=v$f&k8=ypz=op~-oGGrLRVO;>
znZQeut!e%Z8W1UH%#rch7}#ioZf^e4gg8M=t{4Lsnq>6d9UHHM*HyVbc!bh=Z63LU
zTpz-A)fnVezMntzj=;Is*1#M0?6<R#!g$0PjucgayQ<iSC=R(?;5qbjC;EBxJ?eAs
zih*`Pw+p&m)a~N<+X;PA6Ni%-9!GSJ1vT|rpCF&a$xZeCqsZ_)W-F|j?6a01cNru~
zvW7@nEKc_I^e6LAv0%UHD@MZ16t%F7g)v*Y+hlcEiQS@J8Z2%vF0-(~v~;pi68Pb>
z8E{rf_Sn)LhVSp(UA}!=e?!xoeyCOxv8HY<&EK29U1BTu*{TS$^?yn0*}c(v$OF`=
zE8mc~ZsWyMd5|^Ozdq<qRX|E8m$PkqQyad3odm)vfap!FM?uhrbTH@~>$yyVHdHOD
zEY|E@+VqD{sPvjpEiNurO4DKr8>Ke5k`{;$JcyJp$Y_c4R9v8fG&prd(usLGr4r>w
zH5t^Cm`ib)rfkwuvd<}u3J}qTt~8OFk5luL)O?znN&~9q8XeUULA59X)bR#3gfT$5
zkr1;|Q>JDsHJhhZU}7J$HPBWI)g1Pb@1QWeNpljy&+ty07w|iW-@NV#T2<F(7Y#y<
zR7I=91{!1n6s)TjE^8=U)}f{B9cSCz#sT!rBj?Aky#pIcVu?@ig-x@E?vZhrgCbd`
z5qlW@hRG;=m2_Cs-wRmpA{(*@Qp5aM?g!#V&!c(ihrD-w)Pg{&CQj}~DX*C+-UWVX
zP6km>SKw?{f~ks!aq5Y{=TR8L<dUIim)xrNsuM`^q+*u7GQ-qNQZqQszNs*VH?0w)
zlaBfUmP#Fmm^0>e(=jhw;x>J5t*(x(Cb7=Jt68>;#?bLhb8BG6*N5)r9qynviJlAR
zbBpH&<daRF??anOH@OFmEcAY%b)p@S7Wzz*AVKwln2AoTr{-2y=h$i(`w?69W97>(
z+Y9R|5#4Ncwg_C<o+ALAEfocfx?o=@gKWC#M^O-UcKqfX4q?=0^=2YEQZEsAKuPcO
zax-ZK<*mSP$@0>@wZ~tqKY3PuoYaTDoZ^7mQ@<_}S<b53(!G$E*9q_1Y8VBw{AGsS
z>gwXYzlT^1sPsPl6Tl@v8f5X9g5Hn*1b~mh5%^xtr_*2+gj`l4A#Yu&f>y~wSU^-(
zbGnkJC8?m#kXC#QPReN%M&5(}&0fb8cQG>dLpD0}*6~X6y$A31p<279K>ej*LaLNO
zKIQ{sV7#(6Gv90Kc+lUH2;Ly-zJMMCFg*@XY@fy`|IClKgD=`&(iWLNq=-P=qitz#
zdj1d|?rA)}e;N<*U3^}$#rIH&52*M)72~i`ha_o1Bk?%dk6&Q+BpReTM7@5<wvUzS
z0XhfokR{?4w_n?jjhB-H16E19vRBiaG;3iF^Jiw~hpcic;ji<C5&kbghm-&JyWas-
z+A=dG!~?_^R&(zR!cVs0nSPig?Vn(cBytQG&`G@Fuh1TwPO<}JK8b@m;KF$szc3m)
zEBV^v_Ae>=c6vY6`t@<R2c`B|6iUUC27IXswh>g%vo*F4y(U}O2(|Jf7G!a!wG{|*
zsHz!|$Ca>V+Fp*P4i+_BU3@Nry)fy>sJqNI{N3PDwqDPT?G~|^aMb}K`7OftZ;Y#8
zD)1!9%1+cw%>(${LaSTLu*f(>0cPrb82PO&?%$8l`yaeU?>&VLYeNicdw$dj7C+Q^
zguIVNwjA*6-JnZVD~zE_c|a#th!w!l8(@3g*85yI3$%fSS+<Z9AE7;_i|jRh^eHX)
zTNE7bYd0q@^l=i`jDZzj&e8^5+R8bC*c@2{D;q^ZfIJDYpG%S0->nXugS&|CoWnd^
znF-N*@5k0a$9deo2B!vV9`|#UE&kjB^n5=z@Lp9m4dopc`reT_C_n)7KQf*f&y9Wo
zob`JDq7R}0>lpipr&gG*_CwWV!GQ{52{%PD!C^Vk^kLc|4dm1GhZNYn|Nbtb+-<o$
z9-+~;4-hL^Me>tG972QeL-`>^#3v!r_UzU$!&+vGNZD%R4UwIdH00DFnALNqX9Y>m
zZ_SlAqz`W>2&$BdVhOc)gd%lz68Paf4+YVddbJwuSF5E?(hlOZ5I~dyK}k_z<f~<B
z`%<NoNDeU*)dI*)shD~rKBc*g<ZJ`CL5QVhBQ@)(L%zQ1Axl#_(b6qFmTPs1s544U
zn`&}nU@Iv!Gjg6;v@Rn)Dw>y}-V`s*n1YPuShQe2w2Bjn^4BQHg>S=s!<j>DkOtVh
z1@R>X03>LrNhE9v0Z=148n_2v_aRs?>(B75(>MDrgbiiifnj%F-Q6_et%IK^Tvb5m
z0P(d2k*grBF#0)&+Yqj94`J)}F?=?J|L?yS{@-sJuNn|e;}C&|#@jgbvR0qe-tqqp
zC##SC5qP8mL?JLjSrAGQN!(uag@8ZQ;;PkKvMpaCxQEcLlM7l`NqZgs=ZDZ|4e87%
z*|B5OM|v+ABr%gw5p2_ihmO5{ru;3)sowG%qR!6l_2Py0fOqC45TG(>-+4Lzdj}EG
zztrF!c2t7QJH$0d)CHNXWDg|sPCLTTh<cd_AP5VM@Kn~}UrCh`0o~FtknVI5tZJ*x
zgVBOh*s@kv6S4CA;d*U@h`M!#Ewc1td3oW^%Pf~VX~fs-evCM4H_%^_st+H%i&jQ~
zTQcJfIiXS^wc>W_>iux1(`^T&A<!*^GSEJb1cf4j)P?~{bDcOuY>bcrRF?A9OPYyD
zu#+~5psmfa#N`9wT+=YMi>DYPX=@*!nmb|v8=uy)VvAgX{_tm*mbXwC6Gg3B9@NW$
zs!f{H){IuS$zlH-MvJDXV{Pi-8cd8mtc@XhAK{f`|H-1m{!*lEA-2YC9(vaiX~ULt
zw~us%=dQr3Q3^61$z#;hBe*)^1)Ud<R?}QT&)FRLG@|keD8;1jVq48>UFho>*x5P4
zZVr;b=D@T@WA1p#6OQbWTs3TPl<bqhXoIV@M!WDt2&646X!&7OZsYna7<%$!lm0@d
zh+TFfrd?XnVR(5fj9;?$-cx+MjtE`nMI)J*)vBX0(g@M`9|ol(`V-(Nr2i%)qH+vK
zH?Zauar?oRgx$`fmTe@i4CxcALtH`xH5rx1gf*3F%jI%;>9!mp59RmcdazheS|E3S
zK_v?kqPn2q5f_FRIdVa^<icL)FKDhUAj@57h#)8*^L>qCD)<jX6@D~NNs~rY*0C%`
zo+-(<9wU-*P?LNM$9RgNnF}Ol=nXa!wi`y#9|btvXdyaz^D$y)R?kYhYax9kAOB6v
z#%vzJ5yJ(ur(lq6Rz7ZDc@_k2>u~a0fIVLyL(_zeV9x5E&;BTo%qZzBqXDP;J;9-X
zsrf<gJY{@a%OoX_{HXp}NA=vr$4}ND^{mB*$EK-wVSQ*h=}61^1S=&+P?WE4M8tQf
zMXnghjNOvkf^IESGd^urJOZ=<ApeAUN!KpMWzRrjWjOk7qe!9o4o2%VMGsj;3JbO2
zSVg0Iow5miK}OecCd`A03qP2Ob)+52+AWF)CT^8YqX+N!GZP`4&Fz8tQ}em;l@VLd
z(I;=&`;9)aCkKA39R<g71q%VMwIMnu#zx#$qI<k>G^j5w*&I)h#1GXuvnHbjRBLl^
z>$}HdIhw>Rd(c+w)1bSR_=2w?mk^@UR%iEtuX?xzL%&|fwTQZfi#C|C?%dghBhXur
zv|UYPj}?pKE8NG)vCkv7NHBlUo8N%1VLDoU_|a$2Hs%pL;I9F)enCVwBVms|t8A=Q
zzIej!SCD|wX{WBfb4kyiK_7X6-AEEq#;VgoFmZy6UtvB=uqQ0I6-uxjy6A0T9BBky
z@uH#&4OAqyrMJ_3t;Umjt(J)%UF`{SPohM{Qz|H!O<lyP?XGxE10+SMi_62h6z~T|
zCb}e7`Wju|E9=`deMh9zd!1WnX(r{0I#JOfrFL&xNHvxxsH1>7OO?G3TM6$(!F^H@
nxroBi)DeZ*Z_+wvd3JHy%XwElulSbd;+OM0Z^oM~e&_!I9@ysr

literal 0
HcmV?d00001

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
GIT binary patch
literal 3759
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

literal 0
HcmV?d00001

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
GIT binary patch
literal 18992
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

literal 0
HcmV?d00001

diff --git a/iexcode/instruments/backups.py b/iexcode/instruments/backups.py
deleted file mode 100644
index 05d3c3a..0000000
--- 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 979393c..94dfd1a 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 c4d045a..6817162 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 56ac0ce..1436d9b 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 6a72551..5df2d30 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 d22bca8..50814ae 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 4427551..8cfbb77 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 e45ab7f..ef7cb08 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 6f1e48d..9710c1b 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 a757fc5..0eb9050 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 2f158f6..dec2ce2 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 903ed76..54bb5ec 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 f941431..6408b46 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 9b2e864..a34f891 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 33da16e..89be3db 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 c2719c4..2e01a97 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 0000000..ded5e79
--- /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 909009f..2afd842 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 5a1ead3..1b323e3 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 8ff6206..b9d6eef 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 3e71edd..a2269b8 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 fdf2e7f..aa02940 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         ##############################
 ##############################################################################################################
-- 
GitLab