Skip to content

Commit

Permalink
Merge pull request #30 from codeforboston/engine
Browse files Browse the repository at this point in the history
Create engine.py with basic methods for HDD and UA calculations
  • Loading branch information
thadk authored Jun 28, 2023
2 parents 480f509 + 8fa6cbe commit 39e3a15
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 0 deletions.
116 changes: 116 additions & 0 deletions rules-engine/src/rules_engine/engine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
from datetime import datetime, timedelta

btu_per_usage = {
"gas": 100000, # usage in therms
"oil": 139600, # usage in gallons
"propane": 91333, # usage in gallons
}


def hdd(avg_temp: float, balance_point: float) -> float:
"""Calculate the heating degree days on a given day for a given home.
Arguments:
avg_temp -- average outdoor temperature on a given day
balance_point -- outdoor temperature above which no heating is required in
a given home
"""
diff = balance_point - avg_temp

if diff < 0:
return 0
else:
return diff


def period_hdd(avg_temps: list, balance_point: float) -> float:
"""Sum up total heating degree days in a given time period for a given home.
Arguments:
avg_temps -- list of daily average outdoor temperatures (F) for the period
balance_point -- outdoor temperature (F) above which no heating is required
in a given home
"""
return sum([hdd(temp, balance_point) for temp in avg_temps])


def ua(
days_in_period: int,
daily_heat_usage: float,
BTU_per_usage: float,
heat_sys_efficiency: float,
period_hdd: float,
) -> float:
"""Computes the UA coefficient for a given billing period.
Arguments:
days_in_period -- number of days in the given billing period
daily_heat_usage -- average daily usage for heating during the period
BTU_per_usage -- energy density constant for a given fuel type
heat_sys_efficiency -- heating system efficiency (decimal between 0 and 1)
period_hdd -- total number of heating degree days in the given period
"""
return (
days_in_period
* daily_heat_usage
* BTU_per_usage
* heat_sys_efficiency
/ (period_hdd * 24)
)


def get_avg_temps(end_dates: list, days_in_bills: list) -> list:
"""Returns a list of lists of average daily temperatures for each period
Arguments:
end_dates -- list of ending dates for each billing period
days_in_bills -- lengths in days for the list of billing periods
"""
# TODO: write this method once we know how we're getting temp data
return [[]]


def uas(
fuel_type: str,
balance_point: float,
non_heating_usage: float,
heat_sys_efficiency: float,
end_dates: list,
days_in_bills: list,
usages: list,
):
"""Given a list of billing periods, returns a list of UA coefficients
Arguments:
fuel_type -- heating fuel type in the home. One of "gas", "oil", "propane"
balance_point -- outdoor temperature (F) above which no heating is required
in a given home
non_heating_usage -- estimate of daily non-heating fuel usage
end_dates -- list of ending dates for each billing period
days_in_bills -- lengths in days for the list of billing periods
usages -- list of fuel usages for each billing period
"""

# this implementation assumes that the three list arguments are the same
# length, and also that the fuel_type string is valid. Not sure if this is
# the place to do that checking, or if it will be handled earlier

avg_daily_heating_usages = [
usage / days - non_heating_usage for usage, days in zip(usages, days_in_bills)
]
period_hdds = [
period_hdd(temps, balance_point)
for temps in get_avg_temps(end_dates, days_in_bills)
]
BTU_per_usage = btu_per_usage[fuel_type]

return [
ua(
days_in_bills[period],
avg_daily_heating_usages[period],
BTU_per_usage,
heat_sys_efficiency,
period_hdds[period],
)
for period in range(len(usages))
]
27 changes: 27 additions & 0 deletions rules-engine/tests/rules_engine/test_engine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from rules_engine import engine


def test_hdd():
assert engine.hdd(72, 60) == 0 # outside hotter than balance point
assert engine.hdd(60, 60) == 0 # outside equal to balance point
assert engine.hdd(57, 60) == 3 # outside cooler than balance point


def test_period_hdd():
bp = 60
temps_1 = [72, 60, 55, 61]
temps_2 = [52, 60, 55]
temps_3 = [72, 60, 65, 60, 80]

assert engine.period_hdd(temps_1, bp) == 5 # one day with HDDs
assert engine.period_hdd(temps_2, bp) == 13 # two days with HDDs
assert engine.period_hdd(temps_3, bp) == 0 # no days with HDDs


def test_ua():
# I pulled the numbers for this test from the spreadsheet
bill_days, htg, p_hdd = 32, 6.92, 1015.9
btu_per_u = 100000
heat_eff = 0.88

assert engine.ua(bill_days, htg, btu_per_u, heat_eff, p_hdd) - 799.4 < 0.2

0 comments on commit 39e3a15

Please sign in to comment.