Пример #1
0
    def build(self):
        """Build the model.

        Args:
            None
        Returns:
            None
        """
        # Setup model build logger
        model_log = idaeslog.getModelLogger(self.name, tag="unit")

        # Call UnitModel.build to setup dynamics
        super(CondenserData, self).build()

        # Check config arguments
        if self.config.temperature_spec is None:
            raise ConfigurationError("temperature_spec config argument "
                                     "has not been specified. Please select "
                                     "a valid option.")
        if (self.config.condenser_type == CondenserType.partialCondenser) and \
                (self.config.temperature_spec ==
                 TemperatureSpec.atBubblePoint):
            raise ConfigurationError("condenser_type set to partial but "
                                     "temperature_spec set to atBubblePoint. "
                                     "Select customTemperature and specify "
                                     "outlet temperature.")

        # Add Control Volume for the condenser
        self.control_volume = ControlVolume0DBlock(
            default={
                "dynamic": self.config.dynamic,
                "has_holdup": self.config.has_holdup,
                "property_package": self.config.property_package,
                "property_package_args": self.config.property_package_args
            })

        self.control_volume.add_state_blocks(has_phase_equilibrium=True)

        self.control_volume.add_material_balances(
            balance_type=self.config.material_balance_type,
            has_phase_equilibrium=True)

        self.control_volume.add_energy_balances(
            balance_type=self.config.energy_balance_type,
            has_heat_transfer=True)

        self.control_volume.add_momentum_balances(
            balance_type=self.config.momentum_balance_type,
            has_pressure_change=self.config.has_pressure_change)

        # Get liquid and vapor phase objects from the property package
        # to be used below. Avoids repition.
        _liquid_list = []
        _vapor_list = []
        for p in self.config.property_package.phase_list:
            pobj = self.config.property_package.get_phase(p)
            if pobj.is_vapor_phase():
                _vapor_list.append(p)
            elif pobj.is_liquid_phase():
                _liquid_list.append(p)
            else:
                _liquid_list.append(p)
                model_log.warning(
                    "A non-liquid/non-vapor phase was detected but will "
                    "be treated as a liquid.")

        # Create a pyomo set for indexing purposes. This set is appended to
        # model otherwise results in an abstract set.
        self._liquid_set = Set(initialize=_liquid_list)
        self._vapor_set = Set(initialize=_vapor_list)

        self._make_ports()

        if self.config.condenser_type == CondenserType.totalCondenser:

            self._make_splits_total_condenser()

            if (self.config.temperature_spec == TemperatureSpec.atBubblePoint):
                # Option 1: if true, condition for total condenser
                # (T_cond = T_bubble)
                # Option 2: if this is false, then user has selected
                # custom temperature spec and needs to fix an outlet
                # temperature.
                def rule_total_cond(self, t):
                    return self.control_volume.properties_out[t].\
                        temperature == self.control_volume.properties_out[t].\
                        temperature_bubble

                self.eq_total_cond_spec = Constraint(self.flowsheet().time,
                                                     rule=rule_total_cond)

        else:
            self._make_splits_partial_condenser()

        # Add object reference to variables of the control volume
        # Reference to the heat duty
        add_object_reference(self, "heat_duty", self.control_volume.heat)

        # Reference to the pressure drop (if set to True)
        if self.config.has_pressure_change:
            add_object_reference(self, "deltaP", self.control_volume.deltaP)
Пример #2
0
    def _create(self, group=None):
        """
        """
        m = self.parent_block()
        if group is None:
            return None

        # ########################## SETS #####################################

        self.INVESTSTORAGES = Set(initialize=[n for n in group])
        self.INVEST_REL_CAP_IN = Set(initialize=[
            n for n in group if n.invest_relation_input_capacity is not None
        ])

        self.INVEST_REL_CAP_OUT = Set(initialize=[
            n for n in group if n.invest_relation_output_capacity is not None
        ])

        self.INVEST_REL_IN_OUT = Set(initialize=[
            n for n in group if n.invest_relation_input_output is not None
        ])

        self.INITIAL_CAPACITY = Set(
            initialize=[n for n in group if n.initial_capacity is not None])

        # The capacity is set as a non-negative variable, therefore it makes no
        # sense to create an additional constraint if the lower bound is zero
        # for all time steps.
        self.MIN_INVESTSTORAGES = Set(initialize=[
            n for n in group
            if sum([n.capacity_min[t] for t in m.TIMESTEPS]) > 0
        ])

        # ######################### Variables  ################################
        self.capacity = Var(self.INVESTSTORAGES,
                            m.TIMESTEPS,
                            within=NonNegativeReals)

        def _storage_investvar_bound_rule(block, n):
            """Rule definition to bound the invested storage capacity `invest`.
            """
            return 0, n.investment.maximum

        self.invest = Var(self.INVESTSTORAGES,
                          within=NonNegativeReals,
                          bounds=_storage_investvar_bound_rule)

        # ######################### CONSTRAINTS ###############################
        i = {n: [i for i in n.inputs][0] for n in group}
        o = {n: [o for o in n.outputs][0] for n in group}

        def _storage_balance_rule(block, n, t):
            """Rule definition for the storage energy balance.
            """
            expr = 0
            expr += block.capacity[n, t]
            expr += -block.capacity[n, m.previous_timesteps[t]] * (
                1 - n.capacity_loss[t])
            expr += (-m.flow[i[n], n, t] *
                     n.inflow_conversion_factor[t]) * m.timeincrement[t]
            expr += (m.flow[n, o[n], t] /
                     n.outflow_conversion_factor[t]) * m.timeincrement[t]
            return expr == 0

        self.balance = Constraint(self.INVESTSTORAGES,
                                  m.TIMESTEPS,
                                  rule=_storage_balance_rule)

        def _initial_capacity_invest_rule(block, n):
            """Rule definition for constraint to connect initial storage
            capacity with capacity of last timesteps.
            """
            expr = (self.capacity[n,
                                  m.TIMESTEPS[-1]] == (n.investment.existing +
                                                       self.invest[n]) *
                    n.initial_capacity)
            return expr

        self.initial_capacity = Constraint(self.INITIAL_CAPACITY,
                                           rule=_initial_capacity_invest_rule)

        def _power_coupled(block, n):
            """Rule definition for constraint to connect the input power
            and output power
            """
            expr = ((m.InvestmentFlow.invest[n, o[n]] +
                     m.flows[n, o[n]].investment.existing) *
                    n.invest_relation_input_output == (
                        m.InvestmentFlow.invest[i[n], n] +
                        m.flows[i[n], n].investment.existing))
            return expr

        self.power_coupled = Constraint(self.INVEST_REL_IN_OUT,
                                        rule=_power_coupled)

        def _storage_capacity_inflow_invest_rule(block, n):
            """Rule definition of constraint connecting the inflow
            `InvestmentFlow.invest of storage with invested capacity `invest`
            by nominal_capacity__inflow_ratio
            """
            expr = ((m.InvestmentFlow.invest[i[n], n] +
                     m.flows[i[n], n].investment.existing
                     ) == (n.investment.existing + self.invest[n]) *
                    n.invest_relation_input_capacity)
            return expr

        self.storage_capacity_inflow = Constraint(
            self.INVEST_REL_CAP_IN, rule=_storage_capacity_inflow_invest_rule)

        def _storage_capacity_outflow_invest_rule(block, n):
            """Rule definition of constraint connecting outflow
            `InvestmentFlow.invest` of storage and invested capacity `invest`
            by nominal_capacity__outflow_ratio
            """
            expr = ((m.InvestmentFlow.invest[n, o[n]] +
                     m.flows[n, o[n]].investment.existing
                     ) == (n.investment.existing + self.invest[n]) *
                    n.invest_relation_output_capacity)
            return expr

        self.storage_capacity_outflow = Constraint(
            self.INVEST_REL_CAP_OUT,
            rule=_storage_capacity_outflow_invest_rule)

        def _max_capacity_invest_rule(block, n, t):
            """Rule definition for upper bound constraint for the storage cap.
            """
            expr = (
                self.capacity[n, t] <=
                (n.investment.existing + self.invest[n]) * n.capacity_max[t])
            return expr

        self.max_capacity = Constraint(self.INVESTSTORAGES,
                                       m.TIMESTEPS,
                                       rule=_max_capacity_invest_rule)

        def _min_capacity_invest_rule(block, n, t):
            """Rule definition of lower bound constraint for the storage cap.
            """
            expr = (
                self.capacity[n, t] >=
                (n.investment.existing + self.invest[n]) * n.capacity_min[t])
            return expr

        # Set the lower bound of the storage capacity if the attribute exists
        self.min_capacity = Constraint(self.MIN_INVESTSTORAGES,
                                       m.TIMESTEPS,
                                       rule=_min_capacity_invest_rule)
Пример #3
0
def add_model_components(m, d, scenario_directory, subproblem, stage):
    """
    Before adding any components, this module will go through each relevant
    capacity type and add the module components for that capacity type.

    Then the following Pyomo model components are defined in this module:

    +-------------------------------------------------------------------------+
    | Sets                                                                    |
    +=========================================================================+
    | | :code:`TX_OPR_PRDS`                                                   |
    |                                                                         |
    | Two-dimensional set of the transmission lines and their operational     |
    | periods (capacity exists and is available).                             |
    +-------------------------------------------------------------------------+
    | | :code:`TX_LINES_OPR_IN_PRD`                                           |
    | | *Defined over*: :code:`PERIODS`                                       |
    |                                                                         |
    | Indexed set of transmission lines operational in each period.           |
    +-------------------------------------------------------------------------+
    | | :code:`OPR_PRDS_BY_TX_LINE`                                           |
    | | *Defined over*: :code:`TX_LINES`                                      |
    |                                                                         |
    | Indexed set of operational period for each transmission line.           |
    +-------------------------------------------------------------------------+
    | | :code:`TX_OPR_TMPS`                                                   |
    |                                                                         |
    | Two-dimensional set of the transmission lines and their operational     |
    | timepoints, derived from :code:`TX_OPR_PRDS` and the timepoitns in each |
    | period.                                                                 |
    +-------------------------------------------------------------------------+
    | | :code:`TX_LINES_OPR_IN_TMP`                                           |
    | | *Defined over*: :code:`TIMEPOINTS`                                    |
    |                                                                         |
    | Indexed set of transmission lines operatoinal in each timepoint.        |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Expressions                                                             |
    +=========================================================================+
    | | :code:`Tx_Min_Capacity_MW`                                            |
    | | *Defined over*: :code:`TX_OPR_PRDS`                                   |
    |                                                                         |
    | The transmission line's minimum flow in MW (negative number indicates   |
    | flow in the opposite direction of the line's defined flow direction).   |
    | Depending on the capacity type, this can be a pre-specified amount or   |
    | a decision variable (with an associated cost).                          |
    +-------------------------------------------------------------------------+
    | | :code:`Tx_Max_Capacity_MW`                                            |
    | | *Defined over*: :code:`TX_OPR_PRDS`                                   |
    |                                                                         |
    | The transmission line's maximum flow in MW (negative number indicates   |
    | flow in the opposite direction of the line's defined flow direction).   |
    | Depending on the capacity type, this can be a pre-specified amount or   |
    | a decision variable (with an associated cost).                          |
    +-------------------------------------------------------------------------+
    | | :code:`Tx_Capacity_Cost_in_Prd`                                       |
    | | *Defined over*: :code:`TX_OPR_PRDS`                                   |
    |                                                                         |
    | The cost to have the transmission capacity available in the period.     |
    | Depending on the capacity type, this could be zero.                     |
    | If the subproblem is less than a full year (e.g. in production-         |
    | cost mode with 365 daily subproblems), the costs are scaled down        |
    | proportionally.                                                         |
    +-------------------------------------------------------------------------+
    | | :code:`Total_Tx_Capacity_Costs`                                       |
    |                                                                         |
    | The total cost of the system's transmission capacity across all periods.|
    +-------------------------------------------------------------------------+

    """

    # Dynamic Inputs
    ###########################################################################

    df = pd.read_csv(os.path.join(scenario_directory, str(subproblem),
                                  str(stage), "inputs",
                                  "transmission_lines.tab"),
                     sep="\t",
                     usecols=[
                         "TRANSMISSION_LINES", "tx_capacity_type",
                         "tx_operational_type"
                     ])

    # Required capacity modules are the unique set of tx capacity types
    # This list will be used to know which capacity modules to load
    required_tx_capacity_modules = df.tx_capacity_type.unique()

    # Import needed transmission capacity type modules for expression rules
    imported_tx_capacity_modules = load_tx_capacity_type_modules(
        required_tx_capacity_modules)

    # Add model components for each of the transmission capacity modules
    for op_m in required_tx_capacity_modules:
        imp_op_m = imported_tx_capacity_modules[op_m]
        if hasattr(imp_op_m, "add_model_components"):
            imp_op_m.add_model_components(m, d, scenario_directory, subproblem,
                                          stage)

    # Sets
    ###########################################################################

    m.TX_OPR_PRDS = Set(
        dimen=2,
        within=m.TX_LINES * m.PERIODS,
        initialize=lambda mod: join_sets(
            mod,
            getattr(d, tx_capacity_type_operational_period_sets),
        ),
    )  # assumes capacity types model components are already added!

    m.TX_LINES_OPR_IN_PRD = Set(m.PERIODS,
                                initialize=lambda mod, period: list(
                                    set(tx for (tx, p) in mod.TX_OPR_PRDS
                                        if p == period)))

    m.OPR_PRDS_BY_TX_LINE = Set(m.TX_LINES,
                                initialize=lambda mod, tx: list(
                                    set(p for (l, p) in mod.TX_OPR_PRDS
                                        if l == tx)))

    m.TX_OPR_TMPS = Set(
        dimen=2,
        initialize=lambda mod: [(tx, tmp) for tx in mod.TX_LINES
                                for p in mod.OPR_PRDS_BY_TX_LINE[tx]
                                for tmp in mod.TMPS_IN_PRD[p]])

    m.TX_LINES_OPR_IN_TMP = Set(m.TMPS,
                                initialize=lambda mod, tmp: list(
                                    set(tx for (tx, t) in mod.TX_OPR_TMPS
                                        if t == tmp)))

    # Expressions
    ###########################################################################

    def tx_min_capacity_rule(mod, tx, p):
        tx_cap_type = mod.tx_capacity_type[tx]
        return imported_tx_capacity_modules[tx_cap_type]. \
            min_transmission_capacity_rule(mod, tx, p)

    def tx_max_capacity_rule(mod, tx, p):
        tx_cap_type = mod.tx_capacity_type[tx]
        return imported_tx_capacity_modules[tx_cap_type]. \
            max_transmission_capacity_rule(mod, tx, p)

    def tx_capacity_cost_rule(mod, tx, p):
        tx_cap_type = mod.tx_capacity_type[tx]
        return imported_tx_capacity_modules[tx_cap_type].\
            tx_capacity_cost_rule(mod, tx, p) \
            * mod.hours_in_subproblem_period[p] \
            / mod.hours_in_full_period[p]

    m.Tx_Min_Capacity_MW = Expression(m.TX_OPR_PRDS, rule=tx_min_capacity_rule)

    m.Tx_Max_Capacity_MW = Expression(m.TX_OPR_PRDS, rule=tx_max_capacity_rule)

    m.Tx_Capacity_Cost_in_Prd = Expression(m.TX_OPR_PRDS,
                                           rule=tx_capacity_cost_rule)
Пример #4
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,
            "material_balance_type": config.material_balance_type,
            "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)
