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

Issue #137 Output billing periods w/analysis types #142

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions rules-engine/src/rules_engine/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ def convert_to_intermediate_billing_periods(
analysis_type = billing_period.inclusion_override

intermediate_billing_period = BillingPeriod(
start_date=billing_period.period_start_date,
end_date=billing_period.period_end_date,
avg_temps=temperature_input.temperatures[start_idx:end_idx],
usage=billing_period.usage,
analysis_type=analysis_type,
Expand Down Expand Up @@ -518,6 +520,9 @@ def calculate_partial_ua(self, billing_period: BillingPeriod) -> float:
# BTUs/hour
)

def get_all_billing_periods(self) -> List[BillingPeriod]:
return self.bills_winter + self.bills_shoulder + self.bills_summer


class BillingPeriod:
avg_heating_usage: float
Expand All @@ -528,10 +533,14 @@ class BillingPeriod:

def __init__(
self,
start_date: date,
end_date: date,
avg_temps: List[float],
usage: float,
analysis_type: AnalysisType,
) -> None:
self.start_date = start_date
self.end_date = end_date
self.avg_temps = avg_temps
self.usage = usage
self.analysis_type = analysis_type
Expand Down
182 changes: 167 additions & 15 deletions rules-engine/tests/test_rules_engine/test_engine.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from datetime import date
from datetime import date, datetime

import pytest
from pytest import approx
Expand All @@ -20,22 +20,76 @@
@pytest.fixture()
def sample_billing_periods() -> list[engine.BillingPeriod]:
billing_periods = [
engine.BillingPeriod([28, 29, 30, 29], 50, AnalysisType.INCLUDE),
engine.BillingPeriod([32, 35, 35, 38], 45, AnalysisType.INCLUDE),
engine.BillingPeriod([41, 43, 42, 42], 30, AnalysisType.INCLUDE),
engine.BillingPeriod([72, 71, 70, 69], 0.96, AnalysisType.DO_NOT_INCLUDE),
engine.BillingPeriod(
datetime(2023, 1, 1),
datetime(2023, 1, 4),
[28, 29, 30, 29],
50,
AnalysisType.INCLUDE,
),
engine.BillingPeriod(
datetime(2023, 1, 8),
datetime(2023, 1, 11),
[32, 35, 35, 38],
45,
AnalysisType.INCLUDE,
),
engine.BillingPeriod(
datetime(2023, 1, 15),
datetime(2023, 1, 18),
[41, 43, 42, 42],
30,
AnalysisType.INCLUDE,
),
engine.BillingPeriod(
datetime(2023, 5, 1),
datetime(2023, 5, 4),
[72, 71, 70, 69],
0.96,
AnalysisType.DO_NOT_INCLUDE,
),
]
return billing_periods


@pytest.fixture()
def sample_billing_periods_with_outlier() -> list[engine.BillingPeriod]:
billing_periods = [
engine.BillingPeriod([41.7, 41.6, 32, 25.4], 60, AnalysisType.INCLUDE),
engine.BillingPeriod([28, 29, 30, 29], 50, AnalysisType.INCLUDE),
engine.BillingPeriod([32, 35, 35, 38], 45, AnalysisType.INCLUDE),
engine.BillingPeriod([41, 43, 42, 42], 30, AnalysisType.INCLUDE),
engine.BillingPeriod([72, 71, 70, 69], 0.96, AnalysisType.DO_NOT_INCLUDE),
engine.BillingPeriod(
datetime(2023, 1, 1),
datetime(2023, 1, 4),
[41.7, 41.6, 32, 25.4],
60,
AnalysisType.INCLUDE,
),
engine.BillingPeriod(
datetime(2023, 1, 8),
datetime(2023, 1, 11),
[28, 29, 30, 29],
50,
AnalysisType.INCLUDE,
),
engine.BillingPeriod(
datetime(2023, 1, 15),
datetime(2023, 1, 18),
[32, 35, 35, 38],
45,
AnalysisType.INCLUDE,
),
engine.BillingPeriod(
datetime(2023, 1, 22),
datetime(2023, 1, 25),
[41, 43, 42, 42],
30,
AnalysisType.INCLUDE,
),
engine.BillingPeriod(
datetime(2023, 5, 1),
datetime(2023, 5, 4),
[72, 71, 70, 69],
0.96,
AnalysisType.DO_NOT_INCLUDE,
),
]

return billing_periods
Expand Down Expand Up @@ -243,6 +297,74 @@ def test_bp_ua_with_outlier(sample_summary_inputs, sample_billing_periods_with_o
assert home.stdev_pct == approx(0.0474, abs=0.01)


def test_analysis_type_outputs(sample_summary_inputs):
# these would already be constructed in convert_to_intermediate_billing_periods before Home is built
analysis_type_sample_billing_periods = [
engine.BillingPeriod(
datetime(2023, 1, 1),
datetime(2023, 1, 4),
[28, 29, 30, 29],
50,
AnalysisType.INCLUDE,
),
engine.BillingPeriod(
datetime(2023, 1, 8),
datetime(2023, 1, 11),
[32, 35, 35, 38],
45,
AnalysisType.INCLUDE,
),
engine.BillingPeriod(
datetime(2023, 9, 1),
datetime(2023, 9, 4),
[60, 55, 49, 40],
5,
AnalysisType.INCLUDE_IN_OTHER_ANALYSIS,
),
engine.BillingPeriod(
datetime(2023, 9, 9),
datetime(2023, 9, 12),
[60, 54, 55, 52],
21,
AnalysisType.INCLUDE_IN_OTHER_ANALYSIS,
),
engine.BillingPeriod(
datetime(2023, 5, 1),
datetime(2023, 5, 4),
[72, 71, 70, 69],
0.96,
AnalysisType.DO_NOT_INCLUDE,
),
engine.BillingPeriod(
datetime(2023, 5, 9),
datetime(2023, 5, 12),
[80, 65, 70, 75],
0.95,
AnalysisType.DO_NOT_INCLUDE,
),
]

home = engine.Home(
sample_summary_inputs,
analysis_type_sample_billing_periods,
initial_balance_point=58,
)

home.calculate()

results = home.get_all_billing_periods()
# expecting results back in same order as input as they are presorted to INCLUDE, INCLUDE_IN_OTHER, DO_NOT_INCLUDE
expected_results = analysis_type_sample_billing_periods

for i in range(len(expected_results)):
result = results[i]
expected_result = expected_results[i]

assert result.start_date == expected_result.start_date
assert result.end_date == expected_result.end_date
assert result.analysis_type == expected_result.analysis_type


def test_convert_to_intermediate_billing_periods(
sample_temp_inputs, sample_normalized_billing_periods
):
Expand All @@ -251,11 +373,41 @@ def test_convert_to_intermediate_billing_periods(
)

expected_results = [
engine.BillingPeriod([41.7, 41.6, 32, 25.4], 60, AnalysisType.INCLUDE),
engine.BillingPeriod([28, 29, 30, 29], 50, AnalysisType.INCLUDE),
engine.BillingPeriod([32, 35, 35, 38], 45, AnalysisType.INCLUDE),
engine.BillingPeriod([41, 43, 42, 42], 30, AnalysisType.INCLUDE),
engine.BillingPeriod([72, 71, 70, 69], 0.96, AnalysisType.DO_NOT_INCLUDE),
engine.BillingPeriod(
datetime(2023, 1, 1),
datetime(2023, 1, 4),
[41.7, 41.6, 32, 25.4],
60,
AnalysisType.INCLUDE,
),
engine.BillingPeriod(
datetime(2023, 1, 8),
datetime(2023, 1, 11),
[28, 29, 30, 29],
50,
AnalysisType.INCLUDE,
),
engine.BillingPeriod(
datetime(2023, 1, 15),
datetime(2023, 1, 18),
[32, 35, 35, 38],
45,
AnalysisType.INCLUDE,
),
engine.BillingPeriod(
datetime(2023, 1, 22),
datetime(2023, 1, 25),
[41, 43, 42, 42],
30,
AnalysisType.INCLUDE,
),
engine.BillingPeriod(
datetime(2023, 5, 1),
datetime(2023, 5, 4),
[72, 71, 70, 69],
0.96,
AnalysisType.DO_NOT_INCLUDE,
),
]

for i in range(len(expected_results)):
Expand Down
2 changes: 1 addition & 1 deletion rules-engine/tests/test_rules_engine/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def test_average_indoor_temp(data: Example) -> None:
assert data.summary.average_indoor_temperature == approx(avg_indoor_temp, rel=0.1)


def test_get_outputs_natural_gas(data: Example):
def test_get_outputs_natural_gas(data: Example) -> None:
summary_output, balance_point_graph = engine.get_outputs_natural_gas(
data.summary, data.temperature_data, data.natural_gas_usage
)
Expand Down
Loading