예제 #1
0
class TestCompressedAirIn:
    def setup(self):
        """Set up air compressor."""
        self.Tamb = 20
        self.pamb = 1
        fluids = ['Air']

        # compressor part
        self.nw = Network(fluids=fluids)
        self.nw.set_attr(p_unit='bar', T_unit='C', h_unit='kJ / kg')

        # components
        amb = Source('air intake')
        cp = Compressor('compressor')
        cooler = HeatExchangerSimple('cooling')
        cas = Sink('compressed air storage')

        # power input bus
        self.power_in = Bus('power input')
        self.power_in.add_comps({'comp': cp, 'char': 1, 'base': 'bus'})
        # compressed air bus (not sure about this!)
        self.cas_in = Bus('massflow into storage')
        self.cas_in.add_comps({'comp': cas}, {'comp': amb, 'base': 'bus'})
        self.nw.add_busses(self.power_in, self.cas_in)

        # create connections
        amb_cp = Connection(amb, 'out1', cp, 'in1')
        cp_cool = Connection(cp, 'out1', cooler, 'in1')
        cool_cas = Connection(cooler, 'out1', cas, 'in1')
        self.nw.add_conns(amb_cp, cp_cool, cool_cas)

        # component parameters
        cp.set_attr(eta_s=1)
        cooler.set_attr(pr=1)

        # connection parameters
        amb_cp.set_attr(m=2, T=self.Tamb, p=self.pamb, fluid={'Air': 1})
        cool_cas.set_attr(T=self.Tamb, p=10)

        # solve network
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)

    def test_exergy_analysis_bus_conversion(self):
        """Test exergy analysis at product exergy with T < Tamb."""
        self.nw.exergy_analysis(self.pamb,
                                self.Tamb,
                                E_P=[self.cas_in],
                                E_F=[self.power_in])

        exergy_balance = (self.nw.E_F - self.nw.E_P - self.nw.E_L -
                          self.nw.E_D)
        msg = ('Exergy balance must be closed (residual value smaller than ' +
               str(err**0.5) + ') for this test but is ' +
               str(round(abs(exergy_balance), 4)) + ' .')
        assert abs(exergy_balance) <= err**0.5, msg
예제 #2
0
class TestReactors:
    def setup(self):
        """Set up network for electrolyzer tests."""
        self.nw = Network(['O2', 'H2', 'H2O'], T_unit='C', p_unit='bar')
        self.instance = WaterElectrolyzer('electrolyzer')

        fw = Source('feed water')
        cw_in = Source('cooling water')
        o2 = Sink('oxygen sink')
        h2 = Sink('hydrogen sink')
        cw_out = Sink('cooling water sink')

        self.instance.set_attr(pr=0.99, eta=1)

        cw_el = Connection(cw_in,
                           'out1',
                           self.instance,
                           'in1',
                           fluid={
                               'H2O': 1,
                               'H2': 0,
                               'O2': 0
                           },
                           T=20,
                           p=1)
        el_cw = Connection(self.instance, 'out1', cw_out, 'in1', T=45)

        self.nw.add_conns(cw_el, el_cw)

        fw_el = Connection(fw, 'out1', self.instance, 'in2', label='h2o')
        el_o2 = Connection(self.instance, 'out2', o2, 'in1')
        el_h2 = Connection(self.instance, 'out3', h2, 'in1', label='h2')

        self.nw.add_conns(fw_el, el_o2, el_h2)

    def test_WaterElectrolyzer(self):
        """Test component properties of water electrolyzer."""
        # check bus function:
        # power output on component and bus must be indentical
        self.nw.get_conn('h2o').set_attr(T=25, p=1)
        self.nw.get_conn('h2').set_attr(T=25)
        power = Bus('power')
        power.add_comps({'comp': self.instance, 'param': 'P', 'base': 'bus'})
        power.set_attr(P=2.5e6)
        self.nw.add_busses(power)

        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of power must be ' + str(power.P.val) + ', is ' +
               str(self.instance.P.val) + '.')
        assert round(power.P.val, 1) == round(self.instance.P.val), msg

        # effieciency was set to 100 % with inlet and outlet states of the
        # reaction educts and products beeing identical to reference state
        # therefore Q must be equal to 0
        msg = ('Value of heat output must be 0.0, is ' +
               str(self.instance.Q.val) + '.')
        assert round(self.instance.Q.val, 4) == 0.0, msg

        # reset power, change efficiency value and specify heat bus value
        power.set_attr(P=np.nan)
        self.nw.get_conn('h2o').set_attr(T=25, p=1)
        self.nw.get_conn('h2').set_attr(T=50)
        self.instance.set_attr(eta=0.8)
        # check bus function:
        # heat output on component and bus must be indentical
        heat = Bus('heat')
        heat.add_comps({'comp': self.instance, 'param': 'Q'})
        heat.set_attr(P=-8e5)
        self.nw.add_busses(heat)

        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of heat flow must be ' + str(heat.P.val) + ', is ' +
               str(self.instance.Q.val) + '.')
        assert round(heat.P.val, 1) == round(self.instance.Q.val), msg
        self.nw.save('tmp')

        # check bus function:
        # heat output on component and bus must identical (offdesign test)
        Q = heat.P.val * 0.9
        heat.set_attr(P=Q)
        self.nw.solve('offdesign', design_path='tmp')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of heat flow must be ' + str(Q) + ', is ' +
               str(self.instance.Q.val) + '.')
        assert round(Q, 1) == round(self.instance.Q.val), msg

        # delete both busses again
        self.nw.del_busses(heat, power)

        # test efficiency vs. specific energy consumption
        self.nw.get_conn('h2').set_attr(m=0.1)
        self.instance.set_attr(eta=0.9, e='var')
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of efficiency must be ' + str(self.instance.eta.val) +
               ', is ' + str(self.instance.e0 / self.instance.e.val) + '.')
        eta = round(self.instance.eta.val, 2)
        eta_calc = round(self.instance.e0 / self.instance.e.val, 2)
        assert eta == eta_calc, msg

        # test efficiency value > 1, Q must be larger than 0
        e = 130e6
        self.instance.set_attr(e=np.nan, eta=np.nan)
        self.instance.set_attr(e=e)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        # test efficiency
        msg = ('Value of efficiency must be ' + str(self.instance.e0 / e) +
               ', is ' + str(self.instance.eta.val) + '.')
        eta = round(self.instance.e0 / e, 2)
        eta_calc = round(self.instance.eta.val, 2)
        assert eta == eta_calc, msg
        # test Q
        msg = ('Value of heat must be larger than zero, is ' +
               str(self.instance.Q.val) + '.')
        assert self.instance.Q.val > 0, msg

        # test specific energy consumption
        e = 150e6
        self.instance.set_attr(e=np.nan, eta=np.nan)
        self.instance.set_attr(e=e)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of specific energy consumption e must be ' + str(e) +
               ', is ' + str(self.instance.e.val) + '.')
        assert round(e, 1) == round(self.instance.e.val, 1), msg

        # test cooling loop pressure ratio, zeta as variable value
        pr = 0.95
        self.instance.set_attr(pr=pr,
                               e=None,
                               eta=None,
                               zeta='var',
                               P=2e7,
                               design=['pr'])
        self.nw.solve('design')
        shutil.rmtree('./tmp', ignore_errors=True)
        self.nw.save('tmp')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of pressure ratio must be ' + str(pr) + ', is ' +
               str(self.instance.pr.val) + '.')
        assert round(pr, 2) == round(self.instance.pr.val, 2), msg

        # use zeta as offdesign parameter, at design point pressure
        # ratio must not change
        self.instance.set_attr(zeta=np.nan, offdesign=['zeta'])
        self.nw.solve('offdesign', design_path='tmp')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of pressure ratio must be ' + str(pr) + ', is ' +
               str(self.instance.pr.val) + '.')
        assert round(pr, 2) == round(self.instance.pr.val, 2), msg

        # test heat output specification in offdesign mode
        Q = self.instance.Q.val * 0.9
        self.instance.set_attr(Q=Q, P=np.nan)
        self.nw.solve('offdesign', design_path='tmp')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of heat must be ' + str(Q) + ', is ' +
               str(self.instance.Q.val) + '.')
        assert round(Q, 0) == round(self.instance.Q.val, 0), msg
        shutil.rmtree('./tmp', ignore_errors=True)