Пример #5
0
def add_model_components(m, d, scenario_directory, subproblem, stage):
    """
    The following Pyomo model components are defined in this module:

    +-------------------------------------------------------------------------+
    | Sets                                                                    |
    +=========================================================================+
    | | :code:`GEN_HYDRO_MUST_TAKE`                                           |
    |                                                                         |
    | The set of generators of the :code:`gen_hydro_must_take` operational    |
    | type.                                                                   |
    +-------------------------------------------------------------------------+
    | | :code:`GEN_HYDRO_MUST_TAKE_OPR_HRZS`                                  |
    |                                                                         |
    | Two-dimensional set with generators of the :code:`gen_hydro_must_take`  |
    | operational type and their operational horizons.                        |
    +-------------------------------------------------------------------------+
    | | :code:`GEN_HYDRO_MUST_TAKE_OPR_TMPS`                                  |
    |                                                                         |
    | Two-dimensional set with generators of the :code:`gen_hydro_must_take`  |
    | operational type and their operational timepoints.                      |
    +-------------------------------------------------------------------------+
    | | :code:`GEN_HYDRO_MUST_TAKE_LINKED_TMPS`                               |
    |                                                                         |
    | Two-dimensional set with generators of the :code:`gen_hydro_must_take`  |
    | operational type and their linked timepoints.                           |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Required Input Params                                                   |
    +=========================================================================+
    | | :code:`gen_hydro_must_take_max_power_fraction`                        |
    | | *Defined over*: :code:`GEN_HYDRO_MUST_TAKE_OPR_HRZS`                  |
    | | *Within*: :code:`PercentFraction`                                     |
    |                                                                         |
    | The project's maximum power output in each operational horizon as a     |
    | fraction of its available capacity.                                     |
    +-------------------------------------------------------------------------+
    | | :code:`gen_hydro_must_take_min_power_fraction`                        |
    | | *Defined over*: :code:`GEN_HYDRO_MUST_TAKE_OPR_HRZS`                  |
    | | *Within*: :code:`PercentFraction`                                     |
    |                                                                         |
    | The project's minimum power output in each operational horizon as a     |
    | fraction of its available capacity.                                     |
    +-------------------------------------------------------------------------+
    | | :code:`gen_hydro_must_take_average_power_fraction`                    |
    | | *Defined over*: :code:`GEN_HYDRO_MUST_TAKE_OPR_HRZS`                  |
    | | *Within*: :code:`PercentFraction`                                     |
    |                                                                         |
    | The project's avarage power output in each operational horizon as a     |
    | fraction of its available capacity. This can be interpreted as the      |
    | project's average capacity factor or plant load factor.                 |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Optional Input Params                                                   |
    +=========================================================================+
    | | :code:`gen_hydro_must_take_ramp_up_when_on_rate`                      |
    | | *Defined over*: :code:`GEN_HYDRO_MUST_TAKE`                           |
    | | *Within*: :code:`PercentFraction`                                     |
    | | *Default*: :code:`1`                                                  |
    |                                                                         |
    | The project's upward ramp rate limit during operations, defined as a    |
    | fraction of its capacity per minute.                                    |
    +-------------------------------------------------------------------------+
    | | :code:`gen_hydro_must_take_ramp_down_when_on_rate`                    |
    | | *Defined over*: :code:`GEN_HYDRO_MUST_TAKE`                           |
    | | *Within*: :code:`PercentFraction`                                     |
    | | *Default*: :code:`1`                                                  |
    |                                                                         |
    | The project's downward ramp rate limit during operations, defined as a  |
    | fraction of its capacity per minute.                                    |
    +-------------------------------------------------------------------------+
    | | :code:`gen_hydro_must_take_aux_consumption_frac_capacity`             |
    | | *Defined over*: :code:`GEN_HYDRO_MUST_TAKE`                           |
    | | *Within*: :code:`PercentFraction`                                     |
    | | *Default*: :code:`0`                                                  |
    |                                                                         |
    | Auxiliary consumption as a fraction of capacity. This would be          |
    | incurred in all timepoints when capacity is available.                  |
    +-------------------------------------------------------------------------+
    | | :code:`gen_hydro_must_take_aux_consumption_frac_power`                |
    | | *Defined over*: :code:`GEN_HYDRO_MUST_TAKE`                           |
    | | *Within*: :code:`PercentFraction`                                     |
    | | *Default*: :code:`0`                                                  |
    |                                                                         |
    | Auxiliary consumption as a fraction of gross power output.              |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Linked Input Params                                                     |
    +=========================================================================+
    | | :code:`gen_hydro_must_take_linked_power`                              |
    | | *Defined over*: :code:`GEN_HYDRO_MUST_TAKE_LINKED_TMPS`               |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The project's power provision in the linked timepoints.                 |
    +-------------------------------------------------------------------------+
    | | :code:`gen_hydro_must_take_linked_upwards_reserves`                   |
    | | *Defined over*: :code:`GEN_HYDRO_MUST_TAKE_LINKED_TMPS`               |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The project's upward reserve provision in the linked timepoints.        |
    +-------------------------------------------------------------------------+
    | | :code:`gen_hydro_must_take_linked_downwards_reserves`                 |
    | | *Defined over*: :code:`GEN_HYDRO_MUST_TAKE_LINKED_TMPS`               |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The project's downward reserve provision in the linked timepoints.      |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Variables                                                               |
    +=========================================================================+
    | | :code:`GenHydroMustTake_Gross_Power_MW`                               |
    | | *Defined over*: :code:`GEN_HYDRO_MUST_TAKE_OPR_TMPS`                  |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | Power provision in MW from this project in each timepoint in which the  |
    | project is operational (capacity exists and the project is available).  |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Expressions                                                             |
    +=========================================================================+
    | | :code:`GenHydroMustTake_Auxiliary_Consumption_MW`                     |
    | | *Defined over*: :code:`GEN_HYDRO_MUST_TAKE_OPR_TMPS`                  |
    |                                                                         |
    | The project's auxiliary consumption (power consumed on-site and not     |
    | sent to the grid) in each timepoint.                                    |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Constraints                                                             |
    +=========================================================================+
    | Power                                                                   |
    +-------------------------------------------------------------------------+
    | | :code:`GenHydroMustTake_Max_Power_Constraint`                         |
    | | *Defined over*: :code:`GEN_HYDRO_MUST_TAKE_OPR_HRZS`                  |
    |                                                                         |
    | Limits the power plus upward reserves based on the                      |
    | :code:`gen_hydro_must_take_max_power_fraction` and the available        |
    | capacity.                                                               |
    +-------------------------------------------------------------------------+
    | | :code:`GenHydroMustTake_Min_Power_Constraint`                         |
    | | *Defined over*: :code:`GEN_HYDRO_MUST_TAKE_OPR_HRZS`                  |
    |                                                                         |
    | Power provision minus downward reserves should exceed a certain level   |
    | based on the :code:`gen_hydro_must_take_min_power_fraction` and the     |
    | available capacity.                                                     |
    +-------------------------------------------------------------------------+
    | | :code:`GenHydroMustTake_Energy_Budget_Constraint`                     |
    | | *Defined over*: :code:`GEN_HYDRO_MUST_TAKE_OPR_HRZS`                  |
    |                                                                         |
    | The project's average capacity factor in each operational horizon,      |
    | should match the specified                                              |
    | :code:`gen_hydro_must_take_average_power_fraction`.                     |
    +-------------------------------------------------------------------------+
    | Ramps                                                                   |
    +-------------------------------------------------------------------------+
    | | :code:`GenHydroMustTake_Ramp_Up_Constraint`                           |
    | | *Defined over*: :code:`GEN_HYDRO_MUST_TAKE_OPR_TMPS`                  |
    |                                                                         |
    | Limits the allowed project upward ramp based on the                     |
    | :code:`gen_hydro_must_take_ramp_up_when_on_rate`.                       |
    +-------------------------------------------------------------------------+
    | | :code:`GenHydroMustTake_Ramp_Down_Constraint`                         |
    | | *Defined over*: :code:`GEN_HYDRO_MUST_TAKE_OPR_TMPS`                  |
    |                                                                         |
    | Limits the allowed project downward ramp based on the                   |
    | :code:`gen_hydro_must_take_ramp_down_when_on_rate`.                     |
    +-------------------------------------------------------------------------+

    """
    # Sets
    ###########################################################################

    m.GEN_HYDRO_MUST_TAKE = Set(
        within=m.PROJECTS,
        initialize=lambda mod: subset_init_by_param_value(
            mod, "PROJECTS", "operational_type", "gen_hydro_must_take"))

    m.GEN_HYDRO_MUST_TAKE_OPR_HRZS = Set(dimen=2)

    m.GEN_HYDRO_MUST_TAKE_OPR_TMPS = Set(
        dimen=2,
        within=m.PRJ_OPR_TMPS,
        initialize=lambda mod: list(
            set((g, tmp) for (g, tmp) in mod.PRJ_OPR_TMPS
                if g in mod.GEN_HYDRO_MUST_TAKE)))

    m.GEN_HYDRO_MUST_TAKE_LINKED_TMPS = Set(dimen=2)

    # Required Params
    ###########################################################################

    m.gen_hydro_must_take_max_power_fraction = Param(
        m.GEN_HYDRO_MUST_TAKE_OPR_HRZS, within=PercentFraction)

    m.gen_hydro_must_take_min_power_fraction = Param(
        m.GEN_HYDRO_MUST_TAKE_OPR_HRZS, within=PercentFraction)

    m.gen_hydro_must_take_average_power_fraction = Param(
        m.GEN_HYDRO_MUST_TAKE_OPR_HRZS, within=PercentFraction)

    # Optional Params
    ###########################################################################

    m.gen_hydro_must_take_ramp_up_when_on_rate = Param(m.GEN_HYDRO_MUST_TAKE,
                                                       within=PercentFraction,
                                                       default=1)

    m.gen_hydro_must_take_ramp_down_when_on_rate = Param(
        m.GEN_HYDRO_MUST_TAKE, within=PercentFraction, default=1)

    m.gen_hydro_must_take_aux_consumption_frac_capacity = Param(
        m.GEN_HYDRO_MUST_TAKE, within=PercentFraction, default=0)

    m.gen_hydro_must_take_aux_consumption_frac_power = Param(
        m.GEN_HYDRO_MUST_TAKE, within=PercentFraction, default=0)

    # Linked Params
    ###########################################################################

    m.gen_hydro_must_take_linked_power = Param(
        m.GEN_HYDRO_MUST_TAKE_LINKED_TMPS, within=NonNegativeReals)

    m.gen_hydro_must_take_linked_upwards_reserves = Param(
        m.GEN_HYDRO_MUST_TAKE_LINKED_TMPS, within=NonNegativeReals)

    m.gen_hydro_must_take_linked_downwards_reserves = Param(
        m.GEN_HYDRO_MUST_TAKE_LINKED_TMPS, within=NonNegativeReals)

    # Variables
    ###########################################################################

    m.GenHydroMustTake_Gross_Power_MW = Var(m.GEN_HYDRO_MUST_TAKE_OPR_TMPS,
                                            within=NonNegativeReals)

    # Expressions
    ###########################################################################

    def upwards_reserve_rule(mod, g, tmp):
        return sum(
            getattr(mod, c)[g, tmp] for c in getattr(d, headroom_variables)[g])

    m.GenHydroMustTake_Upwards_Reserves_MW = Expression(
        m.GEN_HYDRO_MUST_TAKE_OPR_TMPS, rule=upwards_reserve_rule)

    def downwards_reserve_rule(mod, g, tmp):
        return sum(
            getattr(mod, c)[g, tmp] for c in getattr(d, footroom_variables)[g])

    m.GenHydroMustTake_Downwards_Reserves_MW = Expression(
        m.GEN_HYDRO_MUST_TAKE_OPR_TMPS, rule=downwards_reserve_rule)

    def auxiliary_consumption_rule(mod, g, tmp):
        """
        **Expression Name**: GenHydroMustTake_Auxiliary_Consumption_MW
        **Defined Over**: GEN_HYDRO_MUST_TAKE_OPR_TMPS
        """
        return mod.Capacity_MW[g, mod.period[tmp]] \
            * mod.Availability_Derate[g, tmp] \
            * mod.gen_hydro_must_take_aux_consumption_frac_capacity[g] \
            + mod.GenHydroMustTake_Gross_Power_MW[g, tmp] \
            * mod.gen_hydro_must_take_aux_consumption_frac_power[g]

    m.GenHydroMustTake_Auxiliary_Consumption_MW = Expression(
        m.GEN_HYDRO_MUST_TAKE_OPR_TMPS, rule=auxiliary_consumption_rule)

    # Constraints
    ###########################################################################

    m.GenHydroMustTake_Max_Power_Constraint = Constraint(
        m.GEN_HYDRO_MUST_TAKE_OPR_TMPS, rule=max_power_rule)

    m.GenHydroMustTake_Min_Power_Constraint = Constraint(
        m.GEN_HYDRO_MUST_TAKE_OPR_TMPS, rule=min_power_rule)

    m.GenHydroMustTake_Energy_Budget_Constraint = Constraint(
        m.GEN_HYDRO_MUST_TAKE_OPR_HRZS, rule=energy_budget_rule)

    m.GenHydroMustTake_Ramp_Up_Constraint = Constraint(
        m.GEN_HYDRO_MUST_TAKE_OPR_TMPS, rule=ramp_up_rule)

    m.GenHydroMustTake_Ramp_Down_Constraint = Constraint(
        m.GEN_HYDRO_MUST_TAKE_OPR_TMPS, rule=ramp_down_rule)
Пример #6
0
def create_model():

    m = ConcreteModel()

    m.tf = Param(initialize=20)
    m.t = ContinuousSet(bounds=(0,m.tf))
    m.i = Set(initialize=[0,1,2,3,4,5],ordered=True)
    m.j = Set(initialize=[0,1],ordered=True)
    m.ij = Set(initialize=[(0,0),(0,1),(1,0),(1,1),(2,0),(2,1),(3,0),(4,0)],
                          ordered=True) 
    
    #Set Parameters
    m.eps = Param(initialize = 0.75, mutable=True)
    
    m.sig = Param(initialize = 0.15, mutable=True)
    m.xi  = Param(initialize = 0.983, mutable=True)
    m.omeg  = Param(initialize = 1.0/10, mutable=True)
    
    m.Y0   = Param(initialize = 55816.0, mutable=True)
    m.phi0 = Param(initialize = 0.493, mutable=True)
    
    d={}
    d[(0,0)] = 0.0222
    d[(0,1)] = 0.0222
    d[(1,0)] = 1/7.1
    d[(1,1)] = 1/7.1
    d[(2,0)] = 1/8.1
    d[(2,1)] = 1/(8.1+5)
    d[(3,0)] = 1/2.7
    d[(4,0)] = 1/2.1
    m.dd = Param(m.ij, initialize=d, mutable=True)
    
    d_inv={}
    d_inv[(1,0)] = 7.1
    d_inv[(2,0)] = 8.1
    d_inv[(3,0)] = 2.7
    d_inv[(4,0)] = 2.1
    m.dd_inv = Param(m.ij, initialize=d_inv, default=0, mutable=True)
    
    I={}
    I[(0,0)] =  0.9*m.dd[(0,0)]*m.Y0
    I[(1,0)] = 0.04*m.dd[(0,0)]*m.Y0
    I[(2,0)] = 0.04*m.dd[(0,0)]*m.Y0
    I[(3,0)] = 0.02*m.dd[(0,0)]*m.Y0
    m.II=Param(m.ij, initialize=I, default=0, mutable=True)
    
    p={}
    p[(4,0)] = 0.667
    m.pp = Param(m.ij, initialize=p, default=2, mutable=True)
    
    b={}
    b[(1,0)] = 0.066
    b[(1,1)] = 0.066
    b[(2,0)] = 0.066
    b[(2,1)] = 0.066*(1-0.25)
    b[(3,0)] = 0.147
    b[(4,0)] = 0.147
    m.bb = Param(m.ij,initialize=b, default=0, mutable=True)
    
    eta00={}
    eta00[(0,0)] = 0.505
    eta00[(0,1)] = 0.505
    eta00[(1,0)] = 0.505
    eta00[(1,1)] = 0.505
    eta00[(2,0)] = 0.307
    eta00[(2,1)] = 0.4803
    eta00[(3,0)] = 0.235
    eta00[(4,0)] = 0.235
    m.eta00 = Param(m.ij, initialize=eta00, mutable=True)
    
    eta01={}
    eta01[(0,0)] = 0.505
    eta01[(0,1)] = 0.6287
    eta01[(1,0)] = 0.505
    eta01[(1,1)] = 0.6287
    eta01[(2,0)] = 0.307
    eta01[(2,1)] = 0.4803
    eta01[(3,0)] = 0.235
    eta01[(4,0)] = 0.235
    m.eta01 = Param(m.ij, initialize=eta01, mutable=True)
    
    m.kp  = Param(initialize = 1000.0, mutable=True)
    m.kt  = Param(initialize = 1000.0, mutable=True)
    m.rr  = Param(initialize = 0.05, mutable=True)
    
    c={}
    c[(0,0)] = 3307
    c[(0,1)] = 3307
    c[(1,0)] = 5467
    c[(1,1)] = 5467
    c[(2,0)] = 5467
    c[(2,1)] = 5467
    c[(3,0)] = 12586
    c[(4,0)] = 35394
    m.cc = Param(m.ij, initialize=c, mutable=True)
    
    q={}
    q[(0,0)] = 1
    q[(0,1)] = 1
    q[(1,0)] = 1
    q[(1,1)] = 1
    q[(2,0)] = 0.83
    q[(2,1)] = 0.83
    q[(3,0)] = 0.42
    q[(4,0)] = 0.17
    m.qq = Param(m.ij, initialize=q, mutable=True)
    
    m.aa = Param(initialize = 0.0001, mutable=True)
    
    #Set Variables
    m.yy = Var(m.t,m.ij)
    m.L = Var(m.t)
    
    m.vp = Var(m.t, initialize=0.75, bounds=(0,0.75))
    m.vt = Var(m.t, initialize=0.75, bounds=(0,0.75))
    
    m.dyy = DerivativeVar(m.yy, wrt=m.t)
    m.dL = DerivativeVar(m.L, wrt=m.t)
    
    def CostFunc(m):
        return m.L[m.tf]
    m.cf = Objective(rule=CostFunc)
    
    
    def _initDistConst(m):
        return (m.phi0*m.Y0)/sum(m.dd_inv[kk] for kk in m.ij)
    m.idc = Expression(rule=_initDistConst)
    
    m.yy[0,(0,0)].fix(value((1-m.phi0)*m.Y0))
    m.yy[0,(0,1)].fix(0)
    m.yy[0,(1,0)].fix(value(m.dd_inv[(1,0)]*m.idc))
    m.yy[0,(1,1)].fix(0)
    m.yy[0,(2,0)].fix(value(m.dd_inv[(2,0)]*m.idc))
    m.yy[0,(2,1)].fix(0)
    m.yy[0,(3,0)].fix(value(m.dd_inv[(3,0)]*m.idc))
    m.yy[0,(4,0)].fix(value(m.dd_inv[(4,0)]*m.idc))
    m.L[0].fix(0)
    
    
    #ODEs
    def _yy00(m, t): 
        return sum(m.pp[kk]*m.yy[t,kk] for kk in m.ij)*m.dyy[t,(0,0)] == \
    	   	sum(m.pp[kk]*m.yy[t,kk] for kk in m.ij)*(m.II[(0,0)]-\
    		(m.vp[t]+m.dd[(0,0)])*m.yy[t,(0,0)]+m.omeg*m.yy[t,(0,1)])-\
               	m.pp[(0,0)]*sum(m.bb[kk]*m.eta00[kk]*m.pp[kk]*m.yy[t,kk] 
                                for kk in m.ij)*m.yy[t,(0,0)] 
    m.yy00DiffCon = Constraint(m.t, rule=_yy00)
    
    def _yy01(m, t):
        return sum(m.pp[kk]*m.yy[t,kk] for kk in m.ij)*m.dyy[t,(0,1)] == \
               	sum(m.pp[kk]*m.yy[t,kk] 
                    for kk in m.ij)*(m.vp[t]*m.yy[t,(0,0)]-
                                    (m.dd[(0,0)]+m.omeg)*m.yy[t,(0,1)])-\
                m.pp[(0,1)]*(1-m.eps)*sum(m.bb[kk]*m.eta01[kk]*
                                          m.pp[kk]*m.yy[t,kk] 
                                          for kk in m.ij)*m.yy[t,(0,1)]
    m.yy01DiffCon = Constraint(m.t, rule=_yy01)
    
    def _yy10(m, t):
        return sum(m.pp[kk]*m.yy[t,kk] for kk in m.ij)*m.dyy[t,(1,0)] == \
               	sum(m.pp[kk]*m.yy[t,kk] for kk in m.ij)*\
                (m.II[(1,0)]-((m.sig*m.xi)+m.vp[t]+m.dd[(1,0)]+m.dd[(0,0)])*
                  m.yy[t,(1,0)]+m.omeg*m.yy[t,(1,1)]
                )+m.pp[(0,0)]*sum(m.bb[kk]*m.eta00[kk]*
                                  m.pp[kk]*m.yy[t,kk] 
                                  for kk in m.ij)*m.yy[t,(0,0)]
    m.yy10DiffCon = Constraint(m.t, rule=_yy10)
    
    def _yy11(m, t):
        return sum(m.pp[kk]*m.yy[t,kk] for kk in m.ij)*m.dyy[t,(1,1)] == \
               	sum(m.pp[kk]*m.yy[t,kk] for kk in m.ij)*(m.vp[t]*m.yy[t,(1,0)]-\
                (m.omeg+(m.sig*m.xi)+m.dd[(1,1)]+m.dd[(0,0)])*m.yy[t,(1,1)])+\
    		m.pp[(0,1)]*(1-m.eps)*sum(m.bb[kk]*m.eta01[kk]*
                                          m.pp[kk]*m.yy[t,kk] 
                                          for kk in m.ij)*m.yy[t,(0,1)]
    m.yy11DiffCon = Constraint(m.t, rule=_yy11)
    
    def _yy20(m, t):
        return m.dyy[t,(2,0)] == \
    		m.II[(2,0)]+m.sig*m.xi*(m.yy[t,(1,0)]+m.yy[t,(1,1)])-\
    		(m.vt[t]+m.dd[(2,0)]+m.dd[(0,0)])*m.yy[t,(2,0)]
    m.yy20DiffCon = Constraint(m.t, rule=_yy20)
    
    def _yy21(m, t):
        return m.dyy[t,(2,1)] == \
    		m.vt[t]*m.yy[t,(2,0)]-(m.dd[(2,1)]+m.dd[(0,0)])*m.yy[t,(2,1)]
    m.yy21DiffCon = Constraint(m.t, rule=_yy21)
    
    def _yy30(m, t):
        return m.dyy[t,(3,0)] == \
    		m.II[(3,0)]+m.dd[(1,0)]*m.yy[t,(1,0)]+\
                m.dd[(1,1)]*m.yy[t,(1,1)]+m.dd[(2,0)]*m.yy[t,(2,0)]+\
                m.dd[(2,1)]*m.yy[t,(2,1)]-\
                (m.dd[(3,0)]+m.dd[(0,0)])*m.yy[t,(3,0)]
    m.yy30DiffCon = Constraint(m.t, rule=_yy30)
    
    def _yy40(m, t):
        return m.dyy[t, (4,0)] == \
    		m.dd[(3,0)]*m.yy[t,(3,0)]-(m.dd[(4,0)]+\
                m.dd[(0,0)])*m.yy[t,(4,0)]
    m.yy40DiffCon = Constraint(m.t, rule=_yy40)
    
    def _L(m, t):
        return m.dL[t] == \
            exp(-m.rr*t)*(m.aa*(m.kp*m.vp[t]*(m.yy[t,(0,0)]+m.yy[t,(1,0)]) \
            +(m.kt*m.vt[t]*m.yy[t,(2,0)])+sum(m.cc[kk]*m.yy[t,kk] 
                                              for kk in m.ij)) \
            -(1-m.aa)*sum(m.qq[kk]*m.yy[t,kk] for kk in m.ij))
    m.LDiffCon = Constraint(m.t, rule=_L)
   
    return m 
