From 4bc4fac07d9637f989cf4bf00e3138ecb27a8980 Mon Sep 17 00:00:00 2001 From: Lukas Eggert Date: Thu, 8 Jan 2026 14:21:47 +0000 Subject: [PATCH 01/24] Update parameter and variable description; included new parameters and variables; deleted old --- message_ix/model/MACRO/macro_core.gms | 39 ++++++++++++++------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/message_ix/model/MACRO/macro_core.gms b/message_ix/model/MACRO/macro_core.gms index 23b3ba259..0e164e10f 100755 --- a/message_ix/model/MACRO/macro_core.gms +++ b/message_ix/model/MACRO/macro_core.gms @@ -35,21 +35,27 @@ * ================================== ================================================================================================================================ * Parameter Description * ================================== ================================================================================================================================ -* :math:`\text{duration_period}_y` Number of years in time period :math:`y` (forward diff) -* :math:`\text{total_cost}_{n,y}` Total system costs in region :math:`n` and period :math:`y` from MESSAGE model run -* :math:`\text{enestart}_{n,s,y}` Consumption level of (commercial) end-use services :math:`s` in region :math:`n` and period :math:`y` from MESSAGE model run -* :math:`\text{eneprice}_{n,s,y}` Shadow prices of (commercial) end-use services :math:`s` in region :math:`n` and period :math:`y` from MESSAGE model run +* :math:`\text{period}_t` Number of years in time period :math:`t` (forward diff) +* :math:`\text{total_cost}_{n,t}` Total system costs in region :math:`n` and period :math:`t` from MESSAGE model run +* :math:`\text{enestart}_{n,s,t}` Consumption level of (commercial) end-use services :math:`s` in region :math:`n` and period :math:`t` from MESSAGE model run +* :math:`\text{p}_{n,s,t}` Shadow prices of (commercial) end-use services :math:`s` in region :math:`n` and period :math:`t` from MESSAGE model run +* :math:`\text{E}_{min,n,s,t}` Subsistence level of direct energy consumption (end-use service) in region :math:`n`, sector :math:`s` and period :math:`t` +* :math:`\text{h}_{n,s,t}` Share of the direct energy consumption of the total energy production in region :math:`n`, sector :math:`s` and period :math:`t` + * :math:`\epsilon_n` Elasticity of substitution between capital-labor and total energy in region :math:`n` -* :math:`\rho_n` :math:`\epsilon - 1 / \epsilon` where :math:`\epsilon` is the elasticity of subsitution in region :math:`n` -* :math:`\text{depr}_n` Annual depreciation rate in region :math:`n` +* :math:`\rho_n` :math:`\epsilon - 1 / \epsilon` where :math:`\epsilon` is the elasticity of substitution in region :math:`n` +* :math:`\beta_n` Consumption value share parameter in region :math:`n` +* :math:`\sigma_{n,s}` Direct energy consumption value share parameter in region :math:`n` and of sector :math:`s` +* :math:`\delta_n` Annual depreciation rate in region :math:`n` * :math:`\alpha_n` Capital value share parameter in region :math:`n` * :math:`a_n` Production function coefficient of capital and labor in region :math:`n` -* :math:`b_{n,s}` Production function coefficients of the different end-use sectors in region :math:`n`, sector :math:`s` and period :math:`y` -* :math:`\text{udf}_{n,y}` Utility discount factor in period year in region :math:`n` and period :math:`y` -* :math:`\text{newlab}_{n,y}` New vintage of labor force in region :math:`n` and period :math:`y` -* :math:`\text{grow}_{n,y}` Annual growth rates of potential GDP in region :math:`n` and period :math:`y` -* :math:`\text{aeei}_{n,s,y}` Autonomous energy efficiency improvement (AEEI) in region :math:`n`, sector :math:`s` and period :math:`y` -* :math:`\text{fin_time}_{n,y}` finite time horizon correction factor in utility function in region :math:`n` and period :math:`y` +* :math:`b_{n,s}` Production function coefficients of the different end-use sectors in region :math:`n`, sector :math:`s` and period :math:`t` +* :math:`\text{udf}_{n,t}` Utility discount factor in period year in region :math:`n` and period :math:`t` +* :math:`\text{L}_{n,t}` Labor force in region :math:`n` and period :math:`t` +* :math:`\text{w}_{n,t}` Wage rate in region :math:`n` and period :math:`t` +* :math:`\text{grow}_{n,t}` Annual growth rates of potential GDP in region :math:`n` and period :math:`t` +* :math:`\text{aeei}_{n,s,t}` Autonomous energy efficiency improvement (AEEI) in region :math:`n`, sector :math:`s` and period :math:`t` +* :math:`\text{fin_time}_{n,t}` Finite time horizon correction factor in utility function in region :math:`n` and period :math:`t` * ================================== ================================================================================================================================ *** @@ -65,15 +71,12 @@ * Variable Definition Description * =============================== =========================================================== ============================================================================================================== * :math:`\text{K}_{n,y}` :math:`\text{K}_{n, y}\geq 0 ~ \forall n, y` Capital stock in region :math:`n` and period :math:`y` -* :math:`\text{KN}_{n,y}` :math:`\text{KN}_{n, y}\geq 0 ~ \forall n, y` New Capital vintage in region :math:`n` and period :math:`y` * :math:`\text{Y}_{n,y}` :math:`\text{Y}_{n, y}\geq 0 ~ \forall n, y` Total production in region :math:`n` and period :math:`y` -* :math:`\text{YN}_{n,y}` :math:`\text{YN}_{n, y}\geq 0 ~ \forall n, y` New production vintage in region :math:`n` and period :math:`y` * :math:`\text{C}_{n,y}` :math:`\text{C}_{n, y}\geq 0 ~ \forall n, y` Consumption in region :math:`n` and period :math:`y` -* :math:`\text{I}_{n,y}` :math:`\text{I}_{n, y}\geq 0 ~ \forall n, y` Investment in region :math:`n` and period :math:`y` * :math:`\text{PHYSENE}_{n,s,y}` :math:`\text{PHYSENE}_{n, s, y}\geq 0 ~ \forall n, s, y` Physical end-use service use in region :math:`n`, sector :math:`s` and period :math:`y` -* :math:`\text{PRODENE}_{n,s,y}` :math:`\text{PRODENE}_{n, s, y}\geq 0 ~ \forall n, s, y` Value of end-use service in the production function in region :math:`n`, sector :math:`s` and period :math:`y` -* :math:`\text{NEWENE}_{n,s,y}` :math:`\text{NEWENE}_{n, s, y}\geq 0 ~ \forall n, s, y` New end-use service in the production function in region :math:`n`, sector :math:`s` and period :math:`y` -* :math:`\text{EC}_{n,y}` :math:`\text{EC} \in \left[-\infty..\infty\right]` Approximation of system costs based on MESSAGE results +* :math:`\text{TE}_{n,s,y}` :math:`\text{TE}_{n, s, y}\geq 0 ~ \forall n, s, y` Value of total end-use service in the production function and utility function in region :math:`n`, sector :math:`s` and period :math:`y` +* :math:`\text{E}_{n,s,y}` :math:`\text{E}_{n, s, y}\geq 0 ~ \forall n, s, y` Value of direct energy consumption of end-use service of households in the utility function in region :math:`n`, sector :math:`s` and period :math:`y` +* :math:`\text{YE}_{n,s,y}` :math:`\text{YE}_{n, s, y}\geq 0 ~ \forall n, s, y` Value of end-use service energy consumption in the production function in region :math:`n`, sector :math:`s` and period :math:`y` * :math:`\text{UTILITY}` :math:`\text{UTILITY} \in \left[-\infty..\infty\right]` Utility function (discounted log of consumption) * =============================== =========================================================== ============================================================================================================== * From 15a5ac31e2cda7a6889b0856ba1796cbf86cfc60 Mon Sep 17 00:00:00 2001 From: Lukas Eggert Date: Thu, 8 Jan 2026 14:23:37 +0000 Subject: [PATCH 02/24] Update GAMS parameter and variable definition --- message_ix/model/MACRO/macro_core.gms | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/message_ix/model/MACRO/macro_core.gms b/message_ix/model/MACRO/macro_core.gms index 0e164e10f..940b073bf 100755 --- a/message_ix/model/MACRO/macro_core.gms +++ b/message_ix/model/MACRO/macro_core.gms @@ -88,21 +88,18 @@ POSITIVE VARIABLES K(node, year_all) Capital stock in period year - KN(node, year_all) New Capital vintage in period year - Y(node, year_all) Production in period year - YN(node, year_all) New production vintage in period year + Y(node, year_all) Total GDP - PHYSENE(node, sector, year_all) Physical end-use service or commodity use - PRODENE(node, sector, year_all) Value of end-use services or commodities in the production function - NEWENE(node, sector, year_all) New end-use service or commodity (production function value) + PHYSENE(node, sector, year_all) + TE(node, sector, year_all) Value of end-use services or commodities in the production function + E(node, sector, year_all) + YE(node, sector, year_all) C(node, year_all) Consumption (Trillion $) - I(node, year_all) Investment (Trillion $) ; VARIABLES UTILITY Utility function (discounted log of consumption) - EC(node, year_all) System costs (Trillion $) based on MESSAGE model run ; Variables From abd38c4bf3cc2b4ae1c7673819a936dbd9f1ea4b Mon Sep 17 00:00:00 2001 From: Lukas Eggert Date: Thu, 8 Jan 2026 14:26:53 +0000 Subject: [PATCH 03/24] Update new equation description --- message_ix/model/MACRO/macro_core.gms | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/message_ix/model/MACRO/macro_core.gms b/message_ix/model/MACRO/macro_core.gms index 940b073bf..c876c19f1 100755 --- a/message_ix/model/MACRO/macro_core.gms +++ b/message_ix/model/MACRO/macro_core.gms @@ -113,19 +113,18 @@ Variables EQUATIONS UTILITY_FUNCTION Utility function (discounted log of consumption summed over all projection periods) - CAPITAL_CONSTRAINT(node, year_all) Capital constraint + + CAPITAL(node, year_all) Capital (wealth) formation - NEW_CAPITAL(node, year_all) New capital - NEW_PRODUCTION(node, year_all) New production + PRODUCTION(node, year_all) Total production across all vintages - TOTAL_CAPITAL(node, year_all) Total capital stock across all vintages - TOTAL_PRODUCTION(node, year_all) Total production across all vintages + ENERGY_ACCOUNTING(node, sector, *) New Energy Accounting Equations: Splitting TE into E and YE + ENERGY_ACCOUNTING2(node, sector, *) New Energy Accounting Equations: Defining E as share of the total energy TE + TE_EQUATION(node, sector, *) New Energy Accounting Equations: Determining TE based on optimal direct energy consumption of the households - NEW_ENERGY(node, sector, year_all) New end-use services or commodities (production function) - ENERGY_SUPPLY(node, sector, *) Supply of end-use services or commodities + ENERGY_SUPPLY(node, sector, year_all) New Energy Accounting Equations: PHYSENE - TE relation with aeei - COST_ENERGY(node, year_all) system costs approximation based on MESSAGE input - TERMINAL_CONDITION(node, year_all) Terminal condition + TERMINAL_CONDITION(node, year_all) New terminal condition ; * ------------------------------------------------------------------------------ From db4042a5bb3500ba69b8692cfc94c5ed9f963bd9 Mon Sep 17 00:00:00 2001 From: Lukas Eggert Date: Thu, 8 Jan 2026 14:38:29 +0000 Subject: [PATCH 04/24] Update model equations and descriptions --- message_ix/model/MACRO/macro_core.gms | 72 +++++++++++++-------------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/message_ix/model/MACRO/macro_core.gms b/message_ix/model/MACRO/macro_core.gms index c876c19f1..562b1db67 100755 --- a/message_ix/model/MACRO/macro_core.gms +++ b/message_ix/model/MACRO/macro_core.gms @@ -134,17 +134,14 @@ EQUATIONS *** * Equation UTILITY_FUNCTION * --------------------------------- -* The utility function which is maximized sums up the discounted logarithm of consumption of a single representative producer-consumer over the entire time horizon -* of the model. +* The utility function, which is maximized, sums the discounted logarithm of consumption :math:`\text{C}_{n,y}` and direct energy consumption +* of end-use services :math:`\text{E}_{n,s,y}` of a single representative household over the entire time horizon of the model. * -* .. math:: \text{UTILITY} = \sum_{n} \bigg( & \sum_{y | ( ( {ord}( y ) > 1 ) \wedge ( {ord}( y ) < | y | ) )} \text{udf}_{n, y} \cdot {\log}( \text{C}_{n, y} ) \cdot \text{duration_period}_{y} \\ -* + &\sum_{y | ( {ord}( y ) = | y | ) } \text{udf}_{n, y} \cdot {\log}( \text{C}_{n, y} ) \cdot \big( \text{duration_period}_{y-1} + \frac{1}{\text{fin_time}_{n, y}} \big) \bigg) +* The utility function and the capital formulation of the optimization problem are derived in previously (See equations 10 and 13 of the model documentation). +* +* .. math:: \text{UTILITY} = \sum_{n} \bigg( & \sum_{y | ( ( {ord}( y ) > 1 ) \wedge ( {ord}( y ) < | y | ) )} \text{udf}_{n, y} \cdot \bigg( (\beta_n + \sum_{s=1}^{3} \sigma_{s,n}) \log(\text{C}_{n, y}) - \sum_{s=1}^{3} \sigma_{s,n} \log(\text{p}_{n,s,y}) + \sum_{s=1}^{3} \sigma_{s,n} \log\left(\frac{\sigma_{s,n}}{\beta_n}\right) \bigg) \cdot \text{duration_period}_{y} \\ +* + &\sum_{y | ( {ord}( y ) = | y | ) } \text{udf}_{n, y} \cdot \bigg( (\beta_n + \sum_{s=1}^{3} \sigma_{s,n}) \log(\text{C}_{n, y}) - \sum_{s=1}^{3} \sigma_{s,n} \log(\text{p}_{n,s,y}) + \sum_{s=1}^{3} \sigma_{s,n} \log\left(\frac{\sigma_{s,n}}{\beta_n}\right) \bigg) \cdot \big( \text{duration_period}_{y-1} + \frac{1}{\text{fin_time}_{n, y}} \big) \bigg) * -* The utility discount rate for period :math:`y` is set to :math:`\text{drate}_{n} - \text{grow}_{n,y}`, where :math:`\text{drate}_{n}` is the discount rate used in MESSAGE, typically set to 5%, -* and :math:`\text{grow}` is the potential GDP growth rate. This choice ensures that in the steady state, the optimal growth rate is identical to the potential GDP growth rates :math:`\text{grow}`. -* The values for the utility discount rates are chosen for descriptive rather than normative reasons. The term :math:`\frac{\text{duration_period}_{y} + \text{duration_period}_{y-1}}{2}` mutliples the -* discounted logarithm of consumption with the period length. The final period is treated separately to include a correction factor :math:`\frac{1}{\text{fin_time}_{n, y}}` reflecting -* the finite time horizon of the model. Note that the sum over nodes :math:`\text{node_active}` is artificial, because :math:`\text{node_active}` only contains one element. * *** @@ -152,50 +149,49 @@ UTILITY_FUNCTION.. UTILITY =E= SUM(node_active, 1000 * (SUM(year $ (NOT macro_base_period(year) AND NOT last_period(year)), - udf(node_active, year) * LOG(C(node_active, year)) * duration_period(year)) - + SUM(year $ last_period(year), - udf(node_active, year) * LOG(C(node_active, year)) * (duration_period(year) + 1/finite_time_corr(node_active, year)))) + udf(node_active, year) * ( (alpha(node_active) + beta_rc_spec(node_active) + beta_rc_therm(node_active) + beta_transport(node_active)) * LOG(C(node_active, year)) + - beta_rc_spec(node_active) * LOG(eneprice(node_active, 'rc_spec', year)/1000) + beta_rc_spec(node_active) * LOG(beta_rc_spec(node_active)/alpha(node_active)) + - beta_rc_therm(node_active) * LOG(eneprice(node_active, 'rc_therm', year)/1000) + beta_rc_therm(node_active) * LOG(beta_rc_therm(node_active)/alpha(node_active)) + - beta_transport(node_active) * LOG(eneprice(node_active, 'transport', year)/1000) + beta_transport(node_active) * LOG(beta_transport(node_active)/alpha(node_active)) ) * duration_period(year) ) + + SUM(year $ last_period(year), + udf(node_active, year) * ( (alpha(node_active) + beta_rc_spec(node_active) + beta_rc_therm(node_active) + beta_transport(node_active)) * LOG(C(node_active, year)) + - beta_rc_spec(node_active) * LOG(eneprice(node_active, 'rc_spec', year)/1000) + beta_rc_spec(node_active) * LOG(beta_rc_spec(node_active)/alpha(node_active)) + - beta_rc_therm(node_active) * LOG(eneprice(node_active, 'rc_therm', year)/1000) + beta_rc_therm(node_active) * LOG(beta_rc_therm(node_active)/alpha(node_active)) + - beta_transport(node_active) * LOG(eneprice(node_active, 'transport', year)/1000) + beta_transport(node_active) * LOG(beta_transport(node_active)/alpha(node_active)) ) * (duration_period(year) ) + 1/finite_time_corr(node_active, year)) ) ) ; *** -* Equation CAPITAL_CONSTRAINT +* Equation CAPITAL * --------------------------------- -* The following equation specifies the allocation of total production among current consumption :math:`\text{C}_{n, y}`, investment into building up capital stock excluding -* the sectors represented in MESSAGE :math:`\text{I}_{n, y}` and the MESSAGE system costs :math:`\text{EC}_{n, y}` which are derived from a previous MESSAGE model run. As described in :cite:`Manne-Richels-1992`, the first-order -* optimality conditions lead to the Ramsey rule for the optimal allocation of savings, investment and consumption over time. * -* .. math:: \text{Y}_{n, y} = \text{C}_{n, y} + \text{I}_{r, y} + \text{EC}_{n, y} \qquad \forall{n, y} +* The household maximizes its utility subject to the constraint on wealth accumulation of capital in the sectors not represented in the energy model MESSAGE. +* The net capital (or wealth) formation :math:`\text{K}_{n,t}` is derived from the existing capital stock, returns on capital, labor income, minus the expenses +* for direct energy consumption and all other consumption goods, as well as depreciation of the previous capital stock. * -*** - -CAPITAL_CONSTRAINT(node_active, year).. -Y(node_active, year) =E= -C(node_active, year) + I(node_active, year) + EC(node_active, year) -; - -*** -* Equation NEW_CAPITAL -* --------------------------------- -* The accumulation of capital in the sectors not represented in MESSAGE is governed by new capital stock equation. Net capital formation :math:`\text{KN}_{n,y}` is derived from gross -* investments :math:`\text{I}_{n,y}` minus depreciation of previsouly existing capital stock. -* -* .. math:: \text{KN}_{n,y} = \text{duration_period}_{y} \cdot \text{I}_{n,y} \qquad \forall{n, y > 1} +* .. math:: \text{K}_{t+1,n} = (1 - \delta_{n})^{\text{period}_{t}} \text{K}_{t,n} + ((1 + r_{t,n})^{\text{period}_{t}} - 1) \text{K}_{t,n} + \text{period}_{t} \left( w_{t,n} L_{t,n} - \sum_{s=1}^{3} p_{t,s,n} L_{n,t} E_{min,t,s,n} - \frac{\beta + \sum_{s=1}^{3} \sigma_{s,n}}{\beta} C_{t,n} \right) \qquad (15) * -* Here, the initial boundary condition for the base year :math:`y_0` implies for the investments that :math:`\text{I}_{n,y_0} = (\text{grow}_{n,y_0} + \text{depr}_{n}) \cdot \text{kgdp}_{n} \cdot \text{gdp}_{n,y_0}`. *** -NEW_CAPITAL(node_active, year) $ (NOT macro_base_period(year)).. -KN(node_active, year) =E= duration_period(year) * I(node_active, year) +CAPITAL(node_active, year) $ (NOT macro_base_period(year)).. +K(node_active, year) =E= +SUM(year2$( seq_period(year2,year) ), K(node_active, year2) * (1 - depr(node_active))**duration_period(year2) + K(node_active, year2) * ((1 + interestrate(year2))**duration_period(year2) - 1) ++ duration_period(year2) * labor(node_active, year2) * wage(node_active, year2) +- duration_period(year2) * eneprice(node_active, 'rc_spec', year2)/1000 * labor(node_active, year2) * EMIN(node_active) +- duration_period(year2) * eneprice(node_active, 'rc_therm', year2)/1000 * labor(node_active, year2) * EMIN(node_active) +- duration_period(year2) * eneprice(node_active, 'transport', year2)/1000 * labor(node_active, year2) * EMIN(node_active) +- duration_period(year2) * (((alpha(node_active) + beta_rc_spec(node_active) + beta_rc_therm(node_active) + beta_transport(node_active))/alpha(node_active))) * C(node_active, year2) +) ; *** -* Equation NEW_PRODUCTION +* Equation PRODUCTION * --------------------------------- -* MACRO employs a nested constant elasticity of substitution (CES) production function with capital, labor and the (commercial) end-use services -* represented in MESSAGE as inputs. This version of the production function is equaivalent to that in MARKAL-MACRO. * -* .. math:: \text{YN}_{n,y} = { \left( {a}_{n} \cdot \text{KN}_{n, y}^{ ( {\rho}_{n} \cdot {\alpha}_{n} ) } \cdot \text{newlab}_{n, y}^{ ( {\rho}_{n} \cdot ( 1 - {\alpha}_{n} ) ) } + \displaystyle \sum_{s} ( {b}_{n, s} \cdot \text{NEWENE}_{n, s, y}^{{\rho}_{n}} ) \right) }^{ \frac{1}{{\rho}_{n}} } \qquad \forall{ n, y > 1} +* We implement a nested constant elasticity of substitution (CES) production function with capital, labor, and the (commercial) end-use services +* represented in MESSAGE as inputs. :math:`\text{Y}_{n,t}` should correspond to gross domestic product (GDP). +* +* .. math:: \text{Y}_{n,t} = \left( a_{n} \cdot \text{K}_{n, t}^{ ( \rho_{n} \cdot \alpha_{n} ) } \cdot \text{L}_{n, t}^{ ( \rho_{n} \cdot ( 1 - \alpha_{n} ) ) } + \sum_{s} ( b_{n, s} \cdot \text{YE}_{n, s, t}^{\rho_{n}} ) \right)^{ \frac{1}{\rho_{n}} } \qquad \forall n, t > 1 \qquad (16) * *** From 22db222c7fd79f6775c34e995381e7feb39c6039 Mon Sep 17 00:00:00 2001 From: Lukas Eggert Date: Thu, 8 Jan 2026 14:39:12 +0000 Subject: [PATCH 05/24] Update model definition --- message_ix/model/MACRO/macro_core.gms | 133 ++++++++------------------ 1 file changed, 41 insertions(+), 92 deletions(-) diff --git a/message_ix/model/MACRO/macro_core.gms b/message_ix/model/MACRO/macro_core.gms index 562b1db67..4da7f7877 100755 --- a/message_ix/model/MACRO/macro_core.gms +++ b/message_ix/model/MACRO/macro_core.gms @@ -195,109 +195,60 @@ SUM(year2$( seq_period(year2,year) ), K(node_active, year2) * (1 - depr(node_act * *** -NEW_PRODUCTION(node_active, year) $ (NOT macro_base_period(year)).. -YN(node_active, year) =E= -( LAKL(node_active) * KN(node_active, year)**(rho(node_active) * kpvs(node_active)) * newlab(node_active, year)**(RHO(node_active) * (1 - kpvs(node_active))) -+ SUM(sector, PRFCONST(node_active, sector) * NEWENE(node_active, sector, year)**rho(node_active)) )**(1/rho(node_active)) +PRODUCTION(node_active, year) $ (NOT macro_base_period(year)).. +Y(node_active, year) =E= +(LAKL(node_active) * K(node_active, year)**(rho(node_active) * kpvs(node_active)) * labor(node_active, year)**(RHO(node_active) * (1 - kpvs(node_active))) ++ PRFCONST(node_active, 'i_spec') * YE(node_active, 'i_spec', year)**rho(node_active) ++ PRFCONST(node_active, 'i_therm') * YE(node_active, 'i_therm', year)**rho(node_active) ++ (1-h(node_active, 'rc_spec')) * PRFCONST(node_active, 'rc_spec') * YE(node_active, 'rc_spec', year)**rho(node_active) ++ (1-h(node_active, 'rc_therm')) * PRFCONST(node_active, 'rc_therm') * YE(node_active, 'rc_therm', year)**rho(node_active) ++ (1-h(node_active, 'transport')) * PRFCONST(node_active, 'transport') * YE(node_active, 'transport', year)**rho(node_active) +)**(1/rho(node_active)) ; *** -* Equation TOTAL_CAPITAL +* Equations NEW ENERGY ACCOUNTING * --------------------------------- -* Equivalent to the total production equation above, the total capital stock, again excluding those sectors which are modeled in MESSAGE, is then simply a summation -* of capital stock in the previous period :math:`y-1`, depreciated with the depreciation rate :math:`\text{depr}_{n}`, and the capital stock added in the current period :math:`y`. -* -* .. math:: \text{K}_{n, y} = \text{K}_{n, y-1} \cdot { \left( 1 - \text{depr}_n \right) }^{\text{duration_period}_{y}} + \text{KN}_{n, y} \qquad \forall{ n, y > 1} +*New energy accounting equations. Need to be discussed and checked. See model documentation. * *** -TOTAL_CAPITAL(node_active, year) $ (NOT macro_base_period(year)).. -K(node_active, year) =E= -SUM(year2$( seq_period(year2,year) ), K(node_active, year2)) * (1 - depr(node_active))**duration_period(year) + KN(node_active, year) +ENERGY_ACCOUNTING(node_active, sector, year) $ (NOT macro_base_period(year)).. +TE(node_active, sector, year) =G= +YE(node_active, sector, year) + E(node_active, sector, year) ; -*** -* Equation TOTAL_PRODUCTION -* --------------------------------- -* Total production in the economy (excluding energy sectors) is the sum of production from assets that were already existing in the previous period :math:`y-1`, -* depreciated with the depreciation rate :math:`\text{depr}_{n}`, and the new vintage of production from period :math:`y`. -* -* .. math:: \text{Y}_{n, y} = \text{Y}_{n, y-1} \cdot { \left( 1 - \text{depr}_n \right) }^{\text{duration_period}_{y}} + \text{YN}_{n, y} \qquad \forall{ n, y > 1} -* -*** - -TOTAL_PRODUCTION(node_active, year) $ (NOT macro_base_period(year)).. -Y(node_active, year) =E= -SUM(year2$( seq_period(year2,year) ), Y(node_active, year2)) * (1 - depr(node_active))**duration_period(year) + YN(node_active, year) +ENERGY_ACCOUNTING2(node_active, sector, year) $ (NOT macro_base_period(year)).. +E(node_active, sector, year) =G= +TE(node_active, sector, year) * h(node_active, sector) ; -*** -* Equation NEW_ENERGY -* --------------------------------- -* Total energy production (across the six commerical energy demands :math:`s`) is the sum of production from all assets that were already existing -* in the previous period :math:`y-1`, depreciated with the depreciation rate :math:`\text{depr}_{n}`, and the the new vintage of energy production from -* period :math:`y`. -* -* .. math:: \text{PRODENE}_{n, s, y} = \text{PRODENE}_{n, s, y-1} \cdot { \left( 1 - \text{depr}_n \right) }^{\text{duration_period}_{y}} + \text{NEWENE}_{n, s, y} \qquad \forall{ n, s, y > 1} -* -*** +TE_EQUATION(node_active, sector, year) $ (NOT macro_base_period(year)).. +TE(node_active, sector, year) =E= -NEW_ENERGY(node_active, sector, year) $ (NOT macro_base_period(year)).. -PRODENE(node_active, sector, year) =E= -SUM(year2$( seq_period(year2,year) ), PRODENE(node_active, sector, year2)) * (1 - depr(node_active))**duration_period(year) + NEWENE(node_active, sector, year) -; - -*** -* Equation ENERGY_SUPPLY -* --------------------------------- -* The relationship below establishes the link between physical energy :math:`\text{PHYSENE}_{r, s, y}` as accounted in MESSAGE for the six commerical energy demands :math:`s` and -* energy in terms of monetary value :math:`\text{PRODENE}_{n, s, y}` as specified in the production function of MACRO. -* -* .. math:: \text{PHYSENE}_{n, s, y} \geq \text{PRODENE}_{n, s, y} \cdot \text{aeei_factor}_{n, s, y} \qquad \forall{ n, s, y > 1} -* -* The cumulative effect of autonomous energy efficiency improvements (AEEI) is captured in -* :math:`\text{aeei_factor}_{n,s,y} = \text{aeei_factor}_{n, s, y-1} \cdot (1 - \text{aeei}_{n,s,y})^{\text{duration_period}_{y}}` -* with :math:`\text{aeei_factor}_{n,s,y=1} = 1`. Therefore, choosing the :math:`\text{aeei}_{n,s,y}` coefficients appropriately offers the possibility to calibrate MACRO to a certain energy demand trajectory -* from MESSAGE. -* -*** +( (labor(node_active, year) * EMIN(node_active) + + (beta_rc_spec(node_active) / alpha(node_active)) * C(node_active, year) / (eneprice(node_active, 'rc_spec', year)/1000) +) / h(node_active, 'rc_spec') ) $ (sameas(sector,'rc_spec') AND h(node_active, 'rc_spec') <> 0) -ENERGY_SUPPLY(node_active, sector, year) $ (NOT macro_base_period(year)).. -PHYSENE(node_active, sector, year) =G= -PRODENE(node_active, sector, year) * aeei_factor(node_active, sector, year) -; ++ ( (labor(node_active, year) * EMIN(node_active) + + (beta_rc_therm(node_active) / alpha(node_active)) * C(node_active, year) / (eneprice(node_active, 'rc_therm', year)/1000) +) / h(node_active, 'rc_therm') ) $ (sameas(sector,'rc_therm') AND h(node_active, 'rc_therm') <> 0) -*** -* Equation COST_ENERGY -* --------------------------------- -* Energy system costs are based on a previous MESSAGE model run. The approximation of energy system costs in vicinity of the MESSAGE solution are approximated by a Taylor expansion with the -* first order term using shadow prices :math:`\text{eneprice}_{s, y, n}` of the MESSAGE model's solution and a quadratic second-order term. -* -* .. math:: \text{EC}_{n, y} = & \text{total_cost}_{n, r} \\ -* + & \displaystyle \sum_{s} \text{eneprice}_{s, y, n} \cdot \left( \text{PHYSENE}_{n, s, y} - \text{enestart}_{s, y, n} \right) \\ -* + & \displaystyle \sum_{s} \frac{\text{eneprice}_{s, y, n}}{\text{enestart}_{s, y, n}} \cdot \left( \text{PHYSENE}_{n, s, y} - \text{enestart}_{s, y, n} \right)^2 \qquad \forall{ n, y > 1} -* -*** ++ ( (labor(node_active, year) * EMIN(node_active) + + (beta_transport(node_active) / alpha(node_active)) * C(node_active, year) / (eneprice(node_active, 'transport', year)/1000) +) / h(node_active, 'transport') ) $ (sameas(sector,'transport') AND h(node_active, 'transport') <> 0) -COST_ENERGY(node_active, year) $ (NOT macro_base_period(year)).. -EC(node_active, year) =E= -(total_cost(node_active, year)/1000 -+ SUM(sector, eneprice(node_active, sector, year) * 1E-3 * (PHYSENE(node_active, sector, year) - enestart(node_active, sector, year))) -+ SUM(sector, eneprice(node_active, sector, year) * 1E-3 / enestart(node_active, sector, year) * (PHYSENE(node_active, sector, year) - enestart(node_active, sector, year)) * (PHYSENE(node_active, sector, year) - enestart(node_active, sector, year)))) ++ 0 $ (sameas(sector,'i_spec') OR sameas(sector,'i_therm')) ; -*** -* Equation TERMINAL_CONDITION -* --------------------------------- -* Given the finite time horizon of MACRO, a terminal constraint needs to be applied to ensure that investments are chosen at an appropriate level, i.e. to replace depriciated capital and -* provide net growth of capital stock beyond MACRO's time horizon :cite:`Manne-Richels-1992`. The goal is to avoid to the extend possible model artifacts resulting from this finite time horizon -* cutoff. -* -* .. math:: \text{K}_{n, y} \cdot \left( \text{grow}_{n, y} + \text{depr}_n \right) \leq \text{I}_{n, y} \qquad \forall{ n, y = \text{last year}} -*** +ENERGY_SUPPLY(node_active, sector, year) $ (NOT macro_base_period(year)).. +PHYSENE(node_active, sector, year) =G= +TE(node_active, sector, year) * aeei_factor(node_active, sector, year) +; TERMINAL_CONDITION(node_active, last_period).. -I(node_active, last_period) =G= K(node_active, last_period) * (grow(node_active, last_period) + depr(node_active)) +C(node_active, last_period) / K(node_active, last_period) =E= +interestrate(last_period) + depr(node_active) - grow(node_active, last_period) ; * ------------------------------------------------------------------------------ @@ -305,15 +256,13 @@ I(node_active, last_period) =G= K(node_active, last_period) * (grow(node_active, * ------------------------------------------------------------------------------ MODEL MESSAGE_MACRO / - UTILITY_FUNCTION - CAPITAL_CONSTRAINT - NEW_CAPITAL - NEW_PRODUCTION - TOTAL_CAPITAL - TOTAL_PRODUCTION - NEW_ENERGY + UTILITY_FUNCTION + CAPITAL + PRODUCTION + ENERGY_ACCOUNTING + ENERGY_ACCOUNTING2 + TE_EQUATION ENERGY_SUPPLY - COST_ENERGY TERMINAL_CONDITION / ; From 14631d9018144ec7fcadd9ae3d46838bfa10d1b3 Mon Sep 17 00:00:00 2001 From: Lukas Eggert Date: Thu, 8 Jan 2026 14:41:47 +0000 Subject: [PATCH 06/24] Update PARAMETERS --- message_ix/model/MACRO/macro_data_load.gms | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/message_ix/model/MACRO/macro_data_load.gms b/message_ix/model/MACRO/macro_data_load.gms index 8cbb9eb9d..80f80e190 100755 --- a/message_ix/model/MACRO/macro_data_load.gms +++ b/message_ix/model/MACRO/macro_data_load.gms @@ -71,6 +71,14 @@ PARAMETERS lakl(node) Production function coefficient of capital and labor prfconst(node, sector) Production function coefficient of different energy sectors + EMIN(node) Test Lukas + wage(node,year_all) Test Lukas + h(node,sector) Test Lukas + beta_rc_spec(node) Test Lukas + beta_rc_therm(node) Test Lukas + beta_transport(node) Test Lukas + alpha(node) Test Lukas + enestart(node,sector,year_all) Consumption level of energy services from MESSAGE model run eneprice(node,sector,year_all) Shadow prices of energy services from MESSAGE model run total_cost(node,year_all) Total energy system costs from MESSAGE model run From 6e381802febdf792a0c8d2e0e1436274c6898f96 Mon Sep 17 00:00:00 2001 From: Lukas Eggert Date: Thu, 8 Jan 2026 14:42:30 +0000 Subject: [PATCH 07/24] update * load relevant sets and parameters from dataset gdx --- message_ix/model/MACRO/macro_data_load.gms | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/message_ix/model/MACRO/macro_data_load.gms b/message_ix/model/MACRO/macro_data_load.gms index 80f80e190..df473472c 100755 --- a/message_ix/model/MACRO/macro_data_load.gms +++ b/message_ix/model/MACRO/macro_data_load.gms @@ -139,9 +139,11 @@ $LABEL macro_data $LOAD type_node,cat_node $LOAD sector,mapping_macro_sector -$LOAD kpvs,kgdp,esub,depr,drate,lotol +$LOAD kpvs,kgdp,esub,depr,drate,lotol,alpha,EMIN,beta_rc_spec,beta_rc_therm,beta_transport $LOAD lakl,prfconst $LOAD aeei,grow +$LOAD wage +$LOAD h $LOAD gdp_calibrate,historical_gdp $LOAD demand_MESSAGE,price_MESSAGE,cost_MESSAGE $GDXIN From d47ea20cfafe24dd3fd391744a82f66284e5db13 Mon Sep 17 00:00:00 2001 From: Lukas Eggert Date: Thu, 8 Jan 2026 14:45:43 +0000 Subject: [PATCH 08/24] update gdp_mer_macro(node_macro,year) = Y.L(node_macro,year) * 1000 ; (as accounting equation no longer exist) --- message_ix/model/MACRO/macro_calibration.gms | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/message_ix/model/MACRO/macro_calibration.gms b/message_ix/model/MACRO/macro_calibration.gms index b3aa764a3..52beeb8d9 100644 --- a/message_ix/model/MACRO/macro_calibration.gms +++ b/message_ix/model/MACRO/macro_calibration.gms @@ -43,7 +43,7 @@ demand_new(node_macro,sector,year) = demand_scale(node_macro,sector,year) * dema If (mod(ctr, 2) eq 0, * calculate correction factor for labour force growth rate and apply for next iteration of MACRO - gdp_mer_macro(node_macro,year) = (I.L(node_macro,year) + C.L(node_macro,year) + EC.L(node_macro,year)) * 1000 ; + gdp_mer_macro(node_macro,year) = Y.L(node_macro,year) * 1000 ; gdp_scale(node_macro,year) = gdp_mer_macro(node_macro,year)/gdp_calibrate(node_macro,year) ; growth_correction(node_macro,year) $ (NOT macro_base_period(year)) = SUM(year2 $ seq_period(year2,year), ((gdp_calibrate(node_macro,year)/gdp_calibrate(node_macro,year2))**(1/duration_period(year))) - ((gdp_mer_macro(node_macro,year)/gdp_mer_macro(node_macro,year2))**(1/duration_period(year))) ) ; From 8466d7e1efe2a989c010a6662af1b07625c2c4cb Mon Sep 17 00:00:00 2001 From: Lukas Eggert Date: Thu, 8 Jan 2026 14:47:31 +0000 Subject: [PATCH 09/24] Delete NEWENE as it no longer exists --- message_ix/model/MACRO/macro_solve.gms | 4 ---- 1 file changed, 4 deletions(-) diff --git a/message_ix/model/MACRO/macro_solve.gms b/message_ix/model/MACRO/macro_solve.gms index 5e4611c0e..1735900ab 100755 --- a/message_ix/model/MACRO/macro_solve.gms +++ b/message_ix/model/MACRO/macro_solve.gms @@ -20,10 +20,6 @@ SVNEWE(node_macro, sector, year) = ( ) )$(NOT macro_base_period(year)); -NEWENE.L(node_macro, sector, macro_horizon) = ( - SVNEWE(node_macro, sector, macro_horizon)$(SVNEWE(node_macro, sector, macro_horizon) > 0) + epsilon -); - PHYSENE.L(node_macro, sector, year) = enestart(node_macro, sector, year) ; KN.L(node_macro, macro_horizon) = SVKN(node_macro, macro_horizon) $ (SVKN(node_macro, macro_horizon) > 0) + epsilon ; From a8453368ee47571dcf1dfa5df0df29f93088a5a5 Mon Sep 17 00:00:00 2001 From: Lukas Eggert Date: Thu, 8 Jan 2026 14:48:39 +0000 Subject: [PATCH 10/24] Add startvalue for TE (in original model PRODENE) --- message_ix/model/MACRO/macro_solve.gms | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/message_ix/model/MACRO/macro_solve.gms b/message_ix/model/MACRO/macro_solve.gms index 1735900ab..b419f30b8 100755 --- a/message_ix/model/MACRO/macro_solve.gms +++ b/message_ix/model/MACRO/macro_solve.gms @@ -20,6 +20,10 @@ SVNEWE(node_macro, sector, year) = ( ) )$(NOT macro_base_period(year)); +TE.L(node_macro, sector, macro_horizon) = ( + SVNEWE(node_macro, sector, macro_horizon)$(SVNEWE(node_macro, sector, macro_horizon) > 0) + epsilon +); + PHYSENE.L(node_macro, sector, year) = enestart(node_macro, sector, year) ; KN.L(node_macro, macro_horizon) = SVKN(node_macro, macro_horizon) $ (SVKN(node_macro, macro_horizon) > 0) + epsilon ; From 5bce212d577391dc092656ba216007def428bff3 Mon Sep 17 00:00:00 2001 From: Lukas Eggert Date: Thu, 8 Jan 2026 14:49:32 +0000 Subject: [PATCH 11/24] Delete startvalues for KN, YN, I, and NEWENE as they do not longer exist --- message_ix/model/MACRO/macro_solve.gms | 4 ---- 1 file changed, 4 deletions(-) diff --git a/message_ix/model/MACRO/macro_solve.gms b/message_ix/model/MACRO/macro_solve.gms index b419f30b8..e895a38b0 100755 --- a/message_ix/model/MACRO/macro_solve.gms +++ b/message_ix/model/MACRO/macro_solve.gms @@ -32,15 +32,11 @@ KN.L(node_macro, macro_horizon) = SVKN(node_macro, macro_horizon) $ (SVKN(node_ * ------------------------------------------------------------------------------ K.LO(node_macro, macro_horizon) = LOTOL(node_macro) * k0(node_macro) ; -KN.LO(node_macro, macro_horizon) = LOTOL(node_macro) * i0(node_macro) * duration_period(macro_horizon) ; Y.LO(node_macro, macro_horizon) = LOTOL(node_macro) * y0(node_macro) ; -YN.LO(node_macro, macro_horizon) = LOTOL(node_macro) * y0(node_macro) * newlab(node_macro, macro_horizon) ; C.LO(node_macro, macro_horizon) = LOTOL(node_macro) * c0(node_macro) ; -I.LO(node_macro, macro_horizon) = LOTOL(node_macro) * i0(node_macro) ; PRODENE.LO(node_macro, sector, macro_horizon) = LOTOL(node_macro) * enestart(node_macro, sector, macro_horizon) / aeei_factor(node_macro, sector, macro_horizon) ; -NEWENE.LO(node_macro, sector, macro_horizon) = LOTOL(node_macro) * enestart(node_macro, sector, macro_horizon) / aeei_factor(node_macro, sector, macro_horizon) ; * ------------------------------------------------------------------------------ * Base year values of variables are fixed to historical values From 4f2468240ebdfa240ab83d64dff8fc44b42bf75e Mon Sep 17 00:00:00 2001 From: Lukas Eggert Date: Thu, 8 Jan 2026 14:50:52 +0000 Subject: [PATCH 12/24] Change PRODENE in TE --- message_ix/model/MACRO/macro_solve.gms | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/message_ix/model/MACRO/macro_solve.gms b/message_ix/model/MACRO/macro_solve.gms index e895a38b0..18c7f5f76 100755 --- a/message_ix/model/MACRO/macro_solve.gms +++ b/message_ix/model/MACRO/macro_solve.gms @@ -33,10 +33,9 @@ KN.L(node_macro, macro_horizon) = SVKN(node_macro, macro_horizon) $ (SVKN(node_ K.LO(node_macro, macro_horizon) = LOTOL(node_macro) * k0(node_macro) ; Y.LO(node_macro, macro_horizon) = LOTOL(node_macro) * y0(node_macro) ; - C.LO(node_macro, macro_horizon) = LOTOL(node_macro) * c0(node_macro) ; -PRODENE.LO(node_macro, sector, macro_horizon) = LOTOL(node_macro) * enestart(node_macro, sector, macro_horizon) / aeei_factor(node_macro, sector, macro_horizon) ; +TE.LO(node_macro, sector, macro_horizon) = LOTOL(node_macro) * enestart(node_macro, sector, macro_horizon) / aeei_factor(node_macro, sector, macro_horizon) ; * ------------------------------------------------------------------------------ * Base year values of variables are fixed to historical values From 44e7fa741782232cb64e1fe21193e9156f745076 Mon Sep 17 00:00:00 2001 From: Lukas Eggert Date: Thu, 8 Jan 2026 14:51:23 +0000 Subject: [PATCH 13/24] Add start values for E and YE as they are new Variables --- message_ix/model/MACRO/macro_solve.gms | 2 ++ 1 file changed, 2 insertions(+) diff --git a/message_ix/model/MACRO/macro_solve.gms b/message_ix/model/MACRO/macro_solve.gms index 18c7f5f76..0ff30f636 100755 --- a/message_ix/model/MACRO/macro_solve.gms +++ b/message_ix/model/MACRO/macro_solve.gms @@ -36,6 +36,8 @@ Y.LO(node_macro, macro_horizon) = LOTOL(node_macro) * y0(node_macro) ; C.LO(node_macro, macro_horizon) = LOTOL(node_macro) * c0(node_macro) ; TE.LO(node_macro, sector, macro_horizon) = LOTOL(node_macro) * enestart(node_macro, sector, macro_horizon) / aeei_factor(node_macro, sector, macro_horizon) ; +YE.LO(node_macro, sector, macro_horizon) = (1-h(node_macro, sector)) * LOTOL(node_macro) * enestart(node_macro, sector, macro_horizon) / aeei_factor(node_macro, sector, macro_horizon) ; +E.LO(node_macro, sector, macro_horizon) = h(node_macro, sector) * LOTOL(node_macro) * enestart(node_macro, sector, macro_horizon) / aeei_factor(node_macro, sector, macro_horizon) ; * ------------------------------------------------------------------------------ * Base year values of variables are fixed to historical values From be165fea64177c9367a06cfa3dff7cdf42e932ea Mon Sep 17 00:00:00 2001 From: Lukas Eggert Date: Thu, 8 Jan 2026 14:52:13 +0000 Subject: [PATCH 14/24] Update base year values of variables --- message_ix/model/MACRO/macro_solve.gms | 3 --- 1 file changed, 3 deletions(-) diff --git a/message_ix/model/MACRO/macro_solve.gms b/message_ix/model/MACRO/macro_solve.gms index 0ff30f636..e41d07ac8 100755 --- a/message_ix/model/MACRO/macro_solve.gms +++ b/message_ix/model/MACRO/macro_solve.gms @@ -44,13 +44,10 @@ E.LO(node_macro, sector, macro_horizon) = h(node_macro, sector) * LOTOL(node_mac * ------------------------------------------------------------------------------ * division by aeei_factor is necesary in case MACRO starts after initialize_period (in case of slicing) -PRODENE.FX(node_macro, sector, macro_base_period) = demand_base(node_macro, sector) / aeei_factor(node_macro, sector, macro_base_period) ; Y.FX(node_macro, macro_base_period) = y0(node_macro) ; K.FX(node_macro, macro_base_period) = k0(node_macro) ; C.FX(node_macro, macro_base_period) = c0(node_macro) ; -I.FX(node_macro, macro_base_period) = i0(node_macro) ; -EC.FX(node_macro, macro_base_period) = y0(node_macro) - i0(node_macro) - c0(node_macro) ; $IFTHEN %MACRO_CONCURRENT% == "0" From 50af5138b2ad8520890aab22a253dfe66a7bcd5f Mon Sep 17 00:00:00 2001 From: Lukas Eggert Date: Thu, 8 Jan 2026 14:53:23 +0000 Subject: [PATCH 15/24] Change GDP.L equation as the original accounting equation does no longer exist --- message_ix/model/MACRO/macro_reporting.gms | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/message_ix/model/MACRO/macro_reporting.gms b/message_ix/model/MACRO/macro_reporting.gms index aa6284eb6..bf30cfd5d 100755 --- a/message_ix/model/MACRO/macro_reporting.gms +++ b/message_ix/model/MACRO/macro_reporting.gms @@ -2,4 +2,4 @@ * MACRreport * ------------------------------------------------------------------------------ -GDP.L(node_macro,year) = (I.L(node_macro,year) + C.L(node_macro,year) + EC.L(node_macro,year)) * 1000 ; +GDP.L(node_macro,year) = Y.L(node_macro,year) * 1000 ; \ No newline at end of file From 84f21e47315673f254d1bea493d0f6d702f598a7 Mon Sep 17 00:00:00 2001 From: Lukas Eggert Date: Thu, 8 Jan 2026 14:55:15 +0000 Subject: [PATCH 16/24] Update ixmp items --- message_ix/macro/__init__.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/message_ix/macro/__init__.py b/message_ix/macro/__init__.py index 878519bd2..275d1d9f2 100644 --- a/message_ix/macro/__init__.py +++ b/message_ix/macro/__init__.py @@ -38,6 +38,13 @@ def initialize(cls, scenario, with_data=False): #: ixmp items (sets, parameters, variables, and equations) for MACRO. _set("sector") _set("mapping_macro_sector", "sector c l") +par("EMIN", "node") +par("alpha", "node") +par("wage", "n y") +par("h", "n sector") +par("beta_rc_spec", "node") +par("beta_rc_therm", "node") +par("beta_transport", "node") par("MERtoPPP", "n y") par("aeei", "n sector y") par("cost_MESSAGE", "n y") @@ -59,10 +66,11 @@ def initialize(cls, scenario, with_data=False): var("COST_NODAL_NET", "n y", "Net of trade and emissions cost") var("DEMAND", "n c l y h") var("EC", "n y") +var("EC_household", "n y") +var("EC_production", "n y") var("GDP", "n y") var("I", "n y", "Total investment") var("K", "n y") -var("KN", "n y") var("MAX_ITER", "") var("N_ITER", "") var("NEWENE", "n sector y") @@ -71,7 +79,7 @@ def initialize(cls, scenario, with_data=False): var("PRODENE", "n sector y") var("UTILITY", "") var("Y", "n y") -var("YN", "n y") +var("Y_GOODS", "n y") var("aeei_calibrate", "n sector y") var("grow_calibrate", "n y") equ("COST_ACCOUNTING_NODAL", "n y") From 9d95c101d2f8e88d8f32bc6fba33caf849f7ce61 Mon Sep 17 00:00:00 2001 From: Lukas Eggert Date: Thu, 8 Jan 2026 14:56:56 +0000 Subject: [PATCH 17/24] update macro calibration parameters --- message_ix/macro/calibrate.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/message_ix/macro/calibrate.py b/message_ix/macro/calibrate.py index 7b0a27ce9..240096da7 100644 --- a/message_ix/macro/calibrate.py +++ b/message_ix/macro/calibrate.py @@ -58,6 +58,13 @@ "lotol", "MERtoPPP", "price_ref", + "EMIN", + "alpha", + "wage", + "h", + "beta_rc_spec", + "beta_rc_therm", + "beta_transport", ] From f56e4eaf0b5daa2c363b1205c6155f6bd193e2c1 Mon Sep 17 00:00:00 2001 From: Lukas Eggert Date: Thu, 8 Jan 2026 14:58:54 +0000 Subject: [PATCH 18/24] Add new model description document --- message_ix/new_model_description.pdf | Bin 0 -> 235343 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 message_ix/new_model_description.pdf diff --git a/message_ix/new_model_description.pdf b/message_ix/new_model_description.pdf new file mode 100644 index 0000000000000000000000000000000000000000..bc152a80a9d0dd8cdd75b4e249133722c02ab295 GIT binary patch literal 235343 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⁣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