#!/usr/bin/env python3 """Validate Wuhan 100m grid index.""" import sys import geopandas as gpd import pandas as pd def validate_grid(): print("=== Grid Validation ===\n") errors = [] geojson_path = "processed/grid_100m_index.geojson" parquet_path = "processed/grid_100m_index.parquet" print(f"1. Checking files exist...") try: grid = gpd.read_file(geojson_path) print(f" GeoJSON: {geojson_path} - OK ({len(grid)} features)") except Exception as e: errors.append(f"GeoJSON read failed: {e}") print(f" GeoJSON: FAILED - {e}") return errors try: df = pd.read_parquet(parquet_path) print(f" Parquet: {parquet_path} - OK ({len(df)} rows)") except Exception as e: errors.append(f"Parquet read failed: {e}") print(f" Parquet: FAILED - {e}") return errors print(f"\n2. Validating grid count...") expected_min = 800000 expected_max = 1000000 actual = len(grid) print(f" Expected: {expected_min}-{expected_max}") print(f" Actual: {actual}") if actual < expected_min or actual > expected_max: errors.append(f"Grid count {actual} outside expected range {expected_min}-{expected_max}") print(f" Status: FAILED") else: print(f" Status: OK") print(f"\n3. Validating grid_id format...") sample_ids = df['grid_id'].head(5).tolist() print(f" Sample: {sample_ids}") invalid_ids = df[~df['grid_id'].str.match(r'^r\d+_c\d+$')] if len(invalid_ids) > 0: errors.append(f"Invalid grid_id format in {len(invalid_ids)} rows") print(f" Invalid format: {len(invalid_ids)} rows") else: print(f" All {len(df)} grid_ids valid") print(f"\n4. Validating center coordinates...") lon_min, lat_min, lon_max, lat_max = df['center_lon'].min(), df['center_lat'].min(), df['center_lon'].max(), df['center_lat'].max() print(f" Lon range: {lon_min:.4f} to {lon_max:.4f}") print(f" Lat range: {lat_min:.4f} to {lat_max:.4f}") wuhan_lon_range = (113.7, 115.2) wuhan_lat_range = (29.9, 31.4) if lon_min < wuhan_lon_range[0] or lon_max > wuhan_lon_range[1]: errors.append(f"Longitude range {lon_min:.4f}-{lon_max:.4f} outside Wuhan bounds") print(f" WARNING: Longitude outside expected Wuhan bounds") if lat_min < wuhan_lat_range[0] or lat_max > wuhan_lat_range[1]: errors.append(f"Latitude range {lat_min:.4f}-{lat_max:.4f} outside Wuhan bounds") print(f" WARNING: Latitude outside expected Wuhan bounds") if not errors: print(f" Coordinates within Wuhan bounds") print(f"\n5. Validating required columns...") required_cols = ['grid_id', 'center_lon', 'center_lat', 'row', 'col', 'polygon'] missing = [c for c in required_cols if c not in df.columns] if missing: errors.append(f"Missing columns: {missing}") print(f" Missing: {missing}") else: print(f" All required columns present: {required_cols}") print(f"\n6. Validating geometry in GeoJSON...") if grid.geometry.is_valid.all(): print(f" All geometries valid") else: invalid_count = (~grid.geometry.is_valid).sum() errors.append(f"{invalid_count} invalid geometries") print(f" WARNING: {invalid_count} invalid geometries") print(f"\n=== Validation Summary ===") if errors: print(f"ERRORS: {len(errors)}") for e in errors: print(f" - {e}") return errors else: print(f"PASSED: All validations passed") return [] if __name__ == "__main__": errors = validate_grid() sys.exit(1 if errors else 0)