Пример #7
0
def create_model(namestr,
                 unslim=False,
                 emitlimit=False,
                 nem_ret_ratio=False,
                 nem_ret_gwh=False,
                 region_ret_ratio=False,
                 nem_disp_ratio=False,
                 nem_re_disp_ratio=False):
    """Creates an instance of the pyomo definition of openCEM"""
    m = AbstractModel(name=namestr)
    # Sets
    m.regions = Set(initialize=cemo.const.REGION.keys())  # Set of NEM regions
    m.zones = Set(
        initialize=cemo.const.ZONE.keys())  # Set of NTNDP planning zones
    m.all_tech = Set(
        initialize=cemo.const.ALL_TECH)  # Set of generation technologies
    # set of fuel based gen technologies
    m.fuel_gen_tech = Set(initialize=cemo.const.FUEL_TECH) & m.all_tech
    # set of gen techs that obey linearised unit commitment constraints
    m.commit_gen_tech = Set(initialize=cemo.const.COMMIT_TECH) & m.all_tech
    # set of retireable technologies
    m.retire_gen_tech = Set(initialize=cemo.const.RETIRE_TECH) & m.all_tech
    # set of retireable technologies
    m.nobuild_gen_tech = Set(initialize=cemo.const.NOBUILD_TECH) & m.all_tech
    # Set of storage technologies
    m.stor_tech = Set(initialize=cemo.const.STOR_TECH) & m.all_tech
    # set of hybrid (gen+storage) technologies
    m.hyb_tech = Set(initialize=cemo.const.HYB_TECH) & m.all_tech
    # Set of dispatch intervals
    m.t = Set(ordered=True)

    # Sparse set of zones per region
    m.zones_in_regions = Set(dimen=2, initialize=init_zones_in_regions)
    # Set listing technologies avaialable per zone (like a sparsity pattern)
    m.gen_tech_in_zones = Set(dimen=2)
    # Retirable technologies avaialable per zone (like a sparsity pattern)
    m.retire_gen_tech_in_zones = Set(dimen=2)
    # Fuel/emmitting technologies avaialable per zone (like a sparsity pattern)
    m.fuel_gen_tech_in_zones = Set(dimen=2)
    # Fuel/emmitting technologies avaialable per zone (like a sparsity pattern)
    m.commit_gen_tech_in_zones = Set(dimen=2)
    # Renewable technologies avaialable per zone (like a sparsity pattern)
    m.re_gen_tech_in_zones = Set(dimen=2)
    # Dispatchable technologies avaialable per zone (like a sparsity pattern)
    m.disp_gen_tech_in_zones = Set(dimen=2)
    # Renewable Dispatchable technologies avaialable per zone (like a sparsity pattern)
    m.re_disp_gen_tech_in_zones = Set(dimen=2)
    # Set listing storage avaialable per zone (like a sparsity pattern)
    m.hyb_tech_in_zones = Set(dimen=2)
    # Set listing storage avaialable per zone (like a sparsity pattern)
    m.stor_tech_in_zones = Set(dimen=2)
    # Set listing transmission lines to other regions in each region
    m.intercons_in_zones = Set(dimen=2, initialize=init_intercons_in_zones)

    # sparse sets built by build actions
    # Returns a list of planning zones for each region in R
    m.zones_per_region = Set(m.regions, within=m.zones, initialize=[])
    # Returns a tuple with generating techs in each zone
    m.gen_tech_per_zone = Set(m.zones, within=m.all_tech, initialize=[])
    # Returns a tuple with emitting techs in each zone
    m.fuel_gen_tech_per_zone = Set(m.zones, within=m.all_tech, initialize=[])
    # tuple for techs that obey linearised unit commitment constraints
    m.commit_gen_tech_per_zone = Set(m.zones, within=m.all_tech, initialize=[])
    m.re_gen_tech_per_zone = Set(m.zones, within=m.all_tech, initialize=[])
    m.disp_gen_tech_per_zone = Set(m.zones, within=m.all_tech, initialize=[])
    m.re_disp_gen_tech_per_zone = Set(m.zones,
                                      within=m.all_tech,
                                      initialize=[])
    # Returns a tuple with retirable techs in each zone
    m.retire_gen_tech_per_zone = Set(m.zones, within=m.all_tech, initialize=[])
    # Returns a tuple with storage techs in each zone
    m.stor_tech_per_zone = Set(m.zones, within=m.stor_tech, initialize=[])
    # Returns a tuple with emitting techs in each zone
    m.hyb_tech_per_zone = Set(m.zones, within=m.all_tech, initialize=[])
    # returns a tuple with transmission links in each region
    m.intercon_per_zone = Set(m.zones, initialize=[])

    # @@ Build actions
    # Scan TechinZones and populate ?_gen_tech_per_zone
    m.TpZ_build = BuildAction(rule=ScanForTechperZone)
    # Scan HybTechinZones and populate hyb_tech_per_zone
    m.HpZ_build = BuildAction(rule=ScanForHybridperZone)
    # Scan ZinR and populate ZperR
    m.ZpR_build = BuildAction(rule=ScanForZoneperRegion)
    # Scan TransLines and populate intercon_per_zone
    m.intercon_build = BuildAction(rule=build_intercon_per_zone)
    # Scan StorinZones and populate stor_tech_per_zone
    m.SpZ_build = BuildAction(rule=ScanForStorageperZone)

    # @@ Parameters
    # Capital costs generators
    # Build costs for generators
    m.cost_gen_build = Param(m.gen_tech_in_zones, default=9e7)
    m.cost_stor_build = Param(m.stor_tech_in_zones)  # Capital costs storage
    m.cost_hyb_build = Param(m.hyb_tech_in_zones)  # Capital costs hybrid
    # Capital costs $/MW/km trans
    m.cost_intercon_build = Param(m.intercons_in_zones,
                                  initialize=init_intercon_build_cost)

    m.cost_fuel = Param(m.fuel_gen_tech_in_zones,
                        initialize=init_default_fuel_price)  # Fuel cost

    # Fixed operating costs generators
    m.cost_gen_fom = Param(m.all_tech)
    # Variable operating costs generators
    m.cost_gen_vom = Param(m.all_tech)
    # Fixed operating costs storage
    m.cost_stor_fom = Param(m.stor_tech)
    # Variable operating costs storage
    m.cost_stor_vom = Param(m.stor_tech)
    # Fixed operating costs hybrid
    m.cost_hyb_fom = Param(m.hyb_tech)
    # Variable operating costs hybrid
    m.cost_hyb_vom = Param(m.hyb_tech)
    # Technology lifetime in years
    m.all_tech_lifetime = Param(m.all_tech, initialize=init_default_lifetime)
    # Project discount rate
    m.all_tech_discount_rate = Param(default=0.05)

    # Generator tech fixed charge rate
    m.fixed_charge_rate = Param(m.all_tech, initialize=init_fcr)
    # Transmission tech fixed charge rate
    m.intercon_fixed_charge_rate = Param(initialize=init_intercon_fcr)
    # Per year cost adjustment for sims shorter than 1 year of dispatch
    m.year_correction_factor = Param(initialize=init_year_correction_factor)

    m.cost_retire = Param(m.retire_gen_tech, initialize=init_cost_retire)
    m.cost_unserved = Param(initialize=cemo.const.DEFAULT_COSTS["unserved"]
                            )  # cost of unserved power
    # cost in $/kg of total emissions
    m.cost_emit = Param(initialize=cemo.const.DEFAULT_COSTS["emit"])
    m.cost_trans = Param(
        initialize=cemo.const.DEFAULT_COSTS["trans"])  # cost of transmission

    # Round trip efficiency of storage technology
    m.stor_rt_eff = Param(m.stor_tech, initialize=init_stor_rt_eff)
    # Number of hours of storage technology
    m.stor_charge_hours = Param(m.stor_tech, initialize=init_stor_charge_hours)

    # Collector multiple of hybrid technology
    m.hyb_col_mult = Param(m.hyb_tech, initialize=init_hyb_col_mult)
    # Number of hours of storage technology
    m.hyb_charge_hours = Param(m.hyb_tech, initialize=init_hyb_charge_hours)

    m.fuel_heat_rate = Param(m.fuel_gen_tech_in_zones,
                             initialize=init_default_heat_rate)
    # Emission rates
    m.fuel_emit_rate = Param(m.fuel_gen_tech,
                             initialize=init_default_fuel_emit_rate)
    # proportioning factors for notional interconnectors
    m.intercon_loss_factor = Param(m.intercons_in_zones,
                                   initialize=init_intercon_loss_factor)

    m.gen_cap_factor = Param(
        m.gen_tech_in_zones, m.t,
        initialize=init_cap_factor)  # Capacity factors for generators
    m.hyb_cap_factor = Param(
        m.hyb_tech_in_zones, m.t,
        initialize=init_cap_factor)  # Capacity factors for generators

    # Maximum capacity per generating technology per zone
    m.gen_build_limit = Param(m.gen_tech_in_zones,
                              initialize=init_gen_build_limit)
    m.gen_cap_initial = Param(m.gen_tech_in_zones,
                              default=0)  # operating capacity
    m.stor_cap_initial = Param(m.stor_tech_in_zones,
                               default=0)  # operating capacity
    m.hyb_cap_initial = Param(m.hyb_tech_in_zones,
                              default=0)  # operating capacity
    m.intercon_cap_initial = Param(
        m.intercons_in_zones,
        initialize=init_intercon_cap_initial)  # operating capacity
    # exogenous new capacity
    m.gen_cap_exo = Param(m.gen_tech_in_zones, default=0)
    # exogenous new storage capacity
    m.stor_cap_exo = Param(m.stor_tech_in_zones, default=0)
    # exogenous new hybrid capacity
    m.hyb_cap_exo = Param(m.hyb_tech_in_zones, default=0)
    # exogenous transmission capacity
    m.intercon_cap_exo = Param(m.intercons_in_zones, default=0)
    m.ret_gen_cap_exo = Param(m.retire_gen_tech_in_zones, default=0)
    # Net Electrical load (may include rooftop and EV)
    m.region_net_demand = Param(m.regions, m.t)
    # Zone load distribution factors as a pct of region demand
    m.zone_demand_factor = Param(m.zones,
                                 m.t,
                                 initialize=init_zone_demand_factors)
    # NEM operating reserve margin
    m.nem_operating_reserve = Param(default=0.075)
    # carry forward capital costs calculated
    m.cost_cap_carry_forward_sim = Param(m.zones, default=0)
    # carry forward capital costs NEM historical estimate
    m.cost_cap_carry_forward_hist = Param(m.zones, default=0)
    # carry forward capital costs total
    m.cost_cap_carry_forward = Param(m.zones, mutable=True)

    # Build action to Compute carry forward costs
    m.cost_carry_forward_build = BuildAction(
        rule=build_carry_fwd_cost_per_zone)

    # @@ Variables
    m.gen_cap_new = Var(m.gen_tech_in_zones,
                        within=NonNegativeReals)  # New capacity
    m.gen_cap_op = Var(m.gen_tech_in_zones,
                       within=NonNegativeReals)  # Total generation capacity
    m.stor_cap_new = Var(m.stor_tech_in_zones,
                         within=NonNegativeReals)  # New storage capacity
    m.stor_cap_op = Var(m.stor_tech_in_zones,
                        within=NonNegativeReals)  # Total storage capacity
    m.hyb_cap_new = Var(m.hyb_tech_in_zones, within=NonNegativeReals)
    m.hyb_cap_op = Var(m.hyb_tech_in_zones, within=NonNegativeReals)
    m.intercon_cap_new = Var(m.intercons_in_zones, within=NonNegativeReals)
    m.intercon_cap_op = Var(m.intercons_in_zones, within=NonNegativeReals)
    m.gen_cap_ret = Var(m.retire_gen_tech_in_zones,
                        within=NonNegativeReals)  # retireable capacity
    m.gen_cap_ret_neg = Var(m.retire_gen_tech_in_zones,
                            within=NonNegativeReals
                            )  # slack for exogenous retires beyond gen_op_cap
    m.gen_cap_exo_neg = Var(
        m.gen_tech_in_zones, within=NonNegativeReals
    )  # slack for exogenous builds exceeding gen_build_limit
    m.gen_disp = Var(m.gen_tech_in_zones, m.t,
                     within=NonNegativeReals)  # dispatched power
    # Variables for committed power constraints
    m.gen_disp_com = Var(m.commit_gen_tech_in_zones,
                         m.t,
                         within=NonNegativeReals)
    m.gen_disp_com_p = Var(m.commit_gen_tech_in_zones,
                           m.t,
                           within=NonNegativeReals)
    m.gen_disp_com_m = Var(m.commit_gen_tech_in_zones,
                           m.t,
                           within=NonNegativeReals)
    m.gen_disp_com_s = Var(m.commit_gen_tech_in_zones,
                           m.t,
                           within=NonNegativeReals)

    m.stor_disp = Var(m.stor_tech_in_zones, m.t,
                      within=NonNegativeReals)  # dispatched power from storage
    m.stor_reserve = Var(
        m.stor_tech_in_zones, m.t,
        within=NonNegativeReals)  # dispatched power from storage
    m.stor_charge = Var(m.stor_tech_in_zones, m.t,
                        within=NonNegativeReals)  # power to charge storage

    m.hyb_disp = Var(m.hyb_tech_in_zones, m.t,
                     within=NonNegativeReals)  # dispatched power from hybrid

    m.hyb_reserve = Var(
        m.hyb_tech_in_zones, m.t,
        within=NonNegativeReals)  # reserve capacity for hybrids

    m.hyb_charge = Var(m.hyb_tech_in_zones, m.t,
                       within=NonNegativeReals)  # charging power from hybrid

    m.stor_level = Var(m.stor_tech_in_zones, m.t,
                       within=NonNegativeReals)  # Charge level for storage

    m.hyb_level = Var(m.hyb_tech_in_zones, m.t,
                      within=NonNegativeReals)  # Charge level for storage

    m.unserved = Var(m.zones, m.t, within=NonNegativeReals)  # unserved power
    m.surplus = Var(m.zones, m.t,
                    within=NonNegativeReals)  # surplus power (if any)

    # Interconnector flow
    m.intercon_disp = Var(m.intercons_in_zones, m.t, within=NonNegativeReals)

    # @@ Constraints
    # Transmission limits
    m.con_max_trans = Constraint(m.intercons_in_zones, m.t, rule=con_max_trans)
    # Transmission capacity balance
    m.con_intercon_cap = Constraint(m.intercons_in_zones,
                                    rule=con_intercon_cap)
    # Load balance
    m.ldbal = Constraint(m.zones, m.t, rule=con_ldbal)
    # Dispatch to be within capacity, RE have variable capacity factors
    m.caplim = Constraint(m.gen_tech_in_zones, m.t, rule=con_caplim)
    # Limit maximum capacity to be built in each region and each technology
    m.maxcap = Constraint(m.gen_tech_in_zones, rule=con_maxcap)
    # gen_cap_op in existing period is previous gen_cap_op plus gen_cap_new
    m.con_gen_cap = Constraint(m.gen_tech_in_zones, rule=con_gen_cap)
    # MaxMWh limit
    m.con_max_mwh_per_zone = Constraint(m.gen_tech_in_zones,
                                        rule=con_max_mhw_per_zone)
    # MaxMWh limit (currently only for hydro)
    m.con_max_mwh_nem_wide = Constraint(m.all_tech, rule=con_max_mwh_nem_wide)
    # Slack constraint on exogenous retirement to prevent it to go nevative
    m.con_slackretire = Constraint(m.retire_gen_tech_in_zones,
                                   rule=con_slackretire)
    # Slack constraint on exogenous retirement to prevent it to go nevative
    m.con_slackbuild = Constraint(m.gen_tech_in_zones, rule=con_slackbuild)

    # linearised unit commitment constraints
    m.con_min_load_commit = Constraint(m.commit_gen_tech_in_zones,
                                       m.t,
                                       rule=con_min_load_commit)
    m.con_disp_ramp_down = Constraint(m.commit_gen_tech_in_zones,
                                      m.t,
                                      rule=con_disp_ramp_down)
    m.con_disp_ramp_up = Constraint(m.commit_gen_tech_in_zones,
                                    m.t,
                                    rule=con_disp_ramp_up)
    m.con_ramp_down_uptime = Constraint(m.commit_gen_tech_in_zones,
                                        m.t,
                                        rule=con_ramp_down_uptime)
    m.con_uptime_commitment = Constraint(m.commit_gen_tech_in_zones,
                                         m.t,
                                         rule=con_uptime_commitment)
    m.con_committed_cap = Constraint(m.commit_gen_tech_in_zones,
                                     m.t,
                                     rule=con_committed_cap)
    # NEM operating reserve constraint
    m.con_operating_reserve = Constraint(m.regions,
                                         m.t,
                                         rule=con_operating_reserve)
    # Hard constraint on unserved energy
    if unslim:
        m.con_uns = Constraint(m.regions, rule=con_uns)
    # Emmissions constraint
    if emitlimit:
        m.con_emissions = Constraint(rule=con_emissions)
        # maximum kg/MWh rate of total emissions
        m.nem_year_emit_limit = Param()
    # NEM wide RET constraint as a ratio
    if nem_ret_ratio:
        # NEM wide renewable energy target for current year
        m.nem_ret_ratio = Param(default=0)
        # NEM wide renewable energy constraint
        m.con_nem_ret_ratio = Constraint(rule=con_nem_ret_ratio)

# NEM wide RET constraint as a ratio
    if nem_ret_gwh:
        # NEM wide renewable energy target for current year
        m.nem_ret_gwh = Param(default=0)
        # NEM wide renewable energy constraint
        m.con_nem_ret_gwh = Constraint(rule=con_nem_ret_gwh)

    if region_ret_ratio:
        # Regional RET targets for current year
        m.region_ret_ratio = Param(m.regions, default=0)
        # Regional RET constraint
        m.con_region_ret = Constraint(m.regions, rule=con_region_ret_ratio)
    if nem_re_disp_ratio:
        # NEM wide minimum hour by our generation from "dispatchable" sources
        m.nem_re_disp_ratio = Param(default=0)
        # NEM wide minimum hourly dispatch from dispatchable sources constraint
        m.con_nem_re_disp_ratio = Constraint(m.regions,
                                             m.t,
                                             rule=con_nem_re_disp_ratio)

    # Storage charge/discharge dynamic
    m.StCharDis = Constraint(m.stor_tech_in_zones, m.t, rule=con_storcharge)
    # Maxiumum rate of storage charge
    m.con_stor_flow_lim = Constraint(m.stor_tech_in_zones,
                                     m.t,
                                     rule=con_stor_flow_lim)
    # Maxiumum rate of storage discharge
    m.con_stor_reserve_lim = Constraint(m.stor_tech_in_zones,
                                        m.t,
                                        rule=con_stor_reserve_lim)
    # Maxiumum charge capacity of storage
    m.MaxCharge = Constraint(m.stor_tech_in_zones, m.t, rule=con_maxcharge)
    # StCap in existing period is previous stor_cap_op plus stor_cap_new
    m.con_stor_cap = Constraint(m.stor_tech_in_zones, rule=con_stor_cap)

    # Hybrid charge/discharge dynamic
    m.HybCharDis = Constraint(m.hyb_tech_in_zones, m.t, rule=con_hybcharge)
    # Maxiumum level of hybrid storage discharge
    m.con_hyb_level_max = Constraint(m.hyb_tech_in_zones,
                                     m.t,
                                     rule=con_hyb_level_max)
    # Maxiumum rate of hybrid storage charge/discharge
    m.con_hyb_flow_lim = Constraint(m.hyb_tech_in_zones,
                                    m.t,
                                    rule=con_hyb_flow_lim)
    # Limit hybrid reserve capacity to be within storage level
    m.con_hyb_reserve_lim = Constraint(m.hyb_tech_in_zones,
                                       m.t,
                                       rule=con_hyb_reserve_lim)
    # Maxiumum charge capacity of storage
    m.MaxChargehy = Constraint(m.hyb_tech_in_zones, m.t, rule=con_maxchargehy)
    # HyCap in existing period is previous stor_cap_op plus stor_cap_new
    m.con_hyb_cap = Constraint(m.hyb_tech_in_zones, rule=con_hyb_cap)

    # @@ Objective
    # Minimise capital, variable and fixed costs of system
    m.FSCost = Expression(expr=0)
    m.SSCost = Expression(rule=obj_cost)
    # objective: minimise all other objectives
    m.Obj = Objective(expr=m.FSCost + m.SSCost)

    # Short run marginal prices
    m.dual = Suffix(direction=Suffix.IMPORT)
    return m
Пример #8
0
    def simple_recycle_model(self):
        m = ConcreteModel()
        m.comps = Set(initialize=["A", "B", "C"])

        # Feed
        m.feed = Block()

        m.feed.flow_out = Var(m.comps)
        m.feed.temperature_out = Var()
        m.feed.pressure_out = Var()

        m.feed.expr_var_idx_out = Var(m.comps)

        @m.feed.Expression(m.comps)
        def expr_idx_out(b, i):
            return -b.expr_var_idx_out[i]

        m.feed.expr_var_out = Var()
        m.feed.expr_out = -m.feed.expr_var_out

        @m.feed.Port()
        def outlet(b):
            return dict(flow=b.flow_out,
                        temperature=b.temperature_out,
                        pressure=b.pressure_out,
                        expr_idx=b.expr_idx_out,
                        expr=b.expr_out)

        def initialize_feed(self):
            pass

        m.feed.initialize = MethodType(initialize_feed, m.feed)

        # Mixer
        m.mixer = Block()

        m.mixer.flow_in_side_1 = Var(m.comps)
        m.mixer.temperature_in_side_1 = Var()
        m.mixer.pressure_in_side_1 = Var()

        m.mixer.expr_var_idx_in_side_1 = Var(m.comps)

        @m.mixer.Expression(m.comps)
        def expr_idx_in_side_1(b, i):
            return -b.expr_var_idx_in_side_1[i]

        m.mixer.expr_var_in_side_1 = Var()
        m.mixer.expr_in_side_1 = -m.mixer.expr_var_in_side_1

        m.mixer.flow_in_side_2 = Var(m.comps)
        m.mixer.temperature_in_side_2 = Var()
        m.mixer.pressure_in_side_2 = Var()

        m.mixer.expr_var_idx_in_side_2 = Var(m.comps)

        @m.mixer.Expression(m.comps)
        def expr_idx_in_side_2(b, i):
            return -b.expr_var_idx_in_side_2[i]

        m.mixer.expr_var_in_side_2 = Var()
        m.mixer.expr_in_side_2 = -m.mixer.expr_var_in_side_2

        m.mixer.flow_out = Var(m.comps)
        m.mixer.temperature_out = Var()
        m.mixer.pressure_out = Var()

        m.mixer.expr_var_idx_out = Var(m.comps)

        @m.mixer.Expression(m.comps)
        def expr_idx_out(b, i):
            return -b.expr_var_idx_out[i]

        m.mixer.expr_var_out = Var()
        m.mixer.expr_out = -m.mixer.expr_var_out

        @m.mixer.Port()
        def inlet_side_1(b):
            return dict(flow=b.flow_in_side_1,
                        temperature=b.temperature_in_side_1,
                        pressure=b.pressure_in_side_1,
                        expr_idx=b.expr_idx_in_side_1,
                        expr=b.expr_in_side_1)

        @m.mixer.Port()
        def inlet_side_2(b):
            return dict(flow=b.flow_in_side_2,
                        temperature=b.temperature_in_side_2,
                        pressure=b.pressure_in_side_2,
                        expr_idx=b.expr_idx_in_side_2,
                        expr=b.expr_in_side_2)

        @m.mixer.Port()
        def outlet(b):
            return dict(flow=b.flow_out,
                        temperature=b.temperature_out,
                        pressure=b.pressure_out,
                        expr_idx=b.expr_idx_out,
                        expr=b.expr_out)

        def initialize_mixer(self):
            for i in self.flow_out:
                self.flow_out[i].value = \
                    value(self.flow_in_side_1[i] + self.flow_in_side_2[i])
            for i in self.expr_var_idx_out:
                self.expr_var_idx_out[i].value = \
                    value(self.expr_var_idx_in_side_1[i] +
                        self.expr_var_idx_in_side_2[i])
            self.expr_var_out.value = \
                value(self.expr_var_in_side_1 + self.expr_var_in_side_2)
            assert self.temperature_in_side_1 == self.temperature_in_side_2
            self.temperature_out.value = value(self.temperature_in_side_1)
            assert self.pressure_in_side_1 == self.pressure_in_side_2
            self.pressure_out.value = value(self.pressure_in_side_1)

        m.mixer.initialize = MethodType(initialize_mixer, m.mixer)

        # Pass through
        m.unit = Block()

        m.unit.flow_in = Var(m.comps)
        m.unit.temperature_in = Var()
        m.unit.pressure_in = Var()

        m.unit.expr_var_idx_in = Var(m.comps)

        @m.unit.Expression(m.comps)
        def expr_idx_in(b, i):
            return -b.expr_var_idx_in[i]

        m.unit.expr_var_in = Var()
        m.unit.expr_in = -m.unit.expr_var_in

        m.unit.flow_out = Var(m.comps)
        m.unit.temperature_out = Var()
        m.unit.pressure_out = Var()

        m.unit.expr_var_idx_out = Var(m.comps)

        @m.unit.Expression(m.comps)
        def expr_idx_out(b, i):
            return -b.expr_var_idx_out[i]

        m.unit.expr_var_out = Var()
        m.unit.expr_out = -m.unit.expr_var_out

        @m.unit.Port()
        def inlet(b):
            return dict(flow=b.flow_in,
                        temperature=b.temperature_in,
                        pressure=b.pressure_in,
                        expr_idx=b.expr_idx_in,
                        expr=b.expr_in)

        @m.unit.Port()
        def outlet(b):
            return dict(flow=b.flow_out,
                        temperature=b.temperature_out,
                        pressure=b.pressure_out,
                        expr_idx=b.expr_idx_out,
                        expr=b.expr_out)

        def initialize_unit(self):
            for i in self.flow_out:
                self.flow_out[i].value = value(self.flow_in[i])
            for i in self.expr_var_idx_out:
                self.expr_var_idx_out[i].value = value(self.expr_var_idx_in[i])
            self.expr_var_out.value = value(self.expr_var_in)
            self.temperature_out.value = value(self.temperature_in)
            self.pressure_out.value = value(self.pressure_in)

        m.unit.initialize = MethodType(initialize_unit, m.unit)

        # Splitter
        m.splitter = Block()

        @m.splitter.Block(m.comps)
        def flow_in(b, i):
            b.flow = Var()

        m.splitter.temperature_in = Var()
        m.splitter.pressure_in = Var()

        m.splitter.expr_var_idx_in = Var(m.comps)

        @m.splitter.Expression(m.comps)
        def expr_idx_in(b, i):
            return -b.expr_var_idx_in[i]

        m.splitter.expr_var_in = Var()
        m.splitter.expr_in = -m.splitter.expr_var_in

        m.splitter.flow_out_side_1 = Var(m.comps)
        m.splitter.temperature_out_side_1 = Var()
        m.splitter.pressure_out_side_1 = Var()

        m.splitter.expr_var_idx_out_side_1 = Var(m.comps)

        @m.splitter.Expression(m.comps)
        def expr_idx_out_side_1(b, i):
            return -b.expr_var_idx_out_side_1[i]

        m.splitter.expr_var_out_side_1 = Var()
        m.splitter.expr_out_side_1 = -m.splitter.expr_var_out_side_1

        m.splitter.flow_out_side_2 = Var(m.comps)
        m.splitter.temperature_out_side_2 = Var()
        m.splitter.pressure_out_side_2 = Var()

        m.splitter.expr_var_idx_out_side_2 = Var(m.comps)

        @m.splitter.Expression(m.comps)
        def expr_idx_out_side_2(b, i):
            return -b.expr_var_idx_out_side_2[i]

        m.splitter.expr_var_out_side_2 = Var()
        m.splitter.expr_out_side_2 = -m.splitter.expr_var_out_side_2

        @m.splitter.Port()
        def inlet(b):
            return dict(flow=Reference(b.flow_in[:].flow),
                        temperature=b.temperature_in,
                        pressure=b.pressure_in,
                        expr_idx=b.expr_idx_in,
                        expr=b.expr_in)

        @m.splitter.Port()
        def outlet_side_1(b):
            return dict(flow=b.flow_out_side_1,
                        temperature=b.temperature_out_side_1,
                        pressure=b.pressure_out_side_1,
                        expr_idx=b.expr_idx_out_side_1,
                        expr=b.expr_out_side_1)

        @m.splitter.Port()
        def outlet_side_2(b):
            return dict(flow=b.flow_out_side_2,
                        temperature=b.temperature_out_side_2,
                        pressure=b.pressure_out_side_2,
                        expr_idx=b.expr_idx_out_side_2,
                        expr=b.expr_out_side_2)

        def initialize_splitter(self):
            recycle = 0.1
            prod = 1 - recycle
            for i in self.flow_in:
                self.flow_out_side_1[i].value \
                    = prod * value(self.flow_in[i].flow)
                self.flow_out_side_2[i].value \
                    = recycle * value(self.flow_in[i].flow)
            for i in self.expr_var_idx_in:
                self.expr_var_idx_out_side_1[i].value = \
                    prod * value(self.expr_var_idx_in[i])
                self.expr_var_idx_out_side_2[i].value = \
                    recycle * value(self.expr_var_idx_in[i])
            self.expr_var_out_side_1.value = prod * value(self.expr_var_in)
            self.expr_var_out_side_2.value = recycle * value(self.expr_var_in)
            self.temperature_out_side_1.value = value(self.temperature_in)
            self.temperature_out_side_2.value = value(self.temperature_in)
            self.pressure_out_side_1.value = value(self.pressure_in)
            self.pressure_out_side_2.value = value(self.pressure_in)

        m.splitter.initialize = MethodType(initialize_splitter, m.splitter)

        # Prod
        m.prod = Block()

        m.prod.flow_in = Var(m.comps)
        m.prod.temperature_in = Var()
        m.prod.pressure_in = Var()

        m.prod.actual_var_idx_in = Var(m.comps)
        m.prod.actual_var_in = Var()

        @m.prod.Port()
        def inlet(b):
            return dict(flow=b.flow_in,
                        temperature=b.temperature_in,
                        pressure=b.pressure_in,
                        expr_idx=b.actual_var_idx_in,
                        expr=b.actual_var_in)

        def initialize_prod(self):
            pass

        m.prod.initialize = MethodType(initialize_prod, m.prod)

        # Arcs
        @m.Arc(directed=True)
        def stream_feed_to_mixer(m):
            return (m.feed.outlet, m.mixer.inlet_side_1)

        @m.Arc(directed=True)
        def stream_mixer_to_unit(m):
            return (m.mixer.outlet, m.unit.inlet)

        @m.Arc(directed=True)
        def stream_unit_to_splitter(m):
            return (m.unit.outlet, m.splitter.inlet)

        @m.Arc(directed=True)
        def stream_splitter_to_mixer(m):
            return (m.splitter.outlet_side_2, m.mixer.inlet_side_2)

        @m.Arc(directed=True)
        def stream_splitter_to_prod(m):
            return (m.splitter.outlet_side_1, m.prod.inlet)

        # Expand Arcs
        TransformationFactory("network.expand_arcs").apply_to(m)

        # Fix Feed
        m.feed.flow_out['A'].fix(100)
        m.feed.flow_out['B'].fix(200)
        m.feed.flow_out['C'].fix(300)
        m.feed.expr_var_idx_out['A'].fix(10)
        m.feed.expr_var_idx_out['B'].fix(20)
        m.feed.expr_var_idx_out['C'].fix(30)
        m.feed.expr_var_out.fix(40)
        m.feed.temperature_out.fix(450)
        m.feed.pressure_out.fix(128)

        return m
Пример #9
0
    def build(self):
        '''
        Callable method for Block construction.
        '''
        super(BTParameterData, self).build()

        self.cubic_type = CubicEoS.PR

        # Add Component objects
        self.benzene = Component()
        self.toluene = Component()

        # List of phase equilibrium index
        self.phase_equilibrium_idx = Set(initialize=[1, 2])

        self.phase_equilibrium_list = \
            {1: ["benzene", ("Vap", "Liq")],
             2: ["toluene", ("Vap", "Liq")]}

        # Thermodynamic reference state
        self.pressure_ref = Param(mutable=True,
                                  default=101325,
                                  doc='Reference pressure [Pa]',
                                  units=pyunits.Pa)
        self.temperature_ref = Param(mutable=True,
                                     default=298.15,
                                     doc='Reference temperature [K]',
                                     units=pyunits.K)

        # Critical Properties
        pressure_crit_data = {'benzene': 48.9e5, 'toluene': 41.0e5}

        self.pressure_crit = Param(self.component_list,
                                   within=NonNegativeReals,
                                   mutable=False,
                                   initialize=extract_data(pressure_crit_data),
                                   doc='Critical pressure [Pa]',
                                   units=pyunits.Pa)

        temperature_crit_data = {'benzene': 562.2, 'toluene': 591.8}

        self.temperature_crit = Param(
            self.component_list,
            within=NonNegativeReals,
            mutable=False,
            initialize=extract_data(temperature_crit_data),
            doc='Critical temperature [K]',
            units=pyunits.K)

        # Pitzer acentricity factor
        omega_data = {'benzene': 0.212, 'toluene': 0.263}

        self.omega = Param(self.component_list,
                           within=Reals,
                           mutable=False,
                           initialize=extract_data(omega_data),
                           doc='Acentricity Factor')

        # Peng-Robinson binary interaction parameters
        kappa_data = {
            ('benzene', 'benzene'): 0.0000,
            ('benzene', 'toluene'): 0.0000,
            ('toluene', 'benzene'): 0.0000,
            ('toluene', 'toluene'): 0.0000
        }

        self.kappa = Param(self.component_list,
                           self.component_list,
                           within=Reals,
                           mutable=False,
                           initialize=extract_data(kappa_data),
                           doc='Peng-Robinson binary interaction parameters')

        # Molecular Weights
        mw_comp_data = {'benzene': 78.1136E-3, 'toluene': 92.1405E-3}

        self.mw_comp = Param(self.component_list,
                             mutable=False,
                             initialize=extract_data(mw_comp_data),
                             doc="molecular weight kg/mol",
                             units=pyunits.kg / pyunits.mol)

        # Constants for specific heat capacity, enthalpy and entropy
        self.cp_mol_ig_comp_coeff_1 = Param(
            self.component_list,
            mutable=False,
            initialize={
                'benzene': -3.392E1,
                'toluene': -2.435E1
            },
            doc="Parameter 1 to compute cp_mol_comp",
            units=pyunits.J / pyunits.mol / pyunits.K)

        self.cp_mol_ig_comp_coeff_2 = Param(
            self.component_list,
            mutable=False,
            initialize={
                'benzene': 4.739E-1,
                'toluene': 5.125E-1
            },
            doc="Parameter 2 to compute cp_mol_comp",
            units=pyunits.J / pyunits.mol / pyunits.K**2)

        self.cp_mol_ig_comp_coeff_3 = Param(
            self.component_list,
            mutable=False,
            initialize={
                'benzene': -3.017E-4,
                'toluene': -2.765E-4
            },
            doc="Parameter 3 to compute cp_mol_comp",
            units=pyunits.J / pyunits.mol / pyunits.K**3)

        self.cp_mol_ig_comp_coeff_4 = Param(
            self.component_list,
            mutable=False,
            initialize={
                'benzene': 7.130E-8,
                'toluene': 4.911E-8
            },
            doc="Parameter 4 to compute cp_mol_comp",
            units=pyunits.J / pyunits.mol / pyunits.K**4)

        # Standard heats of formation
        # Source: NIST Webbook, https://webbook.nist.gov
        # Retrieved 25th September 2019
        dh_form_data = {'benzene': 82.9e3, 'toluene': 50.1e3}

        self.enth_mol_form_ref = Param(self.component_list,
                                       mutable=False,
                                       initialize=extract_data(dh_form_data),
                                       doc="Standard heats of formation",
                                       units=pyunits.J / pyunits.mol)

        # Standard entropy of formation
        # Source: Engineering Toolbox, https://www.engineeringtoolbox.com
        # Retrieved 25th September, 2019
        ds_form_data = {'benzene': -269, 'toluene': -321}

        self.entr_mol_form_ref = Param(self.component_list,
                                       mutable=False,
                                       initialize=extract_data(ds_form_data),
                                       doc="Standard entropy of formation",
                                       units=pyunits.J / pyunits.mol /
                                       pyunits.K)

        # Antoine coefficients for ideal vapour (units: bar, K)
        # This is needed for initial guesses of bubble and dew points
        self.antoine_coeff_A = Param(
            self.component_list,
            mutable=False,
            initialize={
                'benzene': 4.202,
                'toluene': 4.216
            },
            doc="Antoine A Parameter to calculate pressure_sat",
            units=pyunits.dimensionless)

        self.antoine_coeff_B = Param(
            self.component_list,
            mutable=False,
            initialize={
                'benzene': 1322,
                'toluene': 1435
            },
            doc="Antoine B Parameter to calculate pressure_sat",
            units=pyunits.K)

        self.antoine_coeff_C = Param(
            self.component_list,
            mutable=False,
            initialize={
                'benzene': -38.56,
                'toluene': -43.33
            },
            doc="Antoine C Parameter to calculate pressure_sat",
            units=pyunits.K)
Пример #10
0
def _setup_mccormick(b, nsegs, indx):
    if not hasattr(b, 'mccormick_cuts'):
        b.mccormick_cuts = Set(initialize=['lb1', 'lb2', 'ub1', 'ub2'])
    if not hasattr(b, 'sets'):
        if indx is None:
            b.sets = Set()
        elif isinstance(indx, tuple):
            b.sets = Set(dimen=len(indx))
        else:
            b.sets = Set(dimen=1)
    if indx is not None and indx not in b.sets:
        # Presumably I would need to add indices to this set, but
        # apparently it's complaining when I do, so I'm not.
        # b.sets.add(indx)
        pass
    if not hasattr(b, 'constr'):
        if indx is not None:
            b.constr = Constraint(b.sets, b.mccormick_cuts)
        else:
            b.constr = Constraint(b.mccormick_cuts)
    if not hasattr(b, 'segs'):
        b.segs = RangeSet(nsegs)
    else:
        if nsegs != len(b.segs):
            raise ValueError(
                'We do not currently support different segment counts within the same set of McCormick relaxations.'
            )
    if not hasattr(b, 'xbar'):
        if indx is not None:
            b.xbar = Var(b.sets, initialize=0)
        else:
            b.xbar = Var(initialize=0)
    if not hasattr(b, 'delta_y'):
        if indx is not None:
            b.delta_y = Var(b.sets,
                            b.segs,
                            domain=NonNegativeReals,
                            initialize=0)
        else:
            b.delta_y = Var(b.segs, domain=NonNegativeReals, initialize=0)
    if not hasattr(b, 'lbda'):
        if indx is not None:
            b.lbda = Var(b.sets, b.segs, domain=Binary)
        else:
            b.lbda = Var(b.segs, domain=Binary)
    if not hasattr(b, 'x_defn'):
        if indx is not None:
            b.x_defn = Constraint(b.sets, ['lb', 'ub'])
        else:
            b.x_defn = Constraint(['lb', 'ub'])
    if not hasattr(b, 'xbar_defn'):
        if indx is not None:
            b.xbar_defn = Constraint(b.sets, ['lb1', 'lb2', 'ub1', 'ub2'])
        else:
            b.xbar_defn = Constraint(['lb1', 'lb2', 'ub1', 'ub2'])
    if not hasattr(b, 'y_defn'):
        if indx is not None:
            b.y_defn = Constraint(b.sets, ['lb', 'ub'])
        else:
            b.y_defn = Constraint(['lb', 'ub'])
    if not hasattr(b, 'dy_ub'):
        if indx is not None:
            b.dy_ub = Constraint(b.sets, b.segs)
        else:
            b.dy_ub = Constraint(b.segs)
    if not hasattr(b, 'lbda_defn'):
        if indx is not None:
            b.lbda_defn = Constraint(b.sets)
        else:
            b.lbda_defn = Constraint()
    b.xbar._index.add(indx)
    for s in b.segs:
        # b.delta_y._index.add((indx, s))
        b.delta_y.add(squish(_concat(indx, s)))
        # b.lbda._index.add(indx)
        b.lbda.add(squish(_concat(indx, s)))