예제 #3
0
class TestHeatExchangers:

    def setup(self):

        self.nw = Network(
            ['H2O', 'Ar', 'INCOMP::S800'], T_unit='C', p_unit='bar',
            v_unit='m3 / s')
        self.inl1 = Source('inlet 1')
        self.outl1 = Sink('outlet 1')

    def setup_HeatExchangerSimple_network(self, instance):

        self.c1 = Connection(self.inl1, 'out1', instance, 'in1')
        self.c2 = Connection(instance, 'out1', self.outl1, 'in1')

        self.nw.add_conns(self.c1, self.c2)

    def setup_HeatExchanger_network(self, instance):

        self.inl2 = Source('inlet 2')
        self.outl2 = Sink('outlet 2')

        self.c1 = Connection(self.inl1, 'out1', instance, 'in1')
        self.c2 = Connection(instance, 'out1', self.outl1, 'in1')
        self.c3 = Connection(self.inl2, 'out1', instance, 'in2')
        self.c4 = Connection(instance, 'out2', self.outl2, 'in1')

        self.nw.add_conns(self.c1, self.c2, self.c3, self.c4)

    def test_HeatExhangerSimple(self):
        """Test component properties of simple heat exchanger."""
        instance = HeatExchangerSimple('heat exchanger')
        self.setup_HeatExchangerSimple_network(instance)
        fl = {'Ar': 0, 'H2O': 1, 'S800': 0}
        self.c1.set_attr(fluid=fl, m=1, p=10, T=100)
        # trigger heat exchanger parameter groups
        instance.set_attr(hydro_group='HW', L=100, ks=100, pr=0.99, Tamb=20)

        # test grouped parameter settings with missing parameters
        instance.hydro_group.is_set = True
        instance.kA_group.is_set = True
        instance.kA_char_group.is_set = True
        self.nw.solve('design', init_only=True)
        msg = ('Hydro group must no be set, if one parameter is missing!')
        assert instance.hydro_group.is_set is False, msg
        msg = ('kA group must no be set, if one parameter is missing!')
        assert instance.kA_group.is_set is False, msg
        msg = ('kA char group must no be set, if one parameter is missing!')
        assert instance.kA_char_group.is_set is False, msg

        # test diameter calculation from specified dimensions (as pipe)
        # with Hazen-Williams method
        instance.set_attr(hydro_group='HW', D='var', L=100,
                          ks=100, pr=0.99, Tamb=20)
        b = Bus('heat', P=-1e5)
        b.add_comps({'comp': instance})
        self.nw.add_busses(b)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        pr = round(self.c2.p.val_SI / self.c1.p.val_SI, 3)
        msg = ('Value of pressure ratio must be ' + str(pr) + ', is ' +
               str(instance.pr.val) + '.')
        assert pr == round(instance.pr.val, 3), msg

        # make zeta system variable and use previously calculated diameter
        # to calculate zeta. The value for zeta must not change
        zeta = round(instance.zeta.val, 0)
        instance.set_attr(D=instance.D.val, zeta='var', pr=np.nan)
        instance.D.is_var = False
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of zeta must be ' + str(zeta) + ', is ' +
               str(round(instance.zeta.val, 0)) + '.')
        assert zeta == round(instance.zeta.val, 0), msg

        # same test with pressure ratio as sytem variable
        pr = round(instance.pr.val, 3)
        instance.set_attr(zeta=np.nan, pr='var')
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of pressure ratio must be ' + str(pr) +
               ', is ' + str(round(instance.pr.val, 3)) + '.')
        assert pr == round(instance.pr.val, 3), msg

        # test heat transfer coefficient as variable of the system (ambient
        # temperature required)
        instance.set_attr(kA='var', pr=np.nan)
        b.set_attr(P=-5e4)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)

        # due to heat output being half of reference (for Tamb) kA should be
        # somewhere near to that (actual value is 677)
        msg = ('Value of heat transfer coefficient must be 677, is ' +
               str(instance.kA.val) + '.')
        assert 677 == round(instance.kA.val, 0), msg

        # test heat transfer as variable of the system
        instance.set_attr(Q='var', kA=np.nan)
        Q = -5e4
        b.set_attr(P=Q)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of heat transfer must be ' + str(Q) +
               ', is ' + str(instance.Q.val) + '.')
        assert Q == round(instance.Q.val, 0), msg

    def test_ParabolicTrough(self):
        """Test component properties of parabolic trough."""
        instance = ParabolicTrough('parabolic trough')
        self.setup_HeatExchangerSimple_network(instance)
        fl = {'Ar': 0, 'H2O': 0, 'S800': 1}
        self.c1.set_attr(fluid=fl, p=2, T=200)
        self.c2.set_attr(T=350)

        # test grouped parameter settings with missing parameters
        instance.hydro_group.is_set = True
        instance.energy_group.is_set = True
        self.nw.solve('design', init_only=True)
        msg = ('Hydro group must no be set, if one parameter is missing!')
        assert instance.hydro_group.is_set is False, msg
        msg = ('Energy group must no be set, if one parameter is missing!')
        assert instance.energy_group.is_set is False, msg

        # test solar collector params as system variables
        instance.set_attr(
            pr=1, aoi=10, doc=0.95, Q=1e6, Tamb=25, A='var', eta_opt=0.816,
            c_1=0.0622, c_2=0.00023, E=8e2, iam_1=-1.59e-3, iam_2=9.77e-5)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        # heat loss must be identical to E * A - Q (internal heat loss
        # calculation)
        T_diff = (self.c2.T.val + self.c1.T.val) / 2 - instance.Tamb.val
        iam = (
            1 - instance.iam_1.val * abs(instance.aoi.val) -
            instance.iam_2.val * instance.aoi.val ** 2)

        Q_loss = -round(instance.A.val * (
            instance.E.val * (
                1 - instance.eta_opt.val * instance.doc.val ** 1.5 * iam
            ) + T_diff * instance.c_1.val + T_diff ** 2 * instance.c_2.val), 0)
        msg = (
            'Value for heat loss of parabolic trough must be ' + str(Q_loss) +
            ', is ' + str(round(instance.Q_loss.val, 0)) + '.')
        assert Q_loss == round(instance.Q_loss.val, 0), msg

        # test all parameters of the energy group: E
        # going to a different operating point first
        area = instance.A.val
        instance.set_attr(A=area * 1.2, E='var')
        self.nw.solve('design')
        instance.set_attr(A=area)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        assert Q_loss == round(instance.Q_loss.val, 0), msg

        # test all parameters of the energy group: eta_opt
        instance.set_attr(E=5e2, eta_opt='var')
        self.nw.solve('design')
        instance.set_attr(E=8e2)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        assert Q_loss == round(instance.Q_loss.val, 0), msg

        # test all parameters of the energy group: c_1
        instance.set_attr(E=5e2, eta_opt=instance.eta_opt.val, c_1='var')
        self.nw.solve('design')
        instance.set_attr(E=8e2)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        assert Q_loss == round(instance.Q_loss.val, 0), msg

        # test all parameters of the energy group: c_2
        instance.set_attr(E=5e2, c_1=instance.c_1.val, c_2='var')
        self.nw.solve('design')
        instance.set_attr(E=8e2)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        assert Q_loss == round(instance.Q_loss.val, 0), msg

        # test all parameters of the energy group: iam_1
        instance.set_attr(E=5e2, c_2=instance.c_2.val, iam_1='var')
        self.nw.solve('design')
        instance.set_attr(E=8e2)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        assert Q_loss == round(instance.Q_loss.val, 0), msg

        # test all parameters of the energy group: iam_2
        instance.set_attr(E=5e2, iam_1=instance.iam_1.val, iam_2='var')
        self.nw.solve('design')
        instance.set_attr(E=8e2)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        assert Q_loss == round(instance.Q_loss.val, 0), msg

        # test all parameters of the energy group: aoi
        instance.set_attr(E=5e2, iam_2=instance.iam_2.val, aoi='var')
        self.nw.solve('design')
        instance.set_attr(E=8e2)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        assert Q_loss == round(instance.Q_loss.val, 0), msg

        # test all parameters of the energy group: doc
        instance.set_attr(E=5e2, aoi=instance.aoi.val, doc='var')
        self.nw.solve('design')
        instance.set_attr(E=8e2)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        assert Q_loss == round(instance.Q_loss.val, 0), msg

    def test_SolarCollector(self):
        """Test component properties of solar collector."""
        instance = SolarCollector('solar collector')
        self.setup_HeatExchangerSimple_network(instance)
        fl = {'Ar': 0, 'H2O': 1, 'S800': 0}
        self.c1.set_attr(fluid=fl, p=10, T=30)
        self.c2.set_attr(T=70)

        # test grouped parameter settings with missing parameters
        instance.hydro_group.is_set = True
        instance.energy_group.is_set = True
        self.nw.solve('design', init_only=True)
        msg = ('Hydro group must no be set, if one parameter is missing!')
        assert instance.hydro_group.is_set is False, msg
        msg = ('Energy group must no be set, if one parameter is missing!')
        assert instance.energy_group.is_set is False, msg

        # test solar collector params as system variables
        instance.set_attr(E=1e3, lkf_lin=1.0, lkf_quad=0.005, A='var',
                          eta_opt=0.9, Q=1e5, Tamb=20, pr=0.99)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        # heat loss must be identical to E * A - Q (internal heat loss
        # calculation)
        T_diff = (self.c2.T.val + self.c1.T.val) / 2 - instance.Tamb.val
        Q_loss = -round(instance.A.val * (
            instance.E.val * (1 - instance.eta_opt.val) +
            T_diff * instance.lkf_lin.val +
            T_diff ** 2 * instance.lkf_quad.val), 0)
        msg = ('Value for heat loss of solar collector must be '
               + str(Q_loss) + ', is ' + str(round(instance.Q_loss.val, 0)) +
               '.')
        assert Q_loss == round(instance.Q_loss.val, 0), msg

        # test all parameters of the energy group: E
        area = instance.A.val
        instance.set_attr(A=area * 1.2, E='var')
        self.nw.solve('design')
        instance.set_attr(A=area)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        assert Q_loss == round(instance.Q_loss.val, 0), msg

        # test all parameters of the energy group: eta_opt
        instance.set_attr(E=8e2, eta_opt='var')
        self.nw.solve('design')
        instance.set_attr(E=1e3)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        assert Q_loss == round(instance.Q_loss.val, 0), msg

        # test all parameters of the energy group: lkf_lin
        instance.set_attr(E=8e2, eta_opt=instance.eta_opt.val, lkf_lin='var')
        self.nw.solve('design')
        instance.set_attr(E=1e3)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        assert Q_loss == round(instance.Q_loss.val, 0), msg

        # test all parameters of the energy group: lkf_quad
        instance.set_attr(E=8e2, lkf_lin=instance.lkf_lin.val, lkf_quad='var')
        self.nw.solve('design')
        instance.set_attr(E=1e3)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        assert Q_loss == round(instance.Q_loss.val, 0), msg

        # test all parameters of the energy group: Tamb
        instance.set_attr(E=8e2, lkf_lin=instance.lkf_lin.val, lkf_quad='var')
        self.nw.solve('design')
        instance.set_attr(E=1e3)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        assert Q_loss == round(instance.Q_loss.val, 0), msg

    def test_HeatExchanger(self):
        """Test component properties of heat exchanger."""
        instance = HeatExchanger('heat exchanger')
        self.setup_HeatExchanger_network(instance)

        # design specification
        instance.set_attr(pr1=0.98, pr2=0.98, ttd_u=5,
                          design=['pr1', 'pr2', 'ttd_u'],
                          offdesign=['zeta1', 'zeta2', 'kA_char'])
        self.c1.set_attr(T=120, p=3, fluid={'Ar': 0, 'H2O': 1, 'S800': 0})
        self.c2.set_attr(T=70)
        self.c3.set_attr(T=40, p=5, fluid={'Ar': 1, 'H2O': 0, 'S800': 0})
        b = Bus('heat transfer', P=-80e3)
        b.add_comps({'comp': instance})
        self.nw.add_busses(b)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        self.nw.save('tmp')
        Q_design = instance.Q.val

        # test specified kA value
        instance.set_attr(kA=instance.kA.val * 2 / 3)
        b.set_attr(P=None)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)

        # test heat transfer
        Q = self.c1.m.val_SI * (self.c2.h.val_SI - self.c1.h.val_SI)
        msg = (
            'Value of heat flow must be ' + str(round(Q_design * 2 / 3, 0)) +
            ', is ' + str(round(Q, 0)) + '.')
        assert round(Q, 1) == round(Q_design * 2 / 3, 1), msg

        # back to design case
        instance.set_attr(kA=None)
        b.set_attr(P=Q_design)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)

        # check heat transfer
        Q = self.c1.m.val_SI * (self.c2.h.val_SI - self.c1.h.val_SI)
        td_log = ((self.c2.T.val - self.c3.T.val -
                   self.c1.T.val + self.c4.T.val) /
                  np.log((self.c2.T.val - self.c3.T.val) /
                         (self.c1.T.val - self.c4.T.val)))
        kA = round(-Q / td_log, 0)
        msg = ('Value of heat transfer must be ' + str(round(Q, 0)) + ', is ' +
               str(round(instance.Q.val, 0)) + '.')
        assert round(Q, 0) == round(instance.Q.val, 0), msg

        # check upper terminal temperature difference
        msg = ('Value of terminal temperature difference must be ' +
               str(round(instance.ttd_u.val, 1)) + ', is ' +
               str(round(self.c1.T.val - self.c4.T.val, 1)) + '.')
        ttd_u_calc = round(self.c1.T.val - self.c4.T.val, 1)
        ttd_u = round(instance.ttd_u.val, 1)
        assert ttd_u_calc == ttd_u, msg

        # check lower terminal temperature difference
        self.c2.set_attr(T=np.nan)
        instance.set_attr(ttd_l=20)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of terminal temperature difference must be ' +
               str(instance.ttd_l.val) + ', is ' +
               str(self.c2.T.val - self.c3.T.val) + '.')
        ttd_l_calc = round(self.c2.T.val - self.c3.T.val, 1)
        ttd_l = round(instance.ttd_l.val, 1)
        assert ttd_l_calc == ttd_l, msg

        # check specified kA value (by offdesign parameter), reset temperatures
        # to design state
        self.c2.set_attr(T=70)
        instance.set_attr(ttd_l=np.nan)
        self.nw.solve('offdesign', design_path='tmp')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of heat flow must be ' + str(instance.Q.val) + ', is ' +
               str(round(Q, 0)) + '.')
        assert round(Q, 0) == round(instance.Q.val, 0), msg
        msg = ('Value of heat transfer coefficient must be ' + str(kA) +
               ', is ' + str(round(instance.kA.val, 0)) + '.')
        assert kA == round(instance.kA.val, 0), msg

        # trigger negative lower terminal temperature difference as result
        self.c4.set_attr(T=np.nan)
        self.c2.set_attr(T=30)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of upper terminal temperature differences must be '
               'smaller than zero, is ' + str(round(instance.ttd_l.val, 1)) +
               '.')
        assert instance.ttd_l.val < 0, msg

        # trigger negative upper terminal temperature difference as result
        self.c4.set_attr(T=100)
        self.c2.set_attr(h=200e3, T=np.nan)
        instance.set_attr(pr1=0.98, pr2=0.98, ttd_u=np.nan,
                          design=['pr1', 'pr2'])
        self.c1.set_attr(h=150e3, T=np.nan)
        self.c3.set_attr(T=40)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of upper terminal temperature differences must be '
               'smaller than zero, is ' + str(round(instance.ttd_u.val, 1)) +
               '.')
        assert instance.ttd_u.val < 0, msg

        shutil.rmtree('./tmp', ignore_errors=True)

    def test_Condenser(self):
        """Test component properties of Condenser."""
        instance = Condenser('condenser')
        self.setup_HeatExchanger_network(instance)

        # design specification
        instance.set_attr(pr1=0.98, pr2=0.98, ttd_u=5,
                          offdesign=['zeta2', 'kA_char'])
        self.c1.set_attr(T=100, p0=0.5, fluid={'Ar': 0, 'H2O': 1, 'S800': 0})
        self.c3.set_attr(T=30, p=5, fluid={'Ar': 0, 'H2O': 1, 'S800': 0})
        self.c4.set_attr(T=40)
        instance.set_attr(Q=-80e3)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        self.nw.save('tmp')
        Q_design = instance.Q.val

        # test specified kA value
        instance.set_attr(kA=instance.kA.val * 2 / 3, Q=None)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)

        # test heat transfer
        Q = self.c1.m.val_SI * (self.c2.h.val_SI - self.c1.h.val_SI)
        msg = (
            'Value of heat flow must be ' + str(round(Q_design * 2 / 3, 0)) +
            ', is ' + str(round(Q, 0)) + '.')
        assert round(Q, 1) == round(Q_design * 2 / 3, 1), msg

        # back to design case
        instance.set_attr(kA=None, Q=Q_design)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)

        # test heat transfer
        Q = self.c1.m.val_SI * (self.c2.h.val_SI - self.c1.h.val_SI)
        msg = ('Value of heat flow must be ' + str(round(instance.Q.val, 0)) +
               ', is ' + str(round(Q, 0)) + '.')
        assert round(Q, 1) == round(instance.Q.val, 1), msg

        # test upper terminal temperature difference. For the component
        # condenser the temperature of the condensing fluid is relevant.
        ttd_u = round(T_bp_p(self.c1.get_flow()) - self.c4.T.val_SI, 1)
        p = round(self.c1.p.val_SI, 5)
        msg = ('Value of terminal temperature difference must be ' +
               str(round(instance.ttd_u.val, 1)) + ', is ' +
               str(ttd_u) + '.')
        assert ttd_u == round(instance.ttd_u.val, 1), msg

        # test lower terminal temperature difference
        instance.set_attr(ttd_l=20, ttd_u=np.nan, design=['pr2', 'ttd_l'])
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of terminal temperature difference must be ' +
               str(instance.ttd_l.val) + ', is ' +
               str(self.c2.T.val - self.c3.T.val) + '.')
        ttd_l_calc = round(self.c2.T.val - self.c3.T.val, 1)
        ttd_l = round(instance.ttd_l.val, 1)
        assert ttd_l_calc == ttd_l, msg

        # check kA value with condensing pressure in offdesign mode:
        # no changes to design point means: identical pressure
        self.nw.solve('offdesign', design_path='tmp')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of condensing pressure be ' + str(p) + ', is ' +
               str(round(self.c1.p.val_SI, 5)) + '.')
        assert p == round(self.c1.p.val_SI, 5), msg
        shutil.rmtree('./tmp', ignore_errors=True)
class PowerPlant():
    def __init__(self):
        self.nw = Network(fluids=['BICUBIC::water'],
                          p_unit='bar',
                          T_unit='C',
                          h_unit='kJ / kg',
                          iterinfo=False)
        # components
        # main cycle
        eco = HeatExchangerSimple('economizer')
        eva = HeatExchangerSimple('evaporator')
        sup = HeatExchangerSimple('superheater')
        cc = CycleCloser('cycle closer')
        hpt = Turbine('high pressure turbine')
        sp1 = Splitter('splitter 1', num_out=2)
        mpt = Turbine('mid pressure turbine')
        sp2 = Splitter('splitter 2', num_out=2)
        lpt = Turbine('low pressure turbine')
        con = Condenser('condenser')
        pu1 = Pump('feed water pump')
        fwh1 = Condenser('feed water preheater 1')
        fwh2 = Condenser('feed water preheater 2')
        dsh = Desuperheater('desuperheater')
        me2 = Merge('merge2', num_in=2)
        pu2 = Pump('feed water pump 2')
        pu3 = Pump('feed water pump 3')
        me = Merge('merge', num_in=2)

        # cooling water
        cwi = Source('cooling water source')
        cwo = Sink('cooling water sink')

        # connections
        # main cycle
        cc_hpt = Connection(cc, 'out1', hpt, 'in1', label='feed steam')
        hpt_sp1 = Connection(hpt, 'out1', sp1, 'in1', label='extraction1')
        sp1_mpt = Connection(sp1, 'out1', mpt, 'in1', state='g')
        mpt_sp2 = Connection(mpt, 'out1', sp2, 'in1', label='extraction2')
        sp2_lpt = Connection(sp2, 'out1', lpt, 'in1')
        lpt_con = Connection(lpt, 'out1', con, 'in1')
        con_pu1 = Connection(con, 'out1', pu1, 'in1')
        pu1_fwh1 = Connection(pu1, 'out1', fwh1, 'in2')
        fwh1_me = Connection(fwh1, 'out2', me, 'in1', state='l')
        me_fwh2 = Connection(me, 'out1', fwh2, 'in2', state='l')
        fwh2_dsh = Connection(fwh2, 'out2', dsh, 'in2', state='l')
        dsh_me2 = Connection(dsh, 'out2', me2, 'in1')
        me2_eco = Connection(me2, 'out1', eco, 'in1', state='l')
        eco_eva = Connection(eco, 'out1', eva, 'in1')
        eva_sup = Connection(eva, 'out1', sup, 'in1')
        sup_cc = Connection(sup, 'out1', cc, 'in1')

        self.nw.add_conns(cc_hpt, hpt_sp1, sp1_mpt, mpt_sp2, sp2_lpt, lpt_con,
                          con_pu1, pu1_fwh1, fwh1_me, me_fwh2, fwh2_dsh,
                          dsh_me2, me2_eco, eco_eva, eva_sup, sup_cc)

        # cooling water
        cwi_con = Connection(cwi, 'out1', con, 'in2')
        con_cwo = Connection(con, 'out2', cwo, 'in1')

        self.nw.add_conns(cwi_con, con_cwo)

        # preheating
        sp1_dsh = Connection(sp1, 'out2', dsh, 'in1')
        dsh_fwh2 = Connection(dsh, 'out1', fwh2, 'in1')
        fwh2_pu2 = Connection(fwh2, 'out1', pu2, 'in1')
        pu2_me2 = Connection(pu2, 'out1', me2, 'in2')

        sp2_fwh1 = Connection(sp2, 'out2', fwh1, 'in1')
        fwh1_pu3 = Connection(fwh1, 'out1', pu3, 'in1')
        pu3_me = Connection(pu3, 'out1', me, 'in2')

        self.nw.add_conns(sp1_dsh, dsh_fwh2, fwh2_pu2, pu2_me2, sp2_fwh1,
                          fwh1_pu3, pu3_me)

        # busses
        # power bus
        self.power = Bus('power')
        self.power.add_comps({
            'comp': hpt,
            'char': -1
        }, {
            'comp': mpt,
            'char': -1
        }, {
            'comp': lpt,
            'char': -1
        }, {
            'comp': pu1,
            'char': -1
        }, {
            'comp': pu2,
            'char': -1
        }, {
            'comp': pu3,
            'char': -1
        })

        # heating bus
        self.heat = Bus('heat')
        self.heat.add_comps({
            'comp': eco,
            'char': 1
        }, {
            'comp': eva,
            'char': 1
        }, {
            'comp': sup,
            'char': 1
        })

        self.nw.add_busses(self.power, self.heat)

        # parametrization
        # components
        hpt.set_attr(eta_s=0.9)
        mpt.set_attr(eta_s=0.9)
        lpt.set_attr(eta_s=0.9)

        pu1.set_attr(eta_s=0.8)
        pu2.set_attr(eta_s=0.8)
        pu3.set_attr(eta_s=0.8)

        eco.set_attr(pr=0.99)
        eva.set_attr(pr=0.99)
        sup.set_attr(pr=0.99)

        con.set_attr(pr1=1, pr2=0.99, ttd_u=5)
        fwh1.set_attr(pr1=1, pr2=0.99, ttd_u=5)
        fwh2.set_attr(pr1=1, pr2=0.99, ttd_u=5)
        dsh.set_attr(pr1=0.99, pr2=0.99)

        # connections
        eco_eva.set_attr(x=0)
        eva_sup.set_attr(x=1)

        cc_hpt.set_attr(m=200, T=650, p=100, fluid={'water': 1})
        hpt_sp1.set_attr(p=20)
        mpt_sp2.set_attr(p=3)
        lpt_con.set_attr(p=0.05)

        cwi_con.set_attr(T=20, p=10, fluid={'water': 1})

        # test run
        self.nw.solve('design')
        document_model(self.nw)

    def calculate_efficiency(self, x):
        # set extraction pressure
        self.nw.get_conn('extraction1').set_attr(p=x[0])
        self.nw.get_conn('extraction2').set_attr(p=x[1])

        self.nw.solve('design')

        for cp in self.nw.comps['object']:
            if isinstance(cp, Condenser) or isinstance(cp, Desuperheater):
                if cp.Q.val > 0:
                    return np.nan
            elif isinstance(cp, Pump):
                if cp.P.val < 0:
                    return np.nan
            elif isinstance(cp, Turbine):
                if cp.P.val > 0:
                    return np.nan

        if self.nw.res[-1] > 1e-3 or self.nw.lin_dep:
            return np.nan
        else:
            return self.nw.busses['power'].P.val / self.nw.busses['heat'].P.val
