def __init__(self): with safe_load('SmarAct'): self.las1 = SmarActTipTilt(prefix='XCS:MCS2:01', tip_pv=':m1', tilt_pv=':m2', name='las1') self.las2 = SmarActTipTilt(prefix='XCS:MCS2:01', tip_pv=':m4', tilt_pv=':m5', name= 'las2') self.las3 = SmarActTipTilt(prefix='XCS:MCS2:01', tip_pv=':m7', tilt_pv=':m8', name = 'las3') with safe_load('elog'): kwargs = dict() self.elog = HutchELog.from_conf('XCS', **kwargs) with safe_load('cameras'): self. = ImagerHdf5(camviewer.xcs_gige_lj1)
def __init__(self): with safe_load('SmarAct'): self.las1 = SmarActTipTilt(prefix='XCS:MCS2:01', tip_pv=':m1', tilt_pv=':m2', name='las1') self.las2 = SmarActTipTilt(prefix='XCS:MCS2:01', tip_pv=':m4', tilt_pv=':m5', name= 'las2') self.las3 = SmarActTipTilt(prefix='XCS:MCS2:01', tip_pv=':m7', tilt_pv=':m8', name = 'las3') with safe_load('lw9319_piezos'): self.gon_top_x = MMC_Axis('XCS:USR:MMC:01', name='gon_top_x') self.gon_top_y = MMC_Axis('XCS:USR:MMC:02', name='gon_top_y') with safe_load('elog'): kwargs = dict() self.elog = HutchELog.from_conf('XCS', **kwargs) with safe_load('cameras'): self.near_fieldh5 = ImagerHdf5(camviewer.xcs_gige_20) self.intermediate_fieldh5 = ImagerHdf5(getattr(camviewer,'cam-crix-gige-03'))
def load_conf(conf, hutch_dir=None): """ Step through the object loading procedure, given a configuration. The procedure is: - Check the configuration for errors - Display the banner by calling `hutch_banner` - Use ``hutch`` key to create ``hutch.db`` importable namespace to stash the objects. This will be literally ``hutch.db`` if hutch is not provided, or the hutch name e.g. ``mfx.db``. - Create a ``RunEngine``, ``RE`` - Import ``plan_defaults`` and include as ``p``, ``plans`` - Create a ``daq`` object with ``RE`` registered, using ``daq_platform`` to define the ``platform`` argument if provided. The default value if ``daq_platform`` was not defined is 0. - Use ``db`` key to load devices from the ``happi`` beamline database and create a ``hutch_beampath`` object from ``lightpath`` - Use ``load`` key to bring up the user's ``beamline`` modules - Use ``experiment`` key to select the current experiment - If ``experiment`` was missing, autoselect experiment using ``hutch`` key - Use current experiment to load experiment objects from questionnaire - Use current experiment to load experiment file If a conf key is missing, we'll note it in a ``logger.info`` message. If an extra conf entry is found, we'll note it in a ``logger.warning`` message. If an automatically selected file is missing, we'll note it in a ``logger.info`` message. All other errors will be noted in a logger.error message. Parameters ---------- conf: ``dict`` ``dict`` interpretation of the original yaml file hutch_dir: ``Path`` or ``str``, optional ``Path`` object that points to the hutch's launch directory. This is the directory that includes the ``experiments`` directory and a hutchname directory e.g. ``mfx`` If this is missing, we'll be unable to write the ``db.txt`` file, do relative filepath database selection for ``happi``, or establish a preset positions directory. Returns ------ objs: ``dict{str: object}`` See the return value of `load` """ # Warn user about excess config entries for key in conf: if key not in VALID_KEYS: txt = ('Found %s in configuration, but this is not a valid key. ' 'The valid keys are %s') logger.warning(txt, key, VALID_KEYS) # Grab configurations from dict, set defaults, show missing try: hutch = conf['hutch'] if isinstance(hutch, str): hutch = hutch.lower() else: logger.error('Invalid hutch conf %s, must be string.', hutch) hutch = None except KeyError: hutch = None logger.info('Missing hutch from conf. Will skip DAQ.') # Display the banner if hutch is None: hutch_banner() else: hutch_banner(hutch) try: db = conf['db'] if isinstance(db, str): if db[0] == '/': db = Path(db) else: db = Path(hutch_dir) / db else: logger.error('Invalid db conf %s, must be string.', db) db = None except KeyError: db = None logger.info(('Missing db from conf. Will skip loading from shared ' 'database.')) try: load = conf['load'] if not isinstance(load, (str, list)): logger.error('Invalid load conf %s, must be string or list', load) load = None except KeyError: load = None logger.info('Missing load from conf. Will skip loading hutch files.') try: experiment = conf['experiment'] if (not isinstance(experiment, dict) or 'proposal' not in experiment or 'run' not in experiment): logger.error(('Invalid experiment selection %s, must be a dict ' 'with keys "proposal" and "run"'), experiment) experiment = None except KeyError: experiment = None if hutch is None: logger.info(('Missing hutch and experiment from conf. Will not ' 'load objects from questionnaire or experiment ' 'file.')) try: # This is an internal variable here for note-keeping. The ELog uses # this to determine if we are in the secondary or primary DAQ mode default_platform = True platform_info = conf['daq_platform'] hostname = gethostname() try: daq_platform = platform_info[hostname] logger.info('Selected %s daq platform: %s', hostname, daq_platform) default_platform = False except KeyError: daq_platform = platform_info['default'] logger.info('Selected default %s daq platform: %s', hutch, daq_platform) except KeyError: daq_platform = 0 logger.info('Selected default hutch-python daq platform: 0') # Make cache namespace cache = LoadCache((hutch or 'hutch') + '.db', hutch_dir=hutch_dir) # Make RunEngine RE = RunEngine({}) bec = BestEffortCallback() RE.subscribe(bec) cache(RE=RE) try: install_kicker() except RuntimeError: # Probably don't have a display if this failed, so nothing to kick pass # Collect Plans cache(plans=plan_defaults) cache(p=plan_defaults) # Daq with safe_load('daq'): daq_objs = get_daq_objs(daq_platform, RE) cache(**daq_objs) # Happi db and Lightpath if db is not None: with safe_load('database'): happi_objs = get_happi_objs(db, hutch) cache(**happi_objs) bp = get_lightpath(db, hutch) cache(**{"{}_beampath".format(hutch.lower()): bp}) # Elog with safe_load('elog'): # Use the fact if we we used the default_platform or not to decide # whether we are in a specialty station or not if default_platform: logger.debug("Using primary experiment ELog") kwargs = dict() else: logger.info("Configuring ELog to post to secondary experiment") kwargs = {'station': '1'} cache(elog=HutchELog.from_conf(hutch.upper(), **kwargs)) # Load user files if load is not None: load_objs = get_user_objs(load) cache(**load_objs) # Auto select experiment if we need to proposal = None if experiment is None: if hutch is not None: try: # xpplp1216 expname = get_current_experiment(hutch) logger.info('Selected active experiment %s', expname) # lp12 proposal = expname[3:-2] # 16 run = expname[-2:] except Exception: err = 'Failed to select experiment automatically' logger.error(err) logger.debug(err, exc_info=True) # Experiment objects if experiment is not None: proposal = experiment['proposal'] run = experiment['run'] if proposal is not None: qs_objs = get_qs_objs(proposal, run) cache(**qs_objs) user = get_exp_objs(proposal, run) for name, obj in qs_objs.items(): setattr(user, name, obj) cache(x=user, user=user) # Default namespaces with safe_load('default groups'): default_class_namespace('EpicsMotor', 'motors', cache) default_class_namespace('Slits', 'slits', cache) if hutch is not None: tree = tree_namespace(scope='hutch_python.db') # Prune meta, remove branches with only one object for name, space in tree.__dict__.items(): if count_ns_leaves(space) > 1: cache(**{name: space}) all_objs = copy(cache.objs) cache(a=all_objs, all_objects=all_objs) # Install Presets if hutch_dir is not None: with safe_load('position presets'): presets_dir = Path(hutch_dir) / 'presets' beamline_presets = presets_dir / 'beamline' preset_paths = [presets_dir, beamline_presets] if proposal is not None: experiment_presets = presets_dir / (proposal + str(run)) preset_paths.append(experiment_presets) for path in preset_paths: if not path.exists(): path.mkdir() path.chmod(0o777) if proposal is None: setup_preset_paths(hutch=beamline_presets) else: setup_preset_paths(hutch=beamline_presets, exp=experiment_presets) # Write db.txt info file to the user's module try: cache.write_file() except OSError: logger.warning('No permissions to write db.txt file') return cache.objs.__dict__
def load_conf(conf, hutch_dir=None): """ Step through the object loading procedure, given a configuration. The procedure is: - Check the configuration for errors - Display the banner by calling `hutch_banner` - Use ``hutch`` key to create ``hutch.db`` importable namespace to stash the objects. This will be literally ``hutch.db`` if hutch is not provided, or the hutch name e.g. ``mfx.db``. - Create a ``RunEngine``, ``RE`` - Import ``plan_defaults`` and include as ``p``, ``plans`` - Create a ``daq`` object with ``RE`` registered. - Create a ``scan_pvs`` object, and leave it ``disabled``. - Use ``hutch`` and ``daq_platform`` keys to create the ``elog`` object and configure it to match the correct experiment. - Use ``db`` key to load devices from the ``happi`` beamline database and create a ``hutch_beampath`` object from ``lightpath`` - Use ``hutch`` key to load detector objects from the ``camviewer`` configuration file. - Use ``experiment`` key to select the current experiment - If ``experiment`` was missing, autoselect experiment using ``hutch`` key - Use current experiment to load experiment objects from questionnaire - Use ``load`` key to bring up the user's ``beamline`` modules - Use current experiment to load experiment file If a conf key is missing, we'll note it in a ``logger.info`` message. If an extra conf entry is found, we'll note it in a ``logger.warning`` message. If an automatically selected file is missing, we'll note it in a ``logger.info`` message. All other errors will be noted in a logger.error message. Parameters ---------- conf: ``dict`` ``dict`` interpretation of the original yaml file hutch_dir: ``Path`` or ``str``, optional ``Path`` object that points to the hutch's launch directory. This is the directory that includes the ``experiments`` directory and a hutchname directory e.g. ``mfx`` If this is missing, we'll be unable to write the ``db.txt`` file, do relative filepath database selection for ``happi``, or establish a preset positions directory. Returns ------ objs: ``dict{str: object}`` See the return value of `load` """ # Warn user about excess config entries for key in conf: if key not in VALID_KEYS: txt = ('Found %s in configuration, but this is not a valid key. ' 'The valid keys are %s') logger.warning(txt, key, VALID_KEYS) # Grab configurations from dict, set defaults, show missing try: hutch = conf['hutch'] if isinstance(hutch, str): hutch = hutch.lower() else: logger.error('Invalid hutch conf %s, must be string.', hutch) hutch = None except KeyError: hutch = None logger.info(('Missing hutch from conf. Will skip elog ' 'and cameras.')) # Display the banner if hutch is None: hutch_banner() else: hutch_banner(hutch) try: db = conf['db'] if isinstance(db, str): if db[0] == '/': db = Path(db) else: db = Path(hutch_dir) / db else: logger.error('Invalid db conf %s, must be string.', db) db = None except KeyError: db = None logger.info(('Missing db from conf. Will skip loading from shared ' 'database.')) try: load = conf['load'] if not isinstance(load, (str, list)): logger.error('Invalid load conf %s, must be string or list', load) load = None except KeyError: load = None logger.info('Missing load from conf. Will skip loading hutch files.') try: experiment = conf['experiment'] if not isinstance(experiment, str): logger.error( 'Invalid experiment selection %s, must be a string ' 'matching the elog experiment name.', experiment) experiment = None except KeyError: experiment = None if hutch is None: logger.info(('Missing hutch and experiment from conf. Will not ' 'load objects from questionnaire or experiment ' 'file.')) try: # This is an internal variable here for note-keeping. The ELog uses # this to determine if we are in the secondary or primary DAQ mode default_platform = True platform_info = conf['daq_platform'] hostname = gethostname() try: daq_platform = platform_info[hostname] logger.info('Selected %s daq platform: %s', hostname, daq_platform) default_platform = False except KeyError: daq_platform = platform_info['default'] logger.info('Selected default %s daq platform: %s', hutch, daq_platform) except KeyError: daq_platform = 0 logger.info('Selected default hutch-python daq platform: 0') # Make cache namespace cache = LoadCache((hutch or 'hutch') + '.db', hutch_dir=hutch_dir) # Make RunEngine RE = RunEngine({}) initialize_qt_teleporter() bec = BestEffortCallback() RE.subscribe(bec) cache(RE=RE) # Collect Plans cache(bp=plan_defaults.plans) cache(bps=plan_defaults.plan_stubs) cache(bpp=plan_defaults.preprocessors) # Daq with safe_load('daq'): cache(daq=Daq(RE=RE, hutch_name=hutch)) # Scan PVs if hutch is not None: with safe_load('scan_pvs'): scan_pvs = ScanVars('{}:SCAN'.format(hutch.upper()), name='scan_pvs', RE=RE) scan_pvs.enable() cache(scan_pvs=scan_pvs) # Elog if hutch is not None: with safe_load('elog'): # Use the fact if we we used the default_platform or not to decide # whether we are in a specialty station or not if default_platform: logger.debug("Using primary experiment ELog") kwargs = dict() else: logger.info("Configuring ELog to post to secondary experiment") kwargs = {'station': '1'} cache(elog=HutchELog.from_conf(hutch.upper(), **kwargs)) # Shared global devices for LCLS with safe_load('lcls PVs'): cache(**global_devices()) # Happi db and Lightpath if db is not None: with safe_load('database'): happi_objs = get_happi_objs(db, hutch) cache(**happi_objs) bp = get_lightpath(db, hutch) if bp.devices: cache(**{"{}_beampath".format(hutch.lower()): bp}) # ArchApp with safe_load('archapp'): cache(archive=EpicsArchive()) # Camviewer if hutch is not None: with safe_load('camviewer config'): objs = read_camviewer_cfg(CAMVIEWER_CFG.format(hutch)) cache(camviewer=SimpleNamespace(**objs)) # Simulated hardware with safe_load('simulated hardware'): cache(sim=sim.get_hw()) # Auto select experiment if we need to if experiment is None: if hutch is not None: try: # xpplp1216 experiment = get_current_experiment(hutch) logger.info('Selected active experiment %s', experiment) except Exception: err = 'Failed to select experiment automatically' logger.error(err) logger.debug(err, exc_info=True) # Process experiment name a bit if experiment is not None: if hutch in experiment: full_expname = experiment raw_expname = experiment.replace(hutch, '', 1) else: full_expname = hutch + experiment raw_expname = experiment # Load questionnaire if experiment is not None: qs_objs = get_qs_objs(full_expname) cache(**qs_objs) # Load user/beamline files if load is not None: load_objs = get_user_objs(load) cache(**load_objs) # Load experiment file if experiment is not None: user = get_exp_objs(raw_expname) for name, obj in qs_objs.items(): setattr(user, name, obj) cache(x=user, user=user) # Default namespaces with safe_load('default groups'): default_class_namespace('ophyd.PositionerBase', 'motors', cache) default_class_namespace('Slits', 'slits', cache) default_class_namespace('pcdsdaq.ami.AmiDet', 'detectors', cache) # Hotfix/disabled until we fix issues here # Tree namespace can cause havoc and break top-level devices # # if hutch is not None: # tree = tree_namespace(scope='hutch_python.db') # # Prune meta, remove branches with only one object # for name, space in tree.__dict__.items(): # if count_ns_leaves(space) > 1: # cache(**{name: space}) all_objs = copy(cache.objs) cache(a=all_objs, all_objects=all_objs) # Install Presets if hutch_dir is not None: with safe_load('position presets'): presets_dir = Path(hutch_dir) / 'presets' beamline_presets = presets_dir / 'beamline' preset_paths = [presets_dir, beamline_presets] if experiment is not None: experiment_presets = presets_dir / raw_expname preset_paths.append(experiment_presets) for path in preset_paths: if not path.exists(): path.mkdir() path.chmod(0o777) if experiment is None: setup_preset_paths(hutch=beamline_presets) else: setup_preset_paths(hutch=beamline_presets, exp=experiment_presets) # Write db.txt info file to the user's module try: cache.write_file() except OSError: logger.warning('No permissions to write db.txt file') return cache.objs.__dict__