def get_siblings_positions(self, use=None, write_pos=True): """Get the last positions for all siblings. If write_pos is True and a sibling has already been moved before, it's last write position is used. Otherwise its read position is used instead. :param use: the already calculated positions. If a sibling is in this dictionary, the position stored here is used instead :type use: dict <PoolElement, :class:`~sardana.sardanavalue.SardanaValue` > :param write_pos: determines if should try to use the last set point [default: True] :type write_pos: bool :return: a dictionary with siblings write positions :rtype: dict <PoolElement, position(float?) >""" positions = {} for sibling in self.siblings: pos_attr = sibling.get_position(propagate=0) if use and sibling in use: pos = use[sibling] elif pos_attr.has_write_value() and write_pos: pos = pos_attr.w_value else: if pos_attr.in_error(): raise PoolException("Cannot get '%s' position" % sibling.name, exc_info=pos_attr.exc_info) pos_value = pos_attr.calc_pseudo() if pos_value.error: raise PoolException("Cannot get '%s' position" % sibling.name, exc_info=pos_value.exc_info) pos = pos_value.value positions[sibling] = pos return positions
def calculate_motion(self, new_position, items=None, calculated=None): # if items already contains the positions for this pseudo motor # underlying motors it means the motion has already been calculated # by a sibling if items is not None and len(items): physical_elements = self.get_physical_elements_set() s_items = set(items) if s_items == physical_elements: if calculated is not None and self in calculated: return user_elements = self.get_user_elements() positions = self.get_siblings_positions( use=calculated, write_pos=self.drift_correction) positions[self] = new_position pseudo_positions = len(positions) * [None] for pseudo, position in list(positions.items()): pseudo_positions[pseudo.axis - 1] = position curr_physical_positions = self._position.get_physical_positions() physical_positions = self.controller.calc_all_physical( pseudo_positions, curr_physical_positions) if physical_positions.error: raise PoolException( "Cannot calculate motion: " "calc_all_physical raises exception", exc_info=physical_positions.exc_info) else: if physical_positions.value is None: raise PoolException("Cannot calculate motion: " "calc_all_physical returns None") if items is None: items = {} for new_position, element in zip(physical_positions.value, user_elements): if new_position is None: raise PoolException("Cannot calculate motion: %s reports " "position to be None" % element.name) # TODO: use Sardana attribute configuration and # get rid of accessing tango - see sardana-org/sardana#663 from sardana.tango.core.util import _check_attr_range try: _check_attr_range(element.name, "position", new_position) except ValueError as e: # TODO: don't concatenate exception message whenever # tango-controls/pytango#340 is fixed msg = "requested move of {} is outside of limits ({})".format( element.name, str(e)) raise ValueError(msg) from e element.calculate_motion(new_position, items=items, calculated=calculated) return items
def calculate_motion(self, new_position, items=None, calculated=None): # if items already contains the positions for this pseudo motor # underlying motors it means the motion has already been calculated # by a sibling if items is not None and len(items): physical_elements = self.get_physical_elements_set() s_items = set(items) if s_items == physical_elements: if calculated is not None and self in calculated: return user_elements = self.get_user_elements() positions = self.get_siblings_positions( use=calculated, write_pos=self.drift_correction) positions[self] = new_position pseudo_positions = len(positions) * [None] for pseudo, position in positions.items(): pseudo_positions[pseudo.axis - 1] = position curr_physical_positions = self._position.get_physical_positions() physical_positions = self.controller.calc_all_physical( pseudo_positions, curr_physical_positions) if physical_positions.error: raise PoolException( "Cannot calculate motion: " "calc_all_physical raises exception", exc_info=physical_positions.exc_info) else: if physical_positions.value is None: raise PoolException("Cannot calculate motion: " "calc_all_physical returns None") if items is None: items = {} for new_position, element in zip(physical_positions.value, user_elements): if new_position is None: raise PoolException("Cannot calculate motion: %s reports " "position to be None" % element.name) element.calculate_motion(new_position, items=items, calculated=calculated) return items
def get_physical_positions(self): ret = [] for pos_attr in self.obj.get_physical_position_attribute_iterator(): # if underlying moveable doesn't have position yet, it is because # of a cold start if not pos_attr.has_value(): pos_attr.update(propagate=0) if pos_attr.in_error(): raise PoolException("Cannot get '%' position" % pos_attr.obj.name, exc_info=pos_attr.exc_info) ret.append(pos_attr.value) return ret
def get_physical_values(self): ret = [] for value_attr in self.obj.get_physical_value_attribute_iterator(): # if underlying channel doesn't have value yet, it is because # of a cold start if not value_attr.has_value(): value_attr.update(propagate=0) if value_attr.in_error(): raise PoolException("Cannot get '%s' value" % value_attr.obj.name, exc_info=value_attr.exc_info) ret.append(value_attr.value) return ret
def calculate_motion(self, new_position, items=None, calculated=None): # if items already contains the positions for this pseudo motor # underlying motors it means the motion has already been calculated # by a sibling if items is not None and len(items): physical_elements = self.get_physical_elements_set() s_items = set(items) if s_items == physical_elements: if calculated is not None and self in calculated: return user_elements = self.get_user_elements() positions = self.get_siblings_positions(use=calculated, write_pos=self.drift_correction) positions[self] = new_position pseudo_positions = len(positions) * [None] for pseudo, position in positions.items(): pseudo_positions[pseudo.axis - 1] = position curr_physical_positions = self._position.get_physical_positions() physical_positions = self.controller.calc_all_physical(pseudo_positions, curr_physical_positions) if physical_positions.error: raise PoolException("Cannot calculate motion: " "calc_all_physical raises exception", exc_info=physical_positions.exc_info) else: if physical_positions.value is None: raise PoolException("Cannot calculate motion: " "calc_all_physical returns None") if items is None: items = {} positions = physical_positions.value if not hasattr(positions , "__iter__"): positions = [positions] for new_position, element in zip(positions, user_elements): if new_position is None: raise PoolException("Cannot calculate motion: %s reports " "position to be None" % element.name) # TODO: get the configuration for an specific sardana class and # get rid of AttributeProxy - see sardana-org/sardana#663 config = AttributeProxy(element.name + '/position').get_config() try: high = float(config.max_value) except ValueError: high = None try: low = float(config.min_value) except ValueError: low = None if high is not None: if float(new_position) > high: msg = "requested movement of %s is above its upper limit"\ % element.name raise RuntimeError(msg) if low is not None: if float(new_position) < low: msg = "requested movement of %s is below its lower limit"\ % element.name raise RuntimeError(msg) element.calculate_motion(new_position, items=items, calculated=calculated)