vibeproj

vibeProj — GPU-accelerated coordinate projection library.

Submodules

Attributes

Exceptions

CoordinateValidationError

Raised when input coordinates are invalid (wrong shape, dtype, etc.).

CRSResolutionError

Raised when a CRS input cannot be parsed or resolved.

UnsupportedProjectionError

Raised when a CRS uses a projection method vibeProj doesn't support.

VibeProjectionError

Base exception for vibeProj errors.

Classes

Transformer

GPU-accelerated coordinate transformer.

AccuracyContract

Validated error bounds relative to native fp64 execution.

DeviceCapability

Device facts used by the strategy resolver.

StrategyDecision

Immutable resolved decision, including fallback reason and workload size.

StrategyExplanation

Immutable public explanation for every stage in one transform direction.

StrategyImplementation

Immutable implementation metadata exposed by registry introspection.

TranscendentalOperation

Operations with independently selectable transcendental strategies.

Functions

list_transcendental_strategies(...)

Return the immutable built-in transcendental strategy registry.

list_projections(→ dict[str, dict])

Return supported projections and their metadata.

warm_up(→ None)

Pre-compile fused NVRTC kernels to eliminate first-call latency.

Package Contents

type vibeproj.CRSInput = int | str | tuple[str, int] | CRS
exception vibeproj.CoordinateValidationError

Bases: VibeProjectionError

Raised when input coordinates are invalid (wrong shape, dtype, etc.).

exception vibeproj.CRSResolutionError

Bases: VibeProjectionError

Raised when a CRS input cannot be parsed or resolved.

exception vibeproj.UnsupportedProjectionError

Bases: VibeProjectionError

Raised when a CRS uses a projection method vibeProj doesn’t support.

exception vibeproj.VibeProjectionError

Bases: Exception

Base exception for vibeProj errors.

class vibeproj.Transformer(crs_from: vibeproj.crs.CRSInput, crs_to: vibeproj.crs.CRSInput, *, always_xy: bool = True, datum_shift: Literal['accurate', 'fast'] = 'accurate', epoch: float | None = None)

GPU-accelerated coordinate transformer.

  • transform(x, y) where x=lon, y=lat for geographic CRS (always_xy=True default)

  • direction=”FORWARD” or “INVERSE”

  • Accepts scalars, lists, numpy arrays, or cupy arrays

When CuPy is available and inputs are on GPU, transforms run on GPU. Otherwise falls back to NumPy on CPU.

Thread Safety

Transformer instances are safe to share across threads. NVRTC compilation is serialized on first use. Device-resident calls lease stream-specific scratch as needed. transform_chunked() calls sharing one Transformer and CUDA device serialize around that device’s persistent staging workspace while retaining two-stream overlap within each call.

static from_crs(crs_from: vibeproj.crs.CRSInput, crs_to: vibeproj.crs.CRSInput, *, always_xy: bool = True, datum_shift: Literal['accurate', 'fast'] = 'accurate', epoch: float | None = None) Transformer

Create a Transformer from source and target CRS.

Parameters

crs_from, crs_to :

EPSG integer (4326), string (“EPSG:4326”), or tuple ((“EPSG”, 4326)).

always_xybool, default True

If True, input/output axis order is always (x, y) — i.e. (longitude, latitude) for geographic CRS and (easting, northing) for most projected CRS. Projected X/Y declarations are preserved: EPSG:5513 remains X=Southing, Y=Westing, matching pyproj. This otherwise follows shapely and geopandas conventions. If False, uses the CRS native axis order (pyproj default).

datum_shiftstr, default “accurate”

“accurate” — use 15-parameter time-dependent Helmert when available, evaluating rate terms at the given epoch. Falls back to 7-parameter when no rates are present or no epoch can be resolved. “fast” — always use the base 7-parameter Helmert (ignores rate terms).

epochfloat, optional

Decimal year at which to evaluate the time-dependent Helmert (e.g. 2024.0). Only used when datum_shift=”accurate”. If omitted, the source CRS coordinate epoch is used when available.

property is_fused: bool

True if fused GPU kernels are available for this transform.

explain_strategy(*, transcendentals: vibeproj.transcendentals.TranscendentalPolicy = 'auto', precision: str = 'auto', direction: Literal['FORWARD', 'INVERSE'] = 'FORWARD', device: vibeproj.transcendentals.DeviceCapability | None = None, workload_size: int | None = None) vibeproj.transcendentals.StrategyExplanation

Explain transcendental decisions for one transform direction.

