def run(self, *args, **kwargs): """Runs this action""" self._running = True synch = kwargs.pop("synch", False) if synch: try: with self.OperationContextClass(self) as context: self.start_action(*args, **kwargs) self._started = False self.action_loop() finally: self._started = False self._running = False else: context = self.OperationContextClass(self) context.enter() try: self.start_action(*args, **kwargs) except: context.exit() self._running = False raise finally: self._started = False cb = kwargs.pop("cb", None) get_thread_pool().add(self._asynch_action_loop, cb, context)
def meas_cont_acquisition(self, config, synchronization, moveable=None, second_config=None): """Executes measurement using the measurement group. Checks the lengths of the acquired data. """ jobs_before = get_thread_pool().qsize channel_names = self.prepare_meas(config) self.pmg.set_synchronization(synchronization) self.pmg.set_moveable(moveable, to_fqdn=False) repetitions = 0 for group in synchronization: repetitions += group[SynchParam.Repeats] self.prepare_attribute_listener() self.acquire() self.acq_asserts(channel_names, repetitions) if second_config is not None: self.consecutive_acquisitions( self.pool, second_config, synchronization) # checking if there are no pending jobs jobs_after = get_thread_pool().qsize msg = ('there are %d jobs pending to be done after the acquisition ' + '(before: %d)') % (jobs_after, jobs_before) self.assertEqual(jobs_before, jobs_after, msg)
def run(self, *args, **kwargs): """Runs this action""" self._running = True synch = kwargs.pop("synch", False) if synch: try: with OperationContext(self) as context: self.start_action(*args, **kwargs) self._started = False self.action_loop() finally: self._started = False self._running = False else: context = OperationContext(self) context.enter() try: self.start_action(*args, **kwargs) except: context.exit() self._running = False raise finally: self._started = False get_thread_pool().add(self._asynch_action_loop, None, context)
def event_received(self, *args, **kwargs): """Callback to execute software start acquisition.""" _, type_, value = args name = type_.name if name == "start": get_thread_pool().add(self.acquisition.run, None, *self.acq_args, **self.acq_kwargs)
def StartOne(self, axis): """Start the specified trigger """ self._log.debug('StartOne(%d): entering...' % axis) idx = axis - 1 tg = self.tg[idx] tg.start() get_thread_pool().add(tg.run)
def _run_multiple(self, *args, **kwargs): n = kwargs['multiple'] synch = kwargs.get("synch", False) if synch: for _ in range(n): self._run_single(self, *args, **kwargs) else: kwargs["synch"] = True get_thread_pool().add(self._run_multiple, None, *args, **kwargs)
def event_received(self, *args, **kwargs): """Callback to execute software start acquisition.""" _, type_, value = args name = type_.name if name != "start": return args = self.acq_args kwargs = self.acq_kwargs get_thread_pool().add(self.acquisition.run, None, *args, **kwargs)
def acquire(self, integ_time, repetitions, latency_time): """Acquire with a dummy C/T synchronized by a hardware start trigger from a dummy T/G.""" self.ct_ctrl_1.set_ctrl_par("synchronization", AcqSynch.HardwareStart) conf_ct_ctrl_1 = createTimerableControllerConfiguration( self.ct_ctrl_1, [self.ct_1_1]) ctrls = get_timerable_ctrls([conf_ct_ctrl_1], AcqMode.Timer) conf_tg_ctrl_1 = createControllerConfiguration(self.tg_ctrl_1, [self.tg_1_1]) synch_ctrls = get_acq_ctrls([conf_tg_ctrl_1]) self.synchronization = self.create_action(PoolSynchronization, [self.tg_1_1]) # add data listeners self.add_listeners([self.ct_1_1]) # creating acquisition actions self.acquisition = self.create_action(PoolAcquisitionHardware, [self.ct_1_1]) self.acq_args = ([conf_ct_ctrl_1], integ_time, repetitions) # prepare synchronization description total_interval = integ_time + latency_time group = { SynchParam.Delay: {SynchDomain.Time: 0}, SynchParam.Active: {SynchDomain.Time: integ_time}, SynchParam.Total: {SynchDomain.Time: total_interval}, SynchParam.Repeats: repetitions } synchronization = [group] # get the current number of jobs jobs_before = get_thread_pool().qsize self.acquisition.run(ctrls, integ_time, repetitions, 0) self.synchronization.run(synch_ctrls, synchronization) self.wait_finish() self.do_asserts(repetitions, jobs_before)
def meas_cont_stop_acquisition(self, config, synchronization, moveable=None): """Executes measurement using the measurement group and tests that the acquisition can be stopped. """ self.prepare_meas(config) self.pmg.synchronization = synchronization self.pmg.set_moveable(moveable, to_fqdn=False) self.prepare_attribute_listener() self.pmg.start_acquisition() # retrieving the acquisition since it was cleaned when applying mg conf acq = self.pmg.acquisition # starting timer (0.05 s) which will stop the acquisiton threading.Timer(0.2, self.stop_acquisition).start() # waiting for acquisition and tggeneration to be stoped by thread while acq.is_running(): time.sleep(0.05) msg = "acquisition shall NOT be running after stopping it" self.assertEqual(acq.is_running(), False, msg) tp = get_thread_pool() numBW = tp.getNumOfBusyWorkers() msg = "The number of busy workers is not zero; numBW = %s" % (numBW) self.assertEqual(numBW, 0, msg) # print the acquisition records for i, record in enumerate(zip(*self.attr_listener.data.values())): print i, record
def event_received(self, *args, **kwargs): """Callback to execute software start acquisition.""" _, type_, value = args name = type_.name if name == "active": if self.acq_busy.is_set(): # skipping acquisition cause the previous on is ongoing return else: self.acq_busy.set() acq_args = list(self.acq_args) acq_kwargs = self.acq_kwargs index = value acq_args[3] = index get_thread_pool().add(self.acquisition.run, None, *acq_args, **acq_kwargs)
def event_received(self, *args, **kwargs): """Executes a single software triggered acquisition.""" _, type_, index = args name = type_.name if name == "active": if self.sw_acq_busy.is_set(): # skipping acquisition cause the previous on is ongoing return else: self.sw_acq_busy.set() args = self.sw_acq_args kwargs = self.sw_acq_kwargs kwargs['index'] = index get_thread_pool().add(self.sw_acq.run, None, *args, **kwargs)
def acquire(self, integ_time, repetitions, latency_time): """Acquire with a dummy C/T synchronized by a hardware start trigger from a dummy T/G.""" self.prepare(integ_time, repetitions, latency_time, 1) conf_ct_ctrl_1 = createTimerableControllerConfiguration( self.channel_ctrl, [self.channel]) ctrls = get_timerable_ctrls([conf_ct_ctrl_1], AcqMode.Timer) master = ctrls[0].master # creating synchronization action self.synchronization = self.create_action(PoolSynchronization, [self.tg]) self.synchronization.add_listener(self) # add_listeners self.add_listeners([self.channel]) # creating acquisition actions self.acquisition = self.create_action(PoolAcquisitionSoftware, [self.channel]) # Since we deposit the software acquisition action on the PoolThread's # queue we can not rely on the action's state - one may still wait # in the queue (its state has not changed to running yet) and we would # be depositing another one. This way we may be starting multiple # times the same action (with the same elements involved), what results # in "already involved in operation" errors. # Use an external Event flag to mark if we have any software # acquisition action pending. self.acq_busy = threading.Event() self.acquisition.add_finish_hook(self.acq_busy.clear) self.acq_args = (ctrls, integ_time, master, None) self.acq_kwargs = {} total_interval = integ_time + latency_time group = { SynchParam.Delay: { SynchDomain.Time: 0 }, SynchParam.Active: { SynchDomain.Time: integ_time }, SynchParam.Total: { SynchDomain.Time: total_interval }, SynchParam.Repeats: repetitions } synchronization = [group] # get the current number of jobs jobs_before = get_thread_pool().qsize self.synchronization.run([], synchronization) self.wait_finish() self.do_asserts(repetitions, jobs_before, strict=False)
def do_asserts(self, repetitions, jobs_before): # print acquisition records table = self.data_listener.get_table() header = table.dtype.names print header n_rows = table.shape[0] for row in xrange(n_rows): print row, table[row] # checking if all channels produced data for channel in self.channel_names: msg = 'data from channel %s were not acquired' % channel self.assertIn(channel, header, msg) # checking if all the data were acquired for ch_name in header: ch_data_len = len(table[ch_name]) msg = 'length of data for channel %s is %d and should be %d' %\ (ch_name, ch_data_len, repetitions) self.assertEqual(ch_data_len, repetitions, msg) # checking if there are no pending jobs jobs_after = get_thread_pool().qsize msg = ('there are %d jobs pending to be done after the acquisition ' + '(before: %d)') % (jobs_after, jobs_before) self.assertEqual(jobs_before, jobs_after, msg)
def continuous_acquisition(self, offset, active_interval, passive_interval, repetitions, integ_time): """Executes measurement running the TGGeneration and Acquisition actions according the test parameters. Checks the lengths of the acquired data. """ # obtaining elements created in the BasePoolTestCase.setUp tg_1_1 = self.tgs['_test_tg_1_1'] tg_ctrl_1 = tg_1_1.get_controller() ct_1_1 = self.cts['_test_ct_1_1'] # hw synchronized ct_2_1 = self.cts['_test_ct_2_1'] # sw synchronized ct_ctrl_1 = ct_1_1.get_controller() ct_ctrl_1.set_ctrl_par("synchronization", AcqSynch.HardwareTrigger) ct_ctrl_2 = ct_2_1.get_controller() self.channel_names.append('_test_ct_1_1') self.channel_names.append('_test_ct_2_1') conf_ct_ctrl_1 = createTimerableControllerConfiguration(ct_ctrl_1, [ct_1_1]) conf_ct_ctrl_2 = createTimerableControllerConfiguration(ct_ctrl_2, [ct_2_1]) hw_ctrls = get_timerable_ctrls([conf_ct_ctrl_1], acq_mode=AcqMode.Timer) sw_ctrls = get_timerable_ctrls([conf_ct_ctrl_2], acq_mode=AcqMode.Timer) sw_master = sw_ctrls[0].master conf_tg_ctrl_1 = createControllerConfiguration(tg_ctrl_1, [tg_1_1]) synch_ctrls = get_acq_ctrls([conf_tg_ctrl_1]) # creating synchronization action self.synchronization = self.create_action(PoolSynchronization, [tg_1_1]) self.synchronization.add_listener(self) # add_listeners self.add_listeners([ct_1_1, ct_2_1]) # creating acquisition actions self.hw_acq = self.create_action(PoolAcquisitionHardware, [ct_1_1]) self.sw_acq = self.create_action(PoolAcquisitionSoftware, [ct_2_1]) # Since we deposit the software acquisition action on the PoolThread's # queue we can not rely on the action's state - one may still wait # in the queue (its state has not changed to running yet) and we would # be depositing another one. This way we may be starting multiple # times the same action (with the same elements involved), what results # in "already involved in operation" errors. # Use an external Event flag to mark if we have any software # acquisition action pending. self.sw_acq_busy = threading.Event() self.sw_acq.add_finish_hook(self.sw_acq_busy.clear) self.sw_acq_args = (sw_ctrls, integ_time, sw_master) self.sw_acq_kwargs = {} total_interval = active_interval + passive_interval group = { SynchParam.Delay: {SynchDomain.Time: offset}, SynchParam.Active: {SynchDomain.Time: active_interval}, SynchParam.Total: {SynchDomain.Time: total_interval}, SynchParam.Repeats: repetitions } synchronization = [group] # get the current number of jobs jobs_before = get_thread_pool().qsize self.hw_acq.run(hw_ctrls, integ_time, repetitions, 0) self.synchronization.run(synch_ctrls, synchronization) # waiting for acquisition and synchronization to finish while (self.hw_acq.is_running() or self.sw_acq.is_running() or self.synchronization.is_running()): time.sleep(.1) self.do_asserts(repetitions, jobs_before)
def _raw_read_value_concurrent_loop(self, ret): """Internal method. Read value in a concurrent mode""" th_pool = get_thread_pool() for pool_ctrl in self.get_read_value_loop_ctrls(): th_pool.add(self._raw_read_ctrl_value, None, ret, pool_ctrl) return ret
def _raw_read_state_info_concurrent(self, ret): """Internal method. Read state in a concurrent mode""" th_pool = get_thread_pool() for pool_ctrl in self._pool_ctrl_dict: th_pool.add(self._raw_read_ctrl_state_info, None, ret, pool_ctrl) return ret
def start_action(self, ctrls, synch_description, moveable=None, sw_synch_initial_domain=None, *args, **kwargs): """Start synchronization action. :param ctrls: list of enabled trigger/gate controllers :type ctrls: list :param synch_description: synchronization description :type synch_description: :class:`~sardana.pool.poolsynchronization.SynchDescription` :param moveable: (optional) moveable object used as the synchronization source in the Position domain :type moveable: :class:`~sardna.pool.poolmotor.PoolMotor` or :class:`~sardana.pool.poolpseudomotor.PoolPseudoMotor` :param sw_synch_initial_domain: (optional) - initial domain for software synchronizer, can be either :obj:`~sardana.pool.pooldefs.SynchDomain.Time` or :obj:`~sardana.pool.pooldefs.SynchDomain.Position` """ with ActionContext(self): # loads synchronization description for ctrl in ctrls: pool_ctrl = ctrl.element pool_ctrl.ctrl.PreSynchAll() for channel in ctrl.get_channels(enabled=True): axis = channel.axis ret = pool_ctrl.ctrl.PreSynchOne(axis, synch_description) if not ret: msg = ("%s.PreSynchOne(%d) returns False" % (ctrl.name, axis)) raise Exception(msg) pool_ctrl.ctrl.SynchOne(axis, synch_description) pool_ctrl.ctrl.SynchAll() # attaching listener (usually acquisition action) # to the software trigger gate generator if self._listener is not None: if sw_synch_initial_domain is not None: self._synch_soft.initial_domain = sw_synch_initial_domain self._synch_soft.set_configuration(synch_description) self._synch_soft.add_listener(self._listener) remove_acq_listener = partial(self._synch_soft.remove_listener, self._listener) self.add_finish_hook(remove_acq_listener, False) self._synch_soft.add_listener( self.main_element.on_element_changed) remove_mg_listener = partial(self._synch_soft.remove_listener, self.main_element) self.add_finish_hook(remove_mg_listener, False) # subscribing to the position change events to generate events # in position domain if moveable is not None: position = moveable.get_position_attribute() position.add_listener(self._synch_soft) remove_pos_listener = partial(position.remove_listener, self._synch_soft) self.add_finish_hook(remove_pos_listener, False) # start software synchronizer if self._listener is not None: self._synch_soft.start() get_thread_pool().add(self._synch_soft.run) # PreStartAll on all controllers for ctrl in ctrls: pool_ctrl = ctrl.element pool_ctrl.ctrl.PreStartAll() # PreStartOne & StartOne on all elements for ctrl in ctrls: pool_ctrl = ctrl.element for channel in ctrl.get_channels(enabled=True): axis = channel.axis ret = pool_ctrl.ctrl.PreStartOne(axis) if not ret: raise Exception("%s.PreStartOne(%d) returns False" % (pool_ctrl.name, axis)) pool_ctrl.ctrl.StartOne(axis) # set the state of all elements to inform their listeners self._channels = [] for ctrl in ctrls: for channel in ctrl.get_channels(enabled=True): channel.set_state(State.Moving, propagate=2) self._channels.append(channel) # StartAll on all controllers for ctrl in ctrls: pool_ctrl = ctrl.element pool_ctrl.ctrl.StartAll()
def add_job(self, job, callback=None, *args, **kw): th_pool = get_thread_pool() th_pool.add(job, callback, *args, **kw)
def set_max_parallel_macros(self, nb): assert nb > 0, "max parallel macros number must be > 0" th_pool = get_thread_pool() if th_pool.size + 5 < nb: th_pool.size = nb self._max_parallel_macros = nb
def start_action(self, ctrls, synchronization, moveable=None, sw_synch_initial_domain=None, *args, **kwargs): """Start synchronization action. :param ctrls: list of enabled trigger/gate controllers :type ctrls: list :param synchronization: synchronization description :type synchronization: :class:`~sardana.pool.poolsynchronization.SynchronizationDescription` :param moveable: (optional) moveable object used as the synchronization source in the Position domain :type moveable: :class:`~sardna.pool.poolmotor.PoolMotor` or :class:`~sardana.pool.poolpseudomotor.PoolPseudoMotor` :param sw_synch_initial_domain: (optional) - initial domain for software synchronizer, can be either :obj:`~sardana.pool.pooldefs.SynchDomain.Time` or :obj:`~sardana.pool.pooldefs.SynchDomain.Position` """ with ActionContext(self): # loads synchronization description for ctrl in ctrls: pool_ctrl = ctrl.element pool_ctrl.ctrl.PreSynchAll() for channel in ctrl.get_channels(enabled=True): axis = channel.axis ret = pool_ctrl.ctrl.PreSynchOne(axis, synchronization) if not ret: msg = ("%s.PreSynchOne(%d) returns False" % (ctrl.name, axis)) raise Exception(msg) pool_ctrl.ctrl.SynchOne(axis, synchronization) pool_ctrl.ctrl.SynchAll() # attaching listener (usually acquisition action) # to the software trigger gate generator if self._listener is not None: if sw_synch_initial_domain is not None: self._synch_soft.initial_domain = sw_synch_initial_domain self._synch_soft.set_configuration(synchronization) self._synch_soft.add_listener(self._listener) remove_acq_listener = partial(self._synch_soft.remove_listener, self._listener) self.add_finish_hook(remove_acq_listener, False) self._synch_soft.add_listener( self.main_element.on_element_changed) remove_mg_listener = partial(self._synch_soft.remove_listener, self.main_element) self.add_finish_hook(remove_mg_listener, False) # subscribing to the position change events to generate events # in position domain if moveable is not None: position = moveable.get_position_attribute() position.add_listener(self._synch_soft) remove_pos_listener = partial(position.remove_listener, self._synch_soft) self.add_finish_hook(remove_pos_listener, False) # start software synchronizer if self._listener is not None: self._synch_soft.start() get_thread_pool().add(self._synch_soft.run) # PreStartAll on all controllers for ctrl in ctrls: pool_ctrl = ctrl.element pool_ctrl.ctrl.PreStartAll() # PreStartOne & StartOne on all elements for ctrl in ctrls: pool_ctrl = ctrl.element for channel in ctrl.get_channels(enabled=True): axis = channel.axis ret = pool_ctrl.ctrl.PreStartOne(axis) if not ret: raise Exception("%s.PreStartOne(%d) returns False" % (pool_ctrl.name, axis)) pool_ctrl.ctrl.StartOne(axis) # set the state of all elements to inform their listeners self._channels = [] for ctrl in ctrls: for channel in ctrl.get_channels(enabled=True): channel.set_state(State.Moving, propagate=2) self._channels.append(channel) # StartAll on all controllers for ctrl in ctrls: pool_ctrl = ctrl.element pool_ctrl.ctrl.StartAll()