Skip to content

Unexpected generation booking dates #23

Description

@caleb-sitton-inl

When EnergyProject.generation is called, DCAF builds the generation stream across various dates. generation provides frequency and timing args intended to allow the user to configure the booking dates. The booking dates are based on calendar years, however, not on window dates. To illustrate, consider a generation across the period 12/31/26 to 12/31/27, with frequency="year" and timing="end". Instead of booking the generation on 12/31/27 (the end of the window), it books the generation on 12/31/26, since that date is the end of the calendar year in which the generation period starts. This feels unintuitive and uncustomary, and it has a significant downstream effect on project economics.

Evidence of this issue is shown here, where the booking date for a generation event is determined:

DCAF/dcaf/project/_compiler.py

Lines 1486 to 1506 in 801234a

delta = time_delta_per_period(frequency)
current = start
schedule = []
while current < exclusive_end:
window_end = min(current + delta, exclusive_end)
schedule.append(
ScheduledPeriod(
start=current,
end=window_end,
event_date=event_date(
current, frequency, timing, phase_start, effective_phase_end
),
fraction=elapsed_periods(
current,
window_end,
frequency,
self.config.day_count_convention,
),
)
)
current += delta

current is set to start, then is passed in as dt to event_date, which handles it thus:

DCAF/dcaf/shared/time.py

Lines 171 to 174 in 801234a

match timing:
case "end":
cal_end = period_end(dt, frequency)
return min(cal_end, phase_end) if phase_end is not None else cal_end

This calculates the end date of the calendar year for dt. Since dt is the start of the generation period, the strange behavior is introduced.

There are two main strategies for addressing this issue. First, generation periods could reflect calendar years. In this scenario, the generation for the first and last partial years would be prorated based on the date. Second, generation periods could remain as mid-year-to-mid-year windows, but the entire generation could be booked based on the period window, not the calendar date. Thus, in the example above, a timing of "end" would place the first generation event on 12/31/27, which would cover all generation from 12/31/26 (inclusive) to 12/31/27 (exclusive).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions