mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-12 13:29:04 +00:00
A small roof derives Sub-Ladder rungs below Google's smallest config 🟪
North-drop now runs once: the selection computes the usable (north-dropped) ladder, feasibility filters it, and Sub-Ladder derivation consumes it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
5d0a7751e6
commit
fbedf4541b
1 changed files with 11 additions and 15 deletions
|
|
@ -228,25 +228,18 @@ def _resized_to(
|
|||
|
||||
|
||||
def _sub_ladder_configs(
|
||||
potential: SolarPotential, panel_cap: float
|
||||
usable: list[SolarPanelConfiguration], panel_cap: float
|
||||
) -> tuple[SolarPanelConfiguration, ...]:
|
||||
"""Sub-Ladder Configurations (ADR-0058): rungs derived BELOW Google's
|
||||
smallest offered config, for when nothing on the ladder fits under the
|
||||
caps — a small roof gets the array its caps allow instead of no PV at
|
||||
all. One rung per whole panel count from the install floor (2) up to
|
||||
``floor(panel_cap)``, derived from the smallest north-dropped config."""
|
||||
``floor(panel_cap)``, derived from the smallest of the (already
|
||||
north-dropped) ``usable`` configs."""
|
||||
rung_max: int = math.floor(panel_cap)
|
||||
if rung_max < _MIN_SUB_LADDER_PANELS:
|
||||
return ()
|
||||
smallest: Optional[SolarPanelConfiguration] = None
|
||||
for config in potential.configurations:
|
||||
dropped = _drop_north_segments(config)
|
||||
if not dropped.segments:
|
||||
continue
|
||||
if smallest is None or dropped.panels_count < smallest.panels_count:
|
||||
smallest = dropped
|
||||
if smallest is None:
|
||||
if rung_max < _MIN_SUB_LADDER_PANELS or not usable:
|
||||
return ()
|
||||
smallest: SolarPanelConfiguration = min(usable, key=lambda c: c.panels_count)
|
||||
return tuple(
|
||||
_resized_to(smallest, panels)
|
||||
for panels in range(_MIN_SUB_LADDER_PANELS, rung_max + 1)
|
||||
|
|
@ -274,16 +267,19 @@ def select_conservative_configs(
|
|||
)
|
||||
if roof_cap is not None:
|
||||
panel_cap = min(panel_cap, roof_cap)
|
||||
feasible: list[SolarPanelConfiguration] = [
|
||||
usable: list[SolarPanelConfiguration] = [
|
||||
trimmed
|
||||
for config in potential.configurations
|
||||
for trimmed in (_drop_north_segments(config),)
|
||||
if trimmed.segments and trimmed.panels_count <= panel_cap
|
||||
if trimmed.segments
|
||||
]
|
||||
feasible: list[SolarPanelConfiguration] = [
|
||||
config for config in usable if config.panels_count <= panel_cap
|
||||
]
|
||||
if not feasible:
|
||||
# Nothing on Google's ladder fits under the caps — a small roof, not
|
||||
# an unusable one. Derive Sub-Ladder Configurations (ADR-0058).
|
||||
return _sub_ladder_configs(potential, panel_cap)
|
||||
return _sub_ladder_configs(usable, panel_cap)
|
||||
# Collapse rungs that trimmed to the same usable size (north-drop can make
|
||||
# distinct original rungs coincide), keeping the higher-generation layout —
|
||||
# the Optimiser's dial is panel count (≈ kWp ≈ cost), so duplicates of the
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue