PlantSimEngine

PlantSimEngine: A Simulation Engine For The Soil-Plant-Atmosphere System - Published in JOSS (2023)

https://github.com/virtualplantlab/plantsimengine.jl

Science Score: 98.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
    Found CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
    Found 1 DOI reference(s) in JOSS metadata
  • Academic publication links
    Links to: joss.theoj.org, zenodo.org
  • Committers with academic emails
  • Institutional organization owner
  • JOSS paper metadata
    Published in Journal of Open Source Software

Keywords

crops fspm julia julialang modeling plants simulation

Keywords from Contributors

pde meshing interpretability standardization ode fluxes raytracer plasma fluid-dynamics finite-volume
Last synced: 4 months ago · JSON representation ·

Repository

A framework to build plant models at the scales that matter

Basic Info
Statistics
  • Stars: 19
  • Watchers: 2
  • Forks: 2
  • Open Issues: 66
  • Releases: 36
Topics
crops fspm julia julialang modeling plants simulation
Created about 3 years ago · Last pushed 4 months ago
Metadata Files
Readme Contributing License Citation

README.md

PlantSimEngine

Stable Dev Build Status Coverage ColPrac: Contributor's Guide on Collaborative Practices for Community Packages Aqua QA DOI JOSS

Overview

PlantSimEngine is a comprehensive framework for building models of the soil-plant-atmosphere continuum. It includes everything you need to prototype, evaluate, test, and deploy plant/crop models at any scale, with a strong emphasis on performance and efficiency, so you can focus on building and refining your models.

Why choose PlantSimEngine?

  • Simplicity: Write less code, focus on your model's logic, and let the framework handle the rest.
  • Modularity: Each model component can be developed, tested, and improved independently. Assemble complex simulations by reusing pre-built, high-quality modules.
  • Standardisation: Clear, enforceable guidelines ensure that all models adhere to best practices. This built-in consistency means that once you implement a model, it works seamlessly with others in the ecosystem.
  • Optimised Performance: Don't re-invent the wheel. Delegating low-level tasks to PlantSimEngine guarantees that your model will benefit from every improvement in the framework. Enjoy faster prototyping, robust simulations, and efficient execution using Julia's high-performance capabilities.

Unique Features

Automatic Model Coupling

Seamless Integration: PlantSimEngine leverages Julia's multiple-dispatch capabilities to automatically compute the dependency graph between models. This allows researchers to effortlessly couple models without writing complex connection code or manually managing dependencies.

Intuitive Multi-Scale Support: The framework naturally handles models operating at different scales—from organelle to ecosystem—connecting them with minimal effort and maintaining consistency across scales.

Flexibility with Precision Control

Effortless Model Switching: Researchers can switch between different component models using a simple syntax without rewriting the underlying model code. This enables rapid comparison between different hypotheses and model versions, accelerating the scientific discovery process.

Batteries included

  • Automated Management: Seamlessly handle inputs, outputs, time-steps, objects, and dependency resolution.
  • Iterative Development: Fast and interactive prototyping of models with built-in constraints to avoid errors and sensible defaults to streamline the model writing process.
  • Control Your Degrees of Freedom: Fix variables to constant values or force to observations, use simpler models for specific processes to reduce complexity.
  • High-Speed Computations: Achieve impressive performance with benchmarks showing operations in the 100th of nanoseconds range for complex models (see this benchmark script).
  • Parallelize and Distribute Computing: Out-of-the-box support for sequential, multi-threaded, or distributed computations over objects, time-steps, and independent processes, thanks to Floops.jl.
  • Scale Effortlessly: Methods for computing over objects, time-steps, and Multi-Scale Tree Graphs.
  • Compose Freely: Use any types as inputs, including Unitful for unit propagation and MonteCarloMeasurements.jl for measurement error propagation.

Ask Questions

If you have any questions or feedback, open an issue or ask on discourse.

Installation

To install the package, enter the Julia package manager mode by pressing ] in the REPL, and execute the following command:

julia add PlantSimEngine

