def __init__(self, comp1, outlet_id, comp2, inlet_id, **kwargs): # check input parameters if not (isinstance(comp1, component) and isinstance(comp2, component)): msg = ('Error creating connection. Check if comp1, comp2 are of ' 'type component.') logging.error(msg) raise TypeError(msg) if comp1 == comp2: msg = ('Error creating connection. Cannot connect component ' + comp1.label + ' to itself.') logging.error(msg) raise TESPyConnectionError(msg) if outlet_id not in comp1.outlets(): msg = ('Error creating connection. Specified oulet_id (' + outlet_id + ') is not valid for component ' + comp1.component() + '. Valid ids are: ' + str(comp1.outlets()) + '.') logging.error(msg) raise ValueError(msg) if inlet_id not in comp2.inlets(): msg = ( 'Error creating connection. Specified inlet_id (' + inlet_id + ') is not valid for component ' + comp2.component() + '. Valid ids are: ' + str(comp2.inlets()) + '.') logging.error(msg) raise ValueError(msg) self.label = ( comp1.label + ':' + outlet_id + '_' + comp2.label + ':' + inlet_id) # set specified values self.source = comp1 self.source_id = outlet_id self.target = comp2 self.target_id = inlet_id # defaults self.new_design = True self.design_path = None self.design = [] self.offdesign = [] self.local_design = False self.local_offdesign = False self.printout = True # set default values for kwargs self.variables = self.attr() self.variables0 = [x + '0' for x in self.variables.keys()] self.__dict__.update(self.variables) self.set_attr(**kwargs) msg = ( 'Created connection ' + self.source.label + ' (' + self.source_id + ') -> ' + self.target.label + ' (' + self.target_id + ').') logging.debug(msg)
def __init__(self, *args, **kwargs): msg = ('Version 0.4.x introduced PEP 8 conform class names for all ' 'classes used in TESPy. Please refer to ' 'https://tespy.readthedocs.io/en/master/whats_new.html ' 'learn about the changes necessary to adapt your script to the ' 'latest API.') logging.error(msg) raise TESPyConnectionError(msg)
def __init__(self, comp1, outlet_id, comp2, inlet_id, **kwargs): # check input parameters if not (isinstance(comp1, cmp.component) and isinstance(comp2, cmp.component)): msg = ('Error creating connection. Check if comp1, comp2 are of ' 'type component.') logging.error(msg) raise TypeError(msg) if comp1 == comp2: msg = ('Error creating connection. Can\'t connect component ' + comp1.label + ' to itself.') logging.error(msg) raise TESPyConnectionError(msg) if outlet_id not in comp1.outlets(): msg = ('Error creating connection. Specified oulet_id (' + outlet_id + ') is not valid for component ' + comp1.component() + '. Valid ids are: ' + str(comp1.outlets()) + '.') logging.error(msg) raise ValueError(msg) if inlet_id not in comp2.inlets(): msg = ('Error creating connection. Specified inlet_id (' + inlet_id + ') is not valid for component ' + comp2.component() + '. Valid ids are: ' + str(comp2.inlets()) + '.') logging.error(msg) raise ValueError(msg) # set specified values self.s = comp1 self.s_id = outlet_id self.t = comp2 self.t_id = inlet_id # defaults self.new_design = True self.design_path = None self.design = [] self.offdesign = [] self.local_design = False self.local_offdesign = False # set default values for kwargs var = self.attr() for key in self.attr().keys(): self.__dict__.update({key: var[key]}) self.set_attr(**kwargs) msg = ('Created connection ' + self.s.label + ' (' + self.s_id + ') -> ' + self.t.label + ' (' + self.t_id + ').') logging.debug(msg)
def add_comps(self, *args): r""" Add components to a bus. Parameters ---------- c : dict Dictionary containing the component information to be added to the bus. These information are described in the notes! Note ---- Keys for the dictionary c: - c (tespy.components.components.component): Component you want to add to the bus. - p (str): Bus parameter, optional. - You do not need to provide a parameter, if the component only has one option for the bus (turbomachines, heat exchangers, combustion chamber). - For instance, you do neet do provide a parameter, if you want to add a cogeneration unit ('Q', 'Q1', 'Q2', 'TI', 'P', 'Qloss'). - char (float/tespy.components.characteristics.characteristics): Characteristic function for this components share to the bus value, optional. - If you do not provide a characteristic line at all, TESPy assumes a constant factor of 1. - If you provide a numeric value instead of a characteristic line, TESPy takes this numeric value as a constant factor. - Provide a TESPy.characteristic (cmp_char), if you want the factor to follow a characteristic line. - P_ref (float): Energy flow specification for reference case, :math:`P \text{/W}`, optional. """ for c in args: if isinstance(c, dict): if 'c' in c.keys(): if isinstance(c['c'], cmp.component): self.comps.loc[c['c']] = [None, np.nan, self.char] else: msg = ('Keyword c must hold a TESPy component.') logging.error(msg) raise TypeError(msg) else: msg = ('You must provide the component c.') logging.error(msg) raise TypeError(msg) for k, v in c.items(): if k == 'p': if isinstance(v, str) or v is None: self.comps.loc[c['c']]['param'] = v else: msg = ('Parameter p must be a string.') logging.error(msg) raise TypeError(msg) elif k == 'char': if isinstance(v, cmp_char.characteristics): self.comps.loc[c['c']]['char'] = v elif (isinstance(v, float) or isinstance(v, np.float64) or isinstance(v, np.int64) or isinstance(v, int)): x = np.array([0, 1, 2, 3]) y = np.array([1, 1, 1, 1]) * v self.comps.loc[c['c']]['char'] = ( cmp_char.characteristics(x=x, y=y)) else: msg = ( 'Char must be a number or a TESPy characteristics.' ) logging.error(msg) raise TypeError(msg) elif k == 'P_ref': if (v is None or isinstance(v, float) or isinstance(v, np.float64) or isinstance(v, np.int64) or isinstance(v, int)): self.comps.loc[c['c']]['P_ref'] = v else: msg = ('Reference value must be numeric.') logging.error(msg) raise TypeError(msg) else: msg = ( 'Provide arguments as dicts. See the documentation of bus.add_comps() for more information.' ) logging.error(msg) raise TESPyConnectionError(msg) msg = 'Added component ' + c[ 'c'].label + ' to bus ' + self.label + '.' logging.debug(msg)
def set_attr(self, **kwargs): r""" Set, reset or unset attributes of a connection. Parameters ---------- m : float, tespy.connections.connection.Ref Mass flow specification. m0 : float Starting value specification for mass flow. p : float, tespy.connections.connection.Ref Pressure specification. p0 : float Starting value specification for pressure. h : float, tespy.connections.connection.Ref Enthalpy specification. h0 : float Starting value specification for enthalpy. fluid : dict Fluid compostition specification. fluid0 : dict Starting value specification for fluid compostition. fluid_balance : boolean Fluid balance equation specification. x : float Gas phase mass fraction specification. T : float, tespy.connections.connection.Ref Temperature specification. Td_bp : float Temperature difference to boiling point at pressure corresponding pressure of this connection in K. v : float Volumetric flow specification. state : str State of the pure fluid on this connection: liquid ('l') or gaseous ('g'). design : list List containing design parameters (stated as string). offdesign : list List containing offdesign parameters (stated as string). design_path : str Path to individual design case for this connection. local_offdesign : boolean Treat this connection in offdesign mode in a design calculation. local_design : boolean Treat this connection in design mode in an offdesign calculation. printout : boolean Include this connection in the network's results printout. Note ---- - The fluid balance parameter applies a balancing of the fluid vector on the specified conntion to 100 %. For example, you have four fluid components (a, b, c and d) in your vector, you set two of them (a and b) and want the other two (components c and d) to be a result of your calculation. If you set this parameter to True, the equation (0 = 1 - a - b - c - d) will be applied. - The specification of values for design and/or offdesign is used for automatic switch from design to offdesign calculation: All parameters given in 'design', e.g. :code:`design=['T', 'p']`, are unset in any offdesign calculation, parameters given in 'offdesign' are set for offdesign calculation. - The property state is applied on pure fluids only. If you specify the desired state of the fluid at a connection the convergence check will adjust the enthalpy values of that connection for the first iterations in order to meet the state requirement. """ # set specified values for key in kwargs: if key == 'label': # bad datatype msg = 'Label can only be specified on instance creation.' logging.error(msg) raise TESPyConnectionError(msg) elif key in self.variables or key in self.variables0: # fluid specification try: float(kwargs[key]) is_numeric = True except (TypeError, ValueError): is_numeric = False if 'fluid' in key and key != 'fluid_balance': if isinstance(kwargs[key], dict): # starting values if key in self.variables0: self.fluid.set_attr(val0=kwargs[key].copy()) # specified parameters else: self.fluid.set_attr(val=kwargs[key].copy()) self.fluid.set_attr( val_set={f: True for f in kwargs[key].keys()}) else: # bad datatype msg = ( 'Datatype for fluid vector specification must be ' 'dict.') logging.error(msg) raise TypeError(msg) elif key == 'state': if kwargs[key] in ['l', 'g']: self.state.set_attr(val=kwargs[key], is_set=True) elif kwargs[key] is None: self.state.set_attr(is_set=False) elif is_numeric: if np.isnan(kwargs[key]): self.get_attr(key).set_attr(is_set=False) else: msg = ( 'To unset the state specification either use ' 'np.nan or None.') logging.error(msg) raise ValueError(msg) else: msg = ('Keyword argument "state" must either be ' '"l" or "g" or be None or np.nan.') logging.error(msg) raise TypeError(msg) elif kwargs[key] is None: self.get_attr(key).set_attr(val_set=False) self.get_attr(key).set_attr(ref_set=False) elif is_numeric: if np.isnan(kwargs[key]): self.get_attr(key).set_attr(val_set=False) self.get_attr(key).set_attr(ref_set=False) else: # value specification if key in self.variables: self.get_attr(key).set_attr(val_set=True, val=kwargs[key]) # starting value specification else: self.get_attr(key.replace( '0', '')).set_attr(val0=kwargs[key]) # reference object elif isinstance(kwargs[key], Ref): if key in ['x', 'v', 'Td_bp']: msg = ('References for volumetric flow, vapor mass ' 'fraction and subcooling/superheating are not ' 'implemented.') logging.error(msg) raise NotImplementedError(msg) else: self.get_attr(key).set_attr(ref=kwargs[key]) self.get_attr(key).set_attr(ref_set=True) # invalid datatype for keyword else: msg = 'Bad datatype for keyword argument ' + key + '.' logging.error(msg) raise TypeError(msg) # fluid balance elif key == 'fluid_balance': if isinstance(kwargs[key], bool): self.get_attr('fluid').set_attr(balance=kwargs[key]) else: msg = ( 'Datatype for keyword argument fluid_balance must be ' 'boolean.') logging.error(msg) raise TypeError(msg) # design/offdesign parameter list elif key == 'design' or key == 'offdesign': if not isinstance(kwargs[key], list): msg = 'Please provide the ' + key + ' parameters as list!' logging.error(msg) raise TypeError(msg) elif set(kwargs[key]).issubset(self.variables.keys()): self.__dict__.update({key: kwargs[key]}) else: params = ', '.join(self.variables.keys()) msg = ( 'Available parameters for (off-)design specification ' 'are: ' + params + '.') logging.error(msg) raise ValueError(msg) # design path elif key == 'design_path': if isinstance(kwargs[key], str): self.__dict__.update({key: kwargs[key]}) elif np.isnan(kwargs[key]): self.design_path = None else: msg = ( 'Please provide the design_path parameter as string ' 'or as nan.') logging.error(msg) raise TypeError(msg) self.new_design = True # other boolean keywords elif key in ['printout', 'local_design', 'local_offdesign']: if not isinstance(kwargs[key], bool): msg = ('Please provide the ' + key + ' as boolean.') logging.error(msg) raise TypeError(msg) else: self.__dict__.update({key: kwargs[key]}) # invalid keyword else: msg = 'Connection has no attribute ' + key + '.' logging.error(msg) raise KeyError(msg)