コード例 #1
0
    def build(self):
        """
        Building model

        Args:
            None
        Returns:
            None
        """
        ########################################################################
        #  Call UnitModel.build to setup dynamics and configure                #
        ########################################################################
        super().build()
        self._process_config()
        config = self.config

        ########################################################################
        # Add control volumes                                                  #
        ########################################################################
        hot_side = _make_heater_control_volume(
            self,
            config.hot_side_name,
            config.hot_side_config,
            dynamic=config.dynamic,
            has_holdup=config.has_holdup,
        )
        cold_side = _make_heater_control_volume(
            self,
            config.cold_side_name,
            config.cold_side_config,
            dynamic=config.dynamic,
            has_holdup=config.has_holdup,
        )
        # Add references to the hot side and cold side, so that we have solid
        # names to refer to internally.  side_1 and side_2 also maintain
        # compatability with older models.  Using add_object_reference keeps
        # these from showing up when you iterate through pyomo compoents in a
        # model, so only the user specified control volume names are "seen"
        if not hasattr(self, "side_1"):
            add_object_reference(self, "side_1", hot_side)
        if not hasattr(self, "side_2"):
            add_object_reference(self, "side_2", cold_side)
        if not hasattr(self, "hot_side"):
            add_object_reference(self, "hot_side", hot_side)
        if not hasattr(self, "cold_side"):
            add_object_reference(self, "cold_side", cold_side)

        ########################################################################
        # Add variables                                                        #
        ########################################################################
        # Use hot side units as basis
        s1_metadata = config.hot_side_config.property_package.get_metadata()

        q_units = s1_metadata.get_derived_units("power")
        u_units = s1_metadata.get_derived_units("heat_transfer_coefficient")
        a_units = s1_metadata.get_derived_units("area")
        temp_units = s1_metadata.get_derived_units("temperature")

        u = self.overall_heat_transfer_coefficient = Var(
            self.flowsheet().config.time,
            domain=PositiveReals,
            initialize=100.0,
            doc="Overall heat transfer coefficient",
            units=u_units)
        a = self.area = Var(domain=PositiveReals,
                            initialize=1000.0,
                            doc="Heat exchange area",
                            units=a_units)
        self.delta_temperature_in = Var(
            self.flowsheet().config.time,
            initialize=10.0,
            doc="Temperature difference at the hot inlet end",
            units=temp_units)
        self.delta_temperature_out = Var(
            self.flowsheet().config.time,
            initialize=10.1,
            doc="Temperature difference at the hot outlet end",
            units=temp_units)
        if self.config.flow_pattern == HeatExchangerFlowPattern.crossflow:
            self.crossflow_factor = Var(
                self.flowsheet().config.time,
                initialize=1.0,
                doc="Factor to adjust coutercurrent flow heat "
                "transfer calculation for cross flow.",
            )
            f = self.crossflow_factor

        self.heat_duty = Reference(cold_side.heat)
        ########################################################################
        # Add ports                                                            #
        ########################################################################
        i1 = self.add_inlet_port(name=f"{config.hot_side_name}_inlet",
                                 block=hot_side,
                                 doc="Hot side inlet")
        i2 = self.add_inlet_port(name=f"{config.cold_side_name}_inlet",
                                 block=cold_side,
                                 doc="Cold side inlet")
        o1 = self.add_outlet_port(name=f"{config.hot_side_name}_outlet",
                                  block=hot_side,
                                  doc="Hot side outlet")
        o2 = self.add_outlet_port(name=f"{config.cold_side_name}_outlet",
                                  block=cold_side,
                                  doc="Cold side outlet")

        # Using Andrew's function for now.  I want these port names for backward
        # compatablity, but I don't want them to appear if you iterate throught
        # components and add_object_reference hides them from Pyomo.
        if not hasattr(self, "inlet_1"):
            add_object_reference(self, "inlet_1", i1)
        if not hasattr(self, "inlet_2"):
            add_object_reference(self, "inlet_2", i2)
        if not hasattr(self, "outlet_1"):
            add_object_reference(self, "outlet_1", o1)
        if not hasattr(self, "outlet_2"):
            add_object_reference(self, "outlet_2", o2)

        if not hasattr(self, "hot_inlet"):
            add_object_reference(self, "hot_inlet", i1)
        if not hasattr(self, "cold_inlet"):
            add_object_reference(self, "cold_inlet", i2)
        if not hasattr(self, "hot_outlet"):
            add_object_reference(self, "hot_outlet", o1)
        if not hasattr(self, "cold_outlet"):
            add_object_reference(self, "cold_outlet", o2)
        ########################################################################
        # Add end temperature differnece constraints                           #
        ########################################################################

        @self.Constraint(self.flowsheet().config.time)
        def delta_temperature_in_equation(b, t):
            if b.config.flow_pattern == HeatExchangerFlowPattern.cocurrent:
                return (b.delta_temperature_in[t] ==
                        hot_side.properties_in[t].temperature -
                        pyunits.convert(cold_side.properties_in[t].temperature,
                                        to_units=temp_units))
            else:
                return (
                    b.delta_temperature_in[t] ==
                    hot_side.properties_in[t].temperature -
                    pyunits.convert(cold_side.properties_out[t].temperature,
                                    to_units=temp_units))

        @self.Constraint(self.flowsheet().config.time)
        def delta_temperature_out_equation(b, t):
            if b.config.flow_pattern == HeatExchangerFlowPattern.cocurrent:
                return (
                    b.delta_temperature_out[t] ==
                    hot_side.properties_out[t].temperature -
                    pyunits.convert(cold_side.properties_out[t].temperature,
                                    to_units=temp_units))
            else:
                return (b.delta_temperature_out[t] ==
                        hot_side.properties_out[t].temperature -
                        pyunits.convert(cold_side.properties_in[t].temperature,
                                        to_units=temp_units))

        ########################################################################
        # Add a unit level energy balance                                      #
        ########################################################################
        @self.Constraint(self.flowsheet().config.time)
        def unit_heat_balance(b, t):
            return 0 == (hot_side.heat[t] +
                         pyunits.convert(cold_side.heat[t], to_units=q_units))

        ########################################################################
        # Add delta T calculations using callack function, lots of options,    #
        #   and users can provide their own if needed                          #
        ########################################################################
        config.delta_temperature_callback(self)
        ########################################################################
        # Add Heat transfer equation                                           #
        ########################################################################
        deltaT = self.delta_temperature

        @self.Constraint(self.flowsheet().config.time)
        def heat_transfer_equation(b, t):
            if self.config.flow_pattern == HeatExchangerFlowPattern.crossflow:
                return pyunits.convert(self.heat_duty[t],
                                       to_units=q_units) == (f[t] * u[t] * a *
                                                             deltaT[t])
            else:
                return pyunits.convert(self.heat_duty[t],
                                       to_units=q_units) == (u[t] * a *
                                                             deltaT[t])

        ########################################################################
        # Add symbols for LaTeX equation rendering                             #
        ########################################################################
        self.overall_heat_transfer_coefficient.latex_symbol = "U"
        self.area.latex_symbol = "A"
        hot_side.heat.latex_symbol = "Q_1"
        cold_side.heat.latex_symbol = "Q_2"
        self.delta_temperature.latex_symbol = "\\Delta T"
