Skip to content

Instantly share code, notes, and snippets.

@nazt
Last active May 7, 2026 06:35
Show Gist options
  • Select an option

  • Save nazt/2311a0e7341b1d828a9beaf03da4c21d to your computer and use it in GitHub Desktop.

Select an option

Save nazt/2311a0e7341b1d828a9beaf03da4c21d to your computer and use it in GitHub Desktop.
Volt Oracle — D2 Building Type plan (TingTing canonical 21 tasks, 2026-05-07)
name D2 — Deliverable 2 spec (C40)
date 2026-05-07
due 2026-05-11
source nazt_ Discord 2026-05-07 06:01Z

Deliverable 2 — Amount of solar energy penetration / current solar adoption

Quantified, analysed, illustrated.

Requirements

  • Innovative approach to determine solar penetration in Bangkok. Methodology appropriate to scope + limited time.
  • Quantify installed capacity of rooftop solar:
    • Power: kW, MW
    • Energy generation: kWh, MWh
  • Aggregate per Building Type (residential, small commercial, medium, large, specific commercial)
  • Other groupings allowed — but C40 approval at kickoff

Building Type criteria (per MEA)

Naming convention — use "Building Type" (capitalized, not "building typology")

Type Name Includes
1 Residential households, temples, religious residences/places of worship, residential dormitories
2 Small Commercial small businesses — retail shops, offices
3 Medium Commercial moderate-electricity-consumption businesses
4 Large Commercial industrial factories, department stores, large enterprises
5 Specific Commercial hotels, apartments, shopping malls, gas stations, cinemas

Definition by Roof Area Rule (chosen methodology — per April BMA meeting)

Note — Type 5 changed from "Specific Commercial" → "BMA Buildings" (owner-based, not roof-area). Uses "Other groupings allowed" clause from D2 spec. Hotels/malls/apartments fold into Type 4.

Type 1 — Residential

  • Roof area < 200 sq.m. AND not on main public road
  • OSM highway = residential / service / living_street
  • Captures: detached houses, townhouses, semi-detached, rowhouses, in-soi shophouses, low-rise apartments, religious buildings
  • ~67% of Bangkok's 3.26M buildings (after Shophouse Rule)
  • Tariff 1 บ้านอยู่อาศัย — 31.5% MEA load (17,814 GWh 2024)

Type 2 — Small Commercial / Shophouse

  • EITHER
    • (a) Shophouse on main road — aspect ratio 1:3+, 48–120 sq.m. per unit, OSM highway = primary/secondary/tertiary, no front setback (Shophouse Rule)
    • (b) Any building 200–500 sq.m. roof area
  • Captures: small offices, retail, restaurants, clinics, small markets
  • Tariff 2 กิจการขนาดเล็ก (<30 kW) — 14.1% MEA load (7,963 GWh 2024)

Type 3 — Medium Commercial

  • Roof area 500–2,000 sq.m.
  • Aspect ratio + height proxy refines factory vs office
  • Captures: mid-rise offices, mid-size shopping centers, condominium common areas, hotels, private schools, mid-size markets/factories, warehouses
  • Tariff 3 กิจการขนาดกลาง (30–999 kW) — 16.1% MEA load (9,078 GWh 2024)
  • Mapped via BMA Type ข–ค thresholds (>2,000 sq.m. floor or >15m tall)

Type 4 — Large Commercial / Industrial

  • Roof area > 2,000 sq.m. OR building height > 23m (high-rise via shadow length)
  • Captures: large factories, big-box malls, large hotels/hospitals, high-rise offices/condos, airports, mass transit stations, large warehouses
  • Highest solar potential per building
  • Tariff 4 กิจการขนาดใหญ่ (≥1,000 kW) — 32.2% MEA load (18,178 GWh 2024)
  • Plus partial Tariff 5 Specific Business (hotels) — 3.8%

