Files
common/packages/pyscan/interface/pyScan/scan.py
2025-01-07 12:38:15 +01:00

714 lines
32 KiB
Python

import traceback
from copy import deepcopy
from datetime import datetime
from time import sleep
import numpy as np
from pyscan.dal.epics_dal import PyEpicsDal
from pyscan.interface.pyScan.utils import PyScanDataProcessor
from pyscan.positioner.compound import CompoundPositioner
from pyscan.positioner.serial import SerialPositioner
from pyscan.positioner.vector import VectorPositioner
from pyscan.scan_parameters import scan_settings
from pyscan.scanner import Scanner
from pyscan.utils import convert_to_list, convert_to_position_list, compare_channel_value
READ_GROUP = "Measurements"
WRITE_GROUP = "Knobs"
MONITOR_GROUP = "Monitors"
class Scan(object):
def execute_scan(self):
after_executor = self.get_action_executor("In-loopPostAction")
# Wrap the post action executor to update the number of completed scans.
def progress_after_executor(scanner_instance, data):
# Execute other post actions.
after_executor(scanner_instance)
# Update progress.
self.n_done_measurements += 1
self.ProgDisp.Progress = 100.0 * (self.n_done_measurements /
self.n_total_positions)
def prepare_monitors(reader):
# If there are no monitors defined we have nothing to validate.
if not self.dimensions[-1]["Monitor"]:
return None
def validate_monitors(position, data):
monitor_values = reader.read()
combined_data = zip(self.dimensions[-1]['Monitor'],
self.dimensions[-1]['MonitorValue'],
self.dimensions[-1]['MonitorTolerance'],
self.dimensions[-1]['MonitorAction'],
self.dimensions[-1]['MonitorTimeout'],
monitor_values)
for pv, expected_value, tolerance, action, timeout, value in combined_data:
# Monitor value does not match.
if not compare_channel_value(value, expected_value, tolerance):
if action == "Abort":
raise ValueError("Monitor %s, expected value %s, tolerance %s, has value %s. Aborting."
% (pv, expected_value, tolerance, value))
elif action == "WaitAndAbort":
return False
else:
raise ValueError("MonitorAction %s, on PV %s, is not supported." % (pv, action))
return True
return validate_monitors
# Setup scan settings.
settings = scan_settings(settling_time=self.dimensions[-1]["KnobWaitingExtra"],
n_measurements=self.dimensions[-1]["NumberOfMeasurements"],
measurement_interval=self.dimensions[-1]["Waiting"])
data_processor = PyScanDataProcessor(self.outdict,
n_readbacks=self.n_readbacks,
n_validations=self.n_validations,
n_observables=self.n_observables,
n_measurements=settings.n_measurements)
self.scanner = Scanner(positioner=self.get_positioner(), data_processor=data_processor,
reader=self.epics_dal.get_group(READ_GROUP).read,
writer=self.epics_dal.get_group(WRITE_GROUP).set_and_match,
before_measurement_executor=self.get_action_executor("In-loopPreAction"),
after_measurement_executor=progress_after_executor,
initialization_executor=self.get_action_executor("PreAction"),
finalization_executor=self.get_action_executor("PostAction"),
data_validator=prepare_monitors(self.epics_dal.get_group(MONITOR_GROUP)),
settings=settings)
self.outdict.update(self.scanner.discrete_scan())
def get_positioner(self):
"""
Generate a positioner for the provided dimensions.
:return: Positioner object.
"""
# Read all the initial positions - in case we need to do an additive scan.
initial_positions = self.epics_dal.get_group(READ_GROUP).read()
positioners = []
knob_readback_offset = 0
for dimension in self.dimensions:
is_additive = bool(dimension.get("Additive", 0))
is_series = bool(dimension.get("Series", 0))
n_knob_readbacks = len(dimension["KnobReadback"])
# This dimension uses relative positions, read the PVs initial state.
# We also need initial positions for the series scan.
if is_additive or is_series:
offsets = convert_to_list(
initial_positions[knob_readback_offset:knob_readback_offset + n_knob_readbacks])
else:
offsets = None
# Series scan in this dimension, use StepByStepVectorPositioner.
if is_series:
# In the StepByStep positioner, the initial values need to be added to the steps.
positions = convert_to_list(dimension["ScanValues"])
positioners.append(SerialPositioner(positions, initial_positions=offsets,
offsets=offsets if is_additive else None))
# Line scan in this dimension, use VectorPositioner.
else:
positions = convert_to_position_list(convert_to_list(dimension["KnobExpanded"]))
positioners.append(VectorPositioner(positions, offsets=offsets))
# Increase the knob readback offset.
knob_readback_offset += n_knob_readbacks
# Assemble all individual positioners together.
positioner = CompoundPositioner(positioners)
return positioner
def get_action_executor(self, entry_name):
actions = []
max_waiting = 0
for dim_index, dim in enumerate(self.dimensions):
for action_index, action in enumerate(dim[entry_name]):
set_pv, read_pv, value, tolerance, timeout = action
if set_pv == "match":
raise NotImplementedError("match not yet implemented for PreAction.")
# Initialize the write group, to speed up in loop stuff.
group_name = "%s_%d_%d" % (entry_name, dim_index, action_index)
self.epics_dal.add_writer_group(group_name, set_pv, read_pv, tolerance, timeout)
actions.append((group_name, value))
if entry_name + "Waiting" in dim:
max_waiting = max(max_waiting, dim[entry_name + "Waiting"])
def execute(scanner):
for action in actions:
name = action[0]
value = action[1]
# Retrieve the epics group and write the value.
self.epics_dal.get_group(name).set_and_match(value)
sleep(max_waiting)
return execute
class DummyProgress(object):
def __init__(self):
# For Thomas?
self.Progress = 1
self.abortScan = 0
def __init__(self):
self.dimensions = None
self.epics_dal = None
self.scanner = None
self.outdict = None
self.all_read_pvs = None
self.n_readbacks = None
self.n_validations = None
self.n_observables = None
self.n_total_positions = None
self.n_measurements = None
# Accessed by some clients.
self.ProgDisp = Scan.DummyProgress()
self._pauseScan = 0
# Just to make old GUI work.
self._abortScan = 0
self.n_done_measurements = 0
@property
def abortScan(self):
return self._abort_scan
@abortScan.setter
def abortScan(self, value):
self._abortScan = value
if self._abortScan:
self.scanner.abort_scan()
@property
def pauseScan(self):
return self._pauseScan
@pauseScan.setter
def pauseScan(self, value):
self._pauseScan = value
if self._pauseScan:
self.scanner.pause_scan()
else:
self.scanner.resume_scan()
def initializeScan(self, inlist, dal=None):
"""
Initialize and verify the provided scan values.
:param inlist: List of dictionaries for each dimension.
:param dal: Which reader should be used to access the PVs. Default: PyEpicsDal.
:return: Dictionary with results.
"""
if not inlist:
raise ValueError("Provided inlist is empty.")
if dal is not None:
self.epics_dal = dal
else:
self.epics_dal = PyEpicsDal()
# Prepare the scan dimensions.
if isinstance(inlist, list):
self.dimensions = inlist
# In case it is a simple one dimensional scan.
else:
self.dimensions = [inlist]
try:
for index, dic in enumerate(self.dimensions):
# We read most of the PVs only if declared in the last dimension.
is_last_dimension = index == (len(self.dimensions) - 1)
# Just in case there are identical input dictionaries. (Normally, it may not happen.)
dic['ID'] = index
# Waiting time.
if is_last_dimension and ('Waiting' not in dic.keys()):
raise ValueError('Waiting for the scan was not given.')
# Validation channels - values just added to the results.
if 'Validation' in dic.keys():
if not isinstance(dic['Validation'], list):
raise ValueError('Validation should be a list of channels. Input dictionary %d.' % index)
else:
dic['Validation'] = []
# Relative scan.
if 'Additive' not in dic.keys():
dic['Additive'] = 0
# Step back when pause is invoked.
if is_last_dimension and ('StepbackOnPause' not in dic.keys()):
dic['StepbackOnPause'] = 1
# Number of measurments per position.
if is_last_dimension and ('NumberOfMeasurements' not in dic.keys()):
dic['NumberOfMeasurements'] = 1
# PVs to sample.
if is_last_dimension and ('Observable' not in dic.keys()):
raise ValueError('The observable is not given.')
elif is_last_dimension:
if not isinstance(dic['Observable'], list):
dic['Observable'] = [dic['Observable']]
self._setup_knobs(index, dic)
self._setup_knob_scan_values(index, dic)
self._setup_pre_actions(index, dic)
self._setup_inloop_pre_actions(index, dic)
self._setup_post_action(index, dic)
self._setup_inloop_post_action(index, dic)
# Total number of measurements
self.n_total_positions = 1
for dic in self.dimensions:
if not dic['Series']:
self.n_total_positions = self.n_total_positions * dic['Nstep']
else:
self.n_total_positions = self.n_total_positions * sum(dic['Nstep'])
self._setup_epics_dal()
# Monitors only in the last dimension.
self._setup_monitors(self.dimensions[-1])
# Prealocating the place for the output
self.outdict = {"ErrorMessage": None,
"KnobReadback": self.allocateOutput(),
"Validation": self.allocateOutput(),
"Observable": self.allocateOutput()}
except ValueError:
self.outdict = {"ErrorMessage": traceback.format_exc()}
# Backward compatibility.
self.ProgDisp.Progress = 0
self.ProgDisp.abortScan = 0
self._pauseScan = 0
self.abortScan = 0
self.n_done_measurements = 0
return self.outdict
def allocateOutput(self):
root_list = []
for dimension in reversed(self.dimensions):
n_steps = dimension['Nstep']
if dimension['Series']:
# For Series scan, each step of each knob represents another result.
current_dimension_list = []
for n_steps_in_knob in n_steps:
current_knob_list = []
for _ in range(n_steps_in_knob):
current_knob_list.append(deepcopy(root_list))
current_dimension_list.append(deepcopy(current_knob_list))
root_list = current_dimension_list
else:
# For line scan, each step represents another result.
current_dimension_list = []
for _ in range(n_steps):
current_dimension_list.append(deepcopy(root_list))
root_list = current_dimension_list
return root_list
def _setup_epics_dal(self):
# Collect all PVs that need to be read at each scan step.
self.all_read_pvs = []
all_write_pvs = []
all_readback_pvs = []
all_tolerances = []
max_knob_waiting = -1
self.n_readbacks = 0
for d in self.dimensions:
self.all_read_pvs.append(d['KnobReadback'])
self.n_readbacks += len(d['KnobReadback'])
# Collect all data need to write to PVs.
all_write_pvs.append(d["Knob"])
all_readback_pvs.append(d["KnobReadback"])
all_tolerances.append(d["KnobTolerance"])
max_knob_waiting = max(max_knob_waiting, max(d["KnobWaiting"]))
self.all_read_pvs.append(self.dimensions[-1]['Validation'])
self.n_validations = len(self.dimensions[-1]['Validation'])
self.all_read_pvs.append(self.dimensions[-1]['Observable'])
self.n_observables = len(self.dimensions[-1]['Observable'])
# Expand all read PVs
self.all_read_pvs = [item for sublist in self.all_read_pvs for item in sublist]
# Expand Knobs and readbacks PVs.
all_write_pvs = [item for sublist in all_write_pvs for item in sublist]
all_readback_pvs = [item for sublist in all_readback_pvs for item in sublist]
all_tolerances = [item for sublist in all_tolerances for item in sublist]
# Initialize PV connections and check if all PV names are valid.
self.epics_dal.add_reader_group(READ_GROUP, self.all_read_pvs)
self.epics_dal.add_writer_group(WRITE_GROUP, all_write_pvs, all_readback_pvs, all_tolerances, max_knob_waiting)
def _setup_knobs(self, index, dic):
"""
Setup the values for moving knobs in the scan.
:param index: Index in the dictionary.
:param dic: The dictionary.
"""
if 'Knob' not in dic.keys():
raise ValueError('Knob for the scan was not given for the input dictionary %d.' % index)
else:
if not isinstance(dic['Knob'], list):
dic['Knob'] = [dic['Knob']]
if 'KnobReadback' not in dic.keys():
dic['KnobReadback'] = dic['Knob']
if not isinstance(dic['KnobReadback'], list):
dic['KnobReadback'] = [dic['KnobReadback']]
if len(dic['KnobReadback']) != len(dic['Knob']):
raise ValueError('The number of KnobReadback does not meet to the number of Knobs.')
if 'KnobTolerance' not in dic.keys():
dic['KnobTolerance'] = [1.0] * len(dic['Knob'])
if not isinstance(dic['KnobTolerance'], list):
dic['KnobTolerance'] = [dic['KnobTolerance']]
if len(dic['KnobTolerance']) != len(dic['Knob']):
raise ValueError('The number of KnobTolerance does not meet to the number of Knobs.')
if 'KnobWaiting' not in dic.keys():
dic['KnobWaiting'] = [10.0] * len(dic['Knob'])
if not isinstance(dic['KnobWaiting'], list):
dic['KnobWaiting'] = [dic['KnobWaiting']]
if len(dic['KnobWaiting']) != len(dic['Knob']):
raise ValueError('The number of KnobWaiting does not meet to the number of Knobs.')
if 'KnobWaitingExtra' not in dic.keys():
dic['KnobWaitingExtra'] = 0.0
else:
try:
dic['KnobWaitingExtra'] = float(dic['KnobWaitingExtra'])
except:
raise ValueError('KnobWaitingExtra is not a number in the input dictionary %d.' % index)
# Originally dic["Knob"] values were saved. I'm supposing this was a bug - readback values needed to be saved.
# TODO: We can optimize this by moving the initialization in the epics_dal init
# but pre actions need to be moved after the epics_dal init than
self.epics_dal.add_reader_group("KnobReadback", dic['KnobReadback'])
dic['KnobSaved'] = self.epics_dal.get_group("KnobReadback").read()
self.epics_dal.close_group("KnobReadback")
def _setup_knob_scan_values(self, index, dic):
if 'Series' not in dic.keys():
dic['Series'] = 0
if not dic['Series']: # Setting up scan values for SKS and MKS
if 'ScanValues' not in dic.keys():
if 'ScanRange' not in dic.keys():
raise ValueError('Neither ScanRange nor ScanValues is given '
'in the input dictionary %d.' % index)
elif not isinstance(dic['ScanRange'], list):
raise ValueError('ScanRange is not given in the right format. '
'Input dictionary %d.' % index)
elif not isinstance(dic['ScanRange'][0], list):
dic['ScanRange'] = [dic['ScanRange']]
if ('Nstep' not in dic.keys()) and ('StepSize' not in dic.keys()):
raise ValueError('Neither Nstep nor StepSize is given.')
if 'Nstep' in dic.keys(): # StepSize is ignored when Nstep is given
if not isinstance(dic['Nstep'], int):
raise ValueError('Nstep should be an integer. Input dictionary %d.' % index)
ran = []
for r in dic['ScanRange']:
s = (r[1] - r[0]) / (dic['Nstep'] - 1)
f = np.arange(r[0], r[1], s)
f = np.append(f, np.array(r[1]))
ran.append(f.tolist())
dic['KnobExpanded'] = ran
else: # StepSize given
if len(dic['Knob']) > 1:
raise ValueError('Give Nstep instead of StepSize for MKS. '
'Input dictionary %d.' % index)
# StepSize is only valid for SKS
r = dic['ScanRange'][0]
# TODO: THIS IS RECONSTRUCTED AND MIGHT BE WRONG, CHECK!
s = dic['StepSize'][0]
f = np.arange(r[0], r[1], s)
f = np.append(f, np.array(r[1]))
dic['Nstep'] = len(f)
dic['KnobExpanded'] = [f.tolist()]
else:
# Scan values explicitly defined.
if not isinstance(dic['ScanValues'], list):
raise ValueError('ScanValues is not given in the right fromat. '
'Input dictionary %d.' % index)
if len(dic['ScanValues']) != len(dic['Knob']) and len(dic['Knob']) != 1:
raise ValueError('The length of ScanValues does not meet to the number of Knobs.')
if len(dic['Knob']) > 1:
minlen = 100000
for r in dic['ScanValues']:
if minlen > len(r):
minlen = len(r)
ran = []
for r in dic['ScanValues']:
ran.append(r[0:minlen]) # Cut at the length of the shortest list.
dic['KnobExpanded'] = ran
dic['Nstep'] = minlen
else:
dic['KnobExpanded'] = [dic['ScanValues']]
dic['Nstep'] = len(dic['ScanValues'])
else: # Setting up scan values for Series scan
if 'ScanValues' not in dic.keys():
raise ValueError('ScanValues should be given for Series '
'scan in the input dictionary %d.' % index)
if not isinstance(dic['ScanValues'], list):
raise ValueError('ScanValues should be given as a list (of lists) '
'for Series scan in the input dictionary %d.' % index)
if len(dic['Knob']) != len(dic['ScanValues']):
raise ValueError('Scan values length does not match to the '
'number of knobs in the input dictionary %d.' % index)
Nstep = []
for vl in dic['ScanValues']:
if not isinstance(vl, list):
raise ValueError('ScanValue element should be given as a list for '
'Series scan in the input dictionary %d.' % index)
Nstep.append(len(vl))
dic['Nstep'] = Nstep
def _setup_pre_actions(self, index, dic):
if 'PreAction' in dic.keys():
if not isinstance(dic['PreAction'], list):
raise ValueError('PreAction should be a list. Input dictionary %d.' % index)
for l in dic['PreAction']:
if not isinstance(l, list):
raise ValueError('Every PreAction should be a list. Input dictionary %d.' % index)
if len(l) != 5:
if not l[0] == 'SpecialAction':
raise ValueError('Every PreAction should be in a form of '
'[Ch-set, Ch-read, Value, Tolerance, Timeout]. '
'Input dictionary ' + str(index) + '.')
if 'PreActionWaiting' not in dic.keys():
dic['PreActionWaiting'] = 0.0
if not isinstance(dic['PreActionWaiting'], float) and not isinstance(dic['PreActionWaiting'], int):
raise ValueError('PreActionWating should be a float. Input dictionary %d.' % index)
if 'PreActionOrder' not in dic.keys():
dic['PreActionOrder'] = [0] * len(dic['PreAction'])
if not isinstance(dic['PreActionOrder'], list):
raise ValueError('PreActionOrder should be a list. Input dictionary %d.' % index)
else:
dic['PreAction'] = []
dic['PreActionWaiting'] = 0.0
dic['PreActionOrder'] = [0] * len(dic['PreAction'])
def _setup_inloop_pre_actions(self, index, dic):
if 'In-loopPreAction' in dic.keys():
if not isinstance(dic['In-loopPreAction'], list):
raise ValueError('In-loopPreAction should be a list. Input dictionary %d.' % index)
for l in dic['In-loopPreAction']:
if not isinstance(l, list):
raise ValueError('Every In-loopPreAction should be a list. '
'Input dictionary ' + str(index) + '.')
if len(l) != 5:
if not l[0] == 'SpecialAction':
raise ValueError('Every In-loopPreAction should be in a form of '
'[Ch-set, Ch-read, Value, Tolerance, Timeout]. '
'Input dictionary ' + str(index) + '.')
if 'In-loopPreActionWaiting' not in dic.keys():
dic['In-loopPreActionWaiting'] = 0.0
if not isinstance(dic['In-loopPreActionWaiting'], float) and not isinstance(
dic['In-loopPreActionWaiting'], int):
raise ValueError('In-loopPreActionWating should be a float. Input dictionary %d.' % index)
if 'In-loopPreActionOrder' not in dic.keys():
dic['In-loopPreActionOrder'] = [0] * len(dic['In-loopPreAction'])
if not isinstance(dic['In-loopPreActionOrder'], list):
raise ValueError('In-loopPreActionOrder should be a list. Input dictionary %d.' % index)
else:
dic['In-loopPreAction'] = []
dic['In-loopPreActionWaiting'] = 0.0
dic['In-loopPreActionOrder'] = [0] * len(dic['In-loopPreAction'])
def _setup_post_action(self, index, dic):
if 'PostAction' in dic.keys():
if dic['PostAction'] == 'Restore':
PA = []
for index in range(0, len(dic['Knob'])):
k = dic['Knob'][index]
v = dic['KnobSaved'][index]
PA.append([k, k, v, 1.0, 10])
dic['PostAction'] = PA
elif not isinstance(dic['PostAction'], list):
raise ValueError('PostAction should be a list. Input dictionary %d.' % index)
Restore = 0
for index in range(0, len(dic['PostAction'])):
l = dic['PostAction'][index]
if l == 'Restore':
Restore = 1
PA = []
for j in range(0, len(dic['Knob'])):
k = dic['Knob'][j]
v = dic['KnobSaved'][j]
PA.append([k, k, v, 1.0, 10])
elif not isinstance(l, list):
raise ValueError('Every PostAction should be a list. Input dictionary %d.' % index)
elif len(l) != 5:
if not l[0] == 'SpecialAction':
raise ValueError('Every PostAction should be in a form of '
'[Ch-set, Ch-read, Value, Tolerance, Timeout]. '
'Input dictionary %d.' % index)
if Restore:
dic['PostAction'].remove('Restore')
dic['PostAction'] = dic['PostAction'] + PA
else:
dic['PostAction'] = []
def _setup_inloop_post_action(self, index, dic):
if 'In-loopPostAction' in dic.keys():
if dic['In-loopPostAction'] == 'Restore':
PA = []
for index in range(0, len(dic['Knob'])):
k = dic['Knob'][index]
v = dic['KnobSaved'][index]
PA.append([k, k, v, 1.0, 10])
dic['In-loopPostAction'] = PA
elif not isinstance(dic['In-loopPostAction'], list):
raise ValueError('In-loopPostAction should be a list. Input dictionary %d.' % index)
Restore = 0
for index in range(0, len(dic['In-loopPostAction'])):
l = dic['In-loopPostAction'][index]
if l == 'Restore':
Restore = 1
PA = []
for j in range(0, len(dic['Knob'])):
k = dic['Knob'][j]
v = dic['KnobSaved'][j]
PA.append([k, k, v, 1.0, 10])
dic['In-loopPostAction'][index] = PA
elif not isinstance(l, list):
raise ValueError('Every In-loopPostAction should be a list. '
'Input dictionary %d.' % index)
elif len(l) != 5:
raise ValueError('Every In-loopPostAction should be in a form of '
'[Ch-set, Ch-read, Value, Tolerance, Timeout]. '
'Input dictionary %d.' % index)
if Restore:
dic['In-loopPostAction'].remove('Restore')
dic['In-loopPostAction'] = dic['In-loopPostAction'] + PA
else:
dic['In-loopPostAction'] = []
def _setup_monitors(self, dic):
if ('Monitor' in dic.keys()) and (dic['Monitor']):
if isinstance(dic['Monitor'], str):
dic['Monitor'] = [dic['Monitor']]
# Initialize monitor group and check if all monitor PVs are valid.
self.epics_dal.add_reader_group(MONITOR_GROUP, dic["Monitor"])
if 'MonitorValue' not in dic.keys():
dic["MonitorValue"] = self.epics_dal.get_group(MONITOR_GROUP).read()
elif not isinstance(dic['MonitorValue'], list):
dic['MonitorValue'] = [dic['MonitorValue']]
if len(dic['MonitorValue']) != len(dic['Monitor']):
raise ValueError('The length of MonitorValue does not meet to the length of Monitor.')
# Try to construct the monitor tolerance, if not given.
if 'MonitorTolerance' not in dic.keys():
dic['MonitorTolerance'] = []
for value in self.epics_dal.get_group(MONITOR_GROUP).read():
if isinstance(value, str):
# No tolerance for string values.
dic['MonitorTolerance'].append(None)
elif value == 0:
# Default tolerance for unknown values is 0.1.
dic['MonitorTolerance'].append(0.1)
else:
# 10% of the current value will be the torelance when not given
dic['MonitorTolerance'].append(abs(value * 0.1))
elif not isinstance(dic['MonitorTolerance'], list):
dic['MonitorTolerance'] = [dic['MonitorTolerance']]
if len(dic['MonitorTolerance']) != len(dic['Monitor']):
raise ValueError('The length of MonitorTolerance does not meet to the length of Monitor.')
if 'MonitorAction' not in dic.keys():
raise ValueError('MonitorAction is not give though Monitor is given.')
if not isinstance(dic['MonitorAction'], list):
dic['MonitorAction'] = [dic['MonitorAction']]
for m in dic['MonitorAction']:
if m != 'Abort' and m != 'Wait' and m != 'WaitAndAbort':
raise ValueError('MonitorAction shold be Wait, Abort, or WaitAndAbort.')
if 'MonitorTimeout' not in dic.keys():
dic['MonitorTimeout'] = [30.0] * len(dic['Monitor'])
elif not isinstance(dic['MonitorTimeout'], list):
dic['MonitorValue'] = [dic['MonitorValue']]
if len(dic['MonitorValue']) != len(dic['Monitor']):
raise ValueError('The length of MonitorValue does not meet to the length of Monitor.')
for m in dic['MonitorTimeout']:
try:
float(m)
except:
raise ValueError('MonitorTimeout should be a list of float(or int).')
else:
dic['Monitor'] = []
dic['MonitorValue'] = []
dic['MonitorTolerance'] = []
dic['MonitorAction'] = []
dic['MonitorTimeout'] = []
def startScan(self):
if self.outdict['ErrorMessage']:
if 'After the last scan,' not in self.outdict['ErrorMessage']:
self.outdict['ErrorMessage'] = 'It seems that the initialization was not successful... ' \
'No scan was performed.'
return self.outdict
# Execute the scan.
self.outdict['TimeStampStart'] = datetime.now()
self.execute_scan()
self.outdict['TimeStampEnd'] = datetime.now()
self.outdict['ErrorMessage'] = 'Measurement finalized (finished/aborted) normally. ' \
'Need initialisation before next measurement.'
# Cleanup after the scan.
self.epics_dal.close_all_groups()
return self.outdict