def __notify_and_remove_none_values( self, parameters: PythonJsonStructure) -> PythonJsonStructure: """ Return parameters from the QCoDeS snapshot which are not None. Takes the parameters of the QCoDeS instrument snapshot. Removes all parameters which have a value of None. Returns the parameter settings which have a value. All parameters with None value will be listed in the log as an error. Args: parameters: The parameters of a QCoDeS instrument snapshot. Returns: PythonJsonStructure: Contains the instrument snapshot parameters without the instrument parameters which a none value. """ valued_parameters = PythonJsonStructure() none_value_parameters = PythonJsonStructure() for parameter_name, settings in parameters.items(): if 'value' in settings and settings['value'] is None: none_value_parameters[parameter_name] = settings else: valued_parameters[parameter_name] = settings if none_value_parameters: parameter_names = list(none_value_parameters.keys()) error_message = f'Parameter values of {self._instrument_name} are None. Please set: {parameter_names}.' logging.error(error_message) return valued_parameters
def apply(self, config: PythonJsonStructure) -> None: """ Applies configuration 1. Apply configuration update for step, inter_delay. 2. Apply configuration update for unit of dac parameters based on dac1 unit. 3. Compares rest of the configuration values with setter command, to existing values and raises error in case of mismatch. Args: config: Containing the instrument configuration. """ unit = config['dac1']['unit'] self._instrument.set_dac_unit(unit) dac_parameters = { param: values for param, values in config.items() if param[0:3] == 'dac' } for dac, values in dac_parameters.items(): self._instrument[dac].step = values['step'] self._instrument[dac].inter_delay = values['inter_delay'] super().apply(config)
def _filter_parameters(self, parameters: PythonJsonStructure) -> PythonJsonStructure: filter_items = ['_elf_data', '_waveform_descriptors', '_sequencer_program', '_sequencer_assembly', '_elf_name', '_dio_data', '_waveform_waves_', 'system_nics_', 'triggers_streams_', 'features_code'] filtered = {parameter: value for (parameter, value) in parameters.items() if all(filter not in parameter for filter in filter_items)} return PythonJsonStructure(filtered)
class InstrumentConfiguration: """ Associates a configuration with an InstrumentAdapter and allows it to be stored or retrieved from storage.""" STORAGE_BASE_TAG = 'configuration' def __init__(self, adapter_class_name: str, address: str, storage: StorageInterface, tag: Optional[List[str]] = None, configuration: Optional[PythonJsonStructure] = None, instrument_name: Optional[str] = None) -> None: """ A set of instrument configurations Args instrument_adapter_class_name: Name of the InstrumentAdapter subclass address: Address of the physical instrument storage: Any storage that implements the StorageInterface tag: A unique identifier for a instrument configuration set configuration: The instrument configuration instrument_name: User defined name for the instrument """ self._adapter_class_name = adapter_class_name self._address = address self._storage = storage self._instrument_name = instrument_name self._adapter = InstrumentAdapterFactory.get_instrument_adapter(adapter_class_name, address, instrument_name) self._configuration = PythonJsonStructure() if configuration is None else configuration self._tag = [self.STORAGE_BASE_TAG, adapter_class_name, StorageInterface.datetag_part()] if tag is None else tag def __repr__(self): repr_string = f'{self.__class__.__name__}({self._adapter_class_name!r}, {self._address!r}, {self._storage!r}, '\ f'{self._tag!r}, {self._configuration!r}, {self._instrument_name!r})' return repr_string @property def tag(self) -> List[str]: """ A unique identifier for this instrument configuration set """ return self._tag @property def storage(self) -> StorageInterface: """ The storage interface used """ return self._storage @property def address(self) -> str: """ The address of the physical instrument """ return self._address @property def configuration(self) -> PythonJsonStructure: """ The instrument configuration """ return self._configuration @staticmethod def load(tag: List[str], storage: StorageInterface) -> 'InstrumentConfiguration': """ A factory that creates a new InstrumentConfiguration by loading from database. Args: tag: A unique identifier for a instrument configuration. storage: Default mongo database, but can optionally be any storage that implements the StorageInterface. Returns: A new InstrumentConfiguration loaded from database. """ document = storage.load_data(tag) adapter_class_name = document['adapter_class_name'] address = document['address'] instrument_name = document.get('instrument_name', None) configuration = document['configuration'] return InstrumentConfiguration(adapter_class_name, address, storage, tag, configuration, instrument_name) def store(self) -> None: """ Saves object to storage. Raises: DuplicateTagError: If this object's tag is already in the database. """ if self._storage.tag_in_storage(self._tag): raise DuplicateTagError( f"InstrumentConfiguration for {self._adapter_class_name} with tag '{self._tag}' already in storage") document = PythonJsonStructure(adapter_class_name=self._adapter_class_name, address=self._address, instrument_name=self._instrument_name, configuration=self._configuration) self._storage.save_data(document, self._tag) def apply(self) -> None: """ Uploads the configuration to the instrument.""" self._adapter.apply(self._configuration) def apply_delta(self, update: bool = True) -> None: """ Compare configuration with instrument and apply configuration that differs. Args: update: If True, request all parameter values from instrument, else use latest set values. """ instrument_config = self._adapter.read(update=update) delta = self._get_configuration_delta(instrument_config) self._adapter.apply(delta) def _get_configuration_delta(self, instrument_config: PythonJsonStructure) -> PythonJsonStructure: delta = PythonJsonStructure() for parameter, configuration in self._configuration.items(): if 'value' in configuration and configuration['value'] != instrument_config[parameter]['value']: delta[parameter] = configuration return delta def apply_delta_lazy(self) -> None: """ Compare configuration with instrument driver last known settings and apply configuration that differs.""" self.apply_delta(update=False) def refresh(self) -> None: """ Read the settings from the instrument and updated configuration. If the settings read from the instrument differs from the configuration the tag is also updated. """ instrument_config = self._adapter.read(update=True) delta = self._get_configuration_delta(instrument_config) if len(delta) > 0 or len(instrument_config) != len(self._configuration): self._configuration = instrument_config self._tag = [self.STORAGE_BASE_TAG, self._adapter_class_name, StorageInterface.datetag_part()] def accept(self, visitor: Visitor) -> None: """ Accept a visitor, run visit method with self as a parameter and propagate to instrument adapter. Args: visitor: An implementation of the Visitor interface. """ visitor.visit(self) self._adapter.accept(visitor)