コード例 #2
0
    def build(self):
        """
        Building model

        Args:
            None
        Returns:
            None
        """
        ########################################################################
        #  Call UnitModel.build to setup dynamics and configure                #
        ########################################################################
        super().build()
        self._process_config()
        config = self.config
        time = self.flowsheet().config.time

        ########################################################################
        # Add control volumes                                                  #
        ########################################################################
        hot_side = _make_heater_control_volume(
            self,
            config.hot_side_name,
            config.hot_side_config,
            dynamic=config.dynamic,
            has_holdup=config.has_holdup,
        )
        cold_side = _make_heater_control_volume(
            self,
            config.cold_side_name,
            config.cold_side_config,
            dynamic=config.dynamic,
            has_holdup=config.has_holdup,
        )
        # Add refernces to the hot side and cold side, so that we have solid
        # names to refere to internally.  side_1 and side_2 also maintain
        # compatability with older models.  Using add_object_reference keeps
        # these from showing up when you iterate through pyomo compoents in a
        # model, so only the user specified control volume names are "seen"
        if not hasattr(self, "side_1"):
            add_object_reference(self, "side_1", hot_side)
        if not hasattr(self, "side_2"):
            add_object_reference(self, "side_2", cold_side)
        if not hasattr(self, "hot_side"):
            add_object_reference(self, "hot_side", hot_side)
        if not hasattr(self, "cold_side"):
            add_object_reference(self, "cold_side", cold_side)

        ########################################################################
        # Add variables                                                        #
        ########################################################################
        # Use hot side units as basis
        s1_metadata = config.hot_side_config.property_package.get_metadata()

        f_units = s1_metadata.get_derived_units("flow_mole")
        cp_units = s1_metadata.get_derived_units("heat_capacity_mole")
        q_units = s1_metadata.get_derived_units("power")
        u_units = s1_metadata.get_derived_units("heat_transfer_coefficient")
        a_units = s1_metadata.get_derived_units("area")
        temp_units = s1_metadata.get_derived_units("temperature")

        self.overall_heat_transfer_coefficient = pyo.Var(
            time,
            domain=pyo.PositiveReals,
            initialize=100.0,
            doc="Overall heat transfer coefficient",
            units=u_units,
        )
        self.area = pyo.Var(
            domain=pyo.PositiveReals,
            initialize=1000.0,
            doc="Heat exchange area",
            units=a_units,
        )
        self.heat_duty = pyo.Reference(cold_side.heat)
        ########################################################################
        # Add ports                                                            #
        ########################################################################
        i1 = self.add_inlet_port(name=f"{config.hot_side_name}_inlet",
                                 block=hot_side,
                                 doc="Hot side inlet")
        i2 = self.add_inlet_port(name=f"{config.cold_side_name}_inlet",
                                 block=cold_side,
                                 doc="Cold side inlet")
        o1 = self.add_outlet_port(name=f"{config.hot_side_name}_outlet",
                                  block=hot_side,
                                  doc="Hot side outlet")
        o2 = self.add_outlet_port(name=f"{config.cold_side_name}_outlet",
                                  block=cold_side,
                                  doc="Cold side outlet")

        # Using Andrew's function for now.  I want these port names for backward
        # compatablity, but I don't want them to appear if you iterate throught
        # components and add_object_reference hides them from Pyomo.
        if not hasattr(self, "inlet_1"):
            add_object_reference(self, "inlet_1", i1)
        if not hasattr(self, "inlet_2"):
            add_object_reference(self, "inlet_2", i2)
        if not hasattr(self, "outlet_1"):
            add_object_reference(self, "outlet_1", o1)
        if not hasattr(self, "outlet_2"):
            add_object_reference(self, "outlet_2", o2)

        if not hasattr(self, "hot_inlet"):
            add_object_reference(self, "hot_inlet", i1)
        if not hasattr(self, "cold_inlet"):
            add_object_reference(self, "cold_inlet", i2)
        if not hasattr(self, "hot_outlet"):
            add_object_reference(self, "hot_outlet", o1)
        if not hasattr(self, "cold_outlet"):
            add_object_reference(self, "cold_outlet", o2)

        ########################################################################
        # Add a unit level energy balance                                      #
        ########################################################################
        @self.Constraint(time, doc="Heat balance equation")
        def unit_heat_balance(b, t):
            return 0 == (hot_side.heat[t] +
                         pyunits.convert(cold_side.heat[t], to_units=q_units))

        ########################################################################
        # Add some useful expressions for condenser performance                #
        ########################################################################

        @self.Expression(time, doc="Inlet temperature difference")
        def delta_temperature_in(b, t):
            return (hot_side.properties_in[t].temperature - pyunits.convert(
                cold_side.properties_in[t].temperature, temp_units))

        @self.Expression(time, doc="Outlet temperature difference")
        def delta_temperature_out(b, t):
            return (hot_side.properties_out[t].temperature - pyunits.convert(
                cold_side.properties_out[t].temperature, temp_units))

        @self.Expression(time, doc="NTU Based temperature difference")
        def delta_temperature_ntu(b, t):
            return (hot_side.properties_in[t].temperature_sat -
                    pyunits.convert(cold_side.properties_in[t].temperature,
                                    temp_units))

        @self.Expression(
            time,
            doc="Minimum product of flow rate and heat "
            "capacity (always on tube side since shell side has phase change)")
        def mcp_min(b, t):
            return pyunits.convert(
                cold_side.properties_in[t].flow_mol *
                cold_side.properties_in[t].cp_mol_phase['Liq'],
                f_units * cp_units)

        @self.Expression(time, doc="Number of transfer units (NTU)")
        def ntu(b, t):
            return b.overall_heat_transfer_coefficient[t] * b.area / b.mcp_min[
                t]

        @self.Expression(time, doc="Condenser effectiveness factor")
        def effectiveness(b, t):
            return 1 - pyo.exp(-self.ntu[t])

        @self.Expression(time, doc="Heat treansfer")
        def heat_transfer(b, t):
            return b.effectiveness[t] * b.mcp_min[t] * b.delta_temperature_ntu[
                t]

        ########################################################################
        # Add Equations to calculate heat duty based on NTU method             #
        ########################################################################
        @self.Constraint(time,
                         doc="Heat transfer rate equation based on NTU method")
        def heat_transfer_equation(b, t):
            return (pyunits.convert(cold_side.heat[t],
                                    q_units) == self.heat_transfer[t])

        @self.Constraint(
            time, doc="Shell side outlet enthalpy is saturated water enthalpy")
        def saturation_eqn(b, t):
            return (hot_side.properties_out[t].enth_mol ==
                    hot_side.properties_in[t].enth_mol_sat_phase["Liq"])
