Commit graph

4 commits

Author SHA1 Message Date
Khalim Conn-Kowlessar
3bf728ce2f Slice S0380.74: Appendix H (H7) U3.3 monthly-integrated convention closes 1.81× over-count
Root cause: SAP 10.2 has an internal unit-convention ambiguity for
(H7)m between page 75 (Equation H1 implies W/m² 24-hour-average flux)
and page 76 (verbatim "Monthly solar radiation per m² from U3.3 in
Appendix U", i.e. kWh/m²/month monthly integrated). Page 77 (H23)
formula's `× hours / 1000` term double-converts when (H7) is W/m².

The cascade's `surface_solar_flux_w_per_m2` returns the §U3.2 24h-avg
flux in W/m² (verified bit-exact vs Elmhurst worksheet line 295: SE
90° Jan region 0 = 36.7938 W/m²). The (H9) helper was using this
directly without applying the U3.3 conversion that page 76's "from
U3.3" cross-reference calls for. Elmhurst-certified software follows
the U3.3 reading.

SAP 10.2 spec p.76 line (H7): "Monthly solar radiation per m² from
U3.3 in Appendix U". Appendix U §U3.3 (p.130) defines the conversion
S_monthly = 0.024 × n_m × S(orient,p,m), where S(orient,p,m) is the
§U3.2 24-hour-average flux in W/m². Therefore:

  (H7)m_U3.3 [kWh/m²/month] = flux_U3.2 [W/m²] × hours / 1000

Option A fix (per ChatGPT-mediated research): apply the U3.3
conversion inside the (H9) helper, so (H9) is in kWh/month rather
than W. Spec p.77 (H23) formula then carries the conversion's
dimensional residue correctly without double-counting.

Diagnostic that closed the trap: back-solving poly(X_cas, Y_eff) =
ws_H24/H17 at fixed X across 24 worksheet-positive observations from
4 cert fixtures (000565 + new A/B/C at sap worksheets/Solar PV tests/)
revealed Y_eff/Y_cascade took ONLY two distinct values:
- 0.7200 (exact) for every 30-day month observation
- 0.7440 (exact) for every 31-day month observation
i.e. exactly days × 24 / 1000. No utilizability function, no missing
constant — a per-month unit-conversion factor that the polynomial
non-linearity had been masking.

Closure metrics (HEAD post-fix):
- 000565 (W-30, modest): annual Δ −0.0000 kWh (every month exact)
- A-baseline (S-30, modest): annual Δ +0.0001 kWh
- B-highY (S-30, none): annual Δ −0.0000 kWh (incl Oct 10.5905)
- C-lowY (N-60, signif): annual Δ −4.36 kWh (polynomial zero-clamp
  boundary; worksheet poly = 0.0024 → 0.41 kWh, cascade poly =
  −0.04 → 0)

47/48 month-observations pin at <1e-4 kWh.

Test baseline: 547 pass + 9 expected `test_sap_result_pin[000565-*]`
cascade-gap fails (unchanged — orchestrator still NOT integrated
into water_heating.py:943; that's the follow-on slice that closes
cert 000565's HW pin +272 → ~0).

Pyright net-zero on both touched files.

Files:
- domain/sap10_calculator/worksheet/appendix_h_solar.py: rename
  `monthly_solar_energy_available_h9_w` → `_h9_kwh_per_month`,
  add `hours_in_month` param, apply U3.3 conversion. Y23 param
  renamed accordingly. Orchestrator updated.
- domain/sap10_calculator/worksheet/tests/test_appendix_h_solar.py:
  add cert 000565 (H24)m monthly magnitude pin at abs < 1e-3 kWh;
  update H9 + Y23 unit tests for new kWh/month units.
- BRIEF_APPENDIX_H_EN_15316_RESEARCH.md: new "Closure" section with
  the days-in-month diagnostic, root cause, and lessons.
- HANDOVER_POST_4_CERT_EMPIRICAL.md: NEW — closure handover.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 18:02:35 +00:00
Khalim Conn-Kowlessar
f0ab7446b2 Slice S0380.68: Appendix H (H7)m flux helper + top-level orchestrator
Builds on S0380.66 (Appendix H pure helpers) + S0380.67 (W·h → kWh
unit fix) to assemble the spec-ordered H7 → H9 → … → H24 cascade
into a single entry point. Cert 000565's complete Appendix H input
set now flows through one call:

    h24 = solar_water_heating_input_monthly_kwh(
        collector_orientation=Orientation.W, collector_pitch_deg=30.0,
        region=0,                               # UK average per rating
        aperture_area_m2=3.0,                   # (H1)
        zero_loss_efficiency=0.8,               # (H2)
        linear_heat_loss_a1=4.0,                # (H3)
        second_order_heat_loss_a2=0.01,         # (H4)
        loop_efficiency=0.9,                    # (H5)
        incidence_angle_modifier=0.94,          # (H6)
        overshading_factor=0.8,                 # (H8) Table H2 "Modest"
        overall_heat_loss_coefficient_from_test=6.5,  # (H10) override
        dedicated_solar_storage_volume_l=53.0,  # (H12)
        combined_cylinder_total_volume_l=160.0, # (H13)
        hot_water_demand_monthly_kwh=...,       # (62)m
        wwhrs_monthly_kwh=(0,)*12,              # (63a)m
        cold_water_temperatures_monthly_c=TABLE_J1_TCOLD_FROM_MAINS_C,
        external_temperatures_monthly_c=...,    # (96)m
        solar_hot_water_only=True,
    )

New module surface:
- `monthly_collector_solar_flux_w_per_m2` — thin 12-month wrapper over
  the existing `surface_solar_flux_w_per_m2` (Appendix U §U3.2
  orientation + tilt polynomial). Cert 000565 collector: W, 30° pitch,
  Thames Valley.
- `solar_water_heating_input_monthly_kwh` — chains all line-ref
  helpers in spec order; returns (H24)m as a 12-tuple.

Tests:
- `test_monthly_collector_solar_flux_h7_returns_twelve_values_
  matching_appendix_u` — smoke test pinning Jan < May < Jun shape
  for the W-facing 30°-pitched collector.
- `test_solar_water_heating_input_monthly_kwh_returns_winter_zero_
  summer_peak_shape` — orchestrator shape pin: 12-month tuple, all
  non-negative, winter clamp to zero (Jan/Feb/Nov/Dec via Equation
  H1's negative-X dominance), monotone Mar < May, Sep < Jun.

Magnitude pin against worksheet line 415 (Σ(H24)1..12 = 281.3478)
is DEFERRED to the next slice: current orchestrator output is
~510 kWh annual (1.8× the worksheet), traced to a spec ambiguity
between the top-level Equation H1 Y formula
(Y = Px · Aap · IAM · η0 · ηloop · Im · Hm / (1000 · Dm) — excludes
overshading H8) and the line-ref (H23) formulation
(Y = [(H18) · (H6) · (H5) · (H9) · ((41) · 24)] / [1000 · (H17)],
where (H9) = (H1) · (H2) · (H7) · (H8) includes H8). Both are
present in SAP 10.2 spec page 75-76 and differ by a factor of H8
(0.8 for cert 000565). Picking the spec-correct branch requires
either a worksheet trace of one cert's (H22)/(H23) intermediates or
a confirmed errata; the next slice runs that down and pins the
magnitude.

Test suite: 279 pass + 9 expected 000565 cascade-gap fails (unchanged
— orchestrator is not yet wired into `water_heating_from_cert`).
Pyright net-zero on both touched files.

Spec source: SAP 10.2 specification (14-03-2025) Appendix H pp.74-78
+ Appendix U §U3.2 page 127.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 10:02:29 +00:00
Khalim Conn-Kowlessar
2795e2569d Slice S0380.67: Appendix H (H9) helper + fix (H23) W·h → kWh units
S0380.66 landed (H23) with an incorrect unit treatment: the spec
formula on SAP 10.2 p.76 is

    Y_HW = [(H18)m × (H6) × (H5) × (H9)m × (41)m × 24] ÷ [1000 × (H17)m]

and Appendix U (per `domain/sap10_calculator/climate/appendix_u.
horizontal_solar_irradiance_w_per_m2`) returns (H7)m as a monthly-
average flux in W/m². That makes (H9)m = (H1) × (H2) × (H7)m × (H8)
an instantaneous power in W — the `× hours × 24 / 1000` factor in
the (H23) formula is what time-integrates W·h → kWh so the Y_HW
ratio lands dimensionless against (H17)m (kWh/month).

S0380.66's (H23) elided the time integration by absorbing it into
the input parameter (a kWh/m²/month name) — that broke unit
consistency with the downstream Appendix U integration this module
will consume in the next slice.

Changes:
- New `monthly_solar_energy_available_h9_w` — pure (H9)m calculator
  taking aperture, η₀, (H7)m flux tuple, and overshading. Returns W.
- `hot_water_factor_y_monthly_h23`: parameter renamed
  `monthly_solar_energy_available_h9_w` (was `..._kwh_per_m2`); new
  `hours_in_month` parameter; formula now includes the spec's
  `× hours / 1000` time integration explicitly.

Tests:
- `test_monthly_solar_energy_available_h9_applies_spec_formula` —
  cert 000565 H1/H2/H8 with flat 100 W/m² flux → 192 W (the spec
  multiplicand 3 × 0.8 × 100 × 0.8).
- `test_hot_water_factor_y_h23_applies_w_to_kwh_time_integration` —
  unit-consistency pin: H9=1000 W, hours=744, H17=744 kWh → Y=1.0.
- `test_hot_water_factor_y_h23_clamps_lower_bound_at_zero` updated
  to the new parameter name and supplies `hours_in_month`.

Test suite: 277 pass + 9 expected 000565 cascade-gap fails. Pyright
net-zero on both touched files.

Spec source: SAP 10.2 specification (14-03-2025) Appendix H p.76.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 09:46:12 +00:00
Khalim Conn-Kowlessar
db4f1b3167 Slice S0380.66: SAP 10.2 Appendix H solar HW pure math module (HW path)
New module `domain/sap10_calculator/worksheet/appendix_h_solar.py`
implements line refs (H10), (H11), (H14)..(H16), (H17)..(H24) for the
hot-water solar contribution path. The space-heating path (H25)..(H29)
is deferred until a fixture exercises it — cert 000565 lodges solar
HW only (worksheet line 414 H29=0 across all months).

Algorithm per SAP 10.2 specification §Appendix H pages 74-78
(14-03-2025 revision). The monthly procedure follows EN 15316-4-3:2017:
the collector + cylinder + demand parameters feed dimensionless X and
Y ratios into Equation H1 with Table H3 (p.78) correlation factors:

    Q_s,w = (Ca·Y + Cb·X + Cc·Y² + Cd·X² + Ce·Y³ + Cf·X³) × (H17)m

clamped to [0, (H17)m] per spec p.76. Cert 000565 worksheet line 415
shows total Q_s,w = 281.3478 kWh/year delivered to HW from a 3 m²
flat-plate collector + 53 L dedicated solar storage in a 160 L
combined cylinder, W orientation, 30° pitch, Thames Valley region.

Helpers implemented:
- `overall_heat_loss_coefficient_h10`     — 5 + 0.5×(H1) or test-cert
- `loop_heat_loss_coefficient_h11`        — (H3) + 40·(H4) + (H10)/(H1)
- `effective_solar_volume_h14`            — separate / combined cylinder
- `reference_volume_h15`                  — 75 × (H1)
- `storage_tank_correction_coefficient_h16` — [(H15)/(H14)]^0.25
- `hot_water_demand_monthly_h17_kwh`      — (62)m − (63a)m
- `proportion_solar_to_hot_water_monthly_h18` — HW-only/SH-only/blend
- `hot_water_reference_temperature_h20_c` — 55 + 3.86·Tcold − 1.32·Te
- `hot_water_reference_temperature_difference_h21_c` — (H20) − (96)
- `hot_water_factor_x_monthly_h22`        — clamp [0, 18]
- `hot_water_factor_y_monthly_h23`        — clamp ≥ 0
- `heat_delivered_to_hot_water_monthly_h24_kwh` — Equation H1 + clamp
  [0, (H17)m]

18 unit tests cover:
- Spec-default vs test-certificate (H10)
- Cert 000565 worksheet pinned (H11) ≈ 6.5667 (line 407)
- Cert 000565 worksheet pinned (H14) = 85.1 (line 410)
- Cert 000565 worksheet pinned (H15) = 225 (line 411)
- Cert 000565 worksheet pinned (H16) ≈ 1.2752 (line 412)
- Separate-tank vs combined-cylinder branches of (H14)
- All three branches of (H18) (HW-only, SH-only, blend formula)
- (H20)/(H21) spec formulas verbatim
- (H22) zero-demand short-circuit + upper clamp at 18
- (H23) negative-input lower clamp at 0
- (H24) Equation H1 polynomial with Table H3 factors
- (H24) demand-cap clamp when Y dominates positive
- (H24) zero-floor clamp when X dominates negative

Scope EXCLUDES (deferred to follow-on slices):
- Appendix U §U3.3 monthly solar radiation lookup for the collector's
  orientation/tilt → (H7)m → (H9)m
- Solar SH path (H25-H29)
- Appendix H §H2 primary-loss reduction Table H4
- EpcPropertyData solar collector field schema additions
- Elmhurst + API extractor / mapper updates
- Cascade integration via `water_heating_from_cert.solar_monthly_kwh`

Pyright: 0 errors on both touched files. 275 pass + 9 expected 000565
cascade-gap fails on the handover test suite (unchanged from S0380.65).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 09:41:22 +00:00