Пример #11
0
    def extensive_recycle_model(self):
        def build_in_out(b):
            b.flow_in = Var(m.comps)
            b.mass_in = Var()
            b.temperature_in = Var()
            b.pressure_in = Var()

            b.expr_var_idx_in = Var(m.comps)

            @b.Expression(m.comps)
            def expr_idx_in(b, i):
                return -b.expr_var_idx_in[i]

            b.expr_var_in = Var()
            b.expr_in = -b.expr_var_in

            b.flow_out = Var(m.comps)
            b.mass_out = Var()
            b.temperature_out = Var()
            b.pressure_out = Var()

            b.expr_var_idx_out = Var(m.comps)

            @b.Expression(m.comps)
            def expr_idx_out(b, i):
                return -b.expr_var_idx_out[i]

            b.expr_var_out = Var()
            b.expr_out = -b.expr_var_out

            b.inlet = Port(rule=inlet)
            b.outlet = Port(rule=outlet)

            b.initialize = MethodType(initialize, b)

        def inlet(b):
            return dict(flow=(b.flow_in, Port.Extensive),
                        mass=(b.mass_in, Port.Extensive),
                        temperature=b.temperature_in,
                        pressure=b.pressure_in,
                        expr_idx=(b.expr_idx_in, Port.Extensive),
                        expr=(b.expr_in, Port.Extensive))

        def outlet(b):
            return dict(flow=(b.flow_out, Port.Extensive),
                        mass=(b.mass_out, Port.Extensive),
                        temperature=b.temperature_out,
                        pressure=b.pressure_out,
                        expr_idx=(b.expr_idx_out, Port.Extensive),
                        expr=(b.expr_out, Port.Extensive))

        def initialize(self):
            for i in self.flow_out:
                self.flow_out[i].value = value(self.flow_in[i])
            self.mass_out.value = value(self.mass_in)
            for i in self.expr_var_idx_out:
                self.expr_var_idx_out[i].value = value(self.expr_var_idx_in[i])
            self.expr_var_out.value = value(self.expr_var_in)
            self.temperature_out.value = value(self.temperature_in)
            self.pressure_out.value = value(self.pressure_in)

        def nop(self):
            pass

        m = ConcreteModel()
        m.comps = Set(initialize=["A", "B", "C"])

        # Feed
        m.feed = Block()

        m.feed.flow_out = Var(m.comps)
        m.feed.mass_out = Var()
        m.feed.temperature_out = Var()
        m.feed.pressure_out = Var()

        m.feed.expr_var_idx_out = Var(m.comps)

        @m.feed.Expression(m.comps)
        def expr_idx_out(b, i):
            return -b.expr_var_idx_out[i]

        m.feed.expr_var_out = Var()
        m.feed.expr_out = -m.feed.expr_var_out

        m.feed.outlet = Port(rule=outlet)

        m.feed.initialize = MethodType(nop, m.feed)

        # Mixer
        m.mixer = Block()
        build_in_out(m.mixer)

        # Pass through
        m.unit = Block()
        build_in_out(m.unit)

        # Splitter
        m.splitter = Block()
        build_in_out(m.splitter)

        # Prod
        m.prod = Block()

        m.prod.flow_in = Var(m.comps)
        m.prod.mass_in = Var()
        m.prod.temperature_in = Var()
        m.prod.pressure_in = Var()

        m.prod.actual_var_idx_in = Var(m.comps)
        m.prod.actual_var_in = Var()

        @m.prod.Port()
        def inlet(b):
            return dict(flow=(b.flow_in, Port.Extensive),
                        mass=(b.mass_in, Port.Extensive),
                        temperature=b.temperature_in,
                        pressure=b.pressure_in,
                        expr_idx=(b.actual_var_idx_in, Port.Extensive),
                        expr=(b.actual_var_in, Port.Extensive))

        m.prod.initialize = MethodType(nop, m.prod)

        # Arcs
        @m.Arc(directed=True)
        def stream_feed_to_mixer(m):
            return (m.feed.outlet, m.mixer.inlet)

        @m.Arc(directed=True)
        def stream_mixer_to_unit(m):
            return (m.mixer.outlet, m.unit.inlet)

        @m.Arc(directed=True)
        def stream_unit_to_splitter(m):
            return (m.unit.outlet, m.splitter.inlet)

        @m.Arc(directed=True)
        def stream_splitter_to_mixer(m):
            return (m.splitter.outlet, m.mixer.inlet)

        @m.Arc(directed=True)
        def stream_splitter_to_prod(m):
            return (m.splitter.outlet, m.prod.inlet)

        # Split Fraction
        rec = 0.1
        prod = 1 - rec
        m.splitter.outlet.set_split_fraction(m.stream_splitter_to_mixer, rec)
        m.splitter.outlet.set_split_fraction(m.stream_splitter_to_prod, prod)

        # Expand Arcs
        TransformationFactory("network.expand_arcs").apply_to(m)

        # Fix Feed
        m.feed.flow_out['A'].fix(100)
        m.feed.flow_out['B'].fix(200)
        m.feed.flow_out['C'].fix(300)
        m.feed.mass_out.fix(400)
        m.feed.expr_var_idx_out['A'].fix(10)
        m.feed.expr_var_idx_out['B'].fix(20)
        m.feed.expr_var_idx_out['C'].fix(30)
        m.feed.expr_var_out.fix(40)
        m.feed.temperature_out.fix(450)
        m.feed.pressure_out.fix(128)

        return m
Пример #12
0
def build_rect_strip_packing_model():
    """Build the strip packing model."""
    model = ConcreteModel(name="Rectangles strip packing")
    model.rectangles = Set(ordered=True, initialize=[0, 1, 2, 3, 4, 5, 6, 7])

    # Width and Length of each rectangle
    model.rect_width = Param(
        model.rectangles, initialize={0: 3, 1: 3, 2: 2, 3: 2, 4: 3, 5: 5,
                                      6: 7, 7: 7})
    # parameter indexed by each rectangle
    # same as height?
    model.rect_length = Param(
        model.rectangles, initialize={0: 4, 1: 3, 2: 2, 3: 2, 4: 3, 5: 3,
                                      6: 4, 7: 4})

    model.strip_width = Param(
        initialize=10, doc="Available width of the strip")

    # upperbound on length (default is sum of lengths of rectangles)
    model.max_length = Param(
        initialize=sum(model.rect_length[i] for i in model.rectangles),
        doc="maximum length of the strip (if all rectangles were arranged "
        "lengthwise)")

    # x (length) and y (width) coordinates of each of the rectangles
    model.x = Var(model.rectangles,
                  bounds=(0, model.max_length),
                  doc="rectangle corner x-position (position across length)")

    def w_bounds(m, i):
        return (0, m.strip_width - m.rect_width[i])
    model.y = Var(model.rectangles,
                  bounds=w_bounds,
                  doc="rectangle corner y-position (position down width)")

    model.strip_length = Var(
        within=NonNegativeReals, doc="Length of strip required.")

    def rec_pairs_filter(model, i, j):
        return i < j
    model.overlap_pairs = Set(
        initialize=model.rectangles * model.rectangles,
        dimen=2, filter=rec_pairs_filter,
        doc="set of possible rectangle conflicts")

    @model.Constraint(model.rectangles)
    def strip_ends_after_last_rec(model, i):
        return model.strip_length >= model.x[i] + model.rect_length[i]

    model.total_length = Objective(expr=model.strip_length,
                                   doc="Minimize length")

    @model.Disjunction(
        model.overlap_pairs,
        doc="Make sure that none of the rectangles on the strip overlap in "
        "either the x or y dimensions.")
    def no_overlap(m, i, j):
        return [
            m.x[i] + m.rect_length[i] <= m.x[j],
            m.x[j] + m.rect_length[j] <= m.x[i],
            m.y[i] + m.rect_width[i] <= m.y[j],
            m.y[j] + m.rect_width[j] <= m.y[i],
        ]

    return model
Пример #13
0
def add_model_components(m, d, scenario_directory, subproblem, stage):
    """
     The following Pyomo model components are defined in this module:

    +-------------------------------------------------------------------------+
    | Sets                                                                    |
    +=========================================================================+
    | | :code:`STOR_SPEC_OPR_PRDS`                                            |
    |                                                                         |
    | Two-dimensional set of project-period combinations that helps describe  |
    | the project capacity available in a given period. This set is added to  |
    | the list of sets to join to get the final :code:`PRJ_OPR_PRDS` set      |
    | defined in **gridpath.project.capacity.capacity**.                      |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Required Input Params                                                   |
    +=========================================================================+
    | | :code:`stor_spec_power_capacity_mw`                                   |
    | | *Defined over*: :code:`STOR_SPEC_OPR_PRDS`                            |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The storage project's specified power capacity (in MW) in each          |
    | operational period.                                                     |
    +-------------------------------------------------------------------------+
    | | :code:`stor_spec_energy_capacity_mwh`                                 |
    | | *Defined over*: :code:`STOR_SPEC_OPR_PRDS`                            |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The storage project's specified energy capacity (in MWh) in each        |
    | operational period.                                                     |
    +-------------------------------------------------------------------------+
    | | :code:`stor_spec_fixed_cost_per_mw_yr`                                |
    | | *Defined over*: :code:`STOR_SPEC_OPR_PRDS`                            |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The storage project's fixed cost for the power components (in $ per     |
    | MW-yr.) in each operational period. This cost will be added to the      |
    | objective function but will not affect optimization decisions.          |
    +-------------------------------------------------------------------------+
    | | :code:`stor_spec_fixed_cost_per_mwh_yr`                               |
    | | *Defined over*: :code:`STOR_SPEC_OPR_PRDS`                            |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The storage project's fixed cost for the energy components (in $ per    |
    | MWh-yr.) in each operational period. This cost will be added to the     |
    | objective function but will not affect optimization decisions.          |
    +-------------------------------------------------------------------------+

    """

    # Sets
    ###########################################################################

    m.STOR_SPEC_OPR_PRDS = Set(dimen=2)

    # Required Params
    ###########################################################################

    m.stor_spec_power_capacity_mw = Param(m.STOR_SPEC_OPR_PRDS,
                                          within=NonNegativeReals)

    m.stor_spec_energy_capacity_mwh = Param(m.STOR_SPEC_OPR_PRDS,
                                            within=NonNegativeReals)

    m.stor_spec_fixed_cost_per_mw_yr = Param(m.STOR_SPEC_OPR_PRDS,
                                             within=NonNegativeReals)

    m.stor_spec_fixed_cost_per_mwh_yr = Param(m.STOR_SPEC_OPR_PRDS,
                                              within=NonNegativeReals)

    # Dynamic Components
    ###########################################################################

    # Add to list of sets we'll join to get the final
    # PRJ_OPR_PRDS set
    getattr(d, capacity_type_operational_period_sets).append(
        "STOR_SPEC_OPR_PRDS", )

    # Add to list of sets we'll join to get the final
    # STOR_OPR_PRDS set
    getattr(d, storage_only_capacity_type_operational_period_sets).append(
        "STOR_SPEC_OPR_PRDS", )
Пример #14
0
    def __init__(self, y, x, orient):
        """DEA model

        Args:
            y (float): output variable.
            x (float): input variables.
            orient (String): ORIENT_IO (input orientation) or ORIENT_OO (output orientation)
        """
        # TODO(error/warning handling): Check the configuration of the model exist
        self.x = x.tolist()
        self.y = y.tolist()
        self.orient = orient

        if type(self.x[0]) != list:
            self.x = []
            for x_value in x.tolist():
                self.x.append([x_value])

        if type(self.y[0]) != list:
            self.y = []
            for y_value in y.tolist():
                self.y.append([y_value])

        # Initialize DEA model
        self.__model__ = ConcreteModel()

        # Initialize sets
        self.__model__.I = Set(initialize=range(len(self.y)))
        self.__model__.J = Set(initialize=range(len(self.x[0])))
        self.__model__.K = Set(initialize=range(len(self.y[0])))

        # Initialize variable
        self.__model__.theta = Var(self.__model__.I, doc='efficiency')
        self.__model__.lamda = Var(self.__model__.I,
                                   self.__model__.I,
                                   within=Binary,
                                   doc='intensity variables')

        # Setup the objective function and constraints
        if self.orient == ORIENT_IO:
            self.__model__.objective = Objective(rule=self.__objective_rule(),
                                                 sense=minimize,
                                                 doc='objective function')
        else:
            self.__model__.objective = Objective(rule=self.__objective_rule(),
                                                 sense=maximize,
                                                 doc='objective function')
        self.__model__.input = Constraint(self.__model__.I,
                                          self.__model__.J,
                                          rule=self.__input_rule(),
                                          doc='input constraint')
        self.__model__.output = Constraint(self.__model__.I,
                                           self.__model__.K,
                                           rule=self.__output_rule(),
                                           doc='output constraint')
        self.__model__.vrs = Constraint(self.__model__.I,
                                        rule=self.__vrs_rule(),
                                        doc='various return to scale rule')

        # Optimize model
        self.optimization_status = 0
        self.problem_status = 0
Пример #15
0
 def Xtest_pyomo_Set_domain_duplicates(self):
     with self.assertRaises(ValueError) as cm:
         self.model = ConcreteModel()
         self.model.s = Set(initialize=[1.7, 2, 3])
         self.model.y = Var([1, 2], within=self.model.s)
Пример #16
0
def add_model_components(m, d, scenario_directory, subproblem, stage):
    """
    The following Pyomo model components are defined in this module:

    +-------------------------------------------------------------------------+
    | Sets                                                                    |
    +=========================================================================+
    | | :code:`GEN_NEW_BIN`                                                   |
    |                                                                         |
    | Two-dimensional set of project-vintage combinations to describe all     |
    | possible project-vintage combinations for projects with a cumulative    |
    | minimum build capacity specified.                                       |
    +-------------------------------------------------------------------------+
    | | :code:`GEN_NEW_BIN_VNTS`                                              |
    |                                                                         |
    | A two-dimensional set of project-vintage combinations to describe the   |
    | periods in time when project capacity can be built in the optimization. |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Required Input Params                                                   |
    +=========================================================================+
    | | :code:`gen_new_bin_lifetime_yrs_by_vintage`                           |
    | | *Defined over*: :code:`GEN_NEW_BIN_VNTS`                              |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The project's lifetime, i.e. how long project capacity of a particular  |
    | vintage remains operational.                                            |
    +-------------------------------------------------------------------------+
    | | :code:`gen_new_bin_annualized_real_cost_per_mw_yr`                    |
    | | *Defined over*: :code:`GEN_NEW_BIN_VNTS`                              |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The project's cost to build new capacity in annualized real dollars per |
    | MW.                                                                     |
    +-------------------------------------------------------------------------+
    | | :code:`gen_new_bin_build_size_mw`                                     |
    | | *Defined over*: :code:`GEN_NEW_BIN`                                   |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The project's specified build size in MW. The model can only build the  |
    | project in this pre-specified size.                                     |
    +-------------------------------------------------------------------------+

    .. note:: The cost input to the model is a levelized cost per unit
        capacity. This annualized cost is incurred in each period of the study
        (and multiplied by the number of years the period represents) for
        the duration of the project's lifetime. It is up to the user to
        ensure that the :code:`gen_new_bin_lifetime_yrs_by_vintage` and
        :code:`gen_new_bin_annualized_real_cost_per_mw_yr` parameters are
        consistent.

    +-------------------------------------------------------------------------+
    | Derived Sets                                                            |
    +=========================================================================+
    | | :code:`OPR_PRDS_BY_GEN_NEW_BIN_VINTAGE`                               |
    | | *Defined over*: :code:`GEN_NEW_BIN_VNTS`                              |
    |                                                                         |
    | Indexed set that describes the operational periods for each possible    |
    | project-vintage combination, based on the                               |
    | :code:`gen_new_bin_lifetime_yrs_by_vintage`. For instance, capacity of  |
    | the 2020 vintage with lifetime of 30 years will be assumed operational  |
    | starting Jan 1, 2020 and through Dec 31, 2049, but will *not* be        |
    | operational in 2050.                                                    |
    +-------------------------------------------------------------------------+
    | | :code:`GEN_NEW_BIN_OPR_PRDS`                                          |
    |                                                                         |
    | Two-dimensional set that includes the periods when project capacity of  |
    | any vintage *could* be operational if built. This set is added to the   |
    | list of sets to join to get the final :code:`PRJ_OPR_PRDS` set defined  |
    | in **gridpath.project.capacity.capacity**.                              |
    +-------------------------------------------------------------------------+
    | | :code:`GEN_NEW_BIN_VNTS_OPR_IN_PERIOD`                                |
    | | *Defined over*: :code:`PERIODS`                                       |
    |                                                                         |
    | Indexed set that describes the project-vintages that could be           |
    | operational in each period based on the                                 |
    | :code:`gen_new_bin_lifetime_yrs_by_vintage`.                            |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Variables                                                               |
    +=========================================================================+
    | | :code:`GenNewBin_Build`                                               |
    | | *Defined over*: :code:`GEN_NEW_BIN_VNTS`                              |
    | | *Within*: :code:`Binary          `                                    |
    |                                                                         |
    | Binary build decision for each project-vintage combination (1=build).   |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Constraints                                                             |
    +=========================================================================+
    | | :code:`GenNewBin_Only_Build_Once_Constraint`                          |
    | | *Defined over*: :code:`GEN_NEW_BIN_OPR_PRDS`                          |
    |                                                                         |
    | Once a project is built, it cannot be built again in another vintage    |
    | until its lifetime is expired.                                          |
    +-------------------------------------------------------------------------+

    """

    # Sets
    ###########################################################################

    m.GEN_NEW_BIN = Set(
        within=m.PROJECTS
    )

    m.GEN_NEW_BIN_VNTS = Set(
        dimen=2, within=m.PROJECTS*m.PERIODS
    )

    # Required Params
    ###########################################################################

    m.gen_new_bin_lifetime_yrs_by_vintage = Param(
        m.GEN_NEW_BIN_VNTS,
        within=NonNegativeReals
    )

    m.gen_new_bin_annualized_real_cost_per_mw_yr = Param(
        m.GEN_NEW_BIN_VNTS,
        within=NonNegativeReals
    )

    m.gen_new_bin_build_size_mw = Param(
        m.GEN_NEW_BIN,
        within=NonNegativeReals
    )

    # Derived Sets
    ###########################################################################

    m.OPR_PRDS_BY_GEN_NEW_BIN_VINTAGE = Set(
        m.GEN_NEW_BIN_VNTS,
        initialize=operational_periods_by_generator_vintage
    )

    m.GEN_NEW_BIN_OPR_PRDS = Set(
        dimen=2,
        initialize=gen_new_bin_operational_periods
    )

    m.GEN_NEW_BIN_VNTS_OPR_IN_PERIOD = Set(
        m.PERIODS, dimen=2,
        initialize=gen_new_bin_vintages_operational_in_period
    )

    # Variables
    ###########################################################################

    m.GenNewBin_Build = Var(
        m.GEN_NEW_BIN_VNTS,
        within=Binary
    )

    # Constraints
    ###########################################################################

    m.GenNewBin_Only_Build_Once_Constraint = Constraint(
        m.GEN_NEW_BIN_OPR_PRDS,
        rule=only_build_once_rule
    )

    # Dynamic Components
    ###########################################################################

    # Add to list of sets we'll join to get the final
    # PRJ_OPR_PRDS set
    getattr(d, capacity_type_operational_period_sets).append(
        "GEN_NEW_BIN_OPR_PRDS",
    )
Пример #17
0
    def build(self):
        '''
        Callable method for Block construction.
        '''
        super(PhysicalParameterData, self).build()

        self.state_block_class = IdealStateBlock

        # List of valid phases in property package
        # List of valid phases in property package
        if self.config.valid_phase == ('Liq', 'Vap') or \
                self.config.valid_phase == ('Vap', 'Liq'):
            self.phase_list = Set(initialize=['Liq', 'Vap'], ordered=True)
        elif self.config.valid_phase == 'Liq':
            self.phase_list = Set(initialize=['Liq'])
        else:
            self.phase_list = Set(initialize=['Vap'])

        self.component_list = Set(initialize=['CH4', 'CO', 'H2', 'CH3OH'])

        # List of components in each phase (optional)
        self.phase_comp = {
            "Liq": self.component_list,
            "Vap": self.component_list
        }

        self.phase_equilibrium_idx = Set(initialize=[1, 2, 3, 4])

        self.phase_equilibrium_list = \
            {1: ["CH4", ("Vap", "Liq")],
             2: ["CO", ("Vap", "Liq")],
             3: ["H2", ("Vap", "Liq")],
             4: ["CH3OH", ("Vap", "Liq")]}

        # Gas Constant
        self.gas_constant = Param(within=NonNegativeReals,
                                  mutable=False,
                                  default=0.008314,
                                  doc='Gas Constant [MJ/(kgmol.K)]')

        self.vapor_pressure_coeff = {
            ('CH4', 'A'): 15.2243,
            ('CH4', 'B'): 897.84,
            ('CH4', 'C'): -7.16,
            ('CO', 'A'): 14.3686,
            ('CO', 'B'): 530.22,
            ('CO', 'C'): -13.15,
            ('H2', 'A'): 13.6333,
            ('H2', 'B'): 164.9,
            ('H2', 'C'): 3.19,
            ('CH3OH', 'A'): 18.5875,
            ('CH3OH', 'B'): 3626.55,
            ('CH3OH', 'C'): -34.29
        }

        Cp = self.config.Cp
        Cv = Cp - self.gas_constant.value
        gamma = Cp / Cv

        self.gamma = Param(within=NonNegativeReals,
                           mutable=True,
                           default=gamma,
                           doc='Ratio of Cp to Cv')

        self.Cp = Param(within=NonNegativeReals,
                        mutable=True,
                        default=Cp,
                        doc='Constant pressure heat capacity [MJ/(kgmol K)]')