class TestSEGS:
    def setup(self):
        """
        Full model validation of SEGS model in TESPy vs. EBSILON.

        Find original models at https://github.com/fwitte/SEGS_exergy.
        """
        # specification of ambient state
        self.pamb = 1.013
        self.Tamb = 25

        # setting up network
        self.nw = Network(fluids=['water', 'INCOMP::TVP1', 'air'])
        self.nw.set_attr(T_unit='C',
                         p_unit='bar',
                         h_unit='kJ / kg',
                         m_unit='kg / s',
                         s_unit="kJ / kgK")

        # components definition
        air_in = Source('Ambient air source', fkt_group='CW')
        air_out = Sink('Ambient air sink', fkt_group='CW')

        closer_pt = CycleCloser('Cycle closer pt', fkt_group='SF')
        pt = ParabolicTrough('Parabolic trough', fkt_group='SF')
        ptpump = Pump('HTF pump', fkt_group='SF')

        closer = CycleCloser('Cycle closer power cycle', fkt_group='SG')

        eco = HeatExchanger('Economizer', fkt_group='SG')
        eva = HeatExchanger('Evaporator', fkt_group='SG')
        sup = HeatExchanger('Superheater', fkt_group='SG')
        drum = Drum('Drum', fkt_group='SG')

        reh = HeatExchanger('Reheater', fkt_group='RH')

        hpt1 = Turbine('HP turbine 1', fkt_group='HPT')
        hpt2 = Turbine('HP turbine 2', fkt_group='HPT')
        lpt1 = Turbine('LP turbine 1', fkt_group='LPT')
        lpt2 = Turbine('LP turbine 2', fkt_group='LPT')
        lpt3 = Turbine('LP turbine 3', fkt_group='LPT')
        lpt4 = Turbine('LP turbine 4', fkt_group='LPT')
        lpt5 = Turbine('LP turbine 5', fkt_group='LPT')

        cond = Condenser('Condenser', fkt_group='CW')
        condpump = Pump('Condenser pump', fkt_group='CW')
        fwt = Merge('Feedwater tank', num_in=3, fkt_group='LPP')
        fwp = Pump('Feedwater pump', fkt_group='FWP')
        cwp = Pump('Cooling water pump', fkt_group='CW')
        closer_cw = CycleCloser('Cycle closer cw', fkt_group='CW')
        ct = HeatExchanger('Cooling tower', fkt_group='CW')
        fan = Compressor('Cooling tower fan', fkt_group='CW')

        sp1 = Splitter('Splitter 1', fkt_group='HPT')
        sp2 = Splitter('Splitter 2', fkt_group='HPT')
        sp3 = Splitter('Splitter 3', fkt_group='LPT')
        sp4 = Splitter('Splitter 4', fkt_group='LPT')
        sp5 = Splitter('Splitter 5', fkt_group='LPT')
        sp6 = Splitter('Splitter 6', fkt_group='LPT')
        sp7 = Splitter('Splitter 7', fkt_group='SF')

        m1 = Merge('Merge 1', fkt_group='CW')
        m2 = Merge('Merge 2', fkt_group='HPP')
        m3 = Merge('Merge 3', fkt_group='LPP')
        m4 = Merge('Merge 4', fkt_group='LPP')
        m5 = Merge('Merge 5', fkt_group='SF')

        v1 = Valve('Valve 1', fkt_group='HPP')
        v2 = Valve('Valve 2', fkt_group='HPP')
        v3 = Valve('Valve 3', fkt_group='LPP')
        v4 = Valve('Valve 4', fkt_group='LPP')
        v5 = Valve('Valve 5', fkt_group='LPP')

        hppre1 = Condenser('High pressure preheater 1', fkt_group='HPP')
        hppre2 = Condenser('High pressure preheater 2', fkt_group='HPP')
        hppre1_sub = HeatExchanger('High pressure preheater 1 subcooling',
                                   fkt_group='HPP')
        hppre2_sub = HeatExchanger('High pressure preheater 2 subcooling',
                                   fkt_group='HPP')

        lppre1 = Condenser('Low pressure preheater 1', fkt_group='LPP')
        lppre2 = Condenser('Low pressure preheater 2', fkt_group='LPP')
        lppre3 = Condenser('Low pressure preheater 3', fkt_group='LPP')
        lppre1_sub = HeatExchanger('Low pressure preheater 1 subcooling',
                                   fkt_group='LPP')
        lppre2_sub = HeatExchanger('Low pressure preheater 2 subcooling',
                                   fkt_group='LPP')
        lppre3_sub = HeatExchanger('Low pressure preheater 3 subcooling',
                                   fkt_group='LPP')

        # connections definition
        # power cycle
        c1 = Connection(sup, 'out2', closer, 'in1', label='1')
        c2 = Connection(closer, 'out1', hpt1, 'in1', label='2')
        c3 = Connection(hpt1, 'out1', sp1, 'in1', label='3')
        c4 = Connection(sp1, 'out1', hpt2, 'in1', label='4')
        c5 = Connection(hpt2, 'out1', sp2, 'in1', label='5')
        c6 = Connection(sp2, 'out1', reh, 'in2', label='6')
        c7 = Connection(reh, 'out2', lpt1, 'in1', label='7')
        c8 = Connection(lpt1, 'out1', sp3, 'in1', label='8')
        c9 = Connection(sp3, 'out1', lpt2, 'in1', label='9')
        c10 = Connection(lpt2, 'out1', sp4, 'in1', label='10')
        c11 = Connection(sp4, 'out1', lpt3, 'in1', label='11')
        c12 = Connection(lpt3, 'out1', sp5, 'in1', label='12')
        c13 = Connection(sp5, 'out1', lpt4, 'in1', label='13')
        c14 = Connection(lpt4, 'out1', sp6, 'in1', label='14')
        c15 = Connection(sp6, 'out1', lpt5, 'in1', label='15')
        c16 = Connection(lpt5, 'out1', m1, 'in1', label='16')
        c17 = Connection(m1, 'out1', cond, 'in1', label='17')
        c18 = Connection(cond, 'out1', condpump, 'in1', label='18')
        c19 = Connection(condpump, 'out1', lppre1, 'in2', label='19')
        # c19 = Connection(condpump, 'out1', lppre1_sub, 'in2', label='19')
        # c20 = Connection(lppre1_sub, 'out2', lppre1, 'in2', label='20')
        c21 = Connection(lppre1, 'out2', lppre2, 'in2', label='21')
        # c21 = Connection(lppre1, 'out2', lppre2_sub, 'in2', label='21')
        # c22 = Connection(lppre2_sub, 'out2', lppre2, 'in2', label='22')
        c23 = Connection(lppre2, 'out2', lppre3, 'in2', label='23')
        # c23 = Connection(lppre2, 'out2', lppre3_sub, 'in2', label='23')
        # c24 = Connection(lppre3_sub, 'out2', lppre3, 'in2', label='24')
        c25 = Connection(lppre3, 'out2', fwt, 'in1', label='25')
        c26 = Connection(fwt, 'out1', fwp, 'in1', label='26')
        c27 = Connection(fwp, 'out1', hppre1, 'in2', label='27')
        c29 = Connection(hppre1, 'out2', hppre2, 'in2', label='29')
        c31 = Connection(hppre2, 'out2', eco, 'in2', label='31')

        c36 = Connection(sp1, 'out2', hppre2, 'in1', label='36')
        c37 = Connection(hppre2, 'out1', v1, 'in1', label='37')
        c39 = Connection(v1, 'out1', m2, 'in2', label='39')
        c40 = Connection(sp2, 'out2', m2, 'in1', label='40')
        c41 = Connection(m2, 'out1', hppre1, 'in1', label='41')
        c42 = Connection(hppre1, 'out1', v2, 'in1', label='42')
        c44 = Connection(v2, 'out1', fwt, 'in2', label='44')
        c45 = Connection(sp3, 'out2', fwt, 'in3', label='45')
        c46 = Connection(sp4, 'out2', lppre3, 'in1', label='46')
        c47 = Connection(lppre3, 'out1', v3, 'in1', label='47')
        # c47 = Connection(lppre3, 'out1', lppre3_sub, 'in1', label='47')
        # c48 = Connection(lppre3_sub, 'out1', v3, 'in1', label='48')
        c49 = Connection(v3, 'out1', m3, 'in1', label='49')
        c50 = Connection(sp5, 'out2', m3, 'in2', label='50')
        c51 = Connection(m3, 'out1', lppre2, 'in1', label='51')
        c52 = Connection(lppre2, 'out1', v4, 'in1', label='52')
        # c52 = Connection(lppre2, 'out1', lppre2_sub, 'in1', label='52')
        # c53 = Connection(lppre2_sub, 'out1', v4, 'in1', label='53')
        c54 = Connection(v4, 'out1', m4, 'in2', label='54')
        c55 = Connection(sp6, 'out2', m4, 'in1', label='55')
        c56 = Connection(m4, 'out1', lppre1, 'in1', label='56')
        c57 = Connection(lppre1, 'out1', v5, 'in1', label='57')
        # c57 = Connection(lppre1, 'out1', lppre1_sub, 'in1', label='57')
        # c58 = Connection(lppre1_sub, 'out1', v5, 'in1', label='58')
        c59 = Connection(v5, 'out1', m1, 'in2', label='59')

        # components from subsystem
        c32 = Connection(eco, 'out2', drum, 'in1', label='32')
        c33 = Connection(drum, 'out1', eva, 'in2', label='33')
        c34 = Connection(eva, 'out2', drum, 'in2', label='34')
        c35 = Connection(drum, 'out2', sup, 'in2', label='35')
        c73 = Connection(sup, 'out1', eva, 'in1', label='73')
        c74 = Connection(eva, 'out1', eco, 'in1', label='74')

        # cooling water
        c60 = Connection(cond, 'out2', closer_cw, 'in1', label='60')
        c61 = Connection(closer_cw, 'out1', ct, 'in1', label='61')
        c62 = Connection(ct, 'out1', cwp, 'in1', label='62')
        c63 = Connection(cwp, 'out1', cond, 'in2', label='63')

        # cooling tower
        c64 = Connection(air_in, 'out1', fan, 'in1', label='64')
        c65 = Connection(fan, 'out1', ct, 'in2', label='65')
        c66 = Connection(ct, 'out2', air_out, 'in1', label='66')

        # parabolic trough cycle
        c70 = Connection(pt, 'out1', closer_pt, 'in1', label='67')
        c71 = Connection(closer_pt, 'out1', sp7, 'in1', label='71')
        c72 = Connection(sp7, 'out1', sup, 'in1', label='72')
        c75 = Connection(eco, 'out1', m5, 'in1', label='75')
        c76 = Connection(sp7, 'out2', reh, 'in1', label='76')
        c77 = Connection(reh, 'out1', m5, 'in2', label='77')
        c78 = Connection(m5, 'out1', ptpump, 'in1', label='78')
        c79 = Connection(ptpump, 'out1', pt, 'in1', label='79')

        # add connections to network
        self.nw.add_conns(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,
                          c13, c14, c15, c16, c17, c18, c19, c21, c23, c25,
                          c26, c27, c29, c31, c32, c33, c34, c35, c36, c37,
                          c39, c40, c41, c42, c44, c45, c46, c47, c49, c50,
                          c51, c52, c54, c55, c56, c57, c59, c60, c61, c62,
                          c63, c64, c65, c66, c70, c71, c72, c73, c74, c75,
                          c76, c77, c78, c79)

        # power bus
        power = Bus('total output power')
        power.add_comps({
            'comp': hpt1,
            'char': 0.97,
            'base': 'component'
        }, {
            'comp': hpt2,
            'char': 0.97,
            'base': 'component'
        }, {
            'comp': lpt1,
            'char': 0.97,
            'base': 'component'
        }, {
            'comp': lpt2,
            'char': 0.97,
            'base': 'component'
        }, {
            'comp': lpt3,
            'char': 0.97,
            'base': 'component'
        }, {
            'comp': lpt4,
            'char': 0.97,
            'base': 'component'
        }, {
            'comp': lpt5,
            'char': 0.97,
            'base': 'component'
        }, {
            'comp': fwp,
            'char': 0.95,
            'base': 'bus'
        }, {
            'comp': condpump,
            'char': 0.95,
            'base': 'bus'
        }, {
            'comp': ptpump,
            'char': 0.95,
            'base': 'bus'
        }, {
            'comp': cwp,
            'char': 0.95,
            'base': 'bus'
        }, {
            'comp': fan,
            'char': 0.95,
            'base': 'bus'
        })

        heat_input_bus = Bus('heat input')
        heat_input_bus.add_comps({'comp': pt, 'base': 'bus'})

        exergy_loss_bus = Bus('exergy loss')
        exergy_loss_bus.add_comps({
            'comp': air_in,
            'base': 'bus'
        }, {'comp': air_out})

        self.nw.add_busses(power, heat_input_bus, exergy_loss_bus)

        # component parameters
        pt.set_attr(doc=0.95,
                    aoi=0,
                    Tamb=25,
                    A='var',
                    eta_opt=0.73,
                    c_1=0.00496,
                    c_2=0.000691,
                    E=1000,
                    iam_1=1,
                    iam_2=1)

        ptpump.set_attr(eta_s=0.6)

        eco.set_attr()
        eva.set_attr(ttd_l=5)
        sup.set_attr()

        hpt1.set_attr(eta_s=0.8376)
        hpt2.set_attr(eta_s=0.8463)
        lpt1.set_attr(eta_s=0.8623)
        lpt2.set_attr(eta_s=0.917)
        lpt3.set_attr(eta_s=0.9352)
        lpt4.set_attr(eta_s=0.88)
        lpt5.set_attr(eta_s=0.6445)

        cond.set_attr(pr1=1, pr2=0.9, ttd_u=5)
        condpump.set_attr(eta_s=0.7)
        fwp.set_attr(eta_s=0.7)
        cwp.set_attr(eta_s=0.7)
        ct.set_attr(pr1=0.95)
        fan.set_attr(eta_s=0.6)

        lppre1.set_attr(pr1=1, ttd_u=5)
        lppre2.set_attr(pr1=1, ttd_u=5)
        lppre3.set_attr(pr1=1, ttd_u=5)
        hppre1.set_attr(pr1=1, ttd_u=5)
        hppre2.set_attr(pr1=1, ttd_u=5)

        lppre1_sub.set_attr(pr1=1, pr2=1, ttd_l=10)
        lppre2_sub.set_attr(pr1=1, pr2=1, ttd_l=10)
        lppre3_sub.set_attr(pr1=1, pr2=1, ttd_l=10)
        hppre1_sub.set_attr(pr1=1, pr2=1, ttd_l=10)
        hppre2_sub.set_attr(pr1=1, pr2=1, ttd_l=10)

        # connection parameters
        # parabolic trough cycle
        c70.set_attr(fluid={'TVP1': 1, 'water': 0, 'air': 0}, T=390, p=23.304)
        c76.set_attr(m=Ref(c70, 0.1284, 0))
        c73.set_attr(p=22.753)
        c74.set_attr(p=21.167)
        c78.set_attr(p=20.34)
        c79.set_attr(p=41.024)

        # cooling water
        c62.set_attr(fluid={
            'TVP1': 0,
            'water': 1,
            'air': 0
        },
                     T=30,
                     p=self.pamb)
        # cooling tower
        c64.set_attr(fluid={
            'water': 0,
            'TVP1': 0,
            'air': 1
        },
                     p=self.pamb,
                     T=self.Tamb)
        c65.set_attr(p=self.pamb + 0.0005)
        c66.set_attr(p=self.pamb, T=30)
        # power cycle
        c32.set_attr(Td_bp=-2)
        c34.set_attr(x=0.5)
        c1.set_attr(fluid={'water': 1, 'TVP1': 0, 'air': 0}, p=100, T=371)

        # steam generator pressure values
        c31.set_attr(p=103.56)
        c35.set_attr(p=103.42)

        # turbine pressure values
        c3.set_attr(p=33.61, m=38.969)
        c5.set_attr(p=18.58)
        c7.set_attr(p=17.1, T=371)
        c8.set_attr(p=7.98)
        c10.set_attr(p=2.73)
        c12.set_attr(p=0.96)
        c14.set_attr(p=0.29)

        # preheater pressure values
        c19.set_attr(p=14.755, state='l')
        c21.set_attr(p=9.9975, state='l')
        c23.set_attr(p=8.7012, state='l')
        c25.set_attr(state='l')

        c27.set_attr(p=125)
        c29.set_attr(p=112)

        # condensation
        c16.set_attr(p=0.08)

        # feedwater tank
        c26.set_attr(x=0)

        # a stable solution is generated for parts of the network
        self.nw.solve(mode='design')

        self.nw.del_conns(c19, c21, c23, c27, c29, c37, c42, c47, c52, c57)

        c19 = Connection(condpump, 'out1', lppre1_sub, 'in2', label='19')
        c20 = Connection(lppre1_sub, 'out2', lppre1, 'in2', label='20')
        c21 = Connection(lppre1, 'out2', lppre2_sub, 'in2', label='21')
        c22 = Connection(lppre2_sub, 'out2', lppre2, 'in2', label='22')
        c23 = Connection(lppre2, 'out2', lppre3_sub, 'in2', label='23')
        c24 = Connection(lppre3_sub, 'out2', lppre3, 'in2', label='24')

        c27 = Connection(fwp, 'out1', hppre1_sub, 'in2', label='27')
        c28 = Connection(hppre1_sub, 'out2', hppre1, 'in2', label='28')
        c29 = Connection(hppre1, 'out2', hppre2_sub, 'in2', label='29')
        c30 = Connection(hppre2_sub, 'out2', hppre2, 'in2', label='30')

        c37 = Connection(hppre2, 'out1', hppre2_sub, 'in1', label='37')
        c38 = Connection(hppre2_sub, 'out1', v1, 'in1', label='38')
        c42 = Connection(hppre1, 'out1', hppre1_sub, 'in1', label='42')
        c43 = Connection(hppre1_sub, 'out1', v2, 'in1', label='43')

        c47 = Connection(lppre3, 'out1', lppre3_sub, 'in1', label='47')
        c48 = Connection(lppre3_sub, 'out1', v3, 'in1', label='48')
        c52 = Connection(lppre2, 'out1', lppre2_sub, 'in1', label='52')
        c53 = Connection(lppre2_sub, 'out1', v4, 'in1', label='53')
        c57 = Connection(lppre1, 'out1', lppre1_sub, 'in1', label='57')
        c58 = Connection(lppre1_sub, 'out1', v5, 'in1', label='58')

        self.nw.add_conns(c19, c20, c21, c22, c23, c24, c27, c28, c29, c30,
                          c37, c38, c42, c43, c47, c48, c52, c53, c57, c58)

        # specification of missing parameters
        c19.set_attr(p=14.755)
        c21.set_attr(p=9.9975, state='l')
        c23.set_attr(p=8.7012, state='l')
        c27.set_attr(p=125)
        c29.set_attr(p=112)

        # solve final state
        self.nw.solve(mode='design')

    def test_model(self):
        """Test the thermodynamic model."""
        power_ebsilon = -31.769
        power_tespy = round(self.nw.busses['total output power'].P.val / 1e6,
                            3)
        msg = ('The total power calculated (' + str(power_tespy) +
               ') does not '
               'match the power calculated with the EBSILON model (' +
               str(power_ebsilon) + ').')
        assert power_tespy == power_ebsilon, msg

        T_c79_ebsilon = 296.254
        T_c79_tespy = round(self.nw.get_conn('79').T.val, 3)
        msg = ('The temperature at connection 79 calculated (' +
               str(T_c79_tespy) +
               ') does not match the temperature calculated '
               'with the EBSILON model (' + str(T_c79_ebsilon) + ').')
        assert T_c79_tespy == T_c79_ebsilon, msg

    def test_exergy_analysis(self):
        """Test the exergy analysis results."""
        # carry out exergy analysis
        ean = ExergyAnalysis(self.nw,
                             E_P=[self.nw.busses['total output power']],
                             E_F=[self.nw.busses['heat input']],
                             E_L=[self.nw.busses['exergy loss']])
        ean.analyse(pamb=self.pamb, Tamb=self.Tamb)

        # generate Grassmann diagram
        links, nodes = ean.generate_plotly_sankey_input()

        # check if exergy product value in links is equal to total power
        # output
        position = links['target'].index(nodes.index('E_P'))
        power_links = round(links['value'][position], 0)
        power_bus = round(-self.nw.busses['total output power'].P.val, 0)
        msg = ('The exergy product value in the links (' + str(power_links) +
               ') must be equal to the power on the respective bus (' +
               str(power_bus) + ').')
        assert power_links == power_bus, msg
예제 #6
0
class TestCompressedAirOut:
    def setup(self):
        """Set up air compressed air turbine."""
        self.Tamb = 20
        self.pamb = 1
        fluids = ['Air']

        # turbine part
        self.nw = Network(fluids=fluids)
        self.nw.set_attr(p_unit='bar', T_unit='C', h_unit='kJ / kg')

        # components
        cas = Source('compressed air storage')
        reheater = HeatExchangerSimple('reheating')
        turb = Turbine('turbine')
        amb = Sink('air outlet')

        # power ouput bus
        self.power_out = Bus('power output')
        self.power_out.add_comps({'comp': turb, 'char': 1})
        # compressed air bus
        self.cas_out = Bus('exergy in')
        self.cas_out.add_comps({
            'comp': cas,
            'base': 'bus'
        }, {
            'comp': reheater,
            'base': 'bus'
        })
        # exergy loss bus
        self.ex_loss = Bus('exergy loss')
        self.ex_loss.add_comps({'comp': amb, 'base': 'component'})
        self.nw.add_busses(self.power_out, self.cas_out)

        # create connections
        cas_reheater = Connection(cas, 'out1', reheater, 'in1')
        reheater_turb = Connection(reheater, 'out1', turb, 'in1')
        turb_amb = Connection(turb, 'out1', amb, 'in1', label='outlet')
        self.nw.add_conns(cas_reheater, reheater_turb, turb_amb)

        # component parameters
        turb.set_attr(eta_s=1)
        reheater.set_attr(pr=1)

        # connection parameters
        cas_reheater.set_attr(m=2, T=self.Tamb, p=10, fluid={'Air': 1})
        reheater_turb.set_attr()
        turb_amb.set_attr(p=self.pamb, T=self.Tamb)

        # solve network
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)

    def test_exergy_analysis_bus_conversion(self):
        """Test exergy analysis at product exergy with T < Tamb."""
        ean = ExergyAnalysis(self.nw,
                             E_P=[self.power_out],
                             E_F=[self.cas_out],
                             E_L=[self.ex_loss])
        ean.analyse(pamb=self.pamb, Tamb=self.Tamb)

        exergy_balance = (ean.network_data.E_F - ean.network_data.E_P -
                          ean.network_data.E_L - ean.network_data.E_D)
        msg = ('Exergy balance must be closed (residual value smaller than ' +
               str(err**0.5) + ') for this test but is ' +
               str(round(abs(exergy_balance), 4)) + '.')
        assert abs(exergy_balance) <= err**0.5, msg

        msg = ('Exergy efficiency must be equal to 1.0 for this test but is ' +
               str(round(ean.network_data.epsilon, 4)) + '.')
        assert round(ean.network_data.epsilon, 4) == 1, msg

        c = self.nw.get_conn('outlet')
        c.set_attr(T=self.Tamb - 20)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)

        ean.analyse(pamb=self.pamb, Tamb=self.Tamb)

        msg = (
            'Exergy destruction must be equal to 0.0 for this test but is ' +
            str(round(ean.network_data.E_D, 4)) + '.')
        assert round(ean.network_data.E_D, 4) == 0, msg

        msg = ('Exergy loss must be equal to ' + str(round(c.Ex_physical, 4)) +
               ' for this test but is ' + str(round(ean.network_data.E_L, 4)) +
               '.')
        assert round(ean.network_data.E_L, 4) == round(c.Ex_physical, 4), msg
예제 #7
0
class TestHeatPump:
    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_model(self):
        """
        Test the operating points of the heat pump against a different model.

        By now, not all characteristic functions of the original model are
        available in detail, thus perfect matching is not possible!
        """
        self.nw.solve('design')
        self.nw.save('tmp')
        self.nw.print_results()

        # input values from ebsilon
        T = [105, 100, 90, 80]
        m_source = np.array([[23, 22, 20, 18, 16], [27, 24, 20, 16, 12],
                             [31, 25, 20, 15, 10], [33, 26, 20, 15, 10]])
        COP = np.array([[2.436, 2.414, 2.368, 2.338, 2.287],
                        [2.591, 2.523, 2.448, 2.355, 2.216],
                        [2.777, 2.635, 2.557, 2.442, 2.243],
                        [2.866, 2.711, 2.629, 2.528, 2.351]])

        i = 0
        for T in T:
            j = 0
            self.cd_cons.set_attr(T=T)
            for m in m_source[i]:
                self.amb_in_su.set_attr(m=m)
                if j == 0:
                    self.nw.solve('offdesign',
                                  design_path='tmp',
                                  init_path='tmp')

                else:
                    self.nw.solve('offdesign', design_path='tmp')

                # relative deviation should not exceed 6.5 %
                # this should be much less, unfortunately not all ebsilon
                # characteristics are available, thus it is
                # difficult/impossible to match the models perfectly!
                d_rel_COP = abs(self.heat.P.val / self.power.P.val -
                                COP[i, j]) / COP[i, j]
                msg = ('The deviation in COP should be less than 0.065, is ' +
                       str(d_rel_COP) + ' at mass flow ' + str(m) +
                       ' and temperature ' + str(T) + '.')
                assert d_rel_COP < 0.065, msg
                j += 1
            i += 1
        shutil.rmtree('./tmp', ignore_errors=True)
예제 #8
0
파일: test_errors.py 프로젝트: oemof/tespy
class TestNetworkErrors:

    def setup(self):
        self.nw = Network(['water'])

    def test_add_conns_TypeError(self):
        with raises(TypeError):
            self.nw.add_conns(Component('test'))

    def test_no_connections_error(self):
        with raises(TESPyNetworkError):
            self.nw.solve('design')

    def test_bad_fluids_in_fluid_vector(self):
        source1 = Source('source1')
        sink1 = Sink('sink1')
        a = Connection(source1, 'out1', sink1, 'in1', fluid={'air': 1})
        self.nw.add_conns(a)
        with raises(TESPyNetworkError):
            self.nw.solve('design')

    def test_duplicate_Connection_labels(self):
        source1 = Source('source1')
        source2 = Source('source2')
        sink1 = Sink('sink1')
        sink2 = Sink('sink2')
        a = Connection(source1, 'out1', sink1, 'in1', label='myconn')
        b = Connection(source2, 'out1', sink2, 'in1', label='myconn')
        with raises(ValueError):
            self.nw.add_conns(a, b)

    def test_Connection_error_source(self):
        source = Source('source')
        sink1 = Sink('sink1')
        sink2 = Sink('sink2')
        a = Connection(source, 'out1', sink1, 'in1')
        b = Connection(source, 'out1', sink2, 'in1')
        self.nw.add_conns(a, b)
        with raises(TESPyNetworkError):
            self.nw.check_network()

    def test_Connection_error_target(self):
        source1 = Source('source1')
        source2 = Source('source2')
        sink = Sink('sink')
        a = Connection(source1, 'out1', sink, 'in1')
        b = Connection(source2, 'out1', sink, 'in1')
        self.nw.add_conns(a, b)
        with raises(TESPyNetworkError):
            self.nw.check_network()

    def test_consistency_inlets(self):
        merge = Merge('merge')
        sink = Sink('label')
        a = Connection(merge, 'out1', sink, 'in1')
        self.nw.add_conns(a)
        with raises(TESPyNetworkError):
            self.nw.check_network()

    def test_consistency_outlets(self):
        source = Source('source')
        splitter = Splitter('splitter')
        a = Connection(source, 'out1', splitter, 'in1')
        self.nw.add_conns(a)
        with raises(TESPyNetworkError):
            self.nw.check_network()

    def test_component_label_duplicates(self):
        source = Source('label')
        sink = Sink('label')
        a = Connection(source, 'out1', sink, 'in1')
        self.nw.add_conns(a)
        with raises(TESPyNetworkError):
            self.nw.check_network()

    def test_missing_offdesign_path(self):
        source = Source('source')
        sink = Sink('sink')
        a = Connection(source, 'out1', sink, 'in1')
        self.nw.add_conns(a)
        with raises(TESPyNetworkError):
            self.nw.solve('offdesign')

    def test_bad_mode_specification(self):
        source = Source('source')
        sink = Sink('sink')
        a = Connection(source, 'out1', sink, 'in1')
        self.nw.add_conns(a)
        with raises(ValueError):
            self.nw.solve('ofdesign')

    def test_underdetermination(self):
        source = Source('source')
        sink = Sink('sink')
        a = Connection(source, 'out1', sink, 'in1', m=1)
        self.nw.add_conns(a)
        with raises(TESPyNetworkError):
            self.nw.solve('design')

    def test_overdetermination(self):
        source = Source('source')
        sink = Sink('sink')
        a = Connection(source, 'out1', sink, 'in1', m=1, p=1e5, x=1, h=1e6,
                       fluid={'water': 1}, fluid_balance=True)
        self.nw.add_conns(a)
        with raises(TESPyNetworkError):
            self.nw.solve('design')

    def test_add_Bus_TypeError(self):
        source = Source('label')
        sink = Sink('label')
        a = Connection(source, 'out1', sink, 'in1')
        with raises(TypeError):
            self.nw.add_busses(a)

    def test_Bus_duplicate(self):
        with raises(TESPyNetworkError):
            b = Bus('mybus')
            self.nw.add_busses(b, b)

    def test_buslabel_duplicate(self):
        with raises(TESPyNetworkError):
            a = Bus('mybus')
            b = Bus('mybus')
            self.nw.add_busses(a, b)
