Skip to content
1 change: 1 addition & 0 deletions RELEASE_NOTES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Migration notes
All changes
-----------

- A tutorial for adding an upper bound on investment (:pull:`602`).
- Add additional oscillation detection mechanism for macro iterations (:pull:`645`, :pull:`676`)
- Adjust default `lpmethod` from "Dual Simplex" (2) to "Barrier" (4); do NOT remove `cplex.opt` file(s) after solving workflow completes (:pull:`657`).
- Adjust :meth:`.Scenario.add_macro` calculations for pandas 1.5.0 (:pull:`656`).
Expand Down
2 changes: 1 addition & 1 deletion message_ix/model/MESSAGE/data_load.gms
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ duration_period, duration_time, interestrate,
resource_volume, resource_cost, is_bound_extraction_up, bound_extraction_up, resource_remaining,
* technology technical-engineering parameters and economic costs
input, output, construction_time, technical_lifetime
capacity_factor, operation_factor, min_utilization_factor, inv_cost, fix_cost, var_cost,
capacity_factor, operation_factor, min_utilization_factor, inv_cost, fix_cost, var_cost, bound_investment_up
* upper and lower bounds on new capacity investment, total installed capacity and activity (including mapping sets)
is_bound_new_capacity_up, is_bound_new_capacity_lo, bound_new_capacity_up, bound_new_capacity_lo,
is_bound_total_capacity_up, is_bound_total_capacity_lo, bound_total_capacity_up, bound_total_capacity_lo,
Expand Down
59 changes: 51 additions & 8 deletions message_ix/model/MESSAGE/model_core.gms
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
* :math:`COMMODITY\_BALANCE_{n,c,l,y,h} \in \mathbb{R}` Auxiliary variable for right-hand side of :ref:`commodity_balance`
* :math:`STORAGE_{n,t,m,l,c,y,h} \in \mathbb{R}` State of charge or content of storage at each sub-annual time slice
* :math:`STORAGE\_CHARGE_{n,t,m,l,c,y,h} \in \mathbb{R}` Charging of storage in each sub-annual time slice (negative for discharging)
* :math:`INVEST_{n,y} \in \mathbb{R}` Investment per region over time
* ======================================================== ====================================================================================
*
* The index :math:`y^V` is the year of construction (vintage) wherever it is necessary to
Expand Down Expand Up @@ -107,6 +108,8 @@ Positive Variables
LAND(node,land_scenario,year_all) relative share of land-use scenario
* content of storage
STORAGE(node,tec,mode,level,commodity,year_all,time) state of charge (SoC) of storage at each sub-annual time slice (positive)
* investment per region and year
INVEST(node,year_all) investment per model region and year
;