Пример #18
0
def add_model_components(m, d, scenario_directory, subproblem, stage):
    """
    The following Pyomo model components are defined in this module:

    +-------------------------------------------------------------------------+
    | Sets                                                                    |
    +=========================================================================+
    | | :code:`BLN_TYPE_HRZS`                                                 |
    |                                                                         |
    | Two dimensional set of balancing types and their associated horizons.   |
    | Balancing types are strings, e.g. year, month, week, day, whereas       |
    | horizons must be non-negative integers.                                 |
    +-------------------------------------------------------------------------+
    | | :code:`TMPS_BY_BLN_TYPE_HRZ`                                          |
    | | *Defined over*: :code:`BLN_TYPE_HRZS`                                 |
    |                                                                         |
    | Ordered, indexed set that describes the the horizons associated with    |
    | each balancing type. The timepoins within a horizon-balancing type      |
    | are ordered.                                                            |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Derived Sets                                                            |
    +=========================================================================+
    | | :code:`BLN_TYPES`                                                     |
    |                                                                         |
    | The list of all balancing types.                                        |
    +-------------------------------------------------------------------------+
    | | :code:`HRZS_BY_BLN_TYPE`                                              |
    | | *Defined over*: :code:`BLN_TYPES`                                     |
    |                                                                         |
    | Ordered, indexed set that describes the horizons associated with        |
    | each balancing type. The horizons within a balancing type are ordered.  |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Required Input Params                                                   |
    +=========================================================================+
    | | :code:`horizon`                                                       |
    | | *Defined over*: :code:`TMPS x BLN_TYPES`                              |
    |                                                                         |
    | Describes the horizon that each timeoint belongs to for a given         |
    | balancing type. Depending on the balancing type, timepoints can be      |
    | grouped in different horizons.                                          |
    +-------------------------------------------------------------------------+
    | | :code:`boundary`                                                      |
    | | *Defined over*: :code:`BLN_TYPE_HRZS`                                 |
    | | *Within*: :code:`['circular', 'linear']`                              |
    |                                                                         |
    | The boundary for each horizon. If the boundary is 'circular,' then the  |
    | last timepoint of the horizon is treated as the 'previous' timepoint    |
    | for the first timepoint of the horizon (e.g. for ramping constraints    |
    | or tracking storage state of charge).                                   |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Derived Input Params                                                    |
    +=========================================================================+
    | | :code:`first_hrz_tmp`                                                 |
    | | *Defined over*: :code:`BLN_TYPE_HRZS`                                 |
    |                                                                         |
    | Derived parameter describing the first timepoint in each horizon for a  |
    | given balancing type. Note: this relies on :code:`TMPS_BY_BLN_TYPE_HRZ` |
    | being an ordered (indexed) set.                                         |
    +-------------------------------------------------------------------------+
    | | :code:`last_hrz_tmp`                                                  |
    | | *Defined over*: :code:`BLN_TYPE_HRZS`                                 |
    |                                                                         |
    | Derived parameter describing the last timepoint in each horizon for a   |
    | given balancing type. Note: this relies on :code:`TMPS_BY_BLN_TYPE_HRZ` |
    | being an ordered (indexed) set.                                         |
    +-------------------------------------------------------------------------+
    | | :code:`prev_tmp`                                                      |
    | | *Defined over*: :code:`TMPS x BLN_TYPES`                              |
    | | *Within*: :code: `m.TMPS | {None}`                                    |
    |                                                                         |
    | Derived parameter describing the previous timepoint for each timepoint  |
    | in each balancing type; depends on whether horizon is circular or       |
    | linear and relies on having ordered :code:`TIMEPOINTS`.                 |
    +-------------------------------------------------------------------------+
    | | :code:`next_tmp`                                                      |
    | | *Defined over*: :code:`TMPS x BLN_TYPES`                              |
    | | *Within*: :code: `m.TMPS | {None}`                                    |
    |                                                                         |
    | Derived parameter describing the next timepoint for each timepoint in   |
    | each balancing type; depends on whether horizon is circular or linear   |
    | and relies on having ordered :code:`TIMEPOINTS`.                        |
    +-------------------------------------------------------------------------+



    """

    # Sets
    ###########################################################################

    m.BLN_TYPE_HRZS = Set(dimen=2, ordered=True)

    m.TMPS_BY_BLN_TYPE_HRZ = Set(m.BLN_TYPE_HRZS,
                                 within=PositiveIntegers,
                                 ordered=True)

    # Derived Sets
    ###########################################################################

    m.BLN_TYPES = Set(initialize=balancing_types_init)

    m.HRZS_BY_BLN_TYPE = Set(m.BLN_TYPES,
                             within=PositiveIntegers,
                             initialize=horizons_by_balancing_type_init)

    # Required Params
    ###########################################################################

    # TODO: can create here instead of upstream in data (i.e. we can get the
    #  balancing type index from the horizon of the timepoint)
    m.horizon = Param(m.TMPS, m.BLN_TYPES)

    m.boundary = Param(m.BLN_TYPE_HRZS,
                       within=['circular', 'linear', 'linked'])

    # Derived Params
    ###########################################################################

    m.first_hrz_tmp = Param(
        m.BLN_TYPE_HRZS,
        within=PositiveIntegers,
        initialize=lambda mod, b, h: list(mod.TMPS_BY_BLN_TYPE_HRZ[b, h])[0])

    m.last_hrz_tmp = Param(
        m.BLN_TYPE_HRZS,
        within=PositiveIntegers,
        initialize=lambda mod, b, h: list(mod.TMPS_BY_BLN_TYPE_HRZ[b, h])[-1])

    m.prev_tmp = Param(m.TMPS,
                       m.BLN_TYPES,
                       within=m.TMPS | {None},
                       initialize=prev_tmp_init)

    m.next_tmp = Param(m.TMPS,
                       m.BLN_TYPES,
                       within=m.TMPS | {None},
                       initialize=next_tmp_init)
