Skip to content

Synthetic Networks From GeoJSON

Gridalyn can build a synthetic distribution network from building-footprint GeoJSON. This path is useful when a utility-grade GIS model is unavailable but you still need a reproducible topology for studies, demos, or early digital twin development.

Data Sources

Two footprint sources are supported by the examples:

Source How Gridalyn uses it Notes
OpenStreetMap through OSMnx BuildingDownloader queries OSM features with building=True inside a polygon and writes a local GeoJSON. OSMnx returns a GeoPandas GeoDataFrame from the OpenStreetMap Overpass API. The OSM building=* tag describes physical buildings and includes broad categories, so inspect local data quality before treating tags as customer classes.
Microsoft Global ML Building Footprints prepare_microsoft_building_footprints.py converts a local line-delimited GeoJSON partition to regular clipped GeoJSON. Microsoft publishes open building footprints derived from imagery under CDLA Permissive 2.0. Many partitions are .csv.gz files whose contents are GeoJSON lines, so convert and clip them before using them as study inputs.

The repository does not track heavyweight source downloads. Keep raw OSM or Microsoft source files outside Git, then write filtered outputs under a project input folder or examples/generated/outputs/ for tutorial work.

Flow

flowchart LR
    osm[OSMnx / OSM buildings] --> raw[Raw building footprints]
    ms[Microsoft footprint partition] --> raw
    raw --> clip[Clip to study polygon]
    clip --> geojson[Building GeoJSON]
    geojson --> bundle[Gridalyn topology bundle]
    bundle --> pp[pandapower network]
    pp --> twin[Digital twin base artifacts]

The canonical footprint preparation entry point is gridalyn.twin.adapters. The canonical network-generation entry point is gridalyn.simulation.build_synthetic_network_from_geojson.

Project API

Projects should call the SDK builder instead of duplicating the tutorial script steps:

from pathlib import Path

from gridalyn.simulation import build_synthetic_network_from_geojson

result = build_synthetic_network_from_geojson(
    footprints_path=Path("projects/my_project/inputs/buildings.geojson"),
    config_path=Path("configs/grid/config.json"),
    out_dir=Path("projects/my_project/outputs/cache"),
    clustering_crs="auto",
    write_cache=True,
    run_powerflow=True,
)

The function returns:

Field Meaning
power_grid Generated topology bundle used by Gridalyn simulation and visualization helpers.
net The generated pandapower network.
validation_report Counts, CRS lineage, source hashes, topology checks, and optional power-flow convergence.
report_path Path to synthetic_network_validation.json when out_dir is provided.

Use clustering_crs="auto" for normal GeoJSON inputs. It estimates a local metric CRS for K-Means and MST distances while preserving longitude/latitude on graph nodes for maps and digital-twin geodata.

Capacity-constrained LV assignment (opt-in)

By default the builder works out how many MV/LV transformers the footprints need, then lets K-Means decide which buildings each one serves. K-Means partitions by geometry alone, so some transformers serve far more buildings than they were sized for: on the shipped Trois-Rivieres footprints, 43 of 193 sit above 100% at the declared envelope.

Pass lv_assignment="capacitated" to cap every transformer at ceil(buildings / transformers) buildings, the count the transformer number was sized for. The validation report then gains an lv_assignment block with the limit, the buildings-per-transformer distribution, and any transformer still above its rated kVA. Adding block_penalty_km2=0.005 also keeps clusters from straddling streets; it needs the geo extra and a street-network fetch, because it works from the blocks the streets enclose.

Both options default off. They change which buildings share a transformer, so turning them on for an existing study is a deliberate re-base, not a display change.

Declaring topology in the grid config

A study pins these choices as data instead of passing arguments. The grid config accepts a topology block with lv_assignment, max_customers_per_transformer (a limit the study can cite, which wins over the sized count), block_penalty_km2, snap_transformers_to_streets and street_layer, plus an external_grid block whose vm_pu sets the slack setpoint (1.0 pu when absent). An explicit argument to the builder overrides the config. A config without either block builds exactly what it built before.

A live fetch from OpenStreetMap is not reproducible, because the map changes. Write the streets once with python tools/snapshot_streets.py --footprints <buildings.geojson> --out <streets.geojson>, commit the file beside the footprints with its OpenStreetMap attribution, and declare street_layer as its path (relative to the footprints file's directory) and the printed sha256. The build refuses a layer whose digest no longer matches, and because the digest lives in the config, a changed layer also changes the config hash every topology cache keys on.

Offline Smoke Test

Run the synthetic generator example:

MPLCONFIGDIR=/tmp/matplotlib-cache \
uv run python examples/tutorials/basic_grid_creation.py

It generates fake building footprints, creates LV/MV/HV graphs, and writes the footprint GeoJSON, the topology/network caches, and synthetic_network_validation.json under examples/generated/outputs/basic_grid_creation/. It does not render maps.

Run the bundled real-footprint example:

MPLCONFIGDIR=/tmp/matplotlib-cache \
uv run python examples/tutorials/create_grid_from_real_data.py

It reads the packaged Trois-Rivieres tutorial footprint sample, builds a pandapower model, runs diagnostics, and writes generated tutorial artifacts under examples/generated/outputs/.

Clip Existing Footprints

Use this when you already have GeoJSON from OSMnx, Microsoft after conversion, or another source:

MPLCONFIGDIR=/tmp/matplotlib-cache \
uv run gridalyn twin clip-buildings \
  --buildings-file examples/tutorials/data/example_buildings.geojson \
  --polygon-file configs/geography/tr01.json \
  --output-file examples/generated/outputs/buildings_inside_polygon.geojson

You can pass a custom polygon file:

uv run gridalyn twin clip-buildings \
  --buildings-file path/to/buildings.geojson \
  --polygon-file configs/geography/tr01.json \
  --output-file projects/my_project/inputs/buildings.geojson

The polygon file can be one of:

  • a JSON file with polygon_coordinates;
  • a GeoJSON Polygon;
  • a GeoJSON Feature whose geometry is a Polygon.

Download From OSMnx

Use this only when you want to query OpenStreetMap through Overpass:

uv run gridalyn twin download-osm-buildings \
  --polygon-file configs/geography/tr01.json \
  --output-file examples/generated/outputs/osmnx_buildings.geojson

Network access and Overpass availability determine whether this command succeeds. For reproducible projects, commit a small input manifest and keep the raw downloaded source outside Git.

Prepare Microsoft Building Footprints

After downloading the relevant Microsoft partition locally, convert and clip it:

uv run gridalyn twin prepare-microsoft-buildings \
  --input-file /path/to/microsoft-partition.csv.gz \
  --polygon-file configs/geography/tr01.json \
  --output-file projects/my_project/inputs/buildings.geojson

Use --limit 1000 for a fast smoke test on a large partition.

Quality Checks

Before using footprints as digital-twin inputs:

  1. Filter to Polygon and MultiPolygon geometries.
  2. Validate geometries and repair invalid polygons.
  3. Clip to the study boundary.
  4. Inspect the footprint count and map.
  5. Confirm CRS is WGS84 or explicitly projected before area-sensitive work.
  6. Store source lineage in the project manifest.

References