From 51ba60c1b9dcde968c36d88d09c3202e81c9c3c3 Mon Sep 17 00:00:00 2001
From: Jessica McChesney <jmcchesn@anl.gov>
Date: Tue, 23 Aug 2022 14:11:46 -0500
Subject: [PATCH] fixing logging

---
 build/lib/iexcode/instruments/ARPES.py        |  38 ++-
 .../iexcode/instruments/IEX_endstations.py    |  32 +-
 build/lib/iexcode/instruments/beamline.py     |  36 ++-
 build/lib/iexcode/instruments/logfile.py      | 285 +++++++++---------
 build/lib/iexcode/instruments/scanRecord.py   |  37 ++-
 iexcode/instruments/ARPES.py                  |  38 ++-
 iexcode/instruments/IEX_endstations.py        |  32 +-
 iexcode/instruments/beamline.py               |  36 ++-
 iexcode/instruments/logfile.py                | 285 +++++++++---------
 iexcode/instruments/scanRecord.py             |  37 ++-
 10 files changed, 478 insertions(+), 378 deletions(-)

diff --git a/build/lib/iexcode/instruments/ARPES.py b/build/lib/iexcode/instruments/ARPES.py
index e2be0d4..9189eca 100644
--- a/build/lib/iexcode/instruments/ARPES.py
+++ b/build/lib/iexcode/instruments/ARPES.py
@@ -8,7 +8,7 @@ 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.logfile import Logfile
 
 from iexcode.instruments.conversions_constants import *
 from iexcode.instruments.utilities import *
@@ -32,8 +32,9 @@ global ARPES_Motors
 
 default_ioc = '29idARPES:'
 #############################################################################
-def ARPES_init(**kwargs):
+def ARPES_init(*userName,**kwargs):
     """
+        user is an optional parameter
         kwargs:
         set_folders: sets the mda and EA folders (default => True)  
         reset: to reset the detectors in the IOC, etc (default => True)  
@@ -54,16 +55,24 @@ def ARPES_init(**kwargs):
 
     #endstation
     global BL
-    BL=Endstation('ARPES',kwargs['scan_ioc'],kwargs['xrays'],kwargs['BL_mode'],ARPES_Motors,ARPES_log_header,ARPES_log_entries)
+    BL=Endstation('ARPES',kwargs['scan_ioc'],kwargs['xrays'],kwargs['BL_mode'],ARPES_Motors)
+    
 
     #setting folders
     if kwargs['set_folders']:
         if BL.mode == 'staff':
             user_name = 'staff'
         else:
-            user_name = input('user name: ')
+            if len(userName)==0:
+                user_name = input('user name: ')
+            else:
+                user_name = userName[0]
+        print(user_name)
         folders_ARPES(user_name,**kwargs)
 
+        #update for default scanRecord advanced parameters
+        BL.mda.log('ARPES',user_name,ARPES_log_header(),ARPES_log_entries)
+
     #EA
     if EA.connected: 
         EA.get()
@@ -202,18 +211,18 @@ def ARPES_reset(**kwargs):
     global BL
     #resetting the scanRecord
     if BL.mode=='staff':
-        detector_dictionary = staff_detector_dictionary()
+        BL.mda.detector_dictionary = staff_detector_dictionary()
     else:
-        detector_dictionary = ARPES_detector_dictionary()
+        BL.mda.detector_dictionary = ARPES_detector_dictionary()
     
-    trigger_dictionary = ARPES_trigger_dictionary(**kwargs)
-    scan_before_sequence = ARPES_scan_before_sequence(**kwargs)
-    scan_after_sequence = ARPES_scan_after_sequence(**kwargs)
+    BL.mda.trigger_dictionary = ARPES_trigger_dictionary(**kwargs)
+    BL.mda.scan_before_sequence = ARPES_scan_before_sequence(**kwargs)
+    BL.mda.scan_after_sequence = ARPES_scan_after_sequence(**kwargs)
     
-    BL.mda.scanRecord.reset_all(detector_dictionary,trigger_dictionary,scan_before_sequence,scan_after_sequence)
+    BL.mda.reset_all()
 
     #resetting the current amplifiers
-    if BL.xray:
+    if BL.xrays:
         ca_reset_all()
     else:
         tey.reset()
@@ -355,12 +364,13 @@ def ARPES_scan_after_sequence(**kwargs):
     kwargs.setdefault('seq_num',10)
     kwargs.setdefault('snake',False)
     kwargs.setdefault('scan_dim',1)
-    seq_num=kwargs['seq_num']
+
+    seq_num = kwargs['seq_num']
+    scan_dim = kwargs['scan_dim']
 
     global BL
     scan_ioc = BL.ioc
-    scan_dim = kwargs[scan_dim]
-
+    
     after_scan_pv,after_scan_proc = userStringSeq_pvs(scan_ioc, seq_num)
     
     #clear and write the after scan user sequence
diff --git a/build/lib/iexcode/instruments/IEX_endstations.py b/build/lib/iexcode/instruments/IEX_endstations.py
index e35cc5d..172f212 100644
--- a/build/lib/iexcode/instruments/IEX_endstations.py
+++ b/build/lib/iexcode/instruments/IEX_endstations.py
@@ -23,15 +23,23 @@ 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
+    BL = Endstation('ARPES')
+        BL.endstaton: name of endstation  ("ARPES" / "Kappa" / "Octupole")
+        
+        BL.ioc: string of scan ioc  ('29idb:', '29idTest:')
+        BL.mda: scanRecord object of ioc specified by .ioc 
+        
+        BL.xrays: True/False, used for detectors and shutter check
+        BL.mode: 'user' / 'staff', used for detectors and to specifiy folder
+        
+        BL.folder: shorthand for where data is save and used for saveData structure ('b','c','d')
+        BL.prefix: mda prefix (set by endstation)
+
+        BL.log: object of log class which holds logging info
 
     """
 
