Source code for libpyvinyl.Instrument

"""
:module Instrument: Module hosting the Instrument class
"""

from libpyvinyl.Parameters.Collections import InstrumentParameters
from libpyvinyl import BaseCalculator
from libpyvinyl.BaseData import DataCollection

# typing
from libpyvinyl.Parameters.Collections import MasterParameters
from typing import Union, Any, Tuple, List, Dict, Optional


[docs]class Instrument: """Class collecting the parameters and calculators representing an entire instrument at a facility"""
[docs] def __init__( self, name: str, calculators: Optional[Dict[str, BaseCalculator]] = None, instrument_base_dir: str = "./", ): """Instrument object initialization: :param name: The name of this instrument :param calculators: a collection of Calculator objects. """ self.__name: str = "" self.__instrument_base_dir: str = "" self.__parameters = InstrumentParameters() self.name = name self.__calculators: Dict[str, BaseCalculator] = {} if calculators is not None: for calculator in calculators: self.add_calculator(calculator) self.set_instrument_base_dir(instrument_base_dir)
[docs] def add_master_parameter(self, name: str, links: Dict[str, str], **kwargs) -> None: """ Add a new parameter with the given name as master parameter. The goal is to link parameters in multiple calculators that represent the same quantity and that should be all changed at the same time when any of them is changed. This is obtained creating the link and by changing the value of the newly created master parameter. :param name: name of the master parameter :param links: dictionary with the names of the calculators and calculator parameters that represent the same quantity and hence can be changed all at once modifying the master parameter" """ self.parameters.add_master_parameter(name, links, **kwargs)
@property def name(self) -> str: """The name of this instrument.""" return self.__name @name.setter def name(self, value: str) -> None: if isinstance(value, str): self.__name = value else: raise TypeError( f"Instrument: name is expecting a str rather than {type(value)}" ) @property def calculators(self) -> Dict[str, BaseCalculator]: """The list of calculators. It's modified either when constructing the class instance or using the :meth:`~libpyvinyl.Instrument.add_calculator` function. """ return self.__calculators @property def parameters(self) -> InstrumentParameters: """ The parameter collection of each calculator in the instrument. These parameters are links to the exact parameters of each calculator. """ return self.__parameters @property def master(self) -> MasterParameters: """Return the master parameters""" return self.parameters.master @property def instrument_base_dir(self) -> str: return self.__instrument_base_dir @instrument_base_dir.setter def instrument_base_dir(self, value): self.set_instrument_base_dir(value)
[docs] def set_instrument_base_dir(self, base: str) -> None: """Set each calculator's `instrument_base_dir` to '`base`. Each calculator's data file ouput directory will be "`instrument_base_dir`/`calculator_base_dir`". :param base: The base directory to be set. :type base: str """ if isinstance(base, str): self.__instrument_base_dir = base for calculator in self.calculators.values(): calculator.instrument_base_dir = self.__instrument_base_dir else: raise TypeError( f"Instrument: instrument_base_dir is expecting a str rather than {type(base)}" )
def __repr_calculators(self) -> str: """ Return the list of all defined calculators for this instrument """ string = f"- Instrument: {self.name} -\n" string += "Calculators:\n" for key in self.calculators: string += f"{key}\n" return string
[docs] def list_calculators(self) -> None: """ Print the list of all defined calculators for this instrument """ string = self.__repr_calculators() print(string)
[docs] def list_parameters(self) -> None: """ Print the list of all calculator parameters """ print(self.parameters)
[docs] def add_calculator(self, calculator: BaseCalculator) -> None: """ Append one calculator to the list of calculators. N.B. calculators are executed in the same order as they are provided :param calculator: calculator """ self.__calculators[calculator.name] = calculator self.__parameters.add(calculator.name, calculator.parameters)
[docs] def remove_calculator(self, calculator_name: str) -> None: """ Remove the calculator with the given name from the list of calculators :param calculator_name: name of one calculator already added to the list """ del self.__calculators[calculator_name] del self.__parameters[calculator_name]
[docs] def run(self) -> None: """ Run the entire simulation, i.e. all the calculators in the order they have been provided """ for calculator in self.calculators.values(): calculator.backengine()
@property def output(self) -> DataCollection: """Return the output of the last calculator""" return list(self.__calculators.values())[-1].output def __str__(self) -> str: mystring = f"######## Instrument {self.name}\n" mystring += self.__repr_calculators() mystring += repr(self.parameters) mystring += f"############" return mystring