def _object_parser(self, input_obj, expect_yml_type): '''a priviate parser for arbitrary object input ''' FEXT = '.yml' e_msg_str_type = '''Can't find your "{} object {}". Please do bt.list() to make sure you type right name'''.format(expect_yml_type, input_obj) e_msg_ind_type = '''Can't find object with index {}. Please do bt.list() to make sure you type correct index'''.format(input_obj) if isinstance(input_obj, str): yml_list = _get_yaml_list() # note: el.split('_', maxsplit=1) = (yml_type, yml_name) yml_name_found = [el for el in yml_list if el.split('_', maxsplit=1)[0] == expect_yml_type and el.split('_', maxsplit=1)[1] == input_obj+FEXT] if yml_name_found: with open(os.path.join(glbl.yaml_dir, yml_name_found[-1]), 'r') as f_out: output_obj = yaml.load(f_out) return output_obj else: # if still can't find it after going over entire list sys.exit(_graceful_exit(e_msg_str_type)) elif isinstance(input_obj, int): try: output_obj = self.get(input_obj) return output_obj except IndexError: sys.exit(_graceful_exit(e_msg_ind_type)) else: # let xpdAcq object validator deal with other cases return input_obj
def _clean_name(name,max_length=25): '''strips a string, but also removes internal whitespace ''' if not isinstance(name,str): sys.exit(_graceful_exit('Your input, {}, appears not to be a string. Please try again'.format(str(name)))) cleaned = "".join(name.split()) if len(cleaned) > max_length: sys.exit(_graceful_exit('Please try a name for your object that is < {} characters long'.format(str(max_length)))) return cleaned
def _scanplan_name_parser(self, sp_name): ''' function to parse name of ScanPlan object into parameters fed into ScanPlan expected format for each type is following: 1) 'ct_10' means Count scan with 10s exposure time in total 2) 'Tramp_10_300_200_5' means temperature ramp from 300k to 200k with 5k step and 10s exposure time each 3) 'tseries_10_60_5' means time series scan of 10s exposure time each scan and run for 5 scans with 60s delay between them. ''' _ct_required_params = ['exposure'] _tseries_required_params = ['exposure', 'delay', 'num'] _Tramp_required_params = ['exposure', 'startingT', 'endingT', 'Tstep'] _ct_optional_params = ['det','subs_dict'] _Tramp_optional_params = ['det', 'subs_dict'] _tseries_optional_params = ['det', 'subs_dict'] parsed_object = sp_name.split('_') # it will split recursively scanplan_type = parsed_object[0] # turn parameters into floats _sp_params = [] for i in range(1, len(parsed_object)): try: _sp_params.append(float(parsed_object[i])) except ValueError: sys.exit(_graceful_exit('''xpdAcq can not parse your positional argument "{}". We use SI units across package, so "5s" or "10k" is not necessary. For more information, please go to http://xpdacq.github.io.\n'''.format(parsed_object[i]))) return # assgin exposure as it is common parameter exposure = _sp_params[0] sp_params = {'exposure':exposure} if scanplan_type not in glbl._allowed_scanplan_type: sys.exit(_graceful_exit('''{} is not a supported ScanPlan type under current version of xpdAcq. Current supported type are {}. Please go to http://xpdacq.github.io for more information or request '''.format(scanplan_type, glbl._allowed_scanplan_type))) if scanplan_type == 'ct' and len(_sp_params) == 1: # exposure return (scanplan_type, sp_params) elif scanplan_type == 'Tramp' and len(_sp_params) == 4: # exposure, startingT, endingT, Tstep sp_params.update({'startingT': _sp_params[1], 'endingT': _sp_params[2], 'Tstep': _sp_params[3]}) return (scanplan_type, sp_params) elif scanplan_type == 'tseries' and len(_sp_params) == 3: # exposure, delay, num sp_params.update({'delay': _sp_params[1], 'num': int(_sp_params[2])}) return (scanplan_type, sp_params) elif scanplan_type == 'bluesky': # leave a hook for future bluesky plan autonaming pass else: sys.exit(_graceful_exit('''xpdAcq can't parse your scanplan name {} into corresponding parameters. Please do ``ScanPlan?`` to find out currently supported conventions. or you can define your scanplan parameter dictionary explicitly. For more information, go to http://xpdacq.github.io '''.format(sp_name)))
def _check_empty_environment(base_dir=None): if base_dir is None: base_dir = glbl.base if os.path.exists(home_dir): if not os.path.isdir(home_dir): sys.exit(_graceful_exit("Expected a folder, got a file. " "Please Talk to beamline staff")) files = os.listdir(home_dir) # that also list dirs that have been created if len(files) > 0: sys.exit(_graceful_exit("Unexpected files in {}, you need to run _end_beamtime(). Please Talk to beamline staff".format(home_dir))) else: sys.exit(_graceful_exit("The xpdUser directory appears not to exist " "Please Talk to beamline staff"))
def _confirm_archive(archive_f_name): print("tarball archived to {}".format(archive_f_name)) conf = _any_input_method(_get_user_confirmation) if conf in ('y','Y'): return else: sys.exit(_graceful_exit('xpdUser directory delete operation cancelled at Users request'))
def _load_bt(bt_yaml_path): btoname = os.path.join(glbl.yaml_dir,'bt_bt.yml') if not os.path.isfile(btoname): sys.exit(_graceful_exit('''{} does not exist in {}. User might have deleted it accidentally. Please create it based on user information or contect user'''.format(os.path.basename(btoname), glbl.yaml_dir))) with open(btoname, 'r') as fi: bto = yaml.load(fi) return bto
def _read_dark_yaml(): dark_yaml_name = glbl.dk_yaml try: with open(dark_yaml_name, 'r') as f: dark_scan_list = yaml.load(f) return dark_scan_list except FileNotFoundError: sys.exit(_graceful_exit('''It seems you haven't initiated your beamtime. Please run _start_beamtime(<your SAF number>) or contact beamline scientist'''))
def _start_beamtime(safn, home_dir=None): ''' priviate function for beamline scientist This function will start a beamtime for user It does following: 1) checks if previous beamtime is properly ended. 2) create default directories 3) instantiate a bt object with information encoded in saf<saf_num>.yml file 4) instantiate lazy user Sample, ScanPlan objects Parameters: ----------- safn : str string to saf number of current beamtime. This function requires to have a `saf<saf_num>.yml' in xpdUser/config_base ''' if home_dir is None: home_dir = glbl.home if not os.path.exists(home_dir): os.makedirs(home_dir) _check_empty_environment() configfile = os.path.join(glbl.xpdconfig, 'saf{}.yml'.format(str(safn))) if os.path.isfile(configfile): with open(configfile, 'r') as fin: setup_dict = yaml.load(fin) else: sys.exit( _graceful_exit( 'the saf config file {} appears to be missing'.format( configfile))) try: piname = setup_dict['PI last name'] safn = setup_dict['saf number'] explist = setup_dict['experimenter list'] except KeyError: sys.exit( _graceful_exit( 'Cannot load input info. File syntax in {} maybe corrupted.'. format(configfile))) bt = _execute_start_beamtime(piname, safn, explist, home_dir=home_dir) _init_dark_yaml() return bt
def _confirm_archive(archive_f_name): print("tarball archived to {}".format(archive_f_name)) conf = _any_input_method(_get_user_confirmation) if conf in ('y', 'Y'): return else: sys.exit( _graceful_exit( 'xpdUser directory delete operation cancelled at Users request' ))
def _check_empty_environment(base_dir=None): if base_dir is None: base_dir = glbl.base if os.path.exists(home_dir): if not os.path.isdir(home_dir): sys.exit( _graceful_exit("Expected a folder, got a file. " "Please Talk to beamline staff")) files = os.listdir( home_dir) # that also list dirs that have been created if len(files) > 0: sys.exit( _graceful_exit( "Unexpected files in {}, you need to run _end_beamtime(). Please Talk to beamline staff" .format(home_dir))) else: sys.exit( _graceful_exit("The xpdUser directory appears not to exist " "Please Talk to beamline staff"))
def _read_dark_yaml(): dark_yaml_name = glbl.dk_yaml try: with open(dark_yaml_name, 'r') as f: dark_scan_list = yaml.load(f) return dark_scan_list except FileNotFoundError: sys.exit( _graceful_exit('''It seems you haven't initiated your beamtime. Please run _start_beamtime(<your SAF number>) or contact beamline scientist''' ))
def _check_empty_environment(base_dir=None): if base_dir is None: base_dir = glbl.base if os.path.exists(home_dir): if not os.path.isdir(home_dir): sys.exit(_graceful_exit("Expected a folder, got a file. " "Please Talk to beamline staff")) files = os.listdir(home_dir) # that also list dirs that have been created if len(files) > 1: sys.exit(_graceful_exit("Unexpected files in {}, you need to run _end_beamtime(). Please Talk to beamline staff".format(home_dir))) elif len(files) == 1: tf, = files if 'tar' not in tf: sys.exit(_graceful_exit("Expected a tarball of some sort, found {} " "Please talk to beamline staff" .format(tf))) os.unlink(os.path.join(home_dir, tf)) else: sys.exit(_graceful_exit("The xpdUser directory appears not to exist " "Please Talk to beamline staff"))
def _load_bt(bt_yaml_path): btoname = os.path.join(glbl.yaml_dir, 'bt_bt.yml') if not os.path.isfile(btoname): sys.exit( _graceful_exit( '''{} does not exist in {}. User might have deleted it accidentally. Please create it based on user information or contect user'''.format( os.path.basename(btoname), glbl.yaml_dir))) with open(btoname, 'r') as fi: bto = yaml.load(fi) return bto
def _end_beamtime(base_dir=None, archive_dir=None, bto=None, usr_confirm='y'): _required_bt_info = ['bt_piLast', 'bt_safN', 'bt_uid'] if archive_dir is None: archive_dir = glbl.archive_dir if base_dir is None: base_dir = glbl.base os.makedirs(glbl.home, exist_ok=True) # check env files = os.listdir(glbl.home) if len(files) == 0: sys.exit( _graceful_exit( 'It appears that end_beamtime may have been run. If so, do not run again but proceed to _start_beamtime' )) # laod bt yaml if not bto: bto = _load_bt(glbl.yaml_dir) try: bt_md = bto.md except AttributeError: # worst situation, user didn't even instantiate bt object with xpdAcq _graceful_exit( '''There is no metadata attribute in beamtime object "{}". User might have gone throgh entirely different workflow. Reconmend to contact user before executing end_beamtime''' ) if 'bt_piLast' in bt_md.keys(): piname = bto.md['bt_piLast'] else: piname = input('Please enter PI last name for this beamtime: ') if 'bt_safN' in bt_md.keys(): safn = bto.md['bt_safN'] else: safn = input('Please enter your SAF number to this beamtime: ') if 'bt_uid' in bt_md.keys(): btuid = bto.md['bt_uid'][:7] else: btuid = '' archive_full_name = _execute_end_beamtime(piname, safn, btuid, base_dir) _confirm_archive(archive_full_name) _delete_home_dir_tree()
def _start_beamtime(safn,home_dir=None): if home_dir is None: home_dir = glbl.home if not os.path.exists(home_dir): os.makedirs(home_dir) _check_empty_environment() configfile = os.path.join(glbl.xpdconfig,'saf{}.yml'.format(str(safn))) if os.path.isfile(configfile): with open(configfile, 'r') as fin: setup_dict = yaml.load(fin) else: sys.exit(_graceful_exit('the saf config file {} appears to be missing'.format(configfile))) try: piname = setup_dict['PI last name'] safn = setup_dict['saf number'] explist = setup_dict['experimenter list'] except KeyError: sys.exit(_graceful_exit('Cannot load input info. File syntax in {} maybe corrupted.'.format(configfile))) bt = _execute_start_beamtime(piname, safn, explist, home_dir=home_dir) _init_dark_yaml() return bt
def _start_beamtime(safn,home_dir=None): ''' priviate function for beamline scientist This function will start a beamtime for user It does following: 1) checks if previous beamtime is properly ended. 2) create default directories 3) instantiate a bt object with information encoded in saf<saf_num>.yml file 4) instantiate lazy user Sample, ScanPlan objects Parameters: ----------- safn : str string to saf number of current beamtime. This function requires to have a `saf<saf_num>.yml' in xpdUser/config_base ''' if home_dir is None: home_dir = glbl.home if not os.path.exists(home_dir): os.makedirs(home_dir) _check_empty_environment() configfile = os.path.join(glbl.xpdconfig,'saf{}.yml'.format(str(safn))) if os.path.isfile(configfile): with open(configfile, 'r') as fin: setup_dict = yaml.load(fin) else: sys.exit(_graceful_exit('the saf config file {} appears to be missing'.format(configfile))) try: piname = setup_dict['PI last name'] safn = setup_dict['saf number'] explist = setup_dict['experimenter list'] except KeyError: sys.exit(_graceful_exit('Cannot load input info. File syntax in {} maybe corrupted.'.format(configfile))) bt = _execute_start_beamtime(piname, safn, explist, home_dir=home_dir) _init_dark_yaml() return bt
def _end_beamtime(base_dir=None,archive_dir=None,bto=None, usr_confirm = 'y'): _required_bt_info = ['bt_piLast', 'bt_safN', 'bt_uid'] if archive_dir is None: archive_dir = glbl.archive_dir if base_dir is None: base_dir = glbl.base os.makedirs(glbl.home, exist_ok = True) # check env files = os.listdir(glbl.home) if len(files)==0: sys.exit(_graceful_exit('It appears that end_beamtime may have been run. If so, do not run again but proceed to _start_beamtime')) # laod bt yaml if not bto: bto = _load_bt(glbl.yaml_dir) try: bt_md = bto.md except AttributeError: # worst situation, user didn't even instantiate bt object with xpdAcq _graceful_exit('''There is no metadata attribute in beamtime object "{}". User might have gone throgh entirely different workflow. Reconmend to contact user before executing end_beamtime''') if 'bt_piLast' in bt_md.keys(): piname = bto.md['bt_piLast'] else: piname = input('Please enter PI last name for this beamtime: ') if 'bt_safN' in bt_md.keys(): safn = bto.md['bt_safN'] else: safn = input('Please enter your SAF number to this beamtime: ') if 'bt_uid' in bt_md.keys(): btuid = bto.md['bt_uid'][:7] else: btuid = '' archive_full_name = _execute_end_beamtime(piname, safn, btuid, base_dir) _confirm_archive(archive_full_name) _delete_home_dir_tree()
def _plan_validator(self): ''' Validator for ScanPlan object It validates if required scan parameters for certain scan type are properly defined in object ''' # based on structures in xpdacq.xpdacq.py _Tramp_required_params = ['startingT', 'endingT', 'Tstep', 'exposure'] _Tramp_optional_params = ['det', 'subs_dict'] _ct_required_params = ['exposure'] _ct_optional_params = ['det','subs_dict'] _tseries_required_params = ['exposure', 'delay', 'num'] if self.scanplan == 'ct': # check missed keys missed_keys = [ el for el in _ct_required_params if el not in self.sp_params] if missed_keys: sys.exit(_graceful_exit('''You are using a "{}" ScanPlan but you missed required parameters: {}'''.format(self.scanplan, missed_keys))) # check value types wrong_type_dict = {} for k,v in self.sp_params.items(): if not isinstance(v,(int,float)): wrong_type_dict.update({k:v}) if wrong_type_dict: sys.exit(_graceful_exit('''You are using a "{}" ScanPlan but following key-value pairs are in correct type(s): {} Please go to http://xpdacq.github.io for more information\n'''. format(self.scanplan, wrong_type_dict))) elif self.scanplan == 'Tramp': # check missed keys missed_keys = [ el for el in _Tramp_required_params if el not in self.sp_params] if missed_keys: sys.exit(_graceful_exit('''You are using a "{}" ScanPlan but you missed required parameters: {}'''.format(self.scanplan, missed_keys))) # check value types wrong_type_dict = {} for k,v in self.sp_params.items(): if not isinstance(v,(int,float)): wrong_type_dict.update({k:v}) if wrong_type_dict: sys.exit(_graceful_exit('''You are using a "{}" ScanPlan but following key-value pairs are in correct type(s): {} Please go to http://xpdacq.github.io for more information\n'''. format(self.scanplan, wrong_type_dict))) elif self.scanplan == 'tseries': # check missed keys missed_keys = [ el for el in _tseries_required_params if el not in self.sp_params] if missed_keys: sys.exit(_graceful_exit('''You are using a "{}" ScanPlan but you missed required parameters: {}'''.format(self.scanplan, missed_keys))) # check value types wrong_type_dict = {} for k,v in self.sp_params.items(): if not isinstance(v,(int,float)): wrong_type_dict.update({k:v}) # num needs to be int if not isinstance(self.sp_params['num'], int): wrong_type_dict.update({'num': self.sp_params.get('num')}) if wrong_type_dict: sys.exit(_graceful_exit('''You are using a "{}" ScanPlan but following key-value pairs are in correct type(s): {} Please go to http://xpdacq.github.io for more information\n'''. format(self.scanplan, wrong_type_dict))) elif self.scanplan == 'bluesky': print('''INFO: You are handing a "bluesky" type scan. Please go to https://nsls-ii.github.io/bluesky/plans.html for complete guide on how to define a plan.''') print('INFO: This ScanPlan does not support auto-dark subtraction') else: print('It seems you are defining an unknown scan') print('Please use uparrow to edit and retry making your ScanPlan object') sys.exit('Please ignore this RunTime error and continue, using the hint above if you like')