@aeroswarm/weather 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/PERFORMANCE.md +78 -0
- package/README.md +1 -0
- package/dist/grid.d.ts.map +1 -1
- package/dist/idw.d.ts +38 -0
- package/dist/idw.d.ts.map +1 -0
- package/dist/index.js +147 -69
- package/dist/store.d.ts.map +1 -1
- package/package.json +9 -5
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
3
3
|
Format: [Keep a Changelog](https://keepachangelog.com/). Versioning: see [STABILITY.md](./STABILITY.md). Entries for
|
|
4
4
|
0.1.1 to 0.4.0 were written afterwards from the git history; every one of them was released on 2026-11-02.
|
|
5
5
|
|
|
6
|
+
## Unreleased
|
|
7
|
+
|
|
8
|
+
### Changed (performance; results are the same within float rounding, checked by a test)
|
|
9
|
+
- `fieldsAt`, `blendInto`, `interpolateScalar`, `windGridFromStations`, `nudgeScalar` and `nudgeWind` are much faster:
|
|
10
|
+
distances and weights are computed once per grid cell and shared between wind, cloud and rain, with no
|
|
11
|
+
trigonometry in the inner loop. 60 stations on a 70 x 60 grid: `fieldsAt` 40 ms to 2.4 ms, `blendInto` 37 ms to
|
|
12
|
+
4 ms; 200 x 200: 340 ms to 19 ms.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- `PERFORMANCE.md` (measured numbers and how to re-run them), `pnpm bench`, `pnpm size`, `size-limits.json`
|
|
16
|
+
(the build fails if the package grows past its size budget), `sideEffects: false`.
|
|
17
|
+
|
|
18
|
+
## 0.4.1 (2026-11-02)
|
|
19
|
+
|
|
20
|
+
- Documentation and tests only: `STABILITY.md`, `LIMITS.md`, `CHANGELOG.md`, public API surface test.
|
|
21
|
+
|
|
6
22
|
## 0.4.0 (2026-11-02)
|
|
7
23
|
|
|
8
24
|
- Release only: no source change since 0.3.0.
|
package/PERFORMANCE.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Performance and size
|
|
2
|
+
|
|
3
|
+
Measured numbers, not claims. Re-run them on your own hardware; the commands are below.
|
|
4
|
+
|
|
5
|
+
**Machine used for these numbers:** Intel Core Ultra 7 155H (22 threads), 31 GB RAM, Node 22.14, Windows 11, run
|
|
6
|
+
on a laptop with other programs open (hence the spread). A weaker machine will be slower. Times are the mean of a
|
|
7
|
+
`vitest bench` run.
|
|
8
|
+
|
|
9
|
+
## Computing weather fields (`@aeroswarm/weather`)
|
|
10
|
+
|
|
11
|
+
`pnpm --filter @aeroswarm/weather bench`
|
|
12
|
+
|
|
13
|
+
| Operation | Time |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `fieldsAt`, 5 stations, 70 x 60 grid | 0.4 ms |
|
|
16
|
+
| `fieldsAt`, 60 stations, 70 x 60 grid | 2.4 ms |
|
|
17
|
+
| `fieldsAt`, 60 stations, 200 x 200 grid | 19 ms |
|
|
18
|
+
| `seriesFieldsAt` (model series, 120 hours), 70 x 60 | 1.3 ms |
|
|
19
|
+
| `seriesFieldsAt` (model series, 120 hours), 200 x 200 | 15 ms |
|
|
20
|
+
| `blendInto` (model + 60 stations), 70 x 60 | 4.1 ms |
|
|
21
|
+
| `blendInto` (model + 60 stations), 200 x 200 | 40 ms (one run varied up to 97 ms) |
|
|
22
|
+
|
|
23
|
+
Target agreed for the product: `fieldsAt` under 20 ms for a 70 x 60 grid. Met, with 8x room, up to 60 stations.
|
|
24
|
+
|
|
25
|
+
Before this change `fieldsAt` with 60 stations on 70 x 60 took about 40 ms and `blendInto` about 37 ms; the cost came from
|
|
26
|
+
recomputing distances and trigonometry for every station and every quantity. They are now computed once per cell and
|
|
27
|
+
shared (results are identical to the plain definition, checked by a test; differences are below float rounding).
|
|
28
|
+
|
|
29
|
+
**Memory of a model series** (`WeatherGridSeries`, five quantities as `Float32Array`, one frame per hour):
|
|
30
|
+
|
|
31
|
+
| Grid | 120 hours |
|
|
32
|
+
|---|---|
|
|
33
|
+
| 70 x 60 | 9.6 MB |
|
|
34
|
+
| 200 x 200 | 91.6 MB |
|
|
35
|
+
|
|
36
|
+
Ask the model source for a coarser grid or fewer quantities before asking for more hours.
|
|
37
|
+
|
|
38
|
+
## Drawing (`@aeroswarm/weather-layer`)
|
|
39
|
+
|
|
40
|
+
`pnpm --filter @aeroswarm/weather-layer bench` measures remapping a field to the screen, which runs each time the
|
|
41
|
+
map moves (at most about 10 times a second). It uses a cheap linear projection, so a real map projection costs more:
|
|
42
|
+
treat these as a lower bound.
|
|
43
|
+
|
|
44
|
+
| Screen | Wind field (24 px cells) | Colour field (8 px cells) |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| 1080p | 0.56 ms | 0.88 ms |
|
|
47
|
+
| 4K | 2.3 ms | 3.6 ms |
|
|
48
|
+
|
|
49
|
+
**Frames per second of the particle renderer have not been measured by the author.** Canvas drawing needs a real
|
|
50
|
+
browser. Run `examples/fps-benchmark.html` (instructions at the top of the file) on the target machine, and record the
|
|
51
|
+
JSON it prints. Until then there is no fps number to quote, and the earlier target (30 fps on an ordinary laptop at
|
|
52
|
+
1080p) is unverified.
|
|
53
|
+
|
|
54
|
+
Behaviours built in:
|
|
55
|
+
|
|
56
|
+
- A hidden tab draws nothing.
|
|
57
|
+
- `prefers-reduced-motion`: the overlay draws a still image. The user can turn motion back on with
|
|
58
|
+
`WeatherMotionToggle` (or `FlowRenderer.setReducedMotion`), and the renderer follows later changes of the system
|
|
59
|
+
setting.
|
|
60
|
+
- Adaptive quality: when a frame takes more than 12 ms to prepare, or frames are drawn less than two thirds as often
|
|
61
|
+
as requested, the particle count drops by 20% (down to 25%); when well under budget it rises again by 10%. The
|
|
62
|
+
current level is `overlay.quality` (1 = full). The rule is tested (`nextQualityScale`); the renderer integration needs
|
|
63
|
+
a browser and is not covered by an automated test.
|
|
64
|
+
|
|
65
|
+
## Package size
|
|
66
|
+
|
|
67
|
+
`pnpm --filter <package> size` after a build. Limits are in each package's `size-limits.json`; `prepublishOnly` fails
|
|
68
|
+
when a number goes over its limit, so growth needs a deliberate change with a note in the changelog.
|
|
69
|
+
|
|
70
|
+
| Package | All of `dist` (gzip per file) | Example: what an app pays (bundled, minified, gzip) |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| `@aeroswarm/weather` | 26.0 kB | `parseMetar` only 2.8 kB, `WeatherStore` 8.3 kB, everything 19.5 kB |
|
|
73
|
+
| `@aeroswarm/weather-layer` | 24.1 kB | `legendFor` only 0.8 kB, field overlay + MapLibre adapter 4.9 kB, all of `/react-ui` 9.3 kB |
|
|
74
|
+
| `@aeroswarm/weather-sources` | 4.1 kB | `aviationWeatherSource` 1.6 kB, everything 3.1 kB |
|
|
75
|
+
|
|
76
|
+
Tree-shaking works (importing one function costs a fraction of the package), and a MapLibre app does not pay for
|
|
77
|
+
Cesium, Leaflet or RIA because each map has its own entry point. `@aeroswarm/weather-layer` now splits shared code into
|
|
78
|
+
chunks; before that, using `.` and `/react-ui` together shipped the core twice (about 12 kB gzip extra).
|
package/README.md
CHANGED
|
@@ -31,6 +31,7 @@ representation around the airport, not the real position of clouds or rain.
|
|
|
31
31
|
- [STABILITY.md](./STABILITY.md): what is public, semver policy, deprecation, the weather-grid standard.
|
|
32
32
|
- [LIMITS.md](./LIMITS.md): **read before operational use**: not an official source, not for safety decisions
|
|
33
33
|
without verification, what is and is not verified.
|
|
34
|
+
- [PERFORMANCE.md](./PERFORMANCE.md): measured speed, memory and bundle size, and how to re-measure.
|
|
34
35
|
- [CHANGELOG.md](./CHANGELOG.md), [GRID_STANDARD.md](./GRID_STANDARD.md).
|
|
35
36
|
|
|
36
37
|
## Gridded fields
|
package/dist/grid.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../src/grid.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../src/grid.ts"],"names":[],"mappings":"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"}
|
package/dist/idw.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inti hitung interpolasi stasiun ke grid (internal: tidak diekspor dari paket). Jarak antar sel dan stasiun
|
|
3
|
+
* dihitung tanpa trigonometri di loop dalam, dan satu putaran jarak dipakai untuk beberapa besaran sekaligus.
|
|
4
|
+
*/
|
|
5
|
+
import type { GridBounds } from "./grid.js";
|
|
6
|
+
export declare const KM_PER_DEG_LAT = 111.32;
|
|
7
|
+
export declare const KT_TO_MS = 0.514444;
|
|
8
|
+
interface Located {
|
|
9
|
+
lat: number;
|
|
10
|
+
lon: number;
|
|
11
|
+
}
|
|
12
|
+
export interface IdwOptions {
|
|
13
|
+
bounds: GridBounds;
|
|
14
|
+
nx: number;
|
|
15
|
+
ny: number;
|
|
16
|
+
power?: number;
|
|
17
|
+
maxDistanceKm?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* IDW (bobot 1/d^p) untuk beberapa besaran di titik yang sama. Tepat di sebuah titik (jarak < 0,5 km) hasilnya
|
|
21
|
+
* persis nilai titik itu; sel yang lebih jauh dari semua titik dari `maxDistanceKm` (bawaan 400) diberi NaN.
|
|
22
|
+
*/
|
|
23
|
+
export declare function interpolateMany(points: readonly Located[], valueSets: readonly (readonly number[])[], options: IdwOptions): Float32Array[];
|
|
24
|
+
/**
|
|
25
|
+
* Tambahkan selisih (pengamatan dikurangi model) di titik-titik ke beberapa grid sekaligus: bobot dihitung
|
|
26
|
+
* sekali per sel dan dipakai untuk semua grid. Sel tanpa data (NaN) dilewati. Di luar `radius` grid tidak berubah.
|
|
27
|
+
*/
|
|
28
|
+
export declare function nudgeMany(grids: readonly Float32Array[], points: readonly Located[], deltaSets: readonly (readonly number[])[], bounds: GridBounds, nx: number, ny: number, radius: number): Float32Array[];
|
|
29
|
+
/** Komponen u/v (m/s) dari angin stasiun; arah null (VRB) dianggap tenang. */
|
|
30
|
+
export declare function stationComponents(stations: readonly {
|
|
31
|
+
speedKt: number;
|
|
32
|
+
directionDeg: number | null;
|
|
33
|
+
}[], ktToMs: number): {
|
|
34
|
+
u: number[];
|
|
35
|
+
v: number[];
|
|
36
|
+
};
|
|
37
|
+
export {};
|
|
38
|
+
//# sourceMappingURL=idw.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idw.d.ts","sourceRoot":"","sources":["../src/idw.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C,eAAO,MAAM,cAAc,SAAS,CAAC;AACrC,eAAO,MAAM,QAAQ,WAAY,CAAC;AAGlC,UAAU,OAAO;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,UAAU,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAuBD;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,SAAS,OAAO,EAAE,EAC1B,SAAS,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,EACzC,OAAO,EAAE,UAAU,GAClB,YAAY,EAAE,CAiDhB;AAMD;;;GAGG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,SAAS,YAAY,EAAE,EAC9B,MAAM,EAAE,SAAS,OAAO,EAAE,EAC1B,SAAS,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,EACzC,MAAM,EAAE,UAAU,EAClB,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,GACb,YAAY,EAAE,CAuChB;AAED,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,SAAS;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAAE,EACrE,MAAM,EAAE,MAAM,GACb;IAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAe9B"}
|
package/dist/index.js
CHANGED
|
@@ -1350,9 +1350,128 @@ function animationSnapshot(input) {
|
|
|
1350
1350
|
return { state: animationFromConditions(conditions), ...meta };
|
|
1351
1351
|
}
|
|
1352
1352
|
|
|
1353
|
-
// src/
|
|
1354
|
-
var KT_TO_MS = 0.514444;
|
|
1353
|
+
// src/idw.ts
|
|
1355
1354
|
var KM_PER_DEG_LAT = 111.32;
|
|
1355
|
+
var KT_TO_MS = 0.514444;
|
|
1356
|
+
var RAD = Math.PI / 180;
|
|
1357
|
+
function halfLatTrig(lats) {
|
|
1358
|
+
const sin = new Float64Array(lats.length);
|
|
1359
|
+
const cos = new Float64Array(lats.length);
|
|
1360
|
+
for (let i = 0; i < lats.length; i++) {
|
|
1361
|
+
const half = lats[i] / 2 * RAD;
|
|
1362
|
+
sin[i] = Math.sin(half);
|
|
1363
|
+
cos[i] = Math.cos(half);
|
|
1364
|
+
}
|
|
1365
|
+
return { sin, cos };
|
|
1366
|
+
}
|
|
1367
|
+
function axes(bounds, nx, ny) {
|
|
1368
|
+
const lats = new Float64Array(ny);
|
|
1369
|
+
const lons = new Float64Array(nx);
|
|
1370
|
+
for (let row = 0; row < ny; row++) lats[row] = bounds.north - (bounds.north - bounds.south) * row / Math.max(1, ny - 1);
|
|
1371
|
+
for (let col = 0; col < nx; col++) lons[col] = bounds.west + (bounds.east - bounds.west) * col / Math.max(1, nx - 1);
|
|
1372
|
+
return { lats, lons };
|
|
1373
|
+
}
|
|
1374
|
+
function interpolateMany(points, valueSets, options) {
|
|
1375
|
+
const { bounds, nx, ny } = options;
|
|
1376
|
+
const power = options.power ?? 2;
|
|
1377
|
+
const maxKm = options.maxDistanceKm ?? 400;
|
|
1378
|
+
const sets = valueSets.length;
|
|
1379
|
+
const outs = valueSets.map(() => new Float32Array(nx * ny).fill(Number.NaN));
|
|
1380
|
+
const sums = new Float64Array(sets);
|
|
1381
|
+
const { lats, lons } = axes(bounds, nx, ny);
|
|
1382
|
+
const cellTrig = halfLatTrig(lats);
|
|
1383
|
+
const pointTrig = halfLatTrig(points.map((p) => p.lat));
|
|
1384
|
+
for (let row = 0; row < ny; row++) {
|
|
1385
|
+
const cellLat = lats[row];
|
|
1386
|
+
const sinC = cellTrig.sin[row];
|
|
1387
|
+
const cosC = cellTrig.cos[row];
|
|
1388
|
+
for (let col = 0; col < nx; col++) {
|
|
1389
|
+
const cellLon = lons[col];
|
|
1390
|
+
let weightSum = 0;
|
|
1391
|
+
let exact = -1;
|
|
1392
|
+
sums.fill(0);
|
|
1393
|
+
for (let i = 0; i < points.length; i++) {
|
|
1394
|
+
const p = points[i];
|
|
1395
|
+
const dLat = (cellLat - p.lat) * KM_PER_DEG_LAT;
|
|
1396
|
+
if (dLat > maxKm || dLat < -maxKm) continue;
|
|
1397
|
+
const cosMean = cosC * pointTrig.cos[i] - sinC * pointTrig.sin[i];
|
|
1398
|
+
const dLon = (cellLon - p.lon) * KM_PER_DEG_LAT * cosMean;
|
|
1399
|
+
const d = Math.sqrt(dLat * dLat + dLon * dLon);
|
|
1400
|
+
if (d > maxKm) continue;
|
|
1401
|
+
if (d < 0.5) {
|
|
1402
|
+
exact = i;
|
|
1403
|
+
break;
|
|
1404
|
+
}
|
|
1405
|
+
const w = power === 2 ? 1 / (d * d) : 1 / d ** power;
|
|
1406
|
+
weightSum += w;
|
|
1407
|
+
for (let k = 0; k < sets; k++) sums[k] = sums[k] + w * valueSets[k][i];
|
|
1408
|
+
}
|
|
1409
|
+
const index = row * nx + col;
|
|
1410
|
+
for (let k = 0; k < sets; k++) {
|
|
1411
|
+
outs[k][index] = exact >= 0 ? valueSets[k][exact] : weightSum > 0 ? sums[k] / weightSum : Number.NaN;
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
return outs;
|
|
1416
|
+
}
|
|
1417
|
+
var influence = (distance, radius) => distance >= radius ? 0 : (radius * radius - distance * distance) / (radius * radius + distance * distance);
|
|
1418
|
+
function nudgeMany(grids, points, deltaSets, bounds, nx, ny, radius) {
|
|
1419
|
+
const outs = grids.map((g) => Float32Array.from(g));
|
|
1420
|
+
if (points.length === 0) return outs;
|
|
1421
|
+
const sets = grids.length;
|
|
1422
|
+
const weighted = new Float64Array(sets);
|
|
1423
|
+
const { lats, lons } = axes(bounds, nx, ny);
|
|
1424
|
+
const cellTrig = halfLatTrig(lats);
|
|
1425
|
+
const pointTrig = halfLatTrig(points.map((p) => p.lat));
|
|
1426
|
+
for (let row = 0; row < ny; row++) {
|
|
1427
|
+
const cellLat = lats[row];
|
|
1428
|
+
const sinC = cellTrig.sin[row];
|
|
1429
|
+
const cosC = cellTrig.cos[row];
|
|
1430
|
+
for (let col = 0; col < nx; col++) {
|
|
1431
|
+
const cellLon = lons[col];
|
|
1432
|
+
const index = row * nx + col;
|
|
1433
|
+
let weights = 0;
|
|
1434
|
+
weighted.fill(0);
|
|
1435
|
+
for (let i = 0; i < points.length; i++) {
|
|
1436
|
+
const p = points[i];
|
|
1437
|
+
const dLat = (cellLat - p.lat) * KM_PER_DEG_LAT;
|
|
1438
|
+
if (dLat >= radius || dLat <= -radius) continue;
|
|
1439
|
+
const cosMean = cosC * pointTrig.cos[i] - sinC * pointTrig.sin[i];
|
|
1440
|
+
const dLon = (cellLon - p.lon) * KM_PER_DEG_LAT * cosMean;
|
|
1441
|
+
const w = influence(Math.sqrt(dLat * dLat + dLon * dLon), radius);
|
|
1442
|
+
if (w === 0) continue;
|
|
1443
|
+
weights += w;
|
|
1444
|
+
for (let k = 0; k < sets; k++) weighted[k] = weighted[k] + w * deltaSets[k][i];
|
|
1445
|
+
}
|
|
1446
|
+
if (weights <= 0) continue;
|
|
1447
|
+
const scale = Math.min(1, weights);
|
|
1448
|
+
for (let k = 0; k < sets; k++) {
|
|
1449
|
+
const out = outs[k];
|
|
1450
|
+
if (Number.isNaN(out[index])) continue;
|
|
1451
|
+
out[index] = out[index] + weighted[k] / weights * scale;
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
return outs;
|
|
1456
|
+
}
|
|
1457
|
+
function stationComponents(stations, ktToMs) {
|
|
1458
|
+
const u = [];
|
|
1459
|
+
const v = [];
|
|
1460
|
+
for (const s of stations) {
|
|
1461
|
+
if (s.directionDeg === null) {
|
|
1462
|
+
u.push(0);
|
|
1463
|
+
v.push(0);
|
|
1464
|
+
continue;
|
|
1465
|
+
}
|
|
1466
|
+
const rad = s.directionDeg * Math.PI / 180;
|
|
1467
|
+
const speed = s.speedKt * ktToMs;
|
|
1468
|
+
u.push(-speed * Math.sin(rad));
|
|
1469
|
+
v.push(-speed * Math.cos(rad));
|
|
1470
|
+
}
|
|
1471
|
+
return { u, v };
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
// src/grid.ts
|
|
1356
1475
|
var speedOf = (u, v) => Math.hypot(u, v);
|
|
1357
1476
|
function directionFromUV(u, v) {
|
|
1358
1477
|
return (Math.atan2(-u, -v) * 180 / Math.PI + 360) % 360;
|
|
@@ -1367,37 +1486,9 @@ function pointOf(bounds, nx, ny, col, row) {
|
|
|
1367
1486
|
lat: bounds.north - (bounds.north - bounds.south) * row / Math.max(1, ny - 1)
|
|
1368
1487
|
};
|
|
1369
1488
|
}
|
|
1370
|
-
function distanceKm(a, b) {
|
|
1371
|
-
const dLat = (a.lat - b.lat) * KM_PER_DEG_LAT;
|
|
1372
|
-
const dLon = (a.lon - b.lon) * KM_PER_DEG_LAT * Math.cos((a.lat + b.lat) / 2 * (Math.PI / 180));
|
|
1373
|
-
return Math.hypot(dLat, dLon);
|
|
1374
|
-
}
|
|
1375
1489
|
function interpolateScalar(points, options) {
|
|
1376
|
-
const
|
|
1377
|
-
|
|
1378
|
-
const maxKm = options.maxDistanceKm ?? 400;
|
|
1379
|
-
const values = new Float32Array(nx * ny).fill(Number.NaN);
|
|
1380
|
-
for (let row = 0; row < ny; row++) {
|
|
1381
|
-
for (let col = 0; col < nx; col++) {
|
|
1382
|
-
const cell = pointOf(bounds, nx, ny, col, row);
|
|
1383
|
-
let weightSum = 0;
|
|
1384
|
-
let sum = 0;
|
|
1385
|
-
let exact = null;
|
|
1386
|
-
for (const p of points) {
|
|
1387
|
-
const d = distanceKm(cell, p);
|
|
1388
|
-
if (d > maxKm) continue;
|
|
1389
|
-
if (d < 0.5) {
|
|
1390
|
-
exact = p.value;
|
|
1391
|
-
break;
|
|
1392
|
-
}
|
|
1393
|
-
const w = 1 / d ** power;
|
|
1394
|
-
weightSum += w;
|
|
1395
|
-
sum += w * p.value;
|
|
1396
|
-
}
|
|
1397
|
-
values[row * nx + col] = exact ?? (weightSum > 0 ? sum / weightSum : Number.NaN);
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
|
-
return { bounds, nx, ny, values };
|
|
1490
|
+
const [values] = interpolateMany(points, [points.map((p) => p.value)], options);
|
|
1491
|
+
return { bounds: options.bounds, nx: options.nx, ny: options.ny, values };
|
|
1401
1492
|
}
|
|
1402
1493
|
function windGridFromStations(stations, options) {
|
|
1403
1494
|
const components = stations.map((s) => {
|
|
@@ -1405,9 +1496,8 @@ function windGridFromStations(stations, options) {
|
|
|
1405
1496
|
const { u: u2, v: v2 } = s.directionDeg === null ? { u: 0, v: 0 } : uvFromSpeedDirection(speedMs, s.directionDeg);
|
|
1406
1497
|
return { lat: s.lat, lon: s.lon, u: u2, v: v2 };
|
|
1407
1498
|
});
|
|
1408
|
-
const u =
|
|
1409
|
-
|
|
1410
|
-
return { bounds: options.bounds, nx: options.nx, ny: options.ny, u: u.values, v: v.values };
|
|
1499
|
+
const [u, v] = interpolateMany(components, [components.map((c) => c.u), components.map((c) => c.v)], options);
|
|
1500
|
+
return { bounds: options.bounds, nx: options.nx, ny: options.ny, u, v };
|
|
1411
1501
|
}
|
|
1412
1502
|
function bilinear(values, bounds, nx, ny, lon, lat) {
|
|
1413
1503
|
if (lon < bounds.west || lon > bounds.east || lat < bounds.south || lat > bounds.north) return null;
|
|
@@ -1434,51 +1524,32 @@ function sampleWind(grid, lon, lat) {
|
|
|
1434
1524
|
const v = bilinear(grid.v, grid.bounds, grid.nx, grid.ny, lon, lat);
|
|
1435
1525
|
return u === null || v === null ? null : { u, v };
|
|
1436
1526
|
}
|
|
1437
|
-
var influence = (distance, radius) => distance >= radius ? 0 : (radius * radius - distance * distance) / (radius * radius + distance * distance);
|
|
1438
|
-
function nudgeValues(values, bounds, nx, ny, deltas, radius) {
|
|
1439
|
-
const out = Float32Array.from(values);
|
|
1440
|
-
if (deltas.length === 0) return out;
|
|
1441
|
-
for (let row = 0; row < ny; row++) {
|
|
1442
|
-
for (let col = 0; col < nx; col++) {
|
|
1443
|
-
const index = row * nx + col;
|
|
1444
|
-
if (Number.isNaN(out[index])) continue;
|
|
1445
|
-
const cell = pointOf(bounds, nx, ny, col, row);
|
|
1446
|
-
let weights = 0;
|
|
1447
|
-
let weighted = 0;
|
|
1448
|
-
for (const d of deltas) {
|
|
1449
|
-
const w = influence(distanceKm(cell, d), radius);
|
|
1450
|
-
weights += w;
|
|
1451
|
-
weighted += w * d.delta;
|
|
1452
|
-
}
|
|
1453
|
-
if (weights > 0) out[index] = out[index] + weighted / weights * Math.min(1, weights);
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
return out;
|
|
1457
|
-
}
|
|
1458
1527
|
function nudgeScalar(grid, points, options = {}) {
|
|
1528
|
+
const located = [];
|
|
1459
1529
|
const deltas = [];
|
|
1460
1530
|
for (const p of points) {
|
|
1461
1531
|
const model = sampleScalar(grid, p.lon, p.lat);
|
|
1462
|
-
if (model
|
|
1532
|
+
if (model === null) continue;
|
|
1533
|
+
located.push({ lat: p.lat, lon: p.lon });
|
|
1534
|
+
deltas.push(p.value - model);
|
|
1463
1535
|
}
|
|
1464
|
-
|
|
1536
|
+
const [values] = nudgeMany([grid.values], located, [deltas], grid.bounds, grid.nx, grid.ny, options.radiusKm ?? 80);
|
|
1537
|
+
return { ...grid, values };
|
|
1465
1538
|
}
|
|
1466
1539
|
function nudgeWind(grid, stations, options = {}) {
|
|
1540
|
+
const located = [];
|
|
1467
1541
|
const du = [];
|
|
1468
1542
|
const dv = [];
|
|
1469
1543
|
for (const s of stations) {
|
|
1470
1544
|
const model = sampleWind(grid, s.lon, s.lat);
|
|
1471
1545
|
if (!model) continue;
|
|
1472
1546
|
const obs = s.directionDeg === null ? { u: 0, v: 0 } : uvFromSpeedDirection(s.speedKt * KT_TO_MS, s.directionDeg);
|
|
1473
|
-
|
|
1474
|
-
|
|
1547
|
+
located.push({ lat: s.lat, lon: s.lon });
|
|
1548
|
+
du.push(obs.u - model.u);
|
|
1549
|
+
dv.push(obs.v - model.v);
|
|
1475
1550
|
}
|
|
1476
|
-
const
|
|
1477
|
-
return {
|
|
1478
|
-
...grid,
|
|
1479
|
-
u: nudgeValues(grid.u, grid.bounds, grid.nx, grid.ny, du, radius),
|
|
1480
|
-
v: nudgeValues(grid.v, grid.bounds, grid.nx, grid.ny, dv, radius)
|
|
1481
|
-
};
|
|
1551
|
+
const [u, v] = nudgeMany([grid.u, grid.v], located, [du, dv], grid.bounds, grid.nx, grid.ny, options.radiusKm ?? 80);
|
|
1552
|
+
return { ...grid, u, v };
|
|
1482
1553
|
}
|
|
1483
1554
|
function blendWindGrids(a, b, t) {
|
|
1484
1555
|
if (a.nx !== b.nx || a.ny !== b.ny) throw new Error("Grid angin harus berukuran sama");
|
|
@@ -2282,12 +2353,19 @@ var WeatherStore = class {
|
|
|
2282
2353
|
fieldsAt(at, grid, options = {}) {
|
|
2283
2354
|
const points = this.pointsAt(at, options);
|
|
2284
2355
|
if (points.stations.length === 0) return null;
|
|
2356
|
+
const { u, v } = stationComponents(points.winds, KT_TO_MS);
|
|
2357
|
+
const [windU, windV, cloud, rain] = interpolateMany(
|
|
2358
|
+
points.winds,
|
|
2359
|
+
[u, v, points.clouds.map((c) => c.value), points.rains.map((r) => r.value)],
|
|
2360
|
+
grid
|
|
2361
|
+
);
|
|
2362
|
+
const { bounds, nx, ny } = grid;
|
|
2285
2363
|
return {
|
|
2286
2364
|
at,
|
|
2287
2365
|
stations: points.stations,
|
|
2288
|
-
wind:
|
|
2289
|
-
cloud:
|
|
2290
|
-
rain:
|
|
2366
|
+
wind: { bounds, nx, ny, u: windU, v: windV },
|
|
2367
|
+
cloud: { bounds, nx, ny, values: cloud },
|
|
2368
|
+
rain: { bounds, nx, ny, values: rain },
|
|
2291
2369
|
temperature: points.temperatures.length > 0 ? interpolateScalar(points.temperatures, grid) : null
|
|
2292
2370
|
};
|
|
2293
2371
|
}
|
package/dist/store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,iBAAiB,EAEtB,KAAK,kBAAkB,EAExB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,UAAU,EAEf,KAAK,YAAY,EAGjB,KAAK,UAAU,EAGf,KAAK,QAAQ,EAEd,MAAM,WAAW,CAAC;AAInB,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAExD,MAAM,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,GAAG,SAAS,CAAC;AAE5D,MAAM,WAAW,aAAa;IAC5B,+EAA+E;IAC/E,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,kFAAkF;IAClF,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAC;IACZ,uFAAuF;IACvF,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,CAAC;IAClB,IAAI,EAAE,IAAI,CAAC;IACX,EAAE,EAAE,IAAI,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,IAAI,CAAC;IACX,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,+CAA+C;IAC/C,YAAY,EAAE,IAAI,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,IAAI,CAAC;IACT,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,EAAE,QAAQ,CAAC;IACf,0BAA0B;IAC1B,KAAK,EAAE,UAAU,CAAC;IAClB,oEAAoE;IACpE,IAAI,EAAE,UAAU,CAAC;IACjB,yDAAyD;IACzD,WAAW,EAAE,UAAU,GAAG,IAAI,CAAC;CAChC;AAED,mFAAmF;AACnF,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,IAAI,CAAC;IACT,0FAA0F;IAC1F,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACzB,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,UAAU,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,UAAU,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAiBD;;;GAGG;AACH,qBAAa,YAAY;IAOX,OAAO,CAAC,QAAQ,CAAC,MAAM;IANnC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsC;IACnE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoC;IAC9D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyB;IACnD,iEAAiE;IACjE,OAAO,SAAK;gBAEiB,MAAM,EAAE,MAAM;IAE3C,2FAA2F;IAC3F,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,YAAY;IAyClE,oEAAoE;IACpE,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAanC,8CAA8C;IAC9C,KAAK,IAAI,IAAI;IAMb,SAAS,IAAI,OAAO;IAOpB,QAAQ,IAAI,MAAM,EAAE;IAMpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAK1C,oEAAoE;IACpE,UAAU,CACR,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,IAAI,EACR,OAAO,GAAE;QAAE,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GACxE,iBAAiB,GAAG,IAAI;IAU3B,wFAAwF;IACxF,YAAY,CACV,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,IAAI,EACR,OAAO,GAAE;QAAE,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GACxE,kBAAkB,GAAG,IAAI;IAU5B,wFAAwF;IACxF,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,GAAG,GAAG,GAAG,IAAI;IAIlD,uGAAuG;IACvG,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE;IASpE,0FAA0F;IAC1F,QAAQ,IAAI,QAAQ,GAAG,IAAI;IAkC3B;;;OAGG;IACH,QAAQ,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,aAAa,GAAG,IAAI;IAqB7G;;;;OAIG;IACH,SAAS,CACP,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI,CAAC,EACxC,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,IAAI,EACR,OAAO,GAAE,YAAY,GAAG;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GACzD,QAAQ;IAYX,wEAAwE;IACxE,OAAO,CAAC,QAAQ;IA+BhB,OAAO,CAAC,OAAO;IAKf,OAAO,CAAC,GAAG;IAkBX,OAAO,CAAC,MAAM;IAUd,OAAO,CAAC,eAAe;IAmBvB,OAAO,CAAC,YAAY;CASrB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aeroswarm/weather",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "Decode raw AFTN/METAR/SPECI/TAF messages and turn them into animation parameters.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"GRID_STANDARD.md",
|
|
18
18
|
"CHANGELOG.md",
|
|
19
19
|
"STABILITY.md",
|
|
20
|
-
"LIMITS.md"
|
|
20
|
+
"LIMITS.md",
|
|
21
|
+
"PERFORMANCE.md"
|
|
21
22
|
],
|
|
22
23
|
"publishConfig": {
|
|
23
24
|
"access": "public",
|
|
@@ -29,16 +30,19 @@
|
|
|
29
30
|
"test": "vitest run --passWithNoTests",
|
|
30
31
|
"typecheck": "tsc --noEmit",
|
|
31
32
|
"clean": "rm -rf dist",
|
|
32
|
-
"prepublishOnly": "pnpm run typecheck && pnpm run test && pnpm run build",
|
|
33
|
+
"prepublishOnly": "pnpm run typecheck && pnpm run test && pnpm run build && pnpm run size",
|
|
33
34
|
"release": "release-it",
|
|
34
35
|
"release:dry": "release-it --dry-run",
|
|
35
36
|
"release:patch": "release-it patch --no-git.requireCleanWorkingDir",
|
|
36
37
|
"release:minor": "release-it minor --no-git.requireCleanWorkingDir",
|
|
37
|
-
"release:major": "release-it major --no-git.requireCleanWorkingDir"
|
|
38
|
+
"release:major": "release-it major --no-git.requireCleanWorkingDir",
|
|
39
|
+
"bench": "vitest bench --run",
|
|
40
|
+
"size": "node ../../../scripts/package-size.mjs"
|
|
38
41
|
},
|
|
39
42
|
"devDependencies": {
|
|
40
43
|
"release-it": "^18.1.2",
|
|
41
44
|
"tsup": "^8.5.1",
|
|
42
45
|
"vitest": "^4.1.6"
|
|
43
|
-
}
|
|
46
|
+
},
|
|
47
|
+
"sideEffects": false
|
|
44
48
|
}
|