mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-04-25 17:14:57 +02:00
fix(climate): broaden natural event filter to accept EONET sources (#2718)
* fix(climate): broaden natural event filter to accept EONET sources The isClimateNaturalEvent filter only accepted events with sourceName "NASA FIRMS" or "GDACS", but natural:events:v1 has EONET events with source IDs (e.g. EONET_2931). Result: 23 raw events, 0 matched. Fix: accept EONET IDs and any event with a sourceName/URL for climate categories (floods, wildfires, volcanoes, drought). Severe storms remain GDACS-only. * fix(review): add volcano/drought type mapping, remove source whitelist guard P1: mapNaturalType had no cases for volcanoes/drought, returning '' which caused mapNaturalEvent to discard them. P1: mapNaturalEvent guarded source !== 'GDACS' && source !== 'NASA FIRMS', dropping all EONET/OTHER events even after isClimateNaturalEvent passed them. Changed to !source (only reject truly unknown sources). P2: Added full pipeline test for EONET volcano, drought, and flood events. Moved NHC rejection test to isClimateNaturalEvent (correct filter layer).
This commit is contained in:
@@ -99,15 +99,19 @@ function getNaturalSourceMeta(event) {
|
||||
const id = String(event?.id || '');
|
||||
if (name === 'nasa firms' || name.startsWith('firms') || url.includes('firms.modaps.')) return { source: 'NASA FIRMS' };
|
||||
if (name === 'gdacs' || name.startsWith('gdacs') || url.includes('gdacs.org') || id.startsWith('gdacs-')) return { source: 'GDACS' };
|
||||
if (url.includes('eonet.') || id.startsWith('EONET_') || name.startsWith('eonet')) return { source: 'EONET' };
|
||||
if (name || url) return { source: 'OTHER' };
|
||||
return null;
|
||||
}
|
||||
|
||||
const CLIMATE_CATEGORIES = new Set(['floods', 'wildfires', 'volcanoes', 'drought']);
|
||||
|
||||
function isClimateNaturalEvent(event) {
|
||||
if (!event || typeof event !== 'object') return false;
|
||||
const sourceMeta = getNaturalSourceMeta(event);
|
||||
if (!sourceMeta) return false;
|
||||
|
||||
if (event.category === 'floods' || event.category === 'wildfires') return true;
|
||||
if (CLIMATE_CATEGORIES.has(event.category)) return true;
|
||||
if (event.category !== 'severeStorms') return false;
|
||||
if (sourceMeta.source !== 'GDACS') return false;
|
||||
|
||||
@@ -120,6 +124,8 @@ function mapNaturalType(event) {
|
||||
if (event.category === 'floods') return 'flood';
|
||||
if (event.category === 'wildfires') return 'wildfire';
|
||||
if (event.category === 'severeStorms') return 'cyclone';
|
||||
if (event.category === 'volcanoes') return 'volcano';
|
||||
if (event.category === 'drought') return 'drought';
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -333,7 +339,7 @@ function mapNaturalEvent(event) {
|
||||
if (!type) return null;
|
||||
|
||||
const source = mapNaturalSource(event);
|
||||
if (source !== 'GDACS' && source !== 'NASA FIRMS') return null;
|
||||
if (!source) return null;
|
||||
const severity = mapNaturalSeverity(event, source);
|
||||
const status = mapNaturalStatus(event, severity);
|
||||
const lat = Number(event.lat);
|
||||
|
||||
@@ -38,23 +38,13 @@ describe('seed-climate-disasters helpers', () => {
|
||||
assert.equal(getReliefWebAppname(), null);
|
||||
});
|
||||
|
||||
it('only reuses GDACS or NASA FIRMS items from natural:events:v1', () => {
|
||||
assert.equal(
|
||||
isClimateNaturalEvent({ category: 'floods', sourceName: 'GDACS', id: 'gdacs-FL-123' }),
|
||||
true,
|
||||
);
|
||||
assert.equal(
|
||||
isClimateNaturalEvent({ category: 'wildfires', sourceName: 'NASA FIRMS', id: 'EONET_1' }),
|
||||
true,
|
||||
);
|
||||
assert.equal(
|
||||
isClimateNaturalEvent({ category: 'severeStorms', sourceName: 'NHC', stormName: 'Alfred', id: 'nhc-AL01-1' }),
|
||||
false,
|
||||
);
|
||||
assert.equal(
|
||||
isClimateNaturalEvent({ category: 'wildfires', sourceName: 'Volcanic Ash Advisory', id: 'EONET_2' }),
|
||||
false,
|
||||
);
|
||||
it('accepts climate events from known sources and rejects unrecognized ones', () => {
|
||||
assert.equal(isClimateNaturalEvent({ category: 'floods', sourceName: 'GDACS', id: 'gdacs-FL-123' }), true);
|
||||
assert.equal(isClimateNaturalEvent({ category: 'wildfires', sourceName: 'NASA FIRMS', id: 'EONET_1' }), true);
|
||||
assert.equal(isClimateNaturalEvent({ category: 'wildfires', sourceName: 'Volcanic Ash Advisory', id: 'EONET_2' }), true);
|
||||
assert.equal(isClimateNaturalEvent({ category: 'volcanoes', sourceName: '', id: 'EONET_3' }), true);
|
||||
assert.equal(isClimateNaturalEvent({ category: 'severeStorms', sourceName: 'NHC', stormName: 'Alfred', id: 'nhc-AL01-1' }), false);
|
||||
assert.equal(isClimateNaturalEvent({ category: 'floods', sourceName: '', id: '' }), false);
|
||||
});
|
||||
|
||||
it('preserves supported natural-event provenance and rejects unsupported rows', () => {
|
||||
@@ -89,21 +79,57 @@ describe('seed-climate-disasters helpers', () => {
|
||||
assert.equal(gdacsEvent.source, 'GDACS');
|
||||
assert.equal(gdacsEvent.severity, 'red');
|
||||
|
||||
// NHC severe storms are filtered by isClimateNaturalEvent (GDACS-only),
|
||||
// not by mapNaturalEvent. mapNaturalEvent accepts any known source.
|
||||
assert.equal(
|
||||
mapNaturalEvent({
|
||||
id: 'nhc-AL01-1',
|
||||
category: 'severeStorms',
|
||||
title: 'Tropical Storm Alfred',
|
||||
sourceName: 'NHC',
|
||||
sourceUrl: 'https://www.nhc.noaa.gov/',
|
||||
date: 1_700_000_000_000,
|
||||
lat: 20,
|
||||
lon: -70,
|
||||
}),
|
||||
null,
|
||||
isClimateNaturalEvent({ category: 'severeStorms', sourceName: 'NHC', stormName: 'Alfred', id: 'nhc-AL01-1' }),
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
it('maps EONET-sourced volcano and drought events through the full pipeline', () => {
|
||||
const volcanoEvent = mapNaturalEvent({
|
||||
id: 'EONET_5001',
|
||||
category: 'volcanoes',
|
||||
title: 'Etna eruption',
|
||||
sourceName: 'SIVolcano',
|
||||
sourceUrl: 'https://volcano.si.edu/',
|
||||
date: 1_700_000_000_000,
|
||||
lat: 37.75,
|
||||
lon: 14.99,
|
||||
});
|
||||
assert.ok(volcanoEvent, 'EONET volcano should not be dropped');
|
||||
assert.equal(volcanoEvent.type, 'volcano');
|
||||
assert.equal(volcanoEvent.source, 'EONET');
|
||||
|
||||
const droughtEvent = mapNaturalEvent({
|
||||
id: 'EONET_5002',
|
||||
category: 'drought',
|
||||
title: 'East Africa drought',
|
||||
sourceName: 'FEWS NET',
|
||||
sourceUrl: 'https://fews.net/',
|
||||
date: 1_700_000_000_000,
|
||||
lat: 1.0,
|
||||
lon: 38.0,
|
||||
});
|
||||
assert.ok(droughtEvent, 'EONET drought should not be dropped');
|
||||
assert.equal(droughtEvent.type, 'drought');
|
||||
|
||||
const eonetFlood = mapNaturalEvent({
|
||||
id: 'EONET_5003',
|
||||
category: 'floods',
|
||||
title: 'Flooding in Bangladesh',
|
||||
sourceName: '',
|
||||
sourceUrl: 'https://eonet.gsfc.nasa.gov/',
|
||||
date: 1_700_000_000_000,
|
||||
lat: 23.8,
|
||||
lon: 90.4,
|
||||
});
|
||||
assert.ok(eonetFlood, 'EONET flood should not be dropped');
|
||||
assert.equal(eonetFlood.type, 'flood');
|
||||
assert.equal(eonetFlood.source, 'EONET');
|
||||
});
|
||||
|
||||
it('derives country codes from coordinates when natural-event text lacks a country', () => {
|
||||
assert.equal(findCountryCodeByCoordinates(35.6762, 139.6503), 'JP');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user