예제 #9
0
class TestOrcEvaporator:
    def setup(self):
        self.nw = Network(['water', 'Isopentane'],
                          T_unit='C',
                          p_unit='bar',
                          h_unit='kJ / kg')
        self.inl1 = Source('inlet 1')
        self.outl1 = Sink('outlet 1')

        self.inl2 = Source('inlet 2')
        self.outl2 = Sink('outlet 2')

        self.inl3 = Source('inlet 3')
        self.outl3 = Sink('outlet 3')

        self.instance = ORCEvaporator('orc evaporator')

        self.c1 = Connection(self.inl1, 'out1', self.instance, 'in1')
        self.c2 = Connection(self.instance, 'out1', self.outl1, 'in1')
        self.c3 = Connection(self.inl2, 'out1', self.instance, 'in2')
        self.c4 = Connection(self.instance, 'out2', self.outl2, 'in1')
        self.c5 = Connection(self.inl3, 'out1', self.instance, 'in3')
        self.c6 = Connection(self.instance, 'out3', self.outl3, 'in1')

        self.nw.add_conns(self.c1, self.c2, self.c3, self.c4, self.c5, self.c6)

    def test_ORCEvaporator(self):
        """Test component properties of orc evaporator."""
        # design specification
        self.instance.set_attr(pr1=0.95,
                               pr2=0.975,
                               pr3=0.975,
                               design=['pr1', 'pr2', 'pr3'],
                               offdesign=['zeta1', 'zeta2', 'zeta3'])
        self.c1.set_attr(T=146.6,
                         p=4.34,
                         m=20.4,
                         state='g',
                         fluid={
                             'water': 1,
                             'Isopentane': 0
                         })
        self.c3.set_attr(T=146.6, p=10.2, fluid={'water': 1, 'Isopentane': 0})
        self.c4.set_attr(T=118.6)
        self.c5.set_attr(T=111.6, p=10.8, fluid={'water': 0, 'Isopentane': 1})

        # test heat transfer
        Q = -6.64e+07
        self.instance.set_attr(Q=Q)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        Q_is = -self.c5.m.val_SI * (self.c6.h.val_SI - self.c5.h.val_SI)
        msg = ('Value of heat flow must be ' + str(round(Q, 0)) + ', is ' +
               str(round(Q_is, 0)) + '.')
        assert round(Q, 0) == round(Q_is, 0), msg

        # test bus
        self.instance.set_attr(Q=np.nan)
        P = -6.64e+07
        b = Bus('heat transfer', P=P)
        b.add_comps({'comp': self.instance})
        self.nw.add_busses(b)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        self.nw.save('tmp')

        Q_is = -self.c5.m.val_SI * (self.c6.h.val_SI - self.c5.h.val_SI)
        msg = ('Value of heat flow must be ' + str(round(P, 0)) + ', is ' +
               str(round(Q_is, 0)) + '.')
        assert round(P, 0) == round(Q_is, 0), msg

        # Check the state of the steam and working fluid outlet:
        x_outl1_calc = self.c2.x.val
        x_outl3_calc = self.c6.x.val
        zeta1 = self.instance.zeta1.val
        zeta2 = self.instance.zeta2.val
        zeta3 = self.instance.zeta3.val

        msg = ('Vapor mass fraction of steam outlet must be 0.0, is ' +
               str(round(x_outl1_calc, 1)) + '.')
        assert round(x_outl1_calc, 1) == 0.0, msg

        msg = ('Vapor mass fraction of working fluid outlet must be 1.0, is ' +
               str(round(x_outl3_calc, 1)) + '.')
        assert round(x_outl3_calc, 1) == 1.0, msg

        # Check offdesign by zeta values
        # geometry independent friction coefficient
        self.nw.solve('offdesign', design_path='tmp')
        convergence_check(self.nw.lin_dep)

        msg = ('Geometry independent friction coefficient '
               'at hot side 1 (steam) '
               'must be ' + str(round(zeta1, 1)) + ', is ' +
               str(round(self.instance.zeta1.val, 1)) + '.')
        assert round(self.instance.zeta1.val, 1) == round(zeta1, 1), msg
        msg = ('Geometry independent friction coefficient at '
               'hot side 2 (brine) '
               'must be ' + str(round(zeta2, 1)) + ', is ' +
               str(round(self.instance.zeta2.val, 1)) + '.')
        assert round(self.instance.zeta2.val, 1) == round(zeta2, 1), msg
        msg = ('Geometry independent friction coefficient at cold side '
               '(Isopentane) must be ' + str(round(zeta3, 1)) + ', is ' +
               str(round(self.instance.zeta3.val, 1)) + '.')
        assert round(self.instance.zeta3.val, 1) == round(zeta3, 1), msg

        # test parameters of 'subcooling' and 'overheating'
        self.instance.set_attr(subcooling=True, overheating=True)
        dT = 0.5
        self.c2.set_attr(Td_bp=-dT)
        self.c6.set_attr(Td_bp=dT)
        self.nw.solve('offdesign', design_path='tmp')
        convergence_check(self.nw.lin_dep)

        T_steam = T_bp_p(self.c2.get_flow()) - dT
        T_isop = T_bp_p(self.c6.get_flow()) + dT

        msg = ('Temperature of working fluid outlet must be ' +
               str(round(T_isop, 1)) + ', is ' +
               str(round(self.c6.T.val_SI, 1)) + '.')
        assert round(T_isop, 1) == round(self.c6.T.val_SI, 1), msg

        msg = ('Temperature of steam outlet must be ' +
               str(round(T_steam, 1)) + ', is ' +
               str(round(self.c2.T.val_SI, 1)) + '.')
        assert round(T_steam, 1) == round(self.c2.T.val_SI, 1), msg

        shutil.rmtree('./tmp', ignore_errors=True)
예제 #10
0
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)
예제 #11
0
he_hs = Connection(he, 'out1', hsin, 'in1')

nw.add_conns(tes_he, he_tes, hs_he, he_hs)

# %% busses

heat = Bus('heat system')
heat_sto = Bus('heat storage')
# needs these busses, even if they are empty
power = Bus('power')
ti = Bus('ti')

heat.add_comps({'comp': he, 'char': -1})
heat_sto.add_comps({'comp': he, 'char': -1})

nw.add_busses(heat, heat_sto, power, ti)

# %% parameters

he.set_attr(pr1=0.98, pr2=0.98, design=['pr1', 'pr2'],
            offdesign=['zeta1', 'zeta2', 'kA_char'])

# %% Schnittstellenparameter

hs_he.set_attr(T=90, p=10, fluid={'water': 1})
he_hs.set_attr(T=60, design=['T'])
tes_he.set_attr(T=40, p=10, fluid={'water': 1})
he_tes.set_attr(T=75)

heat.set_attr(P=1000e3)
heat_design = heat.P.val
예제 #12
0
class TestCombustion:
    def setup(self):

        self.nw = Network(['H2O', 'N2', 'O2', 'Ar', 'CO2', 'CH4'],
                          T_unit='C',
                          p_unit='bar',
                          v_unit='m3 / s')
        self.fuel = Source('fuel')
        self.air = Source('ambient air')
        self.fg = Sink('flue gas')

    def setup_CombustionChamber_network(self, instance):

        self.c1 = Connection(self.air, 'out1', instance, 'in1')
        self.c2 = Connection(self.fuel, 'out1', instance, 'in2')
        self.c3 = Connection(instance, 'out1', self.fg, 'in1')
        self.nw.add_conns(self.c1, self.c2, self.c3)

    def setup_CombustionEngine_network(self, instance):

        self.cw1_in = Source('cooling water 1 source')
        self.cw2_in = Source('cooling water 2 source')
        self.cw1_out = Sink('cooling water 1 sink')
        self.cw2_out = Sink('cooling water 2 sink')

        self.c1 = Connection(self.air, 'out1', instance, 'in3')
        self.c2 = Connection(self.fuel, 'out1', instance, 'in4')
        self.c3 = Connection(instance, 'out3', self.fg, 'in1')
        self.c4 = Connection(self.cw1_in, 'out1', instance, 'in1')
        self.c5 = Connection(self.cw2_in, 'out1', instance, 'in2')
        self.c6 = Connection(instance, 'out1', self.cw1_out, 'in1')
        self.c7 = Connection(instance, 'out2', self.cw2_out, 'in1')
        self.nw.add_conns(self.c1, self.c2, self.c3, self.c4, self.c5, self.c6,
                          self.c7)

    def test_CombustionChamber(self):
        """
        Test component properties of combustion chamber.
        """
        instance = CombustionChamber('combustion chamber')
        self.setup_CombustionChamber_network(instance)

        # connection parameter specification
        air = {
            'N2': 0.7556,
            'O2': 0.2315,
            'Ar': 0.0129,
            'H2O': 0,
            'CO2': 0,
            'CH4': 0
        }
        fuel = {'N2': 0, 'O2': 0, 'Ar': 0, 'H2O': 0, 'CO2': 0.04, 'CH4': 0.96}
        self.c1.set_attr(fluid=air, p=1, T=30)
        self.c2.set_attr(fluid=fuel, T=30)
        self.c3.set_attr(T=1200)

        # test specified bus value on CombustionChamber (must be equal to ti)
        b = Bus('thermal input', P=1e6)
        b.add_comps({'comp': instance})
        self.nw.add_busses(b)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of thermal input must be ' + str(b.P.val) + ', is ' +
               str(instance.ti.val) + '.')
        assert round(b.P.val, 1) == round(instance.ti.val, 1), msg
        b.set_attr(P=np.nan)

        # test specified thermal input for CombustionChamber
        instance.set_attr(ti=1e6)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        ti = (self.c2.m.val_SI * self.c2.fluid.val['CH4'] *
              instance.fuels['CH4']['LHV'])
        msg = ('Value of thermal input must be ' + str(instance.ti.val) +
               ', is ' + str(ti) + '.')
        assert round(ti, 1) == round(instance.ti.val, 1), msg

        # test specified lamb for CombustionChamber
        self.c3.set_attr(T=np.nan)
        instance.set_attr(lamb=1)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of oxygen in flue gas must be 0.0, is ' +
               str(round(self.c3.fluid.val['O2'], 4)) + '.')
        assert 0.0 == round(self.c3.fluid.val['O2'], 4), msg

    def test_CombustionEngine(self):
        """Test component properties of combustion engine."""
        instance = CombustionEngine('combustion engine')
        self.setup_CombustionEngine_network(instance)

        air = {
            'N2': 0.7556,
            'O2': 0.2315,
            'Ar': 0.0129,
            'H2O': 0,
            'CO2': 0,
            'CH4': 0
        }
        fuel = {'N2': 0, 'O2': 0, 'Ar': 0, 'H2O': 0, 'CO2': 0.04, 'CH4': 0.96}
        water1 = {'N2': 0, 'O2': 0, 'Ar': 0, 'H2O': 1, 'CO2': 0, 'CH4': 0}
        water2 = {'N2': 0, 'O2': 0, 'Ar': 0, 'H2O': 1, 'CO2': 0, 'CH4': 0}

        # connection parametrisation
        instance.set_attr(pr1=0.99,
                          pr2=0.99,
                          lamb=1.0,
                          design=['pr1', 'pr2'],
                          offdesign=['zeta1', 'zeta2'])
        self.c1.set_attr(p=5, T=30, fluid=air)
        self.c2.set_attr(T=30, fluid=fuel)
        self.c4.set_attr(p=3, T=60, m=50, fluid=water1)
        self.c5.set_attr(p=3, T=80, m=50, fluid=water2)

        # create busses
        TI = Bus('thermal input')
        Q1 = Bus('heat output 1')
        Q2 = Bus('heat output 2')
        Q = Bus('heat output')
        Qloss = Bus('thermal heat loss')

        TI.add_comps({'comp': instance, 'param': 'TI'})
        Q1.add_comps({'comp': instance, 'param': 'Q1'})
        Q2.add_comps({'comp': instance, 'param': 'Q2'})
        Q.add_comps({'comp': instance, 'param': 'Q'})
        Qloss.add_comps({'comp': instance, 'param': 'Qloss'})

        self.nw.add_busses(TI, Q1, Q2, Q, Qloss)

        # test specified thermal input bus value
        ti = 1e6
        TI.set_attr(P=ti)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        self.nw.save('tmp')
        # calculate in offdesign mode
        self.nw.solve('offdesign', init_path='tmp', design_path='tmp')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of thermal input must be ' + str(TI.P.val) + ', is ' +
               str(instance.ti.val) + '.')
        assert round(TI.P.val, 1) == round(instance.ti.val, 1), msg

        # test specified thermal input in component
        TI.set_attr(P=np.nan)
        instance.set_attr(ti=ti)
        self.nw.solve('offdesign', init_path='tmp', design_path='tmp')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of thermal input must be ' + str(ti) + ', is ' +
               str(instance.ti.val) + '.')
        assert round(ti, 1) == round(instance.ti.val, 1), msg
        instance.set_attr(ti=None)

        # test specified heat output 1 bus value
        Q1.set_attr(P=instance.Q1.val)
        self.nw.solve('offdesign', init_path='tmp', design_path='tmp')
        convergence_check(self.nw.lin_dep)
        # heat output is at design point value, thermal input must therefore
        # not have changed
        msg = ('Value of thermal input must be ' + str(ti) + ', is ' +
               str(instance.ti.val) + '.')
        assert round(ti, 1) == round(instance.ti.val, 1), msg

        # calculate heat output over cooling loop
        heat1 = self.c4.m.val_SI * (self.c6.h.val_SI - self.c4.h.val_SI)
        msg = ('Value of heat output 1 must be ' + str(-heat1) + ', is ' +
               str(instance.Q1.val) + '.')
        assert round(heat1, 1) == -round(instance.Q1.val, 1), msg
        Q1.set_attr(P=np.nan)

        # test specified heat output 2 bus value
        Q2.set_attr(P=1.2 * instance.Q2.val)
        self.nw.solve('offdesign', init_path='tmp', design_path='tmp')
        convergence_check(self.nw.lin_dep)

        # calculate heat output over cooling loop
        heat2 = self.c5.m.val_SI * (self.c7.h.val_SI - self.c5.h.val_SI)
        msg = ('Value of heat output 2 must be ' + str(-heat2) + ', is ' +
               str(instance.Q2.val) + '.')
        assert round(heat2, 1) == -round(instance.Q2.val, 1), msg

        # test specified heat output 2 in component
        Q2.set_attr(P=np.nan)
        instance.set_attr(Q2=-heat2)
        self.nw.solve('offdesign', init_path='tmp', design_path='tmp')
        convergence_check(self.nw.lin_dep)
        heat2 = self.c5.m.val_SI * (self.c7.h.val_SI - self.c5.h.val_SI)
        msg = ('Value of heat output 2 must be ' + str(-heat2) + ', is ' +
               str(instance.Q2.val) + '.')
        assert round(heat2, 1) == -round(instance.Q2.val, 1), msg

        # test total heat output bus value
        instance.set_attr(Q2=np.nan)
        Q.set_attr(P=1.5 * instance.Q1.val)
        self.nw.solve('offdesign', init_path='tmp', design_path='tmp')
        convergence_check(self.nw.lin_dep)
        heat = (self.c4.m.val_SI * (self.c6.h.val_SI - self.c4.h.val_SI) +
                self.c5.m.val_SI * (self.c7.h.val_SI - self.c5.h.val_SI))
        msg = ('Value of total heat output must be ' + str(Q.P.val) + ', is ' +
               str(-heat) + '.')
        assert round(Q.P.val, 1) == -round(heat, 1), msg

        # test specified heat loss bus value
        Q.set_attr(P=np.nan)
        Qloss.set_attr(P=-1e5)
        self.nw.solve('offdesign', init_path='tmp', design_path='tmp')
        convergence_check(self.nw.lin_dep)
        msg = ('Value of heat loss must be ' + str(Qloss.P.val) + ', is ' +
               str(instance.Qloss.val) + '.')
        assert round(Qloss.P.val, 1) == round(instance.Qloss.val, 1), msg
        shutil.rmtree('./tmp', ignore_errors=True)