Type 5 — BMA Buildings (owner-based, not roof-area)

  • Owned/operated by BMA: district offices, BMA schools/vocational, BMA hospitals, fire stations, public works depots, parks/sports facilities
  • Match Google Open Buildings footprint → BMA asset register (needed from BMA)
  • Any roof size
  • Tariff 6 ส่วนราชการและองค์กรฯ — 0.3% MEA load (~152 GWh 2024)
  • Caveat: some BMA facilities sit in T2/T3/T4 by demand (per April BMA meeting)

Decision tree (proposed)

Building (Google Open Buildings V3 footprint)
  │
  ├─ Owner ∈ BMA asset register? → Type 5 (BMA)
  │
  ├─ Roof area > 2000 OR height > 23m? → Type 4 (Large)
  │
  ├─ Roof area 500–2000? → Type 3 (Medium)
  │
  ├─ Shophouse rule (aspect 1:3+, 48–120 sq.m., main road, no setback)
  │   OR roof area 200–500? → Type 2 (Small)
  │
  └─ Roof area < 200 AND OSM highway ∈ {residential/service/living_street}
        → Type 1 (Residential)

Inputs needed

  • ✅ Google Open Buildings V3 footprints (have, Mar 30)
  • ✅ MEA tariff load 2024 (have)
  • ✅ BMA asset register — BKK_by_official/ shapefile bundle (received 2026-05-07, see N3)
  • ✅ OSM highway tags (free, fetch via Overpass)
  • ⏳ Building height — ARKKRA shadow-length output (use if exists, else NULL → treat <23m per N4)
  • ✅ PV detection (51,488 polygons, deliverable-v2)

Source of Truth (decided 2026-05-07)

Building count: 31,249 buildings (Feb 11, 2026 baseline)

Number Unit File Use
31,249 BUILDINGS ψ/lab/solar-roof-poc/deploy/solar-buildings.geojson ✅ SoT for D2
57,170 panel polygons (input) ml/scan-results/solar-panels-seg.geojson input only
51,488 panel polygons (Apr v6l) ml/l5-pv-detection/apps/solar-dashboard/public/erc-data/v6l-detections-v3.geojson dashboard only — wrong unit for typology
79,889 raw v6l detections (pre-filter) raw

Rule — D2 deliverable must report at building level. 31,249 = only number at building unit. Stretch goal: re-run building_solar_join.py on v6l-detections-v3 → updated count using newer model. Defer if time-blocked.

D2 work plan — canonical 21 tasks (TingTing 2026-05-07)

Supersedes Tasks 1, 6, 7 of raw/Deliverable-2-Action-Plan.md. Source: raw/Deliverable-2-Nat-TODO.md Critical path: N4 → N5 → N9 → N15 Estimate: 10–12 working days @ 30% allocation

Phase 1 — Data prep (3–4 days)

  • N1 Pull Google Open Buildings V3 → clip BKK 50-district → PostGIS bkk_buildings_raw
  • N2 Pull OSM road network → tag highway class → PostGIS bkk_roads + spatial index
  • N3 ✅ UNBLOCKED — BMA register received as BKK_by_official/ ESRI shapefile bundle
    • EPSG:32647 (UTM 47N), TIS-620 encoded (encoding='cp874')
    • Most files .rar — extract first
    • POINT geom — spatial join nearest footprint within 30 m → is_bma_asset=True
    • dcode = BMA district code
    • Layers: Administration/{bma_office,bma_zone,bma_training}, Education/{bma_school,bma_library,bec_school,daycare,pre_center,youth,groundsport}, Health/{bma_hos,health_center,health_branch,mhc}, Disaster Prevention/{fire_station,pump_station,floodgate}, Landuse/{bma_housing,community,commuhouse}

