102 lines
3.6 KiB
Python
102 lines
3.6 KiB
Python
|
|
#!/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)
|