EnergyInnovation / eps-us

Energy Policy Simulator - United States
GNU General Public License v3.0
22 stars 7 forks source link

Make logit functions robust across broad range of logit exponent values #254

Closed jrissman closed 1 year ago

jrissman commented 1 year ago

Logit functions involve raising what can be a set of large quantities to a negative exponent, such as -3, -6, etc., which results in tiny values. They are then divided by a larger number produced in a similar way to obtain values of the correct magnitude for the output. Problems arise when the values become so small that Vensim rounds it to zero and ends up allocating nothing.

In EPS 3.4.2, we worked around the rounding error issue by adding * 10^6 to the numerator and the denominator of each logit function. This tended to allow us to use logit exponents that were one larger (one more negative, such as -3 instead of -2) before rounding error would cause a problem. However, it didn't expand the range dramatically.

We also tried dividing the values being raised to the exponent by a fixed amount, but this didn't really expand the range of valid logit exponents at all.

I've found that these two techniques work extremely well when applied together. For instance, in 3.5-wip, I have the logit function in New Capacity Desired for Reliability by Hour set up like this:

ZIDZ((
  Electricity Technology Shareweights Reflecting Hourly Resource Availability[Day,Hour,Electricity Source]
  * (
      Electricity Capacity Allocation Unit Correction
      * Shifted Positive Net Costs per Unit New Capacity by Plant Type[Electricity Source,Day,Hour] / 10^4
    )^ETLE Electricity Technology Logit Exponent for Capacity
  * 10^6
)
,
(
  SUM(Electricity Technology Shareweights Reflecting Hourly Resource Availability[Day,Hour,Electricity Source!]
  * (
      Electricity Capacity Allocation Unit Correction
      * Shifted Positive Net Costs per Unit New Capacity by Plant Type[Electricity Source!,Day,Hour] / 10^4
    )^ETLE Electricity Technology Logit Exponent for Capacity
  )
  * 10^6
))
* Last Year Capacity Shortfall Relative to Desired Reserve Margin[Day,Hour]

The / 10^4 and * 10^6 terms in the numerator and denominator above are the ones being used to prevent Vensim from rounding the results to zero.

I've found that the code above is robust with logit exponent values from -1 to -16. At -17 or greater, it fails. But -16 is already so price-sensitive that almost all of the new capacity is being packed into the single most cost-effective plant type, so I cannot see any reason why we would ever need a logit exponent more negative than -16. More realistic logit exponents are likely to be in the -1 to -8 range.

The exact orders of magnitude to use in the correction factors (in particular, where I have / 10^4) might depend on the order of magnitude of the cost inputs. In this case, Shifted Positive Net Costs per Unit New Capacity by Plant Type tends to have values in the 10^5 - 10^6 range, so dividing it by 10^4 tends to result in values from 10-100. But in some other logit function, the input costs might be different, and we might need to test and see if we need to use some different correction factors.

I'm opening this issue as a reminder to go through the model and update all logit functions to use correction factors in two places in the numerator and two places in the denominator as shown above, and to test them to make sure they work across a sufficiently broad range of logit exponents. Start off by testing with / 10^4 and * 10^6, since those terms might work for all logit functions in the model.

mkmahajan commented 1 year ago

The only other logit function that needed to be tested was for vehicle choice.