\pset tuples_only on \set resolution 9 \set coverage_size 2 \set raster_size 25 \set pixel_size 0.0005 \set value_num 5 \set lat 51.5 \set lng -0.025 -- Regression stability: -- These checks are sensitive to tiny floating differences. Keep the math strict, -- but avoid plan/parallel variability between runs. SET max_parallel_workers_per_gather TO 0; CREATE TABLE h3_test_rasters (id SERIAL, rast raster); INSERT INTO h3_test_rasters (rast) ( WITH vals AS ( SELECT array_agg(row ORDER BY y) AS vals FROM ( SELECT y, array_agg((x + y) % :value_num + 1 ORDER BY x) AS row FROM generate_series(1, :raster_size) AS x, generate_series(1, :raster_size) AS y GROUP BY y ) t), rasts AS ( SELECT ST_AddBand( ST_MakeEmptyCoverage( :raster_size, :raster_size, :raster_size * :coverage_size, :raster_size * :coverage_size, :lng, :lat, :pixel_size, -(:pixel_size), 0, 0, 4326), ARRAY[ROW(1, '8BUI', 1, 0)]::addbandarg[] ) AS rast) SELECT ST_SetValues(r.rast, 1, 1, 1, v.vals) FROM rasts r, vals v ); CREATE FUNCTION h3_test_equal( v1 double precision, v2 double precision) RETURNS boolean AS $$ SELECT ABS(v1 - v2) < 1e-12; $$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE; CREATE FUNCTION h3_test_raster_summary_stats_equal( s1 h3_raster_summary_stats, s2 h3_raster_summary_stats) RETURNS boolean AS $$ SELECT s1 IS NOT NULL AND s2 IS NOT NULL AND h3_test_equal((s1).count, (s2).count) AND h3_test_equal((s1).sum, (s2).sum) AND h3_test_equal((s1).mean, (s2).mean) AND h3_test_equal((s1).stddev, (s2).stddev) AND h3_test_equal((s1).min, (s2).min) AND h3_test_equal((s1).max, (s2).max); $$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE; CREATE FUNCTION h3_test_raster_class_summary_item_equal( i1 h3_raster_class_summary_item, i2 h3_raster_class_summary_item) RETURNS boolean AS $$ SELECT i1 IS NOT NULL AND i2 IS NOT NULL AND h3_test_equal((i1).val, (i2).val) AND h3_test_equal((i1).count, (i2).count) AND h3_test_equal((i1).area, (i2).area); $$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE; -- Results of `h3_raster_summary_clip` and `h3_raster_summary_centroids` -- should be identical WITH clip AS ( SELECT h3, h3_raster_summary_stats_agg(stats ORDER BY id) AS stats FROM ( -- id, h3, stats SELECT r.id, (h3_raster_summary_clip(r.rast, :resolution)).* FROM h3_test_rasters r ) t GROUP BY 1), centroids AS ( SELECT h3, h3_raster_summary_stats_agg(stats ORDER BY id) AS stats FROM ( -- id, h3, stats SELECT r.id, (h3_raster_summary_centroids(r.rast, :resolution)).* FROM h3_test_rasters r ) t GROUP BY 1) SELECT COUNT(*) FROM clip a FULL OUTER JOIN centroids b ON a.h3 = b.h3 WHERE NOT h3_test_raster_summary_stats_equal(a.stats, b.stats); -- Class summary and summary stats (clip) should agree on per-cell pixel counts. WITH class_clip AS ( SELECT h3, sum((summary).count) AS count FROM ( SELECT h3, val, h3_raster_class_summary_item_agg(summary ORDER BY id) AS summary FROM ( -- id, h3, val, summary SELECT r.id, (h3_raster_class_summary_clip(r.rast, :resolution)).* FROM h3_test_rasters r ) t GROUP BY 1, 2 ) t GROUP BY 1 ), stats_clip AS ( SELECT h3, h3_raster_summary_stats_agg(stats ORDER BY id) AS stats FROM ( -- id, h3, stats SELECT r.id, (h3_raster_summary_clip(r.rast, :resolution)).* FROM h3_test_rasters r ) t GROUP BY 1 ) SELECT COUNT(*) FROM class_clip c FULL OUTER JOIN stats_clip s ON c.h3 = s.h3 WHERE c.count IS NULL OR s.stats IS NULL OR NOT h3_test_equal(c.count, (s.stats).count); DROP FUNCTION h3_test_raster_class_summary_item_equal( h3_raster_class_summary_item, h3_raster_class_summary_item); DROP FUNCTION h3_test_raster_summary_stats_equal( h3_raster_summary_stats, h3_raster_summary_stats); DROP FUNCTION h3_test_equal(double precision, double precision); DROP TABLE h3_test_rasters;