City-Scale 3D Solar Digital Twin for Rooftop Solar Potential Analysis
A 3D city-scale solar analysis platform that combines building footprints, LiDAR elevation data, roof geometry, automated solar-panel placement, and interactive 3D visualization to estimate rooftop solar potential and future electricity generation across an entire city. The prototype is currently being developed using London as the initial test environment.

Building a City-Scale Solar Digital Twin
The idea behind this project started with a simple question:
How much electricity could an entire city generate if its usable rooftops were covered with solar panels?
Answering that accurately is much harder than simply measuring the size of a roof.
A real solar-potential system needs to understand the height of every building, the actual geometry of each roof, which direction the roof faces, how steep it is, how much of it is usable, how many solar panels can physically fit, and eventually how much sunlight reaches those panels throughout the day.
That is what this project is designed to solve.
The goal is to create a 3D solar digital twin of a city, where every building can be selected and analysed individually while also contributing to larger neighbourhood, district, and city-wide energy calculations.
The first prototype is being developed using London.
Starting with the 3D City
The frontend of the application is built with Next.js, React, TypeScript, and CesiumJS.
Cesium provides the interactive 3D environment where users can move around the city, zoom between neighbourhoods, rotate the camera, and select individual buildings.
At the beginning of development, Cesium's OpenStreetMap 3D Buildings layer was used to create the visual city environment.
However, an important architectural decision was made very early:
The visual 3D building should not be treated as the analytical building.
Cesium is responsible for visualization, while the scientific calculations are based on dedicated geographic datasets stored in our own database.
This separation allows the system to maintain accurate analytical information without depending on the visual representation of the building.
Building a Local Geographic Database
The first analytical dataset comes from OpenStreetMap.
Instead of sending an external API request every time a user selects a building, the Greater London OpenStreetMap dataset is downloaded through Geofabrik and imported into a local PostgreSQL database using osm2pgsql.
The database uses the PostGIS extension, giving PostgreSQL the ability to perform geographic and spatial calculations.
Each building can therefore contain information such as:
OpenStreetMap ID
building footprint
building name
building type
number of floors
address information
geographic coordinates
footprint area
When a user clicks a building in Cesium, the application obtains the clicked longitude and latitude and sends them to a Next.js API route.
PostGIS then performs a spatial lookup to determine which real building footprint corresponds to the selected 3D building.
The matched footprint is displayed on the map and its information appears in the application dashboard.
This means the system is no longer dependent on public services such as the Overpass API for everyday building queries.
Moving Beyond Estimated Building Heights
OpenStreetMap sometimes contains a building height, but for many buildings that information is missing.
Some buildings contain only the number of floors.
A basic approximation could be made using something such as:
number of floors × 3 metres
but that is not accurate enough for a serious solar and shadow simulation platform.
To solve this, the project uses LiDAR elevation data.
Two different raster datasets are used.
The Digital Terrain Model, or DTM, represents the ground surface.
The Digital Surface Model, or DSM, represents the top surface of the environment and therefore includes buildings, vegetation, and other objects.
By comparing the elevation values from these two datasets, the system can calculate the measured height of a building.
For example:
Roof elevation − Ground elevation = Building height
This makes it possible to replace rough floor-based estimates with measurements derived from real geospatial survey data.
The project currently uses Environment Agency LiDAR data stored in British National Grid coordinates.
Python scripts built with Rasterio, NumPy, Shapely, and psycopg process each building footprint and store the resulting measurements back into PostGIS.
For each analysed building, the database can now contain values such as:
ground elevation
typical roof elevation
95th-percentile roof elevation
LiDAR-derived building height
height source
A fallback system remains available so that buildings without LiDAR information can still use OpenStreetMap height or floor-based estimates.
Understanding the Roof
Knowing the height of the building is only part of the problem.
For solar analysis, the roof itself needs to be understood.
The DSM is therefore processed again to calculate the elevation gradient across each rooftop.
From this information, the system calculates:
roof slope
roof direction
flat-roof percentage
roof surface area
dominant roof orientation
Roof direction is represented using an azimuth value.
For example:
0° represents North
90° represents East
180° represents South
270° represents West
This is important because two roofs with the same area can have very different solar-generation potential depending on their direction and slope.
Splitting Buildings into Individual Roof Planes
Real buildings rarely have one simple roof surface.
A building might contain a south-facing pitched section, a north-facing section, a flat central roof, and several smaller structures.
Because of this, the system does not simply calculate one average roof direction for the entire building.
Instead, the DSM pixels are grouped according to their slope, orientation, and spatial connectivity.
This creates separate roof planes.
Each roof plane is stored independently in PostGIS and contains information such as:
roof-plane geometry
slope
azimuth
horizontal area
actual surface area
whether the roof section is flat
A single building can therefore contain several roof planes with completely different solar characteristics.
This is a major step toward accurate panel placement.
Calculating Solar-Usable Roof Area
Not every square metre of rooftop can contain a solar panel.
The platform therefore applies several constraints before calculating available solar area.
Roof sections that are too small can be rejected.
Safety and maintenance setbacks are added around roof boundaries.
Different packing assumptions are used for pitched roofs and flat roofs.
Flat roofs require additional spacing because solar panels are normally tilted and rows can cast shadows onto each other.
The system then calculates the usable roof surface area for every suitable roof plane.
At this stage, it can already estimate how many solar panels could fit on the roof and calculate the approximate installed peak capacity.
Moving from Estimated Capacity to Real Panel Placement
Area-based capacity estimates are useful, but they are still estimates.
The project therefore goes one step further by generating actual solar-panel polygons.
A generic modern solar module is currently used during development, with approximate dimensions of:
1.134 m × 1.722 m
and a power rating of:
430 W
The placement algorithm attempts to fit individual panel rectangles inside each usable roof plane while respecting:
roof boundaries
setbacks
panel dimensions
panel orientation
panel spacing
roof tilt
roof azimuth
flat-roof row spacing
Every successfully placed panel becomes its own geographic object stored in PostGIS.
Each virtual panel contains information such as:
panel ID
building ID
roof-plane ID
panel geometry
panel dimensions
power rating
tilt
azimuth
This means the system can move beyond saying:
“This building could support approximately 100 panels.”
Instead, it can say:
“These are the exact 87 panel positions that fit within the analysed roof geometry.”
The installed solar capacity can then be calculated directly from the number of successfully placed modules.
Visualizing Solar Panels in the 3D City
The placed panel geometries are exposed through the Next.js backend and loaded into Cesium.
When a user selects a processed building, the application can retrieve the corresponding panel layout from PostGIS and draw those panels over the 3D building.
This provides a direct visual connection between the analytical model and the city map.
The user can therefore select a building and inspect:
building information
footprint area
measured building height
ground elevation
roof elevation
roof planes
usable solar area
number of placed panels
installed solar capacity
The user interface also contains independent loading states so that geographic information and panel information can load without blocking the rest of the map.
The Next Major Stage: The Sun
The next stage of the project introduces the most dynamic part of the digital twin: the Sun.
The application will calculate the real solar position using:
geographic location
date
time
timezone
The Sun will have a real azimuth and elevation based on its actual position in the sky.
The same Sun position can then be represented visually in Cesium.
Users will eventually be able to move a time slider and watch the Sun travel across the city.
As the Sun moves, shadows from surrounding buildings, roof structures, terrain, and eventually vegetation will also change.
From Visual Shadows to Analytical Shadows
The visual shadow shown by the 3D engine is useful for the user experience, but it should not be treated as the scientific result.
The analytical system will independently determine whether sunlight reaches each roof plane or solar panel.
This can be done by tracing the direction between a panel and the Sun and checking whether another object blocks that path.
This creates a shading factor that can change throughout the day.
For example, one panel may receive full direct sunlight at midday while another panel on the same building may be partially shaded by a neighbouring tower.
Tree shading can also be included once vegetation geometry is added to the model.
Calculating Actual Solar Electricity Generation
Sunlight intensity is different from Sun position.
The Sun may be visible, but cloud cover and atmospheric conditions can dramatically change how much energy reaches the solar panel.
The final energy model will therefore combine the geometric Sun model with irradiance data.
Solar-weather datasets such as PVGIS can provide information including:
global horizontal irradiance
direct normal irradiance
diffuse irradiance
temperature
historical solar conditions
The project will eventually use a solar modelling library such as pvlib to calculate the amount of solar radiation reaching each panel.
Electricity generation can then account for:
panel surface area
panel efficiency
tilt
azimuth
solar irradiance
shading
temperature
inverter losses
cable losses
other system losses
From One Building to an Entire City
One of the main objectives of this project is scalability.
The smallest analytical unit is an individual solar panel.
Those values can then be aggregated upward.
For example:
Panel → Roof Plane → Building → Street → Neighbourhood → District → City
The final dashboard could therefore display information such as:
number of analysed buildings
total available rooftop area
solar-usable rooftop area
total number of possible panels
installed peak capacity
current generation
today's generated energy
monthly generation
annual generation
generation by neighbourhood
generation by individual building
The 3D city can also be colour-coded to create a solar heatmap.
Buildings with excellent solar potential could appear differently from heavily shaded or unsuitable buildings.
Building the Digital Twin Efficiently
An important part of the architecture is deciding which calculations happen in real time and which calculations happen beforehand.
Heavy operations such as:
LiDAR processing
building-height calculations
roof segmentation
panel placement
annual shadow analysis
should not be repeated every time a user opens the application.
Instead, these operations are performed as offline batch-processing jobs.
The calculated information is saved into PostGIS.
The web application then retrieves those prepared results very quickly.
This makes it possible to eventually analyse hundreds of thousands of buildings while still providing a responsive interactive 3D experience.
Current Progress
The current prototype already supports the core geospatial pipeline.
A 3D London environment is running in Cesium.
Buildings can be selected interactively.
The selected visual building can be matched to its real OpenStreetMap footprint.
Greater London building data is stored locally in PostGIS.
LiDAR DSM and DTM data can be processed to calculate measured building heights.
Roof slope, orientation, area, and flat-roof characteristics can be extracted.
Buildings can be split into individual analytical roof planes.
Suitable solar roof area can be calculated.
Solar panels can be automatically positioned and stored as individual geographic polygons.
The panel geometry can then be returned to the frontend for visualization in the 3D city.
The current workflow is being validated on a smaller set of London buildings before the processing system is expanded across the full city.
Long-Term Goal
The long-term goal is to create a complete city-scale solar digital twin capable of answering questions such as:
How much rooftop solar capacity exists in this city?
Which buildings have the highest solar potential?
How many solar panels could realistically be installed?
How much electricity could those panels generate today?
How does generation change throughout the year?
How much generation is lost because of building or tree shadows?
What is the total current solar output of an entire neighbourhood or city?
By combining GIS, LiDAR, 3D visualization, solar modelling, and spatial databases, the platform is designed to turn an entire city into an interactive renewable-energy simulation.