Skip to content

fix(weather): physically correct EPW radiation and sky fields (F1) - #212

Merged
michaldengusiak merged 5 commits into
sow/2026-Q4from
fix/epw-weather-radiation-q4
Oct 19, 2026
Merged

michaldengusiak merged 5 commits into
sow/2026-Q4from
fix/epw-weather-radiation-q4

Conversation

@michaldengusiak

@michaldengusiak michaldengusiak commented Oct 19, 2026 •

Copy link
Copy Markdown

Fixes finding F1 from SAM_UI PR HoareLea#239 (SAM-BIM/SAM_UI#239). SAM.Weather.Query.DataString, which Convert.ToEPW and SAM_OpenStudio EmbeddedAnnualWeatherPath use, wrote global horizontal = 0, horizontal IR = 0, and the horizontal beam (GHI − DHI) into the direct-normal field. It also wrote sky cover as a 0–1 fraction where EPW expects tenths, and missing radiation as 0.

Record: documentation/EPW-Weather-Radiation-F1-PR.md. Evidence: documentation/evidence/epw-weather-f1/. Tested content SHA: a2cb16cf. Production code is unchanged since b721c5f4; a2cb16cf adds one review test and evidence, and a55c39b8 and 8de08069 change only the record.

What the writer now does

EPW field Value
GHI (14) stated value; else direct + diffuse; else 9999
DNI (15) horizontal beam ÷ hour-mean cos zenith (hour ending, local standard time, 60 sub-steps), bounded by the pure-Rayleigh-atmosphere beam (binds only at grazing sun); 9999 without a location or beam
DHI (16) stated value; else 9999
ETR horizontal / normal (11/12) astronomical values
Horizontal IR (13) 9999, so EnergyPlus derives it; SAM holds no IR
Dew point (8) stated value; else derived from DBT and RH
Total / opaque sky cover (23/24) SAM cloud cover × 10

The public API is preserved: all existing DataString overloads keep their signatures, and location-aware overloads are added. The SAM importer and the explicit-EPW route are unchanged. TAS/OpenStudio ventilation, comparison tolerances and HVAC work are not touched.

Independent verification

  • 5 committed TMYx reference EPWs (Budapest, Fairbanks, Sydney, Singapore, Phoenix) with an independent solar position (Michalsky 1988) in the tests.

  • Self-consistent datasets (Sydney, Singapore, Fairbanks): annual DNI within +0.3 %, sun-up median error ≤ 0.3 % (P90 ≤ 0.6 %), beam on N/E/S/W facades within 0.4 %.

  • Budapest and Phoenix are internally inconsistent. Their own DNI closes with their own GHI − DHI only when the geometry is taken about 30 minutes earlier (closure error 9 % on the EPW time base). The tests measure this and require energy closure, which holds within −0.4 %. This is a source-data limitation, documented in the record.

  • Fail-first: against the original writer, 34 of 38 new tests fail.

  • Box-model check (EnergyPlus 25.2, the e0 in.idf from PR bug ExtendExternalPanels HoareLea/SAM#239). The control with the old export reproduces PR bug ExtendExternalPanels HoareLea/SAM#239's 2810.0 / 3832.5 kWh exactly. Corrected embedded weather vs explicit EPW:

    Before the fix After the fix
    Transmitted solar −28.5 % +3.6 %
    Heating +29 % −4.2 %
    Sensible cooling −17 % +4.1 %

    Engine agreement between TAS and EnergyPlus is not an acceptance criterion.

Checks (local)

  • dotnet test SAM/SAM.Tests/SAM.Tests.csproj: 3726/3726 in both Release and Debug at a2cb16cf (3721/3721 at b721c5f4).
  • MSBuild SAM.sln /t:Rebuild /p:Configuration=Release: 0 errors. It ran sandboxed, with APPDATA/USERPROFILE redirected.
  • git diff --check: clean.
  • GitHub checks: green at 90822fac and at a55c39b8; final head 8de08069 (docs only).

Risks and open points

  • Embedded-weather results change. Earlier embedded runs, including PR bug ExtendExternalPanels HoareLea/SAM#239 B1a, are not comparable with new ones.
  • The TAS embedded path was not re-run; that needs a licence.
  • Opaque sky cover reuses the single SAM cloud amount. This is a stated proxy.
  • Out of scope and unchanged: culture-dependent formatting of DBT/RH/wind/pressure; missing DBT/RH/wind still written as 0; the importer does not recognise EPW missing codes; leap-year day labelling.

Final review (2026-10-19): no blocking issues

  • Rayleigh bound activation (test RayleighBound_BindsOnlyAtGrazingSun_AndRemovesLittleEnergy, evidence rayleigh-bound-activation.txt): it binds in 0 hours for Sydney, Singapore and Fairbanks (0.00 % change in DNI and on every facade). It binds only for the half-hour-inconsistent files: Budapest in 4.0 % of beam hours (sun below ~4.7°), Phoenix in 6.0 % (below ~21°). There the stated beam implies impossible DNI, up to 2450 W/m² against a Rayleigh limit of ~1080 W/m². It removes 0.18 % and 0.38 % of the stated horizontal beam; east facades are unchanged, and the west facade beam goes down by 16 % and 6 %.
  • Opaque-sky stand-in: documented in code, record and this description. Isolated in EnergyPlus: swapping in the real opaque cover changes IR by +2.6 W/m² and loads by less than 1 %; EnergyPlus’s Clark–Allen IR against the dataset’s IR column is the larger effect (up to 1.7 %). Accepted.
  • CI and mergeability: build, test and spdx green at 90822fac; mergeable and CLEAN against an unchanged base 618db819.

Recommended for owner approval and merge. Not merged automatically.

🤖 Generated with Claude Code

michaldengusiak and others added 2 commits October 19, 2026 09:38
SAM.Weather.Query.DataString wrote global horizontal and horizontal
infrared as 0 and put the horizontal beam (global - diffuse) into the
direct-normal field, so every embedded-weather export (Convert.ToEPW,
OpenStudio EmbeddedAnnualWeatherPath) carried wrong solar and sky inputs
(SAM_UI PR HoareLea#239, finding F1).

- Global horizontal: the stated value (or direct + diffuse).
- Direct normal: horizontal beam / hour-mean cos zenith on the EPW time
  base (hour ending, local standard time), NOAA/Spencer solar position
  averaged over 60 sub-steps; bounded by the pure-Rayleigh-atmosphere
  beam (Kasten-Young air mass, Kasten 1996 optical thickness), which
  only binds at grazing sun. Needs latitude, longitude and time zone;
  without them it is written as missing (9999).
- Extraterrestrial horizontal / normal: astronomical values.
- Horizontal IR: missing (9999), so EnergyPlus derives it; SAM holds no IR.
- Dew point: stated value, else derived from DBT and RH (Magnus).
- Sky cover: SAM cloud cover 0-1 written in tenths (it was written as
  0-1, losing a factor of 10 on every export/import cycle) to total and
  opaque sky cover.
- Missing radiation/sky values use the EPW missing codes, never 0.

Existing public overloads are kept; location-aware overloads are added.
Tests: 38 new (5 TMYx reference EPWs, independent Michalsky 1988
geometry, facade beam, low sun, night, hemispheres, half-hour zones,
missing data, leap year, round trip). Full SAM.Tests 3721/3721.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@michaldengusiak
michaldengusiak marked this pull request as ready for review October 19, 2026 08:57
michaldengusiak and others added 3 commits October 19, 2026 10:58
… (F1 review)

Adds RayleighBound_BindsOnlyAtGrazingSun_AndRemovesLittleEnergy over the
five reference EPWs. The writer's own hour geometry is read back from the
export (ETR horizontal / ETR normal), so "bound" counts exactly the hours
the bound changed. The bound never binds for the self-consistent datasets
(Sydney, Singapore, Fairbanks); for the half-hour-inconsistent Budapest
and Phoenix files it binds in 4.0 % and 6.0 % of beam hours and removes
0.18 % and 0.38 % of the stated horizontal beam.

Evidence: rayleigh-bound-activation.txt, and two EnergyPlus box variants
isolating the opaque-sky-cover proxy (real opaque cover; dataset IR).
Test-only and docs; no production change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…CI (PR record)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…smatch (PR record)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@michaldengusiak
michaldengusiak merged commit 5ac5703 into sow/2026-Q4 Oct 19, 2026
3 checks passed
@michaldengusiak
michaldengusiak deleted the fix/epw-weather-radiation-q4 branch October 19, 2026 09:18
michaldengusiak added a commit that referenced this pull request Oct 19, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant