P6: convert monster to BaseDomain + BaseNodeAdapter + concern split
Refactor of monster to use the platform infrastructure (BaseDomain, BaseNodeAdapter, ChildRouter, commandRegistry, statusBadge). Extracts concerns into focused modules per .claude/refactor/MODULE_SPLIT.md generic template. Tests stay green; CONTRACT.md generated; legacy aliases preserved. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
58
src/rain/rainAggregator.js
Normal file
58
src/rain/rainAggregator.js
Normal file
@@ -0,0 +1,58 @@
|
||||
'use strict';
|
||||
|
||||
// Rain-data aggregator — sums per-location hourly precipitation, weighted
|
||||
// by per-hour probability, and stores both the raw and probability-weighted
|
||||
// values keyed by timestamp. sumRain/avgRain feed parameters.getRainIndex
|
||||
// which scales the predicted flow rate between nominalFlowMin and flowMax.
|
||||
|
||||
class RainAggregator {
|
||||
constructor({ logger } = {}) {
|
||||
this.logger = logger;
|
||||
this.aggregatedOutput = {};
|
||||
this.sumRain = 0;
|
||||
this.avgRain = 0;
|
||||
}
|
||||
|
||||
// Returns the aggregated per-location object so callers can chain.
|
||||
// Mutates this.aggregatedOutput / sumRain / avgRain in place.
|
||||
update(value) {
|
||||
if (!value) return this.aggregatedOutput;
|
||||
|
||||
const totalRaw = {};
|
||||
const totalProb = {};
|
||||
let numberOfLocations = 0;
|
||||
|
||||
Object.entries(value).forEach(([locationKey, location]) => {
|
||||
numberOfLocations++;
|
||||
const slot = (this.aggregatedOutput[locationKey] = {
|
||||
tag: { latitude: location.latitude, longitude: location.longitude },
|
||||
precipationRaw: {},
|
||||
precipationProb: {},
|
||||
});
|
||||
|
||||
Object.entries(location.hourly.time).forEach(([key, time]) => {
|
||||
const currTimestamp = new Date(time).getTime();
|
||||
let probability = 100;
|
||||
if (typeof location.hourly.precipitation_probability !== 'undefined') {
|
||||
probability = location.hourly.precipitation_probability[key];
|
||||
}
|
||||
if (probability > 0) probability /= 100;
|
||||
|
||||
if (totalRaw[currTimestamp] === undefined) totalRaw[currTimestamp] = 0;
|
||||
if (totalProb[currTimestamp] === undefined) totalProb[currTimestamp] = 0;
|
||||
|
||||
totalRaw[currTimestamp] += location.hourly.precipitation[key];
|
||||
totalProb[currTimestamp] += location.hourly.precipitation[key] * probability;
|
||||
|
||||
slot.precipationRaw[key] = { val: location.hourly.precipitation[key], time: currTimestamp };
|
||||
slot.precipationProb[key] = { val: probability, time: currTimestamp };
|
||||
});
|
||||
});
|
||||
|
||||
this.sumRain = Object.values(totalProb).reduce((s, v) => s + v, 0);
|
||||
this.avgRain = numberOfLocations > 0 ? this.sumRain / numberOfLocations : 0;
|
||||
return this.aggregatedOutput;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RainAggregator;
|
||||
Reference in New Issue
Block a user