def test_Valve(self): """Test component properties of valves.""" instance = Valve('valve') self.setup_piping_network(instance) # parameter specification self.c1.set_attr(fluid={'CH4': 1}, m=10, p=10, T=120) self.c2.set_attr(p=1) # test variable pressure ration instance.set_attr(pr='var') self.nw.solve('design') convergence_check(self.nw.lin_dep) pr = round(self.c2.p.val_SI / self.c1.p.val_SI, 2) msg = ('Value of pressure ratio must be ' + str(pr) + ', is ' + str(round(instance.pr.val, 2)) + '.') assert pr == round(instance.pr.val, 2), msg # test variable zeta value zeta = round(instance.zeta.val, 0) instance.set_attr(zeta='var', pr=None) self.nw.solve('design') convergence_check(self.nw.lin_dep) msg = ('Value of dimension independent zeta value must be ' + str(zeta) + ', is ' + str(round(instance.zeta.val, 0)) + '.') assert zeta == round(instance.zeta.val, 0), msg # dp char x = np.array([8, 9, 10, 11, 12]) y = np.array([5, 8, 9, 9.5, 9.6]) * 1e5 dp_char = CharLine(x, y) instance.set_attr(zeta=None, dp_char={ 'char_func': dp_char, 'is_set': True }) m = 11 self.c1.set_attr(m=m) self.c2.set_attr(p=np.nan) self.nw.solve('design') convergence_check(self.nw.lin_dep) self.nw.print_results() dp = round(-dp_char.evaluate(m), 0) dp_act = round(self.c2.p.val_SI - self.c1.p.val_SI) msg = ('The pressure drop at the valve should be ' + str(dp) + ' but ' 'is ' + str(dp_act) + '.') assert dp == dp_act, msg
def test_CharLine_extrapolation(): """Test the characteristc line with extrapolation.""" # create a characteristc line with values of y=(x-2)^2 line = CharLine(x=[0, 1, 2, 3, 4], y=[4, 1, 0, 1, 4], extrapolate=True) # test evaluation at x=-1 to check lower limits, result: y=7 x = -1 y = line.evaluate(x) msg = ('The evaluation of x=' + str(x) + ' must be 7, but is ' + str(y) + '.') assert y == 7.0, msg # test evaluation at x=5 to check upper limits, result: y=7 x = 5 y = line.evaluate(x) msg = ('The evaluation of x=' + str(x) + ' must be 7, but is ' + str(y) + '.') assert y == 7.0, msg
def test_CharLine_evaluation(): """Test the characteristc line evaluation.""" # create a characteristc line with values of y=(x-2)^2 line = CharLine(x=[0, 1, 2, 3, 4], y=[4, 1, 0, 1, 4]) # test evaluation at given x value (x=3, y=1) x = 3 y = line.evaluate(x) msg = ('The evaluation of x=' + str(x) + ' must be 1.0, but is ' + str(y) + '.') assert y == 1.0, msg # test evaluation at x=0.5 to force interpolation, result: y=2.5 x = 0.5 y = line.evaluate(x) msg = ('The evaluation of x=' + str(x) + ' must be 2.5, but is ' + str(y) + '.') assert y == 2.5, msg # test evaluation at x=-1 to check lower limits, result: y=4 x = -1 y = line.evaluate(x) msg = ('The evaluation of x=' + str(x) + ' must be 4, but is ' + str(y) + '.') assert y == 4.0, msg # test evaluation at x=5 to check upper limits, result: y=4 x = 5 y = line.evaluate(x) msg = ('The evaluation of x=' + str(x) + ' must be 4, but is ' + str(y) + '.') assert y == 4.0, msg
def __init__(self, label, **kwargs): self.comps = pd.DataFrame( columns=['param', 'P_ref', 'char', 'efficiency', 'base']) self.label = label self.P = dc_simple(val=np.nan, is_set=False) self.char = CharLine(x=np.array([0, 3]), y=np.array([1, 1])) self.printout = True self.set_attr(**kwargs) msg = 'Created bus ' + self.label + '.' logging.debug(msg)
def test_Turbine_missing_char_parameter(): """Turbine with invalid parameter for eta_s_char function.""" nw = Network(['CH4']) so = Source('source') si = Sink('sink') instance = Turbine('turbine') c1 = Connection(so, 'out1', instance, 'in1') c2 = Connection(instance, 'out1', si, 'in1') nw.add_conns(c1, c2) instance.set_attr(eta_s_char={ 'char_func': CharLine([0, 1], [1, 2]), 'is_set': True, 'param': None}) nw.solve('design', init_only=True) with raises(ValueError): instance.eta_s_char_func()
def test_get_attr_errors(): """Test errors of get_attr methods.""" nw = Network(['water', 'air']) comb = CombustionEngine('combustion engine') pipeline = Pipe('pipeline') conn = Connection(comb, 'out1', pipeline, 'in1') mybus = Bus('mybus') sub = Subsystem('MySub') get_attr_KeyError(comb, 'wow') get_attr_KeyError(conn, 'key') get_attr_KeyError(mybus, 'components') get_attr_KeyError(nw, 'missing') get_attr_KeyError(Ref(conn, 1, 0), 'comp') get_attr_KeyError(sub, 'test') get_attr_KeyError(CharLine(), 'test') get_attr_KeyError(DataContainer(), 'somekey') get_attr_KeyError(CharMap(), 'Stuff')
def busses_add_comps(c, *args): r""" Add components to busses according to data from .csv file. Parameters ---------- c : pandas.core.series.Series Component information from .csv-file. args[0] : pandas.core.frame.DataFrame DataFrame containing all created busses. args[1] : pandas.core.frame.DataFrame DataFrame containing all created characteristic lines. """ i = 0 for b in c.busses: param = c.bus_param[i] P_ref = c.bus_P_ref[i] char = c.bus_char[i] base = 'component' if 'bus_base' in c.index: base = c.bus_base[i] values = char == args[1]['id'] char = CharLine(x=args[1][values].x.values[0], y=args[1][values].y.values[0]) # add component with corresponding details to bus args[0].instance[b == args[0]['label']].values[0].add_comps({ 'comp': c.instance, 'param': param, 'P_ref': P_ref, 'char': char, 'base': base }) i += 1
# heating system cd_hs_feed.set_attr(T=40, p=2, fluid={'water': 1, 'R410A': 0}) hs_ret_hsp.set_attr(T=35, p=2) # starting values va_ev.set_attr(h0=275) cc_cd.set_attr(p0=18) # %% create busses # characteristic function for motor efficiency x = np.array([0, 0.2, 0.4, 0.6, 0.8, 1, 1.2, 1.4]) y = np.array([0, 0.86, 0.9, 0.93, 0.95, 0.96, 0.95, 0.93]) # power bus char = CharLine(x=x, y=y) power = Bus('power input') power.add_comps({ 'comp': cp, 'char': char, 'base': 'bus' }, { 'comp': ghp, 'char': char, 'base': 'bus' }, { 'comp': hsp, 'char': char, 'base': 'bus' })
def setup(self): # %% network setup self.nw = Network(fluids=['water', 'NH3'], T_unit='C', p_unit='bar', h_unit='kJ / kg', m_unit='kg / s') # %% components # sources & sinks cc_coolant = CycleCloser('coolant cycle closer') cc_consumer = CycleCloser('consumer cycle closer') amb_in = Source('source ambient') amb_out = Sink('sink ambient') ic_in = Source('source intercool') ic_out = Sink('sink intercool') # consumer system cd = HeatExchanger('condenser') rp = Pump('recirculation pump') cons = HeatExchangerSimple('consumer') # evaporator system va = Valve('valve') dr = Drum('drum') ev = HeatExchanger('evaporator') su = HeatExchanger('superheater') pu = Pump('pump evaporator') # compressor-system cp1 = Compressor('compressor 1') cp2 = Compressor('compressor 2') he = HeatExchanger('intercooler') # busses self.power = Bus('total compressor power') self.power.add_comps({ 'comp': cp1, 'base': 'bus' }, { 'comp': cp2, 'base': 'bus' }) self.heat = Bus('total delivered heat') self.heat.add_comps({'comp': cd, 'char': -1}) self.nw.add_busses(self.power, self.heat) # %% connections # consumer system c_in_cd = Connection(cc_coolant, 'out1', cd, 'in1') cb_rp = Connection(cc_consumer, 'out1', rp, 'in1') rp_cd = Connection(rp, 'out1', cd, 'in2') self.cd_cons = Connection(cd, 'out2', cons, 'in1') cons_cf = Connection(cons, 'out1', cc_consumer, 'in1') self.nw.add_conns(c_in_cd, cb_rp, rp_cd, self.cd_cons, cons_cf) # connection condenser - evaporator system cd_va = Connection(cd, 'out1', va, 'in1') self.nw.add_conns(cd_va) # evaporator system va_dr = Connection(va, 'out1', dr, 'in1') dr_pu = Connection(dr, 'out1', pu, 'in1') pu_ev = Connection(pu, 'out1', ev, 'in2') ev_dr = Connection(ev, 'out2', dr, 'in2') dr_su = Connection(dr, 'out2', su, 'in2') self.nw.add_conns(va_dr, dr_pu, pu_ev, ev_dr, dr_su) self.amb_in_su = Connection(amb_in, 'out1', su, 'in1') su_ev = Connection(su, 'out1', ev, 'in1') ev_amb_out = Connection(ev, 'out1', amb_out, 'in1') self.nw.add_conns(self.amb_in_su, su_ev, ev_amb_out) # connection evaporator system - compressor system su_cp1 = Connection(su, 'out2', cp1, 'in1') self.nw.add_conns(su_cp1) # compressor-system cp1_he = Connection(cp1, 'out1', he, 'in1') he_cp2 = Connection(he, 'out1', cp2, 'in1') cp2_c_out = Connection(cp2, 'out1', cc_coolant, 'in1') ic_in_he = Connection(ic_in, 'out1', he, 'in2') he_ic_out = Connection(he, 'out2', ic_out, 'in1') self.nw.add_conns(cp1_he, he_cp2, ic_in_he, he_ic_out, cp2_c_out) # %% component parametrization # condenser system x = np.array([ 0, 0.0625, 0.125, 0.1875, 0.25, 0.3125, 0.375, 0.4375, 0.5, 0.5625, 0.6375, 0.7125, 0.7875, 0.9, 0.9875, 1, 1.0625, 1.125, 1.175, 1.2125, 1.2375, 1.25 ]) y = np.array([ 0.0076, 0.1390, 0.2731, 0.4003, 0.5185, 0.6263, 0.7224, 0.8056, 0.8754, 0.9312, 0.9729, 1.0006, 1.0203, 1.0158, 1.0051, 1.0000, 0.9746, 0.9289, 0.8832, 0.8376, 0.7843, 0.7614 ]) rp.set_attr(eta_s=0.8, design=['eta_s'], offdesign=['eta_s_char'], eta_s_char={ 'char_func': CharLine(x, y), 'param': 'm' }) cons.set_attr(pr=1, design=['pr'], offdesign=['zeta']) # evaporator system x = np.linspace(0, 2.5, 26) y = np.array([ 0.000, 0.164, 0.283, 0.389, 0.488, 0.581, 0.670, 0.756, 0.840, 0.921, 1.000, 1.078, 1.154, 1.228, 1.302, 1.374, 1.446, 1.516, 1.585, 1.654, 1.722, 1.789, 1.855, 1.921, 1.986, 2.051 ]) kA_char1 = {'char_func': CharLine(x, y), 'param': 'm'} x = np.array([ 0.0100, 0.0400, 0.0700, 0.1100, 0.1500, 0.2000, 0.2500, 0.3000, 0.3500, 0.4000, 0.4500, 0.5000, 0.5500, 0.6000, 0.6500, 0.7000, 0.7500, 0.8000, 0.8500, 0.9000, 0.9500, 1.0000, 1.5000, 2.0000 ]) y = np.array([ 0.0185, 0.0751, 0.1336, 0.2147, 0.2997, 0.4118, 0.5310, 0.6582, 0.7942, 0.9400, 0.9883, 0.9913, 0.9936, 0.9953, 0.9966, 0.9975, 0.9983, 0.9988, 0.9992, 0.9996, 0.9998, 1.0000, 1.0008, 1.0014 ]) kA_char2 = {'char_func': CharLine(x, y), 'param': 'm'} ev.set_attr(pr1=1, pr2=.999, ttd_l=5, design=['ttd_l'], offdesign=['kA_char'], kA_char1=kA_char1, kA_char2=kA_char2) # no kA modification for hot side! x = np.array([0, 1]) y = np.array([1, 1]) kA_char1 = {'char_func': CharLine(x, y), 'param': 'm'} # characteristic line for superheater kA x = np.array( [0, 0.045, 0.136, 0.244, 0.43, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2]) y = np.array( [0, 0.037, 0.112, 0.207, 0.5, 0.8, 0.85, 0.9, 0.95, 1, 1.04, 1.07]) kA_char2 = {'char_func': CharLine(x, y), 'param': 'm'} su.set_attr(kA_char1=kA_char1, kA_char2=kA_char2, offdesign=['zeta1', 'zeta2', 'kA_char']) x = np.array([ 0, 0.0625, 0.125, 0.1875, 0.25, 0.3125, 0.375, 0.4375, 0.5, 0.5625, 0.6375, 0.7125, 0.7875, 0.9, 0.9875, 1, 1.0625, 1.125, 1.175, 1.2125, 1.2375, 1.25 ]) y = np.array([ 0.0076, 0.1390, 0.2731, 0.4003, 0.5185, 0.6263, 0.7224, 0.8056, 0.8754, 0.9312, 0.9729, 1.0006, 1.0203, 1.0158, 1.0051, 1.0000, 0.9746, 0.9289, 0.8832, 0.8376, 0.7843, 0.7614 ]) pu.set_attr(eta_s=0.8, design=['eta_s'], offdesign=['eta_s_char'], eta_s_char={ 'char_func': CharLine(x, y), 'param': 'm' }) # compressor system x = np.array([0, 0.4, 1, 1.2]) y = np.array([0.5, 0.9, 1, 1.1]) cp1.set_attr(eta_s=0.8, design=['eta_s'], offdesign=['eta_s_char'], eta_s_char={ 'char_func': CharLine(x, y), 'param': 'm' }) cp2.set_attr(eta_s=0.8, design=['eta_s'], offdesign=['eta_s_char'], eta_s_char={ 'char_func': CharLine(x, y), 'param': 'm' }) # characteristic line for intercooler kA x = np.linspace(0, 2.5, 26) y = np.array([ 0.0000, 0.2455, 0.3747, 0.4798, 0.5718, 0.6552, 0.7323, 0.8045, 0.8727, 0.9378, 1.0000, 1.0599, 1.1176, 1.1736, 1.2278, 1.2806, 1.3320, 1.3822, 1.4313, 1.4792, 1.5263, 1.5724, 1.6176, 1.6621, 1.7058, 1.7488 ]) kA_char1 = {'char_func': CharLine(x, y), 'param': 'm'} x = np.linspace(0, 2.5, 26) y = np.array([ 0.000, 0.164, 0.283, 0.389, 0.488, 0.581, 0.670, 0.756, 0.840, 0.921, 1.000, 1.078, 1.154, 1.228, 1.302, 1.374, 1.446, 1.516, 1.585, 1.654, 1.722, 1.789, 1.855, 1.921, 1.986, 2.051 ]) kA_char2 = {'char_func': CharLine(x, y), 'param': 'm'} he.set_attr(kA_char1=kA_char1, kA_char2=kA_char2, offdesign=['zeta1', 'zeta2', 'kA_char']) # characteristic line for condenser kA x = np.linspace(0, 2.5, 26) y = np.array([ 0.0000, 0.2455, 0.3747, 0.4798, 0.5718, 0.6552, 0.7323, 0.8045, 0.8727, 0.9378, 1.0000, 1.0599, 1.1176, 1.1736, 1.2278, 1.2806, 1.3320, 1.3822, 1.4313, 1.4792, 1.5263, 1.5724, 1.6176, 1.6621, 1.7058, 1.7488 ]) kA_char1 = {'char_func': CharLine(x, y), 'param': 'm'} x = np.linspace(0, 2.5, 26) y = np.array([ 0.000, 0.164, 0.283, 0.389, 0.488, 0.581, 0.670, 0.756, 0.840, 0.921, 1.000, 1.078, 1.154, 1.228, 1.302, 1.374, 1.446, 1.516, 1.585, 1.654, 1.722, 1.789, 1.855, 1.921, 1.986, 2.051 ]) kA_char2 = {'char_func': CharLine(x, y), 'param': 'm'} cd.set_attr(kA_char1=kA_char1, kA_char2=kA_char2, pr2=0.9998, design=['pr2'], offdesign=['zeta2', 'kA_char']) # %% connection parametrization # condenser system c_in_cd.set_attr(fluid={'water': 0, 'NH3': 1}, p=60) rp_cd.set_attr(T=60, fluid={'water': 1, 'NH3': 0}, p=10) self.cd_cons.set_attr(T=105) cd_va.set_attr(p=Ref(c_in_cd, 1, -0.01), Td_bp=-5, design=['Td_bp']) # evaporator system cold side pu_ev.set_attr(m=Ref(va_dr, 10, 0), p0=5) dr_su.set_attr(p0=5, T=5) su_cp1.set_attr(p=Ref(dr_su, 1, -0.05), Td_bp=5, design=['Td_bp', 'p']) # evaporator system hot side self.amb_in_su.set_attr(m=20, T=12, p=1, fluid={'water': 1, 'NH3': 0}) su_ev.set_attr(p=Ref(self.amb_in_su, 1, -0.001), design=['p']) ev_amb_out.set_attr() # compressor-system cp1_he.set_attr(p=15) he_cp2.set_attr(T=40, p=Ref(cp1_he, 1, -0.01), design=['T', 'p']) ic_in_he.set_attr(p=1, T=20, m=5, fluid={'water': 1, 'NH3': 0}) he_ic_out.set_attr(p=Ref(ic_in_he, 1, -0.002), design=['p'])
def test_Pump(self): """Test component properties of pumps.""" instance = Pump('pump') self.setup_network(instance) fl = {'N2': 0, 'O2': 0, 'Ar': 0, 'DowQ': 1, 'NH3': 0} self.c1.set_attr(fluid=fl, v=1, p=5, T=50) self.c2.set_attr(p=7) instance.set_attr(eta_s=1) self.nw.solve('design') convergence_check(self.nw.lin_dep) # test calculated value for efficiency eta_s = ((isentropic(self.c1.get_flow(), self.c2.get_flow()) - self.c1.h.val_SI) / (self.c2.h.val_SI - self.c1.h.val_SI)) msg = ('Value of isentropic efficiency must be ' + str(eta_s) + ', is ' + str(instance.eta_s.val) + '.') assert eta_s == instance.eta_s.val, msg # isentropic efficiency of 1 means inlet and outlet entropy are # identical s1 = round(s_mix_ph(self.c1.get_flow()), 4) s2 = round(s_mix_ph(self.c2.get_flow()), 4) msg = ('Value of entropy must be identical for inlet (' + str(s1) + ') and outlet (' + str(s2) + ') at 100 % isentropic efficiency.') assert s1 == s2, msg # specify realistic value for efficiency, outlet pressure from flow # char eta_s_d = 0.8 instance.set_attr(eta_s=eta_s_d) self.nw.solve('design') convergence_check(self.nw.lin_dep) self.nw.save('tmp') self.c2.set_attr(p=np.nan) # flow char (pressure rise vs. volumetric flow) x = [0, 0.2, 0.4, 0.6, 0.8, 1, 1.2, 1.4] y = np.array([14, 13.5, 12.5, 11, 9, 6.5, 3.5, 0]) * 1e5 char = {'char_func': CharLine(x, y), 'is_set': True} # apply flow char and eta_s char instance.set_attr(flow_char=char, eta_s=np.nan, eta_s_char={ 'char_func': ldc('pump', 'eta_s_char', 'DEFAULT', CharLine), 'is_set': True }) self.nw.solve('offdesign', design_path='tmp') convergence_check(self.nw.lin_dep) # value for difference pressure dp = 650000.0 msg = ('Value of pressure rise must be ' + str(dp) + ', is ' + str(self.c2.p.val_SI - self.c1.p.val_SI) + '.') assert round(self.c2.p.val_SI - self.c1.p.val_SI, 0) == dp, msg # test ohter volumetric flow on flow char self.c1.set_attr(v=0.9) self.nw.solve('offdesign', design_path='tmp') convergence_check(self.nw.lin_dep) dp = 775000.0 msg = ('Value of pressure rise must be ' + str(dp) + ', is ' + str(round(self.c2.p.val_SI - self.c1.p.val_SI, 0)) + '.') assert round(self.c2.p.val_SI - self.c1.p.val_SI, 0) == dp, msg # test value of isentropic efficiency eta_s = round( eta_s_d * instance.eta_s_char.char_func.evaluate( self.c1.v.val_SI / self.c1.v.design), 3) msg = ('Value of isentropic efficiency must be ' + str(eta_s) + ', is ' + str(instance.eta_s.val) + '.') assert eta_s == round(instance.eta_s.val, 3), msg instance.eta_s_char.is_set = False # test boundaries of characteristic line: # lower boundary instance.set_attr(eta_s=0.8) self.c1.set_attr(m=0, v=None) self.nw.solve('design') convergence_check(self.nw.lin_dep) msg = ('Value of power must be ' + str(14e5) + ', is ' + str(round(self.c2.p.val_SI - self.c1.p.val_SI, 0)) + '.') assert round(self.c2.p.val_SI - self.c1.p.val_SI, 0) == 14e5, msg # upper boundary self.c1.set_attr(v=1.5, m=None) self.nw.solve('design') convergence_check(self.nw.lin_dep) msg = ('Value of power must be 0, is ' + str(round(self.c2.p.val_SI - self.c1.p.val_SI, 0)) + '.') assert round(self.c2.p.val_SI - self.c1.p.val_SI, 0) == 0, msg shutil.rmtree('./tmp', ignore_errors=True)
def construct_comps(c, *args): r""" Create TESPy component from class name and set parameters. Parameters ---------- c : pandas.core.series.Series Component information from .csv-file. args[0] : pandas.core.frame.DataFrame DataFrame containing the data of characteristic lines. args[1] : pandas.core.frame.DataFrame DataFrame containing the data of characteristic maps. Returns ------- instance : tespy.components.component.Component TESPy component object. """ target_class = comp_target_classes[c['comp_type']] instance = target_class(c['label']) kwargs = {} # basic properties for key in [ 'design', 'offdesign', 'design_path', 'local_design', 'local_offdesign' ]: if key in c: if isinstance(c[key], float): kwargs[key] = None else: kwargs[key] = c[key] for key, value in instance.variables.items(): if key in c: # component parameters if isinstance(value, dc_cp): kwargs[key] = { 'val': c[key], 'is_set': c[key + '_set'], 'is_var': c[key + '_var'] } # component parameters elif isinstance(value, dc_simple): instance.get_attr(key).set_attr(**{ 'val': c[key], 'is_set': c[key + '_set'] }) # component characteristics elif isinstance(value, dc_cc): # finding x and y values of the characteristic function values = args[0]['id'] == c[key] try: x = args[0][values].x.values[0] y = args[0][values].y.values[0] extrapolate = False if 'extrapolate' in args[0].columns: extrapolate = args[0][values].extrapolate.values[0] char = CharLine(x=x, y=y, extrapolate=extrapolate) except IndexError: char = None msg = ('Could not find x and y values for characteristic ' 'line, using defaults instead for function ' + key + ' at component ' + c.label + '.') logging.warning(msg) kwargs[key] = { 'is_set': c[key + '_set'], 'param': c[key + '_param'], 'char_func': char } # component characteristics elif isinstance(value, dc_cm): # finding x and y values of the characteristic function values = args[1]['id'] == c[key] try: x = list(args[1][values].x.values[0]) y = list(args[1][values].y.values[0]) z = list(args[1][values].z.values[0]) char = CharMap(x=x, y=y, z=z) except IndexError: char = None msg = ('Could not find x, y and z values for ' 'characteristic map of component ' + c.label + '!') logging.warning(msg) kwargs[key] = { 'is_set': c[key + '_set'], 'param': c[key + '_param'], 'char_func': char } # grouped component parameters elif isinstance(value, dc_gcp): kwargs[key] = {'method': c[key]} instance.set_attr(**kwargs) return instance
def comp_init(self, nw, num_eq=0): r""" Perform component initialization in network preprocessing. Parameters ---------- nw : tespy.networks.network.Network Network this component is integrated in. """ self.num_nw_fluids = len(nw.fluids) self.nw_fluids = nw.fluids self.always_all_equations = nw.always_all_equations self.num_nw_vars = self.num_nw_fluids + 3 self.it = 0 self.num_eq = 0 self.vars = {} self.num_vars = 0 self.constraints = OrderedDict(self.get_mandatory_constraints().copy()) self.__dict__.update(self.constraints) for constraint in self.constraints.values(): self.num_eq += constraint['num_eq'] for key, val in self.variables.items(): data = self.get_attr(key) if isinstance(val, dc_cp): if data.is_var: data.var_pos = self.num_vars self.num_vars += 1 self.vars[data] = key # component characteristics elif isinstance(val, dc_cc): if data.char_func is None: try: data.char_func = ldc( self.component(), key, 'DEFAULT', CharLine) except KeyError: data.char_func = CharLine(x=[0, 1], y=[1, 1]) # component characteristics elif isinstance(val, dc_cm): if data.char_func is None: try: data.char_func = ldc( self.component(), key, 'DEFAULT', CharMap) except KeyError: data.char_func = CharLine(x=[0, 1], y=[1, 1]) # grouped component properties elif isinstance(val, dc_gcp): is_set = True for e in data.elements: if not self.get_attr(e).is_set: is_set = False if is_set: data.set_attr(is_set=True) elif data.is_set: start = ( 'All parameters of the component group have to be ' 'specified! This component group uses the following ' 'parameters: ') end = ' at ' + self.label + '. Group will be set to False.' logging.warning(start + ', '.join(val.elements) + end) val.set_attr(is_set=False) else: val.set_attr(is_set=False) # component properties if data.is_set and data.func is not None: self.num_eq += data.num_eq # print(key, data.is_set, self.num_eq) # set up Jacobian matrix and residual vector self.jacobian = np.zeros(( self.num_eq, self.num_i + self.num_o + self.num_vars, self.num_nw_vars)) self.residual = np.zeros(self.num_eq) sum_eq = 0 for constraint in self.constraints.values(): num_eq = constraint['num_eq'] if constraint['constant_deriv']: self.jacobian[sum_eq:sum_eq + num_eq] = constraint['deriv']() sum_eq += num_eq # done msg = ( 'The component ' + self.label + ' has ' + str(self.num_vars) + ' custom variables.') logging.debug(msg)
nw.add_conns(cp_c_out) # %% busses # motor efficiency x = np.array([ 0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.05, 1.1, 1.15, 1.2, 10 ]) y = 1 / (np.array([ 0.01, 0.3148, 0.5346, 0.6843, 0.7835, 0.8477, 0.8885, 0.9145, 0.9318, 0.9443, 0.9546, 0.9638, 0.9724, 0.9806, 0.9878, 0.9938, 0.9982, 1.0009, 1.002, 1.0015, 1, 0.9977, 0.9947, 0.9909, 0.9853, 0.9644 ]) * 0.98) mot1 = CharLine(x=x, y=y) mot2 = CharLine(x=x, y=y) mot3 = CharLine(x=x, y=y) mot4 = CharLine(x=x, y=y) power = Bus('total compressor power') power.add_comps({ 'comp': cp, 'char': mot1 }, { 'comp': pu, 'char': mot2 }, { 'comp': dhp, 'char': mot3 }, {
cons_out = Connection(cons, 'out1', cw_out, 'in1') nw.add_conns(m_fgc, fgc_cons, cons_out) # %% busses # motor efficiency x = np.array([ 0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.05, 1.1, 1.15, 1.2, 10 ]) y = 1 / (np.array([ 0.01, 0.3148, 0.5346, 0.6843, 0.7835, 0.8477, 0.8885, 0.9145, 0.9318, 0.9443, 0.9546, 0.9638, 0.9724, 0.9806, 0.9878, 0.9938, 0.9982, 1.0009, 1.002, 1.0015, 1, 0.9977, 0.9947, 0.9909, 0.9853, 0.9644 ]) * 0.97) mot = CharLine(x=x, y=y) # generator efficiency x = np.array([ 0.100, 0.345, 0.359, 0.383, 0.410, 0.432, 0.451, 0.504, 0.541, 0.600, 0.684, 0.805, 1.000, 1.700, 10 ]) y = np.array([ 0.976, 0.989, 0.990, 0.991, 0.992, 0.993, 0.994, 0.995, 0.996, 0.997, 0.998, 0.999, 1.000, 0.999, 0.99 ]) * -0.984 gen1 = CharLine(x=x, y=y) gen2 = CharLine(x=x, y=y) power = Bus('power') power.add_comps({
def test_char_number_of_points(): with raises(ValueError): CharLine(x=[0, 1, 2], y=[1, 2, 3, 4])
nw.add_conns(cc_st, st_con, con_pu, pu_sg1, sg1_sg2, sg2_sg3, sg3_cc) # district heating dh_Source_con = Connection(dh_Source, 'out1', con, 'in2') con_dh_Sink = Connection(con, 'out2', dh_Sink, 'in1') nw.add_conns(dh_Source_con, con_dh_Sink) # %% Busses # power Bus power = Bus('power output') x = np.array([0.2, 0.4, 0.6, 0.8, 1.0, 1.1]) y = np.array([0.85, 0.93, 0.95, 0.96, 0.97, 0.96]) # create a characteristic line for a generator gen = CharLine(x=x, y=y) power.add_comps({'comp': st, 'char': gen}, {'comp': pu, 'char': gen}) nw.add_busses(power) # %% parameterisation # components st.set_attr(eta_s=0.9, design=['eta_s'], offdesign=['eta_s_char', 'cone']) con.set_attr(pr1=0.99, pr2=0.99, ttd_u=5, design=['pr2', 'ttd_u'], offdesign=['kA_char']) pu.set_attr(eta_s=0.8, design=['eta_s'], offdesign=['eta_s_char']) sg1.set_attr(pr=0.99)
def setup(self): """Set up the model.""" # %% network setup fluid_list = ['Ar', 'N2', 'O2', 'CO2', 'CH4', 'H2O'] self.nw = Network(fluids=fluid_list, p_unit='bar', T_unit='C', p_range=[0.5, 20]) # %% components amb = Source('ambient') sf = Source('fuel') cc = CombustionChamber('combustion') cp = Compressor('compressor') gt = Turbine('turbine') fg = Sink('flue gas outlet') # %% connections amb_cp = Connection(amb, 'out1', cp, 'in1', label='ambient air flow') cp_cc = Connection(cp, 'out1', cc, 'in1') sf_cc = Connection(sf, 'out1', cc, 'in2') cc_gt = Connection(cc, 'out1', gt, 'in1') gt_fg = Connection(gt, 'out1', fg, 'in1') self.nw.add_conns(amb_cp, cp_cc, sf_cc, cc_gt, gt_fg) # %% component parameters cc.set_attr(lamb=3) cp.set_attr(eta_s=0.9, pr=15) gt.set_attr(eta_s=0.9) # %% connection parameters amb_cp.set_attr(T=20, p=1, m=100, fluid={ 'Ar': 0.0129, 'N2': 0.7553, 'H2O': 0, 'CH4': 0, 'CO2': 0.0004, 'O2': 0.2314 }) sf_cc.set_attr(T=20, fluid={ 'CO2': 0.04, 'Ar': 0, 'N2': 0, 'O2': 0, 'H2O': 0, 'CH4': 0.96 }) gt_fg.set_attr(p=1) # motor efficiency x = np.array([ 0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.05, 1.1, 1.15, 1.2, 10 ]) y = np.array([ 0.01, 0.3148, 0.5346, 0.6843, 0.7835, 0.8477, 0.8885, 0.9145, 0.9318, 0.9443, 0.9546, 0.9638, 0.9724, 0.9806, 0.9878, 0.9938, 0.9982, 0.999, 0.9995, 0.9999, 1, 0.9977, 0.9947, 0.9909, 0.9853, 0.9644 ]) * 0.975 self.motor_bus_based = CharLine(x=x, y=y) self.motor_comp_based = CharLine(x=x, y=1 / y) # generator efficiency x = np.array([ 0.100, 0.345, 0.359, 0.383, 0.410, 0.432, 0.451, 0.504, 0.541, 0.600, 0.684, 0.805, 1.000, 1.700, 10 ]) y = np.array([ 0.976, 0.989, 0.990, 0.991, 0.992, 0.993, 0.994, 0.995, 0.996, 0.997, 0.998, 0.999, 1.000, 0.999, 0.99 ]) * 0.975 self.generator = CharLine(x=x, y=y) power_bus_total = Bus('total power output') power_bus_total.add_comps( { 'comp': cp, 'char': self.motor_bus_based, 'base': 'bus' }, { 'comp': gt, 'char': self.generator }) thermal_input = Bus('thermal input') thermal_input.add_comps({'comp': cc}) compressor_power_comp = Bus('compressor power input') compressor_power_comp.add_comps({ 'comp': cp, 'char': self.motor_comp_based }) compressor_power_bus = Bus('compressor power input bus based') compressor_power_bus.add_comps({ 'comp': cp, 'char': self.motor_bus_based, 'base': 'bus' }) self.nw.add_busses(power_bus_total, thermal_input, compressor_power_comp, compressor_power_bus) # %% solving self.nw.solve('design') self.nw.save('tmp')
class TestBusses: def setup(self): """Set up the model.""" # %% network setup fluid_list = ['Ar', 'N2', 'O2', 'CO2', 'CH4', 'H2O'] self.nw = Network(fluids=fluid_list, p_unit='bar', T_unit='C', p_range=[0.5, 20]) # %% components amb = Source('ambient') sf = Source('fuel') cc = CombustionChamber('combustion') cp = Compressor('compressor') gt = Turbine('turbine') fg = Sink('flue gas outlet') # %% connections amb_cp = Connection(amb, 'out1', cp, 'in1', label='ambient air flow') cp_cc = Connection(cp, 'out1', cc, 'in1') sf_cc = Connection(sf, 'out1', cc, 'in2') cc_gt = Connection(cc, 'out1', gt, 'in1') gt_fg = Connection(gt, 'out1', fg, 'in1') self.nw.add_conns(amb_cp, cp_cc, sf_cc, cc_gt, gt_fg) # %% component parameters cc.set_attr(lamb=3) cp.set_attr(eta_s=0.9, pr=15) gt.set_attr(eta_s=0.9) # %% connection parameters amb_cp.set_attr(T=20, p=1, m=100, fluid={ 'Ar': 0.0129, 'N2': 0.7553, 'H2O': 0, 'CH4': 0, 'CO2': 0.0004, 'O2': 0.2314 }) sf_cc.set_attr(T=20, fluid={ 'CO2': 0.04, 'Ar': 0, 'N2': 0, 'O2': 0, 'H2O': 0, 'CH4': 0.96 }) gt_fg.set_attr(p=1) # motor efficiency x = np.array([ 0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.05, 1.1, 1.15, 1.2, 10 ]) y = np.array([ 0.01, 0.3148, 0.5346, 0.6843, 0.7835, 0.8477, 0.8885, 0.9145, 0.9318, 0.9443, 0.9546, 0.9638, 0.9724, 0.9806, 0.9878, 0.9938, 0.9982, 0.999, 0.9995, 0.9999, 1, 0.9977, 0.9947, 0.9909, 0.9853, 0.9644 ]) * 0.975 self.motor_bus_based = CharLine(x=x, y=y) self.motor_comp_based = CharLine(x=x, y=1 / y) # generator efficiency x = np.array([ 0.100, 0.345, 0.359, 0.383, 0.410, 0.432, 0.451, 0.504, 0.541, 0.600, 0.684, 0.805, 1.000, 1.700, 10 ]) y = np.array([ 0.976, 0.989, 0.990, 0.991, 0.992, 0.993, 0.994, 0.995, 0.996, 0.997, 0.998, 0.999, 1.000, 0.999, 0.99 ]) * 0.975 self.generator = CharLine(x=x, y=y) power_bus_total = Bus('total power output') power_bus_total.add_comps( { 'comp': cp, 'char': self.motor_bus_based, 'base': 'bus' }, { 'comp': gt, 'char': self.generator }) thermal_input = Bus('thermal input') thermal_input.add_comps({'comp': cc}) compressor_power_comp = Bus('compressor power input') compressor_power_comp.add_comps({ 'comp': cp, 'char': self.motor_comp_based }) compressor_power_bus = Bus('compressor power input bus based') compressor_power_bus.add_comps({ 'comp': cp, 'char': self.motor_bus_based, 'base': 'bus' }) self.nw.add_busses(power_bus_total, thermal_input, compressor_power_comp, compressor_power_bus) # %% solving self.nw.solve('design') self.nw.save('tmp') def test_model(self): """Test the bus functionalities in a gas turbine model.""" tpo = self.nw.busses['total power output'] ti = self.nw.busses['thermal input'] cpi = self.nw.busses['compressor power input'] cpibb = self.nw.busses['compressor power input bus based'] cp = self.nw.components['compressor'] gt = self.nw.components['turbine'] cc = self.nw.components['combustion'] # test results of design case eta_cpi = round(1 / cp.calc_bus_efficiency(cpi), 6) eta_cp_tpo = round(cp.calc_bus_efficiency(tpo), 6) msg = ('The efficiency value of the compressor on the bus ' + tpo.label + ' (' + str(eta_cp_tpo) + ') must be identical to the efficiency ' 'on the bus ' + cpi.label + ' (' + str(eta_cpi) + ').') assert eta_cp_tpo == eta_cpi, msg P_cp_tpo = cp.calc_bus_value(tpo) eta_cp_tpo = cp.calc_bus_efficiency(tpo) P_cp = round(P_cp_tpo * eta_cp_tpo, 0) msg = ('The compressor power must be ' + str(round(cp.P.val, 0)) + ' on ' 'the bus ' + tpo.label + ' but is ' + str(P_cp) + ').') assert round(cp.P.val, 0) == P_cp, msg P_cp_tpo = round( cp.calc_bus_value(tpo) * cp.calc_bus_efficiency(tpo), 0) P_cp_cpi = round( cp.calc_bus_value(cpi) / cp.calc_bus_efficiency(cpi), 0) P_cp_cpibb = round( cp.calc_bus_value(cpibb) * cp.calc_bus_efficiency(cpibb), 0) msg = ( 'The busses\' component power value for the compressor on bus ' + tpo.label + ' (' + str(P_cp_tpo) + ') must be equal to the ' 'component power on all other busses. Bus ' + cpi.label + ' (' + str(P_cp_cpi) + ') and bus ' + cpibb.label + ' (' + str(P_cp_cpibb) + ').') assert P_cp_tpo == P_cp_cpi and P_cp_tpo == P_cp_cpibb, msg eta_gt_tpo = gt.calc_bus_efficiency(tpo) msg = ('The efficiency value of the turbine on the bus ' + tpo.label + ' (' + str(eta_gt_tpo) + ') must be equal to 0.975.') assert eta_gt_tpo == 0.975, msg eta_ti = cc.calc_bus_efficiency(ti) msg = ('The efficiency value of the combustion chamber on the bus ' + ti.label + ' (' + str(eta_ti) + ') must be equal to 1.0.') assert eta_ti == 1.0, msg # test partload for bus functions # first test in identical conditions self.nw.connections['ambient air flow'].set_attr(m=None) P_design = cpibb.P.val cpibb.set_attr(P=P_design) self.nw.solve('offdesign', design_path='tmp') eta_cpi = round(1 / cp.calc_bus_efficiency(cpi), 6) eta_cp_tpo = round(cp.calc_bus_efficiency(tpo), 6) msg = ('The efficiency value of the compressor on the bus ' + tpo.label + ' (' + str(eta_cp_tpo) + ') must be identical to the efficiency ' 'on the bus ' + cpi.label + ' (' + str(eta_cpi) + ').') assert eta_cp_tpo == eta_cpi, msg eta_gt_tpo = gt.calc_bus_efficiency(tpo) msg = ('The efficiency value of the turbine on the bus ' + tpo.label + ' (' + str(eta_gt_tpo) + ') must be equal to 0.975.') assert eta_gt_tpo == 0.975, msg P_cp_tpo = round( cp.calc_bus_value(tpo) * cp.calc_bus_efficiency(tpo), 0) P_cp_cpi = round( cp.calc_bus_value(cpi) / cp.calc_bus_efficiency(cpi), 0) P_cp_cpibb = round( cp.calc_bus_value(cpibb) * cp.calc_bus_efficiency(cpibb), 0) msg = ( 'The busses\' component power value for the compressor on bus ' + tpo.label + ' (' + str(P_cp_tpo) + ') must be equal to the ' 'component power on all other busses. Bus ' + cpi.label + ' (' + str(P_cp_cpi) + ') and bus ' + cpibb.label + ' (' + str(P_cp_cpibb) + ').') assert P_cp_tpo == P_cp_cpi and P_cp_tpo == P_cp_cpibb, msg # 60 % load load = 0.6 cpibb.set_attr(P=P_design * load) self.nw.solve('offdesign', design_path='tmp') eta_cp_tpo = round(cp.calc_bus_efficiency(tpo), 6) eta_cp_char = self.motor_bus_based.evaluate(load) msg = ('The efficiency value of the compressor on the bus ' + tpo.label + ' (' + str(eta_cp_tpo) + ') must be identical to the efficiency ' 'on the characteristic line (' + str(eta_cp_char) + ').') assert eta_cp_tpo == eta_cp_char, msg load_frac = round( cp.calc_bus_value(tpo) / tpo.comps.loc[cp, 'P_ref'], 6) msg = ('The load fraction value of the compressor on the bus ' + tpo.label + ' (' + str(load_frac) + ') must be identical to the ' 'load fraction value on the bus ' + cpibb.label + ' (' + str(load) + ').') assert load == load_frac, msg eta_cpi = round(1 / cp.calc_bus_efficiency(cpi), 6) eta_cp_tpo = round(cp.calc_bus_efficiency(tpo), 6) msg = ('The efficiency value of the compressor on the bus ' + tpo.label + ' (' + str(eta_cp_tpo) + ') must be higher than the efficiency ' 'on the bus ' + cpi.label + ' (' + str(eta_cpi) + ').') assert eta_cp_tpo > eta_cpi, msg P_cp_tpo = round( cp.calc_bus_value(tpo) * cp.calc_bus_efficiency(tpo), 0) P_cp_cpi = round( cp.calc_bus_value(cpi) / cp.calc_bus_efficiency(cpi), 0) P_cp_cpibb = round( cp.calc_bus_value(cpibb) * cp.calc_bus_efficiency(cpibb), 0) msg = ( 'The busses\' component power value for the compressor on bus ' + tpo.label + ' (' + str(P_cp_tpo) + ') must be equal to the ' 'component power on all other busses. Bus ' + cpi.label + ' (' + str(P_cp_cpi) + ') and bus ' + cpibb.label + ' (' + str(P_cp_cpibb) + ').') assert P_cp_tpo == P_cp_cpi and P_cp_tpo == P_cp_cpibb, msg shutil.rmtree('tmp', ignore_errors=True)
def add_comps(self, *args): r""" Add components to a bus. Parameters ---------- *args : dict Dictionaries containing the component information to be added to the bus. The information are described below. Note ---- **Required Key** - comp (tespy.components.component.Component): Component you want to add to the bus. **Optional Keys** - param (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 combustion engine ('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 :py:class:`tespy.tools.characteristics.CharLine`, if you want the factor to follow a characteristic line. - P_ref (float): Energy flow specification for reference case, :math:`P \text{/W}`, optional. - base (str): Base value for characteristic line and efficiency calculation. The base can either be :code:`'component'` (default) or :code:`'bus'`. - In case you choose :code:`'component'`, the characteristic line input will follow the value of the component's bus function and the efficiency definition is :math:`\eta=\frac{P_\mathrm{bus}}{P_\mathrm{component}}`. - In case you choose :code:`'bus'`, the characteristic line input will follow the bus value of the component and the efficiency definition is :math:`\eta=\frac{P_\mathrm{component}}{P_\mathrm{bus}}`. """ for c in args: if isinstance(c, dict): if 'comp' in c.keys(): comp = c['comp'] # default values if isinstance(comp, Component): self.comps.loc[comp] = [ None, np.nan, self.char, np.nan, 'component'] else: msg = 'Keyword "comp" must hold a TESPy component.' logging.error(msg) raise TypeError(msg) else: msg = 'You must provide the component "comp".' logging.error(msg) raise TypeError(msg) for k, v in c.items(): if k == 'param': if isinstance(v, str) or v is None: self.comps.loc[comp, 'param'] = v else: msg = ( 'The bus parameter selection must be a ' 'string (at bus ' + self.label + ').') logging.error(msg) raise TypeError(msg) elif k == 'char': try: float(v) is_numeric = True except (TypeError, ValueError): is_numeric = False if isinstance(v, CharLine): self.comps.loc[comp, 'char'] = v elif is_numeric: x = np.array([0, 3]) y = np.array([1, 1]) * v self.comps.loc[comp, 'char'] = ( CharLine(x=x, y=y)) else: msg = ( 'Char must be a number or a TESPy ' 'characteristics char line.') logging.error(msg) raise TypeError(msg) elif k == 'P_ref': try: float(v) is_numeric = True except (TypeError, ValueError): is_numeric = False if v is None or is_numeric: self.comps.loc[comp, 'P_ref'] = v else: msg = 'Reference value must be numeric.' logging.error(msg) raise TypeError(msg) elif k == 'base': if v in ['bus', 'component']: self.comps.loc[comp, 'base'] = v else: msg = ( 'The base value must be "bus" or "component".') logging.error(msg) raise ValueError(msg) else: msg = ( 'Provide arguments as dictionaries. See the documentation ' 'of bus.add_comps() for more information.') logging.error(msg) raise TypeError(msg) msg = ( 'Added component ' + comp.label + ' to bus ' + self.label + '.') logging.debug(msg)
nw.add_conns(cw_i, cw_o, dh_i, dh_o) # %% busses # motor efficiency x = np.array([ 0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.05, 1.1, 1.15, 1.2, 10 ]) y = (np.array([ 0.01, 0.3148, 0.5346, 0.6843, 0.7835, 0.8477, 0.8885, 0.9145, 0.9318, 0.9443, 0.9546, 0.9638, 0.9724, 0.9806, 0.9878, 0.9938, 0.9982, 1.0009, 1.002, 1.0015, 1, 0.9977, 0.9947, 0.9909, 0.9853, 0.9644 ]) * 0.97) mot = CharLine(x=x, y=y) # generator efficiency x = np.array([ 0.100, 0.345, 0.359, 0.383, 0.410, 0.432, 0.451, 0.504, 0.541, 0.600, 0.684, 0.805, 1.000, 1.700, 10 ]) y = np.array([ 0.976, 0.989, 0.990, 0.991, 0.992, 0.993, 0.994, 0.995, 0.996, 0.997, 0.998, 0.999, 1.000, 0.999, 0.99 ]) * 0.984 gen = CharLine(x=x, y=y) power = Bus('power output') power.add_comps({