The result is immutable and contains a decision for every projection stage plus Helmert when active. Passing device makes hardware policy tests deterministic; otherwise the current device is detected lazily. precision accepts "auto", "fp64", "fp32", or "ds"; transcendentals accepts "auto", "native", or "accelerated". Pass workload_size to preview size-aware "auto" selection. None represents compilation/planning without a concrete array size and selects an otherwise-qualified accelerated implementation. This method does not materialize coordinate arrays.

property accuracy: str

Rough accuracy classification for this transform.

Returns

str

“sub-millimeter” — same datum, projection math only. “sub-5cm” — cross-datum with SVD-compressed grid correction. “sub-decimeter” — cross-datum with 15-param time-dependent Helmert evaluated at a known epoch. “sub-meter” — cross-datum with 7-param Helmert. “datum no-op (… m PROJ accuracy)” — PROJ selected an explicit no-op datum operation with meter-level expected accuracy. “degraded — no datum shift applied” — different datums; results may differ from pyproj by meters to hundreds of meters.

compile(*, precision: str = 'auto', transcendentals: vibeproj.transcendentals.TranscendentalPolicy = 'auto') None

Pre-compile fused NVRTC kernels for this transformer.

precision accepts "auto", "fp64", "fp32", or "ds". transcendentals accepts "auto", "native", or "accelerated" independently. Compilation has no concrete workload size, so "auto" selects an otherwise-qualified implementation without applying runtime crossover thresholds. This front-loads kernel compilation for every distinct projection/direction/implementation triple reachable in either transform direction; first-use stream scratch and chunk staging workspaces are still allocated lazily. No-op if CuPy is unavailable.

transform(x: numpy.typing.ArrayLike, y: numpy.typing.ArrayLike, z: None = None, direction: Literal['FORWARD', 'INVERSE'] = 'FORWARD', *, precision: str = 'auto', transcendentals: vibeproj.transcendentals.TranscendentalPolicy = 'auto') tuple[Any, Any]
transform(x: numpy.typing.ArrayLike, y: numpy.typing.ArrayLike, z: numpy.typing.ArrayLike, direction: Literal['FORWARD', 'INVERSE'] = 'FORWARD', *, precision: str = 'auto', transcendentals: vibeproj.transcendentals.TranscendentalPolicy = 'auto') tuple[Any, Any, Any]

Transform coordinates.

Parameters

x, yscalar, list, numpy array, or cupy array

Input coordinates. With always_xy=True (default): x=longitude, y=latitude for geographic CRS and PROJ visualization order for projected CRS. EPSG:5513 remains X=Southing, Y=Westing. With always_xy=False: native CRS axis order.

zscalar, list, numpy array, or cupy array, optional

Ellipsoidal height in meters. When a Helmert datum shift is active, z is transformed through the ECEF intermediate (correctness fix). When no datum shift is needed, z is passed through unchanged.

directionstr

“FORWARD” or “INVERSE”.

precision{“auto”, “fp64”, “fp32”, “ds”}

Numeric compute precision for fused GPU kernels.

transcendentals{“auto”, “native”, “accelerated”}

Transcendental implementation policy, independent of precision. "auto" uses the concrete input size and device capability when applying qualified acceleration crossover thresholds.

Returns

tuple of arrays (or scalars if scalar input)

Transformed (x, y) or (x, y, z) if z was provided.

transform_buffers(x: numpy.typing.ArrayLike, y: numpy.typing.ArrayLike, z: None = None, *, direction: Literal['FORWARD', 'INVERSE'] = 'FORWARD', out_x: numpy.typing.ArrayLike | None = None, out_y: numpy.typing.ArrayLike | None = None, out_z: numpy.typing.ArrayLike | None = None, precision: str = 'auto', transcendentals: vibeproj.transcendentals.TranscendentalPolicy = 'auto', stream: Any = None) tuple[Any, Any]
transform_buffers(x: numpy.typing.ArrayLike, y: numpy.typing.ArrayLike, z: numpy.typing.ArrayLike, *, direction: Literal['FORWARD', 'INVERSE'] = 'FORWARD', out_x: numpy.typing.ArrayLike | None = None, out_y: numpy.typing.ArrayLike | None = None, out_z: numpy.typing.ArrayLike | None = None, precision: str = 'auto', transcendentals: vibeproj.transcendentals.TranscendentalPolicy = 'auto', stream: Any = None) tuple[Any, Any, Any]

Transform device-resident arrays with optional pre-allocated outputs.

Designed for integration with vibeSpatial’s OwnedGeometryArray. It skips scalar detection and dtype conversion. With pre-allocated outputs, repeated same-size GPU calls on a warmed, cached stream avoid output and correction-scratch allocation. First use, cache growth, and kernel compilation can still allocate.

Parameters

x, ycupy.ndarray or numpy.ndarray

Coordinate arrays (fp64 storage per ADR-0002).

zcupy.ndarray or numpy.ndarray, optional

Ellipsoidal height array. Transformed through Helmert when a datum shift is active; passed through unchanged by projection/SVD-only paths.

directionstr

“FORWARD” or “INVERSE”.

out_x, out_ycupy.ndarray or numpy.ndarray, optional

Pre-allocated fp64 output arrays. Avoids allocation.

out_zcupy.ndarray or numpy.ndarray, optional

Pre-allocated fp64 output height array. Whenever z is provided, this buffer is honored and returned for transformed or passthrough height paths.

precision{“auto”, “fp64”, “fp32”, “ds”}

Numeric compute precision for fused GPU kernels.

transcendentals{“auto”, “native”, “accelerated”}

Hardware-aware transcendental implementation policy. This is independent of numeric compute precision. "auto" uses the array size when applying qualified acceleration thresholds.

streamcupy.cuda.Stream, optional

CUDA stream for asynchronous execution. None uses the current stream on the input array’s device; the legacy null stream is supported. Explicit streams from another device are rejected. The caller owns synchronization.

Returns

tuple of arrays

Transformed (out_x, out_y) or (out_x, out_y, z_out). Supplied output buffers are returned identically.

transform_chunked(x: numpy.typing.ArrayLike, y: numpy.typing.ArrayLike, z: None = None, *, direction: Literal['FORWARD', 'INVERSE'] = 'FORWARD', chunk_size: int = 1000000, precision: str = 'auto', transcendentals: vibeproj.transcendentals.TranscendentalPolicy = 'auto') tuple[numpy.ndarray, numpy.ndarray]
transform_chunked(x: numpy.typing.ArrayLike, y: numpy.typing.ArrayLike, z: numpy.typing.ArrayLike, *, direction: Literal['FORWARD', 'INVERSE'] = 'FORWARD', chunk_size: int = 1000000, precision: str = 'auto', transcendentals: vibeproj.transcendentals.TranscendentalPolicy = 'auto') tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray]

Transform large host-resident arrays in GPU-sized chunks.

Uses a double-buffered pipeline with pinned host memory and two CUDA streams to overlap transfers with GPU compute. Each Transformer keeps a grow-only workspace per CUDA device containing persistent streams, pinned buffers, and device buffers. Calls sharing that Transformer and device serialize around the complete workspace lifecycle; the two streams still overlap work within a call. Workspace and correction scratch allocation occurs on first use or growth and is reused by subsequent same-size calls.

Falls back to CPU transform() when CuPy is not available.

Parameters

x, yarray-like

Input coordinate arrays (host memory).

zarray-like, optional

Ellipsoidal height. Transformed through Helmert when a datum shift is active; passed through unchanged otherwise.

directionstr

“FORWARD” or “INVERSE”.

chunk_sizeint, default 1_000_000

Coordinates per GPU chunk. Larger values use more GPU memory but reduce per-chunk overhead. Size-aware "auto" dispatch uses the planned buffer size once and reuses that decision for every chunk, including a smaller final chunk.

precision{“auto”, “fp64”, “fp32”, “ds”}

Numeric compute precision for fused GPU kernels.

transcendentals{“auto”, “native”, “accelerated”}

Hardware-aware transcendental implementation policy, independent of precision.

Returns

tuple of numpy.ndarray

Transformed (x, y) or (x, y, z) on the host.

transform_bounds(left: float, bottom: float, right: float, top: float, *, densify_pts: int = 21, direction: Literal['FORWARD', 'INVERSE'] = 'FORWARD', precision: str = 'auto', transcendentals: vibeproj.transcendentals.TranscendentalPolicy = 'auto') tuple[float, float, float, float]

Transform a bounding box, densifying edges to handle projection curvature.

Densifies the four edges of the input bounding box, transforms all points, and returns the min/max envelope of the transformed result. This correctly handles non-linear projection distortion that would be missed by transforming only the four corners.

Parameters

left, bottom, right, topfloat

Bounding box coordinates. With always_xy=True (default): left/right are x (longitude), bottom/top are y (latitude).

densify_ptsint, default 21

Number of additional intermediate points per edge (not counting corner endpoints). Matches pyproj/GDAL convention: 0 means corners only, 21 (the default) adds 21 points between each pair of adjacent corners. Clamped to a minimum of 0.

