Files
geointel/docs/ANALYSIS_SPECIFICATIONS.md
Jens faeb58ef6d
GeoIntel release gates / Compile, test, contracts and builds (push) Successful in 1m49s
GeoIntel release gates / Python and npm vulnerability policy (push) Successful in 21s
GeoIntel release gates / Production AI image, SBOM and container scan (push) Successful in 5m39s
GeoIntel release gates / Deploy exact gated revision to Unraid (push) Failing after 58m43s
Initial public release
2026-08-31 21:56:53 +02:00

251 lines
5.6 KiB
Markdown

# GeoIntel Kempen — Analysis Specifications v1.0
This file defines exact inputs, outputs and formulas for the first implementation of the analysis engine.
## Global rules
- All area-based metrics must be calculated in a projected CRS suitable for Belgium/Flanders, preferably EPSG:31370 internally for metric calculations.
- Store geometries consistently and transform only at API/render boundaries when needed.
- All metrics must include unit, input dataset ids, analysis run id and calculation parameters.
- Never let the AI copilot invent metrics. Metrics must come from the analysis engine.
## AreaAnalyzer
### Input
- Area polygon.
### Output metrics
| Key | Unit | Formula |
|---|---|---|
| `area_m2` | m² | `ST_Area(area.geometry)` |
| `area_km2` | km² | `area_m2 / 1_000_000` |
| `perimeter_m` | m | `ST_Perimeter(area.geometry)` |
| `bbox` | geometry/json | calculated bounds |
## BuildingAnalyzer
### Input
- Area polygon.
- Building polygons from GRB, OSM, user vector layer, or AI segmentation/detection polygons.
### Processing
1. Clip building geometries to area.
2. Remove invalid geometries or repair with `make_valid`.
3. Calculate per-building clipped area.
4. Aggregate.
### Output metrics
| Key | Unit | Formula |
|---|---|---|
| `building_count` | count | number of building features intersecting area |
| `building_area_total_m2` | m² | sum clipped building area |
| `building_area_total_ha` | ha | `building_area_total_m2 / 10000` |
| `building_coverage_ratio` | ratio | `building_area_total_m2 / area_m2` |
| `building_density_per_km2` | count/km² | `building_count / area_km2` |
| `mean_building_area_m2` | m² | `building_area_total_m2 / building_count` |
| `largest_building_area_m2` | m² | max building area |
### Output layers
- `buildings_clipped`
- `building_centroids`
- `large_buildings_top_20`
## RoadAnalyzer
### Input
- Area polygon.
- Road line or polygon features.
### Output metrics
| Key | Unit | Formula |
|---|---|---|
| `road_length_total_m` | m | sum clipped road lengths |
| `road_length_total_km` | km | `/1000` |
| `road_density_km_per_km2` | km/km² | `road_length_total_km / area_km2` |
| `major_road_length_km` | km | filtered by road class if available |
### Output layers
- `roads_clipped`
- `major_roads_clipped`
## GreenAnalyzer
### Input options
- Green polygons from OSM/GRB/landuse.
- NDVI raster threshold result.
- Segmentation polygons classified as vegetation.
### Output metrics
| Key | Unit | Formula |
|---|---|---|
| `green_area_total_m2` | m² | sum green polygons clipped to area |
| `green_ratio` | ratio | `green_area_total_m2 / area_m2` |
| `green_patch_count` | count | number of disjoint green patches |
| `largest_green_patch_m2` | m² | max patch area |
| `green_fragmentation_index` | index | `green_patch_count / max(green_area_total_ha, 0.01)` |
### Interpretation
High fragmentation means green is split into many smaller patches.
## WaterAnalyzer
### Input
- Water polygons/lines from GRB/OSM.
- NDWI threshold polygons later.
### Output metrics
| Key | Unit | Formula |
|---|---|---|
| `water_area_total_m2` | m² | sum clipped water polygon area |
| `water_ratio` | ratio | `water_area_total_m2 / area_m2` |
| `watercourse_length_m` | m | sum water line length |
| `distance_to_nearest_water_m` | m | minimum distance from area centroid to water geometry |
## RasterAnalyzer
### Input
- Raster dataset.
- Optional area polygon.
### Output metrics
Per band:
| Key | Unit |
|---|---|
| `band_min` | band unit |
| `band_max` | band unit |
| `band_mean` | band unit |
| `band_std` | band unit |
| `nodata_ratio` | ratio |
### Required operations
- Read metadata.
- Clip by area.
- Compute statistics.
- Generate preview tile or PNG.
## RemoteSensingIndexAnalyzer
### NDVI
Formula:
```text
NDVI = (NIR - Red) / (NIR + Red)
```
Output:
- `ndvi_mean`
- `ndvi_median`
- `ndvi_low_ratio` using threshold configurable, default `< 0.2`
- `ndvi_high_ratio` using threshold configurable, default `> 0.5`
- vectorized high/low vegetation zones later
### NDWI
```text
NDWI = (Green - NIR) / (Green + NIR)
```
### NDBI
```text
NDBI = (SWIR - NIR) / (SWIR + NIR)
```
## DetectionAnalyzer
### Input
- Detection records with class, confidence and geometry.
- Area polygon.
### Output metrics
| Key | Unit | Formula |
|---|---|---|
| `detection_count` | count | detections within area |
| `detection_count_by_class` | json | group by class |
| `mean_confidence` | ratio | average confidence |
| `low_confidence_count` | count | confidence below threshold |
| `detected_area_m2_by_class` | json | sum polygon area where available |
## ScoreEngine v1
The score engine must be transparent. Every score returns value, inputs, weights and explanation.
### Open Space Pressure Score
Default weights:
```yaml
building_coverage_ratio: 0.35
road_density_normalized: 0.25
green_ratio_inverse: 0.25
urban_growth_normalized: 0.15
```
Score:
```text
100 * weighted_sum(normalized_factors)
```
### Nature Connectivity Score
Default weights:
```yaml
green_ratio: 0.35
largest_green_patch_ratio: 0.25
fragmentation_inverse: 0.25
major_road_barrier_inverse: 0.15
```
### Water Resilience Score
Default weights:
```yaml
green_ratio: 0.30
water_buffer_presence: 0.20
impervious_inverse: 0.30
low_point_risk_inverse: 0.20
```
V1 may calculate a simplified score without height data by marking height-dependent factors as unavailable.
## Metric storage contract
Each metric row must include:
```json
{
"analysis_run_id": "uuid",
"key": "building_density_per_km2",
"value": 123.4,
"unit": "count/km2",
"method": "BuildingAnalyzer.v1",
"inputs": ["dataset_uuid"],
"parameters": {},
"quality_flags": []
}
```