Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emi mkt target update #1331

Merged

Conversation

Renato-Rodrigues
Copy link
Member

@Renato-Rodrigues Renato-Rodrigues commented Jun 13, 2023

Purpose of this PR

  • Avoid negative carbon prices if emission target does not require any carbon price. Minimum carbon price is set to $1 / ton for now.
  • Rescaling non-energy reporting values to match EU-27 data. This change hard-codes future non-energy use values to be compatible with the ex-post non-energy reporting values used in the remind2 library. Related with rescaling non-energy reporting values to match EU-27 data pik-piam/remind2#411
  • Improve convergence algorithm for multiple temporal targets applied to the same region.
  • Add auxiliary set to assure that numeric values follow ascending order in the GAMS entry order.
  • Additional switches support to allow control of convergence tolerances for regipol emission quantity targets (cm_emiMktTarget_tolerance and cm_implicitQttyTarget_tolerance).

Type of change

  • Improvements

Checklist:

  • My code follows the coding etiquette
  • I performed a self-review of my own code
  • I explained my changes within the PR, particularly in hard-to-understand areas
  • I checked that the in-code documentation is up-to-date
  • I adjusted the reporting in remind2 where it was needed
  • All automated model tests pass (FAIL 0 in the output of make test)

Further information (optional):

  • Test runs are here: /p/projects/ecemf/REMIND/2040_scenarios/v04_2023_06_02

@Renato-Rodrigues Renato-Rodrigues marked this pull request as ready for review June 13, 2023 12:44
p47_nonEnergyUse("2050",ext_regi)$(sameas(ext_regi, "EU27_regi")) = 0.121606*0.815;
p47_nonEnergyUse("2050",ext_regi)$(sameas(ext_regi, "EUR_regi")) = 0.13*0.841;
*** DEU -> 0.946 EJ = 0.03 Twa (2020 non-energy use)
p47_nonEnergyUse("2030",ext_regi)$(sameas(ext_regi, "DEU")) = 0.03*0.928;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where do the 0.928 and 0.848 and 0.822 come from?

I guess the 2030 value is from the historical 2020 value (as in EU), but how is this projected to 2045/2050 - a REMIND run?
(I am not doubting the values, I am just thinking about the next person who has to work on this in 2 years and is wondering "was there a good source for this, or can I simply change it?")

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pm_fe_nechem values were calculated ad hoc by Michaja, and refers originally to a very rough estimation of non-energy use in chemicals.
Due the lack of a better alternative until we have proper non-energy trajectories being considered in REMIND, these are scaled to represent total non-energy use as described in: pik-piam/remind2#411 .

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the values that you see multiplied by the 2020 original non-energy use, are simply the relative difference that the exogenously defined trajectory in pm_fe_nechem considers in comparison to 2020.

