LINTUL3-Gym
LINTUL3-Gym is a transparent, reproducible Gymnasium
environment for nitrogen-management reinforcement learning, built on PCSE's LINTUL3 crop model.
Every transition returns a complete, inspectable record -- crop state, weather, and reward
components -- instead of an opaque feature vector, and the bundled winter-wheat example reproduces
a peer-reviewed paper's experiment end-to-end. It ships with a spring-wheat scenario for
gym.make(...) to work out of the box, plus two fuller worked examples -- spring wheat and winter
wheat -- with their own tutorial notebooks (see Examples).
Install
pip install lintul3-gym
Quick start
import gymnasium as gym
import lintul3_gym
env = gym.make("Lintul3Gym-v0", decision_interval=7)
observation, info = env.reset(seed=7)
while True:
observation, reward, terminated, truncated, info = env.step([0.0])
if terminated or truncated:
break
The action is one nitrogen dose in g N/m². The observation keeps crop, weather, and management fields separate. Each step's info includes the names and values consumed by the agent, weather metadata, reward components, and a serializable transition record. env.unwrapped.history is the complete episode audit trail.
Inputs and weather
By default the package loads its bundled spring-wheat .crop, .site, .soil, and nl1.xlsx inputs. Point data_dir at another directory to use your own inputs: Lintul3Env auto-discovers whichever single *.crop, *.site, and *.soil file it finds there by extension, not a fixed filename, so any directory shaped like the bundled example works. A sample .agro file may also be present for provenance/documentation, but it is never read as an environment input -- see Custom environments.
from lintul3_gym import Lintul3Env, WeatherConfig
excel_env = Lintul3Env(data_dir="/path/to/my/inputs")
nasa_env = Lintul3Env(
weather=WeatherConfig(
source="nasa",
locations=((51.97, 5.67), (52.0, 5.5)),
years=(2004, 2005, 2006),
random_weather_per_episode=True,
)
)
NASA POWER selections are seeded and cached locally under ~/.cache/lintul3_gym/nasa_power by default. Set cache_dir or refresh_cache in WeatherConfig to control this behavior.
Custom environments
Lintul3Env is flexible and works with any crop that has a LINTUL3
parameter set, via two pieces of configuration:
data_dir: a directory holding exactly one*.crop, one*.site, and one*.soilfile (any filename), and optionally annl1.xlsxforWeatherConfig(source="excel").SeasonConfig: the crop calendar (campaign_start,crop_start/crop_enddates and types,crop_name,max_duration) that would otherwise live in a PCSE.agrofile.Lintul3Envbuilds the equivalent calendar from this in code, so nitrogen application stays entirely under the RL agent's control.
from datetime import date
from lintul3_gym import Lintul3Env, SeasonConfig, WeatherConfig
season = SeasonConfig(
campaign_start=date(2007, 1, 1), crop_start=date(2007, 1, 1),
crop_end=date(2007, 9, 1), crop_name="winter-wheat",
crop_start_type="emergence", crop_end_type="earliest", max_duration=365,
)
env = Lintul3Env(data_dir="lintul3_gym/envs/data/winterwheat", season=season, decision_interval=7)
Two worked examples ship in this repo:
lintul3_gym/envs/data/springwheat/-- the bundled default (Netherlands, 2006).lintul3_gym/envs/data/winterwheat/-- winter wheat (Netherlands + France, 1990-2021), reproducing Kallenberg et al. (2023); see its ownREADME.mdfor full parameter provenance and a model-fidelity discussion.
For more LINTUL3-ready datasets, see PCSE's own documentation and WUR-AI/PCSE-Gym (the source of the winter-wheat set above) -- though most of PCSE-Gym's other crop configs are in WOFOST format (YAMLCropDataProvider/CABOFileReader), not this package's plain-text PCSEFileReader .crop/.site/.soil format, so they need translating rather than dropping in directly.
Reward and comparison
The default reward follows PCSE-Gym's LINTUL cost function:
storage-organ growth (g/m²) - 10.0 × applied nitrogen (g N/m²).
Use RewardConfig(nitrogen_cost=...) to change the cost, or relative_to_zero_nitrogen=True to score growth relative to a synchronized zero-nitrogen crop run.
Policies
lintul3_gym.policies provides a few simple, inspectable reference policies to evaluate a trained agent against, plus the evaluation helpers used throughout the examples:
ZeroNitrogenPolicy-- never applies nitrogen; a lower-bound baseline.ExpertPolicyandStandardPracticePolicy-- both are fixed calendar-dose baselines (apply a predetermined amount of nitrogen on predetermined calendar dates, regardless of crop state):ExpertPolicyreproduces the bundled spring-wheat.agroschedule (10 and 5 g N/m² on Apr 10 and May 5);StandardPracticePolicyreproduces the "Standard Practice" baseline from Kallenberg et al. (2023) for the winter-wheat use case (a configurable total split across three real fertilization dates). Both share the same underlying date-window matching logic.evaluate_policy(environment, policy, seed=...)-- runs one policy episode (works for either of the above, or a Stable-Baselines3 model) and returns a complete, transparentEvaluationResult.evaluate_policy_over_weather(environment, policy)-- runsevaluate_policyonce per(location, year)combination in aWeatherConfig, round-robin.evaluate_sb3_policy(vec_env, model, n_episodes=...)-- theVecNormalize-aware counterpart for trained Stable-Baselines3 models.
See examples/nitrogen-springwheat/Tutorial-Lintul3gym.ipynb and examples/nitrogen-winterwheat/PaperRep-Lintul3gym.ipynb for these in use.
Examples
| Example | What it shows |
|---|---|
examples/nitrogen-springwheat/Tutorial-Lintul3gym.ipynb |
Full tutorial -- what LINTUL3/PCSE need as input, how lintul3_gym supplies it, and both bundled experiments (train+eval on one fixed season; train+eval across disjoint years/locations via NASA POWER). Ends with a guide to adapting the environment to a different crop. |
examples/nitrogen-winterwheat/PaperRep-Lintul3gym.ipynb + lintul3_gym/envs/data/winterwheat/README.md |
Reproduces Kallenberg et al. (2023)'s winter-wheat nitrogen-management experiment: NASA POWER weather, the paper's train/test locations and years, a Standard Practice baseline, and out-of-distribution climate testing (Netherlands vs. France). |
How to cite
If you use lintul3-gym in your research, please cite it as:
Ohagwu, C. P. (2026). LINTUL3-Gym: A transparent, reproducible Gymnasium environment for LINTUL3 nitrogen management (Version 0.1.0) [Computer software]. https://github.com/cpohagwu/lintul3-gym
@software{ohagwu_lintul3gym,
author = {Ohagwu, Collins Patrick},
title = {{LINTUL3-Gym}: A transparent, reproducible {Gymnasium} environment for {LINTUL3} nitrogen management},
year = {2026},
url = {https://github.com/cpohagwu/lintul3-gym},
version = {0.1.0}
}
If you're using the winter-wheat example to reproduce Kallenberg et al. (2023)'s results, please
also cite that paper -- see lintul3_gym/envs/data/winterwheat/README.md
for its citation, which is separate from citing this software.
License
Apache-2.0 (see LICENSE). The design and economic convention of the default reward
are informed by the GPL-3.0 PCSE-Gym reference project.
The winter-wheat example's data files and patch
(lintul3_gym/envs/data/winterwheat/) are copied verbatim from PCSE-Gym and
remain under its GPL-3.0-or-later license rather than this repository's Apache-2.0 license -- see
that directory's README.md for details.
Metadata
Release files for lintul3-gym 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lintul3_gym-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Release files / lintul3_gym-0.1.0-py3-none-any.whl
| Download URL | lintul3_gym-0.1.0-py3-none-any.whl |
|---|---|
| Size | 152.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
754e4c88be19c39eb4ce89ae528534bba04352dad59c7b967387f405c4173da9
|
|
BLAKE2b-256 checksum How to use checksums |
f9cfda8a2b6f6929d67bc243464247d965b7a454e776aa44cec818e1846510de
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.0.0 CPython/3.14.3
|