diff --git a/eco/acquisition/bs_data.py b/eco/acquisition/bs_data.py index 23354ad..324f906 100755 --- a/eco/acquisition/bs_data.py +++ b/eco/acquisition/bs_data.py @@ -13,8 +13,12 @@ from .utilities import Acquisition class BStools: def __init__( - self, default_channel_list={"listname": []}, default_file_path="%s", elog=None - , name=None): + self, + default_channel_list={"listname": []}, + default_file_path="%s", + elog=None, + name=None, + ): self._default_file_path = default_file_path self._default_channel_list = default_channel_list self._elog = elog @@ -79,9 +83,7 @@ class BStools: path_as_path.parent.mkdir() if not channel_list: - print( - "No channels specified, using all lists instead." - ) + print("No channels specified, using all lists instead.") channel_list = [] for tlist in self._default_channel_list.values(): channel_list.extend(tlist) @@ -95,13 +97,20 @@ class BStools: mode = zmq.SUB try: print(f"message proc is {message_processor}") - receive(source, fina, queue_size=queue_size, mode=mode, n_messages=N_pulses, message_processor=message_processor) + receive( + source, + fina, + queue_size=queue_size, + mode=mode, + n_messages=N_pulses, + message_processor=message_processor, + ) except KeyboardInterrupt: # KeyboardInterrupt is thrown if the receiving is terminated via ctrl+c # As we don't want to see a stacktrace then catch this exception pass finally: - print('Closing stream') + print("Closing stream") dispatcher.remove_stream(source) def db( @@ -153,7 +162,7 @@ class BStools: def acquire(self, file_name=None, Npulses=100): file_name += ".h5" - + if self._default_file_path: file_name = self._default_file_path % file_name diff --git a/eco/acquisition/dia.py b/eco/acquisition/dia.py index c5d4432..c7956a9 100644 --- a/eco/acquisition/dia.py +++ b/eco/acquisition/dia.py @@ -18,12 +18,12 @@ class DIAClient: api_address="http://sf-daq-2:10000", jf_channels=[], n_frames_default=100, - config_default = None, - default_file_path = None + config_default=None, + default_file_path=None, ): if config_default: - for cnf,cnfdict in config_default.items(): - self.__dict__[cnf+'_config'] = cnfdict + for cnf, cnfdict in config_default.items(): + self.__dict__[cnf + "_config"] = cnfdict else: self.writer_config = {} self.backend_config = {} @@ -48,32 +48,36 @@ class DIAClient: if instrument is None: print("ERROR: please configure the instrument parameter in DIAClient") self.update_config() - self.active_clients = list(self.get_active_clients()['clients_enabled'].keys()) - self.jf_channels = list(x for x in self.active_clients if x != 'bsread') + self.active_clients = list(self.get_active_clients()["clients_enabled"].keys()) + self.jf_channels = list(x for x in self.active_clients if x != "bsread") def update_config(self,): - #try: + # try: self.get_last_pedestal() - #except: + # except: # print('Did not find a pedestal file in %s'%(self.pedestal_directory)) - self.writer_config.update({ - "output_file": "/sf/%s/data/p%d/raw/test_data" - % (self.instrument, self.pgroup), - "user_id": self.pgroup, - "n_frames": self.n_frames, - "general/user": str(self.pgroup), - "general/process": __name__, - "general/created": str(datetime.now()), - "general/instrument": self.instrument, - }) + self.writer_config.update( + { + "output_file": "/sf/%s/data/p%d/raw/test_data" + % (self.instrument, self.pgroup), + "user_id": self.pgroup, + "n_frames": self.n_frames, + "general/user": str(self.pgroup), + "general/process": __name__, + "general/created": str(datetime.now()), + "general/instrument": self.instrument, + } + ) - self.backend_config.update({ - "n_frames": self.n_frames, - "bit_depth": 16, - "gain_corrections_filename": self.gain_path, - # FIXME: HARDCODED!!! - "is_HG0": False, - }) + self.backend_config.update( + { + "n_frames": self.n_frames, + "bit_depth": 16, + "gain_corrections_filename": self.gain_path, + # FIXME: HARDCODED!!! + "is_HG0": False, + } + ) if self.pede_file != "": self.backend_config["gain_corrections_filename"] = self.gain_path @@ -89,26 +93,29 @@ class DIAClient: self.backend_config["pede_corrections_filename"] = "" self.backend_config["activate_corrections_preview"] = False - self.detector_config.update({ - "timing": "trigger", - # FIXME: HARDCODED - "exptime": 0.000010, - "cycles": self.n_frames, - # "delay" : 0.001992, - "frames": 1, - "dr": 16, - }) + self.detector_config.update( + { + "timing": "trigger", + # FIXME: HARDCODED + "exptime": 0.000_010, + "cycles": self.n_frames, + # "delay" : 0.001992, + "frames": 1, + "dr": 16, + } + ) - - self.bsread_config.update({ - "output_file": "/sf/%s/data/p%d/raw/test_bsread" - % (self.instrument, self.pgroup), - "user_id": self.pgroup, - "general/user": str(self.pgroup), - "general/process": __name__, - "general/created": str(datetime.now()), - "general/instrument": self.instrument, - }) + self.bsread_config.update( + { + "output_file": "/sf/%s/data/p%d/raw/test_bsread" + % (self.instrument, self.pgroup), + "user_id": self.pgroup, + "general/user": str(self.pgroup), + "general/process": __name__, + "general/created": str(datetime.now()), + "general/instrument": self.instrument, + } + ) # self.default_channels_list = jungfrau_utils.load_default_channel_list() @@ -158,9 +165,10 @@ class DIAClient: sleep(time_interval) def take_pedestal( - self, n_frames=1000, analyze=True, analyze_locally=False, n_bad_modules=0): + self, n_frames=1000, analyze=True, analyze_locally=False, n_bad_modules=0 + ): from jungfrau_utils.scripts.jungfrau_run_pedestals import ( - run as jungfrau_utils_run + run as jungfrau_utils_run, ) directory = "/sf/%s/data/p%d/raw/JF_pedestals/" % (self.instrument, self.pgroup) @@ -186,37 +194,60 @@ class DIAClient: self.instrument, ) if analyze: - pedestals_taken = Path(directory).glob(filename+'*') - print('Analysis of pedestal data is outsourced to batch farm, user credentials required.') - user = input('enter user name for analysis on sf batch farm: ') - commandstr = [f'ssh {user}@sf-cn-1 source /sf/{self.instrument}/bin/anaconda_env'] + pedestals_taken = Path(directory).glob(filename + "*") + print( + "Analysis of pedestal data is outsourced to batch farm, user credentials required." + ) + user = input("enter user name for analysis on sf batch farm: ") + commandstr = [ + f"ssh {user}@sf-cn-1 source /sf/{self.instrument}/bin/anaconda_env" + ] for ped in pedestals_taken: - commandstr.append(f'sbatch jungfrau_create_pedestals --filename {ped.as_posix()} --directory {res_dir} --verbosity 4') - os.system('\;'.join(commandstr)) + commandstr.append( + f"sbatch jungfrau_create_pedestals --filename {ped.as_posix()} --directory {res_dir} --verbosity 4" + ) + os.system("\;".join(commandstr)) def get_last_pedestal(self): - self.active_clients = list(self.get_active_clients()['clients_enabled'].keys()) - self.jf_channels = list(x for x in self.active_clients if x != 'bsread') + self.active_clients = list(self.get_active_clients()["clients_enabled"].keys()) + self.jf_channels = list(x for x in self.active_clients if x != "bsread") p = Path(self.pedestal_directory) - allpedestals = [(datetime.strptime(f.stem.split('pedestal_')[1].split('.')[0],"%Y%m%d_%H%M"),f) for f in p.glob('*.h5')] + allpedestals = [ + ( + datetime.strptime( + f.stem.split("pedestal_")[1].split(".")[0], "%Y%m%d_%H%M" + ), + f, + ) + for f in p.glob("*.h5") + ] completepedestals = [] - for pedtime in set([tt for tt,tf in allpedestals]): - tpedset = [pedtime,[]] + for pedtime in set([tt for tt, tf in allpedestals]): + tpedset = [pedtime, []] try: for channel in self.jf_channels: - tpedset[1].append([tf for tt,tf in allpedestals if (tt==pedtime and channel in tf.as_posix())][0]) - if len(tpedset[1])==len(self.jf_channels): + tpedset[1].append( + [ + tf + for tt, tf in allpedestals + if (tt == pedtime and channel in tf.as_posix()) + ][0] + ) + if len(tpedset[1]) == len(self.jf_channels): completepedestals.append(tpedset) else: - print('Number of pedestal files %4f not number of JFs %4f'%(len(tpedset[1]), len(self.jf_channels))) + print( + "Number of pedestal files %4f not number of JFs %4f" + % (len(tpedset[1]), len(self.jf_channels)) + ) return except: pass - if len(completepedestals)>0: + if len(completepedestals) > 0: f = max(completepedestals)[1][0] - #dtim,f = max((datetime.strptime(f.stem.split('pedestal_')[1].split('.')[0],"%Y%m%d_%H%M"),f) for f in p.glob('*.h5')) - self.pede_file = (f.parent / Path(f.stem.split('.')[0])).as_posix() - + # dtim,f = max((datetime.strptime(f.stem.split('pedestal_')[1].split('.')[0],"%Y%m%d_%H%M"),f) for f in p.glob('*.h5')) + self.pede_file = (f.parent / Path(f.stem.split(".")[0])).as_posix() + def start(self): self.client.start() print("start acquisition") @@ -296,14 +327,14 @@ class DIAClient: if stat["status"] == "IntegrationStatus.DETECTOR_STOPPED": done = True sleep(0.1) - outputfilenames = [f'{file_name_JF}.{tcli.upper()}.h5' for tcli in self.active_clients] + + outputfilenames = [ + f"{file_name_JF}.{tcli.upper()}.h5" for tcli in self.active_clients + ] return Acquisition( acquire=acquire, - acquisition_kwargs={ - "file_names": outputfilenames, - "Npulses": Npulses, - }, + acquisition_kwargs={"file_names": outputfilenames, "Npulses": Npulses}, hold=False, ) diff --git a/eco/acquisition/epics_data.py b/eco/acquisition/epics_data.py index afa2624..1a19184 100644 --- a/eco/acquisition/epics_data.py +++ b/eco/acquisition/epics_data.py @@ -23,12 +23,9 @@ class Epicstools: self._elog = elog self.channels = [] - if not channel_list: - print( - "No channels specified, using all lists instead." - ) + print("No channels specified, using all lists instead.") channel_list = [] for tlist in self._default_channel_list.values(): channel_list.extend(tlist) @@ -37,16 +34,9 @@ class Epicstools: for channel in self.channel_list: self.channels.append(PV(channel)) - def h5( - self, - fina=None, - channel_list=None, - N_pulses=None, - queue_size=100, - ): + def h5(self, fina=None, channel_list=None, N_pulses=None, queue_size=100): channel_list = self.channel_list - if os.path.isfile(fina): print("!!! File %s already exists, would you like to delete it?" % fina) if input("(y/n)") == "y": @@ -83,12 +73,11 @@ class Epicstools: if np.mean(counters) == N_pulses - 1: break - f = h5py.File(name=fina, mode="w") for (n, channel) in enumerate(channel_list): - dat = f.create_group(name = channel) - dat.create_dataset(name = 'data', data=data[n]) - dat.create_dataset(name = 'pulse_id', data = np.arange(N_pulses)) + dat = f.create_group(name=channel) + dat.create_dataset(name="data", data=data[n]) + dat.create_dataset(name="pulse_id", data=np.arange(N_pulses)) return data def acquire(self, file_name=None, Npulses=100, default_path=True): @@ -96,9 +85,11 @@ class Epicstools: if default_path: file_name = self._default_file_path + file_name data_dir = Path(os.path.dirname(file_name)) - + if not data_dir.exists(): - print(f"Path {data_dir.absolute().as_posix()} does not exist, will try to create it...") + print( + f"Path {data_dir.absolute().as_posix()} does not exist, will try to create it..." + ) data_dir.mkdir(parents=True) print(f"Tried to create {data_dir.absolute().as_posix()}") data_dir.chmod(0o775) diff --git a/eco/acquisition/scan.py b/eco/acquisition/scan.py index 406fdae..50b76e3 100755 --- a/eco/acquisition/scan.py +++ b/eco/acquisition/scan.py @@ -19,7 +19,7 @@ class Scan: checker=None, scan_directories=False, callbackStartStep=None, - checker_sleep_time = .2 + checker_sleep_time=0.2, ): self.Nsteps = len(values) self.pulses_per_step = Npulses @@ -48,7 +48,7 @@ class Scan: self.checker = checker self.initial_values = [] self._checker_sleep_time = checker_sleep_time - print(f'Scan info in file {self.scan_info_filename}.') + print(f"Scan info in file {self.scan_info_filename}.") for adj in self.adjustables: tv = adj.get_current_value() self.initial_values.append(adj.get_current_value()) @@ -63,7 +63,7 @@ class Scan: def doNextStep(self, step_info=None, verbose=True): # for call in self.callbacks_start_step: - # call() + # call() if self.checker: while not self.checker.check_now(): print("Condition checker is not happy, waiting for OK conditions.") @@ -159,7 +159,9 @@ class Scans: self.data_base_dir = data_base_dir scan_info_dir = Path(scan_info_dir) if not scan_info_dir.exists(): - print(f"Path {scan_info_dir.absolute().as_posix()} does not exist, will try to create it...") + print( + f"Path {scan_info_dir.absolute().as_posix()} does not exist, will try to create it..." + ) scan_info_dir.mkdir(parents=True) print(f"Tried to create {scan_info_dir.absolute().as_posix()}") scan_info_dir.chmod(0o775) @@ -167,9 +169,11 @@ class Scans: for counter in default_counters: if counter._default_file_path is not None: - data_dir = Path( counter._default_file_path + self.data_base_dir ) + data_dir = Path(counter._default_file_path + self.data_base_dir) if not data_dir.exists(): - print(f"Path {data_dir.absolute().as_posix()} does not exist, will try to create it...") + print( + f"Path {data_dir.absolute().as_posix()} does not exist, will try to create it..." + ) data_dir.mkdir(parents=True) print(f"Tried to create {data_dir.absolute().as_posix()}") data_dir.chmod(0o775) @@ -181,13 +185,37 @@ class Scans: self.checker = checker self._scan_directories = scan_directories - def a2scan(self,adjustable0,start0_pos,end0_pos,adjustable1,start1_pos,end1_pos,N_intervals,N_pulses,file_name=None,counters=[], start_immediately=True, step_info = None): - positions0 = np.linspace(start0_pos,end0_pos,N_intervals+1) - positions1 = np.linspace(start1_pos,end1_pos,N_intervals+1) - values = [[tp0,tp1] for tp0,tp1 in zip(positions0,positions1)] + def a2scan( + self, + adjustable0, + start0_pos, + end0_pos, + adjustable1, + start1_pos, + end1_pos, + N_intervals, + N_pulses, + file_name=None, + counters=[], + start_immediately=True, + step_info=None, + ): + positions0 = np.linspace(start0_pos, end0_pos, N_intervals + 1) + positions1 = np.linspace(start1_pos, end1_pos, N_intervals + 1) + values = [[tp0, tp1] for tp0, tp1 in zip(positions0, positions1)] if not counters: counters = self._default_counters - s = Scan([adjustable0, adjustable1],values,self.counters,file_name,Npulses=N_pulses,basepath=self.data_base_dir,scan_info_dir=self.scan_info_dir,checker=self.checker,scan_directories=self._scan_directories) + s = Scan( + [adjustable0, adjustable1], + values, + self.counters, + file_name, + Npulses=N_pulses, + basepath=self.data_base_dir, + scan_info_dir=self.scan_info_dir, + checker=self.checker, + scan_directories=self._scan_directories, + ) if start_immediately: s.scanAll(step_info=step_info) return s @@ -302,7 +330,9 @@ class RunFilenameGenerator: self.prefix + self.Ndigits * "[0-9]" + self.separator + "*." + self.suffix ) fl = [tf for tf in fl if tf.is_file()] - runnos = [int(tf.name.split(self.prefix)[1].split(self.separator)[0]) for tf in fl] + runnos = [ + int(tf.name.split(self.prefix)[1].split(self.separator)[0]) for tf in fl + ] return runnos def get_nextrun_filename(self, name): diff --git a/eco/aliases/aliases.py b/eco/aliases/aliases.py index 549915d..f7022c0 100644 --- a/eco/aliases/aliases.py +++ b/eco/aliases/aliases.py @@ -53,15 +53,15 @@ def find_aliases(*args): obj = obj.alias return tuple(o) -def append_object_to_object(obj_target,obj_init,*args,name=None,**kwargs): + +def append_object_to_object(obj_target, obj_init, *args, name=None, **kwargs): """append a new object to another object together with the alias. The new object needs to be defined with a name keyword. Theadditional args and kwargs are the expected input for the new opject.""" - obj_target.__dict__[name] = obj_init(*args,**kwargs,name=name) + obj_target.__dict__[name] = obj_init(*args, **kwargs, name=name) obj_target.alias.append(obj_target.__dict__[name].alias) - class Namespace: def __init__(self, namespace_file=None): path = Path(namespace_file) diff --git a/eco/bernina/bernina.py b/eco/bernina/bernina.py index da4c74a..1cf9c28 100644 --- a/eco/bernina/bernina.py +++ b/eco/bernina/bernina.py @@ -5,8 +5,9 @@ from ..aliases import NamespaceCollection import logging from .config import components, config + _namespace = globals() -_scope_name = 'bernina' +_scope_name = "bernina" alias_namespaces = NamespaceCollection() @@ -26,20 +27,13 @@ for key, value in initFromConfigList(components, lazy=ecocnf.startup_lazy).items def initDevice(name): - if name=='all': - logging.info(f'initializing all components from {_scope_name}.') + if name == "all": + logging.info(f"initializing all components from {_scope_name}.") name = list(components.keys()) if not name in components.keys(): - raise KeyError(f'Could not find {name} in configuration!') + raise KeyError(f"Could not find {name} in configuration!") if type(name) is list: for tname in name: initDevice(tname) else: initFromConfigList - - - - - - - diff --git a/eco/bernina/config.py b/eco/bernina/config.py index bdf4420..c4bfa37 100755 --- a/eco/bernina/config.py +++ b/eco/bernina/config.py @@ -37,8 +37,8 @@ components = [ "args": config["path_exp"], "name": "path_exp", "kwargs": {}, - "lazy": False - }, + "lazy": False, + }, { "name": "elog", "type": "eco.utilities.elog:Elog", @@ -146,11 +146,15 @@ components = [ { "name": "xp", "args": [], - "kwargs": {"Id": "SAROP21-OPPI103","evronoff": "SGE-CPCW-72-EVR0:FrontUnivOut15-Ena-SP", "evrsrc": "SGE-CPCW-72-EVR0:FrontUnivOut15-Src-SP"}, + "kwargs": { + "Id": "SAROP21-OPPI103", + "evronoff": "SGE-CPCW-72-EVR0:FrontUnivOut15-Ena-SP", + "evrsrc": "SGE-CPCW-72-EVR0:FrontUnivOut15-Src-SP", + }, "z_und": 103, "desc": "X-ray pulse picker", "type": "eco.xoptics.pp:Pulsepick", - "lazy": False + "lazy": False, }, { "name": "monOpt", @@ -246,7 +250,7 @@ components = [ "z_und": 142, "desc": "General purpose station", "type": "eco.endstations.bernina_diffractometers:GPS", - "kwargs": {"Id": "SARES22-GPS", "configuration": config['gps_config']}, + "kwargs": {"Id": "SARES22-GPS", "configuration": config["gps_config"]}, }, { "args": [], @@ -254,7 +258,7 @@ components = [ "z_und": 142, "desc": "Xray diffractometer", "type": "eco.endstations.bernina_diffractometers:XRD", - "kwargs": {"Id": "SARES21-XRD", "configuration": config['xrd_config']}, + "kwargs": {"Id": "SARES21-XRD", "configuration": config["xrd_config"]}, }, { "args": [], @@ -264,7 +268,7 @@ components = [ "type": "eco.xdiagnostics.profile_monitors:Bernina_XEYE", "kwargs": { "zoomstage_pv": config["xeye"]["zoomstage_pv"], - "camera_pv":config["xeye"]["camera_pv"], + "camera_pv": config["xeye"]["camera_pv"], "bshost": "sf-daqsync-01.psi.ch", "bsport": 11151, }, @@ -278,8 +282,8 @@ components = [ "kwargs": { "bshost": "sf-daqsync-01.psi.ch", "bsport": 11149, - "zoomstage_pv": config['cams_qioptiq']['zoomstage_pv'], - "camera_pv":config["cams_qioptiq"]["camera_pv"], + "zoomstage_pv": config["cams_qioptiq"]["zoomstage_pv"], + "camera_pv": config["cams_qioptiq"]["camera_pv"], }, }, { @@ -291,7 +295,7 @@ components = [ "kwargs": { "bshost": "sf-daqsync-01.psi.ch", "bsport": 11149, - "camera_pv":config["cams_sigma"]["camera_pv"], + "camera_pv": config["cams_sigma"]["camera_pv"], }, }, { @@ -309,7 +313,7 @@ components = [ "desc": "Experiment laser optics", "type": "eco.loptics.bernina_experiment:Laser_Exp", "kwargs": {"Id": "SLAAR21-LMOT", "smar_config": config["las_smar_config"]}, - "lazy":False, + "lazy": False, }, { "args": ["SLAAR21-LTIM01-EVR0"], @@ -334,7 +338,7 @@ components = [ "type": "eco.acquisition.epics_data:Epicstools", "kwargs": { "channel_list": Component("epics_channel_list"), - "default_file_path": f"/sf/bernina/data/{config['pgroup']}/res/epics_daq/", + "default_file_path": f"/sf/bernina/data/{config['pgroup']}/res/epics_daq/", }, }, { @@ -345,20 +349,24 @@ components = [ "kwargs": { "instrument": "bernina", "api_address": config["daq_address"], - "pgroup": config['pgroup'], - 'pedestal_directory':config['jf_pedestal_directory'], - "gain_path": config['jf_gain_path'], - "config_default": config['daq_dia_config'], - 'jf_channels':config['jf_channels'], - "default_file_path": None + "pgroup": config["pgroup"], + "pedestal_directory": config["jf_pedestal_directory"], + "gain_path": config["jf_gain_path"], + "config_default": config["daq_dia_config"], + "jf_channels": config["jf_channels"], + "default_file_path": None, }, }, { - "args": [config['checker_PV'], config['checker_thresholds'], config['checker_fractionInThreshold']], #'SARFE10-PBPG050:HAMP-INTENSITY-CAL',[60,700],.7], + "args": [ + config["checker_PV"], + config["checker_thresholds"], + config["checker_fractionInThreshold"], + ], #'SARFE10-PBPG050:HAMP-INTENSITY-CAL',[60,700],.7], "name": "checker", "desc": "checker functions for data acquisition", "type": "eco.acquisition.checkers:CheckerCA", - "kwargs": {} + "kwargs": {}, }, { "args": [], @@ -391,70 +399,74 @@ components = [ "name": "lxt", "desc": "laser timing with pockels cells and phase shifter", "type": "eco.timing.lasertiming:Lxt", - "kwargs": {} + "kwargs": {}, }, { - "args": ['SAR-CCTA-ESB'], + "args": ["SAR-CCTA-ESB"], "name": "seq", "desc": "sequencer timing application (CTA)", "type": "eco.timing.event_timing:CTA_sequencer", - "kwargs": {} + "kwargs": {}, }, { - "args": ['SIN-TIMAST-TMA'], + "args": ["SIN-TIMAST-TMA"], "name": "event_master", "desc": "SwissFEL timing master information", "type": "eco.timing.event_timing:MasterEventSystem", - "kwargs": {} + "kwargs": {}, }, { - "args": ['SARES20-CVME-01-EVR0'], + "args": ["SARES20-CVME-01-EVR0"], "name": "evr_bernina", "desc": "Bernina event receiver", "type": "eco.timing.event_timing:EventReceiver", "kwargs": {}, - "lazy": False + "lazy": False, }, { - "args": ['/sf/bernina/config/channel_lists/default_channel_list'], + "args": ["/sf/bernina/config/channel_lists/default_channel_list"], "name": "default_channel_list", "desc": "Bernina default channels, used in daq", "type": "eco.utilities.config:parseChannelListFile", "kwargs": {}, - "lazy": False + "lazy": False, }, { - "args": ['/sf/bernina/config/channel_lists/default_channel_list_bs'], + "args": ["/sf/bernina/config/channel_lists/default_channel_list_bs"], "name": "default_channel_list_bs", "desc": "Bernina default bs channels, used by bs_daq", "type": "eco.utilities.config:parseChannelListFile", "kwargs": {}, - "lazy": False + "lazy": False, }, { - "args": ['/sf/bernina/config/channel_lists/channel_list_PSSS_projection'], + "args": ["/sf/bernina/config/channel_lists/channel_list_PSSS_projection"], "name": "channels_spectrometer_projection", "desc": "", "type": "eco.utilities.config:parseChannelListFile", "kwargs": {}, - "lazy": False + "lazy": False, }, { "args": [], "name": "bs_daq", "desc": "bs daq writer (locally!)", "type": "eco.acquisition.bs_data:BStools", - "kwargs": {'default_channel_list':{'bernina_default_channels_bs':Component('default_channel_list_bs')}, "default_file_path": f"/sf/bernina/data/{config['pgroup']}/res/%s"}, - "lazy": False + "kwargs": { + "default_channel_list": { + "bernina_default_channels_bs": Component("default_channel_list_bs") + }, + "default_file_path": f"/sf/bernina/data/{config['pgroup']}/res/%s", + }, + "lazy": False, }, ] try: - components.extend(config['components']) - print('Did append additional components!') + components.extend(config["components"]) + print("Did append additional components!") except: - print('Could not append components from config.') - + print("Could not append components from config.") #### OLD STUFF TO BE TRANSFERRED OR DELETED #### diff --git a/eco/devices_general/adjustable.py b/eco/devices_general/adjustable.py index 6258049..231c2f6 100644 --- a/eco/devices_general/adjustable.py +++ b/eco/devices_general/adjustable.py @@ -6,8 +6,6 @@ from ..aliases import Alias from enum import IntEnum, auto - - # wrappers for adjustables >>>>>>>>>>> def default_representation(Obj): def get_name(Obj): @@ -24,41 +22,46 @@ def default_representation(Obj): return Obj.Id Obj._get_name = get_name - Obj.__repr__ = get_repr + Obj.__repr__ = get_repr return Obj + def spec_convenience(Adj): # spec-inspired convenience methods - def mv(self,value): + def mv(self, value): self._currentChange = self.changeTo(value) return self._currentChange - def wm(self,*args,**kwargs): - return self.get_current_value(*args,**kwargs) - def mvr(self,value,*args,**kwargs): - if hasattr(self,'_currentChange'): - if not self._currentChange.status() == 'done': + + def wm(self, *args, **kwargs): + return self.get_current_value(*args, **kwargs) + + def mvr(self, value, *args, **kwargs): + if hasattr(self, "_currentChange"): + if not self._currentChange.status() == "done": startvalue = self._currentChange.target - elif hasattr(self,'get_moveDone'): - if (self.get_moveDone == 1): - startvalue = self.get_current_value(readback=True,*args,**kwargs) + elif hasattr(self, "get_moveDone"): + if self.get_moveDone == 1: + startvalue = self.get_current_value(readback=True, *args, **kwargs) else: - startvalue = self.get_current_value(*args,**kwargs) - self._currentChange = self.changeTo(value+startvalue,*args,**kwargs) + startvalue = self.get_current_value(*args, **kwargs) + self._currentChange = self.changeTo(value + startvalue, *args, **kwargs) return self._currentChange + def wait(self): self._currentChange.wait() - + def call(self, value): self._currentChange = self.changeTo(value) - Adj.mv = mv - Adj.wm = wm + Adj.mv = mv + Adj.wm = wm Adj.mvr = mvr Adj.wait = wait Adj.__call__ = call return Adj + # wrappers for adjustables <<<<<<<<<<< @@ -69,25 +72,20 @@ def _keywordChecker(kw_key_list_tups): class PvRecord: def __init__( - self, - pvsetname, - pvreadbackname = None, - accuracy = None, - name=None, - elog=None, + self, pvsetname, pvreadbackname=None, accuracy=None, name=None, elog=None ): -# alias_fields={"setpv": pvsetname, "readback": pvreadbackname}, -# ): + # alias_fields={"setpv": pvsetname, "readback": pvreadbackname}, + # ): self.Id = pvsetname self.name = name self.alias = Alias(name) -# for an, af in alias_fields.items(): -# self.alias.append( -# Alias(an, channel=".".join([pvname, af]), channeltype="CA") -# ) + # for an, af in alias_fields.items(): + # self.alias.append( + # Alias(an, channel=".".join([pvname, af]), channeltype="CA") + # ) - self._pv = PV(self.Id) + self._pv = PV(self.Id) self._currentChange = None self.accuracy = accuracy @@ -96,69 +94,68 @@ class PvRecord: else: self._pvreadback = PV(pvreadbackname) - - def get_current_value(self, readback=True,): + def get_current_value(self, readback=True): if readback: currval = self._pvreadback.get() if not readback: currval = self._pv.get() return currval - def get_moveDone(self): """ Adjustable convention""" """ 0: moving 1: move done""" - movedone = 1 + movedone = 1 if self.accuracy is not None: - if( np.abs(self.get_current_value(readback=False)-self.get_current_value(readback=True)) > self.accuracy ): + if ( + np.abs( + self.get_current_value(readback=False) + - self.get_current_value(readback=True) + ) + > self.accuracy + ): movedone = 0 return movedone - - def move(self,value): - self._pv.put(value) + def move(self, value): + self._pv.put(value) time.sleep(0.1) - while( self.get_moveDone() == 0 ): - time.sleep(0.1) - + while self.get_moveDone() == 0: + time.sleep(0.1) def changeTo(self, value, hold=False): """ Adjustable convention""" - changer = lambda value: self.move(\ - value) + changer = lambda value: self.move(value) return Changer( - target=value, - parent=self, - changer=changer, - hold=hold, - stopper=None) - + target=value, parent=self, changer=changer, hold=hold, stopper=None + ) # spec-inspired convenience methods - def mv(self,value): + def mv(self, value): self._currentChange = self.changeTo(value) - def wm(self,*args,**kwargs): - return self.get_current_value(*args,**kwargs) - def mvr(self,value,*args,**kwargs): - if(self.get_moveDone == 1): - startvalue = self.get_current_value(readback=True,*args,**kwargs) + def wm(self, *args, **kwargs): + return self.get_current_value(*args, **kwargs) + + def mvr(self, value, *args, **kwargs): + + if self.get_moveDone == 1: + startvalue = self.get_current_value(readback=True, *args, **kwargs) else: - startvalue = self.get_current_value(readback=False,*args,**kwargs) - self._currentChange = self.changeTo(value+startvalue,*args,**kwargs) + startvalue = self.get_current_value(readback=False, *args, **kwargs) + self._currentChange = self.changeTo(value + startvalue, *args, **kwargs) + def wait(self): self._currentChange.wait() def __repr__(self): - return "%s is at: %s"%(self.Id,self.get_current_value()) - + return "%s is at: %s" % (self.Id, self.get_current_value()) # @default_representation @spec_convenience class PvEnum: - def __init__(self,pvname,name=None): + def __init__(self, pvname, name=None): self.Id = pvname self._pv = PV(pvname) self.name = name @@ -167,15 +164,17 @@ class PvEnum: enumname = self.name else: enumname = self.Id - self.PvEnum = IntEnum(enumname,{tstr:n for n,tstr in enumerate(self.enum_strs)}) - self.alias = Alias(name,channel=self.Id,channeltype='CA') - - def validate(self,value): + self.PvEnum = IntEnum( + enumname, {tstr: n for n, tstr in enumerate(self.enum_strs)} + ) + self.alias = Alias(name, channel=self.Id, channeltype="CA") + + def validate(self, value): if type(value) is str: return self.PvEnum.__members__[value] else: return self.PvEnum(value) - + def get_current_value(self): return self.validate(self._pv.get()) @@ -183,44 +182,47 @@ class PvEnum: """ Adjustable convention""" value = self.validate(value) - changer = lambda value: self._pv.put(value,wait=True) + changer = lambda value: self._pv.put(value, wait=True) return Changer( - target=value, - parent=self, - changer=changer, - hold=hold, - stopper=None) + target=value, parent=self, changer=changer, hold=hold, stopper=None + ) + def __repr__(self): if not self.name: name = self.Id else: name = self.name cv = self.get_current_value() - s = f"{name} (enum) at value: {cv}" +'\n' - s+= "{:<5}{:<5}{:<}\n".format("Num.","Sel.","Name") + s = f"{name} (enum) at value: {cv}" + "\n" + s += "{:<5}{:<5}{:<}\n".format("Num.", "Sel.", "Name") # s+= '_'*40+'\n' - for name,val in self.PvEnum.__members__.items(): - if val==cv: - sel = 'x' + for name, val in self.PvEnum.__members__.items(): + if val == cv: + sel = "x" else: - sel = ' ' - s+= "{:>4} {} {}\n".format(val,sel,name) + sel = " " + s += "{:>4} {} {}\n".format(val, sel, name) return s - - @default_representation @spec_convenience class AdjustableVirtual: - def __init__(self,adjustables,foo_get_current_value,foo_set_target_value,set_current_value=False,name=None): + def __init__( + self, + adjustables, + foo_get_current_value, + foo_set_target_value, + set_current_value=False, + name=None, + ): self.name = name self.alias = Alias(name) for adj in adjustables: try: self.alias.append(adj.alias) except: - print(f'could not find alias in {adj}') + print(f"could not find alias in {adj}") pass self._adjustables = adjustables self._foo_set_target_value = foo_set_target_value @@ -228,45 +230,42 @@ class AdjustableVirtual: self._set_current_value = set_current_value if set_current_value: for adj in self._adjustables: - if not hasattr(adj,'set_current_value'): - raise Exception(f'No set_current_value method found in {adj}') + if not hasattr(adj, "set_current_value"): + raise Exception(f"No set_current_value method found in {adj}") - def changeTo(self,value,hold=False): + def changeTo(self, value, hold=False): vals = self._foo_set_target_value(value) - if not hasattr(vals,'__iter__'): + if not hasattr(vals, "__iter__"): vals = (vals,) + def changer(value): - self._active_changers = [adj.changeTo(val,hold=False) for val,adj in zip(vals,self._adjustables)] + self._active_changers = [ + adj.changeTo(val, hold=False) + for val, adj in zip(vals, self._adjustables) + ] for tc in self._active_changers: tc.wait() + def stopper(): for tc in self._active_changers: tc.stop() - self._currentChange = Changer(target=value,parent=self,changer=changer,hold=hold,stopper=stopper) + + self._currentChange = Changer( + target=value, parent=self, changer=changer, hold=hold, stopper=stopper + ) return self._currentChange def get_current_value(self): - return self._foo_get_current_value(*[adj.get_current_value() for adj in self._adjustables]) + return self._foo_get_current_value( + *[adj.get_current_value() for adj in self._adjustables] + ) - def set_current_value(self,value): + def set_current_value(self, value): if not self._set_current_value: - raise NotImplementedError('There is no value setting implemented for this virtual adjuster!') + raise NotImplementedError( + "There is no value setting implemented for this virtual adjuster!" + ) else: vals = self._foo_set_target_value(value) - for adj,val in zip(self._adjustables,vals): + for adj, val in zip(self._adjustables, vals): adj.set_current_value(val) - - - - - - - - - - - - - - - diff --git a/eco/devices_general/alvradetectors.py b/eco/devices_general/alvradetectors.py index 084e3db..a1f0d45 100755 --- a/eco/devices_general/alvradetectors.py +++ b/eco/devices_general/alvradetectors.py @@ -608,7 +608,7 @@ class DIAClient: self, n_frames, analyze=True, n_bad_modules=0, update_config=True ): from jungfrau_utils.scripts.jungfrau_run_pedestals import ( - run as jungfrau_utils_run + run as jungfrau_utils_run, ) directory = "/sf/%s/data/p%d/raw" % (self.instrument, self.pgroup) diff --git a/eco/devices_general/detectors.py b/eco/devices_general/detectors.py index 1c2da6b..24a2e2d 100755 --- a/eco/devices_general/detectors.py +++ b/eco/devices_general/detectors.py @@ -17,32 +17,38 @@ from ..aliases import Alias class PvDataStream: - def __init__(self,Id,name=None): + def __init__(self, Id, name=None): self.Id = Id self._pv = PV(Id) self.name = name - self.alias = Alias(self.name, channel=self.Id, channeltype='CA') + self.alias = Alias(self.name, channel=self.Id, channeltype="CA") - - def accumulate(self,n_buffer): - self._accumulate = {'n_buffer':n_buffer, 'ix':0, 'n_cb':-1} - self._pv.callbacks.pop(self._accumulate['n_cb'],None) - self._data = np.squeeze(np.zeros([n_buffer*2,self._pv.count]))*np.nan + def accumulate(self, n_buffer): + self._accumulate = {"n_buffer": n_buffer, "ix": 0, "n_cb": -1} + self._pv.callbacks.pop(self._accumulate["n_cb"], None) + self._data = np.squeeze(np.zeros([n_buffer * 2, self._pv.count])) * np.nan def addData(**kw): - self._accumulate['ix'] = (self._accumulate['ix'] + 1) % self._accumulate['n_buffer'] - self._data[self._accumulate['ix']::self._accumulate['n_buffer']] = kw['value'] + self._accumulate["ix"] = (self._accumulate["ix"] + 1) % self._accumulate[ + "n_buffer" + ] + self._data[self._accumulate["ix"] :: self._accumulate["n_buffer"]] = kw[ + "value" + ] - self._accumulate['n_cb'] = self._pv.add_callback(addData) + self._accumulate["n_cb"] = self._pv.add_callback(addData) def get_data(self): - return self._data[self._accumulate['ix']+1:self._accumulate['ix']+1+self._accumulate['n_buffer']] + return self._data[ + self._accumulate["ix"] + + 1 : self._accumulate["ix"] + + 1 + + self._accumulate["n_buffer"] + ] data = property(get_data) - - _cameraArrayTypes = ["monochrome", "rgb"] diff --git a/eco/devices_general/pv_adjustable.py b/eco/devices_general/pv_adjustable.py index 68d71d1..1e3cd44 100644 --- a/eco/devices_general/pv_adjustable.py +++ b/eco/devices_general/pv_adjustable.py @@ -6,29 +6,30 @@ from .utilities import Changer from ..aliases import Alias from time import sleep + class PvRecord: def __init__( self, pvsetname, - pvreadbackname = None, - accuracy = None, - sleeptime = 0, + pvreadbackname=None, + accuracy=None, + sleeptime=0, name=None, elog=None, ): -# alias_fields={"setpv": pvsetname, "readback": pvreadbackname}, -# ): + # alias_fields={"setpv": pvsetname, "readback": pvreadbackname}, + # ): self.Id = pvsetname self.name = name self.alias = Alias(name) self.sleeptime = sleeptime -# for an, af in alias_fields.items(): -# self.alias.append( -# Alias(an, channel=".".join([pvname, af]), channeltype="CA") -# ) + # for an, af in alias_fields.items(): + # self.alias.append( + # Alias(an, channel=".".join([pvname, af]), channeltype="CA") + # ) - self._pv = PV(self.Id) + self._pv = PV(self.Id) self._currentChange = None self.accuracy = accuracy @@ -37,66 +38,61 @@ class PvRecord: else: self._pvreadback = PV(pvreadbackname) - - def get_current_value(self, readback=True,): + def get_current_value(self, readback=True): if readback: currval = self._pvreadback.get() if not readback: currval = self._pv.get() return currval - def get_moveDone(self): """ Adjustable convention""" """ 0: moving 1: move done""" - movedone = 1 + movedone = 1 if self.accuracy is not None: - if( np.abs(self.get_current_value(readback=False)-self.get_current_value(readback=True)) > self.accuracy ): + if ( + np.abs( + self.get_current_value(readback=False) + - self.get_current_value(readback=True) + ) + > self.accuracy + ): movedone = 0 else: sleep(self.sleeptime) return movedone - - def move(self,value): - self._pv.put(value) + def move(self, value): + self._pv.put(value) time.sleep(0.1) - while( self.get_moveDone() == 0 ): - time.sleep(0.1) - + while self.get_moveDone() == 0: + time.sleep(0.1) def changeTo(self, value, hold=False): """ Adjustable convention""" - changer = lambda value: self.move(\ - value) + changer = lambda value: self.move(value) return Changer( - target=value, - parent=self, - changer=changer, - hold=hold, - stopper=None) - + target=value, parent=self, changer=changer, hold=hold, stopper=None + ) # spec-inspired convenience methods - def mv(self,value): + def mv(self, value): self._currentChange = self.changeTo(value) - def wm(self,*args,**kwargs): - return self.get_current_value(*args,**kwargs) - def mvr(self,value,*args,**kwargs): - if(self.get_moveDone == 1): - startvalue = self.get_current_value(readback=True,*args,**kwargs) + def wm(self, *args, **kwargs): + return self.get_current_value(*args, **kwargs) + + def mvr(self, value, *args, **kwargs): + + if self.get_moveDone == 1: + startvalue = self.get_current_value(readback=True, *args, **kwargs) else: - startvalue = self.get_current_value(readback=False,*args,**kwargs) - self._currentChange = self.changeTo(value+startvalue,*args,**kwargs) + startvalue = self.get_current_value(readback=False, *args, **kwargs) + self._currentChange = self.changeTo(value + startvalue, *args, **kwargs) + def wait(self): self._currentChange.wait() def __repr__(self): - return "%s is at: %s"%(self.Id,self.get_current_value()) - - - - - + return "%s is at: %s" % (self.Id, self.get_current_value()) diff --git a/eco/devices_general/smaract.py b/eco/devices_general/smaract.py index 4a65d90..566fc2d 100644 --- a/eco/devices_general/smaract.py +++ b/eco/devices_general/smaract.py @@ -109,8 +109,8 @@ class SmarActRecord: def changer(value): self._status = self.move(value, ignore_limits=(not check), wait=True) self._status_message = _status_messages[self._status] - #if not self._status == 0: - #print(self._status_message) + # if not self._status == 0: + # print(self._status_message) # mover = lambda value: self.move(\ # value, ignore_limits=(not check), @@ -205,15 +205,15 @@ class SmarActRecord: tout = t0 + timeout if wait or confirm_move: while time.time() <= thold and s1 == 3: - ca.poll(evt=1.e-2) + ca.poll(evt=1.0e-2) s1 = self._statusstg.get("VAL") while time.time() <= t1 and s1 == 0: - ca.poll(evt=1.e-2) + ca.poll(evt=1.0e-2) s1 = self._statusstg.get("VAL") if s1 == 4: if wait: while time.time() <= tout and s1 == 4: - ca.poll(evt=1.e-2) + ca.poll(evt=1.0e-2) s1 = self._statusstg.get("VAL") if s1 == 3 or s1 == 4: if time.time() > tout: @@ -225,7 +225,7 @@ class SmarActRecord: and time.time() <= tout and abs(self._rbv.get("VAL") - val) >= twv ): - ca.poll(evt=1.e-2) + ca.poll(evt=1.0e-2) return DONE_OK else: return MOVE_BEGUN_CONFIRMED diff --git a/eco/ecocnf.py b/eco/ecocnf.py index 0114645..ee29cc4 100644 --- a/eco/ecocnf.py +++ b/eco/ecocnf.py @@ -12,10 +12,4 @@ scopes = [ ] - - # settings = Configuration(Path.home() / '.ecorc', name='eco_startup_settings') - - - - diff --git a/eco/endstations/bernina_cameras.py b/eco/endstations/bernina_cameras.py index 1628c99..d1eb92a 100755 --- a/eco/endstations/bernina_cameras.py +++ b/eco/endstations/bernina_cameras.py @@ -1,7 +1,7 @@ from ..devices_general.motors import MotorRecord from ..devices_general.detectors import CameraCA, CameraBS from ..devices_general.adjustable import PvRecord -from ..aliases import Alias,append_object_to_object +from ..aliases import Alias, append_object_to_object # from ..devices_general.epics_wrappers import EnumSelector from epics import PV @@ -12,21 +12,41 @@ def addMotorRecordToSelf(self, Id=None, name=None): self.__dict__[name] = MotorRecord(Id, name=name) self.alias.append(self.__dict__[name].alias) -def addPvRecordToSelf(self, name=None, pvsetname=None, pvreadbackname = None, accuracy = None): - self.__dict__[name] = PvRecord(name=name, pvsetname=pvsetname, pvreadbackname = pvreadbackname , accuracy = accuracy) + +def addPvRecordToSelf( + self, name=None, pvsetname=None, pvreadbackname=None, accuracy=None +): + self.__dict__[name] = PvRecord( + name=name, pvsetname=pvsetname, pvreadbackname=pvreadbackname, accuracy=accuracy + ) self.alias.append(self.__dict__[name].alias) - class Sigma: - def __init__(self, camera_pv=None, zoomstage_pvs = {'set_value':'SARES20-OPSI:MOT_SP','readback':'SEARES20-OPSI:MOT_RB'}, bshost=None, bsport=None, name=None): + def __init__( + self, + camera_pv=None, + zoomstage_pvs={ + "set_value": "SARES20-OPSI:MOT_SP", + "readback": "SEARES20-OPSI:MOT_RB", + }, + bshost=None, + bsport=None, + name=None, + ): self.alias = Alias(name) self.name = name - + append_object_to_object if zoomstage_pvs: - append_object_to_object(self, PvRecord, name="zoom", pvsetname=zoomstage_pvs['set_value'], pvreadbackname = zoomstage_pvs['readback']) + append_object_to_object( + self, + PvRecord, + name="zoom", + pvsetname=zoomstage_pvs["set_value"], + pvreadbackname=zoomstage_pvs["readback"], + ) try: self.cam = CameraCA(camera_pv) @@ -50,15 +70,16 @@ class Sigma: return self.get_adjustable_positions_str() - class Qioptiq: - def __init__(self, camera_pv=None, zoomstage_pv=None, bshost=None, bsport=None, name=None): + def __init__( + self, camera_pv=None, zoomstage_pv=None, bshost=None, bsport=None, name=None + ): self.alias = Alias(name) self.name = name if zoomstage_pv: - append_object_to_object(self,MotorRecord,zoomstage_pv, name="zoom") + append_object_to_object(self, MotorRecord, zoomstage_pv, name="zoom") try: addMotorRecordToSelf(self, Id="SARES20-EXP:MOT_QIOPT_F", name="focus") diff --git a/eco/endstations/bernina_diffractometers.py b/eco/endstations/bernina_diffractometers.py index e5df1d6..48d0b67 100644 --- a/eco/endstations/bernina_diffractometers.py +++ b/eco/endstations/bernina_diffractometers.py @@ -48,7 +48,6 @@ class GPS: self.hex_v = PV("SARES20-HEX_PI:POSI-V") self.hex_w = PV("SARES20-HEX_PI:POSI-W") - if "hlxz" in self.configuration: ### motors heavy load goniometer ### addMotorRecordToSelf(self, Id=Id + ":MOT_TBL_TX", name="xhl") @@ -75,7 +74,7 @@ class GPS: class XRD: - def __init__(self, name=None, Id=None, configuration=['base']): + def __init__(self, name=None, Id=None, configuration=["base"]): """X-ray diffractometer platform in AiwssFEL Bernina.\ : list of elements mounted on the plaform, options are kappa, nutable, hlgonio, polana""" @@ -92,7 +91,6 @@ class XRD: addMotorRecordToSelf(self, Id=Id + ":MOT_RX", name="rxbase") addMotorRecordToSelf(self, Id=Id + ":MOT_MY_RYTH", name="alpha") - if "arm" in self.configuration: ### motors XRD detector arm ### addMotorRecordToSelf(self, Id=Id + ":MOT_NY_RY2TH", name="gamma") diff --git a/eco/loptics/bernina_experiment.py b/eco/loptics/bernina_experiment.py index bbafc85..32c7aee 100755 --- a/eco/loptics/bernina_experiment.py +++ b/eco/loptics/bernina_experiment.py @@ -23,38 +23,52 @@ def addDelayStageToSelf(self, stage=None, name=None): class DelayTime(AdjustableVirtual): - def __init__(self,stage,direction=1,passes=2,set_current_value=True,name=None): + def __init__(self, stage, direction=1, passes=2, set_current_value=True, name=None): self._direction = direction - self._group_velo = 299798458 #m/s + self._group_velo = 299798458 # m/s self._passes = passes - self.Id = stage.Id + '_delay' - AdjustableVirtual.__init__(self,[stage],self._mm_to_s,self._s_to_mm,set_current_value=set_current_value,name=name) + self.Id = stage.Id + "_delay" + AdjustableVirtual.__init__( + self, + [stage], + self._mm_to_s, + self._s_to_mm, + set_current_value=set_current_value, + name=name, + ) - def _mm_to_s(self,mm): - return mm*1e-3*self._passes/self._group_velo*self._direction + def _mm_to_s(self, mm): + return mm * 1e-3 * self._passes / self._group_velo * self._direction + + def _s_to_mm(self, s): + return s * self._group_velo * 1e3 / self._passes * self._direction - def _s_to_mm(self,s): - return s*self._group_velo*1e3/self._passes*self._direction class DelayCompensation(AdjustableVirtual): """Simple virtual adjustable for compensating delay adjustables. It assumes the first adjustable is the master for getting the current value.""" - def __init__(self,adjustables,directions,set_current_value=True,name=None): + + def __init__(self, adjustables, directions, set_current_value=True, name=None): self._directions = directions self.Id = name - AdjustableVirtual.__init__(self,adjustables,self._from_values,self._calc_values,set_current_value=set_current_value,name=name) + AdjustableVirtual.__init__( + self, + adjustables, + self._from_values, + self._calc_values, + set_current_value=set_current_value, + name=name, + ) + def _calc_values(self, value): + return tuple(tdir * value for tdir in self._directions) - def _calc_values(self,value): - return tuple(tdir*value for tdir in self._directions) - - def _from_values(self,*args): - positions = [ta*tdir for ta,tdir in zip(args,self._directions)] + def _from_values(self, *args): + positions = [ta * tdir for ta, tdir in zip(args, self._directions)] return positions[0] - + tuple(tdir * value for tdir in self._directions) - tuple(tdir*value for tdir in self._directions) class Laser_Exp: def __init__(self, Id=None, name=None, smar_config=None): @@ -70,10 +84,12 @@ class Laser_Exp: addMotorRecordToSelf(self, self.Id + "-M534:MOT", name="pump_wp") addMotorRecordToSelf(self, self.Id + "-M533:MOT", name="tt_wp") except: - print('No wp found') + print("No wp found") try: - addMotorRecordToSelf(self, Id=self.Id + "-M521:MOTOR_1", name="_pump_delaystg") + addMotorRecordToSelf( + self, Id=self.Id + "-M521:MOTOR_1", name="_pump_delaystg" + ) addDelayStageToSelf( self, stage=self.__dict__["_pump_delaystg"], name="pump_delay" ) @@ -82,20 +98,18 @@ class Laser_Exp: print(expt) # try: - addMotorRecordToSelf( - self, Id=self.Id + "-M521:MOTOR_1", name="delay_eos_stg" - ) - self.delay_eos = DelayTime(self.delay_eos_stg,name="delay_eos") + addMotorRecordToSelf(self, Id=self.Id + "-M521:MOTOR_1", name="delay_eos_stg") + self.delay_eos = DelayTime(self.delay_eos_stg, name="delay_eos") self.alias.append(self.delay_eos.alias) # except Exception as expt: - # print("Problems initializing eos delay stage") - # print(expt) + # print("Problems initializing eos delay stage") + # print(expt) try: addMotorRecordToSelf( self, Id=self.Id + "-M522:MOTOR_1", name="delay_tt_stg" ) - self.delay_tt = DelayTime(self.delay_tt_stg,name="delay_tt") + self.delay_tt = DelayTime(self.delay_tt_stg, name="delay_tt") self.alias.append(self.delay_tt.alias) except: print("Problems initializing global delay stage") @@ -103,15 +117,17 @@ class Laser_Exp: addMotorRecordToSelf( self, Id=self.Id + "-M523:MOTOR_1", name="delay_glob_stg" ) - self.delay_glob = DelayTime(self.delay_glob_stg,name="delay_glob") + self.delay_glob = DelayTime(self.delay_glob_stg, name="delay_glob") self.alias.append(self.delay_glob.alias) except: print("Problems initializing global delay stage") - - # Implementation of delay compensation, this assumes for now that delays_glob and delay_tt actually delay in positive directions. - self.delay_lxtt = DelayCompensation([self.delay_glob,self.delay_tt], [1,-1],name='delay_lxtt') + + # Implementation of delay compensation, this assumes for now that delays_glob and delay_tt actually delay in positive directions. + self.delay_lxtt = DelayCompensation( + [self.delay_glob, self.delay_tt], [1, -1], name="delay_lxtt" + ) self.alias.append(self.delay_lxtt.alias) - + # compressor addMotorRecordToSelf(self, Id=self.Id + "-M532:MOT", name="compressor") # self.compressor = MotorRecord(Id+'-M532:MOT') @@ -144,9 +160,13 @@ class Laser_Exp: for smar_name, smar_address in self.smar_config.items(): try: - addSmarActRecordToSelf(self, Id=(self.IdSA + smar_address), name=smar_name) + addSmarActRecordToSelf( + self, Id=(self.IdSA + smar_address), name=smar_name + ) except: - print("Loading %s SmarAct motor in bernina laser conifg failed")%(smar_name) + print("Loading %s SmarAct motor in bernina laser conifg failed") % ( + smar_name + ) pass def get_adjustable_positions_str(self): @@ -161,6 +181,7 @@ class Laser_Exp: def __repr__(self): return self.get_adjustable_positions_str() + class Laser_Exp_old: def __init__(self, Id=None, name=None, smar_config=None): self.Id = Id @@ -175,10 +196,12 @@ class Laser_Exp_old: addMotorRecordToSelf(self, self.Id + "-M534:MOT", name="pump_wp") addMotorRecordToSelf(self, self.Id + "-M533:MOT", name="tt_wp") except: - print('No wp found') + print("No wp found") try: - addMotorRecordToSelf(self, Id=self.Id + "-M521:MOTOR_1", name="_pump_delaystg") + addMotorRecordToSelf( + self, Id=self.Id + "-M521:MOTOR_1", name="_pump_delaystg" + ) addDelayStageToSelf( self, stage=self.__dict__["_pump_delaystg"], name="pump_delay" ) @@ -189,21 +212,15 @@ class Laser_Exp_old: addMotorRecordToSelf( self, Id=self.Id + "-M522:MOTOR_1", name="_tt_delaystg" ) - addDelayStageToSelf( - self, self.__dict__["_tt_delaystg"], name="tt_delay" - ) + addDelayStageToSelf(self, self.__dict__["_tt_delaystg"], name="tt_delay") # addDelayStageToSelf(self,self.__dict__["_thz_delaystg"], name="thz_delay") except: print("No thz delay stage") pass try: - addMotorRecordToSelf( - self, Id=self.Id + "-M553:MOT", name="_exp_delaystg" - ) - addDelayStageToSelf( - self, self.__dict__["_exp_delaystg"], name="exp_delay" - ) + addMotorRecordToSelf(self, Id=self.Id + "-M553:MOT", name="_exp_delaystg") + addDelayStageToSelf(self, self.__dict__["_exp_delaystg"], name="exp_delay") # addDelayStageToSelf(self,self.__dict__["_thz_delaystg"], name="thz_delay") except: print("No thz delay stage") @@ -240,9 +257,13 @@ class Laser_Exp_old: for smar_name, smar_address in self.smar_config.items(): try: - addSmarActRecordToSelf(self, Id=(self.IdSA + smar_address), name=smar_name) + addSmarActRecordToSelf( + self, Id=(self.IdSA + smar_address), name=smar_name + ) except: - print("Loading %s SmarAct motor in bernina laser conifg failed")%(smar_name) + print("Loading %s SmarAct motor in bernina laser conifg failed") % ( + smar_name + ) pass def get_adjustable_positions_str(self): diff --git a/eco/timing/event_timing.py b/eco/timing/event_timing.py index 686caf3..eee1fd6 100644 --- a/eco/timing/event_timing.py +++ b/eco/timing/event_timing.py @@ -99,33 +99,35 @@ eventcodes = [ 47, 48, 49, - 50 + 50, ] event_code_delays_fix = { - 200: 100, - 201: 107, - 202: 114, - 203: 121, - 204: 128, - 205: 135, - 206: 142, - 207: 149, - 208: 156, - 209: 163, - 210: 170, - 211: 177, - 212: 184, - 213: 191, - 214: 198, - 215: 205, - 216: 212, - 217: 219, - 218: 226, - 219: 233} + 200: 100, + 201: 107, + 202: 114, + 203: 121, + 204: 128, + 205: 135, + 206: 142, + 207: 149, + 208: 156, + 209: 163, + 210: 170, + 211: 177, + 212: 184, + 213: 191, + 214: 198, + 215: 205, + 216: 212, + 217: 219, + 218: 226, + 219: 233, +} tim_tick = 7e-9 + class MasterEventSystem: def __init__(self, pvname, name=None): self.name = name @@ -151,7 +153,7 @@ class MasterEventSystem: if inticks: return self._get_pv(f"{self.pvname}:Evt-{intId}-Delay-RB.A").get() else: - return self._get_pv(f"{self.pvname}:Evt-{intId}-Delay-RB").get() / 1000000 + return self._get_pv(f"{self.pvname}:Evt-{intId}-Delay-RB").get() / 1_000_000 def _get_Id_description(self, intId): return self._get_pv(f"{self.pvname}:Evt-{intId}.DESC").get() @@ -166,7 +168,7 @@ class MasterEventSystem: def get_evtcode_delay(self, evtcode, **kwargs): if evtcode in event_code_delays_fix.keys(): - return event_code_delays_fix[evtcode]*tim_tick + return event_code_delays_fix[evtcode] * tim_tick Id = self._get_evtcode_Id(evtcode) return self._get_Id_delay(Id, **kwargs) @@ -190,7 +192,7 @@ class EvrPulser: self.pv_base = pv_base self.name = name self._pvs = {} - self.polarity = PvEnum(f"{self.pv_base}-Polarity-Sel",name='polarity') + self.polarity = PvEnum(f"{self.pv_base}-Polarity-Sel", name="polarity") def _get_pv(self, pvname): if not pvname in self._pvs: @@ -226,52 +228,59 @@ class EvrPulser: return self._get_pv(f"{self.pv_base}-Polarity-Sel").put(value) - - class EvrOutput: def __init__(self, pv_base, name=None): self.pv_base = pv_base self.name = name self._pulsers = None # self._update_connected_pulsers() - self.pulsers_numbers = (PvEnum(f'{self.pv_base}_SNUMPD',name='pulserA'),PvEnum(f'{self.pv_base}_SNUMPD2',name='pulserB')) + self.pulsers_numbers = ( + PvEnum(f"{self.pv_base}_SNUMPD", name="pulserA"), + PvEnum(f"{self.pv_base}_SNUMPD2", name="pulserB"), + ) def _get_pulserA(self): return self._pulsers[self.pulsers_numbers[0].get_current_value()] + pulserA = property(_get_pulserA) def _get_pulserB(self): return self._pulsers[self.pulsers_numbers[1].get_current_value()] + pulserB = property(_get_pulserB) - - def _get_pv(self,pvname): + + def _get_pv(self, pvname): if not pvname in self._pvs: self._pvs[pvname] = PV(pvname) return self._pvs[pvname] # def _update_connected_pulsers(self): - # self._get_pv() + # self._get_pv() - # self.pulsers = () + # self.pulsers = () def get_status(self): pass + class EventReceiver: - def __init__(self, pvname, n_pulsers=24, n_output_front=8, n_output_rear=16, name=None): + def __init__( + self, pvname, n_pulsers=24, n_output_front=8, n_output_rear=16, name=None + ): self.name = name self.pvname = pvname pulsers = [] for n in range(n_pulsers): - pulsers.append(EvrPulser(f'{self.pvname}:Pul{n}')) + pulsers.append(EvrPulser(f"{self.pvname}:Pul{n}")) self.pulsers = tuple(pulsers) outputs = [] for n in range(n_output_front): - outputs.append(EvrOutput(f'{self.pvname}:FrontUnivOut{n}',name=f'output_front{n}')) + outputs.append( + EvrOutput(f"{self.pvname}:FrontUnivOut{n}", name=f"output_front{n}") + ) for to in outputs: to._pulsers = self.pulsers self.outputs = outputs - class CTA_sequencer: @@ -280,7 +289,6 @@ class CTA_sequencer: self.sequence_local = {} self.synced = False self._master_frequency = master_frequency - def get_active_sequence(self): self.sequence_local = self._cta.download() @@ -290,57 +298,59 @@ class CTA_sequencer: def upload_local_sequence(self): self._cta.upload(self.sequence_local) - def get_start_config(self,set_params=True): + def get_start_config(self, set_params=True): cfg = self._cta.get_start_config() if set_params: - self._start_immediately = cfg['mode'] - self.start_divisor = cfg['divisor'] - self.start_offset = cfg['offset'] + self._start_immediately = cfg["mode"] + self.start_divisor = cfg["divisor"] + self.start_offset = cfg["offset"] else: return cfg - def set_start_config(self,divisor, offset): - if divisor==1 and offset ==0: + def set_start_config(self, divisor, offset): + if divisor == 1 and offset == 0: mode = 0 else: mode = 1 - self._cta.set_start_config(config={'mode':self._cta.StartMode(mode), 'modulo':divisor, 'offset':offset}) + self._cta.set_start_config( + config={ + "mode": self._cta.StartMode(mode), + "modulo": divisor, + "offset": offset, + } + ) def reset_local_sequence(self): self.sequence_local = {} self.length = 0 self.synced = False - def append_singlecode(self,code,pulse_delay): + def append_singlecode(self, code, pulse_delay): if self.length == 0: self.length = 1 if not code in self.sequence_local.keys(): self.sequence_local[code] = self.length * [0] self.length += pulse_delay for tc in self.sequence_local.keys(): - self.sequence_local[tc].extend(pulse_delay*[0]) - self.sequence_local[code][self.length-1] = 1 + self.sequence_local[tc].extend(pulse_delay * [0]) + self.sequence_local[code][self.length - 1] = 1 self.synced = False - def set_repetitions(self,n_rep): + def set_repetitions(self, n_rep): """Set the number of sequence repetitions, 0 is infinite repetitions""" - ntim = int(n_rep>0) - self._cta.set_repetition_config(config={'mode': ntim, 'n': n_rep}) - + ntim = int(n_rep > 0) + self._cta.set_repetition_config(config={"mode": ntim, "n": n_rep}) + def get_repetitions(self): """Get the number of sequence repetitions, 0 is infinite repetitions""" repc = self._cta.get_repetition_config() - if repc['mode']==0: + if repc["mode"] == 0: return 0 else: - return repc['n'] - + return repc["n"] def start(self): self._cta.start() def stop(self): self._cta.stop() - - - diff --git a/eco/tools/screen_panel.py b/eco/tools/screen_panel.py index 55f1ad0..78a2f8d 100644 --- a/eco/tools/screen_panel.py +++ b/eco/tools/screen_panel.py @@ -4,33 +4,39 @@ import signal from subprocess import Popen, PIPE, STDOUT - class ScreenPanel: - def __init__(self,name=None): + def __init__(self, name=None): self.name = name self._proc = None @property def proc(self): if not self._proc: - if input("No screenpanel running, would you like to start now? (y/n)\n").strip()=='y': + if ( + input( + "No screenpanel running, would you like to start now? (y/n)\n" + ).strip() + == "y" + ): self.start() return self._proc def start(self): if self._proc: - print(f'Sreenpanel {self.name} is already running') + print(f"Sreenpanel {self.name} is already running") else: # self.proc = subprocess.Popen(["screen_panel","-console"],stdout=subprocess.PIPE) - self._proc = Popen(["bash", "screen_panel", "-console", "-persist"], stdin=PIPE, stdout=PIPE, preexec_fn=os.setsid) + self._proc = Popen( + ["bash", "screen_panel", "-console", "-persist"], + stdin=PIPE, + stdout=PIPE, + preexec_fn=os.setsid, + ) def quit(self): os.killpg(self.proc.pid, signal.SIGTERM) self._proc = None def set_camera(self, camera_name): - self.proc.stdin.write(('cam ' + camera_name + "\n").encode()) + self.proc.stdin.write(("cam " + camera_name + "\n").encode()) self.proc.stdin.flush() - - - diff --git a/eco/utilities/config.py b/eco/utilities/config.py index 2523264..e4a7ac3 100644 --- a/eco/utilities/config.py +++ b/eco/utilities/config.py @@ -62,6 +62,7 @@ def get_dependencies(inp): outp.append(get_dependencies(ta)) return outp + def replaceComponent(inp, dict_all): if isinstance(inp, list): outp = [] @@ -85,6 +86,7 @@ def replaceComponent(inp, dict_all): return inp return outp + def initFromConfigList(config_list, lazy=False): op = {} for td in config_list: @@ -94,7 +96,7 @@ def initFromConfigList(config_list, lazy=False): # for tkwk, tkwv in td["kwargs"].items() # } try: - tlazy = td['lazy'] + tlazy = td["lazy"] except: tlazy = lazy op[td["name"]] = init_device( @@ -151,7 +153,7 @@ class Configuration: return list(self._config.keys()) def __repr__(self): - return json.dumps(self._config,indent=4) + return json.dumps(self._config, indent=4) def loadConfig(fina): @@ -161,7 +163,7 @@ def loadConfig(fina): def writeConfig(fina, obj): with open(fina, "w") as f: - json.dump(obj, f,indent=4) + json.dump(obj, f, indent=4) def parseChannelListFile(fina): @@ -183,6 +185,7 @@ def append_to_path(*args): for targ in args: sys.path.append(targ) + def prepend_to_path(*args): for targ in args: - sys.path.insert(0,targ) + sys.path.insert(0, targ) diff --git a/eco/xdiagnostics/intensity_monitors.py b/eco/xdiagnostics/intensity_monitors.py index 4cdec23..411683e 100755 --- a/eco/xdiagnostics/intensity_monitors.py +++ b/eco/xdiagnostics/intensity_monitors.py @@ -4,6 +4,7 @@ from ..devices_general.detectors import FeDigitizer from ..devices_general.adjustable import PvEnum from ..aliases import Alias + class GasDetector: def __init__(self): pass @@ -20,14 +21,14 @@ class SolidTargetDetectorPBPS: ch_left=15, ch_right=14, elog=None, - name=None + name=None, ): self.Id = Id self.name = name - self.diode_x = MotorRecord(Id + ":MOTOR_X1", name='diode_x') - self.diode_y = MotorRecord(Id + ":MOTOR_Y1", name='diode_y') - self.target_pos = MotorRecord(Id + ":MOTOR_PROBE", name='target_pos') - self.target = PvEnum(Id + ":PROBE_SP", name='target') + self.diode_x = MotorRecord(Id + ":MOTOR_X1", name="diode_x") + self.diode_y = MotorRecord(Id + ":MOTOR_Y1", name="diode_y") + self.target_pos = MotorRecord(Id + ":MOTOR_PROBE", name="target_pos") + self.target = PvEnum(Id + ":PROBE_SP", name="target") if VME_crate: self.diode_up = FeDigitizer("%s:Lnk%dCh%d" % (VME_crate, link, ch_up)) self.diode_down = FeDigitizer("%s:Lnk%dCh%d" % (VME_crate, link, ch_down)) @@ -58,7 +59,7 @@ class SolidTargetDetectorPBPS: sd += " - Diode down: %i\n" % (sdelf.diode_down.gain.get()) sd += " - Diode left: %i\n" % (sdelf.diode_left.gain.get()) sd += " - Diode right: %i\n" % (sdelf.diode_right.gain.get()) - s+=sd + s += sd except: pass return s diff --git a/eco/xdiagnostics/profile_monitors.py b/eco/xdiagnostics/profile_monitors.py index 4fcd504..908373f 100755 --- a/eco/xdiagnostics/profile_monitors.py +++ b/eco/xdiagnostics/profile_monitors.py @@ -17,10 +17,10 @@ class Pprm: def __init__(self, Id, name=None): self.Id = Id self.name = name - self.target_pos = MotorRecord(Id + ":MOTOR_PROBE",name='target_pos') + self.target_pos = MotorRecord(Id + ":MOTOR_PROBE", name="target_pos") self.cam = CameraCA(Id) - self.led = PvEnum(self.Id + ":LED",name='led') - self.target = PvEnum(self.Id + ":PROBE_SP", name='target') + self.led = PvEnum(self.Id + ":LED", name="led") + self.target = PvEnum(self.Id + ":PROBE_SP", name="target") if name: self.alias = Alias(name) self.alias.append(self.target_pos.alias) @@ -33,7 +33,6 @@ class Pprm: def moveout(self, target=0): self.target.changeTo(target) - def __repr__(self): s = f"**Profile Monitor {self.name}**\n" s += f"Target in beam: {self.target.get_current_value().name}\n" @@ -41,11 +40,13 @@ class Pprm: class Bernina_XEYE: - def __init__(self, camera_pv=None, zoomstage_pv=None,bshost=None, bsport=None, name=None): + def __init__( + self, camera_pv=None, zoomstage_pv=None, bshost=None, bsport=None, name=None + ): self.alias = Alias(name) self.name = name if zoomstage_pv: - append_object_to_object(self,MotorRecord,zoomstage_pv,name='zoom') + append_object_to_object(self, MotorRecord, zoomstage_pv, name="zoom") try: self.cam = CameraCA(camera_pv) except: diff --git a/eco/xoptics/attenuator_aramis.py b/eco/xoptics/attenuator_aramis.py index 4c28eb2..6497140 100755 --- a/eco/xoptics/attenuator_aramis.py +++ b/eco/xoptics/attenuator_aramis.py @@ -6,7 +6,7 @@ from ..devices_general.adjustable import PvEnum class AttenuatorAramis: - def __init__(self, Id, E_min=1500, sleeptime=1, name=None, set_limits=[-52,2]): + def __init__(self, Id, E_min=1500, sleeptime=1, name=None, set_limits=[-52, 2]): self.Id = Id self.E_min = E_min self._pv_status_str = PV(self.Id + ":MOT2TRANS.VALD") @@ -14,15 +14,16 @@ class AttenuatorAramis: self._sleeptime = sleeptime self.name = name self.alias = Alias(name) - self.motors = [MotorRecord(f'SAROP21-OATT135:MOTOR_{n+1}',name=f'motor{n+1}') for n in range(6)] - for n,mot in enumerate(self.motors): - self.__dict__[f'motor_{n+1}'] = mot + self.motors = [ + MotorRecord(f"SAROP21-OATT135:MOTOR_{n+1}", name=f"motor{n+1}") + for n in range(6) + ] + for n, mot in enumerate(self.motors): + self.__dict__[f"motor_{n+1}"] = mot self.alias.append(mot.alias) if set_limits: mot.set_limits(set_limits) - - def __str__(self): pass @@ -35,7 +36,9 @@ class AttenuatorAramis: energy = energy * 1000 if energy < self.E_min: energy = None - print(f'Machine photon energy is below {self.E_min} - waiting for the machine to recover') + print( + f"Machine photon energy is below {self.E_min} - waiting for the machine to recover" + ) sleep(self._sleeptime) PV(self.Id + ":ENERGY").put(energy) print("Set energy to %s eV" % energy) diff --git a/eco/xoptics/offsetMirrors.py b/eco/xoptics/offsetMirrors.py index 7e6d028..35316dd 100755 --- a/eco/xoptics/offsetMirrors.py +++ b/eco/xoptics/offsetMirrors.py @@ -16,9 +16,7 @@ def addMotorRecordToSelf(self, name=None, Id=None): class OffsetMirror: - def __init__( - self, name=None, Id=None, alias_namespace=None - ): + def __init__(self, name=None, Id=None, alias_namespace=None): self.Id = Id self.name = name self.alias = Alias(name) @@ -28,7 +26,6 @@ class OffsetMirror: addMotorRecordToSelf(self, Id=Id + ":W_RX", name="rx") addMotorRecordToSelf(self, Id=Id + ":W_RZ", name="rz") - def out(self): pass diff --git a/eco/xoptics/pp.py b/eco/xoptics/pp.py index 87eb958..4cc907c 100755 --- a/eco/xoptics/pp.py +++ b/eco/xoptics/pp.py @@ -14,6 +14,7 @@ def addMotorRecordToSelf(self, name=None, Id=None): except: print("Warning! Could not find motor {name} (Id:{Id})") + class Pulsepick: def __init__(self, Id=None, evronoff=None, evrsrc=None, name=None): self.name = name @@ -45,9 +46,7 @@ class Pulsepick: self._evrsrc.put(63) print("Closed Pulse Picker") - def trigger(self): self._openclose.put(1) self._evrsrc.put(0) print("Set Pulse Picker to trigger (src 0 and output On)") - diff --git a/eco/xoptics/slits.py b/eco/xoptics/slits.py index 554caaa..f59d9d8 100755 --- a/eco/xoptics/slits.py +++ b/eco/xoptics/slits.py @@ -55,6 +55,7 @@ class SlitBlades: string2 = "pos: (%g,%g) mm" % (self.get_ho(), self.get_vo()) return "\n".join((string1, string2)) + class SlitBladesJJ: def __init__(self, Id, name=None, elog=None): self.Id = Id @@ -71,10 +72,10 @@ class SlitBladesJJ: return -(self._y2.get_current_value() - self._y1.get_current_value()) def get_ho(self): - return ((self._x1.get_current_value() + self._x2.get_current_value()) / 2) + return (self._x1.get_current_value() + self._x2.get_current_value()) / 2 def get_vo(self): - return ((self._y1.get_current_value() + self._y2.get_current_value()) / 2) + return (self._y1.get_current_value() + self._y2.get_current_value()) / 2 def set_hg(self, value): ho = self.get_ho() @@ -109,6 +110,7 @@ class SlitBladesJJ: string2 = "pos: (%g,%g) mm" % (self.get_ho(), self.get_vo()) return "\n".join((string1, string2)) + class SlitFourBlades: def __init__(self, Id, name=None, elog=None): self.Id = Id