loop(regi$regi_groupExt(ext_regi,regi),
loop(emiMkt$emiMktGroup(emiMktExt,emiMkt),
*** if emiMKt target did not converged and we are not forcing negative prices (if the price is at minimal level (1$/tCO2) and current emissions are lower than the target)
if(((abs(pm_emiMktTarget_dev(ttot,ttot2,ext_regi,emiMktExt)) gt cm_emiMktTarget_tolerance) and (not ((pm_taxemiMkt(ttot2,regi,emiMkt) eq 1*sm_DptCO2_2_TDpGtC) and (pm_emiMktTarget_dev(ttot,ttot2,ext_regi,emiMktExt) lt 0)))), !! if emiMKt target did not converged and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 questions:

  1. does GAMS store the pm_taxemiMkt(ttot2,regi,emiMkt) with the same number of digits so that (not ((pm_taxemiMkt(ttot2,regi,emiMkt) eq 1*sm_DptCO2_2_TDpGtC) will really be returned true?

  2. could there be the problem that the model has in one iteration quite low emissions, uses the slope to calculate new (negative) CO2 prices that in the end miss the target, but the algorithm never checks this as it stops in the first iteration?

maybe add a "needs to be 2 iterations in negative prices" safety buffer to prevent this from happening? or do you think this phenomenon will be very unlikely?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. sm_DptCO2_2_TDpGtC is a scalar hard-coded to 0.00366667. So yes, this number should be always the same and equal to 0.00366667 as consequence. Tolerances only affect variables and equations as far as I know.

  2. All targets are checked at every iteration if they are converging or not, so the algorithm keeps checking if the convergence has changed, even if the model reached full convergence in some previous iteration. See: https://github.com/remindmodel/remind/blob/252343cf0b39d827317e6b7affbd86a69729e37e/modules/47_regipol/regiCarbonPrice/postsolve.gms#L181C1-L208

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still about 2, if a slope causes negative prices, the prices will be set to 1 dollar in this iteration. In the next iteration the slope will be then calculated against the 1 dollar price instead. This already adds a second attempt using a different slope to avoid the negative prices.
I am not saying the case you mention could not happen, but I don't I saw it happening yet, at least in the runs I did so far.

Avoiding this would require a bit more complicated code than checking negative prices in two consecutive runs. I only see the need to spend time with this if this becomes a recurrent issue.

Besides, as far as I saw, negative carbon taxes are much more a symptom of ill defined targets than a result of the algorithm so far. In this case, getting the modeler attention with a non-converged run is a much better result than handing these cases quietly inside the algorithm "black-box".

loop((ext_regi,ttot)$regiANDperiodEmiMktTarget_47(ttot,ext_regi),
if(ord(iteration) eq 1,
p47_slopeReferenceIteration(iteration,ttot,ext_regi) = 1;
elseif(NOT(p47_currentConvergence_iter(iteration,ttot,ext_regi) eq p47_currentConvergence_iter(iteration-1,ttot,ext_regi))),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get this - why is it the right question to ask if the target convergence check was different between last and this iteration? if I understand correctly, this gets updated to the current iteration if a) last iteration the check was on and now it is not on, and b) last iteration the check was off and now it is on?

Copy link
Member Author

@Renato-Rodrigues Renato-Rodrigues Jun 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line says that, for a given region, whenever you change the target that you are currently updating in comparison to the previous iteration (NOT(p47_currentConvergence_iter(iteration,ttot,ext_regi) eq p47_currentConvergence_iter(iteration-1,ttot,ext_regi)), you need to reset the p47_slopeReferenceIteration value (p47_slopeReferenceIteration(iteration,ttot,ext_regi) = current iteration).
Otherwise, you just keep the reference iteration value unchanged: p47_slopeReferenceIteration(iteration,ttot,ext_regi) = p47_slopeReferenceIteration(iteration-1,ttot,ext_regi);.

This way, whenever you change your target year focus, you will run an initial tax update using a simplified formula, and only from the next iteration onwards the slope will be used to update the tax values using as reference the closest iteration that used the simplified formula.

Take a look at /p/projects/ecemf/REMIND/2040_scenarios/v04_2023_06_02/output/04_Nzero_57_RpEUEff_bio7p5_limCC_EU27_2023-06-02_17.25.43 for example.

We have two targets for EU27, one by 2030 and another by 2050 (cm_emiMktTarget = 2020.2030.EU27_regi.all.year.netGHG_LULUCFGrassi_intraRegBunker 2.122, 2035.2050.EU27_regi.all.year.netGHG_LULUCFGrassi 0.01)

If you take a look at p47_currentConvergence_iter, you will see that at iterations 1, 6, 9 and 12, our focus to update the taxes changes from 2030 to 2050 to 2030 and back to 2050.

    1 2 3 4 5 6 7 8 9 10 11 12 13
EU27_regi 2030 1 1 1 1 1       1 1 1    
EU27_regi 2050           1 1 1       1 1

This means,

  • the 2030 target converged at iteration 6, so we switched to try to solve the 2050 in the next one.
  • Then, we updated the 2050 taxes for three iterations, but at iteration 9 these updates caused the 2030 to not converge anymore.
  • We kept the 2050 as is, and got back on updating the 2030 target to converge from iteration 9, and it finally converged at iteration 12.
  • The we got back to the 2050 target and finally from iteration 14 onward both targets converged, and kept converging until the end of the model run.

Now how the tax update was done:

  • When you are at iterations that change target focus - iteration 1 by definition and iterations 6, 9 and 12 in the example above - the tax update is defined by a simple rule based on the current deviation.
  • When you are at other iterations, the tax update is defined by the slope between the tax and target changes, calculated from the nearest iteration that had a target change focus.
    • When you are at iterations 2 to 5, the tax update is defined by the slope that you observed from iteration 1.
    • When you are at iterations 7 to 8, the tax update is defined by the slope that you observed from iteration 6.
    • When you are at iterations 10 to 11, the tax update is defined by the slope that you observed from iteration 9.
    • When you are at iteration 13 onward, the tax update is defined by the slope that you observed from iteration 12.

The values of p47_slopeReferenceIteration reflect the reference iterations to calculate the slope as I described above:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14
EU27_regi 2030 1 1 1 1 1 6 6 6 9 9 9 12 12 12
EU27_regi 2050 1 1 1 1 1 6 6 6 9 9 9 12 12 14

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the extended explanation!
what about adding "!! reset the slope if the target that is being analyzed changes" in the elseif line to get people thinking in the right direction?
I had misinterpreted the parameter as "is the target converged", and not "is this the target the model is currently focusing on"

@Renato-Rodrigues Renato-Rodrigues merged commit eafa7cd into remindmodel:develop Jul 6, 2023
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants