Model/datatypes/epc
Khalim Conn-Kowlessar 9a091234cf Slice S0380.23: RdSAP §11.1 b) PV %-of-roof-area synthesis — closes cert 6835 -13.37 → +0.72
RdSAP 10 specification page 60 §11.1 b) (Photovoltaics): "If the kWp
(or DNC) is not known use the following: PV area is roof area for
heat loss (before amendment for any room-in-roof), times percent of
roof area covered by PVs, and if pitched roof divided by cos(35°).
If there is an extension, the roof area is adjusted by the cosine
factor only for those parts having a pitched roof. kWp is 0.12 ×
PV area. If not provided in the RdSAP data set then facing South,
pitch 30°, modest overshading."

Wire-through:
  1. `Renewables.pv_percent_roof_area: Optional[int]` — new field on
     the Elmhurst site-notes dataclass.
  2. Elmhurst extractor `_extract_renewables` parses Summary §19.0
     row "Proportion of roof area" (cert 6835: "40").
  3. Elmhurst mapper `from_elmhurst_site_notes` surfaces it through
     `epc.sap_energy_source.photovoltaic_supply.none_or_no_details
     .percent_roof_area` — mirrors the API mapper's lodgement shape.
  4. `cert_to_inputs._synthesize_pv_arrays_from_percent_roof_area`
     synthesizes a single PV array via the spec formula when
     `photovoltaic_arrays` is empty AND a `percent_roof_area > 0`
     lodgement is present. Fires inside
     `_pv_generation_kwh_per_yr`, so both rating + demand cascades
     pick it up.

Cohort-2 outcome (38 certs, Summary path):
  exact (<1e-4): 20 → 20
  ±0.07..0.5:   1 → 1
  ±0.5..1:      1 → **2**  (cert 6835 closes -13.37 → +0.72)
  ±1..5:        1 → 1
  ±5+:          2 → **1**  (-1: cert 6835 moves out of big-gap band)

Cert 6835 verified end-to-end:
  - kWp = 0.12 × 36.9 × 0.40 / cos(35°) = 2.1622
    (worksheet "Cells Peak = 2.16, Orientation = South, Elevation =
    30°, Overshading = Modest")
  - Cascade PV generation = 1493.88 kWh/yr vs worksheet 1492.33
    (<0.1% delta — kWp-rounding artefact).
  - Cascade SAP 80.92 vs worksheet 80.20 (+0.72, in the ±0.5..1 band).

The residual +0.72 likely traces to the PV-cost cascade's
used-in-dwelling / exported split rather than the synthesis — the
kWh figure is within rounding of the worksheet.

Pyright per-file: net-zero
  - cert_to_inputs.py 35 → 35
  - test_cert_to_inputs.py 13 → 13
  - mapper.py 32 → 32
  - elmhurst_site_notes.py 0 → 0
  - elmhurst_extractor.py 0 → 0

Tests: 702 → 703 pass (+1 new RdSAP §11.1 b synthesis test), 10
expected fails unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 16:28:46 +00:00
..
domain Slice S0380.23: RdSAP §11.1 b) PV %-of-roof-area synthesis — closes cert 6835 -13.37 → +0.72 2026-06-01 16:28:46 +00:00
loaders demo generated for use in address2uprn 2026-05-08 14:48:15 +00:00
schema Slice 100c: API path — surface PV arrays + gap-aware glazing lookup 2026-06-01 16:28:45 +00:00
search bolstering testing 2026-04-28 13:46:09 +00:00
surveys Slice S0380.23: RdSAP §11.1 b) PV %-of-roof-area synthesis — closes cert 6835 -13.37 → +0.72 2026-06-01 16:28:46 +00:00
__init__.py testing out rebaselining 2026-02-12 22:25:03 +00:00
construction_age_band.py testing out rebaselining 2026-02-12 22:25:03 +00:00
efficiency.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
floor.py preparing partiy class 2026-02-05 08:54:27 +00:00
fuel.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
heating_controls.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
hotwater.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
main_heating.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
property_type_built_form.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
roof.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
walls.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
windows.py testing out rebaselining 2026-02-12 22:25:03 +00:00