Skip to main content
Archived

This project has been archived by its maintainers, and is no longer receiving any updates.

AquaCrop-Grid

AquaCrop-Grid

Pixel-wise AquaCrop on rasters: zarr in, Numba kernels out — CPU or GPU.

PyPI Tests Python License

Numba NumPy xarray zarr Dask pytest AquaCrop-OSPy

Scope Parity Conventional Commits

Quick start · Config · Architecture · Schema · Testing · License


Climate as zarr cubes (time, y, x), per-pixel sowing dates (y, x), zarr outputs. Daily-step kernels from AquaCrop-OSPy 3.x are vendored and recompiled with Numba — njit + prange on CPU (one thread per pixel) and numba.cuda on GPU — with bit-exact parity against AquaCrop-OSPy (tests/test_parity.py).

This is not official FAO AquaCrop and not an aquacropos extension. It started in CyMP (Unioeste-LEA).

Layer Stack
Language Python 3.11+
Kernels Numba (njit + prange / numba.cuda)
Arrays NumPy, xarray, zarr, Dask
Reference AquaCrop-OSPy ≥ 3.0.11 (crop/soil params + parity tests)
CLI Typer (aquacrop-grid)
Tests pytest 8 — Ubuntu & Windows, Python 3.11 / 3.12

Current scope: rainfed (no irrigation, no groundwater), one season per pixel. Soil: a single AquaCrop preset or a per-pixel zarr raster (HiHydroSoil hydraulics or sand/silt/clay texture).


Prerequisites

  • Python 3.11+
  • GPU (optional): NVIDIA GPU with a CUDA driver — Numba talks to the driver; the full CUDA toolkit is not required

Quick start

pip install aquacrop-grid

From Git (no clone, before or besides PyPI):

pip install "git+https://github.com/Paloschi/aquacrop-grid.git"

For development, clone and install editable:

git clone https://github.com/Paloschi/aquacrop-grid.git
cd aquacrop-grid
pip install -e ".[dev]"
# 1. synthetic 10×10 pixels / 540 days
aquacrop-grid synth --out ./data

# 2. config
cp examples/config.example.yaml ./data/config.yaml
# (adjust paths if needed)

# 3. run
aquacrop-grid run --config ./data/config.yaml            # CPU
aquacrop-grid run --config ./data/config.yaml -b gpu     # GPU

Output: output.zarr with final yield/biomass (y, x) and, with save_daily: true, daily series (time, y, x) in group daily. Full schema: docs/zarr-schema.md.

Programmatic

from aquacrop_grid.pipeline import run_grid

run_grid("climate.zarr", "sowing.zarr", "output.zarr",
         crop_name="Maize", soil_name="SandyLoam",
         backend="cpu", save_daily=False)

CLI

Command Purpose
aquacrop-grid synth -o ./data Synthetic climate + sowing zarr for tests
aquacrop-grid run -c config.yaml Gridded simulation from YAML (-b cpu|gpu)
aquacrop-grid bench Throughput (pixels/s), excluding JIT compile

YAML config

climate: data/climate.zarr      # cube (time, y, x): tmin, tmax, precip, eto
sowing: data/sowing.zarr        # grid (y, x) int32 YYYYDDD; <=0 = masked
output: data/output.zarr
crop:
  name: Maize                   # any AquaCrop-OSPy crop
soil:
  name: SandyLoam               # AquaCrop preset (xor with zarr below)
  # zarr: data/soil.zarr        # ksat/wcsat/wcpf2/wcpf3 or sand/silt/clay
  # ksat_unit: cm/d
backend: cpu                    # cpu | gpu
options:
  save_daily: false
  tile: 128                     # spatial tile size (pixels)
  max_season_days: 400

Copy from examples/config.example.yaml.


Project structure

aquacrop-grid/
├── docs/                    # zarr I/O schema
├── examples/                # sample YAML config
├── src/aquacrop_grid/
│   ├── cli.py               # Typer: synth / run / bench
│   ├── pipeline.py          # zarr in → tiles → zarr out
│   ├── params.py            # Crop / Soil → kernel arrays
│   ├── soil_grid.py         # PTF + HiHydro layers → compartments
│   ├── bench.py
│   ├── engine/
│   │   ├── cpu.py           # njit + prange
│   │   ├── gpu.py           # numba.cuda
│   │   └── run.py           # shared runner over flat arrays
│   ├── kernels/
│   │   ├── impl.py          # daily step (njit / cuda.jit subset)
│   │   └── loader.py        # compile one source for both backends
│   └── io/                  # schema, validation, synthetic data
└── tests/                   # pytest: parity, grid, soil, io, gpu

Where to look first

Concern Location
Daily AquaCrop step src/aquacrop_grid/kernels/impl.py
CPU / GPU backends src/aquacrop_grid/engine/
Raster pipeline src/aquacrop_grid/pipeline.py
Crop / soil params src/aquacrop_grid/params.py
Soil rasters / PTF src/aquacrop_grid/soil_grid.py
Zarr schema docs/zarr-schema.md
Bit-exact parity tests/test_parity.py

Architecture

climate.zarr (time, y, x) + sowing.zarr (y, x)  [+ soil.zarr]
                         ↓
                   pipeline.py  (spatial tiles)
                         ↓
              params.py  →  kernel arrays
                         ↓
              engine/run.py  →  cpu (prange)  |  gpu (cuda)
                         ↓
         kernels/impl.py   one source, Numba njit / cuda.jit
                         ↓
                    output.zarr
  • kernels/impl.py — AquaCrop daily step ported to a common njit / cuda.jit subset (no allocation in kernels, scalar state per pixel + 1-D compartment views). One source compiled for both backends by kernels/loader.py.
  • params.py — flattens aquacrop Crop / Soil into kernel arrays (weather-independent init, including deepening the profile to Zmax + 0.1).
  • GDD phenology is computed inside the kernel per pixel (sowing date changes each pixel's thermal accumulation), mirroring aquacrop compute_crop_calendar.

I/O schema

Store Shape Role
Climate (time, y, x) tmin, tmax, precip, eto (daily, gap-free)
Sowing (y, x) int32 YYYYDDD; <= 0 = mask
Soil name or zarr AquaCrop preset, or hydraulic / texture raster
Output (y, x) yield, biomass, status; optional daily/ group

Grids must already be aligned — AquaCrop-Grid does not reproject. Details, units, and soil bands: docs/zarr-schema.md.


Benchmark

aquacrop-grid bench --pixels 65536 --days 540 (excluding JIT compile):

Backend Reference hardware Throughput
CPU (njit + prange) Ryzen (all threads) ~58k pixels/s
GPU (numba.cuda) RTX 3060 ~61k pixels/s

One full season (540 days) per pixel. On larger grids the GPU scales better (climate transfer dominates on small grids).


Testing

Tests

pytest            # parity vs AquaCrop-OSPy, io, grid driver, gpu (if present)
File What it covers
test_parity.py Single pixel vs AquaCrop-OSPy, 1e-12 (maize/soybean, calendar and GDD, 3 soils)
test_grid.py Mask, per-pixel sowing, tiles, grid vs single-pixel equality
test_soil.py Hydraulic/texture zarr, Saxton–Rawls PTF, per-pixel soil
test_io.py Synthetic I/O, sowing → plant index
test_gpu.py CPU vs GPU parity (skipped without CUDA)

CI (GitHub Actions) runs on every pull request against main, and again on push to main: Ubuntu and Windows × Python 3.11 / 3.12. Hosted runners are CPU-only; test_gpu.py is skipped.


Contributing

  1. Use conventional commits (feat:, fix:, chore:, ci:, docs:).
  2. Put tests in the same change as the behaviour they cover.
  3. Open a pull request against main — CI must pass before merge.

License and attribution

MIT. Kernels in src/aquacrop_grid/kernels/impl.py are derived from AquaCrop-OSPy (Apache-2.0).

Metadata

Release files for aquacrop-grid 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aquacrop-grid 0.1.1
File Size Uploaded
aquacrop_grid-0.1.1.tar.gz 58.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for aquacrop-grid 0.1.1
File Interpreter ABI Platform
aquacrop_grid-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 109.9 kB

Release files / aquacrop_grid-0.1.1.tar.gz

Download URL aquacrop_grid-0.1.1.tar.gz
Size 58.4 kB
Tags Source
SHA-256 checksum
How to use checksums
4914aaa066cf3026d1e908179bfef5677e4d425bfa057988e1f7d93be54f2680
BLAKE2b-256 checksum
How to use checksums
735192a1b3b440f5fed5a65cc4d93b3a5a9e688a6f731f6a2231314bddac2f17
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release files / aquacrop_grid-0.1.1-py3-none-any.whl

Download URL aquacrop_grid-0.1.1-py3-none-any.whl
Size 51.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e2acc27bb5f482a4bd9853123c16dfbe1a0236af3f70f6875182de2e421a1545
BLAKE2b-256 checksum
How to use checksums
ff23b1ae2b435c8e4f6cafc3161ad8a679af1a9b1d5985c1b01e85308d311139
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page