Phase 2 — Classification (2–3 days)

  • N4 Compute features per footprint: roof_area_m2, aspect_ratio, dist_to_main_road_m (ST_Distance), front_setback_m, height_proxy_m (ARKKRA shadow output, NULL → <23m)
  • N5 Implement cascade in scripts/classify_buildings_5types.py (✅ scaffolded ef5d396) — first match wins
  • N6 Write data/bangkok_buildings_classified.geojson + PostGIS bkk_buildings_classified — columns: building_id, geom, roof_area_m2, aspect_ratio, dist_to_main_road_m, height_proxy_m, building_type, district
  • N7 Validate — hand-label 100 random buildings (Esri + Street View), confusion matrix, target ≥85% top-1

Phase 3 — PV matching + quantification (2 days)

  • N8 Spatial join 31,249 PV-positive buildings × bkk_buildings_classified (ST_Intersects centroid). Unmatched <2% → nearest-neighbour 20m or flag "unclassified"
  • N9 Aggregate data/pv_by_building_type.csv (10 cols):
    building_type, total_buildings, solar_buildings_detected,
    solar_buildings_registered_est, total_panel_area_m2,
    total_capacity_kWp, annual_generation_GWh,
    penetration_rate_detected_%, penetration_rate_registered_%, co2_avoided_tCO2
    
    • solar_buildings_registered_est = apportion MEA 19,484 BKK across types by detected shares
    • sanity: ΣkWp ±30% MEA 628 MW
  • N10 Emit data/summary_kpis.json (one entry per type)

Phase 4 — Dashboard extension (3–4 days)

  • N11 Rebuild PV PMTiles layer with building_type + capacity_kWp properties (from classified geojson + PV detections + pmtiles convert)
  • N12 5-color C40 brand palette (MapLibre paint expression on building_type):
    • 🟢 #03c245 T1 Residential
    • 🟡 #fed939 T2 Small/Shophouse
    • 🔵 #23bced T3 Medium
    • 🔴 #ff614a T4 Large/Industrial
    • 🟣 #7e65c1 T5 BMA
  • N13 Legend (top-right) + filter sidebar (left) — 5 toggleable checkboxes, default all on, MapLibre setFilter
  • N14 Click popup on PV markers — building type label, roof_area, kWp, district. Bilingual TH/EN
  • N15 KPI strip (top of page) — 5 cards reading summary_kpis.json — count + MW + GWh/yr per type. Total row at right edge
  • N16 District choropleth — STUB ONLY (disabled toggle, "coming soon" tooltip)
  • N17 Mobile responsive (Chrome devtools, iPhone 13 + Pixel 7) + WCAG 2.1 AA (contrast + keyboard nav)
  • N18 Deploy preview URL → review by Warisara + Teerapong → public push

Phase 5 — Handover (1–2 days)

  • N19 data/SCHEMA.md — column docs for classified.geojson + pv_by_building_type.csv (schema stability for Warisara)
  • N20 Validation note — sample size, accuracy by type, known limitations
  • N21 Standup demo + sign-off from Warisara before public URL

Locked formulas

capacity_kWp = panel_area_m² × 0.200          # 200 W/m² → kWp
annual_kWh   = capacity_kWp × 1,506           # 5.5 PSH × 365 × 0.75 PR
co2_tCO2     = (annual_kWh / 1000) × 0.4999
penetration_rate_% = solar_buildings / total_buildings × 100

Reuse before writing new

  • solar_impact_corrected.py — CO₂ formula already
  • analyze_bangkok_capacity.py — reads MEA Bangkok-only CSVs

Out of scope (D2)

  • Per-district 50-breakdown (deferred to Phase 2 → STUB)
  • Growth-trend 2022–2025 (Warisara, Action Plan Task 5)
  • Solar potential (= D3)
  • Re-engineering ML model (use ARKKRA 31,249 as-is)

CSV schema (proposed)

building_id, lat, lon, district, mea_zone,
roof_area_m2, height_m_estimate,
osm_highway_class, aspect_ratio, on_main_road,
owner_bma (bool), building_type (1-5),
pv_detected (bool), pv_area_m2_total, pv_kw_estimate,
pv_kwh_yr_estimate, n_pv_polygons, max_confidence
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment