From f0d7def9c74b6e586c260cb62cd3491ba7c451b0 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Tue, 3 Nov 2026 20:29:44 +0400 Subject: [PATCH] Report an empty wind field from get_wind as no surface reading instead of a NaN speed --- src/tools/queries/atmosphere.js | 7 +++++++ src/tools/queries/atmosphere.test.mjs | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/tools/queries/atmosphere.js b/src/tools/queries/atmosphere.js index 9cbd8fec0..32a584225 100644 --- a/src/tools/queries/atmosphere.js +++ b/src/tools/queries/atmosphere.js @@ -201,6 +201,13 @@ export const getWind = defineTool({ point.lon, point.lat, ); + // A field without cells samples to NaN: that is no surface reading, never + // a speed or calm (the wind layer's inspection says the same). + if (!Number.isFinite(vector.u) || !Number.isFinite(vector.v)) + throw new ToolError( + 'unavailable', + `No surface wind reading at ${point.label}: the ${model.toUpperCase()} forecast has no data there right now`, + ); const speed = windSpeed(vector.u, vector.v); const from = windFrom(vector.u, vector.v); const kph = speed * 3.6; diff --git a/src/tools/queries/atmosphere.test.mjs b/src/tools/queries/atmosphere.test.mjs index 57b41b81a..8dfa38211 100644 --- a/src/tools/queries/atmosphere.test.mjs +++ b/src/tools/queries/atmosphere.test.mjs @@ -186,6 +186,25 @@ test('wind is sampled from the model grid at the location', async () => { ); }); +test('an empty wind field is no surface reading, never a NaN speed or calm', async () => { + const grid = { nx: 4, ny: 3, lo1: 0, la1: 90, dx: 90, dy: 90 }; + for (const cells of [new Float32Array(0), new Float32Array(12).fill(NaN)]) { + const catalog = composeCatalog({ + tools: coreTools, + services: { + wind: { getSnapshot: async () => ({ grid, u: cells, v: cells }) }, + }, + }); + await assert.rejects( + catalog.call('get_wind', { location: { lat: 20, lon: 10 } }), + (error) => + error.code === 'unavailable' && + /No surface wind reading at 20\.0000, 10\.0000/.test(error.message) && + !/calm|NaN|undefined/i.test(error.message), + ); + } +}); + test('a weather window that cannot cover the area falls back to the whole map', async () => { const world = { west: -180, south: -90, east: 180, north: 90 }; // 100 km around 179.8° crosses the antimeridian.