Python Crop Simulation Environment (PCSE)

repository·master·Indexed 42 days ago

https://github.com/ajwdewit/pcse

A modular Python framework for implementing and running crop simulation models, providing a flexible alternative to monolithic FORTRAN models. Version 6.0.13 includes implementations of WOFOST, LINTUL3, LINGRA, ALCEPAS, and FAO-WRSI. It features comprehensive modules for agromanagement, soil water and nitrogen dynamics (including SNOMIN), and a variety of weather data providers such as NASA Power and OpenMeteo.

Tokens
26K
Snippets
66
Records
111
Agent score
55%

What's inside PCSE

  1. Overview of the PCSE framework

    master

    PCSE (Python Crop Simulation Environment) is a modular framework for implementing and running crop simulation models. Unlike monolithic FORTRAN-based models, PCSE is written in pure Python, making it highly extensible and easy to interface with modern data tools like databases, GUIs, and scientific packages (e.g., pandas).

    Key architectural features include:

    • Modular Design: Uses a powerful approach to communicate variables between modules, allowing for quick component replacement.
    • Separation of Concerns: Explicitly separates parameters, rate variables, and state variables. It also completely decouples Input/Output from the simulation logic, supporting text files, databases, HDF, and NetCDF.
    • AgroManagement: Includes an AgroManager module to define agromanagement actions (e.g., irrigation, fertilization) triggered by time or model state.
    • Dependencies: Relies on standard PyPI packages such as Pydispather, PyYAML, pandas, Openpyxl, and requests.
  2. Overview of the Python Crop Simulation Environment (PCSE)

    master

    PCSE is a modular environment for developing and running crop simulation models. It was designed to overcome the limitations of monolithic, file-based FORTRAN models by providing a flexible, pure-Python implementation.

    Key characteristics include:

    • Modular Design: Allows for quick addition or replacement of components using a structured approach to variable communication.
    • Separation of Concerns: Explicitly separates parameters, rate variables, and state variables. It also decouples Input/Output (I/O) from the simulation logic, enabling models to interface with databases, text files, HDF, or NetCDF.
    • Extensibility: Easily integrates with the Python scientific ecosystem, including NumPy, SciPy, pandas, and Matplotlib.
    • Deployment Ready: Can be embedded in Docker containers to build web APIs around crop models.
  3. Identify available crop models in PCSE

    master

    PCSE implements several crop and productivity models that can be imported from the pcse.models package. These models vary by production level (Phenology, Potential, Water-limited, or Water and Nitrogen limited) and the complexity of their soil/nitrogen dynamics.

    Available Models:

    • WOFOST: Simulates growth and development of arable crops.
    • LINTUL3: Simulates growth and development of arable crops using a simplified approach for CO2 assimilation compared to WOFOST.
    • LINGRA: Simulates grassland productivity.
    • ALCEPAS: Specifically developed for onion simulation.
    • FAO-WRSI: Computes the Water Requirement Satisfaction Index to represent water shortage stress experienced by the crop.
  4. Use weather data providers

    master

    PCSE provides several weather data providers to retrieve time-series data from various sources. These include:

    • File-based providers:
      • CABOWeatherDataProvider: Uses the CABO Weather System ASCII format.
      • ExcelWeatherDataProvider: Uses Excel files (easier to handle than ASCII).
      • CSVWeatherDataProvider: Uses a simple CSV format.
    • API-based providers:
      • OpenMeteoWeatherDataProvider: Pulls weather information from the OpenMeteo API (historical data via ERA5, forecasts via various providers).
      • NASAPowerWeatherDataProvider: Retrieves global agroclimatology data from the NASA Power database at a 0.25x0.25 degree resolution based on latitude and longitude.
  5. How the VariableKiosk exchanges data between components

    master

    The VariableKiosk is a central component created when a PCSE Engine starts. It acts as a protected cache for exchanging state and rate variables between different model components.

    Key characteristics:

    • Automatic Registration: It automatically registers all state and rate variables defined in StateVariables or RateVariables classes.
    • Uniqueness: It enforces unique names for all state/rate variables within a single Engine hierarchy to prevent retrieval conflicts (e.g., engine.get_variable("LAI")).
    • Protected Updates: Only the SimulationObject that registered and published a variable can change its value in the Kiosk. Other objects can only query the value.
    • Flushing Mechanism: To prevent 'lagging' values (where the Kiosk holds a stale copy), the Engine regularly 'flushes' the Kiosk. After a flush, variables remain registered, but their values become undefined until updated by the corresponding rate/state calculation.
    • Signal Scoping: The VariableKiosk serves as the unique sender ID for signals. This ensures that multiple Engine instances running in the same session do not interfere with each other's signals.
    # Variables are typically published during initialization of rate/state variables
    # and retrieved via standard dictionary lookup on the kiosk.
    # Example conceptual usage:
    # engine.get_variable("LAI")
  6. Extend PCSE using Base Classes

    master

    PCSE uses a hierarchy of base classes to provide core functionality. Note: Except for VariableKiosk and WeatherDataContainer, you should not call these classes directly; instead, you should subclass them to implement your own logic.

    Core Infrastructure

    • pcse.base.VariableKiosk: Used for managing and accessing variables.
    • pcse.base.WeatherDataContainer: Used for handling weather data.
    • pcse.base.ConfigurationLoader: For loading simulation configurations.

    Templates for Simulation Objects

    When building new simulation components, inherit from these templates to ensure compatibility with the engine:

    • pcse.base.StatesTemplate: For objects defining state variables.
    • pcse.base.RatesTemplate: For objects defining rate variables.
    • pcse.base.ParamTemplate: For objects defining simulation parameters.

    Weather Data

    • pcse.base.WeatherDataProvider: Base class for implementing custom weather data providers.
  7. How to broadcast and receive signals in PCSE

    master

    PCSE uses a signal broadcasting mechanism (similar to a UI toolkit) to communicate events like management actions, timer outputs, or simulation termination. Signals are typically strings (or any hashable object).

    To use signals, a SimulationObject must:

    1. Define a signal: A string identifier.
    2. Connect a receiver: Use self._connect_signal(handler_method, signal_name) during the initialize() phase.
    3. Send a signal: Use self._send_signal(signal=signal_name, ...) to broadcast the event with optional arguments.

    Because these methods are part of the SimulationObject base class, they are available to any subclass.

    from pcse.base import SimulationObject, VariableKiosk
    from datetime import date
    
    mysignal = "My first signal"
    
    class MySimObj(SimulationObject):
        def initialize(self, day, kiosk):
            # Connect the handler method to the signal
            self._connect_signal(self.handle_mysignal, mysignal)
    
        def handle_mysignal(self, arg1, arg2):
            # This method is called when the signal is broadcasted
            print(f"Value of arg1, arg2: {arg1}, {arg2}")
    
        def send_mysignal(self):
            # Broadcast the signal with arguments
            self._send_signal(signal=mysignal, arg1=2.5, arg2="A")
    
    # Usage example:
    d = date(2000, 1, 1)
    v = VariableKiosk()
    obj = MySimObj(d, v)
    obj.send_mysignal()
    # Output: Value of arg1, arg2: 2.5, A
  8. How the PCSE architecture works

    master

    PCSE separates simulation logic into several distinct components to allow for modularity and flexibility:

    1. The Engine: A dedicated component that handles the dynamic part of the simulation. It manages initialization, the ordering of rate/state updates for soil and plant modules, time tracking, weather data retrieval, and calling the AgroManager.
    2. SimulationObjects: These implement the (bio)physical processes (e.g., phenological development or CO2 assimilation) by solving differential equations for the soil/plant system and updating the model state.
    3. AgroManager: A module responsible for signaling agricultural management actions such as sowing, harvesting, and irrigation.
    4. Communication: Components communicate by either exporting variables into a shared state object or by implementing signals that can be broadcasted and received by any PCSE object.
    5. Data Tools: Utilities for providing weather data and reading parameter values from files or databases.
  9. How WeatherDataProvider works in PCSE

    master

    PCSE uses the WeatherDataProvider abstraction to provide the simulation Engine with meteorological data. A WeatherDataProvider acts as an interface that retrieves data from various sources (e.g., Excel files, databases) and provides a consistent way for the Engine to access it.

    When you query a WeatherDataProvider for a specific date, it returns a WeatherDataContainer object containing the meteorological values for that day.

  10. How SimulationObjects work in PCSE

    master

    PCSE uses SimulationObject to group biophysical processes (like phenology or assimilation) into modular, logical entities. This modularity allows for easier maintenance, unit testing, and the ability to swap one biophysical approach for another (e.g., replacing a complex assimilation model with a simpler one) as long as they share the same interface.

    Each SimulationObject follows a strict lifecycle to ensure simulation correctness. The execution order must be:

    1. Update States: Integrate rates to update state variables.
    2. Calculate Driving Variables: Determine environmental/driving inputs.
    3. Calculate Rates: Compute the rates of change based on current states and driving variables.

    To maintain this order and prevent data corruption, PCSE uses a locking mechanism. Rate and state variables are read-only by default. They can only be modified within methods decorated with @prepare_rates (for rates) or @prepare_states (for states), which handle the unlocking and locking of the variables.

    class CropProcess(SimulationObject):
        class Parameters(ParamTemplate):
            PAR1 = Float()
    
        class StateVariables(StatesTemplate):
            STATE1 = Float()
    
        class RateVariables(RatesTemplate):
            RATE1 = Float()
    
        def initialize(self, day, kiosk, parametervalues):
            self.params = self.Parameters(parametervalues)
            self.rates = self.RateVariables(kiosk)
            self.states = self.StateVariables(kiosk, STATE1=0., publish=["STATE1"])
    
        @prepare_rates
        def calc_rates(self, day, drv):
            # Rates can only be modified here
            self.rates.RATE1 = self.params.PAR1 * drv.RAIN
    
        @prepare_states
        def integrate(self, day, delt):
            # States can only be modified here
            self.states.STATE1 += self.rates.RATE1 * delt
    
        @prepare_states
        def finalize(self, day):
            """Optional finalization step."""
            pass
  11. Automate crop activation via AgroManagement

    master

    You do not need to manually call set_active_crop if you use an AgroManager. By defining a CropCalendar within your AgroManagement YAML definition, PCSE will automatically activate the specified crop_name and variety_name during the simulation.

    AgroManagement:
    - 1999-08-01:
        CropCalendar:
            crop_name: wheat
            variety_name: Winter_wheat_101
            crop_start_date: 1999-09-15
            crop_start_type: sowing
            crop_end_date:
            crop_end_type: maturity
            max_duration: 300
        TimedEvents:
        StateEvents:
  12. Understand PCSE model naming conventions

    master

    When importing models from pcse.models, the model names follow a specific structured code pattern. This allows you to identify the model version, production level, and the complexity of the water and nitrogen balance modules included.

    The naming pattern is: <modelname><version>_<productionlevel>_<waterbalance>_<nitrogenbalance>

    Component Definitions:

    • Production Level: e.g., Pheno (Phenology only), PP (Potential), WLP (Water-limited), or NWLP (Water and Nitrogen limited).
    • Water Balance: CWB (Classic), MLWB (Multi-layer), or WLP (Water-limited).
    • Nitrogen Balance: CNB (Classic) or SNOMIN (Advanced soil carbon/nitrogen model).