To use the package, execute this command from the Julia REPL:

julia using PlantSimEngine

Example usage

The package is designed to be easy to use, and to help users avoid errors when implementing, coupling and simulating models.

Simple example

Here's a simple example of a model that simulates the growth of a plant, using a simple exponential growth model:

```julia

] add PlantSimEngine

using PlantSimEngine

Include the model definition from the examples sub-module:

using PlantSimEngine.Examples

Define the model:

model = ModelList( ToyLAIModel(), status=(TT_cu=1.0:2000.0,), # Pass the cumulated degree-days as input to the model )

run!(model) # run the model

status(model) # extract the status, i.e. the output of the model ```

Which gives:

TimeStepTable{Status{(:TT_cu, :LAI...}(1300 x 2): ╭─────┬────────────────┬────────────╮ │ Row │ TT_cu │ LAI │ │ │ Float64 │ Float64 │ ├─────┼────────────────┼────────────┤ │ 1 │ 1.0 │ 0.00560052 │ │ 2 │ 2.0 │ 0.00565163 │ │ 3 │ 3.0 │ 0.00570321 │ │ 4 │ 4.0 │ 0.00575526 │ │ 5 │ 5.0 │ 0.00580778 │ │ ⋮ │ ⋮ │ ⋮ │ ╰─────┴────────────────┴────────────╯ 1295 rows omitted

Note
The ToyLAIModel is available from the examples folder, and is a simple exponential growth model. It is used here for the sake of simplicity, but you can use any model you want, as long as it follows PlantSimEngine interface.

Of course you can plot the outputs quite easily:

```julia

] add CairoMakie

using CairoMakie

lines(model[:TT_cu], model[:LAI], color=:green, axis=(ylabel="LAI (m² m⁻²)", xlabel="Cumulated growing degree days since sowing (°C)")) ```

LAI Growth

Model coupling

Model coupling is done automatically by the package, and is based on the dependency graph between the models. To couple models, we just have to add them to the ModelList. For example, let's couple the ToyLAIModel with a model for light interception based on Beer's law:

```julia

] add PlantSimEngine, DataFrames, CSV

using PlantSimEngine, PlantMeteo, DataFrames, CSV

Include the model definition from the examples folder:

using PlantSimEngine.Examples

Import the example meteorological data:

meteoday = CSV.read(joinpath(pkgdir(PlantSimEngine), "examples/meteoday.csv"), DataFrame, header=18)

Define the list of models for coupling:

model = ModelList( ToyLAIModel(), Beer(0.6), status=(TTcu=cumsum(meteoday[:, :TT]),), # Pass the cumulated degree-days as input to ToyLAIModel, this could also be done using another model ) ```

The ModelList couples the models by automatically computing the dependency graph of the models. The resulting dependency graph is:

╭──── Dependency graph ──────────────────────────────────────────╮ │ ╭──── LAI_Dynamic ─────────────────────────────────────────╮ │ │ │ ╭──── Main model ────────╮ │ │ │ │ │ Process: LAI_Dynamic │ │ │ │ │ │ Model: ToyLAIModel │ │ │ │ │ │ Dep: │ │ │ │ │ ╰────────────────────────╯ │ │ │ │ │ ╭──── Soft-coupled model ─────────╮ │ │ │ │ │ │ Process: light_interception │ │ │ │ │ └──│ Model: Beer │ │ │ │ │ │ Dep: (LAI_Dynamic = (:LAI,),) │ │ │ │ │ ╰─────────────────────────────────╯ │ │ │ ╰──────────────────────────────────────────────────────────╯ │ ╰────────────────────────────────────────────────────────────────╯

```julia

Run the simulation:

run!(model, meteo_day)

status(model) ```

Which returns:

TimeStepTable{Status{(:TT_cu, :LAI...}(365 x 3): ╭─────┬────────────────┬────────────┬───────────╮ │ Row │ TT_cu │ LAI │ aPPFD │ │ │ Float64 │ Float64 │ Float64 │ ├─────┼────────────────┼────────────┼───────────┤ │ 1 │ 0.0 │ 0.00554988 │ 0.0476221 │ │ 2 │ 0.0 │ 0.00554988 │ 0.0260688 │ │ 3 │ 0.0 │ 0.00554988 │ 0.0377774 │ │ 4 │ 0.0 │ 0.00554988 │ 0.0468871 │ │ 5 │ 0.0 │ 0.00554988 │ 0.0545266 │ │ ⋮ │ ⋮ │ ⋮ │ ⋮ │ ╰─────┴────────────────┴────────────┴───────────╯ 360 rows omitted

```julia

Plot the results:

using CairoMakie

fig = Figure(resolution=(800, 600)) ax = Axis(fig[1, 1], ylabel="LAI (m² m⁻²)") lines!(ax, model[:TT_cu], model[:LAI], color=:mediumseagreen)

ax2 = Axis(fig[2, 1], xlabel="Cumulated growing degree days since sowing (°C)", ylabel="aPPFD (mol m⁻² d⁻¹)") lines!(ax2, model[:TT_cu], model[:aPPFD], color=:firebrick1)

fig ```

LAI Growth and light interception

Multiscale modelling

See the Multi-scale modeling section of the docs for more details.

The package is designed to be easily scalable, and can be used to simulate models at different scales. For example, you can simulate a model at the leaf scale, and then couple it with models at any other scale, e.g. internode, plant, soil, scene scales. Here's an example of a simple model that simulates plant growth using sub-models operating at different scales:

julia mapping = Dict( "Scene" => ToyDegreeDaysCumulModel(), "Plant" => ( MultiScaleModel( model=ToyLAIModel(), mapped_variables=[ :TT_cu => "Scene", ], ), Beer(0.6), MultiScaleModel( model=ToyAssimModel(), mapped_variables=[:soil_water_content => "Soil"], ), MultiScaleModel( model=ToyCAllocationModel(), mapped_variables=[ :carbon_demand => ["Leaf", "Internode"], :carbon_allocation => ["Leaf", "Internode"] ], ), MultiScaleModel( model=ToyPlantRmModel(), mapped_variables=[:Rm_organs => ["Leaf" => :Rm, "Internode" => :Rm],], ), ), "Internode" => ( MultiScaleModel( model=ToyCDemandModel(optimal_biomass=10.0, development_duration=200.0), mapped_variables=[:TT => "Scene",], ), MultiScaleModel( model=ToyInternodeEmergence(TT_emergence=20.0), mapped_variables=[:TT_cu => "Scene"], ), ToyMaintenanceRespirationModel(1.5, 0.06, 25.0, 0.6, 0.004), Status(carbon_biomass=1.0) ), "Leaf" => ( MultiScaleModel( model=ToyCDemandModel(optimal_biomass=10.0, development_duration=200.0), mapped_variables=[:TT => "Scene",], ), ToyMaintenanceRespirationModel(2.1, 0.06, 25.0, 1.0, 0.025), Status(carbon_biomass=1.0) ), "Soil" => ( ToySoilWaterModel(), ), );

We can import an example plant from the package:

julia mtg = import_mtg_example()

Make a fake meteorological data:

julia meteo = Weather( [ Atmosphere(T=20.0, Wind=1.0, Rh=0.65, Ri_PAR_f=300.0), Atmosphere(T=25.0, Wind=0.5, Rh=0.8, Ri_PAR_f=500.0) ] );

And run the simulation:

```julia outvars = Dict( "Scene" => (:TTcu,), "Plant" => (:carbonallocation, :carbonassimilation, :soilwatercontent, :aPPFD, :TTcu, :LAI), "Leaf" => (:carbondemand, :carbonallocation), "Internode" => (:carbondemand, :carbonallocation), "Soil" => (:soilwater_content,), )

out = run!(mtg, mapping, meteo, outputs=out_vars, executor=SequentialEx()); ```

We can then extract the outputs in a DataFrame and sort them:

julia using DataFrames df_out = convert_outputs(out, DataFrame) sort!(df_out, [:timestep, :node])

| timestep
Int64 | organ
String | node
Int64 | carbon_allocation
U{Nothing, Float64} | TT_cu
U{Nothing, Float64} | carbon_assimilation
U{Nothing, Float64} | aPPFD
U{Nothing, Float64} | LAI
U{Nothing, Float64} | soil_water_content
U{Nothing, Float64} | carbon_demand
U{Nothing, Float64} | |------------------------:|----------------------:|--------------------:|-----------------------------------------------------------------------------------:|------------------------------------:|--------------------------------------------------:|-----------------------------------:|---------------------------------:|--------------------------------------------------:|--------------------------------------------:| | 1 | Scene | 1 | | 10.0 | | | | | | | 1 | Soil | 2 | | | | | | 0.3 | | | 1 | Plant | 3 | | 10.0 | 0.299422 | 4.99037 | 0.00607765 | 0.3 | | | 1 | Internode | 4 | 0.0742793 | | | | | | 0.5 | | 1 | Leaf | 5 | 0.0742793 | | | | | | 0.5 | | 1 | Internode | 6 | 0.0742793 | | | | | | 0.5 | | 1 | Leaf | 7 | 0.0742793 | | | | | | 0.5 | | 2 | Scene | 1 | | 25.0 | | | | | | | 2 | Soil | 2 | | | | | | 0.2 | | | 2 | Plant | 3 | | 25.0 | 0.381154 | 9.52884 | 0.00696482 | 0.2 | | | 2 | Internode | 4 | 0.0627036 | | | | | | 0.75 | | 2 | Leaf | 5 | 0.0627036 | | | | | | 0.75 | | 2 | Internode | 6 | 0.0627036 | | | | | | 0.75 | | 2 | Leaf | 7 | 0.0627036 | | | | | | 0.75 | | 2 | Internode | 8 | 0.0627036 | | | | | | 0.75 | | 2 | Leaf | 9 | 0.0627036 | | | | | | 0.75 |

An example output of a multiscale simulation is shown in the documentation of PlantBiophysics.jl:

Plant growth simulation

Projects that use PlantSimEngine

Take a look at these projects that use PlantSimEngine:

  • PlantBiophysics.jl - For the simulation of biophysical processes for plants such as photosynthesis, conductance, energy fluxes, and temperature
  • XPalm - An experimental crop model for oil palm

Performance

PlantSimEngine delivers impressive performance for plant modeling tasks. On an M1 MacBook Pro, a toy model for leaf area over a year at daily time-scale took only 260 μs to perform (about 688 ns per day), and 275 μs (756 ns per day) when coupled to a light interception model. These benchmarks demonstrate performance on par with compiled languages like Fortran or C, far outpacing typical interpreted language implementations.

For example, PlantBiophysics.jl, which implements ecophysiological models using PlantSimEngine, has been measured to run up to 38,000 times faster than equivalent implementations in other scientific computing languages.

Make it yours

The package is developed so anyone can easily implement plant/crop models, use it freely and as you want thanks to its MIT license.

If you develop such tools and it is not on the list yet, please make a PR or contact me so we can add it! 😃 Make sure to read the community guidelines before in case you're not familiar with such things.

Owner

  • Name: VirtualPlantLab
  • Login: VirtualPlantLab
  • Kind: organization

JOSS Publication

PlantSimEngine: A Simulation Engine For The Soil-Plant-Atmosphere System
Published
June 26, 2023
Volume 8, Issue 86, Page 5371
Authors
Rémi Vezy ORCID
CIRAD, UMR AMAP, F-34398 Montpellier, France., AMAP, Univ Montpellier, CIRAD, CNRS, INRAE, IRD, Montpellier, France.
Editor
Chris Vernon ORCID
Tags
agronomy crops fspm functional-structural plant modeling plants modelling

Citation (CITATION.bib)

@misc{PlantSimEngine.jl,
	author  = {Rémi Vezy <VEZY@users.noreply.github.com> and contributors},
	title   = {PlantSimEngine.jl},
	url     = {https://github.com/VirtualPlantLab/PlantSimEngine.jl},
	version = {v0.11.2},
	year    = {2024},
	month   = {11}
}

GitHub Events

Total
  • Create event: 21
  • Commit comment event: 25
  • Release event: 5
  • Issues event: 37
  • Watch event: 2
  • Delete event: 12
  • Issue comment event: 56
  • Push event: 308
  • Pull request review comment event: 1
  • Pull request review event: 3
  • Pull request event: 26
Last Year
  • Create event: 21
  • Commit comment event: 25
  • Release event: 5
  • Issues event: 37
  • Watch event: 2
  • Delete event: 12
  • Issue comment event: 56
  • Push event: 308
  • Pull request review comment event: 1
  • Pull request review event: 3
  • Pull request event: 26

Committers

Last synced: 5 months ago

All Time
  • Total Commits: 678
  • Total Committers: 5
  • Avg Commits per committer: 135.6
  • Development Distribution Score (DDS): 0.388
Past Year
  • Commits: 246
  • Committers: 4
  • Avg Commits per committer: 61.5
  • Development Distribution Score (DDS): 0.146
Top Committers
Name Email Commits
Rémi Vezy V****Y 415
Samuel-AMAP s****n@c****r 210
github-actions[bot] 4****] 34
CompatHelper Julia c****y@j****g 16
dependabot[bot] 4****] 3
Committer Domains (Top 20 + Academic)

Issues and Pull Requests

Last synced: 4 months ago

All Time
  • Total issues: 71
  • Total pull requests: 33
  • Average time to close issues: 3 months
  • Average time to close pull requests: 17 days
  • Total issue authors: 4
  • Total pull request authors: 4
  • Average comments per issue: 1.48
  • Average comments per pull request: 0.55
  • Merged pull requests: 25
  • Bot issues: 0
  • Bot pull requests: 6
Past Year
  • Issues: 46
  • Pull requests: 22
  • Average time to close issues: 5 months
  • Average time to close pull requests: 15 days
  • Issue authors: 3
  • Pull request authors: 3
  • Average comments per issue: 1.13
  • Average comments per pull request: 0.36
  • Merged pull requests: 15
  • Bot issues: 0
  • Bot pull requests: 2
Top Authors
Issue Authors
  • VEZY (42)
  • Samuel-amap (30)
  • lailanhabibah (1)
  • JuliaTagBot (1)
Pull Request Authors
  • Samuel-amap (19)
  • VEZY (14)
  • dependabot[bot] (7)
  • github-actions[bot] (4)
Top Labels
Issue Labels
enhancement (9) documentation (3) bug (2) question (2) low priority (2) performance (2) API improvement (1)
Pull Request Labels
dependencies (7) github_actions (1)

Packages

  • Total packages: 1
  • Total downloads:
    • julia 6 total
  • Total dependent packages: 1
  • Total dependent repositories: 0
  • Total versions: 37
juliahub.com: PlantSimEngine

A framework to build plant models at the scales that matter

  • Versions: 37
  • Dependent Packages: 1
  • Dependent Repositories: 0
  • Downloads: 6 Total
Rankings
Dependent repos count: 9.9%
Dependent packages count: 23.0%
Average: 33.7%
Stargazers count: 48.5%
Forks count: 53.5%
Last synced: 4 months ago

Dependencies

.github/workflows/CI.yml actions
  • actions/checkout v2 composite
  • codecov/codecov-action v2 composite
  • julia-actions/cache v1 composite
  • julia-actions/julia-buildpkg v1 composite
  • julia-actions/julia-docdeploy v1 composite
  • julia-actions/julia-processcoverage v1 composite
  • julia-actions/julia-runtest v1 composite
  • julia-actions/setup-julia v1 composite
.github/workflows/TagBot.yml actions
  • JuliaRegistries/TagBot v1 composite
.github/workflows/register.yml actions
  • julia-actions/RegisterAction latest composite
.github/workflows/CompatHelper.yml actions