Mimi Framework

MimiFUND emissions pulse

Hi there!

I’ve been looking into the MimiFUND code and noticed the following line in the add_marginal_emissions! function (in the new_marginaldamages.jl file).

if year != nothing 
    # pulse is spread over ten years, and emissions components is in Mt so divide by 1e7, and convert from CO2 to C if gas==:CO2 because emissions component is in MtC
    addem[getindexfromyear(year):getindexfromyear(year) + 9] .= pulse_size / 1e7 * (gas == :CO2 ? 12/44 : 1)

Could you please explain why the pulse is spread over ten years, given that (at least to my understanding) FUND has an annual timestep? And also, why is the marginal pulse pulse_size set to 1e7 metric tonnes (as the default value)? I’m guessing that this has something to do with 1e7 metric tonnes / 10 years = 1 Mt / year, but if the emissions pulse is 1 Mt / year, doesn’t this make the SCC value outputted by the model equal to the social cost of an additional Mt of emissions, rather than an additional metric tonne (t)? Or is there a unit adjustment somewhere in the code? I had a look but I couldn’t find anything, except for this line on the :impactaggregation component:

v.loss[t, r] = (v.eloss[t, r] + v.sloss[t, r]) * 1000000000.0

…which is equally mysterious to me (why multiply by 1e9?)

Apologies if there’s a very obvious answer to this and thanks so much in advance for your help!

Hi @tammyt123, sorry for the delay. This is a more FUND specific question than I am an expert for so you may want to check in with the FUND developers, whom I will also ping for you and point here so they can answer when they have the chance, but off the top of my head:

(1) Why is the pulse spread over ten years when FUND has annual timesteps?

The reasons for spreading the pulse across ten of FUND’s annual time steps is beyond my knowledge, but the high-level view is that all of these timestep-organized equations are an exercise in discretizing continuous functions, so there is probably a level of experimentation that went on to look for what produced stable, proper results in light of the continuous functions. I recognize that’s vague and think the FUND developers can concretize that for me :).

(2) Units

Good questions! I would need to return to the code to trace this properly, and won’t do that here to maintain this as more of a Mimi focused forum, but given the extensive validation code you can assume the units are correctly adjusted to be SCC per ton by the end. FUND developers can feel free to add here too!

Alright looking into this the following two posts will explain what is going on here, in more detail than I previously promised because this really does have to do with a core Mimi function, create_marginal_model and its delta keyword argument.

First of all just to start:

  1. Assuming that based on what FUND design decisions have told us:
  • pulse_size is spread over ten years based on FUND design decisions

  • pulse_size is provided in metric tonnes

  • the emissions component expects what it is given to be in Mt per timestep

    Then exactly as you say, dividing by 1e7 will get our provided emissions pulse into the right units:

    (tonnes per ten years) * (1/1e6 tonnes per Mt) (1/10 of ten years per timestep) = Mt per timestep (where timestep is one year)

  1. The division by 1e9 in :impactaggregation converts from billions of dollars to dollars

Thus, your output from the :impactaggregation component’s :loss variable is going to be in US dollars.

OK so now you wonder, "but where do we make sure we return SCC per ton instead of SCC per 10 Mt?"

Hi Lisa,

No problem! This makes sense. I think the 1e9 thing might be to do with the damages being in trillions and needing to convert to dollars?

(Edit: ** billions)

1 Like

Taking a look at MimiFUND’s new_marginaldamages.jl file, look at this function:

function get_marginal_model(m::Model = get_model(); gas::Symbol = :CO2, year::Union{Int, Nothing} = nothing, pulse_size::Float64 = 1e7)
    year !== nothing && !(year in 1950:3000) ? error("Cannot add marginal emissions in $year, year must be within the model's time index 1950:3000.") : nothing

    mm = create_marginal_model(m, pulse_size)
    add_marginal_emissions!(mm.modified, year; gas = gas, pulse_size = pulse_size)

    return mm

And let’s focus on this line:

mm = create_marginal_model(m, pulse_size)

The function create_marginal_model is a Mimi function described in the documentation here and copied below for simplicity:

So looking back at mm = create_marginal_model(m, pulse_size), the FUND code is setting the delta variable to pulse_size, so instead of defaulting to 1.0 it is 1e7. Internally, whenever you index into a MarginalModel, Mimi takes a look at the delta and divides by it to make sure that the returned value is per unit of delta.

So for example again in new_marginaldamages.jl we see the following line:

 marginaldamage = mm[:impactaggregation, :loss]

Under the hood what Mimi actually returns from this indexing is:

(mm.modified[comp_name, name] .- mm.base[comp_name, name]) ./ mm.delta

So here it takes the difference in the value of the :impactaggregation component’s :loss variable between the base model and the modified model (which in this case was given a CO2 pulse), and then divides by mm.delta, which we have set to be equal to pulse_size!

1 Like

Ah, I see – thank you so much! This makes sense. Appreciate your time and help with this!