locate adress on map and find hail risk
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* hailProbability.js — conservative historical hail-risk model (spec §6).
|
||||
*
|
||||
* IMPORTANT framing (spec §6): the output is a HISTORICAL hazard estimate for the
|
||||
* surrounding area, NOT a property-level forecast or guarantee. The model computes
|
||||
* a RANGE (confidence band), not one overconfident number, and stores every
|
||||
* assumption so the report can be defended.
|
||||
*
|
||||
* lambda (λ) = deduped hail events / years
|
||||
* P(at least one hail event over N years) = 1 - e^(-λN)
|
||||
*
|
||||
* Pure function — no I/O. Fed by /api/storm-history (existing storm module, used
|
||||
* read-only). Returns the hail_risk_snapshot shape (spec §12).
|
||||
*/
|
||||
|
||||
function clamp(n, lo, hi) { return Math.max(lo, Math.min(hi, n)); }
|
||||
function pct(n) { return Math.round(n * 100); }
|
||||
|
||||
/**
|
||||
* @param {object} input
|
||||
* eventCount {number} deduped hail events observed in the window
|
||||
* windowYears {number} historical window analyzed
|
||||
* radiusMiles {number} search radius around the property
|
||||
* geocodeConfidence {'high'|'moderate'|'low'}
|
||||
* maxHailInches {number|null}
|
||||
* lastEventDate {string|null} ISO date of most recent hail event
|
||||
* source {string} human-readable data source label
|
||||
* generatedAt {string} ISO timestamp the snapshot was frozen
|
||||
*/
|
||||
export function computeHailRisk(input) {
|
||||
const {
|
||||
eventCount = 0,
|
||||
windowYears = 5,
|
||||
radiusMiles = 20,
|
||||
geocodeConfidence = 'moderate',
|
||||
maxHailInches = null,
|
||||
lastEventDate = null,
|
||||
source = 'NOAA / IEM Local Storm Reports',
|
||||
generatedAt = new Date().toISOString(),
|
||||
} = input || {};
|
||||
|
||||
const years = Math.max(1, windowYears);
|
||||
const count = Math.max(0, eventCount);
|
||||
|
||||
// Annualized rate (events/year).
|
||||
const lambda = count / years;
|
||||
|
||||
// Poisson confidence band using event-count standard error (√count).
|
||||
const se = Math.sqrt(count);
|
||||
const lambdaLow = Math.max(0, (count - se) / years);
|
||||
const lambdaHigh = (count + se) / years;
|
||||
|
||||
const prob = (lam, n) => 1 - Math.exp(-lam * n);
|
||||
const p10Base = prob(lambda, 10);
|
||||
const p10Low = prob(lambdaLow, 10);
|
||||
const p10High = prob(lambdaHigh, 10);
|
||||
|
||||
// Confidence score (0..1): sample size + window length + geocode precision.
|
||||
const sampleScore = clamp(count / 8, 0, 1); // ~8+ events → strong
|
||||
const windowScore = clamp(years / 10, 0, 1); // 10y window → full
|
||||
const geoScore = geocodeConfidence === 'high' ? 1 : geocodeConfidence === 'moderate' ? 0.6 : 0.3;
|
||||
const confidenceValue = +(0.4 * sampleScore + 0.3 * windowScore + 0.3 * geoScore).toFixed(2);
|
||||
const confidenceLabel = confidenceValue >= 0.66 ? 'High' : confidenceValue >= 0.4 ? 'Moderate' : 'Low';
|
||||
|
||||
// Coarse exposure tier used downstream by the scoring engine (Phase 4).
|
||||
const exposureTier = p10Base >= 0.66 ? 'high' : p10Base >= 0.33 ? 'moderate' : 'low';
|
||||
|
||||
return {
|
||||
// hail_risk_snapshot fields (spec §12)
|
||||
source,
|
||||
windowYears: years,
|
||||
radiusMiles,
|
||||
eventCount: count,
|
||||
annualRate: +lambda.toFixed(3),
|
||||
maxHailInches,
|
||||
lastEventDate,
|
||||
probability10yr: { low: pct(p10Low), base: pct(p10Base), high: pct(p10High) },
|
||||
confidence: confidenceLabel,
|
||||
confidenceValue,
|
||||
exposureTier,
|
||||
generatedAt,
|
||||
|
||||
// Customer-facing wording (spec §6) — historical, never a forecast.
|
||||
wording: {
|
||||
annualRate: count === 0
|
||||
? 'No qualifying hail events were found in the available reports for this area.'
|
||||
: `This area has averaged about ${lambda.toFixed(1)} observed hail event(s) per year in the available dataset.`,
|
||||
probability: count === 0
|
||||
? 'There is not enough historical hail activity nearby to estimate a meaningful probability.'
|
||||
: `Based on historical reports, the chance of at least one hail event in the next 10 years is estimated at ${pct(p10Low)}–${pct(p10High)}%, assuming future patterns resemble the past.`,
|
||||
confidence: `Confidence: ${confidenceLabel}. This is based on county-level and nearby reports within ~${radiusMiles} miles, not a roof-specific inspection.`,
|
||||
lastUpdated: `Storm data reflects reports through ${new Date(generatedAt).toLocaleDateString()}.`,
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user