-    def __init__(self,endstation_name,scan_ioc,xrays,BL_mode,mda_scanRecord=None,Motors=None,log_header=None,log_entries=None):
+    def __init__(self,endstation_name,scan_ioc,xrays,BL_mode,Motors=None):
         """
         intializes the several beamline variables 
 
@@ -40,18 +48,16 @@ class Endstation:
         BL = Endstation()
             BL.endstation => endstation_name
             BL.xrays => True/False 
-            BL.mode => previously: BL_Mode_Set
+            BL.mode => 'user'/'staff' previously: BL_Mode_Set
             BL.folder => 'b','c','d'
             BL.prefix => 'ARPES_','Kappa_'
             BL.ioc => previously: BL_ioc()
-            BL.log_header => dictionary with header list
-            BL.log_entries => method to get pvs to be written to log file
             BL.Motors => motor calls
+
+            intialization does not set default detectors and logging for .mda
             
         """
-        
-        
-
+       
         self.endstation = None
         self.ioc = scan_ioc
         self.folder = None
@@ -62,8 +68,6 @@ class Endstation:
 
         self.mda = ScanRecord(scan_ioc)
         self.Motors = Motors
-        self.log_entries = log_entries
-        self.log_header = log_header
 
         global BL
         endstations_list = ['ARPES','Kappa']   
diff --git a/build/lib/iexcode/instruments/beamline.py b/build/lib/iexcode/instruments/beamline.py
index 2071446..441aaaf 100644
--- a/build/lib/iexcode/instruments/beamline.py
+++ b/build/lib/iexcode/instruments/beamline.py
@@ -4,11 +4,45 @@ short name for functions used with or without x-rays
 
 """
 
+from iexcode.instruments.IEX_endstations import BL
 import numpy as np
 from time import sleep
 
 from epics import PV
-from iexcode.instruments.IEX_endstations import *
+
+
+##############################################################################################################
+##############################             logging           ##############################
+##############################################################################################################
+def log_print(comment=''):
+    """
+    prints a comment to the logfile
+    """
+    global BL
+    try:
+        BL.mda.log.print(comment='')
+    except:
+        print('No logfile written')
+
+def log_update():
+    """
+    updates the log file with the last scan info
+    """
+    global BL
+    try:
+        entry_list,pv_list, format_list = BL.log.entries_function()
+        BL.mda.log.update(entry_list,pv_list,format_list)
+    except:
+        print('No logfile written')
+
+def log_name_set(file_name):
+    global BL
+    try: 
+        BL.mda.log.name_set(filename=file_name)
+    except:
+        print('No logfile name change')
+    
+
 
 
 ##############################################################################################################
diff --git a/build/lib/iexcode/instruments/logfile.py b/build/lib/iexcode/instruments/logfile.py
index b6cf44e..f4a1a97 100644
--- a/build/lib/iexcode/instruments/logfile.py
+++ b/build/lib/iexcode/instruments/logfile.py
@@ -1,169 +1,158 @@
 from os.path import join,isfile
 
 from epics import caget, caput
-#from iexcode.instruments.IEX_endstations import *
-from iexcode.instruments.utilities import today
 
-##############################################################################################################
-##############################             logging           ##############################
-##############################################################################################################
-def log_print(**kwargs):
-    """
-    prints a comment to the logfile
-    """
-    global BL
-    logfile_print(BL.endstation_name,BL.ioc,kwargs['comment'])
-
-def log_update():
-    """
-    updates the log file with the last scan info
-    """
-    global BL
-    try:
-        entry_list,pv_list, format_list = BL.log_entries()
-        logfile_update(BL.endstation_name,BL.ioc,entry_list,pv_list,format_list)
-    except:
-        print('No logfile written')
+from iexcode.instruments.utilities import today
 
+## To do: make this work if User Folder doesn't already exist
 
 ##############################################################################################################
 ##############################            general   logfile functions          ##############################
 ##############################################################################################################
+class Logfile:
+    def __init__(self,endstation_name,user_name,headerlist,entries_function):
+        """
+        endstation: used for filename pv ('ARPES' / 'Kappa' / 'Octupole' / 'Test') 
+        user_name: used for filepath
+        headerlist: header info
+
+        """
+        self.endstation_name = endstation_name
+        self.pv = self._name_pv()
+        self.userName = user_name
+        self.filepath = self._fpath()
+        self.headerlist = headerlist
+        self.entries_function = entries_function
+
+        self.name_set()
+
+    def _name_pv(self):
+        """
+        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',
+            'Octupole':'29idb:userStringSeq10.STR4',
+            }
+        if self.endstation_name in pv_dict.keys():
+            pv=pv_dict[self.endstation_name]
+        else:
+            pv='29idb:userStringSeq10.STR10'
+        return pv
+
+    def name_set(self,**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(self._name_pv(),filename)
+            print("\nLog filename = \'"+filename+"\' @ "+self._name_pv())
+            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 name_get(self):
+        """
+        Gets the string used for the FileName in scanlog and EAlog for the given scanIOC.
 
-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")
+        Previously: logname
+        """
 
+        return caget(self._name_pv())
+       
+    def _fpath(self):
+        """
+        returns the full path to the logfile based on the current user in the mda scanRecord
+
+
+        Previously: logname, logname_generate
+        """
+        try: 
+            filename = self.name_get()
+            user_name = self.userName
+            fpath_with_subfolder = join(user_name,filename)
+        except:
+            fpath_with_subfolder = "logfile.txt"
+            self.name_get()
+            print("Couldn't read log file path, using: "+fpath_with_subfolder)
+            
+        return fpath_with_subfolder
+
+
+    def print(self, 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--------"
         
-def logfile_name_get(endstation_name):
-    """
-    Gets the string used for the FileName in scanlog and EAlog for the given scanIOC.
+        Previously: logprint
+        """
 
-    Previously: logname
-    """
+        try:
+            if not isfile(self.filepath):
+                self.write_header()
+            with open(self.filepath,'a') as myfile:
+                myfile.write(comment)
+                myfile.write('\n')
 
-    return caget(logfile_name_pv(endstation_name))
-       
-def logfile_fpath(endstation_name):
-    """
-    returns the full path to the logfile based on the current user in the mda scanRecord
-
-
-    Previously: logname, logname_generate
-    """
-    global BL
-    try: 
-        filename = logfile_name_get(endstation_name)
-        user_name = BL.mda.scanRecord_user()
-        fpath_with_subfolder = join(user_name,filename)
-    except:
-        fpath_with_subfolder = "logfile.txt"
-        logfile_name_get(endstation_name)
-        print("Couldn't read log file path, using: "+fpath_with_subfolder)
+        except:
+            print("Logprint failed")
+
+
+    def write_header(self): 
+        """
+        file path = path to where file_name lives
+        file_name = name of the logfile
+        entry is a list
+
+        Previously: SaveFile_Header
+        """  
+        version = '1.4'
         
-    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) 
-        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'
-    global BL
-
-    fpath_with_subfolder=logfile_fpath(endstation_name) 
-    with open(fpath_with_subfolder, "w+") as f:
-        f.write('@Log version: '+ version+'\n\n')
-        f.write('FilePath '+endstation_name+': '+fpath_with_subfolder+'\n')
-
-        for key in header_list.keys():
-            f.write(key+' Header:  '+ header_list[key]+'\n\n')
+        with open(self.filepath, "w+") as f:
+            f.write('@Log version: '+ version+'\n\n')
+            f.write('FilePath '+self.endstation_name+': '+self.filepath+'\n')
+
+            for key in self.headerlist.keys():
+                f.write(key+' Header:  '+ self.headerlist[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) 
-    
-    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]))
+    def update(self,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
+        """
+        #entry_list is the human readable portion
+        
+        if not isfile(self.filepath):
+            self.write_header()
+
+        with open(self.filepath, "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/scanRecord.py b/build/lib/iexcode/instruments/scanRecord.py
index c498425..816c10f 100644
--- a/build/lib/iexcode/instruments/scanRecord.py
+++ b/build/lib/iexcode/instruments/scanRecord.py
@@ -5,7 +5,6 @@ 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
 
 
@@ -45,12 +44,13 @@ class ScanRecord:
 
     def __init__(self,scan_ioc,**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
-
+        mda = scanRecord('29idTest:')
+            mda.scan_ioc: full pv for the ioc, "29idARPES:", "29idc:"
+            mda.detector_dictionary: dictionary corresponding to detector num and pv to proc => {det_num:'det_pv'}
+            mda.trigger_dictionary: dictionary corresponding to trigger num and trigger pv => {trigger_num:'trigger_pv'}
+            mda.before_scan_pv: pv to be proc'ed be for the start of a scan
+            mda.after_scan_pv: pv to be proc'ed be for the start of a scan
+            mda.log
         
         **kwargs:
         if a kwargs is not specified then it will not modify that field of the scanRecord
@@ -81,15 +81,23 @@ class ScanRecord:
                     }
         if 'detector_dictionary' in kwargs:
             self.detector_dictionary = kwargs['detector_dictionary']
-
+        else:
+            self.detector_dictionary = {}
+        
         if 'trigger_dictionary' in kwargs:
             self.trigger_dictionary = kwargs['trigger_dictionary']
-        
+        else:
+            self.trigger_dictionary = {}
+
         if 'before_scan_pv' in kwargs:
             self.before_scan_pv = kwargs['before_scan_pv']
+        else:
+            self.before_scan_pv = None
     
         if 'after_scan_pv' in kwargs:
-            self.before_scan_pv = kwargs['after_scan_pv']
+            self.after_scan_pv = kwargs['after_scan_pv']
+        else:
+            self.after_scan_pv = None
 
         if 'default_detector_settling_time' in kwargs:
             self.default_detector_settling_time = kwargs['default_detector_settling_time']
@@ -101,6 +109,10 @@ class ScanRecord:
         else:
             self.default_positioner_settling_time = default_positioner_settling_time
         
+        if 'logging' in kwargs:
+            self.log = kwargs['logging']
+        else:
+            self.log = None
         pass
 
 
@@ -458,7 +470,7 @@ class ScanRecord:
         """
         scan_pv = self.ioc+"scan"+str(scan_dim)
         for det_num in detector_dictionary.keys():
-            det_pv=caget(scan_pv+".D"+det_num+"PV")
+            det_pv=scan_pv+".D"+str(det_num).zfill(2)+"PV"
             caput(det_pv,detector_dictionary[det_num])
 
     def detector_settling_time(self,**kwargs):
@@ -695,7 +707,8 @@ class ScanRecord:
             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
+            if self.log != None:
+                self.log.update() # writes the log file
             print(filename+str(fileNum)+" finished at ", dateandtime())
             print('\n')
             
diff --git a/iexcode/instruments/ARPES.py b/iexcode/instruments/ARPES.py
index e2be0d4..9189eca 100644
--- a/iexcode/instruments/ARPES.py
+++ b/iexcode/instruments/ARPES.py
@@ -8,7 +8,7 @@ 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.logfile import Logfile
 
 from iexcode.instruments.conversions_constants import *
 from iexcode.instruments.utilities import *
@@ -32,8 +32,9 @@ global ARPES_Motors
 
 default_ioc = '29idARPES:'
 #############################################################################
-def ARPES_init(**kwargs):
+def ARPES_init(*userName,**kwargs):
     """
+        user is an optional parameter
         kwargs:
         set_folders: sets the mda and EA folders (default => True)  
         reset: to reset the detectors in the IOC, etc (default => True)  
@@ -54,16 +55,24 @@ def ARPES_init(**kwargs):
 
     #endstation
     global BL
-    BL=Endstation('ARPES',kwargs['scan_ioc'],kwargs['xrays'],kwargs['BL_mode'],ARPES_Motors,ARPES_log_header,ARPES_log_entries)
+    BL=Endstation('ARPES',kwargs['scan_ioc'],kwargs['xrays'],kwargs['BL_mode'],ARPES_Motors)
+    
 
     #setting folders
     if kwargs['set_folders']:
         if BL.mode == 'staff':
             user_name = 'staff'
         else:
-            user_name = input('user name: ')
+            if len(userName)==0:
+                user_name = input('user name: ')
+            else:
+                user_name = userName[0]
+        print(user_name)
         folders_ARPES(user_name,**kwargs)
 
+        #update for default scanRecord advanced parameters
+        BL.mda.log('ARPES',user_name,ARPES_log_header(),ARPES_log_entries)
+
     #EA
     if EA.connected: 
         EA.get()
@@ -202,18 +211,18 @@ def ARPES_reset(**kwargs):
     global BL
     #resetting the scanRecord
     if BL.mode=='staff':
-        detector_dictionary = staff_detector_dictionary()
+        BL.mda.detector_dictionary = staff_detector_dictionary()
     else:
-        detector_dictionary = ARPES_detector_dictionary()
+        BL.mda.detector_dictionary = ARPES_detector_dictionary()
     
-    trigger_dictionary = ARPES_trigger_dictionary(**kwargs)
-    scan_before_sequence = ARPES_scan_before_sequence(**kwargs)
-    scan_after_sequence = ARPES_scan_after_sequence(**kwargs)
+    BL.mda.trigger_dictionary = ARPES_trigger_dictionary(**kwargs)
+    BL.mda.scan_before_sequence = ARPES_scan_before_sequence(**kwargs)
+    BL.mda.scan_after_sequence = ARPES_scan_after_sequence(**kwargs)
     
-    BL.mda.scanRecord.reset_all(detector_dictionary,trigger_dictionary,scan_before_sequence,scan_after_sequence)
+    BL.mda.reset_all()
 
     #resetting the current amplifiers
-    if BL.xray:
+    if BL.xrays:
         ca_reset_all()
     else:
         tey.reset()
@@ -355,12 +364,13 @@ def ARPES_scan_after_sequence(**kwargs):
     kwargs.setdefault('seq_num',10)
     kwargs.setdefault('snake',False)
     kwargs.setdefault('scan_dim',1)
-    seq_num=kwargs['seq_num']
+
+    seq_num = kwargs['seq_num']
+    scan_dim = kwargs['scan_dim']
 
     global BL
     scan_ioc = BL.ioc
-    scan_dim = kwargs[scan_dim]
-
+    
     after_scan_pv,after_scan_proc = userStringSeq_pvs(scan_ioc, seq_num)
     
     #clear and write the after scan user sequence
diff --git a/iexcode/instruments/IEX_endstations.py b/iexcode/instruments/IEX_endstations.py
index e35cc5d..172f212 100644
--- a/iexcode/instruments/IEX_endstations.py
+++ b/iexcode/instruments/IEX_endstations.py
@@ -23,15 +23,23 @@ 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
+    BL = Endstation('ARPES')
+        BL.endstaton: name of endstation  ("ARPES" / "Kappa" / "Octupole")
+        
+        BL.ioc: string of scan ioc  ('29idb:', '29idTest:')
+        BL.mda: scanRecord object of ioc specified by .ioc 
+        
+        BL.xrays: True/False, used for detectors and shutter check
+        BL.mode: 'user' / 'staff', used for detectors and to specifiy folder
+        
+        BL.folder: shorthand for where data is save and used for saveData structure ('b','c','d')
+        BL.prefix: mda prefix (set by endstation)
+
+        BL.log: object of log class which holds logging info
 
     """
 
-    def __init__(self,endstation_name,scan_ioc,xrays,BL_mode,mda_scanRecord=None,Motors=None,log_header=None,log_entries=None):
+    def __init__(self,endstation_name,scan_ioc,xrays,BL_mode,Motors=None):
         """
         intializes the several beamline variables 
 
@@ -40,18 +48,16 @@ class Endstation:
         BL = Endstation()
             BL.endstation => endstation_name
             BL.xrays => True/False 
-            BL.mode => previously: BL_Mode_Set
+            BL.mode => 'user'/'staff' previously: BL_Mode_Set
             BL.folder => 'b','c','d'
             BL.prefix => 'ARPES_','Kappa_'
             BL.ioc => previously: BL_ioc()
-            BL.log_header => dictionary with header list
-            BL.log_entries => method to get pvs to be written to log file
             BL.Motors => motor calls
+
+            intialization does not set default detectors and logging for .mda
             
         """
-        
-        
-
+       
         self.endstation = None
         self.ioc = scan_ioc
         self.folder = None
@@ -62,8 +68,6 @@ class Endstation:
 
         self.mda = ScanRecord(scan_ioc)
         self.Motors = Motors
-        self.log_entries = log_entries
-        self.log_header = log_header
 
         global BL
         endstations_list = ['ARPES','Kappa']   
diff --git a/iexcode/instruments/beamline.py b/iexcode/instruments/beamline.py
index 2071446..441aaaf 100644
--- a/iexcode/instruments/beamline.py
+++ b/iexcode/instruments/beamline.py
@@ -4,11 +4,45 @@ short name for functions used with or without x-rays
 
 """
 
+from iexcode.instruments.IEX_endstations import BL
 import numpy as np
 from time import sleep
 
 from epics import PV
-from iexcode.instruments.IEX_endstations import *
+
+
+##############################################################################################################
+##############################             logging           ##############################
+##############################################################################################################
+def log_print(comment=''):
+    """
+    prints a comment to the logfile
+    """
+    global BL
+    try:
+        BL.mda.log.print(comment='')
+    except:
+        print('No logfile written')
+
+def log_update():
+    """
+    updates the log file with the last scan info
+    """
+    global BL
+    try:
+        entry_list,pv_list, format_list = BL.log.entries_function()
+        BL.mda.log.update(entry_list,pv_list,format_list)
+    except:
+        print('No logfile written')
+
+def log_name_set(file_name):
+    global BL
+    try: 
+        BL.mda.log.name_set(filename=file_name)
+    except:
+        print('No logfile name change')
+    
+
 
 
 ##############################################################################################################
diff --git a/iexcode/instruments/logfile.py b/iexcode/instruments/logfile.py
index b6cf44e..f4a1a97 100644
--- a/iexcode/instruments/logfile.py
+++ b/iexcode/instruments/logfile.py
@@ -1,169 +1,158 @@
 from os.path import join,isfile
 
 from epics import caget, caput
-#from iexcode.instruments.IEX_endstations import *
-from iexcode.instruments.utilities import today
 
-##############################################################################################################
-##############################             logging           ##############################
-##############################################################################################################
-def log_print(**kwargs):
-    """
-    prints a comment to the logfile
-    """
-    global BL
-    logfile_print(BL.endstation_name,BL.ioc,kwargs['comment'])
-
-def log_update():
-    """
-    updates the log file with the last scan info
-    """
-    global BL
-    try:
-        entry_list,pv_list, format_list = BL.log_entries()
-        logfile_update(BL.endstation_name,BL.ioc,entry_list,pv_list,format_list)
-    except:
-        print('No logfile written')
+from iexcode.instruments.utilities import today
 
+## To do: make this work if User Folder doesn't already exist
 
 ##############################################################################################################
 ##############################            general   logfile functions          ##############################
 ##############################################################################################################
+class Logfile:
+    def __init__(self,endstation_name,user_name,headerlist,entries_function):
+        """
+        endstation: used for filename pv ('ARPES' / 'Kappa' / 'Octupole' / 'Test') 
+        user_name: used for filepath
+        headerlist: header info
+
+        """
+        self.endstation_name = endstation_name
+        self.pv = self._name_pv()
+        self.userName = user_name
+        self.filepath = self._fpath()
+        self.headerlist = headerlist
+        self.entries_function = entries_function
+
+        self.name_set()
+
+    def _name_pv(self):
+        """
+        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',
+            'Octupole':'29idb:userStringSeq10.STR4',
+            }
+        if self.endstation_name in pv_dict.keys():
+            pv=pv_dict[self.endstation_name]
+        else:
+            pv='29idb:userStringSeq10.STR10'
+        return pv
+
+    def name_set(self,**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(self._name_pv(),filename)
+            print("\nLog filename = \'"+filename+"\' @ "+self._name_pv())
+            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 name_get(self):
+        """
+        Gets the string used for the FileName in scanlog and EAlog for the given scanIOC.
 
-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")
+        Previously: logname
+        """
 
+        return caget(self._name_pv())
+       
+    def _fpath(self):
+        """
+        returns the full path to the logfile based on the current user in the mda scanRecord
+
+
+        Previously: logname, logname_generate
+        """
+        try: 
+            filename = self.name_get()
+            user_name = self.userName
+            fpath_with_subfolder = join(user_name,filename)
+        except:
+            fpath_with_subfolder = "logfile.txt"
+            self.name_get()
+            print("Couldn't read log file path, using: "+fpath_with_subfolder)
+            
+        return fpath_with_subfolder
+
+
+    def print(self, 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--------"
         
-def logfile_name_get(endstation_name):
-    """
-    Gets the string used for the FileName in scanlog and EAlog for the given scanIOC.
+        Previously: logprint
+        """
 
-    Previously: logname
-    """
+        try:
+            if not isfile(self.filepath):
+                self.write_header()
+            with open(self.filepath,'a') as myfile:
+                myfile.write(comment)
+                myfile.write('\n')
 
-    return caget(logfile_name_pv(endstation_name))
-       
-def logfile_fpath(endstation_name):
-    """
-    returns the full path to the logfile based on the current user in the mda scanRecord
-
-
-    Previously: logname, logname_generate
-    """
-    global BL
-    try: 
-        filename = logfile_name_get(endstation_name)
-        user_name = BL.mda.scanRecord_user()
-        fpath_with_subfolder = join(user_name,filename)
-    except:
-        fpath_with_subfolder = "logfile.txt"
-        logfile_name_get(endstation_name)
-        print("Couldn't read log file path, using: "+fpath_with_subfolder)
+        except:
+            print("Logprint failed")
+
+
+    def write_header(self): 
+        """
+        file path = path to where file_name lives
+        file_name = name of the logfile
+        entry is a list
+
+        Previously: SaveFile_Header
+        """  
+        version = '1.4'
         
-    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) 
-        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'
-    global BL
-
-    fpath_with_subfolder=logfile_fpath(endstation_name) 
-    with open(fpath_with_subfolder, "w+") as f:
-        f.write('@Log version: '+ version+'\n\n')
-        f.write('FilePath '+endstation_name+': '+fpath_with_subfolder+'\n')
-
-        for key in header_list.keys():
-            f.write(key+' Header:  '+ header_list[key]+'\n\n')
+        with open(self.filepath, "w+") as f:
+            f.write('@Log version: '+ version+'\n\n')
+            f.write('FilePath '+self.endstation_name+': '+self.filepath+'\n')
+
+            for key in self.headerlist.keys():
+                f.write(key+' Header:  '+ self.headerlist[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) 
-    
-    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]))
+    def update(self,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
+        """
+        #entry_list is the human readable portion
+        
+        if not isfile(self.filepath):
+            self.write_header()
+
+        with open(self.filepath, "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/iexcode/instruments/scanRecord.py b/iexcode/instruments/scanRecord.py
index c498425..816c10f 100644
--- a/iexcode/instruments/scanRecord.py
+++ b/iexcode/instruments/scanRecord.py
@@ -5,7 +5,6 @@ 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
 
 
@@ -45,12 +44,13 @@ class ScanRecord:
 
     def __init__(self,scan_ioc,**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
-
+        mda = scanRecord('29idTest:')
+            mda.scan_ioc: full pv for the ioc, "29idARPES:", "29idc:"
+            mda.detector_dictionary: dictionary corresponding to detector num and pv to proc => {det_num:'det_pv'}
+            mda.trigger_dictionary: dictionary corresponding to trigger num and trigger pv => {trigger_num:'trigger_pv'}
+            mda.before_scan_pv: pv to be proc'ed be for the start of a scan
+            mda.after_scan_pv: pv to be proc'ed be for the start of a scan
+            mda.log
         
         **kwargs:
         if a kwargs is not specified then it will not modify that field of the scanRecord
@@ -81,15 +81,23 @@ class ScanRecord:
                     }
         if 'detector_dictionary' in kwargs:
             self.detector_dictionary = kwargs['detector_dictionary']
-
+        else:
+            self.detector_dictionary = {}
+        
         if 'trigger_dictionary' in kwargs:
             self.trigger_dictionary = kwargs['trigger_dictionary']
-        
+        else:
+            self.trigger_dictionary = {}
+
         if 'before_scan_pv' in kwargs:
             self.before_scan_pv = kwargs['before_scan_pv']
+        else:
+            self.before_scan_pv = None
     
         if 'after_scan_pv' in kwargs:
-            self.before_scan_pv = kwargs['after_scan_pv']
+            self.after_scan_pv = kwargs['after_scan_pv']
+        else:
+            self.after_scan_pv = None
 
         if 'default_detector_settling_time' in kwargs:
             self.default_detector_settling_time = kwargs['default_detector_settling_time']
@@ -101,6 +109,10 @@ class ScanRecord:
         else:
             self.default_positioner_settling_time = default_positioner_settling_time
         
+        if 'logging' in kwargs:
+            self.log = kwargs['logging']
+        else:
+            self.log = None
         pass
 
 
@@ -458,7 +470,7 @@ class ScanRecord:
         """
         scan_pv = self.ioc+"scan"+str(scan_dim)
         for det_num in detector_dictionary.keys():
-            det_pv=caget(scan_pv+".D"+det_num+"PV")
+            det_pv=scan_pv+".D"+str(det_num).zfill(2)+"PV"
             caput(det_pv,detector_dictionary[det_num])
 
     def detector_settling_time(self,**kwargs):
@@ -695,7 +707,8 @@ class ScanRecord:
             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
+            if self.log != None:
+                self.log.update() # writes the log file
             print(filename+str(fileNum)+" finished at ", dateandtime())
             print('\n')
             
-- 
GitLab