mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-12 13:29:04 +00:00
feat(modelling): ASHP reuse case prices flush + half distribution
Slice 3 of ADR-0025 costing. When the dwelling has a reusable wet system, _distribution charges a power-flush (168) plus _REUSE_DISTRIBUTION_FRACTION (0.5) of the full radiator band -- a documented stand-in for partial radiator upsizing at ASHP flow temps, the headline uncertainty in the model. Without a wet system the full new distribution is priced. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
cf7c2e017d
commit
22612a19eb
2 changed files with 34 additions and 1 deletions
|
|
@ -63,6 +63,13 @@ _DISTRIBUTION_BY_RADIATORS: dict[int, float] = {
|
||||||
}
|
}
|
||||||
_MIN_RADIATORS = 4
|
_MIN_RADIATORS = 4
|
||||||
_MAX_RADIATORS = 12
|
_MAX_RADIATORS = 12
|
||||||
|
# Power-flush + inhibitor when reusing an existing wet system (ECOHT67).
|
||||||
|
_DISTRIBUTION_FLUSH = 168.0
|
||||||
|
# Fraction of a full new distribution charged when reusing an existing wet
|
||||||
|
# system — a stand-in for partial radiator upsizing at low ASHP flow temps.
|
||||||
|
# The headline uncertainty in the model; recalibrate against real reuse-job
|
||||||
|
# costs / survey data (ADR-0025).
|
||||||
|
_REUSE_DISTRIBUTION_FRACTION = 0.5
|
||||||
|
|
||||||
|
|
||||||
class AshpExistingSystem(Enum):
|
class AshpExistingSystem(Enum):
|
||||||
|
|
@ -133,4 +140,9 @@ class Products:
|
||||||
|
|
||||||
def _distribution(self, inputs: AshpCostInputs) -> float:
|
def _distribution(self, inputs: AshpCostInputs) -> float:
|
||||||
radiators: int = max(_MIN_RADIATORS, min(_MAX_RADIATORS, inputs.radiator_count))
|
radiators: int = max(_MIN_RADIATORS, min(_MAX_RADIATORS, inputs.radiator_count))
|
||||||
return _DISTRIBUTION_BY_RADIATORS[radiators]
|
full: float = _DISTRIBUTION_BY_RADIATORS[radiators]
|
||||||
|
# An existing wet system is reused, not rebuilt: a flush plus a fraction
|
||||||
|
# of the full distribution to cover partial radiator upsizing.
|
||||||
|
if inputs.has_reusable_wet_system:
|
||||||
|
return _DISTRIBUTION_FLUSH + _REUSE_DISTRIBUTION_FRACTION * full
|
||||||
|
return full
|
||||||
|
|
|
||||||
|
|
@ -63,3 +63,24 @@ def test_decommission_cost_varies_by_existing_system() -> None:
|
||||||
assert abs(products.ashp_bundle_cost(_large_no_reuse(AshpExistingSystem.OIL)).total - (common + 720.0)) <= 1e-9
|
assert abs(products.ashp_bundle_cost(_large_no_reuse(AshpExistingSystem.OIL)).total - (common + 720.0)) <= 1e-9
|
||||||
assert abs(products.ashp_bundle_cost(_large_no_reuse(AshpExistingSystem.LPG)).total - (common + 960.0)) <= 1e-9
|
assert abs(products.ashp_bundle_cost(_large_no_reuse(AshpExistingSystem.LPG)).total - (common + 960.0)) <= 1e-9
|
||||||
assert abs(products.ashp_bundle_cost(_large_no_reuse(AshpExistingSystem.ELECTRIC_STORAGE)).total - (common + 840.0)) <= 1e-9
|
assert abs(products.ashp_bundle_cost(_large_no_reuse(AshpExistingSystem.ELECTRIC_STORAGE)).total - (common + 840.0)) <= 1e-9
|
||||||
|
|
||||||
|
|
||||||
|
def test_reusable_wet_system_prices_a_flush_plus_half_the_distribution() -> None:
|
||||||
|
# Arrange — a gas dwelling whose wet system is reusable: instead of a full
|
||||||
|
# new distribution, the ASHP pays a power-flush plus half the radiator band
|
||||||
|
# (a documented estimate for partial radiator upsizing — ADR-0025).
|
||||||
|
products = Products()
|
||||||
|
inputs = AshpCostInputs(
|
||||||
|
existing_system=AshpExistingSystem.GAS,
|
||||||
|
is_small_property=False,
|
||||||
|
design_heat_loss_kw=8.0,
|
||||||
|
radiator_count=8,
|
||||||
|
has_reusable_wet_system=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
cost: Cost = products.ashp_bundle_cost(inputs)
|
||||||
|
|
||||||
|
# Assert — decommission 720 + pump 9840 + cylinder 2382.60 + distribution
|
||||||
|
# (flush 168 + 0.5 x 4152 = 2244) = 15186.60.
|
||||||
|
assert abs(cost.total - 15186.60) <= 1e-9
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue