Andronikos Weather Intelligence
Fullstack documentation untuk engine weather intelligence Indonesia: GraphCast, Open-Meteo, ERA5, GFS, GEFS, AIGFS, AIGEFS, HGEFS, BMKG, dan multi-source fusion dengan pola pembobotan enterprise.
Asal-Usul: Menara Angin dan Nalar Andronikos
Setiap sistem prakiraan pada akhirnya menjawab pertanyaan yang lebih tua daripada komputasi: bagaimana manusia menempatkan diri di antara langit dan tanah. Menara Angin di Athena adalah jawaban paling awal yang masih berdiri; Andronikos adalah upaya menuliskan kembali jawaban itu dengan mesin hari ini.
Sebuah Bangunan yang Menolak Punah
Di Agora Romawi, Athena, berdiri menara segi delapan dari marmer Pentelik: tingginya sekitar 12 meter, garis tengahnya sekitar 8 meter, dan di sekeliling puncaknya terpahat delapan relief dewa angin. Penanggalannya tidak pasti. Ia selesai paling lambat sekitar 50 SM, sebab Varro sudah menyebutnya sekitar 37 SM, dan perancangnya lazim disebut astronom Andronikos dari Kyrrhos, sosok yang nyaris tak meninggalkan biografi. Menara ini termasuk segelintir bangunan klasik yang nyaris utuh hingga kini, dan sebabnya paradoksal: ia tidak dibekukan menjadi monumen, melainkan terus dipakai untuk fungsi yang berganti-ganti. Salah satu sebutan lamanya, Jam Andronikos, adalah asal nama platform ini.
Satu Bangunan, Empat Instrumen
Yang istimewa dari menara ini bukan marmernya, melainkan integrasinya. Dalam satu badan ia menghimpun relief delapan angin, baling-baling perunggu berbentuk Triton di puncak (menurut Vitruvius; kini hilang), delapan jam matahari pada sisi luar, dan jam air di dalam yang dialiri dari mata air di Akropolis. Arsitektur, pahatan, dan sains baru dileburkan agar warga dapat mengorientasikan diri dalam ruang dan waktu. Kata kuncinya orientasi, bukan ramalan: menara tidak memutuskan apa yang harus dilakukan orang Athena, ia memberi mereka bahasa bersama untuk membaca langit.
Peta Gagasan: dari Menara ke Mesin
Tabel berikut memetakan bukti tentang menara ke keputusan desain yang dapat ditelusuri di dokumentasi ini. Pemetaannya argumen analogis, bukan klaim silsilah.
| Bukti dari menara | Gagasan | Wujud di Andronikos |
|---|---|---|
| Delapan relief angin, masing-masing dicirikan lewat atribut: hujan, dingin, kering, subur | Bahaya diberi nama dan wajah sebelum diukur | Katalog 17 WeatherVariable dan modul risiko longsor, banjir, asap. Skiron, pembawa abu dan bara yang mungkin merujuk kebakaran hutan, menjadi pendahulu simbolik modul asap dan titik panas (fire.firms, fire.sipongi) |
| Baling-baling Triton di puncak | Pengamatan mendahului prediksi | obs.bmkg_stn dan obs.isd (setelah QC) menjadi acuan verifikasi; ref.era5 tidak |
| Delapan jam matahari, masing-masing disetel menurut lamanya sisi itu disinari (timur dan barat hanya empat garis jam, selatan delapan) | Kalibrasi lokal: satu prinsip, banyak sisi | Koreksi bias per variabel, lead, siklus, dan stasiun; semua anggota ensemble memakai b yang sama |
| Jam air yang mekanismenya hilang; rekonstruksinya tetap tak pasti | Kejujuran epistemik: yang tak diketahui tidak ditambal tebakan | WIError::BelumDiputuskan, daftar “Undecided (JANGAN diisi tebakan)”, bobot fusi dan ambang siaga yang sengaja belum ditetapkan |
| Menara dibuat tinggi agar jam matahari dan baling-baling terlihat dari Agora; belum jelas bagaimana bacaan jam air di dalam sampai ke orang di luar | Informasi harus tiba di tempat keputusan diambil, dengan takaran yang jujur | Peta Leptos + MapLibre, panel risiko, endpoint keputusan CoalForge; label_istilah, atribusi, dan bahasa probabilitas tanpa klaim “memprediksi pasti” |
| Atap batu asli dari 24 lempeng trapesium yang dikunci satu batu kunci melingkar | Kekokohan lahir dari sambungan yang saling mengunci | Delapan crate dengan batas tanggung jawab jelas; tanpa unwrap() atau panic! di kode non-test |
| Berganti fungsi berabad-abad, sempat terkubur separuh tinggi, digali pada abad ke-19, dipugar 2014–2016 | Ketahanan lewat kemampuan beralih guna | Single VPS ke Three VPS; jalur ganda Burn GraphCast dan ONNX; “Python melatih, Rust menyajikan” |
| Gambar ukur Stuart dan Revett (1762) yang “merapikan” relief aus | Dokumentasi berisiko mengidealkan yang didokumentasikan | Status apa adanya: Skeleton, Perlu GPU, persentase kematangan per crate. Dokumen ini tidak merapikan yang belum rapi |
| Bab tata kota Vitruvius: orientasi jalan untuk memaksimalkan manfaat dan meminimalkan bahaya angin | Pengetahuan angin sebagai alat tata ruang | unit_id (sub-DAS, unit lereng, kelurahan): informasi risiko turun hingga unit yang dapat diputuskan |
Mengapa Nusantara, Mengapa Sekarang
Indonesia adalah kepulauan tropis yang bentang petanya, sebagaimana dikunci pada antarmuka ini, membentang sekitar 11,15°LS hingga 6,25°LU dan 94,95°BT hingga 141,25°BT, dengan hujan dan angin muson yang membentuk risiko longsor, banjir, dan asap. Persoalan hari ini bukan kelangkaan data: tujuh adapter ingesti, beberapa model global, dan jaringan pengamatan sudah tersedia. Yang langka adalah orientasi, yakni cara menggabungkan banyak sumber tanpa menghitung satu sensor dua kali, tanpa menyembunyikan ketidakpastian, dan tanpa mengaku memiliki otoritas yang bukan miliknya.
Menara itu sendiri lahir dalam suasana pemulihan. Jika penanggalan lazim benar, ia bagian dari pembangunan kembali Athena setelah kota itu hampir rata akibat legiun Sulla pada 86 SM: pengetahuan tentang angin dan waktu dijadikan infrastruktur sipil, bukan rahasia segelintir orang. Andronikos mengambil sikap serupa dengan satu penegasan modern. Ia menyebut dirinya penyedia “informasi risiko” dan “analisis pendukung”, bukan peringatan resmi, karena UU 31/2009 menempatkan informasi meteorologi pada BMKG. Menara boleh mengorientasikan; yang berwenang memerintahkan tetaplah otoritas.
Lima Prinsip Menara
Orientasi, bukan ramalan
Probabilitas adalah proporsi anggota ensemble yang melewati ambang, bukan kepastian.
Kalibrasi per sisi
Bias dikoreksi menurut variabel, lead, siklus, dan stasiun, dengan pengamatan sebagai acuan.
Kejujuran epistemik
Yang belum diputuskan ditandai terang-terangan, tidak diisi tebakan.
Terlihat di tempat keputusan
Peta, tingkat siaga, atribusi, dan unit keputusan dirancang untuk dibaca, bukan sekadar disimpan.
Hidup lewat beralih guna
Modular: delapan crate, dua topologi deployment, dua jalur ML, siap berganti fungsi.
Menara adalah analogi disiplin, bukan klaim genealogi. Penanggalannya sendiri diperdebatkan (ada dugaan lebih awal, terkait kedermawanan Attalus III dari Pergamon), asal Andronikos dari Kyrrhos di Makedonia atau di tepi Efrat tidak pasti, dan cara kerja persis jam airnya belum terpulihkan.
Rujukan
- Wikipedia, “Tower of the Winds”: sumber utama narasi ini.
- Noble, J. V. dan de Solla Price, D. J. (1968). “The Water Clock in the Tower of the Winds”, American Journal of Archaeology 72(4): 345–355. doi:10.2307/503828
- Webb, P. A. (2017). The Tower of the Winds in Athens: Greeks, Romans, Christians, and Muslims. Memoirs of the American Philosophical Society 270.
- Lawrence, A. W. (1957). Greek Architecture. Pelican History of Art, Penguin.
- Wallace-Hadrill, A. (2022), dalam Rome and the Colonial City: Rethinking the Grid. Oxbow Books.
Butir 2–5 dirujuk sebagaimana dikutip artikel Wikipedia tersebut, bukan dibaca langsung.
Engine 1-Minuten Capability
| Operasi | Waktu | 1 Menit? | Catatan |
|---|---|---|---|
predict_point (1 titik) | 10-50 ms | Ya | Single cell batch forward |
predict_grid (≤10.000 cell) | < 10 ms | Ya | Batch inference dalam satu forward() call |
predict_grid_batch (multi-area) | < 1 menit | Ya | Banyak area, spatial tiling otomatis |
infer_area_distributed (38,9M cell) | < 1 menit* | Ya | *Dengan GPU + spatial tiling + multiple concurrent tile requests |
predict_grid 0.5km penuh (38,9M cell) | > 1 menit | Perlu GPU | Perlu multi-request via tiling |
| ONNX downscale (1 titik) | < 5 ms | Ya | 4 intra-threads, Level3 |
Re-arsitektur yang Diimplementasi
Batch Inference
create_batch_input() membangun tensor [N, features] untuk N cell sekaligus, satu forward() call untuk semua cell. Tidak lagi per-cell sequential.
Mesh Graph
build_mesh_edges() membangun edge_index [2, E] dengan 4-connectivity untuk GNN message passing.
Spatial Tiling
TilingManager::split_area_into_tiles() bagi area besar menjadi tile (default 2,5M cell/tile) dengan overlap untuk konsistensi GNN di batas tile.
Multi-Area Coordinator
TileCoordinator::infer_area_distributed() otomatis split ke tiles, process secara concurrent via futures::future::join_all.
Device Selection
DeviceType (CPU/CUDA/WGPU/Metal) via create_burn_device().
Lead Time Cap
MAX_LEAD_SECONDS = 168 * 3600 enforced di semua entry point.
No unwrap/panic/race
Semua operasi via Result, tidak ada unwrap()/expect()/panic! di non-test code.
// predict_grid_batch untuk banyak area
let areas = vec![
AreaPredictRequest {
area_id: "jakarta".to_string(),
bbox: Bbox::new(106.5, -6.5, 107.0, -6.0),
resolution: 0, // 0.5km
lead_seconds: 3600,
variables: WeatherVariable::surface_variables(),
max_cells: Some(5000),
},
];
let request = BatchGridPredictRequest::new(areas)
.with_device(DeviceType::Cpu)
.with_max_total_cells(10_000);
let output = forecaster.predict_grid_batch(request).await?;
// Distributed Inference untuk Area Besar (38.9M cell)
let result = coordinator.infer_area_distributed(
"indonesia_full",
&Bbox::new(95.0, -11.0, 141.1, 6.1),
0,
3600,
&WeatherVariable::surface_variables(),
).await?;
// result.total_cells = 38.900.000
// result.total_inference_ms < 60.000 (dengan GPU + tiling)
// result.completed_within_target = true
Data Fusion (Anti-Double Counting)
SourceRegistry mencegah double-counting saat runtime:
| Sumber | Role | Dependency Group | Eligible? | Alasan |
|---|---|---|---|---|
met.gfs | BasePhysics | Independent | Ya | Dasar fisika deterministik |
met.gefs | BaseEnsemble | NoaaGefsFamily | Ya | Dasar ensemble probabilistik |
met.aigfs | AiMember | NoaaGefsFamily | Ya | Anggota AI tambahan |
met.aigefs | AiMember | NoaaGefsFamily | Ya | Anggota ensemble AI |
met.hgefs | Excluded | NoaaGefsFamily | Tidak | Gabungan AIGEFS+GEFSv12, tidak independen |
met.bmkg_fc | LocalMember | Independent | Ya | Anggota gabungan lokal |
met.graphcast | Excluded | GraphCastNonCommercial | Tidak | CC BY-NC-SA, tidak komersial |
met.openmeteo | ComparatorOnly | OpenMeteoAggregator | Tidak | Agregasi, tidak independen |
ref.era5 | TrainingOnly | Era5Reanalysis | Tidak | Training + bias correction only |
fire.firms | ModuleSpecific | FireHotspotFamily | Ya | Titik panas |
fire.sipongi | ModuleSpecific | FireHotspotFamily | Ya | Sensor sama dengan FIRMS, hitung sekali |
met.hgefstidak dapat bobot terpisah darimet.gefs+met.aigefs(dependensi NoaaGefsFamily)met.openmeteo= bobot 0 dalam fusion (hanya pembanding)ref.era5= bobot 0 real-time (training only)fire.firms+fire.sipongi= satu sensor, hitung sekalican_have_separate_weight()mencegah dua sumber dalam group yang sama sama-sama menerima bobot non-nol
Alur Penggabungan (5 Langkah)
- Ingest mentah dengan metadata: sumber, lisensi, waktu terbit, waktu berlaku.
- Selaraskan grid, satuan, zona waktu (UTC), nama variabel.
- Saring pengamatan (QC): rentang nilai, konsistensi antar stasiun, data ganda.
- Gabungkan: fisika (GFS/GEFS) sebagai dasar, AI (AIGFS/AIGEFS/BMKG_fc) sebagai anggota tambahan. Bobot dipelajari dari data historis.
- Verifikasi terhadap pengamatan, bukan ERA5.
Pola Pembobotan (Weighting Pattern)
A. Bias Correction (Additive)
x_koreksi = x_prakiraan - b
b_baru = (1 - α) * b_lama + α * (prakiraan - pengamatan)
αdan panjang jendela BELUM DIPUTUSKAN →WIError::BelumDiputuskan- Variabel aditif: suhu 2m, tekanan permukaan laut, angin (u,v), kelembapan (clamp 0-100%)
- Hujan: BUKAN aditif — pakai rasio, clamp ≥ 0
- Semua anggota ensemble pakai
byang sama - Acuan:
obs.bmkg_stn,obs.isd(setelah QC), BUKANref.era5
B. Ensemble Probability
p = (1/M) * Σ(1[x_m > T])
- Hazard function dijalankan pada SETIAP anggota ensemble, baru proporsi dihitung
Mkecil → probabilitas kasar (0 atau 1)
C. Fusion Weight (constraint: Σw = 1, w ≥ 0)
Fusion = w_physics * Base(GFS, GEFS)
+ w_ai * Σ(w_member_i * Member_i) [AIGFS, AIGEFS, BMKG_fc]
+ BiasCorrection(...)
→ Calibrated Probability via Ensemble CDF
Σ w = 1,w ≥ 0, divalidasi olehFusionEngine::validate_weights()- Nilai konkret bobot belum ditetapkan — harus diturunkan dari verifikasi historis
- Fisika (GFS, GEFS) = baseline weight tinggi
- AI members (AIGFS, AIGEFS) = weight tambahan, bukan pengganti fisika
API REST + gRPC
| Endpoint | Method | Deskripsi | Status |
|---|---|---|---|
GET /health | GET | Health check | Working |
POST /v1/predict | POST | Prediksi titik tunggal → FusionOutput | Working |
POST /v1/predict/grid | POST | Prediksi grid tunggal | Working |
POST /v1/predict/grid/batch | POST | Prediksi grid batch multi-area | Working |
POST /v1/predict/grid/distributed | POST | Prediksi distributed 38.9M cell | Working |
GET /v1/model/info | GET | Model metadata | Working |
GET /v1/variables | GET | List 17 WeatherVariable | Working |
gRPC Services
| Service | Type | Deskripsi | Status |
|---|---|---|---|
| Predict | Unary | Prediksi titik tunggal | Working |
| PredictGrid | Unary | Prediksi grid tunggal | Working |
| StreamPredict | Server Streaming | Stream prediksi multi-lead | Working |
Request/Response Schema
// POST /v1/predict Request
{
"latitude": -6.595,
"longitude": 106.806,
"lead_seconds": 3600,
"variables": ["Temperature", "RelativeHumidity", "Precipitation"]
}
// POST /v1/predict Response (FusionOutput)
{
"unit_id": null,
"jenis_unit": null,
"modul": "cuaca",
"terbit": "2026-10-17T00:00:00Z",
"berlaku_dari": "2026-10-17T01:00:00Z",
"berlaku_sampai": "2026-10-17T02:00:00Z",
"lead_seconds": 3600,
"probabilitas": null,
"tingkat_siaga": null,
"anggota": 1,
"versi_model": "GraphCast-1.0.0",
"koreksi_bias": false,
"sumber_id": ["met.graphcast"],
"atribusi": ["DeepMind GraphCast (lokal, dilatih sendiri)"],
"label_istilah": "analisis pendukung",
"klaim": [],
"variables": {
"Temperature": { "weighted_mean": 298.15, "exceedance_probability": null, "member_count": 1, "bias_applied": false }
}
}
Middleware
- JWT RS256 Authentication - scope-based authorization
- Rate Limiting - sliding window, Redis-backed
- CORS - configurable origins
- Request Validation - lat/lon bounds, lead time max (168h), variable names
- Redis Cache - TTL (1hr point, 30min grid), pattern invalidation
- Tracing - structured JSON with cell, model_run, latency
CLI Commands
| Command | Deskripsi | Status |
|---|---|---|
wi sync --hours 24 | Real data sync dengan ParquetSyncEngine | Working |
wi train | GraphCast model initialization + Python training pipeline | Working |
wi predict --latitude -6.595 --longitude 106.806 --lead-seconds 3600 | Real inference dengan GraphCastForecaster | Working |
wi serve --host 0.0.0.0 --port 8080 | API server dengan axum, rate limiting, CORS | Working |
wi verify --model model.bin --data test.parquet | Dashboard generation + Python verification pipeline | Working |
wi export --model model.bin --format onnx --output model.onnx | Export guidance ONNX, TorchScript, TensorRT | Working |
wi info | Model architecture info | Working |
wi ingest | Source registry listing | Working |
Frontend UI (Leptos + MapLibre)
Frontend dibuat di folder andronikos/:
MapLibre GL JS
Bounds dibatasi ke wilayah Indonesia: lat -11.15° to 6.25°, lon 94.95° to 141.25°. maxBounds mencegah panning keluar. maxZoom 10, minZoom 4.
Panel Kiri
Prakiraan cuaca (suhu, kelembapan, curah hujan, angin, tekanan) + Risiko Dampak (longsor/banjir/asap dengan tingkat siaga + probabilitas).
Badge Atribusi
BMKG (terverifikasi), NOAA (terverifikasi), ERA5 (training only), Open-Meteo (dikecualikan dari fusion).
Istilah Baku
"Informasi risiko" / "analisis pendukung", bukan "peringatan resmi" (compliance gate UU 31/2009).
cargo install trunk
cd andronikos/leptos
trunk serve
# Buka http://127.0.0.1:8080
Arsitektur Lengkap (8 Crates)
| Crate | Deskripsi | Status | Key Tech |
|---|---|---|---|
wi-core | Types, errors, units, config, DeviceType, SourceRegistry | 95% | thiserror, serde, chrono |
wi-grid | Geospatial (H3 + FixedGrid 0.5km) | 95% | h3o, geo |
wi-ingest | Data ingestion (7 adapters + bias_correction) | 85% | reqwest, quick-xml, parquet |
wi-storage | Storage (Parquet, PostgreSQL/PostGIS, Redis, .atd) | 80% | sqlx, redis, arrow |
wi-model | ML Inference — DUAL PATH (Burn GraphCast + ONNX + Tiling) | 65% | burn 0.22, ort, rayon |
wi-verify | Verification metrics (MAE, RMSE, Brier, CRPS) | 95% | statrs, ndarray |
wi-api | REST + gRPC (axum + tonic), Redis cache, JWT auth | 75% | axum, tonic, tower-http |
wi-cli | CLI commands (sync, train, predict, serve, verify, export, info) | 80% | clap, tokio |
Data Flow Architecture
SOURCES (7 APIs)
→ wi-ingest (SyncEngine + validation + gap fill)
→ wi-storage (Parquet + PostgreSQL + Redis + .atd)
→ wi-model (Burn GraphCast global + ONNX downscaler + Tiling Coordinator)
→ wi-verify (metrics + baselines)
→ wi-api (REST + gRPC + Redis cache)
│
▼
CONSUMERS: wi-cli, wi-ui (Leptos+Deck.gl), CoalForge (REST+Kafka), External APIs
ML Pipeline — Dual Path
Path 1: Global Model (Burn GraphCast)
12 GNN layers, 8 heads, hidden_dim=256, ~40-60M params. SwiGLU MLP, O(N) Linear Attention (Performer). 17 output heads.
Path 2: Regional Downscaler (ONNX)
Input 14 features → Output 6 vars × 4 quantiles = 24 outputs. ort crate Level3, 4 intra-threads.
Training
Python melatih, Rust menyajikan. PyTorch/Lightning → ONNX/Burn → serve in Rust.
Ingestion Adapters (7 Sources)
| Adapter | Status | Rate Limit | Notes |
|---|---|---|---|
| Open-Meteo | Complete | 10 req/s | Arsip + Forecast |
| NOAA (ISD/GHCN) | Complete | 5 req/s | Token bucket |
| BMKG | Complete | 60 req/min | UU 31/2009 attribution |
| ERA5 | Complete | 1 req/s | CDS API, NetCDF |
| GFS | Complete | 120 req/min | NOMADS, GRIB2 |
| Himawari | Complete | 30 req/min | JAXA/AWS, NetCDF |
| WeatherNext | Complete | 10 req/min | DeepMind allowlist |
Storage Backends (4)
| Backend | Status | Notes |
|---|---|---|
| Parquet | Complete + Wired | Hive partitioning, ZSTD |
| PostgreSQL/PostGIS | Complete | Full schema, spatial queries |
| ATD (custom binary) | Skeleton | bincode+zstd |
| Redis | Skeleton | moka + redis, TTL |
Verification Metrics
| Category | Metrics | Baseline |
|---|---|---|
| Deterministic | MAE, RMSE, Bias, Correlation | Persistence, Climatology, Raw Model |
| Probabilistic | Brier Score, Reliability Diagram, ROC AUC | — |
| Ensemble | CRPS (fair), Spread, Spread-Skill Ratio | — |
| Splits | Temporal, Spatial, Cross-Validation | — |
Grid Systems
| Grid Type | Resolution | Cells (Indonesia) | Status |
|---|---|---|---|
| H3 res 7 | 1.22 km / 5.16 km² | ~7,500 | Siap |
| H3 res 8 | 454 m / 0.74 km² | ~52,000 | Siap |
| FixedGrid 0.0045° | 500 m / 0.25 km² | 38.9M | VERIFIED |
Output Contract (16 Field: 15 Wajib, 1 Opsional)
| Bidang | Isi |
|---|---|
unit_id, jenis_unit | Sub-DAS, unit lereng, atau kelurahan |
modul | longsor, banjir, atau asap |
terbit, berlaku_dari, berlaku_sampai | Waktu UTC |
lead | Jangka waktu prakiraan |
probabilitas | Proporsi anggota ensemble yang melewati ambang |
tingkat_siaga | Hasil gabungan ambang hujan dan kelas kerentanan |
anggota | Jumlah anggota ensemble |
versi_model | Versi model per sumber |
koreksi_bias | Apakah koreksi dipakai atau dikembalikan ke mentah |
sumber_id | Daftar ID dari katalog variabel |
atribusi | Teks atribusi yang wajib |
label_istilah | "Informasi risiko" atau "analisis pendukung" |
klaim | Daftar kode pembeda (D1-D4) yang lulus verifikasi opsional |
Compliance (Wajib)
- UU 31/2009 Pasal 36 ayat 1 + PP 11/2016 Pasal 4: Info meteorologi hanya oleh BMKG, kecuali UU lain.
- Istilah: "informasi risiko" atau "analisis pendukung", bukan "peringatan dini" sebelum izin BMKG.
- Atribusi: BMKG wajib, FIRMS acknowledgment, Copernicus/Open-Meteo atribusi, NOAA tidak boleh disiratkan didukung NOAA.
- Open-Meteo: gratis hanya non-komersial, <10.000 panggilan/hari.
- BMKG: 60 req/min/IP, izin tertulis untuk komersial.
- NOMADS: ~120 hit/min/user, pusatkan unduhan pada satu node dengan rate limiter.
- GraphCast/GenCast bobot: CC BY-NC-SA 4.0 → dikecualikan untuk produk komersial.
Gerbang Sebelum Penyajian
- Istilah keluaran sesuai dan tidak menyebut "peringatan dini" tanpa izin.
- Atribusi lengkap: BMKG wajib, FIRMS acknowledgment, Copernicus/Open-Meteo atribusi.
- Tidak ada sumber berstatus belum dan tidak ada sumber tidak independen yang terhitung dua kali.
- Bahasa probabilitas dan tingkat risiko, tanpa klaim "memprediksi pasti".
- Skor verifikasi pilot sudah melewati ambang kelulusan.
Undecided (JANGAN diisi tebakan)
αdan panjang jendela koreksi bias →BelumDiputuskanerror- Ambang tingkat siaga (longsor/banjir/asap)
- Model sebaran asap
- Indeks kekeringan
- Sumber sungai, tanah, tutupan lahan, drainase, dll.
- BMKG PNBP tariff, PVMBG download rights, GPM/GSMaP licenses
- Commercial product decision
Arsitektur Deployment — Three VPS Topology
Engine didesain untuk berjalan dalam tiga VPS terpisah untuk memisahkan tanggung jawab ingestion, inference, dan API. Untuk development/prototype, semua dapat dijalankan dalam satu VPS.
VPS-1: Data Pipeline
Tugas: Ingest, validasi, penyimpanan, koreksi bias
- wi-ingest (7 adapters)
- wi-storage (Parquet, PostGIS, Redis)
- BiasCorrectionEngine
- Checkpoint sync (SHA256)
VPS-2: ML Engine (GPU)
Tugas: Inferensi GraphCast, tiling, distributed
- wi-model (Burn, ONNX)
- TilingManager + TileCoordinator
- CUDA/WGPU device
- 38.9M cell inference
VPS-3: API + Frontend
Tugas: API gateway, UI, CoalForge integration
- wi-api (REST + gRPC)
- JWT auth, rate limiting
- Leptos + MapLibre UI
- CoalForge decision endpoints
VPS-1 (Data Pipeline) ──┬──────────────┐
│ ▼
└──► [Kafka/Avro Events] ──► VPS-2 (ML Engine GPU) ──► [Kafka] ──► VPS-3 (API + UI)
│ │ │
▼ ▼ ▼
[GraphCast Burn] [ONNX Downscaler] [REST + gRPC + Leptos UI]
│ │ │
▼ ▼ ▼
[Parquet Storage] [Redis Cache] [CoalForge Events]
Single VPS vs Distributed (Three VPS)
| Aspek | Single VPS (Development) | Three VPS (Production) |
|---|---|---|
| Ingestion | Lokal, satu proses | VPS-1 dedicated, 7 adapters parallel |
| Model Inference | CPU only, batch kecil | VPS-2 GPU (CUDA/WGPU), tiling 38.9M cell |
| API Layer | Lokal, axum + tonic | VPS-3 dedicated, JWT + rate limit |
| Storage | Lokal disk | VPS-1 Parquet + PostgreSQL/PostGIS |
| Komunikasi | In-memory function call | Kafka/Avro event streaming |
| Frontend | Trunk serve lokal | VPS-3, built static + API proxy |
# VPS-1: Data Pipeline (Ingestion + Storage)
cargo run --bin wi -- sync --hours 24
cargo run --bin wi -- ingest
# VPS-2: ML Engine (dengan GPU support)
cargo run --bin wi-serve --features cuda -- --port 8081
# VPS-3: API + Frontend
cargo run --bin wi-serve -- --port 8080
# Frontend: trunk serve --public-url https://api.andronikos.id
Diagram Arsitektur
Semua diagram ditulis sebagai teks monospace, jadi tampil identik di setiap browser dan bisa disalin ke dokumen lain.
╔═════════════════════════════════╗
║ SOURCES ║
║ 7 APIs ║
╚═════════════════════════════════╝
│
▼
┌─────────────────────────────────┐
│ wi-ingest │
│ SyncEngine + QC │
└─────────────────────────────────┘
│
▼
┌─────────────────────────────────┐
│ wi-storage │
│ Parquet, PostGIS, Redis │
└─────────────────────────────────┘
│
▼
┌─────────────────────────────────┐
│ wi-model │
│ Burn GraphCast + ONNX │
└─────────────────────────────────┘
│
▼
┌─────────────────────────────────┐
│ wi-verify │
│ Metrics + Baselines │
└─────────────────────────────────┘
│
▼
╔═════════════════════════════════╗
║ wi-api ║
║ REST + gRPC ║
╚═════════════════════════════════╝
│
▼
╔═════════════════════════════════╗
║ CONSUMERS ║
║ CLI, UI, CoalForge ║
╚═════════════════════════════════╝ ┌─────────────────────────┐
│ Sources │
│ (GFS, GEFS, ERA5) │
└─────────────────────────┘
│
┌───────────────────────┴───────────────────────┐
▼ ▼
┌─ PATH 1: Global Model (Burn GraphCast) ─┐ ┌─ PATH 2: Regional Downscaler (ONNX) ────┐
│ │ │ │
│ ┌───────────────────────────────┐ │ │ ┌───────────────────────────────┐ │
│ │ Encoder │ │ │ │ Coarse Forecast + │ │
│ │ surface + atmosphere │ │ │ │ DEM + Land Mask │ │
│ └───────────────────────────────┘ │ │ └───────────────────────────────┘ │
│ │ │ │ │ │
│ ▼ │ │ ▼ │
│ ┌───────────────────────────────┐ │ │ ┌───────────────────────────────┐ │
│ │ 12x GNN Layers │ │ │ │ Feature │ │
│ │ message passing │ │ │ │ Engineering │ │
│ └───────────────────────────────┘ │ │ └───────────────────────────────┘ │
│ │ │ │ │ │
│ ▼ │ │ ▼ │
│ ┌───────────────────────────────┐ │ │ ┌───────────────────────────────┐ │
│ │ 3x Temporal Attention │ │ │ │ ONNX Runtime │ │
│ │ Performer │ │ │ │ Level3, 4 threads │ │
│ └───────────────────────────────┘ │ │ └───────────────────────────────┘ │
│ │ │ │ │ │
│ ▼ │ │ ▼ │
│ ┌───────────────────────────────┐ │ │ ╔═══════════════════════════════╗ │
│ │ Multi-Task Decoder │ │ │ ║ 6 vars x 4 quantiles ║ │
│ │ 17 heads │ │ │ ║ + P(rain) ║ │
│ └───────────────────────────────┘ │ │ ╚═══════════════════════════════╝ │
│ │ │ │
└─────────────────────────────────────────┘ └─────────────────────────────────────────┘┌─ VPS-1: Data Pipeline (Ingestion + Storage) ──────────────────────────────┐
│ │
│ ┌────────────┐ ┌───────────┐ ┌─────────────────────────┐ │
│ │ 7 Adapters │────►│ wi-ingest │────►│ wi-storage │ │
│ └────────────┘ └───────────┘ │ Parquet, PostGIS, Redis │ │
│ └─────────────────────────┘ │
│ ┆ │
│ ▲ │
│ ┌─────────────────┐ │
│ │ BiasCorrection │ │
│ └─────────────────┘ │
│ │
└───────────────────────────────────────────────────────────────────────────┘
│ Kafka/Avro
▼
┌─ VPS-2: ML Engine (GPU, CUDA/WGPU) ───────────────────────────────────────┐
│ │
│ ┌────────────────┐ ┌─────────────────┐ │
│ │ Burn GraphCast │────►│ ONNX Downscaler │ │
│ └────────────────┘ └─────────────────┘ │
│ │
│ ┌────────────────┐ ┌─────────────────┐ │
│ │ TilingManager │────►│ TileCoordinator │ │
│ └────────────────┘ └─────────────────┘ │
│ │
└───────────────────────────────────────────────────────────────────────────┘
│ Kafka/Avro
▼
┌─ VPS-3: API + Frontend ───────────────────────────────────────────────────┐
│ │
│ ┌─────────────┐ ┌──────────────────┐ │
│ │ wi-api │────►│ JWT + Rate Limit │ │
│ │ REST + gRPC │ └──────────────────┘ │
│ └─────────────┘ │ │
│ │ │
│ ┌───────────────────┘ │
│ ▼ │
│ ┌───────────────────┐ ╔══════════════════╗ │
│ │ Leptos + MapLibre │────►║ CoalForge Events ║ │
│ └───────────────────┘ ╚══════════════════╝ │
│ │
└───────────────────────────────────────────────────────────────────────────┘met.gfs Base Physics ──────────────────────────┐ ┌────────────────────────────┐
met.gefs Base Ensemble ──────────────────────────┤ │ │
met.aigfs AI Member ──────────────────────────┼──►│ │
met.aigefs AI Member ──────────────────────────┤ │ Source Registry │
met.bmkg_fc Local Member ──────────────────────────┘ │ can_have_separate_weight() │
│ │
met.hgefs Excluded ┄┄ Blocked: Dependency ┄┄┄┐ │ │
met.openmeteo Excluded ┄┄ Blocked: Aggregator ┄┄┄┼┄┄►│ │
ref.era5 Training Only ┄┄ Blocked: Training ┄┄┄┄┄┘ └────────────────────────────┘
───► masuk fusion (bobot terpisah) ┄┄► diblokir ┌─ Bias Correction (Additive) ────────────────────────────────────────────┐
│ │
│ ┌───────────────────────────────┐ │
│ │ x_prakiraan │ │
│ └───────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────┐ ┌───────────────────────────────┐ │
│ │ b (bias per variabel x │┄┄┄┄►│ b_baru = (1-α)·b_lama + │ │
│ │ lead x siklus x stasiun) │ │ α·(prakiraan - pengamatan) │ │
│ └───────────────────────────────┘ └───────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────┐ │
┌──┼─┤ x_koreksi = x_prakiraan - b │ │
│ │ └───────────────────────────────┘ │
│ │ │
│ └─────────────────────────────────────────────────────────────────────────┘
│
│ ┌─ Ensemble Probability ──────────────────────────────────────────────────┐
│ │ │
│ │ ┌───────────────────────────────┐ │
│ │ │ M anggota ensemble │ │
│ │ └───────────────────────────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌───────────────────────────────┐ │
│ │ │ Hazard pada setiap anggota │ │
│ │ └───────────────────────────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌───────────────────────────────┐ │
│ │ │ p = (1/M) · Σ(1[x_m > T]) │ │
│ │ └───────────────────────────────┘ │
│ │ │ │
│ └─────────────────┼───────────────────────────────────────────────────────┘
│ │
│ ▼
│ ╔═════════════════════╗
└────────►║ Fusion Output ║
║ FusedVariable ║
╚═════════════════════╝╔═══════════════════════╗ ║ FusionOutput Contract ║ ╚══╤════════════════════╝ │ ├── unit_id / jenis_unit [wajib] ├── modul [wajib] ├── terbit / berlaku_dari / berlaku_sampai [wajib] ├── lead [wajib] ├── probabilitas [wajib] ├── tingkat_siaga [wajib] ├── anggota / versi_model [wajib] ├── koreksi_bias [wajib] ├── sumber_id / atribusi [wajib] ├── label_istilah [wajib] └── klaim (D1-D4) [opsional]
Lewati ke konten