Tegelgrootte en parallelisatie van afwateringseenheden
Meetopzet
Vervolgbenchmark van 10 september 2026, met de bestaande coverage-definitie
union(full_extent_of_each_source_tif). Voor die benchmark werd de productiecode
niet aangepast; de latere productie-workflow ondersteunt inmiddels parallel rekenen.
De tijdelijke scripts tools/benchmark_afwateringseenheden_scaling.py en
tools/analyze_afwateringseenheden_scaling.py bewaren hun meetgegevens onder
data/benchmark_afwateringseenheden_scaling/.
Gemeenschappelijk centrum: (168000, 406500), EPSG:28992. Dit is het volledig gedekte kandidaatcentrum het dichtst bij het geometrische zwaartepunt van de lokale hydroobjectsegmenten, op een zoekgrid met stappen van 1000 m. Het is een geografisch gemotiveerde keuze, geen bewijs van statistische representativiteit voor alle terreintypen of waterschappen.
Vooraf zijn zowel de vereniging van de TIFF-rechthoeken als de daadwerkelijke coverage-maskers op het 2 m doelgrid gecontroleerd. Alle drie maskers zijn volledig True. De VRT bevat 121 TIFFs.
| Kern | Gebufferde bounds | Grid | Cellen | Coverage | TIFFs met overlap | Segmentfeatures |
|---|---|---|---|---|---|---|
| 5 km | (163500, 402000, 172500, 411000) | 4500 × 4500 | 20.250.000 | 100% | 6 | 640 |
| 10 km | (161000, 399500, 175000, 413500) | 7000 × 7000 | 49.000.000 | 100% | 12 | 1436 |
| 20 km | (156000, 394500, 180000, 418500) | 12000 × 12000 | 144.000.000 | 100% | 20 | 4441 |
Instellingen: buffer 2000 m, resolutie 2 m, burn depth 100 m, max fill depth
50 m, engine PCRaster, overwrite=True en een unieke uitvoermap per job.
Downloads en het opbouwen van het watersysteem zijn uitgesloten; de bestaande
lokale VRT en GeoPackage worden gedeeld als alleen-lezen bronbestanden.
Windows 11, Python 3.14.7, Rasterio 1.5.1, GDAL 3.13.3, PCRaster 4.4.3. De machine heeft 16 fysieke en 32 logische cores en 66,21 GB RAM; bij de dekkingscontrole was 51,04 GB beschikbaar. Alle GB zijn decimaal.
De seriële meetreeks gebruikt één spawn-worker met achtereenvolgens twee runs van 5, 10 en 20 km. Zo blijven Python-imports en de extent-cache bij herhaling beschikbaar. Windows-bestandscaches worden niet geleegd: eerste/tweede run is geen gecontroleerde vergelijking tussen koude en warme SSD-cache.
De bestaande volledige tegelworkflow wordt gemeten, inclusief rastervoorbereiding,
PCRaster, polygoniseren, bufferrandcontrole, clip, dissolve en schrijven. De
aanroepen van lddcreate en subcatchment hebben elk hun eigen timer. Alleen de
korte rastervoorbereidingsfunctie wordt op regelniveau gevolgd om de NumPy-burn
te isoleren. De parent bemonstert elke 100 ms het procesgeheugen, CPU-tijd,
threadaantal en I/O, ook wanneer native code de GIL vasthoudt.
Per-job RSS wordt uit de samples binnen het jobtijdvak afgeleid. Windows
peak_wset wordt ook bewaard, maar is cumulatief voor de levensduur van een
worker. Voor gelijktijdige jobs is totaal-RAM het maximum van de gelijktijdige
som van parent- en worker-RSS, niet de som van afzonderlijke pieken op
verschillende tijdstippen. Gedeelde pagina's kunnen daarbij dubbel worden
geteld. CPU-seconden en wall-clockseconden worden afzonderlijk gerapporteerd.
Proces-I/O betreft logische bytes; systeemschijf-I/O omvat ook andere processen.
Referentie: functioneel landgebruik
src/waterlagen/functioneel_landgebruik/parallel.py gebruikt
ProcessPoolExecutor(max_workers=worker_count) en as_completed. Elke tegel
wordt een bevroren FunctioneelLandgebruikTileJob met bounds, bronpaden,
laagnamen, CRS, resolutie, uitvoerconfiguratie en een uniek doelpad. De top-level
functie _build_tile_worker roept de bestaande bouwfunctie aan en retourneert
een Path. Er worden geen open datasets of volledige arrays naar workers
gestuurd. Bronvalidatie en eventuele downloads gebeuren vooraf in de parent;
workers downloaden niets.
Bronlagen worden in de worker via waterlagen._geopandas.read_file geopend;
het uitvoerraster wordt daar met rasterio.open geopend. Elke worker schrijft
via een uniek tijdelijk bestand naast zijn doelbestand en vervangt dat doel
na afloop. De parent verzamelt succesvolle paden in de oorspronkelijke
tegelvolgorde. Exceptions van future.result() worden per tile-ID vastgelegd;
na afhandeling van de jobs volgt een gezamenlijke TileBuildError. De
voortgangsbalk en voltooiings-/foutmeldingen worden door de parent beheerd.
Er is al een expliciete workers-parameter. De bibliotheekdefault is
min(4, os.cpu_count() or 1); het workflow-script begrenst standaard op drie.
Deze defaults houden geen rekening met RAM. Logging wordt in het script
geconfigureerd. Er is geen pool-initializer of QueueHandler/QueueListener
voor workerlogs. Bij Windows spawn erft een worker die parentconfiguratie niet
automatisch; centrale INFO-logging vanuit workers is dus niet geregeld.
PCRaster, GDAL en procesisolatie
De lokale PCRaster-wrapper gebruikt een runtime-stack via _pcraster._rte();
de pipeline stelt per job de globale clone en opties unittrue en lddin in.
Dit is een reden om onafhankelijke jobs in aparte processen uit te voeren.
Een threadpool rond verschillende clones is hier niet als veilig aangetoond.
De officiële multicorelijst bevat vooral lokale en focale operaties en noemt
lddcreate niet. Het activeren van PCRASTER_NR_WORKER_THREADS schakelt in de
geïnstalleerde __init__.py bovendien alternatieve operaties in; dat is geen
algemene versnelling van de klassieke LDD-aanroep. Daarom blijft de klassieke
PCRaster-implementatie in deze proef behouden.
PCRaster multicore-documentatie.
Procesisolatie is ook een bekend PCRaster-patroon: het Monte Carlo-framework
kan samples in eigen processen draaien, maar zijn setForkSamples ondersteunt
Windows niet. Voor deze Windows-pipeline gebruiken we expliciet Python spawn,
een top-level worker, serialiseerbare jobs, freeze_support() en een
if __name__ == "__main__"-guard.
PCRaster framework.
Rasterio-datasets mogen niet tussen processen worden gedeeld. Elke worker opent de VRT, GeoPackages en eigen rasters opnieuw. Spawn voorkomt ook het overnemen van GDAL-mutexen en filehandles via fork na GDAL-initialisatie. Rasterio concurrency, GDAL multiprocessing.
VRT-readers kunnen sinds GDAL 3.10 zelf meerdere threads gebruiken, standaard
ALL_CPUS voor ondersteunde reads. Meer Python-workers kan dus native
oversubscription veroorzaken. GDAL_NUM_THREADS en VRT_NUM_THREADS moeten
bij een productiepool expliciet worden begrensd. De GDAL-blockcache is per
proces; de standaardlimiet is 5% van RAM en mag bij veel workers niet zonder
meer als gedeelde cache worden beschouwd.
VRT threading,
GDAL cacheconfiguratie.
Interpretatie voor een heel domein
Voor kernzijde s in km en buffer b = 2 km geldt:
processed_area = (s + 4)^2
retained_area = s^2
overhead_factor = processed_area / retained_area
tiles = domain_area / retained_area
serial_wall = tiles * mean_tile_wall
cpu_work = tiles * mean_tile_cpu
parallel_wall ≈ serial_wall / measured_speedup
Het rekenvoorbeeld gebruikt een vierkant domein van 100 × 100 km, dus 10.000 km². Dat is exact deelbaar door alle drie kernmaten. Werkelijke waterschapsgrenzen vragen extra randtegels en een gezamenlijke eindmerge; deze zijn niet door dit ideale oppervlaktemodel gedekt. De empirische LDD-fit over drie geneste gebieden beschrijft deze locatie en parameters, geen universele complexiteitswet: reliëf, depressies en netwerkdichtheid veranderen mee met het gebied.
Controle van parallelle berekening
De productie-workflow rekent inmiddels parallel, met een vaste seed per tegel. Zie de actuele productie-instellingen voor het uitvoeren van heel Aa en Maas en het samenvoegen, opschonen en aanvullen.
De gerichte tests controleren:
- Serieel versus zes workers: dezelfde rasters en polygonen, ook bij hergebruik.
- Eén aanvultest: bruikbare buurpolygonen vullen gaten, randpolygonen vallen af en bestaande toewijzingen blijven behouden.
- Lijnresten bij het aanvullen worden verwijderd, ook tussen opeenvolgende buren.
Uitvoeren vanuit de repository:
pixi run --environment afwateringseenheden pytest tests/test_afwateringseenheden_workers.py tests/test_afwateringseenheden_merging.py
De tests gebruiken kleine synthetische datasets en vereisen geen downloads.
Historische proef van 14 september 2026
De toenmalige proef met twee kernen van 2 × 2 km, 2 km buffer, 2 m resolutie en
seed 12345 per job is geslaagd. Inclusief beide batches en vergelijking duurde
hij 213,3 seconden. Resultaten staan in
data/benchmark_afwateringseenheden_scaling/20260914_170149_151917_parallel_check/comparison.json.
| Uitvoering van dezelfde twee tegels | Tijd | Piek-RAM (parent + workers) |
|---|---|---|
| Eén worker | 128,2 s | 1,01 GB |
| Twee workers | 83,2 s | 1,76 GB |
Dat is 1,54× zo snel, of 35% minder wachttijd in deze proef. De LDD-stappen liepen daadwerkelijk tegelijk. Er waren nul afwijkende rastercellen en nul afwijkende segmentpolygonen, zowel in de ruwe als gefilterde uitvoer. De bronversies bleven ongewijzigd. Deze meting mag niet rechtstreeks worden vertaald naar de huidige volledige run met grotere tegels en meer workers. De serie met één worker draaide eerst: bestandscaches kunnen de versnelling beïnvloeden. Dit was geen gecontroleerde herhaalde prestatiebenchmark.
Redactie: AI