Пример #19
0
    def test_get_check_units_on_all_expressions(self):
        # this method is going to test all the expression types that should work
        # to be defensive, we will also test that we actually have the expected expression type
        # therefore, if the expression system changes and we get a different expression type,
        # we will know we need to change these tests

        uc = units
        kg = uc.kg
        m = uc.m

        model = ConcreteModel()
        model.x = Var()
        model.y = Var()
        model.z = Var()
        model.p = Param(initialize=42.0, mutable=True)
        model.xkg = Var(units=kg)
        model.ym = Var(units=m)

        # test equality
        self._get_check_units_ok(3.0 * kg == 1.0 * kg, uc, 'kg',
                                 EXPR.EqualityExpression)
        self._get_check_units_fail(3.0 * kg == 2.0 * m, uc,
                                   EXPR.EqualityExpression)

        # test inequality
        self._get_check_units_ok(3.0 * kg <= 1.0 * kg, uc, 'kg',
                                 EXPR.InequalityExpression)
        self._get_check_units_fail(3.0 * kg <= 2.0 * m, uc,
                                   EXPR.InequalityExpression)
        self._get_check_units_ok(3.0 * kg >= 1.0 * kg, uc, 'kg',
                                 EXPR.InequalityExpression)
        self._get_check_units_fail(3.0 * kg >= 2.0 * m, uc,
                                   EXPR.InequalityExpression)

        # test RangedExpression
        self._get_check_units_ok(inequality(3.0 * kg, 4.0 * kg, 5.0 * kg), uc,
                                 'kg', EXPR.RangedExpression)
        self._get_check_units_fail(inequality(3.0 * m, 4.0 * kg, 5.0 * kg), uc,
                                   EXPR.RangedExpression)
        self._get_check_units_fail(inequality(3.0 * kg, 4.0 * m, 5.0 * kg), uc,
                                   EXPR.RangedExpression)
        self._get_check_units_fail(inequality(3.0 * kg, 4.0 * kg, 5.0 * m), uc,
                                   EXPR.RangedExpression)

        # test SumExpression, NPV_SumExpression
        self._get_check_units_ok(
            3.0 * model.x * kg + 1.0 * model.y * kg + 3.65 * model.z * kg, uc,
            'kg', EXPR.SumExpression)
        self._get_check_units_fail(
            3.0 * model.x * kg + 1.0 * model.y * m + 3.65 * model.z * kg, uc,
            EXPR.SumExpression)

        self._get_check_units_ok(3.0 * kg + 1.0 * kg + 2.0 * kg, uc, 'kg',
                                 EXPR.NPV_SumExpression)
        self._get_check_units_fail(3.0 * kg + 1.0 * kg + 2.0 * m, uc,
                                   EXPR.NPV_SumExpression)

        # test ProductExpression, NPV_ProductExpression
        self._get_check_units_ok(model.x * kg * model.y * m, uc, 'kg*m',
                                 EXPR.ProductExpression)
        self._get_check_units_ok(3.0 * kg * 1.0 * m, uc, 'kg*m',
                                 EXPR.NPV_ProductExpression)
        self._get_check_units_ok(3.0 * kg * m, uc, 'kg*m',
                                 EXPR.NPV_ProductExpression)
        # I don't think that there are combinations that can "fail" for products

        # test MonomialTermExpression
        self._get_check_units_ok(model.x * kg, uc, 'kg',
                                 EXPR.MonomialTermExpression)

        # test DivisionExpression, NPV_DivisionExpression
        self._get_check_units_ok(1.0 / (model.x * kg), uc, '1/kg',
                                 EXPR.DivisionExpression)
        self._get_check_units_ok(2.0 / kg, uc, '1/kg',
                                 EXPR.NPV_DivisionExpression)
        self._get_check_units_ok((model.x * kg) / 1.0, uc, 'kg',
                                 EXPR.MonomialTermExpression)
        self._get_check_units_ok(kg / 2.0, uc, 'kg',
                                 EXPR.NPV_DivisionExpression)
        self._get_check_units_ok(model.y * m / (model.x * kg), uc, 'm/kg',
                                 EXPR.DivisionExpression)
        self._get_check_units_ok(m / kg, uc, 'm/kg',
                                 EXPR.NPV_DivisionExpression)
        # I don't think that there are combinations that can "fail" for products

        # test PowExpression, NPV_PowExpression
        # ToDo: fix the str representation to combine the powers or the expression system
        self._get_check_units_ok(
            (model.x * kg**2)**3, uc, 'kg**6',
            EXPR.PowExpression)  # would want this to be kg**6
        self._get_check_units_fail(kg**model.x, uc, EXPR.PowExpression,
                                   UnitsError)
        self._get_check_units_fail(model.x**kg, uc, EXPR.PowExpression,
                                   UnitsError)
        self._get_check_units_ok(kg**2, uc, 'kg**2', EXPR.NPV_PowExpression)
        self._get_check_units_fail(3.0**kg, uc, EXPR.NPV_PowExpression,
                                   UnitsError)

        # test NegationExpression, NPV_NegationExpression
        self._get_check_units_ok(-(kg * model.x * model.y), uc, 'kg',
                                 EXPR.NegationExpression)
        self._get_check_units_ok(-kg, uc, 'kg', EXPR.NPV_NegationExpression)
        # don't think there are combinations that fan "fail" for negation

        # test AbsExpression, NPV_AbsExpression
        self._get_check_units_ok(abs(kg * model.x), uc, 'kg',
                                 EXPR.AbsExpression)
        self._get_check_units_ok(abs(kg), uc, 'kg', EXPR.NPV_AbsExpression)
        # don't think there are combinations that fan "fail" for abs

        # test the different UnaryFunctionExpression / NPV_UnaryFunctionExpression types
        # log
        self._get_check_units_ok(log(3.0 * model.x), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(log(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(log(3.0 * model.p), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(log(3.0 * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # log10
        self._get_check_units_ok(log10(3.0 * model.x), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(log10(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(log10(3.0 * model.p), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(log10(3.0 * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # sin
        self._get_check_units_ok(sin(3.0 * model.x * uc.radians), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(sin(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_fail(sin(3.0 * kg * model.x * uc.kg), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(sin(3.0 * model.p * uc.radians), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(sin(3.0 * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # cos
        self._get_check_units_ok(cos(3.0 * model.x * uc.radians), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(cos(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_fail(cos(3.0 * kg * model.x * uc.kg), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(cos(3.0 * model.p * uc.radians), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(cos(3.0 * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # tan
        self._get_check_units_ok(tan(3.0 * model.x * uc.radians), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(tan(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_fail(tan(3.0 * kg * model.x * uc.kg), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(tan(3.0 * model.p * uc.radians), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(tan(3.0 * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # sin
        self._get_check_units_ok(sinh(3.0 * model.x * uc.radians), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(sinh(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_fail(sinh(3.0 * kg * model.x * uc.kg), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(sinh(3.0 * model.p * uc.radians), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(sinh(3.0 * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # cos
        self._get_check_units_ok(cosh(3.0 * model.x * uc.radians), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(cosh(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_fail(cosh(3.0 * kg * model.x * uc.kg), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(cosh(3.0 * model.p * uc.radians), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(cosh(3.0 * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # tan
        self._get_check_units_ok(tanh(3.0 * model.x * uc.radians), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(tanh(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_fail(tanh(3.0 * kg * model.x * uc.kg), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(tanh(3.0 * model.p * uc.radians), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(tanh(3.0 * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # asin
        self._get_check_units_ok(asin(3.0 * model.x), uc, 'rad',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(asin(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(asin(3.0 * model.p), uc, 'rad',
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(asin(3.0 * model.p * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # acos
        self._get_check_units_ok(acos(3.0 * model.x), uc, 'rad',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(acos(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(acos(3.0 * model.p), uc, 'rad',
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(acos(3.0 * model.p * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # atan
        self._get_check_units_ok(atan(3.0 * model.x), uc, 'rad',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(atan(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(atan(3.0 * model.p), uc, 'rad',
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(atan(3.0 * model.p * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # exp
        self._get_check_units_ok(exp(3.0 * model.x), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(exp(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(exp(3.0 * model.p), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(exp(3.0 * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # sqrt
        self._get_check_units_ok(sqrt(3.0 * model.x), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_ok(sqrt(3.0 * model.x * kg**2), uc, 'kg',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_ok(sqrt(3.0 * model.x * kg), uc, 'kg**0.5',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_ok(sqrt(3.0 * model.p), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_ok(sqrt(3.0 * model.p * kg**2), uc, 'kg',
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_ok(sqrt(3.0 * model.p * kg), uc, 'kg**0.5',
                                 EXPR.NPV_UnaryFunctionExpression)
        # asinh
        self._get_check_units_ok(asinh(3.0 * model.x), uc, 'rad',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(asinh(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(asinh(3.0 * model.p), uc, 'rad',
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(asinh(3.0 * model.p * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # acosh
        self._get_check_units_ok(acosh(3.0 * model.x), uc, 'rad',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(acosh(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(acosh(3.0 * model.p), uc, 'rad',
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(acosh(3.0 * model.p * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # atanh
        self._get_check_units_ok(atanh(3.0 * model.x), uc, 'rad',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(atanh(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(atanh(3.0 * model.p), uc, 'rad',
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(atanh(3.0 * model.p * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # ceil
        self._get_check_units_ok(ceil(kg * model.x), uc, 'kg',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_ok(ceil(kg), uc, 'kg',
                                 EXPR.NPV_UnaryFunctionExpression)
        # don't think there are combinations that fan "fail" for ceil
        # floor
        self._get_check_units_ok(floor(kg * model.x), uc, 'kg',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_ok(floor(kg), uc, 'kg',
                                 EXPR.NPV_UnaryFunctionExpression)
        # don't think there are combinations that fan "fail" for floor

        # test Expr_ifExpression
        # consistent if, consistent then/else
        self._get_check_units_ok(
            EXPR.Expr_if(IF=model.x * kg + kg >= 2.0 * kg,
                         THEN=model.x * kg,
                         ELSE=model.y * kg), uc, 'kg', EXPR.Expr_ifExpression)
        # unitless if, consistent then/else
        self._get_check_units_ok(
            EXPR.Expr_if(IF=model.x >= 2.0,
                         THEN=model.x * kg,
                         ELSE=model.y * kg), uc, 'kg', EXPR.Expr_ifExpression)
        # consistent if, unitless then/else
        self._get_check_units_ok(
            EXPR.Expr_if(IF=model.x * kg + kg >= 2.0 * kg,
                         THEN=model.x,
                         ELSE=model.x), uc, None, EXPR.Expr_ifExpression)
        # inconsistent then/else
        self._get_check_units_fail(
            EXPR.Expr_if(IF=model.x >= 2.0,
                         THEN=model.x * m,
                         ELSE=model.y * kg), uc, EXPR.Expr_ifExpression)
        # inconsistent then/else NPV
        self._get_check_units_fail(
            EXPR.Expr_if(IF=model.x >= 2.0,
                         THEN=model.p * m,
                         ELSE=model.p * kg), uc, EXPR.Expr_ifExpression)
        # inconsistent then/else NPV units only
        self._get_check_units_fail(
            EXPR.Expr_if(IF=model.x >= 2.0, THEN=m, ELSE=kg), uc,
            EXPR.Expr_ifExpression)

        # test EXPR.IndexTemplate and GetItemExpression
        model.S = Set()
        i = EXPR.IndexTemplate(model.S)
        j = EXPR.IndexTemplate(model.S)
        self._get_check_units_ok(i, uc, None, EXPR.IndexTemplate)

        model.mat = Var(model.S, model.S)
        self._get_check_units_ok(model.mat[i, j + 1], uc, None,
                                 EXPR.GetItemExpression)

        # test ExternalFunctionExpression, NPV_ExternalFunctionExpression
        model.ef = ExternalFunction(python_callback_function)
        self._get_check_units_ok(model.ef(model.x, model.y), uc, None,
                                 EXPR.ExternalFunctionExpression)
        self._get_check_units_ok(model.ef(1.0, 2.0), uc, None,
                                 EXPR.NPV_ExternalFunctionExpression)
        self._get_check_units_fail(model.ef(model.x * kg, model.y), uc,
                                   EXPR.ExternalFunctionExpression, UnitsError)
        self._get_check_units_fail(model.ef(2.0 * kg, 1.0), uc,
                                   EXPR.NPV_ExternalFunctionExpression,
                                   UnitsError)

        # test ExternalFunctionExpression, NPV_ExternalFunctionExpression
        model.ef2 = ExternalFunction(python_callback_function, units=uc.kg)
        self._get_check_units_ok(model.ef2(model.x, model.y), uc, 'kg',
                                 EXPR.ExternalFunctionExpression)
        self._get_check_units_ok(model.ef2(1.0, 2.0), uc, 'kg',
                                 EXPR.NPV_ExternalFunctionExpression)
        self._get_check_units_fail(model.ef2(model.x * kg, model.y), uc,
                                   EXPR.ExternalFunctionExpression, UnitsError)
        self._get_check_units_fail(model.ef2(2.0 * kg, 1.0), uc,
                                   EXPR.NPV_ExternalFunctionExpression,
                                   UnitsError)

        # test ExternalFunctionExpression, NPV_ExternalFunctionExpression
        model.ef3 = ExternalFunction(python_callback_function,
                                     units=uc.kg,
                                     arg_units=[uc.kg, uc.m])
        self._get_check_units_fail(model.ef3(model.x, model.y), uc,
                                   EXPR.ExternalFunctionExpression)
        self._get_check_units_fail(model.ef3(1.0, 2.0), uc,
                                   EXPR.NPV_ExternalFunctionExpression)
        self._get_check_units_fail(model.ef3(model.x * kg, model.y), uc,
                                   EXPR.ExternalFunctionExpression, UnitsError)
        self._get_check_units_fail(model.ef3(2.0 * kg, 1.0), uc,
                                   EXPR.NPV_ExternalFunctionExpression,
                                   UnitsError)
        self._get_check_units_ok(model.ef3(2.0 * kg, 1.0 * uc.m), uc, 'kg',
                                 EXPR.NPV_ExternalFunctionExpression)
        self._get_check_units_ok(model.ef3(model.x * kg, model.y * m), uc,
                                 'kg', EXPR.ExternalFunctionExpression)
        self._get_check_units_ok(model.ef3(model.xkg, model.ym), uc, 'kg',
                                 EXPR.ExternalFunctionExpression)
        self._get_check_units_fail(model.ef3(model.ym, model.xkg), uc,
                                   EXPR.ExternalFunctionExpression,
                                   InconsistentUnitsError)
Пример #20
0
    def test_nonnegativity_transformation_2(self):
        self.model.S = RangeSet(0, 10)
        self.model.T = Set(initialize=["foo", "bar"])

        # Unindexed, singly indexed, and doubly indexed variables with
        # explicit bounds
        self.model.x1 = Var(bounds=(-3, 3))
        self.model.y1 = Var(self.model.S, bounds=(-3, 3))
        self.model.z1 = Var(self.model.S, self.model.T, bounds=(-3, 3))

        # Unindexed, singly indexed, and doubly indexed variables with
        # rule-defined bounds
        def boundsRule(*args):
            return (-4, 4)

        self.model.x2 = Var(bounds=boundsRule)
        self.model.y2 = Var(self.model.S, bounds=boundsRule)
        self.model.z2 = Var(self.model.S, self.model.T, bounds=boundsRule)

        # Unindexed, singly indexed, and doubly indexed variables with
        # explicit domains
        self.model.x3 = Var(domain=NegativeReals)
        self.model.y3 = Var(self.model.S, domain=NegativeIntegers)
        self.model.z3 = Var(self.model.S, self.model.T, domain=Reals)

        # Unindexed, singly indexed, and doubly indexed variables with
        # rule-defined domains
        def domainRule(*args):
            if len(args) == 1 or args[0] == 0:
                return NonNegativeReals
            elif args[0] == 1:
                return NonNegativeIntegers
            elif args[0] == 2:
                return NonPositiveReals
            elif args[0] == 3:
                return NonPositiveIntegers
            elif args[0] == 4:
                return NegativeReals
            elif args[0] == 5:
                return NegativeIntegers
            elif args[0] == 6:
                return PositiveReals
            elif args[0] == 7:
                return PositiveIntegers
            elif args[0] == 8:
                return Reals
            elif args[0] == 9:
                return Integers
            elif args[0] == 10:
                return Binary
            else:
                return NonNegativeReals

        self.model.x4 = Var(domain=domainRule)
        self.model.y4 = Var(self.model.S, domain=domainRule)
        self.model.z4 = Var(self.model.S, self.model.T, domain=domainRule)

        instance = self.model.create_instance()
        xfrm = TransformationFactory('core.nonnegative_vars')
        transformed = xfrm.create_using(instance)

        # Make sure everything is nonnegative
        for c in ('x', 'y', 'z'):
            for n in ('1', '2', '3', '4'):
                var = transformed.__getattribute__(c + n)
                for ndx in var._index:
                    self.assertTrue(self.nonnegativeBounds(var[ndx]))
Пример #21
0
    def __init__(self,
                 y,
                 x,
                 cutactive,
                 cet=CET_ADDI,
                 fun=FUN_PROD,
                 rts=RTS_VRS):
        """CNLS+G model 1

        Args:
            y (float): output variable.
            x (float): input variables.
            cutactive (float): active concavity constraint.
            cet (String, optional): CET_ADDI (additive composite error term) or CET_MULT (multiplicative composite error term). Defaults to CET_ADDI.
            fun (String, optional): FUN_PROD (production frontier) or FUN_COST (cost frontier). Defaults to FUN_PROD.
            rts (String, optional): RTS_VRS (variable returns to scale) or RTS_CRS (constant returns to scale). Defaults to RTS_VRS.
        """
        # TODO(error/warning handling): Check the configuration of the model exist
        self.x = x
        self.y = y
        self.cet = cet
        self.fun = fun
        self.rts = rts

        self.cutactive = cutactive

        # Initialize the CNLS model
        self.__model__ = ConcreteModel()

        # Initialize the sets
        self.__model__.I = Set(initialize=range(len(self.y)))
        self.__model__.J = Set(initialize=range(len(self.x[0])))

        # Initialize the variables
        self.__model__.alpha = Var(self.__model__.I, doc='alpha')
        self.__model__.beta = Var(self.__model__.I,
                                  self.__model__.J,
                                  bounds=(0.0, None),
                                  doc='beta')
        self.__model__.epsilon = Var(self.__model__.I, doc='residual')
        self.__model__.frontier = Var(self.__model__.I,
                                      bounds=(0.0, None),
                                      doc='estimated frontier')

        # Setup the objective function and constraints
        self.__model__.objective = Objective(rule=self.__objective_rule(),
                                             sense=minimize,
                                             doc='objective function')
        self.__model__.regression_rule = Constraint(
            self.__model__.I,
            rule=self.__regression_rule(),
            doc='regression equation')
        if self.cet == CET_MULT:
            self.__model__.log_rule = Constraint(
                self.__model__.I,
                rule=self.__log_rule(),
                doc='log-transformed regression equation')
        self.__model__.afriat_rule = Constraint(
            self.__model__.I,
            rule=self.__afriat_rule(),
            doc='elementary Afriat approach')
        self.__model__.sweet_rule = Constraint(self.__model__.I,
                                               self.__model__.I,
                                               rule=self.__sweet_rule(),
                                               doc='sweet spot approach')

        # Optimize model
        self.optimization_status = 0
        self.problem_status = 0
Пример #22
0
    def test_nonnegative_transform_3(self):
        self.model.S = RangeSet(0, 10)
        self.model.T = Set(initialize=["foo", "bar"])

        # Unindexed, singly indexed, and doubly indexed variables with
        # explicit bounds
        self.model.x1 = Var(bounds=(-3, 3))
        self.model.y1 = Var(self.model.S, bounds=(-3, 3))
        self.model.z1 = Var(self.model.S, self.model.T, bounds=(-3, 3))

        # Unindexed, singly indexed, and doubly indexed variables with
        # rule-defined bounds
        def boundsRule(*args):
            return (-4, 4)

        self.model.x2 = Var(bounds=boundsRule)
        self.model.y2 = Var(self.model.S, bounds=boundsRule)
        self.model.z2 = Var(self.model.S, self.model.T, bounds=boundsRule)

        # Unindexed, singly indexed, and doubly indexed variables with
        # explicit domains
        self.model.x3 = Var(domain=NegativeReals, bounds=(-10, 10))
        self.model.y3 = Var(self.model.S,
                            domain=NegativeIntegers,
                            bounds=(-10, 10))
        self.model.z3 = Var(self.model.S,
                            self.model.T,
                            domain=Reals,
                            bounds=(-10, 10))

        # Unindexed, singly indexed, and doubly indexed variables with
        # rule-defined domains
        def domainRule(*args):
            if len(args) == 1:
                arg = 0
            else:
                arg = args[1]

            if len(args) == 1 or arg == 0:
                return NonNegativeReals
            elif arg == 1:
                return NonNegativeIntegers
            elif arg == 2:
                return NonPositiveReals
            elif arg == 3:
                return NonPositiveIntegers
            elif arg == 4:
                return NegativeReals
            elif arg == 5:
                return NegativeIntegers
            elif arg == 6:
                return PositiveReals
            elif arg == 7:
                return PositiveIntegers
            elif arg == 8:
                return Reals
            elif arg == 9:
                return Integers
            elif arg == 10:
                return Binary
            else:
                return Reals

        self.model.x4 = Var(domain=domainRule, bounds=(-10, 10))
        self.model.y4 = Var(self.model.S, domain=domainRule, bounds=(-10, 10))
        self.model.z4 = Var(self.model.S,
                            self.model.T,
                            domain=domainRule,
                            bounds=(-10, 10))

        def objRule(model):
            return sum(5*sum_product(model.__getattribute__(c+n)) \
                       for c in ('x', 'y', 'z') for n in ('1', '2', '3', '4'))

        self.model.obj = Objective(rule=objRule)

        transform = TransformationFactory('core.nonnegative_vars')
        instance = self.model.create_instance()
        transformed = transform.create_using(instance)

        opt = SolverFactory("glpk")

        instance_sol = opt.solve(instance)
        transformed_sol = opt.solve(transformed)

        self.assertEqual(
            instance_sol["Solution"][0]["Objective"]['obj']["value"],
            transformed_sol["Solution"][0]["Objective"]['obj']["value"])
Пример #23
0
def add_model_components(m, d, scenario_directory, subproblem, stage):
    """
    The following Pyomo model components are defined in this module:

    +-------------------------------------------------------------------------+
    | Sets                                                                    |
    +=========================================================================+
    | | :code:`STOR`                                                          |
    |                                                                         |
    | The set of projects of the :code:`stor` operational type.               |
    +-------------------------------------------------------------------------+
    | | :code:`STOR_OPR_TMPS`                                                 |
    |                                                                         |
    | Two-dimensional set with projects of the :code:`stor`                   |
    | operational type and their operational timepoints.                      |
    +-------------------------------------------------------------------------+
    | | :code:`STOR_LINKED_TMPS`                                              |
    |                                                                         |
    | Two-dimensional set with generators of the :code:`stor`                 |
    | operational type and their linked timepoints.                           |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Required Input Params                                                   |
    +=========================================================================+
    | | :code:`stor_charging_efficiency`                                      |
    | | *Defined over*: :code:`STOR`                                          |
    | | *Within*: :code:`PercentFraction`                                     |
    |                                                                         |
    | The storage project's charging efficiency (1 = 100% efficient).         |
    +-------------------------------------------------------------------------+
    | | :code:`stor_discharging_efficiency`                                   |
    | | *Defined over*: :code:`STOR`                                          |
    | | *Within*: :code:`PercentFraction`                                     |
    |                                                                         |
    | The storage project's discharging efficiency (1 = 100% efficient).      |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Optional Input Params                                                   |
    +=========================================================================+
    | | :code:`stor_losses_factor_in_rps`                                     |
    | | *Within*: :code:`PercentFraction`                                     |
    | | *Default*: :code:`1`                                                  |
    |                                                                         |
    | The fraction of storage losses that count against the RPS target.       |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Linked Input Params                                                     |
    +=========================================================================+
    | | :code:`stor_linked_starting_energy_in_storage`                        |
    | | *Defined over*: :code:`STOR_LINKED_TMPS`                              |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The project's starting energy in storage in the linked timepoints.      |
    +-------------------------------------------------------------------------+
    | | :code:`stor_linked_discharge`                                         |
    | | *Defined over*: :code:`STOR_LINKED_TMPS`                              |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The project's dicharging in the linked timepoints.                      |
    +-------------------------------------------------------------------------+
    | | :code:`stor_linked_charge`                                            |
    | | *Defined over*: :code:`STOR_LINKED_TMPS`                              |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The project's charging in the linked timepoints.                        |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Variables                                                               |
    +=========================================================================+
    | | :code:`Stor_Charge_MW`                                                |
    | | *Defined over*: :code:`STOR_OPR_TMPS`                                 |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | Charging power in MW from this project in each timepoint in which the   |
    | project is operational (capacity exists and the project is available).  |
    +-------------------------------------------------------------------------+
    | | :code:`Stor_Discharge_MW`                                             |
    | | *Defined over*: :code:`STOR_OPR_TMPS`                                 |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | Discharging power in MW from this project in each timepoint in which the|
    |  project is operational (capacity exists and the project is available). |
    +-------------------------------------------------------------------------+
    | | :code:`Stor_Starting_Energy_in_Storage_MWh`                           |
    | | *Defined over*: :code:`STOR_OPR_TMPS`                                 |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The state of charge of the storage project at the start of each         |
    | timepoint, in MWh of energy stored.                                     |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Constraints                                                             |
    +=========================================================================+
    | Power and Stage of Charge                                               |
    +-------------------------------------------------------------------------+
    | | :code:`Stor_Max_Charge_Constraint`                                    |
    | | *Defined over*: :code:`STOR_OPR_TMPS`                                 |
    |                                                                         |
    | Limits the project's charging power to the available capacity.          |
    +-------------------------------------------------------------------------+
    | | :code:`Stor_Max_Discharge_Constraint`                                 |
    | | *Defined over*: :code:`STOR_OPR_TMPS`                                 |
    |                                                                         |
    | Limits the project's discharging power to the available capacity.       |
    +-------------------------------------------------------------------------+
    | | :code:`Stor_Energy_Tracking_Constraint`                               |
    | | *Defined over*: :code:`STOR_OPR_TMPS`                                 |
    |                                                                         |
    | Tracks the amount of energy stored in each timepoint based on the       |
    | previous timepoint's energy stored and the charge and discharge         |
    | decisions.                                                              |
    +-------------------------------------------------------------------------+
    | | :code:`Stor_Max_Energy_in_Storage_Constraint`                         |
    | | *Defined over*: :code:`STOR_OPR_TMPS`                                 |
    |                                                                         |
    | Limits the project's total energy stored to the available energy        |
    | capacity.                                                               |
    +-------------------------------------------------------------------------+
    | Reserves                                                                |
    +-------------------------------------------------------------------------+
    | | :code:`Stor_Max_Headroom_Power_Constraint`                            |
    | | *Defined over*: :code:`STOR_OPR_TMPS`                                 |
    |                                                                         |
    | Limits the project's upward reserves based on available headroom.       |
    | Going from charging to non-charging also counts as headroom, doubling   |
    | the maximum amount of potential headroom.                               |
    +-------------------------------------------------------------------------+
    | | :code:`Stor_Max_Footroom_Power_Constraint`                            |
    | | *Defined over*: :code:`STOR_OPR_TMPS`                                 |
    |                                                                         |
    | Limits the project's downward reserves based on available footroom.     |
    | Going from non-charging to charging also counts as footroom, doubling   |
    | the maximum amount of potential footroom.                               |
    +-------------------------------------------------------------------------+
    | | :code:`Stor_Max_Headroom_Energy_Constraint`                           |
    | | *Defined over*: :code:`STOR_OPR_TMPS`                                 |
    |                                                                         |
    | Can't provide more upward reserves (times sustained duration required)  |
    |than available energy in storage in that timepoint.                      |
    +-------------------------------------------------------------------------+
    | | :code:`Stor_Max_Footroom_Energy_Constraint`                           |
    | | *Defined over*: :code:`STOR_OPR_TMPS`                                 |
    |                                                                         |
    | Can't provide more downard reserves (times sustained duration required) |
    | than available capacity to store energy in that timepoint.              |
    +-------------------------------------------------------------------------+



    """

    # Sets
    ###########################################################################

    m.STOR = Set(within=m.PROJECTS,
                 initialize=lambda mod: subset_init_by_param_value(
                     mod, "PROJECTS", "operational_type", "stor"))

    m.STOR_OPR_TMPS = Set(dimen=2,
                          within=m.PRJ_OPR_TMPS,
                          initialize=lambda mod: list(
                              set((g, tmp) for (g, tmp) in mod.PRJ_OPR_TMPS
                                  if g in mod.STOR)))

    m.STOR_LINKED_TMPS = Set(dimen=2)

    # Required Params
    ###########################################################################

    m.stor_charging_efficiency = Param(m.STOR, within=PercentFraction)

    m.stor_discharging_efficiency = Param(m.STOR, within=PercentFraction)

    # Optional Params
    ###########################################################################

    m.stor_losses_factor_in_rps = Param(default=1)

    # Linked Params
    ###########################################################################

    m.stor_linked_starting_energy_in_storage = Param(m.STOR_LINKED_TMPS,
                                                     within=NonNegativeReals)

    m.stor_linked_discharge = Param(m.STOR_LINKED_TMPS,
                                    within=NonNegativeReals)

    m.stor_linked_charge = Param(m.STOR_LINKED_TMPS, within=NonNegativeReals)

    # Variables
    ###########################################################################

    m.Stor_Charge_MW = Var(m.STOR_OPR_TMPS, within=NonNegativeReals)

    m.Stor_Discharge_MW = Var(m.STOR_OPR_TMPS, within=NonNegativeReals)

    m.Stor_Starting_Energy_in_Storage_MWh = Var(m.STOR_OPR_TMPS,
                                                within=NonNegativeReals)

    # Expressions
    ###########################################################################

    def upward_reserve_rule(mod, g, tmp):
        return sum(
            getattr(mod, c)[g, tmp] for c in getattr(d, headroom_variables)[g])

    m.Stor_Upward_Reserves_MW = Expression(m.STOR_OPR_TMPS,
                                           rule=upward_reserve_rule)

    def downward_reserve_rule(mod, g, tmp):
        return sum(
            getattr(mod, c)[g, tmp] for c in getattr(d, footroom_variables)[g])

    m.Stor_Downward_Reserves_MW = Expression(m.STOR_OPR_TMPS,
                                             rule=downward_reserve_rule)

    # Constraints
    ###########################################################################

    # Power and State of Charge
    m.Stor_Max_Charge_Constraint = Constraint(m.STOR_OPR_TMPS,
                                              rule=max_charge_rule)

    m.Stor_Max_Discharge_Constraint = Constraint(m.STOR_OPR_TMPS,
                                                 rule=max_discharge_rule)

    m.Stor_Energy_Tracking_Constraint = Constraint(m.STOR_OPR_TMPS,
                                                   rule=energy_tracking_rule)

    m.Stor_Max_Energy_in_Storage_Constraint = Constraint(
        m.STOR_OPR_TMPS, rule=max_energy_in_storage_rule)

    # Reserves
    m.Stor_Max_Headroom_Power_Constraint = Constraint(
        m.STOR_OPR_TMPS, rule=max_headroom_power_rule)

    m.Stor_Max_Footroom_Power_Constraint = Constraint(
        m.STOR_OPR_TMPS, rule=max_footroom_power_rule)

    m.Stor_Max_Headroom_Energy_Constraint = Constraint(
        m.STOR_OPR_TMPS, rule=max_headroom_energy_rule)

    m.Stor_Max_Footroom_Energy_Constraint = Constraint(
        m.STOR_OPR_TMPS, rule=max_footroom_energy_rule)
Пример #24
0
    def test_standard_form_transform_2(self):
        """ Same as #1, but adds constraints """
        self.model.S = RangeSet(0, 10)
        self.model.T = Set(initialize=["foo", "bar"])

        # Unindexed, singly indexed, and doubly indexed variables with
        # explicit bounds
        self.model.x1 = Var(bounds=(-3, 3))
        self.model.y1 = Var(self.model.S, bounds=(-3, 3))
        self.model.z1 = Var(self.model.S, self.model.T, bounds=(-3, 3))

        # Unindexed, singly indexed, and doubly indexed variables with
        # rule-defined bounds
        def boundsRule(*args):
            return (-4, 4)

        self.model.x2 = Var(bounds=boundsRule)
        self.model.y2 = Var(self.model.S, bounds=boundsRule)
        self.model.z2 = Var(self.model.S, self.model.T, bounds=boundsRule)

        # Unindexed, singly indexed, and doubly indexed variables with
        # explicit domains
        self.model.x3 = Var(domain=NegativeReals, bounds=(-10, 10))
        self.model.y3 = Var(self.model.S,
                            domain=NegativeIntegers,
                            bounds=(-10, 10))
        self.model.z3 = Var(self.model.S,
                            self.model.T,
                            domain=Reals,
                            bounds=(-10, 10))

        # Unindexed, singly indexed, and doubly indexed variables with
        # rule-defined domains
        def domainRule(*args):
            if len(args) == 1:
                arg = 0
            else:
                arg = args[1]

            if len(args) == 1 or arg == 0:
                return NonNegativeReals
            elif arg == 1:
                return NonNegativeIntegers
            elif arg == 2:
                return NonPositiveReals
            elif arg == 3:
                return NonPositiveIntegers
            elif arg == 4:
                return NegativeReals
            elif arg == 5:
                return NegativeIntegers
            elif arg == 6:
                return PositiveReals
            elif arg == 7:
                return PositiveIntegers
            elif arg == 8:
                return Reals
            elif arg == 9:
                return Integers
            elif arg == 10:
                return Binary
            else:
                return Reals

        self.model.x4 = Var(domain=domainRule, bounds=(-10, 10))
        self.model.y4 = Var(self.model.S, domain=domainRule, bounds=(-10, 10))
        self.model.z4 = Var(self.model.S,
                            self.model.T,
                            domain=domainRule,
                            bounds=(-10, 10))

        # Add some constraints
        def makeXConRule(var):
            def xConRule(model, var):
                return (-1, var, 1)

        def makeYConRule(var):
            def yConRule(model, var, s):
                return (-1, var[s], 1)

        def makeZConRule(var):
            def zConRule(model, var, s, t):
                return (-1, var[s, t], 1)

        for n in ('1', '2', '3', '4'):
            self.model.__setattr__(
                "x" + n + "_constraint",
                Constraint(
                    rule=makeXConRule(self.model.__getattribute__("x" + n))))

            self.model.__setattr__(
                "y" + n + "_constraint",
                Constraint(
                    rule=makeYConRule(self.model.__getattribute__("y" + n))))

            self.model.__setattr__(
                "z" + n + "_constraint",
                Constraint(
                    rule=makeZConRule(self.model.__getattribute__("z" + n))))

        def objRule(model):
            return sum(5*sum_product(model.__getattribute__(c+n)) \
                       for c in ('x', 'y', 'z') for n in ('1', '2', '3', '4'))

        self.model.obj = Objective(rule=objRule)

        transform = StandardForm()
        instance = self.model.create_instance()
        transformed = transform(instance)

        opt = SolverFactory("glpk")

        instance_sol = opt.solve(instance)
        transformed_sol = opt.solve(transformed)

        self.assertEqual(
            instance_sol["Solution"][0]["Objective"]['obj']["value"],
            transformed_sol["Solution"][0]["Objective"]['obj']["value"])
Пример #25
0
    def _create(self, group=None):
        """
        Parameters
        ----------
        group : list
            List containing storage objects.
            e.g. groups=[storage1, storage2,..]
        """
        m = self.parent_block()

        if group is None:
            return None

        i = {n: [i for i in n.inputs][0] for n in group}
        o = {n: [o for o in n.outputs][0] for n in group}

        self.STORAGES = Set(initialize=[n for n in group])

        self.STORAGES_WITH_INVEST_FLOW_REL = Set(initialize=[
            n for n in group if n.invest_relation_input_output is not None
        ])

        def _storage_capacity_bound_rule(block, n, t):
            """Rule definition for bounds of capacity variable of storage n
            in timestep t
            """
            bounds = (n.nominal_capacity * n.capacity_min[t],
                      n.nominal_capacity * n.capacity_max[t])
            return bounds

        self.capacity = Var(self.STORAGES,
                            m.TIMESTEPS,
                            bounds=_storage_capacity_bound_rule)

        # set the initial capacity of the storage
        for n in group:
            if n.initial_capacity is not None:
                self.capacity[n, m.TIMESTEPS[-1]] = (n.initial_capacity *
                                                     n.nominal_capacity)
                self.capacity[n, m.TIMESTEPS[-1]].fix()

        # storage balance constraint
        def _storage_balance_rule(block, n, t):
            """Rule definition for the storage balance of every storage n and
            timestep t
            """
            expr = 0
            expr += block.capacity[n, t]
            expr += -block.capacity[n, m.previous_timesteps[t]] * (
                1 - n.capacity_loss[t])
            expr += (-m.flow[i[n], n, t] *
                     n.inflow_conversion_factor[t]) * m.timeincrement[t]
            expr += (m.flow[n, o[n], t] /
                     n.outflow_conversion_factor[t]) * m.timeincrement[t]
            return expr == 0

        self.balance = Constraint(self.STORAGES,
                                  m.TIMESTEPS,
                                  rule=_storage_balance_rule)

        def _power_coupled(block, n):
            """Rule definition for constraint to connect the input power
            and output power
            """
            expr = ((m.InvestmentFlow.invest[n, o[n]] +
                     m.flows[n, o[n]].investment.existing) *
                    n.invest_relation_input_output == (
                        m.InvestmentFlow.invest[i[n], n] +
                        m.flows[i[n], n].investment.existing))
            return expr

        self.power_coupled = Constraint(self.STORAGES_WITH_INVEST_FLOW_REL,
                                        rule=_power_coupled)
Пример #26
0
    def test_sim_initialization_multi_index2(self):

        m = self.m
        m.s2 = Set(initialize=[(1, 1), (2, 2)])
        m.w1 = Var(m.t, m.s2)
        m.dw1 = DerivativeVar(m.w1)

        m.w2 = Var(m.s2, m.t)
        m.dw2 = DerivativeVar(m.w2)

        m.w3 = Var([0, 1], m.t, m.s2)
        m.dw3 = DerivativeVar(m.w3)

        t = IndexTemplate(m.t)
        
        def _deq1(m, t, i, j):
            return m.dw1[t, i, j] == m.w1[t, i, j]
        m.deq1 = Constraint(m.t, m.s2, rule=_deq1)

        def _deq2(m, *idx):
            return m.dw2[idx] == m.w2[idx]
        m.deq2 = Constraint(m.s2, m.t, rule=_deq2)

        def _deq3(m, i, t, j, k):
            return m.dw3[i, t, j, k] == m.w1[t, j, k] + m.w2[j, k, t]
        m.deq3 = Constraint([0, 1], m.t, m.s2, rule=_deq3)

        mysim = Simulator(m)

        self.assertIs(mysim._contset, m.t)
        self.assertEqual(len(mysim._diffvars), 8)
        self.assertTrue(_GetItemIndexer(m.w1[t, 1, 1]) in mysim._diffvars)
        self.assertTrue(_GetItemIndexer(m.w1[t, 2, 2]) in mysim._diffvars)
        self.assertTrue(_GetItemIndexer(m.w2[1, 1, t]) in mysim._diffvars)
        self.assertTrue(_GetItemIndexer(m.w2[2, 2, t]) in mysim._diffvars)
        self.assertTrue(_GetItemIndexer(m.w3[0, t, 1, 1]) in mysim._diffvars)
        self.assertTrue(_GetItemIndexer(m.w3[1, t, 2, 2]) in mysim._diffvars)

        self.assertEqual(len(mysim._derivlist), 8)
        self.assertTrue(_GetItemIndexer(m.dw1[t, 1, 1]) in mysim._derivlist)
        self.assertTrue(_GetItemIndexer(m.dw1[t, 2, 2]) in mysim._derivlist)
        self.assertTrue(_GetItemIndexer(m.dw2[1, 1, t]) in mysim._derivlist)
        self.assertTrue(_GetItemIndexer(m.dw2[2, 2, t]) in mysim._derivlist)
        self.assertTrue(_GetItemIndexer(m.dw3[0, t, 1, 1]) in mysim._derivlist)
        self.assertTrue(_GetItemIndexer(m.dw3[1, t, 2, 2]) in mysim._derivlist)

        self.assertEqual(len(mysim._templatemap), 4)
        self.assertTrue(_GetItemIndexer(m.w1[t, 1, 1]) in mysim._templatemap)
        self.assertTrue(_GetItemIndexer(m.w1[t, 2, 2]) in mysim._templatemap)
        self.assertTrue(_GetItemIndexer(m.w2[1, 1, t]) in mysim._templatemap)
        self.assertTrue(_GetItemIndexer(m.w2[2, 2, t]) in mysim._templatemap)
        self.assertFalse(_GetItemIndexer(m.w3[0, t, 1, 1]) in
                         mysim._templatemap)
        self.assertFalse(_GetItemIndexer(m.w3[1, t, 2, 2]) in
                         mysim._templatemap)

        self.assertEqual(len(mysim._rhsdict), 8)
        self.assertTrue(isinstance(
            mysim._rhsdict[_GetItemIndexer(m.dw1[t, 1, 1])], Param))
        self.assertTrue(isinstance(
            mysim._rhsdict[_GetItemIndexer(m.dw1[t, 2, 2])], Param))
        self.assertTrue(isinstance(
            mysim._rhsdict[_GetItemIndexer(m.dw2[1, 1, t])], Param))
        self.assertTrue(isinstance(
            mysim._rhsdict[_GetItemIndexer(m.dw2[2, 2, t])], Param))
        self.assertTrue(isinstance(
            mysim._rhsdict[_GetItemIndexer(m.dw3[0, t, 1, 1])],
            EXPR.SumExpression))
        self.assertTrue(isinstance(
            mysim._rhsdict[_GetItemIndexer(m.dw3[1, t, 2, 2])],
            EXPR.SumExpression))
        self.assertEqual(mysim._rhsdict[_GetItemIndexer(m.dw1[t, 1, 1])].name,
                         'w1[{t},1,1]')
        self.assertEqual(mysim._rhsdict[_GetItemIndexer(m.dw1[t, 2, 2])].name,
                         'w1[{t},2,2]')
        self.assertEqual(mysim._rhsdict[_GetItemIndexer(m.dw2[1, 1, t])].name,
                         'w2[1,1,{t}]')
        self.assertEqual(mysim._rhsdict[_GetItemIndexer(m.dw2[2, 2, t])].name,
                         'w2[2,2,{t}]')

        self.assertEqual(len(mysim._rhsfun(0, [0] * 8)), 8)
        self.assertIsNone(mysim._tsim)
        self.assertIsNone(mysim._simsolution)

        m.del_component('deq1')
        m.del_component('deq1_index')
        m.del_component('deq2')
        m.del_component('deq2_index')
        m.del_component('deq3')
        m.del_component('deq3_index')
Пример #27
0
    def _create(self, group=None):
        """
        Create constraints for GenericCHPBlock.

        Parameters
        ----------
        group : list
            List containing `GenericCHP` objects.
            e.g. groups=[ghcp1, gchp2,..]
        """
        m = self.parent_block()

        if group is None:
            return None

        self.GENERICCHPS = Set(initialize=[n for n in group])

        # variables
        self.H_F = Var(self.GENERICCHPS, m.TIMESTEPS, within=NonNegativeReals)
        self.H_L_FG_max = Var(self.GENERICCHPS,
                              m.TIMESTEPS,
                              within=NonNegativeReals)
        self.H_L_FG_min = Var(self.GENERICCHPS,
                              m.TIMESTEPS,
                              within=NonNegativeReals)
        self.P_woDH = Var(self.GENERICCHPS,
                          m.TIMESTEPS,
                          within=NonNegativeReals)
        self.P = Var(self.GENERICCHPS, m.TIMESTEPS, within=NonNegativeReals)
        self.Q = Var(self.GENERICCHPS, m.TIMESTEPS, within=NonNegativeReals)
        self.Y = Var(self.GENERICCHPS, m.TIMESTEPS, within=Binary)

        # constraint rules
        def _H_flow_rule(block, n, t):
            """Link fuel consumption to component inflow."""
            expr = 0
            expr += self.H_F[n, t]
            expr += -m.flow[list(n.fuel_input.keys())[0], n, t]
            return expr == 0

        self.H_flow = Constraint(self.GENERICCHPS,
                                 m.TIMESTEPS,
                                 rule=_H_flow_rule)

        def _Q_flow_rule(block, n, t):
            """Link heat flow to component outflow."""
            expr = 0
            expr += self.Q[n, t]
            expr += -m.flow[n, list(n.heat_output.keys())[0], t]
            return expr == 0

        self.Q_flow = Constraint(self.GENERICCHPS,
                                 m.TIMESTEPS,
                                 rule=_Q_flow_rule)

        def _P_flow_rule(block, n, t):
            """Link power flow to component outflow."""
            expr = 0
            expr += self.P[n, t]
            expr += -m.flow[n, list(n.electrical_output.keys())[0], t]
            return expr == 0

        self.P_flow = Constraint(self.GENERICCHPS,
                                 m.TIMESTEPS,
                                 rule=_P_flow_rule)

        def _H_F_1_rule(block, n, t):
            """Set P_woDH depending on H_F."""
            expr = 0
            expr += -self.H_F[n, t]
            expr += n.alphas[0][t] * self.Y[n, t]
            expr += n.alphas[1][t] * self.P_woDH[n, t]
            return expr == 0

        self.H_F_1 = Constraint(self.GENERICCHPS,
                                m.TIMESTEPS,
                                rule=_H_F_1_rule)

        def _H_F_2_rule(block, n, t):
            """Determine relation between H_F, P and Q."""
            expr = 0
            expr += -self.H_F[n, t]
            expr += n.alphas[0][t] * self.Y[n, t]
            expr += n.alphas[1][t] * (self.P[n, t] + n.Beta[t] * self.Q[n, t])
            return expr == 0

        self.H_F_2 = Constraint(self.GENERICCHPS,
                                m.TIMESTEPS,
                                rule=_H_F_2_rule)

        def _H_F_3_rule(block, n, t):
            """Set upper value of operating range via H_F."""
            expr = 0
            expr += self.H_F[n, t]
            expr += - self.Y[n, t] * \
                (list(n.electrical_output.values())[0].P_max_woDH[t] /
                 list(n.electrical_output.values())[0].Eta_el_max_woDH[t])
            return expr <= 0

        self.H_F_3 = Constraint(self.GENERICCHPS,
                                m.TIMESTEPS,
                                rule=_H_F_3_rule)

        def _H_F_4_rule(block, n, t):
            """Set lower value of operating range via H_F."""
            expr = 0
            expr += self.H_F[n, t]
            expr += - self.Y[n, t] * \
                (list(n.electrical_output.values())[0].P_min_woDH[t] /
                 list(n.electrical_output.values())[0].Eta_el_min_woDH[t])
            return expr >= 0

        self.H_F_4 = Constraint(self.GENERICCHPS,
                                m.TIMESTEPS,
                                rule=_H_F_4_rule)

        def _H_L_FG_max_rule(block, n, t):
            """Set max. flue gas loss as share fuel flow share."""
            expr = 0
            expr += -self.H_L_FG_max[n, t]
            expr += self.H_F[n, t] * \
                list(n.fuel_input.values())[0].H_L_FG_share_max[t]
            return expr == 0

        self.H_L_FG_max_def = Constraint(self.GENERICCHPS,
                                         m.TIMESTEPS,
                                         rule=_H_L_FG_max_rule)

        def _Q_max_res_rule(block, n, t):
            """Set maximum Q depending on fuel and electrical flow."""
            expr = 0
            expr += self.P[n, t] + self.Q[n, t] + self.H_L_FG_max[n, t]
            expr += list(n.heat_output.values())[0].Q_CW_min[t] * self.Y[n, t]
            expr += -self.H_F[n, t]
            # back-pressure characteristics or one-segment model
            if n.back_pressure is True:
                return expr == 0
            else:
                return expr <= 0

        self.Q_max_res = Constraint(self.GENERICCHPS,
                                    m.TIMESTEPS,
                                    rule=_Q_max_res_rule)

        def _H_L_FG_min_rule(block, n, t):
            """Set min. flue gas loss as fuel flow share."""
            # minimum flue gas losses e.g. for motoric CHPs
            if getattr(
                    list(n.fuel_input.values())[0], 'H_L_FG_share_min', None):
                expr = 0
                expr += -self.H_L_FG_min[n, t]
                expr += self.H_F[n, t] * \
                    list(n.fuel_input.values())[0].H_L_FG_share_min[t]
                return expr == 0
            else:
                return Constraint.Skip

        self.H_L_FG_min_def = Constraint(self.GENERICCHPS,
                                         m.TIMESTEPS,
                                         rule=_H_L_FG_min_rule)

        def _Q_min_res_rule(block, n, t):
            """Set minimum Q depending on fuel and eletrical flow."""
            # minimum restriction for heat flows e.g. for motoric CHPs
            if getattr(
                    list(n.fuel_input.values())[0], 'H_L_FG_share_min', None):
                expr = 0
                expr += self.P[n, t] + self.Q[n, t] + self.H_L_FG_min[n, t]
                expr += list(n.heat_output.values())[0].Q_CW_min[t] \
                    * self.Y[n, t]
                expr += -self.H_F[n, t]
                return expr >= 0
            else:
                return Constraint.Skip

        self.Q_min_res = Constraint(self.GENERICCHPS,
                                    m.TIMESTEPS,
                                    rule=_Q_min_res_rule)
Пример #28
0
 def test_abstract_index(self):
     model = AbstractModel()
     model.A = Set()
     model.B = Set()
     model.C = model.A | model.B
     model.x = Expression(model.C)
Пример #29
0
    def __init__(self, y, x, cet='addi', fun='prod', rts='vrs'):
        """
            y : Output variable
            x : Input variables
            cet  = "addi" : Additive composite error term
                 = "mult" : Multiplicative composite error term
            fun  = "prod" : Production frontier
                 = "cost" : Cost frontier
            rts  = "vrs"  : Variable returns to scale
                 = "crs"  : Constant returns to scale
        """

        # TODO(error/warning handling): Check the configuration of the model exist
        self.x = x.tolist()
        self.y = y.tolist()
        self.cet = cet
        self.fun = fun
        self.rts = rts

        if type(self.x[0]) != list:
            self.x = []
            for x_value in x.tolist():
                self.x.append([x_value])

        # Initialize the CNLS model
        self.__model__ = ConcreteModel()

        # Initialize the sets
        self.__model__.I = Set(initialize=range(len(self.y)))
        self.__model__.J = Set(initialize=range(len(self.x[0])))

        # Initialize the variables
        self.__model__.alpha = Var(self.__model__.I, doc='alpha')
        self.__model__.beta = Var(self.__model__.I,
                                  self.__model__.J,
                                  bounds=(0.0, None),
                                  doc='beta')
        self.__model__.epsilon = Var(self.__model__.I, doc='residual')
        self.__model__.frontier = Var(self.__model__.I,
                                      bounds=(0.0, None),
                                      doc='estimated frontier')

        # Setup the objective function and constraints
        self.__model__.objective = Objective(rule=self.__objective_rule(),
                                             sense=minimize,
                                             doc='objective function')
        self.__model__.regression_rule = Constraint(
            self.__model__.I,
            rule=self.__regression_rule(),
            doc='regression equation')
        if self.cet == "mult":
            self.__model__.log_rule = Constraint(
                self.__model__.I,
                rule=self.__log_rule(),
                doc='log-transformed regression equation')
        self.__model__.afriat_rule = Constraint(self.__model__.I,
                                                self.__model__.I,
                                                rule=self.__afriat_rule(),
                                                doc='afriat inequality')

        # Optimize model
        self.optimization_status = 0
        self.problem_status = 0
Пример #30
0
    def __init__(self, y, x, b=None, gy=[1], gx=[1], gb=None, fun='prod', tau=0.9):
        """
            y : Output variables
            x : Input variables
            b : Undesirable output variables
            gy : Output directional vector
            gx : Input directional vector
            gb : Undesirable output directional vector
            fun  = "prod" : Production frontier
                 = "cost" : Cost frontier
        """

        # TODO(error/warning handling): Check the configuration of the model exist
        self.x = x.tolist()
        self.y = y.tolist()
        self.b = b
        self.tau = tau
        self.fun = fun

        self.gy = self._CNLSDDF__to_1d_list(gy)
        self.gx = self._CNLSDDF__to_1d_list(gx)
        self.gb = self._CNLSDDF__to_1d_list(gb)

        if type(self.x[0]) != list:
            self.x = []
            for x_value in x.tolist():
                self.x.append([x_value])

        if type(self.y[0]) != list:
            self.y = []
            for y_value in y.tolist():
                self.y.append([y_value])

        self.__model__ = ConcreteModel()

        # Initialize the sets
        self.__model__.I = Set(initialize=range(len(self.y)))
        self.__model__.J = Set(initialize=range(len(self.x[0])))
        self.__model__.K = Set(initialize=range(len(self.y[0])))

        # Initialize the variables
        self.__model__.alpha = Var(self.__model__.I, doc='alpha')
        self.__model__.beta = Var(
            self.__model__.I, self.__model__.J, bounds=(0.0, None), doc='beta')
        self.__model__.gamma = Var(
            self.__model__.I, self.__model__.K, bounds=(0.0, None), doc='gamma')

        self.__model__.epsilon = Var(self.__model__.I, doc='residuals')
        self.__model__.epsilon_plus = Var(
            self.__model__.I, bounds=(0.0, None), doc='positive error term')
        self.__model__.epsilon_minus = Var(
            self.__model__.I, bounds=(0.0, None), doc='negative error term')

        if type(self.b) != type(None):
            self.b = b.tolist()
            self.gb = self._CNLSDDF__to_1d_list(gb)

            if type(self.b[0]) != list:
                self.b = []
                for b_value in b.tolist():
                    self.b.append([b_value])

            self.__model__.L = Set(initialize=range(len(self.b[0])))
            self.__model__.delta = Var(
                self.__model__.I, self.__model__.L, bounds=(0.0, None), doc='delta')

        self.__model__.objective = Objective(rule=self._CQR__objective_rule(),
                                             sense=minimize,
                                             doc='objective function')

        self.__model__.error_decomposition = Constraint(self.__model__.I,
                                                        rule=self._CQR__error_decomposition(),
                                                        doc='decompose error term')

        self.__model__.regression_rule = Constraint(self.__model__.I,
                                                    rule=self.__regression_rule(),
                                                    doc='regression equation')

        self.__model__.translation_rule = Constraint(self.__model__.I,
                                                     rule=self._CNLSDDF__translation_property(),
                                                     doc='translation property')

        self.__model__.afriat_rule = Constraint(self.__model__.I,
                                                self.__model__.I,
                                                rule=self.__afriat_rule(),
                                                doc='afriat inequality')

        # Optimize model
        self.optimization_status = 0
        self.problem_status = 0