예제 #13
0
파일: chp.py 프로젝트: oemof/oemof-examples
x = np.array([0, 0.2, 0.4, 0.6, 0.8, 1, 1.2])
y = np.array([0.5, 0.87, 0.91, 0.94, 0.96, 0.97, 0.96])

char = CharLine(x, y)
# power bus
power_bus = Bus('power')
power_bus.add_comps(
    {'comp': turbine_hp, 'char': char, 'base': 'component'},
    {'comp': turbine_lp, 'char': char, 'base': 'component'},
    {'comp': pump, 'char': char, 'base': 'bus'})

# heating bus
heat_bus = Bus('heat')
heat_bus.add_comps({'comp': cond, 'char': -1})

nw.add_busses(power_bus, heat_bus)

# %% parametrization of components

turbine_hp.set_attr(eta_s=0.9, design=['eta_s'],
                    offdesign=['eta_s_char', 'cone'])
turbine_lp.set_attr(eta_s=0.9, design=['eta_s'],
                    offdesign=['eta_s_char', 'cone'])

cond.set_attr(pr1=1, pr2=0.99, ttd_u=12, design=['pr2', 'ttd_u'],
              offdesign=['zeta2', 'kA_char'])
preheater.set_attr(pr1=1, pr2=0.99, ttd_u=5,
                   design=['pr2', 'ttd_u', 'ttd_l'],
                   offdesign=['zeta2', 'kA_char'])

pump.set_attr(eta_s=0.8, design=['eta_s'], offdesign=['eta_s_char'])
예제 #14
0
class TestClausiusRankine:
    def setup(self):
        """Set up clausis rankine cycle with turbine driven feed water pump."""
        self.Tamb = 20
        self.pamb = 1
        fluids = ['water']
        self.nw = Network(fluids=fluids)
        self.nw.set_attr(p_unit='bar', T_unit='C', h_unit='kJ / kg')

        # create components
        splitter1 = Splitter('splitter 1')
        merge1 = Merge('merge 1')
        turb = Turbine('turbine')
        fwp_turb = Turbine('feed water pump turbine')
        condenser = HeatExchangerSimple('condenser')
        fwp = Pump('pump')
        steam_generator = HeatExchangerSimple('steam generator')
        cycle_close = CycleCloser('cycle closer')

        # create busses
        # power output bus
        self.power = Bus('power_output')
        self.power.add_comps({'comp': turb, 'char': 1})
        # turbine driven feed water pump internal bus
        self.fwp_power = Bus('feed water pump power', P=0)
        self.fwp_power.add_comps({
            'comp': fwp_turb,
            'char': 1
        }, {
            'comp': fwp,
            'char': 1,
            'base': 'bus'
        })
        # heat input bus
        self.heat = Bus('heat_input')
        self.heat.add_comps({'comp': steam_generator, 'base': 'bus'})
        self.nw.add_busses(self.power, self.fwp_power, self.heat)

        # create connections
        fs_in = Connection(cycle_close, 'out1', splitter1, 'in1', label='fs')
        fs_fwpt = Connection(splitter1, 'out1', fwp_turb, 'in1')
        fs_t = Connection(splitter1, 'out2', turb, 'in1')
        fwpt_ws = Connection(fwp_turb, 'out1', merge1, 'in1')
        t_ws = Connection(turb, 'out1', merge1, 'in2')
        ws = Connection(merge1, 'out1', condenser, 'in1')
        cond = Connection(condenser, 'out1', fwp, 'in1', label='cond')
        fw = Connection(fwp, 'out1', steam_generator, 'in1', label='fw')
        fs_out = Connection(steam_generator, 'out1', cycle_close, 'in1')
        self.nw.add_conns(fs_in, fs_fwpt, fs_t, fwpt_ws, t_ws, ws, cond, fw,
                          fs_out)

        # component parameters
        turb.set_attr(eta_s=1)
        fwp_turb.set_attr(eta_s=1)
        condenser.set_attr(pr=1)
        fwp.set_attr(eta_s=1)
        steam_generator.set_attr(pr=1)

        # connection parameters
        fs_in.set_attr(m=10, p=120, T=600, fluid={'water': 1})
        cond.set_attr(T=self.Tamb, x=0)

        # solve network
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)

    def test_exergy_analysis_perfect_cycle(self):
        """Test exergy analysis in the perfect clausius rankine cycle."""
        self.nw.exergy_analysis(self.pamb,
                                self.Tamb,
                                E_P=[self.power],
                                E_F=[self.heat],
                                internal_busses=[self.fwp_power])
        msg = ('Exergy destruction of this network must be 0 (smaller than ' +
               str(err**0.5) + ') for this test but is ' +
               str(round(abs(self.nw.E_D), 4)) + ' .')
        assert abs(self.nw.E_D) <= err**0.5, msg

        msg = ('Exergy efficiency of this network must be 1 for this test but '
               'is ' + str(round(self.nw.epsilon, 4)) + ' .')
        assert round(self.nw.epsilon, 4) == 1, msg

        exergy_balance = self.nw.E_F - self.nw.E_P - self.nw.E_L - self.nw.E_D
        msg = ('Exergy balance must be closed (residual value smaller than ' +
               str(err**0.5) + ') for this test but is ' +
               str(round(abs(exergy_balance), 4)) + ' .')
        assert abs(exergy_balance) <= err**0.5, msg

        msg = (
            'Fuel exergy and product exergy must be identical for this test. '
            'Fuel exergy value: ' + str(round(self.nw.E_F, 4)) +
            '. Product exergy value: ' + str(round(self.nw.E_P, 4)) + '.')
        assert round(abs(self.nw.E_F - self.nw.E_P), 4) < err**0.5, msg

    def test_entropy_perfect_cycle(self):
        """Test entropy values in the perfect clausius rankine cycle."""
        labels = [
            'turbine', 'feed water pump turbine', 'condenser',
            'steam generator', 'pump'
        ]
        for label in labels:
            cp = self.nw.get_comp(label)
            msg = (
                'Entropy production due to irreversibility must be 0 for all '
                'components in this test but is ' + str(round(cp.S_irr, 4)) +
                ' at component ' + label + ' of type ' + cp.component() + '.')
            assert round(cp.S_irr, 4) == 0, msg
        sg = self.nw.get_comp('steam generator')
        cd = self.nw.get_comp('condenser')
        msg = (
            'Value of entropy production due to heat input at steam generator '
            '(S_Q=' + str(round(sg.S_Q, 4)) + ') must equal the negative '
            'value of entropy reduction in condenser (S_Q=' +
            str(round(cd.S_Q, 4)) + ').')
        assert round(sg.S_Q, 4) == -round(cd.S_Q, 4), msg

    def test_exergy_analysis_violated_balance(self):
        """Test exergy analysis with violated balance."""
        # specify efficiency values for the internal bus
        self.nw.del_busses(self.fwp_power)
        self.fwp_power = Bus('feed water pump power', P=0)
        self.fwp_power.add_comps(
            {
                'comp': self.nw.get_comp('feed water pump turbine'),
                'char': 0.99
            }, {
                'comp': self.nw.get_comp('pump'),
                'char': 0.98,
                'base': 'bus'
            })
        self.nw.add_busses(self.fwp_power)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        # miss out on internal bus in exergy_analysis
        self.nw.exergy_analysis(self.pamb,
                                self.Tamb,
                                E_P=[self.power],
                                E_F=[self.heat])

        exergy_balance = self.nw.E_F - self.nw.E_P - self.nw.E_L - self.nw.E_D
        msg = ('Exergy balance must be violated for this test (larger than ' +
               str(err**0.5) + ') but is ' +
               str(round(abs(exergy_balance), 4)) + ' .')
        assert abs(exergy_balance) > err**0.5, msg

    def test_exergy_analysis_bus_conversion(self):
        """Test exergy analysis bus conversion factors."""
        # specify efficiency values for the internal bus
        self.nw.del_busses(self.fwp_power)
        self.fwp_power = Bus('feed water pump power', P=0)
        self.fwp_power.add_comps(
            {
                'comp': self.nw.get_comp('feed water pump turbine'),
                'char': 0.99
            }, {
                'comp': self.nw.get_comp('pump'),
                'char': 0.98,
                'base': 'bus'
            })
        self.nw.add_busses(self.fwp_power)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        # no exergy losses in this case
        self.nw.exergy_analysis(self.pamb,
                                self.Tamb,
                                E_P=[self.power],
                                E_F=[self.heat],
                                internal_busses=[self.fwp_power])
        label = 'pump on bus feed water pump power'
        eps = self.nw.component_exergy_data.loc[label, 'epsilon']
        msg = ('Pump exergy efficiency must be 0.98 but is ' +
               str(round(eps, 4)) + ' .')
        assert round(eps, 4) == 0.98, msg

        label = 'feed water pump turbine on bus feed water pump power'
        eps = self.nw.component_exergy_data.loc[label, 'epsilon']
        eps = self.nw.component_exergy_data.loc[label, 'epsilon']
        msg = (
            'Feed water pump turbine exergy efficiency must be 0.99 but is ' +
            str(round(eps, 4)) + ' .')
        assert round(eps, 4) == 0.99, msg

    def test_exergy_analysis_missing_E_F_E_P_information(self):
        """Test exergy analysis errors with missing information."""
        with raises(TESPyNetworkError):
            self.nw.exergy_analysis(self.pamb,
                                    self.Tamb,
                                    E_P=[self.power],
                                    E_F=[])

        with raises(TESPyNetworkError):
            self.nw.exergy_analysis(self.pamb,
                                    self.Tamb,
                                    E_P=[],
                                    E_F=[self.heat])

    def test_exergy_analysis_component_on_two_busses(self):
        """Test exergy analysis errors with components on more than one bus."""
        with raises(TESPyNetworkError):
            self.nw.exergy_analysis(self.pamb,
                                    self.Tamb,
                                    E_P=[self.power],
                                    E_F=[self.heat, self.power])
예제 #15
0
class TestRefrigerator:
    def setup(self):
        """Set up simple refrigerator."""
        self.Tamb = 20
        self.pamb = 1
        fluids = ['R134a']
        self.nw = Network(fluids=fluids)
        self.nw.set_attr(p_unit='bar', T_unit='C', h_unit='kJ / kg')

        # create components
        va = Valve('expansion valve')
        cp = Compressor('compressor')
        cond = HeatExchangerSimple('condenser')
        eva = HeatExchangerSimple('evaporator')
        cc = CycleCloser('cycle closer')

        # create busses
        # power output bus
        self.power = Bus('power input')
        self.power.add_comps({'comp': cp, 'char': 1, 'base': 'bus'})
        # cooling bus
        self.cool = Bus('heat from fridge')
        self.cool.add_comps({'comp': eva})
        # heat input bus
        self.heat = Bus('heat to ambient')
        self.heat.add_comps({'comp': cond})
        self.nw.add_busses(self.power, self.cool, self.heat)

        # create connections
        cc_cp = Connection(cc, 'out1', cp, 'in1', label='from eva')
        cp_cond = Connection(cp, 'out1', cond, 'in1', label='to cond')
        cond_va = Connection(cond, 'out1', va, 'in1', label='from cond')
        va_eva = Connection(va, 'out1', eva, 'in1', label='to eva')
        eva_cc = Connection(eva, 'out1', cc, 'in1')
        self.nw.add_conns(cc_cp, cp_cond, cond_va, va_eva, eva_cc)

        # component parameters
        cp.set_attr(eta_s=0.9)
        cond.set_attr(pr=0.97)
        eva.set_attr(pr=0.96)

        # connection parameters
        cc_cp.set_attr(m=1, x=1, T=-25, fluid={'R134a': 1})
        cond_va.set_attr(x=0, T=self.Tamb + 1)

        # solve network
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)

    def test_exergy_analysis_bus_conversion(self):
        """Test exergy analysis at product exergy with T < Tamb."""
        # no exergy losses in this case
        ean = ExergyAnalysis(self.nw, E_P=[self.cool], E_F=[self.power])
        ean.analyse(pamb=self.pamb, Tamb=self.Tamb)

        exergy_balance = (ean.network_data.E_F - ean.network_data.E_P -
                          ean.network_data.E_L - ean.network_data.E_D)
        msg = ('Exergy balance must be closed (residual value smaller than ' +
               str(err**0.5) + ') for this test but is ' +
               str(round(abs(exergy_balance), 4)) + ' .')
        assert abs(exergy_balance) <= err**0.5, msg
예제 #16
0
파일: ccet_040.py 프로젝트: maltefritz/SWSH
    'base': 'bus'
})

gt_power = Bus('gas turbine power output')
gt_power.add_comps({'comp': g_turb}, {'comp': comp})

heat_out = Bus('heat output')
heat_out.add_comps({'comp': cond_dh})

heat_cond = Bus('heat cond')
heat_cond.add_comps({'comp': cond})

heat_in = Bus('heat input')
heat_in.add_comps({'comp': c_c})

nw.add_busses(power, gt_power, heat_out, heat_cond, heat_in)

# %% component parameters

# characteristic line for compressor isentropic efficiency
x = np.array([0.000, 0.400, 1.000, 1.600, 2.000])
y = np.array([0.500, 0.900, 1.000, 1.050, 0.9500])
cp_char1 = dict(char_func=CharLine(x, y), param='m')
cp_char2 = dict(char_func=CharLine(x, y), param='m')

