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