Repository navigation
Speed up AAL, GBS lookups, facilities and raster steps; same results - #1
Merged
Merged
Conversation
- aal_by_soccup: exact integer arithmetic instead of a Python loop over Fractions (coefficients are C / L, so 2 L x AAL is an integer); Python integers if int64 could overflow - GBS: per-block x occupancy values by array lookup on factorized blocks instead of melting each exposure table and merging on two string keys; set() and isin() on large Arrow-backed string columns (pandas 3) replaced by unique(). Nullable Int64 exposure with <NA> now reads as NaN instead of raising - debris: the same isin() fix - facilities: default damage-function ids and restoration rows come from dicts built once; every grid is sampled once for all facility kinds, one read per 512-cell tile instead of one per point - area weighting: depth bins and zones computed once per depth cell, then resampled; counts by bincount; the boundary is only rasterized for tiles it cuts; block cell counts are shared between the grids of a scenario - prepare_depth_grid warps and compresses on all CPUs (threads=); merge_max compresses in parallel - tests/test_vectorized_paths.py checks each fast path exactly against the code it replaced, on edge cases Synthetic DC-scale region (5,000 blocks, 5 return periods): GBS, debris, shelter and AAL 601 s -> 102 s. Full run_scenario on 625 blocks with facilities: 162 s -> 35 s. Every result table is identical to the previous code (values, dtypes, row order). The SQL parity tests were not run here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Performance fixes from a profiling pass over the flood pipeline. Every result table is identical to
main: values, dtypes and row order. The changes only remove overhead.mainrun_scenario: 625 blocks, 5 depth grids, facilitiesprepare_depth_grid: 36M-cell UTM gridChanges
aal.py): exact integer arithmetic replaces the per-group Python loop overFractions. The coefficients areC / L, so2 L × AALis an integer and rounding half away from zero is integer division. Python integers take over if int64 could overflow.gbs.py): per-block × occupancy values come from an array lookup on factorized blocks. Before, each exposure table was melted and merged on two string keys, 18 times per run.gbs.py,debris.py):isin(<large Series>)andset(series)handle Arrow-backed strings one element at a time, about 60× slower thanunique(). They now useunique().facility_analysis.py,hazard.py): default damage-function ids and restoration rows come from dicts built once. Each grid is sampled once for all facility kinds, with one read per 512-cell tile instead of one per point.exposure.py,scenario.py): depth bins and zones are computed once per depth cell, then resampled. Counts usebincount. The boundary is only rasterized for tiles it cuts. Block cell counts are shared between the grids of a scenario.hazard.py): GDAL warps and compresses on all CPUs, with a newthreads=argument to limit that.merge_maxalso compresses in parallel.Behaviour changes
Int64with<NA>now reads as NaN in the GBS lookups. Before, it raised.prepare_depth_griduses all CPUs by default.Testing
tests/test_vectorized_paths.py(19 tests). Each fast path is compared exactly with the code it replaced, on edge cases: duplicate rows, half-way rounding, int64 overflow, NoData, misaligned and partial grids, boundaries that cut tiles, points outside every grid, ambiguous defaults. Bugs injected into AAL rounding, boundary handling, point indexing and the xref filter all make it fail.main's output, all identical: area weighting (5 grid set-ups), facilities (10 tables), GBS, debris, shelter and AAL at 300 and 5,000 blocks, and a fullrun_scenario(24 tables).tests/test_sql_parity*.py). Please run them before merging.Not in this PR
flGBSFinalis 13M rows (about 2.7 GiB), andecon_lossbriefly holds about 3.3× that because each merge copies the whole table. Selecting columns before those merges, or running GBS one return period at a time, would cut the peak._merge_calcscombines only about 1 % of rows but costs about 2 s at 1,000 blocks. A cheaper path has to keep pandas' Kahan-compensated float sums to stay exact.🤖 Generated with Claude Code