Variables
Expand Down Expand Up @@ -290,6 +293,8 @@ Equations
STORAGE_BALANCE balance of the state of charge of storage
STORAGE_BALANCE_INIT balance of the state of charge of storage at sub-annual time slices with initial storage content
STORAGE_INPUT connecting an input commodity to maintain the activity of storage container (not stored commodity)
INVESTMENT_EQUIVALENCE investment per node and year
INVESTMENT_CONSTRAINT upper bound on investment per node and year
;
*----------------------------------------------------------------------------------------------------------------------*
* equation statements *
Expand Down Expand Up @@ -337,10 +342,8 @@ OBJECTIVE..
*
* .. math::
* COST\_NODAL_{n,y} & = \sum_{c,g} \ resource\_cost_{n,c,g,y} \cdot EXT_{n,c,g,y} \\
* & + \sum_{t} \
* \bigg( inv\_cost_{n,t,y} \cdot construction\_time\_factor_{n,t,y} \\
* & \quad \quad \quad \cdot end\_of\_horizon\_factor_{n,t,y} \cdot CAP\_NEW_{n,t,y} \\[4 pt]
* & \quad \quad + \sum_{y^V \leq y} \ fix\_cost_{n,t,y^V,y} \cdot CAP_{n,t,y^V,y} \\
* & + INVEST_{n, y} + \sum_{t} \
* \bigg( \sum_{y^V \leq y} \ fix\_cost_{n,t,y^V,y} \cdot CAP_{n,t,y^V,y} \\
* & \quad \quad + \sum_{\substack{y^V \leq y \\ m,h}} \ var\_cost_{n,t,y^V,y,m,h} \cdot ACT_{n,t,y^V,y,m,h} \\
* & \quad \quad + \Big( abs\_cost\_new\_capacity\_soft\_up_{n,t,y} \\
* & \quad \quad \quad
Expand Down Expand Up @@ -371,10 +374,9 @@ COST_ACCOUNTING_NODAL(node, year)..
SUM((commodity,grade)$( map_resource(node,commodity,grade,year) ),
resource_cost(node,commodity,grade,year) * EXT(node,commodity,grade,year) )
* technology capacity investment, maintainance, operational cost
+ INVEST(node, year)
+ SUM((tec)$( map_tec(node,tec,year) ),
( inv_cost(node,tec,year) * construction_time_factor(node,tec,year)
* end_of_horizon_factor(node,tec,year) * CAP_NEW(node,tec,year)
+ SUM(vintage$( map_tec_lifetime(node,tec,vintage,year) ),
(SUM(vintage$( map_tec_lifetime(node,tec,vintage,year) ),
fix_cost(node,tec,vintage,year) * CAP(node,tec,vintage,year) ) )$( inv_tec(tec) )
+ SUM((vintage,mode,time)$( map_tec_lifetime(node,tec,vintage,year) AND map_tec_act(node,tec,year,mode,time) ),
var_cost(node,tec,vintage,year,mode,time) * ACT(node,tec,vintage,year,mode,time) )
Expand Down Expand Up @@ -447,13 +449,54 @@ COST_ACCOUNTING_NODAL(node, year)..
%SLACK_RELATION_BOUND_LO% + 1e6 * SLACK_RELATION_BOUND_LO(relation,node,year)$( is_relation_lower(relation,node,year) )
)
;

***
* Here, :math:`n^L \in N(n)` are all nodes :math:`n^L` that are sub-nodes of node :math:`n`.
* The subset of technologies :math:`t \in T(\widehat{t})` are all tecs that belong to category :math:`\widehat{t}`,
* and similar notation is used for emissions :math:`e \in E`.
***

***
* Regional investment cost accounting
* ----------------------------------------
*
* Accounting of regional investment costs over time
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*
* .. _equation_investment_equivalence:
*
* Equation INVESTMENT_EQUIVALENCE
* """"""""""""""""""""""""""""""
*
* This equation calculates the regional investment costs over time.
*
* .. math::
* INVEST_{n,y} & = \sum_{t} \
* \bigg( inv\_cost_{n,t,y} \cdot construction\_time\_factor_{n,t,y} \\
* & \quad \quad \quad \cdot end\_of\_horizon\_factor_{n,t,y} \cdot CAP\_NEW_{n,t,y}) \\
***

INVESTMENT_EQUIVALENCE(node, year) ..
INVEST(node, year) =E= SUM(tec$( map_tec(node,tec,year) ),
( inv_cost(node,tec,year) * construction_time_factor(node,tec,year)
* end_of_horizon_factor(node,tec,year) * CAP_NEW(node,tec,year) )$( inv_tec(tec) )
)
;

***
*
* .. _equation_investment_constraint:
*
* Equation INVESTMENT_CONSTRAINT
* """"""""""""""""""""""""""""""
*
* This equation puts an upper bound on the regional investment costs over time.
*
* .. math::
* INVEST_{n,y} \leq bound\_investment\_up_{n,y} \\
***
INVESTMENT_CONSTRAINT(node, year)$(bound_investment_up(node, year) ) ..
INVEST(node, year) =L= bound_investment_up(node, year)
;
*----------------------------------------------------------------------------------------------------------------------*
***
* .. _section_resource_commodity:
Expand Down
3 changes: 3 additions & 0 deletions message_ix/model/MESSAGE/parameter_def.gms
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,8 @@ Parameters
* - ``node`` | ``tec`` | ``year``
* * - beyond_horizon_factor
* - ``node`` | ``tec`` | ``year``
* * - bound_investment_up
* - ``node`` | ``year``
*
*
***
Expand All @@ -583,6 +585,7 @@ Parameters
end_of_horizon_factor(node,tec,year_all) multiplier for value of investment at end of model horizon
beyond_horizon_lifetime(node,tec,year_all) remaining technical lifetime at the end of model horizon
beyond_horizon_factor(node,tec,year_all) discount factor of remaining lifetime beyond model horizon
bound_investment_up(node, year_all) upper bound on investment per node and year
;

*----------------------------------------------------------------------------------------------------------------------*
Expand Down
3 changes: 3 additions & 0 deletions message_ix/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ def item(ix_type, expr):
"bound_activity_up": item("par", "nl t ya m h"),
"bound_emission": item("par", "n type_emission type_tec type_year"),
"bound_extraction_up": item("par", "n c g y"),
"bound_investment_up": item("par", "n y"),
"bound_new_capacity_lo": item("par", "nl t yv"),
"bound_new_capacity_up": item("par", "nl t yv"),
"bound_total_capacity_lo": item("par", "nl t ya"),
Expand Down Expand Up @@ -269,6 +270,8 @@ def item(ix_type, expr):
#
# Variables
#
# # Investment
"INVEST": item("var", "n y"),
# # Activity
# "ACT": item("var", "nl t yv ya m h"),
# # Maintained capacity
Expand Down
6 changes: 3 additions & 3 deletions message_ix/tests/test_reporting.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def test_reporter_from_scenario(message_test_mp):
rep = Reporter.from_scenario(scen)

# Number of quantities available in a rudimentary MESSAGEix Scenario
assert len(rep.graph["all"]) == 125
assert len(rep.graph["all"]) == 127

# Quantities have short dimension names
assert "demand:n-c-l-y-h" in rep
Expand All @@ -69,11 +69,11 @@ def test_reporter_from_scenario(message_test_mp):
assert_qty_equal(obs, demand, check_attrs=False)

# ixmp.Reporter pre-populated with only model quantities and aggregates
assert len(rep_ix.graph) == 5609
assert len(rep_ix.graph) == 5617

# message_ix.Reporter pre-populated with additional, derived quantities
# This is the same value as in test_tutorials.py
assert len(rep.graph) == 13074
assert len(rep.graph) == 13082

# Derived quantities have expected dimensions
vom_key = rep.full_key("vom")
Expand Down
3 changes: 2 additions & 1 deletion message_ix/tests/test_tutorials.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@
(("westeros", "westeros_soft_constraints"), [], {}),
(("westeros", "westeros_addon_technologies"), [], {}),
(("westeros", "westeros_historical_new_capacity"), [], {}),
(("westeros", "westeros_investment"), [], {}),
# NB this is the same value as in test_reporter()
(("westeros", "westeros_report"), [("len-rep-graph", 13074)], {}),
(("westeros", "westeros_report"), [("len-rep-graph", 13082)], {}),
((AT, "austria"), [("solve-objective-value", 206321.90625)], {}),
(
(AT, "austria_single_policy"),
Expand Down
6 changes: 6 additions & 0 deletions tutorial/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,12 @@ framework, such as used in global research applications of |MESSAGEix|.
#. Import and combine data from multiple files to create a new scenario
(:tut:`westeros/westeros_baseline_using_xlsx_import_part2.ipynb`).

#. Extend the features of :mod:`message_ix` and :mod:`ixmp`:

#. Extend the GAMS formulation by adding new sets, parameters, variables,
and equations, and change the :mod:`message_ix` code accordingly
(:tut:`westeros/westeros_investment.ipynb`).

.. _austria-tutorials:

Austrian energy system
Expand Down
Loading