Skip to content

Commit

Permalink
Merge pull request #51 from VirtualPlantLab/mtg
Browse files Browse the repository at this point in the history
Improve how computations are made over MTGs
  • Loading branch information
VEZY authored Nov 23, 2023
2 parents d189154 + 70477a1 commit 48dd4f1
Show file tree
Hide file tree
Showing 63 changed files with 3,907 additions and 817 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ jobs:
matrix:
version:
- "1.7"
- "1.8"
- "nightly"
- "1"
os:
- ubuntu-latest
arch:
Expand Down
5 changes: 5 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ version = "0.8.2"
[deps]
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
DataAPI = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
FLoops = "cc61a311-1640-44b5-9fba-1b764f453329"
Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a"
Expand All @@ -18,12 +19,16 @@ Term = "22787eb5-b846-44ae-b979-8e399b8463ab"
[compat]
AbstractTrees = "0.4"
CSV = "0.10"
DataAPI = "1.15"
DataFrames = "1"
FLoops = "0.2"
Markdown = "1.7"
MultiScaleTreeGraph = "0.12"
PlantMeteo = "0.6"
Statistics = "1.7"
Tables = "1"
Term = "1, 2"
Test = "1.7"
julia = "1.7"

[extras]
Expand Down
25 changes: 12 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ Here's a simple example of a model that simulates the growth of a plant, using a
# ] add PlantSimEngine
using PlantSimEngine

# Include the model definition from the examples folder:
include(joinpath(pkgdir(PlantSimEngine), "examples/ToyLAIModel.jl"))
# Include the model definition from the examples sub-module:
using PlantSimEngine.Examples

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

run!(model) # run the model
Expand All @@ -71,9 +71,9 @@ status(model) # extract the status, i.e. the output of the model
Which gives:

```
TimeStepTable{Status{(:degree_days_cu, :LAI...}(1300 x 2):
TimeStepTable{Status{(:TT_cu, :LAI...}(1300 x 2):
╭─────┬────────────────┬────────────╮
│ Row │ degree_days_cu │ LAI │
│ Row │ TT_cu │ LAI │
│ │ Float64 │ Float64 │
├─────┼────────────────┼────────────┤
│ 1 │ 1.0 │ 0.00560052 │
Expand All @@ -95,7 +95,7 @@ Of course you can plot the outputs quite easily:
# ] add CairoMakie
using CairoMakie

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

![LAI Growth](examples/LAI_growth.png)
Expand All @@ -109,8 +109,7 @@ Model coupling is done automatically by the package, and is based on the depende
using PlantSimEngine, PlantMeteo, DataFrames, CSV

# Include the model definition from the examples folder:
include(joinpath(pkgdir(PlantSimEngine), "examples/ToyLAIModel.jl"))
include(joinpath(pkgdir(PlantSimEngine), "examples/Beer.jl"))
using PlantSimEngine.Examples

# Import the example meteorological data:
meteo_day = CSV.read(joinpath(pkgdir(PlantSimEngine), "examples/meteo_day.csv"), DataFrame, header=18)
Expand All @@ -119,7 +118,7 @@ meteo_day = CSV.read(joinpath(pkgdir(PlantSimEngine), "examples/meteo_day.csv"),
model = ModelList(
ToyLAIModel(),
Beer(0.6),
status=(degree_days_cu=cumsum(meteo_day[:, :degree_days]),), # Pass the cumulated degree-days as input to `ToyLAIModel`, this could also be done using another model
status=(TT_cu=cumsum(meteo_day[:, :TT]),), # Pass the cumulated degree-days as input to `ToyLAIModel`, this could also be done using another model
)
```

Expand Down Expand Up @@ -152,9 +151,9 @@ status(model)
Which returns:

```
TimeStepTable{Status{(:degree_days_cu, :LAI...}(365 x 3):
TimeStepTable{Status{(:TT_cu, :LAI...}(365 x 3):
╭─────┬────────────────┬────────────┬───────────╮
│ Row │ degree_days_cu │ LAI │ aPPFD │
│ Row │ TT_cu │ LAI │ aPPFD │
│ │ Float64 │ Float64 │ Float64 │
├─────┼────────────────┼────────────┼───────────┤
│ 1 │ 0.0 │ 0.00554988 │ 0.0476221 │
Expand All @@ -173,10 +172,10 @@ using CairoMakie

fig = Figure(resolution=(800, 600))
ax = Axis(fig[1, 1], ylabel="LAI (m² m⁻²)")
lines!(ax, model[:degree_days_cu], model[:LAI], color=:mediumseagreen)
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[:degree_days_cu], model[:aPPFD], color=:firebrick1)
lines!(ax2, model[:TT_cu], model[:aPPFD], color=:firebrick1)

fig
```
Expand Down
1 change: 1 addition & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
MultiScaleTreeGraph = "dd4a991b-8a45-4075-bede-262ee62d5583"
PlantMeteo = "4630fe09-e0fb-4da5-a846-781cb73437b6"
PlantSimEngine = "9a576370-710b-4269-adf9-4f603a9c6423"
12 changes: 8 additions & 4 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ DocMeta.setdocmeta!(PlantSimEngine, :DocTestSetup, :(using PlantSimEngine, Plant
makedocs(;
modules=[PlantSimEngine],
authors="Rémi Vezy <[email protected]> and contributors",
repo="https://github.com/VirtualPlantLab/PlantSimEngine.jl/blob/{commit}{path}#{line}",
repo=Documenter.Remotes.GitHub("VirtualPlantLab", "PlantSimEngine.jl"),
sitename="PlantSimEngine.jl",
format=Documenter.HTML(;
prettyurls=get(ENV, "CI", "false") == "true",
canonical="https://VirtualPlantLab.github.io/PlantSimEngine.jl",
edit_link="main",
assets=String[]
assets=String[],
size_threshold=250000
),
pages=[
"Home" => "index.md",
Expand All @@ -30,7 +31,10 @@ makedocs(;
"Input types" => "./extending/inputs.md",
],
"Coupling" => [
"Users" => "./model_coupling/model_coupling_user.md",
"Users" => [
"Simple case" => "./model_coupling/model_coupling_user.md",
"Multi-scale modelling" => "./model_coupling/multiscale.md",
],
"Modelers" => "./model_coupling/model_coupling_modeler.md",
],
"FAQ" => ["./FAQ/translate_a_model.md"],
Expand All @@ -39,6 +43,6 @@ makedocs(;
)

deploydocs(;
repo="github.com/VirtualPlantLab/PlantSimEngine.jl",
repo="github.com/VirtualPlantLab/PlantSimEngine.jl.git",
devbranch="main"
)
18 changes: 17 additions & 1 deletion docs/src/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,20 @@ Private functions, types or constants from `PlantSimEngine`. These are not expor
Modules = [PlantSimEngine]
Public = false
Private = true
```
```

## Example models

PlantSimEngine provides example processes and models to users. They are available from a sub-module called `Examples`. To get access to these models, you can simply use this sub-module:

```julia
using PlantSimEngine.Examples
```

The models are detailed below.

```@autodocs
Modules = [PlantSimEngine.Examples]
Public = true
Private = true
```
27 changes: 14 additions & 13 deletions docs/src/FAQ/translate_a_model.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
using PlantSimEngine
using CairoMakie
using CSV, DataFrames
include(joinpath(pkgdir(PlantSimEngine), "examples/ToyLAIModel.jl"))
# Import the example models defined in the `Examples` sub-module:
using PlantSimEngine.Examples
function lai_toymodel(degree_days_cu; max_lai=8.0, dd_incslope=500, inc_slope=70, dd_decslope=1000, dec_slope=20)
LAI = max_lai * (1 / (1 + exp((dd_incslope - degree_days_cu) / inc_slope)) - 1 / (1 + exp((dd_decslope - degree_days_cu) / dec_slope)))
function lai_toymodel(TT_cu; max_lai=8.0, dd_incslope=500, inc_slope=70, dd_decslope=1000, dec_slope=20)
LAI = max_lai * (1 / (1 + exp((dd_incslope - TT_cu) / inc_slope)) - 1 / (1 + exp((dd_decslope - TT_cu) / dec_slope)))
if LAI < 0
LAI = 0
end
Expand All @@ -33,15 +34,15 @@ Simulate leaf area index (LAI, m² m⁻²) for a crop based on the amount of deg
# Arguments
- `degree_days_cu`: degree-days since sowing
- `TT_cu`: degree-days since sowing
- `max_lai=8`: Maximum value for LAI
- `dd_incslope=500`: degree-days at which we get the maximal increase in LAI
- `inc_slope=5`: slope of the increasing part of the LAI curve
- `dd_decslope=1000`: degree-days at which we get the maximal decrease in LAI
- `dec_slope=2`: slope of the decreasing part of the LAI curve
"""
function lai_toymodel(degree_days_cu; max_lai=8.0, dd_incslope=500, inc_slope=70, dd_decslope=1000, dec_slope=20)
LAI = max_lai * (1 / (1 + exp((dd_incslope - degree_days_cu) / inc_slope)) - 1 / (1 + exp((dd_decslope - degree_days_cu) / dec_slope)))
function lai_toymodel(TT_cu; max_lai=8.0, dd_incslope=500, inc_slope=70, dd_decslope=1000, dec_slope=20)
LAI = max_lai * (1 / (1 + exp((dd_incslope - TT_cu) / inc_slope)) - 1 / (1 + exp((dd_decslope - TT_cu) / dec_slope)))
if LAI < 0
LAI = 0
end
Expand Down Expand Up @@ -96,7 +97,7 @@ This way users can create a model with default parameters just by calling `ToyLA
Then we can define the inputs and outputs of the model, and the default value at initialization:

```julia
PlantSimEngine.inputs_(::ToyLAIModel) = (degree_days_cu=-Inf,)
PlantSimEngine.inputs_(::ToyLAIModel) = (TT_cu=-Inf,)
PlantSimEngine.outputs_(::ToyLAIModel) = (LAI=-Inf,)
```

Expand All @@ -109,7 +110,7 @@ Finally, we can define the model function that will be called at each time step:

```julia
function PlantSimEngine.run!(::ToyLAIModel, models, status, meteo, constants=nothing, extra=nothing)
status.LAI = models.LAI_Dynamic.max_lai * (1 / (1 + exp((models.LAI_Dynamic.dd_incslope - status.degree_days_cu) / model.LAI_Dynamic.inc_slope)) - 1 / (1 + exp((models.LAI_Dynamic.dd_decslope - status.degree_days_cu) / models.LAI_Dynamic.dec_slope)))
status.LAI = models.LAI_Dynamic.max_lai * (1 / (1 + exp((models.LAI_Dynamic.dd_incslope - status.TT_cu) / model.LAI_Dynamic.inc_slope)) - 1 / (1 + exp((models.LAI_Dynamic.dd_decslope - status.TT_cu) / models.LAI_Dynamic.dec_slope)))

if status.LAI < 0
status.LAI = 0
Expand Down Expand Up @@ -138,21 +139,21 @@ period = [Dates.Date("2021-01-01"), Dates.Date("2021-12-31")]
meteo = get_weather(43.649777, 3.869889, period, sink = DataFrame)

# Compute the degree-days with a base temperature of 10°C:
meteo.degree_days = max.(meteo.T .- 10.0, 0.0)
meteo.TT = max.(meteo.T .- 10.0, 0.0)

# Aggregate the weather data to daily values:
meteo_day = to_daily(meteo, :degree_days => (x -> sum(x) / 24) => :degree_days)
meteo_day = to_daily(meteo, :TT => (x -> sum(x) / 24) => :TT)
```

Then we can define our list of models, passing the values for `degree_days_cu` in the status at initialization:
Then we can define our list of models, passing the values for `TT_cu` in the status at initialization:

```@example mymodel
m = ModelList(
ToyLAIModel(),
status = (degree_days_cu = cumsum(meteo_day.degree_days),),
status = (TT_cu = cumsum(meteo_day.TT),),
)
run!(m)
lines(m[:degree_days_cu], m[:LAI], color=:green, axis=(ylabel="LAI (m² m⁻²)", xlabel="Days since sowing"))
lines(m[:TT_cu], m[:LAI], color=:green, axis=(ylabel="LAI (m² m⁻²)", xlabel="Days since sowing"))
```
10 changes: 5 additions & 5 deletions docs/src/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

```@setup usepkg
using PlantSimEngine, PlantMeteo
include(joinpath(pkgdir(PlantSimEngine), "examples/Beer.jl"))
using PlantSimEngine.Examples
meteo = Atmosphere(T = 20.0, Wind = 1.0, Rh = 0.65, Ri_PAR_f = 500.0)
leaf = ModelList(Beer(0.5), status = (LAI = 2.0,))
run!(leaf, meteo)
Expand Down Expand Up @@ -56,10 +56,10 @@ Importing the package:
using PlantSimEngine
```

Including the script that defines `light_interception` and `Beer`:
Import the examples defined in the `Examples` sub-module (`light_interception` and `Beer`):

```julia
include(joinpath(pkgdir(PlantSimEngine), "examples/Beer.jl"))
using PlantSimEngine.Examples
```

And then making a [`ModelList`](@ref) with the `Beer` model:
Expand Down Expand Up @@ -187,8 +187,8 @@ For example we can simulate the `light_interception` of a leaf like so:
```@example usepkg
using PlantSimEngine, PlantMeteo
# Including the script defining light_interception and Beer:
include(joinpath(pkgdir(PlantSimEngine), "examples/Beer.jl"))
# Import the examples defined in the `Examples` sub-module
using PlantSimEngine.Examples
meteo = Atmosphere(T = 20.0, Wind = 1.0, Rh = 0.65, Ri_PAR_f = 500.0)
Expand Down
7 changes: 4 additions & 3 deletions docs/src/extending/implement_a_model.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@ In those files, you'll see that in order to implement a new model you'll need to

If you create your own process, the function will print a short tutorial on how to do all that, adapted to the process you just created (see [Implement a new process](@ref)).

In this page, we'll just implement a model for a process that already exists: the light interception. This process is defined in `PlantBiophysics.jl`, but also in an example script in `PlantSimEngine.jl` here: [`examples/Beer.jl`](https://github.com/VirtualPlantLab/PlantSimEngine.jl/blob/main/examples/Beer.jl).
In this page, we'll just implement a model for a process that already exists: the light interception. This process is defined in `PlantBiophysics.jl`, and also made available as an example model from the `Examples` sub-module. You can access the script from here: [`examples/Beer.jl`](https://github.com/VirtualPlantLab/PlantSimEngine.jl/blob/main/examples/Beer.jl).

We can include this file like so:
We can import the model like so:

```julia
include(joinpath(pkgdir(PlantSimEngine), "examples/Beer.jl"))
# Import the example models defined in the `Examples` sub-module:
using PlantSimEngine.Examples
```

But instead of just using it, we will review the script line by line.
Expand Down
6 changes: 4 additions & 2 deletions docs/src/fitting.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

```@setup usepkg
using PlantSimEngine, PlantMeteo, DataFrames, Statistics
include(joinpath(pkgdir(PlantSimEngine), "examples/Beer.jl"))
using PlantSimEngine.Examples
meteo = Atmosphere(T=20.0, Wind=1.0, P=101.3, Rh=0.65, Ri_PAR_f=300.0)
m = ModelList(Beer(0.6), status=(LAI=2.0,))
run!(m, meteo)
Expand Down Expand Up @@ -42,7 +43,8 @@ Importing the script first:

```julia
using PlantSimEngine, PlantMeteo, DataFrames, Statistics
include(joinpath(pkgdir(PlantSimEngine), "examples/Beer.jl"))
# Import the examples defined in the `Examples` sub-module:
using PlantSimEngine.Examples
```

Defining the meteo data:
Expand Down
Loading

0 comments on commit 48dd4f1

Please sign in to comment.