コード例 #1
0
def build_valve_liquid():
    m = ConcreteModel()
    m.fs = FlowsheetBlock(default={"dynamic": False})
    m.fs.properties = iapws95_ph.Iapws95ParameterBlock()
    m.fs.valve = SteamValve(default={"property_package": m.fs.properties,
                                     "phase": "Liq"})
    return m
コード例 #2
0
def build_valve_vapor():
    m = ConcreteModel()
    m.fs = FlowsheetBlock(default={"dynamic": False})
    m.fs.properties = iapws95.Iapws95ParameterBlock()
    m.fs.valve = SteamValve(default={"property_package": m.fs.properties})
    return m
コード例 #3
0
    def build(self):
        super(TurbineMultistageData, self).build()
        config = self.config
        unit_cfg = { # general unit model config
            "dynamic":config.dynamic,
            "has_holdup":config.has_holdup,
            "has_phase_equilibrium":config.has_phase_equilibrium,
            "property_package":config.property_package,
            "property_package_args":config.property_package_args,
        }
        ni = self.config.num_parallel_inlet_stages
        inlet_idx = self.inlet_stage_idx = RangeSet(ni)

        # Adding unit models
        #------------------------

        # Splitter to inlet that splits main flow into parallel flows for
        # paritial arc admission to the turbine
        self.inlet_split = Separator(default=self._split_cfg(unit_cfg, ni))
        self.throttle_valve = SteamValve(inlet_idx, default=unit_cfg)
        self.inlet_stage = TurbineInletStage(inlet_idx, default=unit_cfg)
        # mixer to combine the parallel flows back together
        self.inlet_mix = Mixer(default=self._mix_cfg(unit_cfg, ni))
        # add turbine sections.
        # inlet stage -> hp stages -> ip stages -> lp stages -> outlet stage
        self.hp_stages = TurbineStage(RangeSet(config.num_hp),
                                      default=unit_cfg)
        self.ip_stages = TurbineStage(RangeSet(config.num_ip),
                                      default=unit_cfg)
        self.lp_stages = TurbineStage(RangeSet(config.num_lp),
                                      default=unit_cfg)
        self.outlet_stage = TurbineOutletStage(default=unit_cfg)

        for i in self.hp_stages:
            self.hp_stages[i].ratioP.fix()
            self.hp_stages[i].efficiency_isentropic[:].fix()
        for i in self.ip_stages:
            self.ip_stages[i].ratioP.fix()
            self.ip_stages[i].efficiency_isentropic[:].fix()
        for i in self.lp_stages:
            self.lp_stages[i].ratioP.fix()
            self.lp_stages[i].efficiency_isentropic[:].fix()

        # Then make splitter config.  If number of outlets is specified
        # make a specific config, otherwise use default with 2 outlets
        s_sfg_default = self._split_cfg(unit_cfg, 2)
        hp_splt_cfg = {}
        ip_splt_cfg = {}
        lp_splt_cfg = {}
        # Now to finish up if there are more than two outlets, set that
        for i, v in config.hp_split_num_outlets.items():
            hp_splt_cfg[i] = self._split_cfg(unit_cfg, v)
        for i, v in config.ip_split_num_outlets.items():
            ip_splt_cfg[i] = self._split_cfg(unit_cfg, v)
        for i, v in config.lp_split_num_outlets.items():
            lp_splt_cfg[i] = self._split_cfg(unit_cfg, v)
        # put in splitters for turbine steam extractions
        if config.hp_split_locations:
            self.hp_split = Separator(config.hp_split_locations,
                                      default=s_sfg_default,
                                      initialize=hp_splt_cfg)
        if config.ip_split_locations:
            self.ip_split = Separator(config.ip_split_locations,
                                      default=s_sfg_default,
                                      initialize=ip_splt_cfg)
        if config.lp_split_locations:
            self.lp_split = Separator(config.lp_split_locations,
                                      default=s_sfg_default,
                                      initialize=lp_splt_cfg)

        # Done with unit models.  Adding Arcs (streams).
        #------------------------------------------------

        # First up add streams in the inlet section
        def _split_to_rule(b, i):
            return {
                "source": getattr(self.inlet_split, "outlet_{}".format(i)),
                "destination": self.throttle_valve[i].inlet
            }

        def _valve_to_rule(b, i):
            return {
                "source": self.throttle_valve[i].outlet,
                "destination": self.inlet_stage[i].inlet
            }

        def _inlet_to_rule(b, i):
            return {
                "source": self.inlet_stage[i].outlet,
                "destination": getattr(self.inlet_mix, "inlet_{}".format(i))
            }

        self.split_to_valve_stream = Arc(inlet_idx, rule=_split_to_rule)
        self.valve_to_inlet_stage_stream = Arc(inlet_idx, rule=_valve_to_rule)
        self.inlet_stage_to_mix = Arc(inlet_idx, rule=_inlet_to_rule)

        # There are three sections HP, IP, and LP which all have the same sort
        # of internal connctions, so the functions below provide some generic
        # capcbilities for adding the internal Arcs (streams).
        def _arc_indexes(nstages, index_set, discon, splits):
            """
            This takes the index set of all possible streams in a turbine
            section and throws out arc indexes for stages that are disconnected
            and arc indexes that are not needed because there is no splitter
            after a stage.

            Args:
                nstages (int): Number of stages in section
                index_set (Set): Index set for arcs in the section
                discon (list): Disconnected stages in the section
                splits (list): Spliter locations
            """
            sr = set()  # set of things to remove from the Arc index set
            for i in index_set:
                if (i[0] in discon or i[0] == nstages) and i[0] in splits:
                    # don't connect stage i to next remove stream after split
                    sr.add((i[0], 2))
                elif (i[0] in discon
                      or i[0] == nstages) and i[0] not in splits:
                    # no splitter and disconnect so remove both streams
                    sr.add((i[0], 1))
                    sr.add((i[0], 2))
                elif i[0] not in splits:
                    # no splitter and not disconnected so just second stream
                    sr.add((i[0], 2))
                else:
                    # has splitter so need both streams don't remove anything
                    pass
            for i in sr:  # remove the unneeded Arc indexes
                index_set.remove(i)

        def _arc_rule(turbines, splitters):
            """
            This creates a rule function for arcs in a turbine section. When
            this is used the indexes for nonexistant stream will have already
            been removed, so any indexes the rule will get should have a stream
            associated.

            Args:
                turbines (TurbineStage): Indexed block with turbine section stages
                splitters (Separator): Indexed block of splitters
            """
            def _rule(b, i, j):
                if i in splitters and j == 1:
                    return {
                        "source": turbines[i].outlet,
                        "destination": splitters[i].inlet
                    }
                elif j == 2:
                    return {
                        "source": splitters[i].outlet_1,
                        "destination": turbines[i + 1].inlet
                    }
                else:
                    return {
                        "source": turbines[i].outlet,
                        "destination": turbines[i + 1].inlet
                    }

            return _rule

        # Create initial arcs index sets with all possible streams
        self.hp_stream_idx = Set(initialize=self.hp_stages.index_set() *
                                 [1, 2])
        self.ip_stream_idx = Set(initialize=self.ip_stages.index_set() *
                                 [1, 2])
        self.lp_stream_idx = Set(initialize=self.lp_stages.index_set() *
                                 [1, 2])

        # Throw out unneeded streams
        _arc_indexes(config.num_hp, self.hp_stream_idx, config.hp_disconnect,
                     config.hp_split_locations)
        _arc_indexes(config.num_ip, self.ip_stream_idx, config.ip_disconnect,
                     config.ip_split_locations)
        _arc_indexes(config.num_lp, self.lp_stream_idx, config.lp_disconnect,
                     config.lp_split_locations)

        # Create connections internal to each turbine section (hp, ip, and lp)
        self.hp_stream = Arc(self.hp_stream_idx,
                             rule=_arc_rule(self.hp_stages, self.hp_split))
        self.ip_stream = Arc(self.ip_stream_idx,
                             rule=_arc_rule(self.ip_stages, self.ip_split))
        self.lp_stream = Arc(self.lp_stream_idx,
                             rule=_arc_rule(self.lp_stages, self.lp_split))

        # Connect hp section to ip section unless its a disconnect location
        last_hp = config.num_hp
        if 0 not in config.ip_disconnect and last_hp not in config.hp_disconnect:
            if last_hp in config.hp_split_locations:  # connect splitter to ip
                self.hp_to_ip_stream = Arc(
                    source=self.hp_split[last_hp].outlet_1,
                    destination=self.ip_stages[1].inlet)
            else:  # connect last hp to ip
                self.hp_to_ip_stream = Arc(
                    source=self.hp_stages[last_hp].outlet,
                    destination=self.ip_stages[1].inlet)
        # Connect ip section to lp section unless its a disconnect location
        last_ip = config.num_ip
        if 0 not in config.lp_disconnect and last_ip not in config.ip_disconnect:
            if last_ip in config.ip_split_locations:  # connect splitter to ip
                self.ip_to_lp_stream = Arc(
                    source=self.ip_split[last_ip].outlet_1,
                    destination=self.lp_stages[1].inlet)
            else:  # connect last hp to ip
                self.ip_to_lp_stream = Arc(
                    source=self.ip_stages[last_ip].outlet,
                    destination=self.lp_stages[1].inlet)
        # Connect inlet stage to hp section
        #   not allowing disconnection of inlet and first regular hp stage
        if 0 in config.hp_split_locations:
            # connect inlet mix to splitter and splitter to hp section
            self.inlet_to_splitter_stream = Arc(
                source=self.inlet_mix.outlet,
                destination=self.hp_split[0].inlet)
            self.splitter_to_hp_stream = Arc(
                source=self.hp_split[0].outlet_1,
                destination=self.hp_stages[1].inlet)
        else:  # connect mixer to first hp turbine stage
            self.inlet_to_hp_stream = Arc(source=self.inlet_mix.outlet,
                                          destination=self.hp_stages[1].inlet)

        @self.Expression(self.flowsheet().config.time)
        def power(b, t):
            return (sum(b.inlet_stage[i].power_shaft[t]
                        for i in b.inlet_stage) +
                    b.outlet_stage.power_shaft[t] +
                    sum(b.hp_stages[i].power_shaft[t] for i in b.hp_stages) +
                    sum(b.ip_stages[i].power_shaft[t] for i in b.ip_stages) +
                    sum(b.lp_stages[i].power_shaft[t] for i in b.lp_stages))

        # Connect inlet stage to hp section
        #   not allowing disconnection of inlet and first regular hp stage
        last_lp = config.num_lp
        if last_lp in config.lp_split_locations:  # connect splitter to outlet
            self.lp_to_outlet_stream = Arc(
                source=self.lp_split[last_lp].outlet_1,
                destination=self.outlet_stage.inlet)
        else:  # connect last lpstage to outlet
            self.lp_to_outlet_stream = Arc(
                source=self.lp_stages[last_lp].outlet,
                destination=self.outlet_stage.inlet)
        TransformationFactory("network.expand_arcs").apply_to(self)
