Source code for dachs.equipment

#!/usr/bin/env python
# coding: utf-8

"""
A dataclass for specifying a generic piece of equipment.
"""

__author__ = "Brian R. Pauw"
__contact__ = "brian@stack.nl"
__license__ = "GPLv3+"
__date__ = "2022/11/15"
__status__ = "beta"

import logging
from typing import Dict, Optional

import pandas as pd
from attrs import Factory, define, field, validators

from dachs import ureg  # get importError when using: "from . import ureg"
from dachs.additemstoattrs import addItemsToAttrs
from dachs.helpers import whitespaceCleanup


[docs] @define class PV(addItemsToAttrs): """ A process variable which can be added to a piece of equipment. Each process variable has a calibration factor and calibration offset as well. These link the actual output with the set value as follows: PV_real = PV_set * calibrationFactor + calibrationOffset """ ID: str = field( default=None, validator=[validators.instance_of(str), validators.min_len(1)], converter=str, ) PVName: str = field( default=None, validator=[validators.instance_of(str), validators.min_len(1)], converter=str, ) Setpoint: float = field( default=None, validator=validators.instance_of(ureg.Quantity), converter=ureg, ) Actual: float = field( default=None, validator=validators.instance_of(ureg.Quantity), converter=ureg, ) Description: str = field( default=None, validator=validators.instance_of(str), converter=whitespaceCleanup, ) CalibrationFactor: float = field( default=None, validator=validators.optional(validators.instance_of(float)), # filter out NaN which is valid float, set it to a neutral value converter=lambda val: float(val) if not pd.isnull(val) else 1.0, ) CalibrationOffset: ureg.Quantity = field( default=None, validator=validators.optional(validators.instance_of(ureg.Quantity)), # filter out NaN which is valid float, set it to a neutral value converter=lambda val: ureg(str(val if not pd.isnull(val) else "0 dimensionless")), ) # internals, don't need a lot of validation: _excludeKeys: list = ["_excludeKeys", "_storeKeys"] # exclude from HDF storage _storeKeys: list = [] # store these keys (will be filled in later) _loadKeys: list = [] # load these keys from file if reconstructing
# value=Setpoint # straightforward for now # def __attrs_post_init__(self): # # auto-generate the store and load key lists: # super().__attrs_post_init__()
[docs] @define class Equipment(addItemsToAttrs): ID: str = field( default=None, validator=validators.instance_of(str), converter=str, ) EquipmentID: str = field( default=None, validator=validators.instance_of(str), converter=str, ) EquipmentName: str = field( default=None, validator=validators.instance_of(str), converter=str, ) Manufacturer: str = field( default=None, validator=validators.instance_of(str), converter=str, ) ModelName: str = field( default=None, validator=validators.instance_of(str), converter=str, ) ModelNumber: Optional[str] = field( default=None, validator=validators.optional(validators.instance_of(str)), converter=str, ) Description: Optional[str] = field( default=None, validator=validators.optional(validators.instance_of(str)), converter=whitespaceCleanup, ) PriceDate: Optional[str] = field( default=None, validator=validators.optional(validators.instance_of(str)), ) UnitPrice: Optional[ureg.Quantity] = field( default=None, validator=validators.optional(validators.instance_of(ureg.Quantity)), ) UnitSize: Optional[ureg.Quantity] = field( default=None, validator=validators.optional(validators.instance_of(ureg.Quantity)), ) PVs: Dict[str, PV] = field( default=Factory(dict), validator=validators.instance_of(dict), ) # AlternativeIDs: List[str] = field( # default=Factory(list), # validator=validators.instance_of(list), # ) # internals, don't need a lot of validation: _excludeKeys: list = ["_excludeKeys", "_storeKeys"] # exclude from HDF storage _storeKeys: list = [] # store these keys (will be filled in later) _loadKeys: list = [] # load these keys from file if reconstructing # def __attrs_post_init__(self): # # auto-generate the store and load key lists: # super().__attrs_post_init__() def PricePerUnit(self): assert (self.UnitPrice is not None) and (self.UnitSize is not None), logging.warning( "PricePerUnit can only be calculated when both UnitSize and UnitPrice are set" ) return self.UnitPrice / self.UnitSize