diff --git a/core/declarations.gms b/core/declarations.gms index 36ced4acb..3b937fcdf 100644 --- a/core/declarations.gms +++ b/core/declarations.gms @@ -572,6 +572,8 @@ parameters pm_budgetCO2eq(all_regi) "budget for regional energy-emissions in period 1 [GtC]" pm_actualbudgetco2(ttot) "actual level of cumulated emissions starting from 2020 [GtCO2]" p_actualbudgetco2_iter(iteration,ttot) "track actual level of cumulated emissions starting from 2020 over iterations [GtCO2]" +pm_actualbudgetco2Regi(ttot,all_regi) "Regional- actual level of cumulated emissions starting from 2020 [GtCO2]" +p_actualbudgetco2Regi_iter(iteration,ttot,all_regi) "Regional- track actual level of cumulated emissions starting from 2020 over iterations [GtCO2]" *** iteration parameters pm_SolNonInfes(all_regi) "model status from last iteration. 1 means status 2 or 7, 0 for all other status codes" diff --git a/core/postsolve.gms b/core/postsolve.gms index dd2fb7e7d..ecc761235 100644 --- a/core/postsolve.gms +++ b/core/postsolve.gms @@ -18,8 +18,21 @@ pm_actualbudgetco2(ttot)$( 2020 lt ttot.val ) ) ) * sm_c_2_co2; + +*** `pm_actualbudgetco2Regi(ttot, regi)` includes emissions from 2020 to `ttot` (inclusive). +pm_actualbudgetco2Regi(ttot,regi)$( 2020 lt ttot.val ) + = sum((ttot2)$( 2020 le ttot2.val AND ttot2.val le ttot.val ), + vm_emiAll.l(ttot2,regi,"co2") + * ( (0.5 + pm_ts(ttot2) / 2)$( ttot2.val eq 2020 ) !! second half of the 2020 period (mid 2020 - end 2022) plus 0.5 to account fo beginning 2020 - mid 2020 + + (pm_ts(ttot2))$( 2020 lt ttot2.val AND ttot2.val lt ttot.val ) !! entire middle periods + + ((pm_ttot_val(ttot) - pm_ttot_val(ttot-1)) / 2 + 0.5)$(ttot2.val eq ttot.val ) !! first half of the final period plus 0.5 to account fo mid - end of final year + ) + ) + * sm_c_2_co2; + *** track `pm_actualbudgetco2(ttot)` over iterations p_actualbudgetco2_iter(iteration,ttot)$( 2020 lt ttot.val) = pm_actualbudgetco2(ttot); +p_actualbudgetco2Regi_iter(iteration,ttot,regi)$( 2020 lt ttot.val) = pm_actualbudgetco2Regi(ttot,regi); *** track pm_taxCO2eq over iterations - pm_taxCO2eq is adjusted in 45_carbonprice/functionalForm/postsolve.gms and consequently pm_taxCO2eq_iter gets overwritten there pm_taxCO2eq_iter(iteration,t,regi) = pm_taxCO2eq(t,regi); diff --git a/main.gms b/main.gms index 384ff266e..b062f7579 100755 --- a/main.gms +++ b/main.gms @@ -373,8 +373,8 @@ $setglobal emicapregi none !! def = none *' * (functionalForm): [REMIND default for peak budget and end-of-century budget runs] *' * Carbon price trajectory follows a prescribed functional form (linear/exponential) - either until peak year or until end-of-century - *' * and can be endogenously adjusted to meet CO2 budget targets - either peak or end-of-century - that are formulated in terms of total cumulated CO2 emissions from 2020 (cm_budgetCO2from2020). -*' * Flexible choices for regional carbon price differentiation. -*' * Four main design choices: +*' * For global targets, flexible choices for regional carbon price differentiation. +*' * Four main design choices: *' * [Global anchor trajectory]: The realization uses a global anchor trajectory based on which the regional carbon price trajectories are defined. *' * The functional form (linear/exponential) of the global anchor trajectory is chosen via cm_taxCO2_functionalForm [default = linear]. *' * The (initial) carbon price in cm_startyear is chosen via cm_taxCO2_startyear. This value is endogenously adjusted to meet CO2 budget targets if cm_iterative_target_adj is set to 5, 7, or 9. @@ -384,6 +384,7 @@ $setglobal emicapregi none !! def = none *' * [Post-peak behaviour]: The global anchor trajectory can be adjusted after reaching the peak of global CO2 emissions in cm_peakBudgYr. See cm_iterative_target_adj and 45_carbonprice/functionalForm/realization.gms for details. *' * [Regional differentiation]: Regional carbon price differentiation relative to global anchor trajectory is chosen via cm_taxCO2_regiDiff [default = initialSpread10]. *' * In addition, the carbon prices provided by path_gdx_ref can be used as a lower bound based on the switch cm_taxCO2_lowerBound_path_gdx_ref [def = on]. +*' * For regional targets, the shape can be chosen to peak in a specified year or in 2100. Linear shapes can be either shifted up and down in start-year or the slope can be endogenously adjusted to meet the target *' * (expoLinear): 4.5% exponential increase until cm_expoLinear_yearStart, transitioning into linear increase thereafter *' * (exogenous): carbon price is specified using an external input file or using the switch cm_regiExoPrice. Requires cm_emiscen = 9 and cm_iterative_target_adj = 0 *' * (temperatureNotToExceed): [see realization for details. Test and verify before using it! ] @@ -550,7 +551,45 @@ parameter ; cm_budgetCO2_absDevTol = 2; !! def = 2 !! regexp = is.nonnegative *' - +parameter + cm_regionalBudgetTolerance_Rel +; + cm_regionalBudgetTolerance_Rel = 0.3; !! def = 0.3 !! regexp. is.nonnegative +*' +parameter + cm_regionalBudgetTolerance_Abs "absolute deviation from a regional target. If = 0 -> Relative tolerance is used instead" +; + cm_regionalBudgetTolerance_Abs = 0; !! def = 0 !! regexp. is.nonnegative +*' +parameter + cm_CPslopeAdjustment "whether the slope of the carbon price is adjusted endogenously or the entire curve is just shifted up and down" +; + cm_CPslopeAdjustment = 0; !! def = 0 +*' (0): no adjustment of the slope; i.e. carbon price shape chosen from the input-gdx and the curve is shifted up and down from cm_startYear +*' (1): endogenous adjustment of the slope, i.e. linear increase to the highest carbon price +*' +parameter + cm_CPadjustmentAlternating "for regional targets: whether carbon prices are adjusted only one direction per iteration, or both directions " +; + cm_CPadjustmentAlternating = 0; !! def = 0 +*' (0): carbon prices are always adjusted +*' (1): regional carbon prices are adjusted only upwards or downwards in a given iteration. Alternating up and down +*' +parameter + cm_funnelFactor +; + cm_funnelFactor = 2; !! def = 2 +*' +parameter + cm_funnelExponent +; + cm_funnelExponent = 0.18; !! def = 0.18 +*' +parameter + cm_funnelLower +; + cm_funnelLower = 0.001; !! def = 0.005 !! regexp. is.nonnegative +*' parameter cm_peakBudgYr "time of global net-zero CO2 emissions (peak budget)" ; @@ -895,14 +934,16 @@ parameter parameter cm_iterative_target_adj "settings on iterative adjustment for CO2 tax based on in-iteration emission or forcing level. Allow iteratively generated endogenous global CO2 tax under peak budget constraint or end-of-century budget constraint." ; - cm_iterative_target_adj = 0; !! def = 0 !! regexp = 0|2|3|5|7|9 + cm_iterative_target_adj = 0; !! def = 0 !! regexp = 0|2|3|4|44|5|7|9 *' * (0): no iterative adjustment of CO2 tax (terminology: CO2 price and CO2 tax in REMIND is used interchangeably) *' * (2): iterative adjustment of CO2 tax or cumulative emission based on climate forcing calculated by climate model magicc, for runs with budget or CO2 tax constraints. See ./modules/45_carbonprice/NDC/postsolve.gms for direct algorithm *' * (3): [requires 45_carbonprice = NDC and emiscen = 9] iterative adjustment of CO2 tax based on 2025 or 2030 regionally differentiated emissions, for runs with emission budget or CO2 tax constraints. See ./modules/45_carbonprice/NDC/postsolve.gms for direct algorithm -*' * (5): [requires 45_carbonprice = functionalForm and emiscen = 9] iterative adjustment of CO2 tax based on economy-wide CO2 cumulative emission budget(2020-2100), for runs with emission budget or CO2 tax constraints. [see 45_carbonprice/functionalForm/postsolve.gms for direct algorithm] +*' * (4): [requires 45_carbonprice = functionalForm and emiscen = 9] regional: iterative adjustment of CO2 tax based on economy-wide CO2 cumulative emission budget(2020-2100), for runs with emission budget or CO2 tax constraints. [see 45_carbonprice/functionalForm/postsolve.gms for direct algorithm] +*' * (44): [requires 45_carbonprice = functionalForm and emiscen = 9] regional: iterative adjustment of CO2 tax based on regional economy-wide CO2 cumulative emission EOC budget, +*' * (5): [requires 45_carbonprice = functionalForm and emiscen = 9] global: iterative adjustment of CO2 tax based on economy-wide CO2 cumulative emission budget(2020-2100), for runs with emission budget or CO2 tax constraints. [see 45_carbonprice/functionalForm/postsolve.gms for direct algorithm] *' * (7): [requires 45_carbonprice = functionalForm and emiscen = 9] iterative adjustment of CO2 tax based on economy-wide CO2 cumulative emission peak budget, for runs with emission budget or CO2 tax constraints. Features: results in a peak budget with zero net CO2 emissions after peak budget is reached. See core/postsolve.gms for direct algorithms [see 45_carbonprice/functionalForm/postsolve.gms for direct algorithm] -*' * (9): [requires 45_carbonprice = functionalForm and emiscen = 9] iterative adjustment of CO2 tax based on economy-wide CO2 cumulative emission peak budget, for runs with emission budget or CO2 tax constraints. Features: 1) after the year when budget peaks, CO2 tax has an annual increase by cm_taxCO2_IncAfterPeakBudgYr, 2) automatically shifts cm_peakBudgYr to find the correct year of budget peaking for a given budget. [see 45_carbonprice/functionalForm/postsolve.gms for direct algorithm] -*' +*' * (9): [requires 45_carbonprice = functionalForm and emiscen = 9] global: iterative adjustment of CO2 tax based on economy-wide CO2 cumulative emission peak budget, for runs with emission budget or CO2 tax constraints. Features: 1) after the year when budget peaks, CO2 tax has an annual increase by cm_taxCO2_IncAfterPeakBudgYr, 2) automatically shifts cm_peakBudgYr to find the correct year of budget peaking for a given budget. [see 45_carbonprice/functionalForm/postsolve.gms for direct algorithm] + parameter cm_NDC_divergentScenario "choose scenario about convergence of CO2eq prices [45_carbonprice = NDC]" ; @@ -1817,7 +1858,8 @@ $setglobal cm_taxCO2_regiDiff_convergence scenario !! def = scenario *** For example, setting the switch to GLO 50, SSA 5, CHA 40 means that in cm_startyear, SSA has carbon price of 5$/tCO2, CHA has carbon price of 40$/tCO2, and all other regions have carbon price of 50$/tCO2. *** Important note: If regional carbon prices in the start year are manually set, the regional values are used as lower bounds for pm_taxCO2eq $setglobal cm_taxCO2_regiDiff_startyearValue endogenous !! def = "endogenous" - +*' cm_budgetCO2from2020RegiShare "switch to set eoc regional carbon budget shares by region (for easier comparison than total budgets, endogenous calculation possible)" +$setglobal cm_budgetCO2from2020RegiShare off !! def = off *** cm_ind_energy_limit Switch for setting upper limits on industry energy *** efficiency improvements. See ./modules/37_subsectors/datainput.gms for *** implementation. diff --git a/modules/45_carbonprice/functionalForm/datainput.gms b/modules/45_carbonprice/functionalForm/datainput.gms index 06e3a54e1..dc36a8b6c 100644 --- a/modules/45_carbonprice/functionalForm/datainput.gms +++ b/modules/45_carbonprice/functionalForm/datainput.gms @@ -7,8 +7,8 @@ *** SOF ./modules/45_carbonprice/functionalForm/datainput.gms *** Check that cm_iterative_target_adj is equal to 0, 5, 7, or 9 -if( not ((cm_iterative_target_adj = 0) or (cm_iterative_target_adj eq 5) or (cm_iterative_target_adj eq 7) or (cm_iterative_target_adj eq 9) ), - abort "The realization 45_carbonprice/functionalForm is only compatible with cm_iterative_target_adj = 0, 5, 7 or 9. Please adjust config file accordingly" +if( not ((cm_iterative_target_adj = 0) or (cm_iterative_target_adj eq 5) or (cm_iterative_target_adj eq 7) or (cm_iterative_target_adj eq 9) OR (cm_iterative_target_adj eq 4) OR (cm_iterative_target_adj eq 44)), + abort "The realization 45_carbonprice/functionalForm is only compatible with cm_iterative_target_adj = 0, 4, 44, 5, 7 or 9. Please adjust config file accordingly" ); *** Read pm_taxCO2eq from path_gdx_ref @@ -19,6 +19,28 @@ display p45_taxCO2eq_path_gdx_ref; o45_reached_until2150pricepath(iteration) = 0; +*** ---- for regional carbon budgets (cm_iterative_target_adj eq 4) OR (cm_iterative_target_adj eq 44) +if (not ((cm_iterative_target_adj = 4) OR (cm_iterative_target_adj = 44)), +pm_budgetCO2from2020Regi(regi) = 1; !! not sure if needed +pm_budgetCO2from2020RegiShare(regi) = 1; !! +else +pm_budgetCO2from2020Regi(regi) = pm_budgetCO2from2020RegiShare(regi) * cm_budgetCO2from2020; +); + +** Compute the absolute budget deviation tolerance level +if(cm_regionalBudgetTolerance_Abs > 0, + pm_regionalBudget_absDevTol(regi) = cm_regionalBudgetTolerance_Abs; + else + pm_regionalBudget_absDevTol(regi) = cm_regionalBudgetTolerance_Rel * pm_budgetCO2from2020Regi(regi); +); + +loop(iteration, +p45_FunnelUpper(iteration) = cm_funnelFactor * EXP( -cm_funnelExponent * iteration.val) + 1 + cm_funnelLower; +p45_FunnelLower(iteration) = 1/ ( cm_funnelFactor * EXP( -cm_funnelExponent * iteration.val) + 1 + cm_funnelLower); +); + +s45_YearBeforeStartYear = smax(ttot$( ttot.val lt cm_startyear ), ttot.val); !! Timestep before startyear + ***----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- *** Part I (Global anchor trajectory): The functional form (linear/exponential) of the global anchor trajectory is chosen via cm_taxCO2_functionalForm. *** The (initial) global anchor carbon price in cm_startyear is chosen via cm_taxCO2_startyear. Alternatively, the (initial) global anchor carbon price in cm_peakBudgYr is chosen via cm_taxCO2_peakBudgYr. diff --git a/modules/45_carbonprice/functionalForm/declarations.gms b/modules/45_carbonprice/functionalForm/declarations.gms index 951380919..e060b7320 100644 --- a/modules/45_carbonprice/functionalForm/declarations.gms +++ b/modules/45_carbonprice/functionalForm/declarations.gms @@ -47,8 +47,39 @@ p45_regiDiff_startyearValue(all_regi) "manually chosen regional carbon pri p45_regiDiff_startyearValue_data(ext_regi) "input data for regional carbon price in start year provided by switch cm_taxCO2_regiDiff_startyearValue" / %cm_taxCO2_regiDiff_startyearValue% / $endIf.taxCO2regiDiffStartyearValue1 -; + +*** If there is a regional budget, read regional carbon budget from switch and set additionally needed parameters +pm_budgetCO2from2020Regi(all_regi) "regional carbon budget (Gt CO2)" +!!$ifthen.regiBudget "%cm_iterative_target_adj%" == "4" OR "%cm_iterative_target_adj%" == "44" +$ifthen.regiBudget "%cm_budgetCO2from2020RegiShare%" == "off" !! (cm_iterative_target_adj == "4") OR (cm_iterative_target_adj == "44") +pm_budgetCO2from2020RegiShare(all_regi) "share of region in global carbon budget" +$else.regiBudget +pm_budgetCO2from2020RegiShare(all_regi) "share of region in global carbon budget" /%cm_budgetCO2from2020RegiShare%/ +$endif.regiBudget +p45_actualbudgetco2Regi(all_regi) "regional - actual level of 2020-2100 cumulated emissions, including all CO2 for last iteration" +p45_actualbudgetco2Regi_iter(iteration,all_regi) "regional - actual level of 2020-2100 cumulated emissions, including all CO2 for last iteration" +p45_factorRescale_taxCO2Regi(iteration,all_regi) "regional - Multiplicative factor for rescaling the CO2 price to reach the target" +p45_factorRescale_taxCO2Regi_Funneled(iteration, all_regi) "regional - Multiplicative factor for rescaling the CO2 price to reach the target - Funnelled (static)" +pm_factorRescale_taxCO2Regi_Funneled2(iteration, all_regi) "regional - Multiplicative factor for rescaling the CO2 price to reach the target - Funnelled (interactive, incl. adjustments based on last iterations)" +p45_factorRescale_taxCO2Regi_Final(iteration, all_regi) "regional - Multiplicative factor for rescaling the CO2 price to reach the target - Funnelled, may include up/downward iteration differentiation" +p45_taxCO2eq_anchorRegi(ttot,all_regi) "regional anchor trajectory for regional CO2 price trajectories in T$/GtC = $/kgC" +p45_taxCO2eq_anchorRegi_iter(ttot, all_regi, iteration) "regional anchor trajectory for regional CO2 price trajectories in T$/GtC = $/kgC across iterations" +p45_temp_anchor(ttot,all_regi) "regionally shifted anchor for all iterations (helper, may be removed)" +pm_budgetDeviation(all_regi) "deviations from regional targets" +p45_budgetDeviation_iter(iteration, all_regi) "deviations from regional targets across iterations" +pm_regionalBudget_absDevTol(all_regi) "tolerance of deviation from regional targets in absolute terms" + +p45_TaxBudgetSlopeCurrent(all_regi) "regional carbon price change/regional carbon budget change - from the last 2 iterations" +p45_TaxBudgetSlopeCurrent_iter(iteration, all_regi) "regional carbon price change/regional carbon budget change - from the last 2 iterations, for each iteration. 0 when no carbon price change" +p45_TaxBudgetSlopeBest(all_regi) "last available regional carbon price change/regional carbon budget change that is negative" +p45_TaxBudgetSlopeBest_iter(iteration, all_regi) "last available regional carbon price change/regional carbon budget change that is negative for each iteration" +p45_CarbonPriceSlope(all_regi) "when carbon price slope is regionally adjusted: increase of carbon price per year" +p45_CarbonPriceSlope_iter(iteration,all_regi) "when carbon price slope is regionally adjusted: increase of carbon price per year for each iteration" + +p45_FunnelUpper(iteration) "upper bound on regional carbon price funnel (helper, may be removed)" +p45_FunnelLower(iteration) "lower bound on regional carbon price funnel (helper, may be removed)" +; *** Scalars only used in functionForm/postsolve.gms scalars s45_actualbudgetco2 "actual level of 2020-2100 cumulated emissions, including all CO2 for last iteration" @@ -58,6 +89,8 @@ s45_factorRescale_taxCO2_exponent_from10 "exponent determining se s45_peakBudget "peak CO2 budget as calculated as the maximum of cumulative CO2 emissions, used to check adjustment algorithm [GtC/yr]" sm_peakBudgYr_check "peak budget year calculated based on maximum of cumulative CO2 emissions, used to check adjustment algorithm [year]" sm_peakbudget_diff "difference in cumulative CO2 emissions between cumulative emissions in cm_peakBudgYr and time step of maximum cumulative CO2 emissions [GtCO2]" + +s45_YearBeforeStartYear "! This is the same value as s45_interpolation_startYr but the naming does not make sense for these extended purposes, thus creating a new scalar as preliminary solution" ; *** Parameters only used in functionForm/postsolve.gms diff --git a/modules/45_carbonprice/functionalForm/postsolve.gms b/modules/45_carbonprice/functionalForm/postsolve.gms index 81f623b14..12484b41f 100644 --- a/modules/45_carbonprice/functionalForm/postsolve.gms +++ b/modules/45_carbonprice/functionalForm/postsolve.gms @@ -6,6 +6,231 @@ *** | Contact: remind@pik-potsdam.de *** SOF ./modules/45_carbonprice/functionalForm/postsolve.gms +***------------------------------------------------------------------------------------------------------------------------------------------------ +***regional eoc emission budget: +***------------------------------------------------------------------------------------------------------------------------------------------------ +if((cm_iterative_target_adj eq 4) OR (cm_iterative_target_adj eq 44), +*** 1. Get the relevant information from this iteration + !! Update the actual budget by region and save across iterations for debugging + p45_actualbudgetco2Regi(regi) = sum(t$(t.val eq 2100), pm_actualbudgetco2Regi(t,regi)); + p45_actualbudgetco2Regi_iter(iteration, regi) = p45_actualbudgetco2Regi(regi); + + !! Save pm_taxCO2eq over iterations + pm_taxCO2eq_iter(iteration,ttot,regi) = pm_taxCO2eq(ttot,regi); + + !! Compute deviation from regional target budget + pm_budgetDeviation(regi) = p45_actualbudgetco2Regi(regi) - pm_budgetCO2from2020Regi(regi); + p45_budgetDeviation_iter(iteration, regi) = pm_budgetDeviation(regi) ; + + !! Save the best available information about the reaction of the actual budget to the change in prices + if (iteration.val ge 2, + !! determine the (price change / budget change) in the last iteration. If no change in tax, then 0; no change of budget at all is very unlikely, thus negligible risk of infeasibility + p45_TaxBudgetSlopeCurrent(regi) = (pm_taxCO2eq_iter(iteration, "2100", regi) - pm_taxCO2eq_iter(iteration-1, "2100", regi)) + / (p45_actualbudgetco2Regi_iter(iteration, regi) - p45_actualbudgetco2Regi_iter(iteration - 1, regi)); + p45_TaxBudgetSlopeCurrent_iter(iteration, regi) = p45_TaxBudgetSlopeCurrent(regi); + + !! The slope is expected to be negative (i.e. price increase leads to lower actual budget). + !! If it is indeed negative, update the information from the previous iterations. (if there was no change, then the previously estalished relation remains available) + loop(regi, + if((p45_TaxBudgetSlopeCurrent(regi) <0), + p45_TaxBudgetSlopeBest(regi) = p45_TaxBudgetSlopeCurrent(regi); + ); !! If condition + ); !! Regi loop + p45_TaxBudgetSlopeBest_iter(iteration,regi) = p45_TaxBudgetSlopeBest(regi); + ); + +*** 2. Compute the rescaling factor +loop(regi, + !! No adjustment if within tolerance +if (abs(pm_budgetDeviation(regi)) < abs(pm_regionalBudget_absDevTol(regi) ), + p45_factorRescale_taxCO2Regi(iteration, regi) = 1; + +else !! if not yet within tolerance +*** 2.1 for later iterations and if there is information about the carbon price adjustment leading into the right direction + if ((iteration.val ge 3) AND (p45_TaxBudgetSlopeBest(regi) lt 0), !! i.e. increase in carbon price led to reduction in budget, or vice versa; i.e. slope was meaningful + p45_factorRescale_taxCO2Regi(iteration, regi) = (pm_taxCO2eq("2100", regi) + !! price in the previous iteration + (- pm_budgetDeviation(regi) * p45_TaxBudgetSlopeBest(regi))) !! price change needed according to p45_TaxBudgetSlopeBest + / pm_taxCO2eq("2100", regi); + !! Note: p45_factorRescale_taxCO2Regi from this calculation coudl be negative when |pm_taxCO2eq| < |negative required price change|. + !! This is the case when the carbon-price-sensitivity is very low compared to the required budget change. + !! Leaving it for now, because the funnel takes care of it. +*** 2.2 for the first iteration or if p45_TaxBudgetSlopeBest is not yet established + else !! i.e. if iteration.val < 3 or unintuitive change + !! a) positive budget target + if (pm_budgetCO2from2020Regi(regi) > 0, + !! a1) positive actual budget => case analogous to global target default case: ratio = (actual budget/target) + if (p45_actualbudgetco2Regi(regi) >= 0, + p45_factorRescale_taxCO2Regi(iteration, regi) = max(0.5, (p45_actualbudgetco2Regi(regi) / pm_budgetCO2from2020Regi(regi))); + !! a2) negative actual budget => ratio = (positive target) / (absolute difference). Potential problem: Approaches 1 for small negative budgets + else + p45_factorRescale_taxCO2Regi(iteration, regi) = + max(0.5, (pm_budgetCO2from2020Regi(regi) / (pm_budgetCO2from2020Regi(regi) + abs(p45_actualbudgetco2Regi(regi))) ) ) ; + ) !! positive target sub-categories + !! b) negative budget target + else + !! b1) positive actual budget => take the absolute deviation & rescale to get a factor: ratio = log(actual + asb(target)) + if (p45_actualbudgetco2Regi(regi) >= 0, + p45_factorRescale_taxCO2Regi(iteration, regi) = log(abs(pm_budgetCO2from2020Regi(regi)) + p45_actualbudgetco2Regi(regi)) + !! b2) negative actual budget => case reverse to global target default case: ratio = (target/actual budget) + else + p45_factorRescale_taxCO2Regi(iteration, regi) = max(0.5, (pm_budgetCO2from2020Regi(regi) / p45_actualbudgetco2Regi(regi)))) + ) !! target type + ); !! earlier vs. later iterations + ); !! tolerance check + ); !! regi loop for scaling factor calculation + +*** 3. add a funnel to avoid excessive adjustments. + !! regi loop 3 + loop(regi, + p45_factorRescale_taxCO2Regi_Funneled(iteration, regi) + = max(min( cm_funnelFactor * EXP( -cm_funnelExponent * iteration.val) + 1 + cm_funnelLower, !! a) a maximum adjustment value which decreases with the number of iterations + p45_factorRescale_taxCO2Regi(iteration,regi)), + 1/ ( cm_funnelFactor * EXP( -cm_funnelExponent * iteration.val) + 1 + cm_funnelLower) !! b) a minimum adjustment value which increases with the number of iterations (0.95 for iter 25) + ); + ); !! regi loop 3 (funnelling the rescaling factor) + + !! copy the information before further funnelling + pm_factorRescale_taxCO2Regi_Funneled2(iteration, regi) = p45_factorRescale_taxCO2Regi_Funneled(iteration, regi) ; + + !! check how the rescaling factor changed over the last three iterations to dampen or expand the rescaling factor depending on the case + if ((iteration.val ge 4), + loop(regi, + !! if the factor was set to the *upper* bound for this and the last 2 iterations: increase the allowed factor this iteration + if (( (pm_factorRescale_taxCO2Regi_Funneled2(iteration, regi) ge p45_FunnelUpper(iteration)) !! ge because last iteration may have already been adjusted upwards + AND (pm_factorRescale_taxCO2Regi_Funneled2(iteration-1, regi) ge p45_FunnelUpper(iteration-1)) + AND (pm_factorRescale_taxCO2Regi_Funneled2(iteration-2, regi) ge p45_FunnelUpper(iteration-2))), + pm_factorRescale_taxCO2Regi_Funneled2(iteration, regi) = min(1.2 * p45_FunnelUpper(iteration), !! if funnel was 1.001, it is now 1.201 + p45_factorRescale_taxCO2Regi(iteration,regi)); !! unless the original planned rescaling factor was less + ); + + !! if the factor was set to the *lower* bound for this and the last 2 iterations: increase the allowed factor this iteration + if (( (pm_factorRescale_taxCO2Regi_Funneled2(iteration, regi) le p45_FunnelLower(iteration)) !! le because last iteration may have already been adjusted upwards + AND (pm_factorRescale_taxCO2Regi_Funneled2(iteration-1, regi) le p45_FunnelLower(iteration-1)) + AND (pm_factorRescale_taxCO2Regi_Funneled2(iteration-2, regi) le p45_FunnelLower(iteration-2))), + pm_factorRescale_taxCO2Regi_Funneled2(iteration, regi) = max( p45_FunnelLower(iteration) / 1.2, + p45_factorRescale_taxCO2Regi(iteration,regi)); + ); + !! if the factor jumping pos-neg-pos or neg-pos-neg or if it was already on 1 for the last two iterations -> make the last increase only 30% of what was intended + if (( (pm_factorRescale_taxCO2Regi_Funneled2(iteration, regi) le 1) !! ge because last iteration may have already been adjusted upwards + AND (pm_factorRescale_taxCO2Regi_Funneled2(iteration-1, regi) ge 1) + AND (pm_factorRescale_taxCO2Regi_Funneled2(iteration-2, regi) le 1)) + OR + ( (pm_factorRescale_taxCO2Regi_Funneled2(iteration, regi) ge 1) !! ge because last iteration may have already been adjusted upwards + AND (pm_factorRescale_taxCO2Regi_Funneled2(iteration-1, regi) le 1) + AND (pm_factorRescale_taxCO2Regi_Funneled2(iteration-2, regi) ge 1)), + pm_factorRescale_taxCO2Regi_Funneled2(iteration, regi) = 1 - (0.3 * (1-p45_factorRescale_taxCO2Regi_Funneled(iteration, regi))); !! decrease the distance to 1 + ); + ); !! regi loop + ); !! if iteration far enough + +!! if alternating adjustment: set "actual" adjustment factors to 1 according to iteration number +if ((cm_CPadjustmentAlternating eq 1) and (iteration.val ge 4), + !! a) uneven iteration => only update downwards + if ((mod(iteration.val, 2) eq 1), + loop(regi, + if(pm_factorRescale_taxCO2Regi_Funneled2(iteration, regi) gt 1, + p45_factorRescale_taxCO2Regi_Final(iteration, regi) = 1; + else + p45_factorRescale_taxCO2Regi_Final(iteration, regi) = pm_factorRescale_taxCO2Regi_Funneled2(iteration, regi); + ); !! if condition + ); !! regi Loop + !! b) even iteration => only update upwards + else + loop(regi, + if(pm_factorRescale_taxCO2Regi_Funneled2(iteration, regi) lt 1, + p45_factorRescale_taxCO2Regi_Final(iteration, regi) = 1; + else + p45_factorRescale_taxCO2Regi_Final(iteration, regi) = pm_factorRescale_taxCO2Regi_Funneled2(iteration, regi); + ); !! if condition + ); !! regi Loop + ); !! un/even iteration +!! if not alternating adjustment or lower iteration value +else + p45_factorRescale_taxCO2Regi_Final(iteration, regi) = pm_factorRescale_taxCO2Regi_Funneled2(iteration, regi); +) ; + +*** 4. Shift anchor curve with regional adjustment factor +!! 4.1. get the carbon price trajectory used in this iteration +if((iteration.val eq 1), !! the global anchor trajectory is chosen as starting point after iteration 1 -> all regions have the same shape + p45_taxCO2eq_anchorRegi(ttot, regi)$(ttot.val gt 2005) = p45_taxCO2eq_anchor(ttot); + else !! For all iterations > 1: get the CO2 tax that was used in this iteration, to be adjusted + p45_taxCO2eq_anchorRegi(ttot, regi)$(ttot.val gt 2005) = pm_taxCO2eq(ttot,regi); + ); + +!! Option 4A: slope of CP is not adjusted --> entire trajectory is rescaled, values will be used as of cm_startYear (see below) +if(cm_CPslopeAdjustment = 0, + !! A4.2. Scale the anchor trajectory in this iteration to get the adjusted trajectory to be used in iteration+1 + p45_taxCO2eq_anchorRegi(ttot,regi)$(ttot.val gt 2005) = + p45_taxCO2eq_anchorRegi(ttot, regi) * p45_factorRescale_taxCO2Regi_Final(iteration,regi); + + !! Adjust the shape if the peak-budget carbon price shape is set + if(cm_iterative_target_adj = 44 , !! After cm_peakBudgYr, the global anchor trajectory increases linearly with fixed annual increase given by cm_taxCO2_IncAfterPeakBudgYr + p45_taxCO2eq_anchorRegi(t,regi)$(t.val gt cm_peakBudgYr) = sum(t2$(t2.val eq cm_peakBudgYr), p45_taxCO2eq_anchorRegi(t2,regi)) !! CO2 tax in peak budget year + + (t.val - cm_peakBudgYr) * cm_taxCO2_IncAfterPeakBudgYr * sm_DptCO2_2_TDpGtC; !! increase by cm_taxCO2inc_after_peakBudgYr per year + ); +); !! no CP slope adjustment + +!! Option 4B: slope of CP is adjusted +if(cm_CPslopeAdjustment = 1, + p45_taxCO2eq_anchorRegi(ttot,regi)$(ttot.val ge 2005) = 0; !! reset carbon price trajectory to track errors + p45_temp_anchor(ttot,regi)$(ttot.val ge 2005) = pm_taxCO2eq(ttot,regi); !! helper + + !! B4.2: Save the carbon price. The values prior to cm_startYear will not be adjusted + p45_taxCO2eq_anchorRegi(ttot,regi)$(ttot.val ge 2005) = pm_taxCO2eq(ttot,regi); + + !! Option (a): If peak-budget shape: + if(cm_iterative_target_adj = 44, + !! B4.3a: Set the rescaled anchor trajectory as of cm_peakBudgYr + p45_taxCO2eq_anchorRegi(ttot,regi)$(ttot.val eq cm_peakBudgYr) = + p45_temp_anchor(ttot,regi) * p45_factorRescale_taxCO2Regi_Final(iteration,regi); + !! Set the peakBudgYr value plus predefined increase thereafter (the only currently tested version is post-increase slope = 0) (necessary because initial shape & thus all following are taken from the anchor trajectory) + p45_taxCO2eq_anchorRegi(ttot,regi)$(ttot.val ge cm_peakBudgYr) = + sum(ttot2$(ttot2.val eq cm_peakBudgYr), p45_taxCO2eq_anchorRegi(ttot2,regi)) !! CO2 tax in peak budget year + + (ttot.val - cm_peakBudgYr) * cm_taxCO2_IncAfterPeakBudgYr * sm_DptCO2_2_TDpGtC; !! increase by cm_taxCO2inc_after_peakBudgYr per year + + !! B4.4a: Calculate the slope for a linear connection between the last carbon price from input data and the Price in the Peak Budget year + p45_CarbonPriceSlope(regi) = (sum(ttot2$(ttot2.val eq cm_peakBudgYr), p45_taxCO2eq_anchorRegi(ttot2,regi)) + - sum(ttot3$(ttot3.val eq s45_YearBeforeStartYear), p45_taxCO2eq_anchorRegi(ttot3,regi))) + / (cm_peakBudgYr - s45_YearBeforeStartYear); + p45_CarbonPriceSlope_iter(iteration,regi) = p45_CarbonPriceSlope(regi); + + p45_taxCO2eq_anchorRegi(ttot,regi)$(ttot.val ge cm_startYear AND ttot.val lt cm_peakBudgYr) = + sum(ttot3$(ttot3.val eq s45_YearBeforeStartYear), p45_taxCO2eq_anchorRegi(ttot3,regi)) !! CO2 tax in last fixed period + + (ttot.val - s45_YearBeforeStartYear) * p45_CarbonPriceSlope(regi) ; + + !! Option (b): If increase until EOC + else + !! B2.3b: Set the rescaled anchor trajectory as of cm_peakBudgYr + p45_taxCO2eq_anchorRegi(ttot,regi)$(ttot.val eq 2100) = + p45_temp_anchor(ttot,regi) * p45_factorRescale_taxCO2Regi_Final(iteration,regi); + + !! Calculate the carbon price slope between last year from input gdx and 2100 + p45_CarbonPriceSlope(regi) = (sum(ttot2$(ttot2.val eq 2100), p45_taxCO2eq_anchorRegi(ttot2,regi)) + - sum(ttot3$(ttot3.val eq s45_YearBeforeStartYear), p45_taxCO2eq_anchorRegi(ttot3,regi))) + / (2100- s45_YearBeforeStartYear); + + p45_CarbonPriceSlope_iter(iteration,regi) = p45_CarbonPriceSlope(regi); + + p45_taxCO2eq_anchorRegi(ttot,regi)$(ttot.val ge cm_startYear AND ttot.val lt 2100) = + sum(ttot3$(ttot3.val eq s45_YearBeforeStartYear), p45_taxCO2eq_anchorRegi(ttot3,regi)) !! CO2 tax in last fixed period + + (ttot.val - s45_YearBeforeStartYear) * p45_CarbonPriceSlope(regi) ; + ); !! whether it is increase until 2100 or PB shape + );!! CP slope adjustment +!! 4.4. Always set carbon price constant after 2100 to prevent huge taxes after 2100 and the resulting convergence problems +p45_taxCO2eq_anchorRegi(ttot,regi)$(ttot.val gt 2100) = p45_taxCO2eq_anchorRegi("2100",regi); + +!! 4.5. assign p45_taxCO2eq_anchorRegi as the new value of pm_taxCO2eq that will be used in the next iteration +pm_taxCO2eq(ttot,regi)$(ttot.val ge cm_startyear) = p45_taxCO2eq_anchorRegi(ttot,regi); + +!! save the adjusted carbon price trajectory +p45_taxCO2eq_anchorRegi_iter(ttot, regi, iteration) = p45_taxCO2eq_anchorRegi(ttot, regi); +); !! closing the overarching cm_iterative Target condition + +***------------------------------------------------------------------------------------------------------------------------------------------------ +***END regional eoc emission budget +***------------------------------------------------------------------------------------------------------------------------------------------------ + + ***----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- *** Part 0 (Actual CO2 budget): If iterative_target_adj = 0, 7 or 9, compute actual CO2 peak budget in current iteration. If iterative_target_adj = 5, compute actual CO2 end-of-century budget in current iteration. ***----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/modules/80_optimization/nash/declarations.gms b/modules/80_optimization/nash/declarations.gms index acc7f6d46..0c56505c9 100644 --- a/modules/80_optimization/nash/declarations.gms +++ b/modules/80_optimization/nash/declarations.gms @@ -103,6 +103,7 @@ $ifthen.cm_implicitQttyTarget not "%cm_implicitQttyTarget%" == "off" p80_implicitQttyTarget_dev_iter(iteration,ttot,ext_regi,qttyTarget,qttyTargetGroup) "deviation of current iteration quantity target from target per iteration - relative for total targets, absolute (= share points) for share targets" $endif.cm_implicitQttyTarget p80_globalBudget_absDev_iter(iteration) "absolute deviation of global cumulated CO2 emissions budget from target budget" +p80_regionalBudget_absDev_iter(iteration,all_regi) "absolute deviation of regional cumulated CO2 emissions target budgets" p80_sccConvergenceMaxDeviation_iter(iteration) "max deviation of SCC from last iteration per iteration [percent]" p80_gmt_conv_iter(iteration) "global mean temperature convergence per iteration" ; diff --git a/modules/80_optimization/nash/postsolve.gms b/modules/80_optimization/nash/postsolve.gms index 982ef409f..1fc14e895 100644 --- a/modules/80_optimization/nash/postsolve.gms +++ b/modules/80_optimization/nash/postsolve.gms @@ -387,7 +387,6 @@ if ( abs(p80_globalBudget_absDev_iter(iteration)) gt cm_budgetCO2_absDevTol , !! p80_messageShow("globalbudget") = YES; ); - $ifthen.carbonprice %carbonprice% == "functionalForm" *** check whether cm_peakBudgYr corresponds to year of maximum cumulative CO2 emissions if ( ( cm_iterative_target_adj eq 9 @@ -402,6 +401,26 @@ if ( ( cm_iterative_target_adj eq 9 s80_bool = 0; p80_messageShow("peakbudget") = YES; ); + +*** check regional budget target, must be within tolerance level of target value +!!$ifthen.cm_iterative_target_adj (cm_iterative_target_adj == "4") OR (cm_iterative_target_adj == "44") +if(cm_iterative_target_adj eq 55, + p80_regionalBudget_absDev_iter(iteration,regi) = pm_budgetDeviation(regi); + loop(regi, + if(cm_regionalBudgetTolerance_Abs = 0, + if (abs(p80_regionalBudget_absDev_iter(iteration,regi)) gt abs(cm_regionalBudgetTolerance_Rel * pm_budgetCO2from2020Regi(regi)), + s80_bool = 0; + p80_messageShow("regiBudget") = YES; + ); + else + if (abs(p80_regionalBudget_absDev_iter(iteration,regi)) gt abs(cm_regionalBudgetTolerance_Abs), + s80_bool = 0; + p80_messageShow("regiBudget") = YES; + ); + ); + ); +); +!!$endIf.cm_iterative_target_adj $endIf.carbonprice @@ -479,13 +498,19 @@ $ifthen.carbonprice %carbonprice% == "functionalForm" display "#### 6.) PeakBudget not reached: sm_peakbudget_diff is greater than sm_peakbudget_diff_tolerance."; display sm_peakbudget_diff; ); + if(sameas(convMessage80, "regiBudget"), + display "#### 7.) A regional budget target has not been reached yet."; + display "#### pm_budgetCO2from2020Regi. Convergence determined by pm_regionalBudget_absDevTol or cm_regionalBudgetTolerance_Rel."; + display "#### Also check pm_taxCO2eq_iter (regional CO2 tax paths tracked over iterations [T$/GtC])"; + display pm_factorRescale_taxCO2Regi_Funneled2, p80_regionalBudget_absDev_iter; + ); $endIf.carbonprice if(sameas(convMessage80, "IterationNumber"), display "#### 0.) REMIND did not run sufficient iterations (currently set at 18, to allow for at least 4 iterations with EDGE-T)"; ); $ifthen.emiMkt not "%cm_emiMktTarget%" == "off" if(sameas(convMessage80, "regiTarget"), - display "#### 7) A regional climate target has not been reached yet."; + display "#### 7.) A regional climate target has not been reached yet."; display "#### Check out the pm_emiMktTarget_dev parameter of 47_regipol module."; display "#### For budget targets, the parameter gives the percentage deviation of current emissions in relation to the target value."; display "#### For yearly targets, the parameter gives the current emissions minus the target value in relative terms to the 2005 emissions."; diff --git a/modules/80_optimization/nash/sets.gms b/modules/80_optimization/nash/sets.gms index 9fdaaf9e1..5633232b6 100644 --- a/modules/80_optimization/nash/sets.gms +++ b/modules/80_optimization/nash/sets.gms @@ -26,7 +26,7 @@ solvestat, modelstat, resusd, objval convMessage80 "contains all convergence criteria" / -infes,surplus,nonopt,taxconv,anticip,globalbudget,peakbudgyr,peakbudget,regiTarget,implicitEnergyTarget,cm_implicitPriceTarget,cm_implicitPePriceTarget,damage,DevPriceAnticip, IterationNumber +infes,surplus,nonopt,taxconv,anticip,globalbudget,peakbudgyr,peakbudget,regiBudget,regiTarget,implicitEnergyTarget,cm_implicitPriceTarget,cm_implicitPePriceTarget,damage,DevPriceAnticip, IterationNumber / activeConvMessage80(convMessage80) "all active convergence criterias" / /