# characteristic line for turbine isentropic efficiency
x = np.array([
    0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4,
    1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5
])
y = np.array([
예제 #17
0
class TestClausiusRankine:
    def setup(self):
        """Set up clausis rankine cycle with turbine driven feed water pump."""
        self.Tamb = 20
        self.pamb = 1
        fluids = ['water']
        self.nw = Network(fluids=fluids)
        self.nw.set_attr(p_unit='bar', T_unit='C', h_unit='kJ / kg')

        # create components
        splitter1 = Splitter('splitter 1')
        merge1 = Merge('merge 1')
        turb = Turbine('turbine')
        fwp_turb = Turbine('feed water pump turbine')
        condenser = HeatExchangerSimple('condenser')
        fwp = Pump('pump')
        steam_generator = HeatExchangerSimple('steam generator')
        cycle_close = CycleCloser('cycle closer')

        # create busses
        # power output bus
        self.power = Bus('power_output')
        self.power.add_comps({'comp': turb, 'char': 1})
        # turbine driven feed water pump internal bus
        self.fwp_power = Bus('feed water pump power', P=0)
        self.fwp_power.add_comps({
            'comp': fwp_turb,
            'char': 1
        }, {
            'comp': fwp,
            'char': 1,
            'base': 'bus'
        })
        # heat input bus
        self.heat = Bus('heat_input')
        self.heat.add_comps({'comp': steam_generator, 'base': 'bus'})
        self.nw.add_busses(self.power, self.fwp_power, self.heat)

        # create connections
        fs_in = Connection(cycle_close, 'out1', splitter1, 'in1', label='fs')
        fs_fwpt = Connection(splitter1, 'out1', fwp_turb, 'in1')
        fs_t = Connection(splitter1, 'out2', turb, 'in1')
        fwpt_ws = Connection(fwp_turb, 'out1', merge1, 'in1')
        t_ws = Connection(turb, 'out1', merge1, 'in2')
        ws = Connection(merge1, 'out1', condenser, 'in1')
        cond = Connection(condenser, 'out1', fwp, 'in1', label='cond')
        fw = Connection(fwp, 'out1', steam_generator, 'in1', label='fw')
        fs_out = Connection(steam_generator, 'out1', cycle_close, 'in1')
        self.nw.add_conns(fs_in, fs_fwpt, fs_t, fwpt_ws, t_ws, ws, cond, fw,
                          fs_out)

        # component parameters
        turb.set_attr(eta_s=1)
        fwp_turb.set_attr(eta_s=1)
        condenser.set_attr(pr=1)
        fwp.set_attr(eta_s=1)
        steam_generator.set_attr(pr=1)

        # connection parameters
        fs_in.set_attr(m=10, p=120, T=600, fluid={'water': 1})
        cond.set_attr(T=self.Tamb, x=0)

        # solve network
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)

    def test_exergy_analysis_perfect_cycle(self):
        """Test exergy analysis in the perfect clausius rankine cycle."""
        ean = ExergyAnalysis(self.nw,
                             E_P=[self.power],
                             E_F=[self.heat],
                             internal_busses=[self.fwp_power])
        ean.analyse(pamb=self.pamb, Tamb=self.Tamb)
        msg = ('Exergy destruction of this network must be 0 (smaller than ' +
               str(err**0.5) + ') for this test but is ' +
               str(round(abs(ean.network_data.E_D), 4)) + ' .')
        assert abs(ean.network_data.E_D) <= err**0.5, msg

        msg = ('Exergy efficiency of this network must be 1 for this test but '
               'is ' + str(round(ean.network_data.epsilon, 4)) + ' .')
        assert round(ean.network_data.epsilon, 4) == 1, msg

        exergy_balance = (ean.network_data.E_F - ean.network_data.E_P -
                          ean.network_data.E_L - ean.network_data.E_D)
        msg = ('Exergy balance must be closed (residual value smaller than ' +
               str(err**0.5) + ') for this test but is ' +
               str(round(abs(exergy_balance), 4)) + ' .')
        assert abs(exergy_balance) <= err**0.5, msg

        msg = (
            'Fuel exergy and product exergy must be identical for this test. '
            'Fuel exergy value: ' + str(round(ean.network_data.E_F, 4)) +
            '. Product exergy value: ' + str(round(ean.network_data.E_P, 4)) +
            '.')
        delta = round(abs(ean.network_data.E_F - ean.network_data.E_P), 4)
        assert delta < err**0.5, msg

    def test_exergy_analysis_plotting_data(self):
        """Test exergy analysis plotting."""
        self.nw.get_comp('steam generator').set_attr(pr=0.9)
        self.nw.get_comp('turbine').set_attr(eta_s=0.9)
        self.nw.get_comp('feed water pump turbine').set_attr(eta_s=0.85)
        self.nw.get_comp('pump').set_attr(eta_s=0.75)
        self.nw.get_conn('cond').set_attr(T=self.Tamb + 3)

        # specify efficiency values for the internal bus and power bus
        self.nw.del_busses(self.fwp_power, self.power)

        self.fwp_power = Bus('feed water pump power', P=0)
        self.fwp_power.add_comps(
            {
                'comp': self.nw.get_comp('feed water pump turbine'),
                'char': 0.99
            }, {
                'comp': self.nw.get_comp('pump'),
                'char': 0.98,
                'base': 'bus'
            })
        self.power = Bus('power_output')
        self.power.add_comps({
            'comp': self.nw.get_comp('turbine'),
            'char': 0.98
        })

        self.nw.add_busses(self.fwp_power, self.power)

        # solve network
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        ean = ExergyAnalysis(self.nw,
                             E_P=[self.power],
                             E_F=[self.heat],
                             internal_busses=[self.fwp_power])
        ean.analyse(pamb=self.pamb, Tamb=self.Tamb)

        exergy_balance = (ean.network_data.E_F - ean.network_data.E_P -
                          ean.network_data.E_L - ean.network_data.E_D)
        msg = ('Exergy balance must be closed (residual value smaller than ' +
               str(err**0.5) + ') for this test but is ' +
               str(round(abs(exergy_balance), 4)) + ' .')
        assert abs(exergy_balance) <= err**0.5, msg

        nodes = [
            'E_F', 'steam generator', 'splitter 1', 'feed water pump turbine',
            'turbine', 'merge 1', 'condenser', 'pump', 'E_D', 'E_P'
        ]

        links, nodes = ean.generate_plotly_sankey_input(node_order=nodes)
        # checksum for targets and source
        checksum = sum(links['target'] + links['source'])
        msg = ('The checksum of all target and source values in the link lists'
               'must be 148, but is ' + str(checksum) + '.')
        assert 148 == checksum, msg

    def test_exergy_analysis_violated_balance(self):
        """Test exergy analysis with violated balance."""
        # specify efficiency values for the internal bus
        self.nw.del_busses(self.fwp_power)
        self.fwp_power = Bus('feed water pump power', P=0)
        self.fwp_power.add_comps(
            {
                'comp': self.nw.get_comp('feed water pump turbine'),
                'char': 0.99
            }, {
                'comp': self.nw.get_comp('pump'),
                'char': 0.98,
                'base': 'bus'
            })
        self.nw.add_busses(self.fwp_power)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        # miss out on internal bus in exergy_analysis
        ean = ExergyAnalysis(self.nw, E_P=[self.power], E_F=[self.heat])
        ean.analyse(pamb=self.pamb, Tamb=self.Tamb)

        exergy_balance = (ean.network_data.E_F - ean.network_data.E_P -
                          ean.network_data.E_L - ean.network_data.E_D)
        msg = ('Exergy balance must be violated for this test (larger than ' +
               str(err**0.5) + ') but is ' +
               str(round(abs(exergy_balance), 4)) + ' .')
        assert abs(exergy_balance) > err**0.5, msg

    def test_exergy_analysis_bus_conversion(self):
        """Test exergy analysis bus conversion factors."""
        # specify efficiency values for the internal bus
        self.nw.del_busses(self.fwp_power)
        self.fwp_power = Bus('feed water pump power', P=0)
        self.fwp_power.add_comps(
            {
                'comp': self.nw.get_comp('feed water pump turbine'),
                'char': 0.99
            }, {
                'comp': self.nw.get_comp('pump'),
                'char': 0.98,
                'base': 'bus'
            })
        self.nw.add_busses(self.fwp_power)
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)
        # no exergy losses in this case
        ean = ExergyAnalysis(self.nw,
                             E_P=[self.power],
                             E_F=[self.heat],
                             internal_busses=[self.fwp_power])
        ean.analyse(pamb=self.pamb, Tamb=self.Tamb)

        label = 'pump'
        eps = ean.bus_data.loc[label, 'epsilon']
        msg = ('Pump exergy efficiency must be 0.98 but is ' +
               str(round(eps, 4)) + ' .')
        assert round(eps, 4) == 0.98, msg

        label = 'feed water pump turbine'
        eps = ean.bus_data.loc[label, 'epsilon']
        msg = (
            'Feed water pump turbine exergy efficiency must be 0.99 but is ' +
            str(round(eps, 4)) + ' .')
        assert round(eps, 4) == 0.99, msg

    def test_exergy_analysis_missing_E_F_E_P_information(self):
        """Test exergy analysis errors with missing information."""
        with raises(TESPyNetworkError):
            ExergyAnalysis(self.nw, E_P=[self.power], E_F=[])

        with raises(TESPyNetworkError):
            ExergyAnalysis(self.nw, E_P=[], E_F=[self.heat])

    def test_exergy_analysis_component_on_two_busses(self):
        """Test exergy analysis errors with components on more than one bus."""
        with raises(TESPyNetworkError):
            ean = ExergyAnalysis(self.nw,
                                 E_P=[self.power],
                                 E_F=[self.heat, self.power])
            ean.analyse(pamb=self.pamb, Tamb=self.Tamb)
예제 #18
0
class TestClausiusRankine:
    def setup(self):
        """Set up clausis rankine cycle with turbine driven feed water pump."""
        self.Tamb = 20
        self.pamb = 1
        fluids = ['water']
        self.nw = Network(fluids=fluids)
        self.nw.set_attr(p_unit='bar', T_unit='C', h_unit='kJ / kg')

        # create components
        splitter1 = Splitter('splitter 1')
        merge1 = Merge('merge 1')
        turb = Turbine('turbine')
        fwp_turb = Turbine('feed water pump turbine')
        condenser = HeatExchangerSimple('condenser')
        fwp = Pump('pump')
        steam_generator = HeatExchangerSimple('steam generator')
        cycle_close = CycleCloser('cycle closer')

        # create busses
        # power output bus
        self.power = Bus('power_output')
        self.power.add_comps({'comp': turb, 'char': 1})
        # turbine driven feed water pump internal bus
        self.fwp_power = Bus('feed water pump power', P=0)
        self.fwp_power.add_comps({
            'comp': fwp_turb,
            'char': 1
        }, {
            'comp': fwp,
            'char': 1,
            'base': 'bus'
        })
        # heat input bus
        self.heat = Bus('heat_input')
        self.heat.add_comps({'comp': steam_generator, 'base': 'bus'})
        self.nw.add_busses(self.power, self.fwp_power, self.heat)

        # create connections
        fs_in = Connection(cycle_close, 'out1', splitter1, 'in1', label='fs')
        fs_fwpt = Connection(splitter1, 'out1', fwp_turb, 'in1')
        fs_t = Connection(splitter1, 'out2', turb, 'in1')
        fwpt_ws = Connection(fwp_turb, 'out1', merge1, 'in1')
        t_ws = Connection(turb, 'out1', merge1, 'in2')
        ws = Connection(merge1, 'out1', condenser, 'in1')
        cond = Connection(condenser, 'out1', fwp, 'in1', label='cond')
        fw = Connection(fwp, 'out1', steam_generator, 'in1', label='fw')
        fs_out = Connection(steam_generator, 'out1', cycle_close, 'in1')
        self.nw.add_conns(fs_in, fs_fwpt, fs_t, fwpt_ws, t_ws, ws, cond, fw,
                          fs_out)

        # component parameters
        turb.set_attr(eta_s=1)
        fwp_turb.set_attr(eta_s=1)
        condenser.set_attr(pr=1)
        fwp.set_attr(eta_s=1)
        steam_generator.set_attr(pr=1)

        # connection parameters
        fs_in.set_attr(m=10, p=120, T=600, fluid={'water': 1})
        cond.set_attr(T=self.Tamb, x=0)

        # solve network
        self.nw.solve('design')
        convergence_check(self.nw.lin_dep)

    def test_entropy_perfect_cycle(self):
        """Test entropy values in the perfect clausius rankine cycle."""
        labels = [
            'turbine', 'feed water pump turbine', 'condenser',
            'steam generator', 'pump'
        ]
        for label in labels:
            cp = self.nw.get_comp(label)
            msg = (
                'Entropy production due to irreversibility must be 0 for all '
                'components in this test but is ' + str(round(cp.S_irr, 4)) +
                ' at component ' + label + ' of type ' + cp.component() + '.')
            assert round(cp.S_irr, 4) == 0, msg
        sg = self.nw.get_comp('steam generator')
        cd = self.nw.get_comp('condenser')
        msg = (
            'Value of entropy production due to heat input at steam generator '
            '(S_Q=' + str(round(sg.S_Q, 4)) + ') must equal the negative '
            'value of entropy reduction in condenser (S_Q=' +
            str(round(cd.S_Q, 4)) + ').')
        assert round(sg.S_Q, 4) == -round(cd.S_Q, 4), msg
예제 #19
0
class PowerPlant():

    def __init__(self, working_fluid):
        """Set up model."""
        self.working_fluid = working_fluid
        fluids = ['water', self.working_fluid, 'air']
        self.nw = Network(fluids=fluids)
        self.nw.set_attr(p_unit='bar', T_unit='C', h_unit='kJ / kg')

        # geo parameters

        self.geo_mass_flow = 200
        geo_steam_share = 0.1
        self.T_brine_in = 140

        # ambient parameters

        self.T_amb = 5
        self.p_amb = 0.6

        # main components

        geo_steam = Source('geosteam source')
        geo_brine = Source('geobrine source')
        geo_reinjection = Sink('re-injection')

        air_in = Source('air source')
        air_out = Sink('air sink')
        air_fan = Compressor('air fan')
        air_cond = Condenser('condenser')

        orc_cc = CycleCloser('orc cycle closer')

        evap_splitter = Splitter('splitter evaporation')
        evap_merge = Merge('merge evaporation')
        evap_steam = Condenser('geosteam evaporator')
        evap_brine = HeatExchanger('geobrine evaporator')
        dr = Drum('drum')
        geo_merge = Merge('merge brine')

        pre = HeatExchanger('preheater')
        feed_working_fluid_pump = Pump('feed pump')

        tur = Turbine('turbine')

        ihe = HeatExchanger('internal heat exchanger')

        # busses
        net_power = Bus('net power output')
        net_power.add_comps(
            {'comp': tur, 'char': 0.97},
            {'comp': feed_working_fluid_pump, 'char': 0.97, 'base': 'bus'},
            {'comp': air_fan, 'char': 0.97, 'base': 'bus'}
        )

        ORC_power_bus = Bus('cycle gross power output')
        ORC_power_bus.add_comps(
            {'comp': tur}, {'comp': feed_working_fluid_pump}
        )

        geothermal_bus = Bus('thermal input')
        geothermal_bus.add_comps(
            {'comp': pre, 'char': -1}, {'comp': evap_brine, 'char': -1},
            {'comp': evap_steam, 'char': -1}
        )

        self.nw.add_busses(net_power, ORC_power_bus, geothermal_bus)

        # turbine to condenser
        c1 = Connection(orc_cc, 'out1', tur, 'in1', label='1')
        c2 = Connection(tur, 'out1', ihe, 'in1', label='2')
        c3 = Connection(ihe, 'out1', air_cond, 'in1', label='3')
        self.nw.add_conns(c1, c2, c3)

        # condenser to steam generator
        c4 = Connection(air_cond, 'out1', feed_working_fluid_pump, 'in1', label='4')
        c5 = Connection(feed_working_fluid_pump, 'out1', ihe, 'in2', label='5')
        self.nw.add_conns(c4, c5)

        # steam generator
        c6 = Connection(ihe, 'out2', pre, 'in2', label='6')
        c7 = Connection(pre, 'out2', dr, 'in1', label='7')
        c8 = Connection(dr, 'out1', evap_splitter, 'in1', label='8')
        c9 = Connection(evap_splitter, 'out2', evap_steam, 'in2', label='9')
        c10 = Connection(evap_steam, 'out2', evap_merge, 'in2', label='10')
        c11 = Connection(evap_splitter, 'out1', evap_brine, 'in2', label='11')
        c12 = Connection(evap_brine, 'out2', evap_merge, 'in1', label='12')
        c13 = Connection(evap_merge, 'out1', dr, 'in2', label='13')
        c0 = Connection(dr, 'out2', orc_cc, 'in1', label='0')
        self.nw.add_conns(c6, c7, c8, c11, c9, c12, c10, c13, c0)

        # condenser cold side
        c20 = Connection(air_in, 'out1', air_fan, 'in1', label='20')
        c21 = Connection(air_fan, 'out1', air_cond, 'in2', label='21')
        c22 = Connection(air_cond, 'out2', air_out, 'in1', label='22')
        self.nw.add_conns(c20, c21, c22)

        # geo source
        c30 = Connection(geo_steam, 'out1', evap_steam, 'in1', label='30')
        c31 = Connection(evap_steam, 'out1',  geo_merge, 'in1', label='31')
        c32 = Connection(geo_brine, 'out1', geo_merge, 'in2', label='32')
        c33 = Connection(geo_merge, 'out1', evap_brine, 'in1', label='33')
        self.nw.add_conns(c30, c31, c32, c33)

        c34 = Connection(evap_brine, 'out1', pre, 'in1', label='34')
        c35 = Connection(pre, 'out1', geo_reinjection, 'in1', label='35')
        self.nw.add_conns(c34, c35)

        # generate a set of stable starting values of every working fluid
        # fluid settings
        c6.set_attr(fluid={self.working_fluid: 1.0, 'air': 0.0, 'water': 0.0})
        c20.set_attr(fluid={self.working_fluid: 0.0, 'air': 1.0, 'water': 0.0})
        c30.set_attr(fluid={self.working_fluid: 0.0, 'air': 0.0, 'water': 1.0})
        c32.set_attr(fluid={self.working_fluid: 0.0, 'air': 0.0, 'water': 1.0})

        # connection parameters
        p0 = PSI('P', 'T', self.T_brine_in + 273.15, 'Q', 1, self.working_fluid)
        c1.set_attr(p0=p0 / 1e5)
        ws_stable_h0 = (
            PSI('H', 'T', self.T_amb + 273.15, 'Q', 1, self.working_fluid) +
            0.5 * (
                PSI('H', 'T', self.T_brine_in + 273.15, 'Q', 1, self.working_fluid) -
                PSI('H', 'T', self.T_amb + 273.15, 'Q', 1, self.working_fluid)
            )
        ) / 1e3
        c2.set_attr(h=ws_stable_h0)
        p0 = PSI('P', 'T', self.T_amb + 273.15, 'Q', 1, self.working_fluid)
        c3.set_attr(Td_bp=5, design=['Td_bp'], p0=p0 / 1e5)
        c5.set_attr(h=Ref(c4, 1, 1))

        # steam generator
        c30.set_attr(
            m=self.geo_mass_flow * geo_steam_share,
            T=self.T_brine_in, x=1, p0=5)
        c32.set_attr(
            m=self.geo_mass_flow * (1 - geo_steam_share),
            T=self.T_brine_in, x=0)

        c13.set_attr()
        c12.set_attr(x=0.5)
        c10.set_attr(x=0.5, design=['x'])
        c34.set_attr(h=Ref(c33, 1, -50))

        c7.set_attr(Td_bp=-2)

        # main condenser
        c20.set_attr(p=self.p_amb, T=self.T_amb)
        c22.set_attr(T=self.T_amb + 15, p=self.p_amb)

        # component parameters
        # condensing
        ihe.set_attr(pr1=0.98, pr2=0.98)
        air_cond.set_attr(pr1=1, pr2=0.995, ttd_u=10)
        air_fan.set_attr(eta_s=0.6)

        # steam generator
        evap_brine.set_attr(pr1=0.98, ttd_l=8)
        pre.set_attr(pr1=0.98, pr2=0.98)

        self.nw.set_attr(iterinfo=False)
        self.nw.solve('design')
        self.nw.save('stable_' + self.working_fluid)

        # specify actual parameters
        tur.set_attr(eta_s=0.9)
        feed_working_fluid_pump.set_attr(eta_s=0.75)
        c2.set_attr(h=None)
        c5.set_attr(h=None)
        c34.set_attr(h=None, T=Ref(c33, 1, -10))

        self.nw.solve('design')
        c22.set_attr(T=None)
        c3.set_attr(Td_bp=None)

        self.ude_IHE_size = UserDefinedEquation(
            label='ihe deshuperheat ratio',
            func=desuperheat, deriv=desuperheat_deriv,
            latex={
                'equation':
                    r'0 = h_3 - h_2 - x_\mathrm{IHE} \cdot \left(h_3 -'
                    r'h\left(p_2, T_5 + \Delta T_\mathrm{t,u,min} \right)'
                    r'\right)'},
            conns=[
                self.nw.get_conn('2'),
                self.nw.get_conn('3'),
                self.nw.get_conn('5')],
            params={'distance': 0.0, 'ttd_min': 2}
        )
        if self.nw.lin_dep or self.nw.res[-1] > 1e-3:
            msg = 'No stable solution found.'
            raise TESPyNetworkError(msg)
        print(
            'Generated stable starting values for working fluid ' +
            self.working_fluid + '.')

    def run_simulation(
            self, p_before_tur=None, Q_ihe=None, Q_brine_ev=None,
            T_before_tur=None, T_reinjection=None, brine_evap_Td=None,
            dT_air=None, IHE_sizing=None, geo_steam_share=None):
        """Run simulation on specified parameter set."""

        self.nw.get_comp('internal heat exchanger').set_attr(Q=Q_ihe)
        self.nw.get_conn('1').set_attr(p=p_before_tur, T=T_before_tur)
        self.nw.get_conn('35').set_attr(T=T_reinjection)
        self.nw.get_comp('geobrine evaporator').set_attr(Q=Q_brine_ev)

        if geo_steam_share is not None:
            self.nw.get_conn('30').set_attr(
                m=self.geo_mass_flow * geo_steam_share)
            self.nw.get_conn('32').set_attr(
                m=self.geo_mass_flow * (1 - geo_steam_share))

        if brine_evap_Td is not None:
            self.nw.get_conn('34').set_attr(
                T=Ref(self.nw.get_conn('33'), 1, brine_evap_Td))
        else:
            self.nw.get_conn('34').set_attr(T=None)

        if dT_air is not None:
            self.nw.get_conn('22').set_attr(T=Ref(self.nw.get_conn('21'), 1, dT_air))
        else:
            self.nw.get_conn('22').set_attr(T=None)

        if IHE_sizing is None:
            if self.ude_IHE_size in self.nw.user_defined_eq.values():
                self.nw.del_ude(self.ude_IHE_size)
            self.nw.get_comp('internal heat exchanger').set_attr(pr1=0.98, pr2=0.98)
        else:
            if self.ude_IHE_size not in self.nw.user_defined_eq.values():
                self.nw.add_ude(self.ude_IHE_size)
            self.ude_IHE_size.params['distance'] = IHE_sizing
            if IHE_sizing == 0:
                self.nw.get_comp('internal heat exchanger').set_attr(pr1=1, pr2=1)
            else:
                self.nw.get_comp('internal heat exchanger').set_attr(pr1=0.98, pr2=0.98)

        try:
            self.nw.solve('design')
#            self.nw.print_results()
        except ValueError:
            self.nw.res = [1]
            pass

    def check_simulation(self, value):
        """Check if simulation converged."""
        if self.nw.lin_dep or self.nw.res[-1] > 1e-3:
            self.nw.solve(
                'design', init_path='stable_' + self.working_fluid,
                init_only=True)
            return np.nan
        else:
            for cp in self.nw.comps['object']:
                if isinstance(cp, HeatExchanger):
                    if cp.Q.val > 0:
                        print(cp.label)
                        return np.nan
                    elif cp.kA.val <= 0 or (np.isnan(cp.kA.val) and cp.Q.val != 0):
                        print(cp.label)
                        return np.nan
        return value

    def get_power(self):
        """Calculate ORC gross power (main cycle only)."""
        return self.check_simulation(self.nw.busses['cycle gross power output'].P.val)

    def get_net_power(self):
        """Calculate net power."""
        return self.check_simulation(self.nw.busses['net power output'].P.val)

    def get_thermal_efficiency(self):
        """Calculate thermal efficiency."""
        return self.check_simulation(
            -self.nw.busses['cycle gross power output'].P.val /
            self.nw.busses['thermal input'].P.val)

    def get_net_efficiency(self):
        """Calculate net efficiency."""
        return self.check_simulation(
            -self.nw.busses['net power output'].P.val /
            self.nw.busses['thermal input'].P.val)

    def get_geosteam_share(self):
        """Return a geosteam share."""
        return self.check_simulation(
            self.nw.get_conn('geosteam').m.val_SI / self.geo_mass_flow)

    def get_connection_param(self, conn, param):
        """Return a connection parameter."""
        return self.check_simulation(
            self.nw.get_conn(conn).get_attr(param).val)

    def get_component_param(self, comp, param):
        """Return a component parameter."""
        return self.check_simulation(
            self.nw.get_comp(comp).get_attr(param).val)

    def get_misc_param(self, param):
        """Get non component or connection parameters."""
        if param == 'gross power output':
            return self.get_power()
        elif param == 'net power output':
            return self.get_net_power()
        elif param == 'thermal efficiency':
            return self.get_thermal_efficiency()
        elif param == 'net efficiency':
            return self.get_net_efficiency()
        elif param == 'IHE sizing factor':
            return self.ude_IHE_size.params['distance']

    def get_objective_func(self, objective):
        """Return corresponding objective function."""
        if objective == 'net power output':
            return self.get_net_power
        elif objective == 'gross power output':
            return self.get_power
        else:
            msg = (
                'Please specify valid objective function: "net power output" '
                'or "gross power output".')
            raise ValueError(msg)
예제 #20
0
    'char': mot1
}, {
    'comp': pu,
    'char': mot2
}, {
    'comp': dhp,
    'char': mot3
}, {
    'comp': erp,
    'char': mot4
})

heat = Bus('total delivered heat')
heat.add_comps({'comp': cd})

nw.add_busses(power, heat)

# %% component parametrization

# condenser system

cd.set_attr(pr1=0.99,
            pr2=0.99,
            ttd_u=5,
            design=['pr2', 'ttd_u'],
            offdesign=['zeta2', 'kA'])
dhp.set_attr(eta_s=0.8, design=['eta_s'], offdesign=['eta_s_char'])
cons.set_attr(pr=0.99, design=['pr'], offdesign=['zeta'])

# low temp water system
예제 #21
0
    'comp': cp,
    'char': mot,
    'base': 'bus'
}, {
    'comp': pump_ev,
    'char': mot,
    'base': 'bus'
})
heat = Bus('heat system')
heat.add_comps({'comp': cd, 'char': -1})
heat_storage = Bus('heat storage')
heat_storage.add_comps({'comp': ev, 'char': -1}, {'comp': su, 'char': -1})

ti = Bus('ti')

nw.add_busses(power, heat, ti, heat_storage)

# %% characteristics

# %% component parametrization

# consumer system

cd.set_attr(pr1=0.99,
            pr2=0.99,
            ttd_u=5,
            subcooling=True,
            design=['pr2', 'ttd_u'],
            offdesign=['zeta2', 'kA_char'])

# evaporator system
예제 #22
0
nw.add_conns(cw_in, cw_out)

# %% busses

# characteristic function for generator efficiency
x = np.array([0, 0.2, 0.4, 0.6, 0.8, 1, 1.2])
y = np.array([0, 0.86, 0.9, 0.93, 0.95, 0.96, 0.95])

char = CharLine(x=x, y=y)

# motor of pump has a constant efficiency
power = Bus('total output power')
power.add_comps(
    {'comp': turb, 'char': char},
    {'comp': pu, 'char': char, 'base': 'bus'})
nw.add_busses(power)

# %% parametrization of components

turb.set_attr(eta_s=0.9, design=['eta_s'], offdesign=['eta_s_char', 'cone'])
con.set_attr(pr1=1, pr2=0.98, ttd_u=5, design=['pr2', 'ttd_u'],
             offdesign=['zeta2', 'kA_char'])
pu.set_attr(eta_s=0.8, design=['eta_s'], offdesign=['eta_s_char'])
steam_generator.set_attr(pr=0.95)

# %% parametrization of connections

# offdesign calculation: use parameter design for auto deactivation
# turbine inlet pressure is deriven by stodolas law, outlet pressure by
# characteristic of condenser
fs_in.set_attr(p=100, T=500, fluid={'water': 1}, design=['p'])
예제 #23
0
    'base': 'bus'
}, {
    'comp': hsp,
    'char': char,
    'base': 'bus'
})

# consumer heat bus
heat_cons = Bus('heating system')
heat_cons.add_comps({'comp': hs_ret, 'base': 'bus'}, {'comp': hs_feed})

# geothermal heat bus
heat_geo = Bus('geothermal heat')
heat_geo.add_comps({'comp': gh_in, 'base': 'bus'}, {'comp': gh_out})

nw.add_busses(power, heat_cons, heat_geo)

# %% key parameter

cd.set_attr(Q=-4e3)

# %% design calculation

path = 'R410A'
nw.solve('design')
# alternatively use:
# nw.solve('design', init_path=path)
print("\n##### DESIGN CALCULATION #####\n")
nw.print_results()
nw.save(path)
예제 #24
0
# %% busses
#
heat_losses = Bus('network losses')
heat_consumer = Bus('network consumer')
nw.check_network()

for comp in nw.comps.index:
    if isinstance(comp, Pipe):
        comp.set_attr(Tamb=0)

        heat_losses.add_comps({'comp': comp})

    if (isinstance(comp, HeatExchangerSimple) and not isinstance(comp, Pipe)):
        heat_consumer.add_comps({'comp': comp})

nw.add_busses(heat_losses, heat_consumer)

# %% solve

# design case: 0 °C ambient temperature
nw.solve('design')
nw.save('grid')
document_model(nw)
# no documentation of offedesign state added, as report creation takes
# quite long with all characteristics applied, try it out yourself :)

print('Heat demand consumer:', heat_consumer.P.val)
print('network losses at 0 °C outside temperature (design):',
      heat_losses.P.val)

# offdesign case: 10 °C ambient temperature
예제 #25
0
}, {
    'comp': turb,
    'char': char
}, {
    'comp': pu,
    'char': char,
    'base': 'bus'
})

heat_out = Bus('heat output')
heat_out.add_comps({'comp': cond}, {'comp': dh_whr})

heat_in = Bus('heat input')
heat_in.add_comps({'comp': c_c})

nw.add_busses(power, heat_out, heat_in)

# %% component parameters
# gas turbine
comp.set_attr(pr=14,
              eta_s=0.91,
              design=['pr', 'eta_s'],
              offdesign=['eta_s_char'])
g_turb.set_attr(eta_s=0.88, design=['eta_s'], offdesign=['eta_s_char', 'cone'])

# steam turbine
suph.set_attr(pr1=0.99,
              pr2=0.834,
              design=['pr1', 'pr2'],
              offdesign=['zeta1', 'zeta2', 'kA_char'])
eco.set_attr(pr1=0.99,
예제 #26
0
파일: ice_020.py 프로젝트: maltefritz/SWSH
    'comp': ice,
    'param': 'P',
    'char': gen1
})

ice_power = Bus('ice_power')
ice_power.add_comps({'comp': ice, 'param': 'P', 'char': gen2})

heat = Bus('heat')
heat.add_comps({'comp': ice, 'param': 'Q'}, {'comp': fgc})

heat_cond = Bus('heat_cond')

ti = Bus('ti')
ti.add_comps({'comp': ice, 'param': 'TI'})
nw.add_busses(power, heat, ti, ice_power, heat_cond)

# %% component parameters

# pump isentropic efficiency char_line
x = np.array([
    0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4,
    1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5
])
y = np.array([
    0.7, 0.7667, 0.8229, 0.8698, 0.9081, 0.9387, 0.9623, 0.9796, 0.9913,
    0.9979, 1.0, 0.9981, 0.9926, 0.9839, 0.9725, 0.9586, 0.9426, 0.9248,
    0.9055, 0.8848, 0.8631, 0.8405, 0.8171, 0.7932, 0.7689, 0.7444
])
eta_s_char = dict(char_func=CharLine(x, y), param='m')
pump.set_attr(eta_s=0.8,