-
Notifications
You must be signed in to change notification settings - Fork 1
Surface Plant time series integrations fix (Electricity Provided + other profiles final year value correction) #52
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
Conversation
…Wh integration (WIP)
…electricity_pumping_power. FIXME TODO WIP marked for remaining integrations to adjust.
… into SurfacePlant, SurfacePlantAGS, and SurfacePlantIndustrialHeat (other plant types remain WIP/TODO to fix still; unit tests not yet updated)
…low this commit to serve as a checkpoint that ensures unit tests are passing and results are not affected by any structural issues in refactoring.
@staticmethod | ||
def integrate_time_series_slice( | ||
series: np.ndarray, | ||
_i: int, | ||
time_steps_per_year: int, | ||
utilization_factor: float | ||
) -> np.float64: | ||
slice_start_index = _i * time_steps_per_year | ||
slice_end_index = ((_i + 1) * time_steps_per_year) + 1 | ||
_slice = list(series[slice_start_index:slice_end_index]) | ||
|
||
# Note that len(_slice) - 1 may be less than time_steps_per_year for the last slice. | ||
|
||
if len(_slice) == 1: | ||
extrapolated_future_datapoint = _slice[0] | ||
if slice_start_index - 1 > 0: | ||
delta = series[slice_start_index] - series[slice_start_index - 1] | ||
extrapolated_future_datapoint = _slice[0] + delta | ||
_slice.append(extrapolated_future_datapoint) | ||
|
||
dx_steps = len(_slice) - 1 | ||
|
||
integral = np.trapz( | ||
_slice, | ||
dx=1. / dx_steps * 365. * 24. | ||
) | ||
|
||
return integral * 1000. * utilization_factor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The crux of this fix is that the previous behavior was doing the equivalent of erroneously setting dx_steps
to time_steps_per_year
. The last slices of the time series in question always have one less data point than time_steps_per_year
, which was causing the trapezoidal rule to behave as if the slice had a 'phantom' entry with value=0 appended to it, thus lowering the estimated integral value of the slice.
It was brought to my attention by some user feedback that Electricity Provided showed an unexplained dropoff in the final project year:
Upon investigation, I discovered that this was an artifact of the
dx
argument tonp.trapz
used for integrating the Electricity Provided profile from individual time step values incorrectly assuming that the final profile slice had number of members = time steps per year, when the final slice actually has 1 fewer member (in the cases I looked at).To confirm that this is indeed a bug, conceptually speaking: Consider current behavior when time steps per year is set to 1. In this case, Heat Extracted and Electricity Provided will be zero for the final year. This is obviously wrong, and demonstrates that the current usage of

np.trapz
is flawed and that the behavior is not intentional:To resolve, I updated usage of
np.trapz
inSurfaceApplication*.py
time series integrations to calculatedx
according to the actual number of time steps in the slice, rather than assuming the value is equal to time steps per year.Testing/verification of fix:
SurfacePlant.integrate_time_series_slice
.out
files (per standard procedure) and manually sanity-checked