3.2.3.1
Fix average to top temps
This commit is contained in:
@@ -87,22 +87,24 @@ function soilCacheKey(loc) {
|
||||
}
|
||||
|
||||
// ─── CLIMATE NORMALS (ERA5 archive) ───────────────────────────────────────
|
||||
// Open-Meteo's Historical Archive gives daily mean temps back to 1940. We pull
|
||||
// the WMO reference period (1991-2020) once per location and reduce it into a
|
||||
// 366-entry day-of-year table of "normal" daily-mean temperature, so the app
|
||||
// can show how far the forecast for a day sits above/below its seasonal norm.
|
||||
// Normals don't change, so this caches for a long time.
|
||||
// Open-Meteo's Historical Archive gives daily temps back to 1940. We pull the
|
||||
// WMO reference period (1991-2020) once per location and reduce it into two
|
||||
// 366-entry day-of-year tables of "normal" daily HIGH and daily MEAN temperature,
|
||||
// so the app can show how far a day's forecast high AND daily average each sit
|
||||
// above/below their seasonal norm. Normals don't change, so this caches long.
|
||||
|
||||
function buildClimateUrl(loc) {
|
||||
return `https://archive-api.open-meteo.com/v1/archive` +
|
||||
`?latitude=${loc.lat}&longitude=${loc.lon}` +
|
||||
`&start_date=1991-01-01&end_date=2020-12-31` +
|
||||
`&daily=temperature_2m_mean&timezone=auto`;
|
||||
`&daily=temperature_2m_max,temperature_2m_mean&timezone=auto`;
|
||||
}
|
||||
|
||||
// Coarser key (~2 dp ≈ 1 km) so nearby lookups share one cached climatology.
|
||||
// The `_hm` marks the { high, mean } shape so it won't collide with any
|
||||
// earlier single-array cache from a previous build.
|
||||
function climateCacheKey(loc) {
|
||||
return `sunscope_normals_${loc.lat.toFixed(2)}_${loc.lon.toFixed(2)}`;
|
||||
return `sunscope_normals_hm_${loc.lat.toFixed(2)}_${loc.lon.toFixed(2)}`;
|
||||
}
|
||||
|
||||
// Cumulative days before each month on a leap-year calendar, so every date
|
||||
@@ -114,15 +116,13 @@ function doyFromKey(key) {
|
||||
return LEAP_CUM[m - 1] + (d - 1); // 0..365
|
||||
}
|
||||
|
||||
// Reduce raw daily means into a smoothed 366-entry day-of-year normals table.
|
||||
function reduceNormals(daily) {
|
||||
const times = daily?.time;
|
||||
const means = daily?.temperature_2m_mean;
|
||||
if (!times || !means) return null;
|
||||
// Reduce one raw daily series into a smoothed 366-entry day-of-year table.
|
||||
function reduceSeries(times, values) {
|
||||
if (!times || !values) return null;
|
||||
const sums = new Array(366).fill(0);
|
||||
const counts = new Array(366).fill(0);
|
||||
for (let i = 0; i < times.length; i++) {
|
||||
const v = means[i];
|
||||
const v = values[i];
|
||||
if (v == null) continue;
|
||||
const doy = doyFromKey(times[i]);
|
||||
sums[doy] += v;
|
||||
@@ -143,8 +143,18 @@ function reduceNormals(daily) {
|
||||
return smooth;
|
||||
}
|
||||
|
||||
// Fetches (or reads cached) climate normals for a location. Returns a
|
||||
// 366-entry array of daily-mean °C, or null on any failure (feature hides).
|
||||
// Build both the normal-high and normal-mean day-of-year tables from the
|
||||
// archive response. Returns { high, mean } or null.
|
||||
function reduceNormals(daily) {
|
||||
const times = daily?.time;
|
||||
const high = reduceSeries(times, daily?.temperature_2m_max);
|
||||
const mean = reduceSeries(times, daily?.temperature_2m_mean);
|
||||
if (!high && !mean) return null;
|
||||
return { high, mean };
|
||||
}
|
||||
|
||||
// Fetches (or reads cached) climate normals for a location. Returns
|
||||
// { high, mean } day-of-year tables (°C), or null on any failure (feature hides).
|
||||
async function fetchClimateNormals(loc) {
|
||||
const key = climateCacheKey(loc);
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user