Metadata-Version: 2.4
Name: vibeproj
Version: 1.0.5
Summary: GPU-accelerated coordinate projection library
Project-URL: Homepage, https://github.com/jarmak-personal/vibeProj
Project-URL: Repository, https://github.com/jarmak-personal/vibeProj
Project-URL: Documentation, https://jarmak-personal.github.io/vibeProj/
Project-URL: Issues, https://github.com/jarmak-personal/vibeProj/issues
Author-email: Ben Jarmak <ben@vibespatial.dev>
License-Expression: Apache-2.0
License-File: LICENSE
License-File: NOTICE
Keywords: coordinate,cuda,cupy,geospatial,gis,gpu,projection
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: GIS
Requires-Python: >=3.12
Requires-Dist: numpy>=2
Requires-Dist: pyproj>=3.7.0
Provides-Extra: cu12
Requires-Dist: cuda-cccl[cu12]; extra == 'cu12'
Requires-Dist: cuda-python<14,>=12; extra == 'cu12'
Requires-Dist: cupy-cuda12x>=13; extra == 'cu12'
Provides-Extra: cu13
Requires-Dist: cuda-cccl[cu13]; extra == 'cu13'
Requires-Dist: cuda-python>=13; extra == 'cu13'
Requires-Dist: cupy-cuda13x>=14; extra == 'cu13'
Description-Content-Type: text/markdown

# vibeProj

