Coverage for backend/django/Economics/costing/operating/resource_classification.py: 91%
43 statements
« prev ^ index » next coverage.py v7.10.7, created at 2026-07-22 05:22 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2026-07-22 05:22 +0000
1"""High-level resource classifications for persisted operating result lines."""
3from __future__ import annotations
5from Economics.costing.operating.line_calculation import AnnualBasisQuantity
6from Economics.costing.models import OperatingCostLine
7from Economics.costing.operating.resource_basis import (
8 AnnualResourceQuantity,
9 RESOURCE_CATEGORY_ANNUAL_COOLING_DUTY,
10 RESOURCE_CATEGORY_ANNUAL_HEATING_DUTY,
11 annual_resource_quantity,
12 steam_fuel_energy_from_default_rate,
13)
14from Economics.shared.choices import DefaultRateType
16RESOURCE_CLASSIFICATION_ELECTRICITY = "electricity"
17RESOURCE_CLASSIFICATION_NATURAL_GAS = "natural_gas"
18RESOURCE_CLASSIFICATION_STEAM_ELECTRICITY = "steam_electricity"
19RESOURCE_CLASSIFICATION_STEAM_NATURAL_GAS = "steam_natural_gas"
20RESOURCE_CLASSIFICATION_HEATING_DUTY = "heating_duty"
21RESOURCE_CLASSIFICATION_COOLING_DUTY = "cooling_duty"
22RESOURCE_CLASSIFICATION_OTHER = "other"
25def operating_resource_classification(
26 *,
27 line: OperatingCostLine,
28 resource_category: str,
29) -> str:
30 """Classify an operating line for high-level resource metrics."""
31 if line.rate_type == DefaultRateType.ELECTRICITY:
32 return RESOURCE_CLASSIFICATION_ELECTRICITY
33 if line.rate_type == DefaultRateType.NATURAL_GAS:
34 return RESOURCE_CLASSIFICATION_NATURAL_GAS
35 if line.rate_type == DefaultRateType.STEAM:
36 return _steam_resource_classification(line)
37 if resource_category == RESOURCE_CATEGORY_ANNUAL_HEATING_DUTY:
38 return RESOURCE_CLASSIFICATION_HEATING_DUTY
39 if resource_category == RESOURCE_CATEGORY_ANNUAL_COOLING_DUTY:
40 return RESOURCE_CLASSIFICATION_COOLING_DUTY
41 return RESOURCE_CLASSIFICATION_OTHER
44def operating_resource_metric_quantity(
45 *,
46 line: OperatingCostLine,
47 classification: str,
48 annual_basis: AnnualBasisQuantity | None,
49) -> AnnualResourceQuantity | None:
50 """Snapshot the annual resource quantity consumed by high-level metrics."""
51 if annual_basis is None: 51 ↛ 52line 51 didn't jump to line 52 because the condition on line 51 was never true
52 return None
53 if classification in {
54 RESOURCE_CLASSIFICATION_ELECTRICITY,
55 RESOURCE_CLASSIFICATION_NATURAL_GAS,
56 RESOURCE_CLASSIFICATION_HEATING_DUTY,
57 RESOURCE_CLASSIFICATION_COOLING_DUTY,
58 RESOURCE_CLASSIFICATION_OTHER,
59 }:
60 return annual_resource_quantity(
61 annual_basis_quantity=annual_basis.quantity,
62 annual_basis_unit=annual_basis.unit,
63 )
64 if classification in { 64 ↛ 77line 64 didn't jump to line 77 because the condition on line 64 was always true
65 RESOURCE_CLASSIFICATION_STEAM_ELECTRICITY,
66 RESOURCE_CLASSIFICATION_STEAM_NATURAL_GAS,
67 }:
68 fuel_energy = steam_fuel_energy_from_default_rate(
69 annual_basis_quantity=annual_basis.quantity,
70 annual_basis_unit=annual_basis.unit,
71 source_default_rate=line.source_default_rate,
72 target_unit="GJ/year",
73 )
74 if fuel_energy is None: 74 ↛ 75line 74 didn't jump to line 75 because the condition on line 74 was never true
75 return None
76 return AnnualResourceQuantity(quantity=fuel_energy, unit="GJ/year")
77 return None
80def _steam_resource_classification(line: OperatingCostLine) -> str:
81 source_default_rate = line.source_default_rate
82 source_key = source_default_rate.key if source_default_rate is not None else ""
83 if source_key.startswith("steam_electric_"):
84 return RESOURCE_CLASSIFICATION_STEAM_ELECTRICITY
85 if source_key.startswith("steam_natural_gas_"):
86 return RESOURCE_CLASSIFICATION_STEAM_NATURAL_GAS
87 return RESOURCE_CLASSIFICATION_OTHER