Resource_Analytics / calculator.py
shivamsshhiivvaamm's picture
Upload 8 files
0a87e25 verified
from config import FLOW_RATES, USAGE_PATTERNS, USER_MULTIPLIERS, DRINKING_WATER
def calculate_usage(requirements):
"""
Calculates daily water usage and survival days.
IMPORTANT - How effective multipliers work (matching Excel model):
- eff_shower/sink = SUM of (count Γ— mult) across all user types
β†’ This already encodes total group usage, so NO extra Γ— num_adults needed
- eff_toilet = SUM of all adult counts (toilet mult = 1 for everyone)
β†’ Used for display only; toilet formula uses base per-person Γ— 1 event
- Toilet daily = flow Γ— frequency Γ— 1 (base, not scaled by eff_toilet)
- Drinking adults = 0.7 Γ— num_adults from CORE PARAMS (not user type total)
"""
# ── User type counts (from User Type Distribution) ──────────────────────
num_expert = requirements.get("num_expert", 0)
num_typical = requirements.get("num_typical", 0)
num_glamper = requirements.get("num_glamper", 0)
# ── Core params ──────────────────────────────────────────────────────────
num_adults = requirements.get("num_adults", num_expert + num_typical + num_glamper)
num_children = requirements.get("num_children", 0)
climate_mult = requirements.get("climate_mult", 1.0)
# ── Effective Multipliers (SUM β€” already encodes all adults) ─────────────
# Excel: Eff Shower = 2Γ—0.6 + 0Γ—1.0 + 1Γ—1.5 = 2.7 (NOT divided by adults)
eff_shower_mult = (
num_expert * USER_MULTIPLIERS["expert"]["shower"] +
num_typical * USER_MULTIPLIERS["typical"]["shower"] +
num_glamper * USER_MULTIPLIERS["glamper"]["shower"]
)
eff_sink_mult = (
num_expert * USER_MULTIPLIERS["expert"]["sink"] +
num_typical * USER_MULTIPLIERS["typical"]["sink"] +
num_glamper * USER_MULTIPLIERS["glamper"]["sink"]
)
# Toilet mult = 1 for all types β†’ eff_toilet = total adults (display only)
eff_toilet_mult = num_expert + num_typical + num_glamper
# ── Daily Fresh Water Per Activity ───────────────────────────────────────
# Shower: flow Γ— duration Γ— frequency Γ— eff_shower_mult Γ— climate
# (eff_shower_mult already accounts for all adults β€” no Γ— num_adults)
shower_daily = (
FLOW_RATES["shower"] *
USAGE_PATTERNS["shower"]["duration"] *
USAGE_PATTERNS["shower"]["frequency"] *
eff_shower_mult *
climate_mult
)
# Kitchen Sink: same pattern
kitchen_sink_daily = (
FLOW_RATES["kitchen_sink"] *
USAGE_PATTERNS["kitchen_sink"]["duration"] *
USAGE_PATTERNS["kitchen_sink"]["frequency"] *
eff_sink_mult *
climate_mult
)
# Bathroom Sink: same pattern
bathroom_sink_daily = (
FLOW_RATES["bathroom_sink"] *
USAGE_PATTERNS["bathroom_sink"]["duration"] *
USAGE_PATTERNS["bathroom_sink"]["frequency"] *
eff_sink_mult *
climate_mult
)
# Toilet: base per-person usage only (1.8 gal Γ— 6 flushes Γ— 1 person base)
# Excel shows 10.8 regardless of group size in activity table
toilet_daily = (
FLOW_RATES["toilet"] *
USAGE_PATTERNS["toilet"]["frequency"] *
1 # base single-person; eff_toilet is display only
)
# Drinking: uses core num_adults (e.g., 2) not user-type total
drinking_adults_daily = DRINKING_WATER["adult"] * num_adults
drinking_children_daily = DRINKING_WATER["child"] * num_children
total_drinking_daily = drinking_adults_daily + drinking_children_daily
# ── Totals ───────────────────────────────────────────────────────────────
total_fresh_used_per_day = (
shower_daily + kitchen_sink_daily + bathroom_sink_daily +
toilet_daily + total_drinking_daily
)
total_grey_added_per_day = shower_daily + kitchen_sink_daily + bathroom_sink_daily
total_black_added_per_day = toilet_daily
# ── Tank Levels ──────────────────────────────────────────────────────────
fresh_cap = requirements.get("fresh_cap", 0)
grey_cap = requirements.get("grey_cap", 0)
black_cap = requirements.get("black_cap", 0)
fresh_level = requirements.get("fresh_level", 0)
grey_level = requirements.get("grey_level", 0)
black_level = requirements.get("black_level", 0)
# ── Survival Days ────────────────────────────────────────────────────────
# Fresh: runs DOWN β†’ days until empty
# Grey: fills UP β†’ days until full
# Black: fills UP β†’ days until full
days_fresh = (fresh_level / total_fresh_used_per_day
if total_fresh_used_per_day > 0 and fresh_level > 0
else 0.0)
days_grey = ((grey_cap - grey_level) / total_grey_added_per_day
if total_grey_added_per_day > 0
else float('inf'))
days_black = ((black_cap - black_level) / total_black_added_per_day
if total_black_added_per_day > 0
else float('inf'))
overall_survival = min(days_fresh, days_grey, days_black)
# Limiting factor
tank_map = {days_fresh: "Fresh", days_grey: "Grey", days_black: "Black"}
limiting_tank = tank_map[min(days_fresh, days_grey, days_black)]
return {
"daily_usage": {
"fresh": round(total_fresh_used_per_day, 2),
"grey": round(total_grey_added_per_day, 2),
"black": round(total_black_added_per_day, 2),
"drinking": round(total_drinking_daily, 2),
"shower": round(shower_daily, 2),
"kitchen_sink": round(kitchen_sink_daily, 2),
"bathroom_sink": round(bathroom_sink_daily, 2),
"toilet": round(toilet_daily, 2),
},
"survival_days": {
"fresh": round(days_fresh, 4),
"grey": round(days_grey, 4),
"black": round(days_black, 4),
"overall": round(overall_survival, 4),
"limiting_tank": limiting_tank,
},
"effective_multipliers": {
"shower": round(eff_shower_mult, 3),
"sink": round(eff_sink_mult, 3),
"toilet": eff_toilet_mult,
},
"tanks": {
"fresh": {"cap": fresh_cap, "level": fresh_level},
"grey": {"cap": grey_cap, "level": grey_level},
"black": {"cap": black_cap, "level": black_level}
}
}