コード例 #4
0
def create_model(steady_state=True, time_set=[0, 3], nfe=5, calc_integ=True):
    """ Create a test model and solver

    Args:
        steady_state (bool): If True, create a steady state model, otherwise
            create a dynamic model
        time_set (list): The begining and end point of the time domain
        nfe (int): Number of finite elements argument for the DAE transformation
        calc_integ (bool): If Ture, calculate in the initial condition for
            the integral term, else use a fixed variable (fs.ctrl.err_i0), flase
            is the better option if you have a value from a previous time period

    Returns
        (tuple): (ConcreteModel, Solver)
    """
    if steady_state:
        fs_cfg = {"dynamic": False}
        model_name = "Steam Tank, Steady State"
    else:
        fs_cfg = {"dynamic": True, "time_set": time_set}
        model_name = "Steam Tank, Dynamic"
    m = pyo.ConcreteModel(name=model_name)
    m.fs = FlowsheetBlock(default=fs_cfg)
    # Create a property parameter block
    m.fs.prop_water = iapws95.Iapws95ParameterBlock(
        default={"phase_presentation": iapws95.PhaseType.LG})
    # Create the valve and tank models
    m.fs.valve_1 = SteamValve(
        default={
            "dynamic": False,
            "has_holdup": False,
            "material_balance_type": MaterialBalanceType.componentTotal,
            "property_package": m.fs.prop_water
        })
    m.fs.tank = Heater(
        default={
            "has_holdup": True,
            "material_balance_type": MaterialBalanceType.componentTotal,
            "property_package": m.fs.prop_water
        })
    m.fs.valve_2 = SteamValve(
        default={
            "dynamic": False,
            "has_holdup": False,
            "material_balance_type": MaterialBalanceType.componentTotal,
            "property_package": m.fs.prop_water
        })
    # Connect the models
    m.fs.v1_to_t = Arc(source=m.fs.valve_1.outlet, destination=m.fs.tank.inlet)
    m.fs.t_to_v2 = Arc(source=m.fs.tank.outlet, destination=m.fs.valve_2.inlet)
    # The control volume block doesn't assume the two phases are in equilibrium
    # by default, so I'll make that assumption here, I don't actually expect
    # liquid to form but who knows. The phase_fraction in the control volume is
    # volumetric phase fraction hense the densities.
    @m.fs.tank.Constraint(m.fs.time)
    def vol_frac_vap(b, t):
        return b.control_volume.properties_out[t].phase_frac["Vap"]\
            *b.control_volume.properties_out[t].dens_mol\
            /b.control_volume.properties_out[t].dens_mol_phase["Vap"]\
            == b.control_volume.phase_fraction[t, "Vap"]

    # Add the stream constraints and do the DAE transformation
    pyo.TransformationFactory('network.expand_arcs').apply_to(m.fs)
    if not steady_state:
        pyo.TransformationFactory('dae.finite_difference').apply_to(
            m.fs, nfe=nfe, wrt=m.fs.time, scheme='BACKWARD')
    # Fix the derivative variables to zero at time 0 (steady state assumption)
    m.fs.fix_initial_conditions()
    # A tank pressure reference that's directly time-indexed
    m.fs.tank_pressure = pyo.Reference(
        m.fs.tank.control_volume.properties_out[:].pressure)
    # Add a controller
    m.fs.ctrl = PIDBlock(
        default={
            "pv": m.fs.tank_pressure,
            "output": m.fs.valve_1.valve_opening,
            "upper": 1.0,
            "lower": 0.0,
            "calculate_initial_integral": calc_integ
        })
    m.fs.ctrl.deactivate()  # Don't want controller turned on by default
    # Fix the input variables
    m.fs.valve_1.inlet.enth_mol.fix(50000)
    m.fs.valve_1.inlet.pressure.fix(5e5)
    m.fs.valve_2.outlet.pressure.fix(101325)
    m.fs.valve_1.Cv.fix(0.001)
    m.fs.valve_2.Cv.fix(0.001)
    m.fs.valve_1.valve_opening.fix(1)
    m.fs.valve_2.valve_opening.fix(1)
    m.fs.tank.heat_duty.fix(0)
    m.fs.tank.control_volume.volume.fix(2.0)
    m.fs.ctrl.gain.fix(1e-6)
    m.fs.ctrl.time_i.fix(0.1)
    m.fs.ctrl.time_d.fix(0.1)
    m.fs.ctrl.setpoint.fix(3e5)
    # Initialize the model
    solver = pyo.SolverFactory("ipopt")
    solver.options = {'tol': 1e-6, 'linear_solver': "mumps", 'max_iter': 100}
    for t in m.fs.time:
        m.fs.valve_1.inlet.flow_mol = 100  # initial guess on flow
    # simple initialize
    m.fs.valve_1.initialize(outlvl=1)
    _set_port(m.fs.tank.inlet, m.fs.valve_1.outlet)
    m.fs.tank.initialize(outlvl=1)
    _set_port(m.fs.valve_2.inlet, m.fs.tank.outlet)
    m.fs.valve_2.initialize(outlvl=1)
    solver.solve(m, tee=True)
    # Return the model and solver
    return m, solver