GPU-accelerated coordinate projection library. Extracted from [RAPIDS cuProj](https://github.com/rapidsai/cuspatial), re-engineered as a pure Python + CuPy package, and expanded from 1 to 24 projections — each with a fused NVRTC kernel that runs the full transform pipeline in a single GPU kernel launch.

## Performance

On an RTX 4090 vs i9-13900k, 1M coordinates:
(Note: datacenter GPUs will see far higher speedups due to better double precision performance)

| Projection | GPU | vs CPU |
|---|---|---|
| Transverse Mercator / UTM | 0.49 ms | 281x |
| Lambert Conformal Conic | 0.54 ms | 96x |
| Albers Equal Area | 0.27 ms | 143x |
| Web Mercator | 0.15 ms | 126x |
| Equal Earth | 0.43 ms | 145x |
| Plate Carrée | 0.04 ms | 311x |
| Oblique Mercator (Hotine) | 0.76 ms | 115x |
| Krovak | 2.08 ms | 173x |

All 24 projections run in under 3 ms at 1M coordinates. See full benchmark in the repo.

## Supported Projections

| Projection | Internal Name | EPSG Examples |
|---|---|---|
| Transverse Mercator / UTM | `tmerc` | 32601–32760, 27700 |
| Web Mercator | `webmerc` | 3857 |
| Mercator (ellipsoidal) | `merc` | 3395 |
| Lambert Conformal Conic | `lcc` | 2154 |
| Albers Equal Area | `aea` | 5070 |
| Polar Stereographic | `stere` | 3031, 3413 |
| Lambert Azimuthal Equal Area | `laea` | 3035 |
| Oblique Stereographic | `sterea` | 28992 |
| Plate Carrée | `eqc` | 4087 |
| Sinusoidal | `sinu` | — |
| Equal Earth | `eqearth` | 8857 |
| Cylindrical Equal Area | `cea` | 6933 |
| Orthographic | `ortho` | — |
| Gnomonic | `gnom` | — |
| Mollweide | `moll` | — |
| Robinson | `robin` | — |
| Winkel Tripel | `wintri` | — |
| Natural Earth | `natearth` | — |
| Azimuthal Equidistant | `aeqd` | — |
| Geostationary Satellite | `geos` | — |
| Oblique Mercator (Hotine) | `omerc` | 3375 |
| Krovak | `krovak` | 5514 |
| Eckert IV | `eck4` | — |
| Eckert VI | `eck6` | — |

## Install

```bash
pip install vibeproj            # CPU-only (NumPy fallback)
pip install vibeproj[cu12]      # CUDA 12
pip install vibeproj[cu13]      # CUDA 13
```

For development:

```bash
uv sync                         # CPU-only
uv sync --extra cu12            # CUDA 12
uv sync --extra cu13            # CUDA 13
```

## Usage

```python
from vibeproj import Transformer

# Default: always_xy=True — (lon, lat) order, matches shapely/geopandas
t = Transformer.from_crs("EPSG:4326", "EPSG:32631")
x, y = t.transform(2.0, 49.0)           # (lon, lat) in, (easting, northing) out

# always_xy=False: native CRS axis order (matches pyproj default)
t = Transformer.from_crs("EPSG:4326", "EPSG:32631", always_xy=False)
x, y = t.transform(49.0, 2.0)           # (lat, lon) in, (easting, northing) out
```

### Cross-datum transforms (Helmert)

```python
# Cross-datum: Helmert 7/15-parameter shift applied automatically
t = Transformer.from_crs("EPSG:4326", "EPSG:27700")  # WGS84 → OSGB36
x, y = t.transform(-0.1278, 51.5074)

# With ellipsoidal height — z is transformed through the ECEF intermediate
x, y, z = t.transform(-0.1278, 51.5074, z=45.0)

# Same-datum: z passes through unchanged, zero overhead
t = Transformer.from_crs("EPSG:4326", "EPSG:32631")
x, y, z = t.transform(2.0, 49.0, z=45.0)  # z == 45.0
```

For datum pairs with baked SVD corrections (e.g. NAD27 to NAD83), vibeProj achieves sub-5cm accuracy without external grid files. You can also [generate your own SVD corrections](https://jarmak-personal.github.io/vibeProj/user/datum-corrections.html) for any datum pair that pyproj supports using the included fitting tool (`tools/fit_datum_corrections.py`). For other grid-only datum pairs without a baked or custom correction, vibeProj warns and proceeds without a datum shift.

### Integration with CPU libraries

vibeProj works with popular geospatial Python libraries. GPU acceleration is automatic when CuPy is installed; otherwise it falls back to NumPy transparently.

- [GeoPandas](https://jarmak-personal.github.io/vibeProj/recipes/geopandas.html) — bulk GeoDataFrame reprojection
- [Rasterio](https://jarmak-personal.github.io/vibeProj/recipes/rasterio.html) — GPU-accelerated raster coordinate grids
- [Shapely](https://jarmak-personal.github.io/vibeProj/recipes/shapely.html) — geometry transforms via `shapely.transform()`

### vibeSpatial Integration (zero-copy GPU)

```python
# Pre-allocated output, no intermediate allocations, stays on GPU
t = Transformer.from_crs(src_crs, dst_crs, always_xy=True)
new_x = cp.empty_like(buf.x)
new_y = cp.empty_like(buf.y)
t.transform_buffers(buf.x, buf.y, out_x=new_x, out_y=new_y)

# 3D: z is transformed through Helmert when crossing datums
new_z = cp.empty_like(buf.z)
t.transform_buffers(buf.x, buf.y, buf.z, out_x=new_x, out_y=new_y, out_z=new_z)
```

`transform_buffers()` accepts pre-allocated CuPy output arrays, writes results directly into them, and returns the same objects. No host round-trip, no intermediate allocation. Designed for vibeSpatial's `OwnedGeometryArray` coordinate buffers.

## Architecture

- **Pure Python + CuPy** — no compiled extensions, no CMake
- **Fused NVRTC kernels** — each projection's full pipeline (axis swap, deg/rad, central meridian, projection math, scale/offset) runs in a single CUDA kernel launch via CuPy `RawKernel`
- **NumPy fallback** — all projections work on CPU when CuPy is unavailable
- **Helmert datum shifts** — 7/15-parameter (time-dependent) datum transformation with 3D ellipsoidal height support, runs on its own GPU kernel
- **SVD datum corrections** — baked SVD-compressed grid corrections for sub-5cm accuracy on supported datum pairs (e.g. NAD27 to NAD83), no external grid files needed
- **pyproj for CRS metadata** — EPSG codes resolved via pyproj, transform math is ours
- **fp64 I/O** — input/output arrays always double precision (ADR-0002 compliant)
- **Auto GPU detection** — queries `SingleToDoublePrecisionPerfRatio` to classify consumer vs datacenter GPU

## Test

```bash
uv run pytest                    # all tests
uv run pytest tests/test_fused_kernels.py  # GPU kernel tests (requires CuPy)
```