direction{“FORWARD”, “INVERSE”}

Transform direction.

precision{“auto”, “fp64”, “fp32”, “ds”}

Numeric compute precision forwarded to the densified transform.

transcendentals{“auto”, “native”, “accelerated”}

Hardware-aware transcendental implementation policy, independent of precision. "auto" uses the densified point count.

Returns

tuple of four floats

(left, bottom, right, top) of the transformed bounding box.

Notes

When the transformed result crosses the antimeridian (±180°), the returned left will be greater than right (e.g. left=153, right=-162), matching the pyproj convention.

class vibeproj.AccuracyContract

Validated error bounds relative to native fp64 execution.

reference: str
max_horizontal_error_m: float
max_vertical_error_m: float | None = None
notes: str = ''
max_physical_scale_m: float | None = None
class vibeproj.DeviceCapability

Device facts used by the strategy resolver.

backend: DeviceBackend
compute_capability: tuple[int, int] | None = None
fp32_to_fp64_ratio: int | None = None
name: str | None = None
device_id: int | None = None
class vibeproj.StrategyDecision

Immutable resolved decision, including fallback reason and workload size.

operation: TranscendentalOperation
requested_policy: TranscendentalPolicy
implementation_id: str
family: str
reason: str
fallback: bool
accuracy: AccuracyContract
device: DeviceCapability
domain: str
workload_size: int | None
class vibeproj.StrategyExplanation

Immutable public explanation for every stage in one transform direction.

requested_policy: TranscendentalPolicy
direction: Literal['FORWARD', 'INVERSE']
device: DeviceCapability
workload_size: int | None
decisions: tuple[StrategyDecision, Ellipsis]
class vibeproj.StrategyImplementation

Immutable implementation metadata exposed by registry introspection.

min_elements is the runtime crossover used by "auto" after device, domain, and precision qualification. Explicit "accelerated" requests do not apply that size threshold.

implementation_id: str
operation: TranscendentalOperation
family: str
supported_policies: tuple[TranscendentalPolicy, Ellipsis]
supported_backends: tuple[DeviceBackend, Ellipsis]
supported_compute_capabilities: tuple[tuple[int, int], Ellipsis]
min_fp32_to_fp64_ratio: int | None
supported_compute_precisions: tuple[ComputePrecision, Ellipsis]
min_elements: int
domains: tuple[str, Ellipsis]
accuracy: AccuracyContract
native_fallback: bool
priority: int = 0
class vibeproj.TranscendentalOperation

Bases: str, enum.Enum

Operations with independently selectable transcendental strategies.

HELMERT = 'helmert'
PROJECTION = 'projection'
TMERC_FORWARD = 'tmerc.forward'
vibeproj.TranscendentalPolicy
vibeproj.list_transcendental_strategies() tuple[StrategyImplementation, Ellipsis]

Return the immutable built-in transcendental strategy registry.

Entries expose stable IDs, hardware/domain/precision qualifications, min_elements crossover thresholds, accuracy contracts, and native fallback behavior. Returning a tuple of frozen dataclasses prevents callers from changing global dispatch policy.

vibeproj.list_projections() dict[str, dict]

Return supported projections and their metadata.

Returns

dict[str, dict]

Keys are internal projection names. Each value has: - “methods”: list of pyproj method names that map to this projection - “fused”: True if a GPU-accelerated fused kernel is available

vibeproj.warm_up(projections: list[str] | None = None, *, precision: str = 'auto', transcendentals: transcendentals.TranscendentalPolicy = 'auto') None

Pre-compile fused NVRTC kernels to eliminate first-call latency.

Parameters

projectionslist of str, optional

Projection names to compile (e.g. [“tmerc”, “webmerc”]). If None, compiles all supported projections.

precision{“auto”, “fp64”, “fp32”, “ds”}

Compute precision: "auto", "fp64", "fp32", or "ds".

transcendentals{“auto”, “native”, “accelerated”}

Hardware-aware transcendental implementation policy, independent of compute precision. Warm-up has no concrete workload size, so "auto" selects an otherwise-qualified implementation without applying runtime crossover thresholds.

Notes

This compiles fused projection kernels. Per-Transformer correction scratch, pinned staging buffers, device buffers, and persistent chunk streams remain lazily allocated on first use or growth. Module warm-up has no CRS domain; qualified tmerc warm-up therefore includes both generic-TM native and forward-UTM accelerated variants.

Examples

>>> import vibeproj
>>> vibeproj.warm_up(["tmerc", "webmerc"])  # selective
>>> vibeproj.warm_up()                       # all projections