Files
WeatherTool/web/src/pages/harmonie/draw/precipitation.ts
T
2025-03-14 11:31:47 +02:00

99 lines
4.5 KiB
TypeScript

import moment from 'moment'
import { valueToColorInterpolated, valueToColorThreshold } from '../../../helpers/interpolateColors'
import { GribMessage, MeteoConversion } from '../interfaces'
import { PRECIPITATION } from './constants'
import { fetchBuffer } from '../../../helpers/fetch'
import { apiHost } from '../../../consts'
export function precipitationColors(
encodedValue: number,
{ reference, binaryScale, decimalScale}: MeteoConversion,
isInterpolated = true,
): [number, number, number, number] {
const rainMM = (reference + encodedValue * Math.pow(2, binaryScale)) * Math.pow(10, -decimalScale)
return isInterpolated
? valueToColorInterpolated(rainMM, PRECIPITATION)
: valueToColorThreshold(rainMM, PRECIPITATION)
}
export function hourPrecipitationColors(
encodedValNow: number,
convNow: MeteoConversion,
encodedValPrev: number,
convPrev: MeteoConversion,
isInterpolated = true,
): [number, number, number, number] {
const nowVal = (convNow.reference + encodedValNow * Math.pow(2, convNow.binaryScale)) * Math.pow(10, -convNow.decimalScale)
const prevVal = (convPrev.reference + encodedValPrev * Math.pow(2, convPrev.binaryScale)) * Math.pow(10, -convPrev.decimalScale)
const rainMM = nowVal - prevVal
return isInterpolated
? valueToColorInterpolated(rainMM, PRECIPITATION)
: valueToColorThreshold(rainMM, PRECIPITATION)
}
export function fetchHourPrecipitationData(
customMessage: GribMessage,
gribArr: GribMessage[],
): Promise<[GribMessage[], ArrayBuffer[], ArrayBuffer[]]> {
const totalPrecipitation = gribArr.find(g => isPrecipitation(g)
&& g.time.referenceTime === customMessage.time.referenceTime
&& g.time.forecastTime === customMessage.time.forecastTime
)
if (!totalPrecipitation) throw new Error('Not found total precipitation')
const { forecastTime } = totalPrecipitation.time
const prevForecastTime = moment(forecastTime.replace(/(\d{2})(\d{2})Z/, '$1:$2:00Z'))
.subtract(1, 'hours')
.utc()
.format("YYYY-MM-DDTHHmm")+'Z'
const prevTotalPrecipitation = gribArr.find(g => isPrecipitation(g)
&& g.time.referenceTime === customMessage.time.referenceTime
&& g.time.forecastTime === prevForecastTime
)
const section7now = totalPrecipitation.sections.find(section => section.id === 7)
const section7prev = prevTotalPrecipitation?.sections.find(section => section.id === 7)
if (!section7now) throw new Error('Didnt found binary section for total precipitation')
const nowBinaryOffset = section7now.offset + 5
const nowBinaryLength = section7now.size - 5
const nowFileName = `harmonie_${totalPrecipitation.time.referenceTime}_${totalPrecipitation.time.forecastTime}.grib`
// for oldest message there is no more -1h message
let prevPromise: Promise<ArrayBuffer> | undefined
if (prevTotalPrecipitation && section7prev) {
const prevBinaryOffset = section7prev.offset + 5
const prevBinaryLength = section7prev.size - 5
const prevFileName = `harmonie_${prevTotalPrecipitation.time.referenceTime}_${prevTotalPrecipitation.time.forecastTime}.grib`
prevPromise = fetchBuffer(`${apiHost}/api/grib/binary-chunk/${prevBinaryOffset}/${prevBinaryLength}/${prevFileName}`)
}
if (!prevPromise) prevPromise = new Promise(resolve => resolve(new Uint8Array(nowBinaryLength).buffer))
return Promise.all([
fetchBuffer(`${apiHost}/api/grib/binary-chunk/${nowBinaryOffset}/${nowBinaryLength}/${nowFileName}`),
prevPromise,
]).then(([bufferNow, bufferPrev]) => {
const messages = [customMessage, totalPrecipitation, prevTotalPrecipitation ?? totalPrecipitation]
const buffers = [bufferNow, bufferNow, bufferPrev]
return [messages, buffers, []]
})
}
export function isPrecipitation(grib: GribMessage): boolean {
return grib.meteo.discipline === 0 && grib.meteo.category === 1 && grib.meteo.product === 52
}
export function isCalculatedHourPrecipitation(grib: GribMessage): boolean {
return grib.meteo.discipline === 0 && grib.meteo.category === 1 && grib.meteo.product === 236
}
export function getFakeHourPrecipitation(totalPrecipitation: GribMessage): GribMessage {
const modifiedPrecipitation = structuredClone(totalPrecipitation)
modifiedPrecipitation.meteo = {...modifiedPrecipitation.meteo, product: 236}
modifiedPrecipitation.title = 'meteorology, moisture, hour precipitation rate'
return modifiedPrecipitation
}