High-performance geospatial processing with GPU acceleration, Numba JIT, and format conversion
Project description
GeoFast
High-performance geospatial processing framework: an aerial-spray line-generation engine (compiled Rust), GPU acceleration, Numba JIT compilation, file format conversion, and intelligent caching.
Features
- Aerial spray line generation: compiled Rust engine (ellipsoidal projection, sweep-angle search, per-gap fly-through-vs-turn, boustrophedon cell decomposition) producing crop-spraying coverage paths
- Multi-backend execution: CPU, CPU Parallel, GPU (CUDA), Numba JIT, Hybrid
- Automatic backend selection: Based on data size and available hardware
- File format conversion: GeoJSON, KML, GPX, CSV, MPZ/MapPlus
- Numba JIT primitives: Point-in-polygon, haversine, Douglas-Peucker, hex grids
- Spatial indexing: R-tree, hex grid index, point index
- GPU kernels: CUDA acceleration via Numba CUDA and CuPy
- Intelligent caching: Memory and disk caching for expensive computations
- Command-line interface: Convert files, view system info, manage cache
Installation
# Basic installation (CPU only)
pip install geofast
# With Numba JIT support (recommended)
pip install geofast[full]
# With GPU support (requires NVIDIA GPU + CUDA)
pip install geofast[gpu]
# Everything
pip install geofast[all]
Prebuilt wheels bundle the compiled spray engine, so pip install geofast needs no Rust
toolchain. numpy and shapely are installed by default. A Rust toolchain is only
required when building from source (an sdist or a git checkout), which is handled
automatically by maturin.
Quick Start
Spray Pattern Generation
from geofast import generate_spray_patterns
# Read a field boundary (GeoJSON/KML/...), generate spray lines, write the result.
# The Rust engine selects the spray angle and decomposes the field itself.
generate_spray_patterns(
"field.geojson", "spray.geojson",
config={"swath_width_ft": 50.0},
)
For finer control, the generator and optimizer are available directly:
from geofast.spray_line_generator import SprayLineGenerator, SprayConfig
gen = SprayLineGenerator(SprayConfig(swath_width_ft=50.0))
result = gen.generate(field_coords) # field_coords: GeoJSON polygon rings, lon/lat degrees
print(result.num_lines, result.total_spray_distance_miles, result.field_area_acres)
File Format Conversion
from geofast import convert, read_kml, MPZReader
# Convert between formats (auto-detects from extension)
convert('tracks.kml', 'tracks.geojson')
convert('field.geojson', 'field.kml')
convert('points.csv', 'points.gpx')
# Read KML directly
data = read_kml('file.kml') # Returns GeoJSON-like dict
# Read MapPlus/MPZ files
with MPZReader('data.mpz') as reader:
tracks = reader.get_tracks()
polygons = reader.get_polygons()
geojson = reader.to_geojson()
High-Performance Primitives
from geofast import (
haversine_scalar, haversine_batch,
point_in_polygon, points_in_polygon_batch,
douglas_peucker,
lat_lon_to_hex, polygon_to_hex_cells,
)
import numpy as np
# Fast haversine distance (Numba JIT)
dist = haversine_scalar(lat1, lon1, lat2, lon2, radius=3959) # miles
# Batch operations (parallel)
lats1 = np.array([40.0, 41.0, 42.0])
lons1 = np.array([-74.0, -73.0, -72.0])
distances = haversine_batch(lats1, lons1, lats2, lons2)
# Point-in-polygon (Numba JIT)
poly_x = np.array([0, 1, 1, 0, 0], dtype=np.float64)
poly_y = np.array([0, 0, 1, 1, 0], dtype=np.float64)
inside = point_in_polygon(0.5, 0.5, poly_x, poly_y) # True
# Line simplification
coords = np.array([[0, 0], [1, 0.1], [2, 0], [3, 0.1], [4, 0]])
simplified = douglas_peucker(coords, epsilon=0.2)
# Hex grid operations
q, r = lat_lon_to_hex(40.7128, -74.0060, hex_size_lat=0.001, hex_size_lon=0.001)
Spatial Indexing
from geofast import SpatialIndex, HexGridIndex
# R-tree index for fast polygon queries
index = SpatialIndex()
index.add_polygon('field1', polygon_coords)
index.add_polygon('field2', polygon_coords)
index.build()
# O(log n) point query
hits = index.query_point(lon, lat)
# Hex grid index for O(1) lookups
hex_index = HexGridIndex(hex_size_lat=0.001, hex_size_lon=0.001)
hex_index.add_polygons(polygons_dict)
hex_index.build()
field_ids = hex_index.query_point(lat, lon)
GPU Acceleration
from geofast import haversine_auto, hex_keys_auto, gpu_available
# Automatically uses GPU for large arrays, CPU for small
distances = haversine_auto(lats1, lons1, lats2, lons2)
q_arr, r_arr = hex_keys_auto(lats, lons, hex_size_lat, hex_size_lon)
# Check GPU availability
if gpu_available():
print("GPU acceleration available!")
Caching
from geofast import (
get_polygon_cell_cache,
cached,
set_cache_config,
print_cache_stats,
)
# Enable/configure caching
set_cache_config(enabled=True, cache_dir='~/.geofast/cache')
# Cache expensive computations
cache = get_polygon_cell_cache()
cells = cache.get_or_compute(polygon, hex_lat, hex_lon, compute_func)
# Decorator for automatic caching
@cached(cache_type='disk', ttl=3600)
def expensive_computation(data):
...
# View cache statistics
print_cache_stats()
Decorator-based Backend Selection
from geofast import process, Backend
# Auto-select best backend based on data size
@process(backend=Backend.AUTO, item_count_arg="geometries")
def simplify_fields(geometries, tolerance=0.001):
from shapely import simplify
return list(simplify(geometries, tolerance))
# Force GPU with CPU fallback
@process(backend=Backend.GPU, fallback=Backend.CPU)
def compute_distances(lats1, lons1, lats2, lons2):
...
# Parallel file processing
@process(backend=Backend.CPU_PARALLEL, batch=True)
def convert_files(filepaths):
...
Command Line Interface
# Convert files
geofast convert input.kml output.geojson
geofast convert tracks.mpz tracks.geojson
# Show system info
geofast info
geofast info --cache
# Manage cache
geofast cache --stats
geofast cache --clear
# List supported formats
geofast formats
Supported File Formats
| Format | Read | Write | Notes |
|---|---|---|---|
| GeoJSON | ✅ | ✅ | .geojson, .json |
| KML | ✅ | ✅ | .kml |
| GPX | ✅ | ✅ | .gpx (tracks, waypoints, routes) |
| CSV | ✅ | ✅ | Requires lat/lon columns |
| MPZ/MapPlus | ✅ | ❌ | .mpz, .sdb (SQLite-based) |
| Shapefile | ✅ | ✅ | Requires fiona |
Backends
| Backend | Best For | Requirements |
|---|---|---|
CPU |
Small datasets, simple operations | numpy |
CPU_PARALLEL |
File I/O, embarrassingly parallel tasks | numpy |
GPU |
Large arrays (10k+), matrix operations | cupy |
NUMBA |
Tight loops, custom algorithms | numba |
NUMBA_CUDA |
Custom GPU kernels | numba + CUDA |
HYBRID |
Very large datasets, max throughput | all |
AUTO |
Let GeoFast decide | any |
Configuration
from geofast import set_config
set_config(
max_workers=8, # CPU cores to use
chunk_size=1000, # Items per parallel chunk
gpu_batch_size=10000, # Items per GPU batch
auto_gpu_min_items=1000, # Threshold for AUTO->GPU
verbose=True # Log backend selection
)
Performance
Benchmarks on a system with 16 CPU cores and NVIDIA RTX 4050:
| Operation | Original | With GeoFast | Speedup |
|---|---|---|---|
| Polygon cell computation (7352 polygons) | ~20s | 1.3s (cached) | 15x |
| Track processing (262 tracks) | ~60s | 10.7s | 5.6x |
| Point-in-polygon (batch) | ~30s | 4.7s | 6.4x |
| Full analysis pipeline | ~300s | 41s | 7.3x |
Spray Pattern Generation
Generate optimal spray lines for agricultural fields:
from geofast import generate_spray_patterns
# Generate spray lines from field boundaries
generate_spray_patterns(
'fields.kml', # Input: field polygons
'spray_lines.geojson', # Output: spray lines + boundaries
config={
'swath_width_ft': 50, # Spray width per pass
'hop_distance_ft': 1300 # Max gap for pilot hopping
}
)
Features
- Optimal direction selection: Automatically chooses N-S or E-W based on field shape
- Multi-field optimization: Groups nearby fields for consistent spray direction
- Powerline detection: Flags fields with
hasPowerlines: truewhen transmission lines intersect - Efficiency metrics: Calculates acres/hour, total time, line counts
Command Line
# Basic usage
geofast spray field.kml lines.geojson
# With options
geofast spray field.kml lines.geojson --swath 60 --metadata
# Ground operations (no hopping)
geofast spray field.kml lines.geojson --no-hop
Output Properties
Each field boundary in the output includes:
hasPowerlines: Boolean indicating if powerlines cross the fieldangle: Optimal spray direction (0=N-S, 90=E-W)acres: Field areanum_tracks: Number of spray passes
Project Structure
geofast/
├── __init__.py # Package exports
├── core.py # Backend enum, @process decorator
├── executor.py # Backend dispatch logic
├── primitives.py # Numba JIT functions
├── spatial_index.py # R-tree, hex grid indexing
├── cuda_kernels.py # GPU kernels (CUDA/CuPy)
├── parallel.py # Shared memory, parallel utilities
├── geo_ops.py # High-level geo operations
├── formats.py # File format converters
├── cache.py # Caching layer
├── cli.py # Command-line interface
└── utils.py # Detection, helpers
Requirements
- Python 3.9+
- numpy
Optional
- numba (for JIT compilation)
- shapely 2.0+ (for spatial operations)
- cupy (for GPU acceleration)
- geopandas, fiona (for shapefile support)
License
MIT License - see LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file geofast-0.5.0.tar.gz.
File metadata
- Download URL: geofast-0.5.0.tar.gz
- Upload date:
- Size: 75.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1d427bed91bd231058d71bd0af4cce7ff8ae8136d2918f3d6732e0f1bbfa9966
|
|
| MD5 |
bff82413b505089f68927cdb32f108e1
|
|
| BLAKE2b-256 |
2bb99621df09172b49e47143cfedae5dabb8fda56be980859613033274531d3f
|
File details
Details for the file geofast-0.5.0-cp39-abi3-win_amd64.whl.
File metadata
- Download URL: geofast-0.5.0-cp39-abi3-win_amd64.whl
- Upload date:
- Size: 482.5 kB
- Tags: CPython 3.9+, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4bafacd6e0863a3a7a127ced76c7dda58ff6007e00f7d33391fe641414d7145b
|
|
| MD5 |
9cf6d3bfefbc37d5bbc8b5c1181e924c
|
|
| BLAKE2b-256 |
d468658d1cecd23890459b263f566403e37adfffb55fa19af0cb86463ab5bbe3
|
File details
Details for the file geofast-0.5.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: geofast-0.5.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 611.9 kB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0c1c998e7b6150c17f4cbe6aa8ba52bc7069a4f61b4ad929425b72e4121d0a00
|
|
| MD5 |
2bc742c96df99a83b8ec67cbab4e514d
|
|
| BLAKE2b-256 |
2221c3d3b0cbe607ab9ec3b651a865d2293003a9705d37e7829cf0030ab2143a
|
File details
Details for the file geofast-0.5.0-cp39-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: geofast-0.5.0-cp39-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 540.5 kB
- Tags: CPython 3.9+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
61deb811989dc7aa66713fdf5d5e54ca8ee1f7efe8c57f6dbee4288ed3e84566
|
|
| MD5 |
b8f283fadfbcffbc8cbfae9145d1132b
|
|
| BLAKE2b-256 |
707bf1cf4887f7b3b6c4fd45b8b1c9a9b9c1ab511832f9f171cd3aae3b34891c
|