コード例 #3
0
ファイル: heat_exchanger.py プロジェクト: jghouse88/idaes-pse
    def build(self):
        """
        Building model

        Args:
            None
        Returns:
            None
        """
        ########################################################################
        #  Call UnitModel.build to setup dynamics and configure                #
        ########################################################################
        super().build()
        self._process_config()
        config = self.config

        ########################################################################
        # Add variables                                                        #
        ########################################################################
        # Use side 1 units as basis
        s1_metadata = config.hot_side_config.property_package.get_metadata()

        q_units = s1_metadata.get_derived_units("power")
        u_units = s1_metadata.get_derived_units("heat_transfer_coefficient")
        a_units = s1_metadata.get_derived_units("area")
        t_units = s1_metadata.get_derived_units("temperature")

        u = self.overall_heat_transfer_coefficient = Var(
            self.flowsheet().config.time,
            domain=PositiveReals,
            initialize=100.0,
            doc="Overall heat transfer coefficient",
            units=u_units)
        a = self.area = Var(domain=PositiveReals,
                            initialize=1000.0,
                            doc="Heat exchange area",
                            units=a_units)
        self.delta_temperature_in = Var(
            self.flowsheet().config.time,
            initialize=10.0,
            doc="Temperature difference at the hot inlet end",
            units=t_units)
        self.delta_temperature_out = Var(
            self.flowsheet().config.time,
            initialize=10.1,
            doc="Temperature difference at the hot outlet end",
            units=t_units)
        if self.config.flow_pattern == HeatExchangerFlowPattern.crossflow:
            self.crossflow_factor = Var(
                self.flowsheet().config.time,
                initialize=1.0,
                doc="Factor to adjust coutercurrent flow heat "
                "transfer calculation for cross flow.",
            )
            f = self.crossflow_factor
        ########################################################################
        # Add control volumes                                                  #
        ########################################################################
        _make_heater_control_volume(
            self,
            "side_1",
            config.hot_side_config,
            dynamic=config.dynamic,
            has_holdup=config.has_holdup,
        )
        _make_heater_control_volume(
            self,
            "side_2",
            config.cold_side_config,
            dynamic=config.dynamic,
            has_holdup=config.has_holdup,
        )
        # Add named references to side_1 and side_2, side 1 and 2 maintain
        # backward compatability and are names the user doesn't need to worry
        # about. The sign convention for duty is heat from side 1 to side 2 is
        # positive
        add_object_reference(self, config.hot_side_name, self.side_1)
        add_object_reference(self, config.cold_side_name, self.side_2)

        # Add convienient references to heat duty.
        self.heat_duty = Reference(self.side_2.heat)
        # Need to do this as Reference does not have units (Pyomo fixing this)
        q = self.side_2.heat
        ########################################################################
        # Add ports                                                            #
        ########################################################################
        # Keep old port names, just for backward compatability
        self.add_inlet_port(name="inlet_1",
                            block=self.side_1,
                            doc="Hot side inlet")
        self.add_inlet_port(name="inlet_2",
                            block=self.side_2,
                            doc="Cold side inlet")
        self.add_outlet_port(name="outlet_1",
                             block=self.side_1,
                             doc="Hot side outlet")
        self.add_outlet_port(name="outlet_2",
                             block=self.side_2,
                             doc="Cold side outlet")

        # Using Andrew's function for now, I think Pyomo's refrence has trouble
        # with scalar (pyomo) components.
        add_object_reference(self, config.hot_side_name + "_inlet",
                             self.inlet_1)
        add_object_reference(self, config.cold_side_name + "_inlet",
                             self.inlet_2)
        add_object_reference(self, config.hot_side_name + "_outlet",
                             self.outlet_1)
        add_object_reference(self, config.cold_side_name + "_outlet",
                             self.outlet_2)
        ########################################################################
        # Add end temperature differnece constraints                            #
        ########################################################################
        @self.Constraint(self.flowsheet().config.time)
        def delta_temperature_in_equation(b, t):
            if b.config.flow_pattern == HeatExchangerFlowPattern.cocurrent:
                return (b.delta_temperature_in[t] ==
                        b.side_1.properties_in[t].temperature -
                        pyunits.convert(b.side_2.properties_in[t].temperature,
                                        to_units=t_units))
            else:
                return (b.delta_temperature_in[t] ==
                        b.side_1.properties_in[t].temperature -
                        pyunits.convert(b.side_2.properties_out[t].temperature,
                                        to_units=t_units))

        @self.Constraint(self.flowsheet().config.time)
        def delta_temperature_out_equation(b, t):
            if b.config.flow_pattern == HeatExchangerFlowPattern.cocurrent:
                return (b.delta_temperature_out[t] ==
                        b.side_1.properties_out[t].temperature -
                        pyunits.convert(b.side_2.properties_out[t].temperature,
                                        to_units=t_units))
            else:
                return (b.delta_temperature_out[t] ==
                        b.side_1.properties_out[t].temperature -
                        pyunits.convert(b.side_2.properties_in[t].temperature,
                                        to_units=t_units))

        ########################################################################
        # Add a unit level energy balance                                      #
        ########################################################################
        @self.Constraint(self.flowsheet().config.time)
        def unit_heat_balance(b, t):
            return 0 == (
                self.side_1.heat[t] +
                pyunits.convert(self.side_2.heat[t], to_units=q_units))

        ########################################################################
        # Add delta T calculations using callack function, lots of options,    #
        #   and users can provide their own if needed                          #
        ########################################################################
        config.delta_temperature_callback(self)
        ########################################################################
        # Add Heat transfer equation                                           #
        ########################################################################
        deltaT = self.delta_temperature

        @self.Constraint(self.flowsheet().config.time)
        def heat_transfer_equation(b, t):
            if self.config.flow_pattern == HeatExchangerFlowPattern.crossflow:
                return pyunits.convert(
                    q[t], to_units=q_units) == (f[t] * u[t] * a * deltaT[t])
            else:
                return pyunits.convert(q[t], to_units=q_units) == (u[t] * a *
                                                                   deltaT[t])

        ########################################################################
        # Add symbols for LaTeX equation rendering                             #
        ########################################################################
        self.overall_heat_transfer_coefficient.latex_symbol = "U"
        self.area.latex_symbol = "A"
        self.side_1.heat.latex_symbol = "Q_1"
        self.side_2.heat.latex_symbol = "Q_2"
        self.delta_temperature.latex_symbol = "\\Delta T"