Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/Benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ jobs:
with:
julia-version: ${{ matrix.version }}
bench-on: ${{ github.event.pull_request.head.sha }}
extra-pkgs: |
https://github.com/PalmStudio/XPalm.jl#main
https://github.com/VEZY/PlantBiophysics.jl#master
15 changes: 4 additions & 11 deletions .github/workflows/Integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ concurrency:
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}
jobs:
test:
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ github.event_name }}
runs-on: ${{ matrix.os }}
timeout-minutes: 60
permissions: # needed to allow julia-actions/cache to proactively delete old caches that it has created
permissions:
# needed to allow julia-actions/cache to proactively delete old caches that it has created
actions: write
contents: read
strategy:
Expand All @@ -26,22 +27,14 @@ jobs:
- "1"
os:
- ubuntu-latest
arch:
- x64
package:
- { user: PalmStudio, repo: XPalm.jl, branch: main, default: main }
- {
user: VEZY,
repo: PlantBioPhysics.jl,
branch: master,
default: master,
}
- { user: VEZY, repo: PlantBioPhysics.jl, branch: master, default: master }
steps:
- uses: actions/checkout@v6
- uses: julia-actions/setup-julia@v3
with:
version: ${{ matrix.version }}
arch: ${{ matrix.arch }}
- uses: julia-actions/julia-buildpkg@v1
- name: Clone Downstream
uses: actions/checkout@v6
Expand Down
36 changes: 18 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,52 +233,52 @@ The package is designed to be easily scalable, and can be used to simulate model

```julia
mapping = ModelMapping(
"Scene" => ToyDegreeDaysCumulModel(),
"Plant" => (
:Scene => ToyDegreeDaysCumulModel(),
:Plant => (
MultiScaleModel(
model=ToyLAIModel(),
mapped_variables=[
:TT_cu => "Scene",
:TT_cu => :Scene,
],
),
Beer(0.6),
MultiScaleModel(
model=ToyAssimModel(),
mapped_variables=[:soil_water_content => "Soil"],
mapped_variables=[:soil_water_content => :Soil],
),
MultiScaleModel(
model=ToyCAllocationModel(),
mapped_variables=[
:carbon_demand => ["Leaf", "Internode"],
:carbon_allocation => ["Leaf", "Internode"]
:carbon_demand => [:Leaf, :Internode],
:carbon_allocation => [:Leaf, :Internode]
],
),
MultiScaleModel(
model=ToyPlantRmModel(),
mapped_variables=[:Rm_organs => ["Leaf" => :Rm, "Internode" => :Rm],],
mapped_variables=[:Rm_organs => [:Leaf => :Rm, :Internode => :Rm],],
),
),
"Internode" => (
:Internode => (
MultiScaleModel(
model=ToyCDemandModel(optimal_biomass=10.0, development_duration=200.0),
mapped_variables=[:TT => "Scene",],
mapped_variables=[:TT => :Scene,],
),
MultiScaleModel(
model=ToyInternodeEmergence(TT_emergence=20.0),
mapped_variables=[:TT_cu => "Scene"],
mapped_variables=[:TT_cu => :Scene],
),
ToyMaintenanceRespirationModel(1.5, 0.06, 25.0, 0.6, 0.004),
Status(carbon_biomass=1.0)
),
"Leaf" => (
:Leaf => (
MultiScaleModel(
model=ToyCDemandModel(optimal_biomass=10.0, development_duration=200.0),
mapped_variables=[:TT => "Scene",],
mapped_variables=[:TT => :Scene,],
),
ToyMaintenanceRespirationModel(2.1, 0.06, 25.0, 1.0, 0.025),
Status(carbon_biomass=1.0)
),
"Soil" => (
:Soil => (
ToySoilWaterModel(),
),
);
Expand All @@ -305,11 +305,11 @@ And run the simulation:

```julia
out_vars = ModelMapping(
"Scene" => (:TT_cu,),
"Plant" => (:carbon_allocation, :carbon_assimilation, :soil_water_content, :aPPFD, :TT_cu, :LAI),
"Leaf" => (:carbon_demand, :carbon_allocation),
"Internode" => (:carbon_demand, :carbon_allocation),
"Soil" => (:soil_water_content,),
:Scene => (:TT_cu,),
:Plant => (:carbon_allocation, :carbon_assimilation, :soil_water_content, :aPPFD, :TT_cu, :LAI),
:Leaf => (:carbon_demand, :carbon_allocation),
:Internode => (:carbon_demand, :carbon_allocation),
:Soil => (:soil_water_content,),
)

out = run!(mtg, mapping, meteo, outputs=out_vars, executor=SequentialEx());
Expand Down
4 changes: 2 additions & 2 deletions benchmark/benchmarks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ SUITE[suite_name]["XPalm_setup"] = @benchmarkable xpalm_default_param_create() s
palm, models, out_vars, meteo = xpalm_default_param_create()
sim_outputs = xpalm_default_param_run(palm, models, out_vars, meteo)

SUITE[suite_name]["XPalm_run"] = @benchmarkable xpalm_default_param_run($palm, $models, $out_vars, $meteo) seconds = 120
SUITE[suite_name]["XPalm_convert_outputs"] = @benchmarkable xpalm_default_param_convert_outputs($sim_outputs) seconds = 120
SUITE[suite_name]["XPalm_run"] = @benchmarkable xpalm_default_param_run(palm, models, out_vars, meteo) setup = ((palm, models, out_vars, meteo) = xpalm_default_param_create())
SUITE[suite_name]["XPalm_convert_outputs"] = @benchmarkable xpalm_default_param_convert_outputs($sim_outputs)

#tune!(SUITE)
#results = run(SUITE, verbose=true)
Expand Down
58 changes: 29 additions & 29 deletions benchmark/test-PSE-benchmark.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,21 @@ function PlantSimEngine.run!(m::ToyInternodeCrazyEmergence, models, status, mete

if length(MultiScaleTreeGraph.children(status.node)) == 1 && status.TT_cu - status.TT_cu_emergence >= m.TT_emergence

status_new_internode = add_organ!(status.node, sim_object, "<", "Internode", 2, index=1)
add_organ!(status_new_internode.node, sim_object, "+", "Leaf", 2, index=1)
status_new_internode = add_organ!(status.node, sim_object, "<", :Internode, 2, index=1)
add_organ!(status_new_internode.node, sim_object, "+", :Leaf, 2, index=1)
status_new_internode.TT_cu_emergence = status.TT_cu
elseif (length(MultiScaleTreeGraph.children(status.node)) >= 2 && length(MultiScaleTreeGraph.children(status.node)) < 7) && status.TT_cu - status.TT_cu_emergence >= m.TT_emergence
status_new_internode = add_organ!(status.node, sim_object, "<", "Internode", 2, index=1)
add_organ!(status.node, sim_object, "+", "Leaf", 2, index=4)
add_organ!(status.node, sim_object, "+", "Leaf", 2, index=5)
status_new_internode = add_organ!(status.node, sim_object, "<", :Internode, 2, index=1)
add_organ!(status.node, sim_object, "+", :Leaf, 2, index=4)
add_organ!(status.node, sim_object, "+", :Leaf, 2, index=5)
status_new_internode.TT_cu_emergence = status.TT_cu
elseif (length(MultiScaleTreeGraph.children(status.node)) >= 7 && length(MultiScaleTreeGraph.children(status.node)) < 30) && status.TT_cu - status.TT_cu_emergence >= m.TT_emergence
add_organ!(status.node, sim_object, "+", "Leaf", 2, index=6)
add_organ!(status.node, sim_object, "+", "Leaf", 2, index=7)
add_organ!(status.node, sim_object, "+", "Leaf", 2, index=8)
add_organ!(status.node, sim_object, "+", "Leaf", 2, index=9)
add_organ!(status.node, sim_object, "+", "Leaf", 2, index=10)
add_organ!(status.node, sim_object, "+", "Leaf", 2, index=11)
add_organ!(status.node, sim_object, "+", :Leaf, 2, index=6)
add_organ!(status.node, sim_object, "+", :Leaf, 2, index=7)
add_organ!(status.node, sim_object, "+", :Leaf, 2, index=8)
add_organ!(status.node, sim_object, "+", :Leaf, 2, index=9)
add_organ!(status.node, sim_object, "+", :Leaf, 2, index=10)
add_organ!(status.node, sim_object, "+", :Leaf, 2, index=11)

end

Expand All @@ -60,62 +60,62 @@ function do_benchmark_on_heavier_mtg()

#similar to the mtg growth test but with a much lower emergence threshold
mapping = ModelMapping(
"Scene" => ToyDegreeDaysCumulModel(),
"Plant" => (
:Scene => ToyDegreeDaysCumulModel(),
:Plant => (
MultiScaleModel(
model=ToyLAIModel(),
mapped_variables=[
:TT_cu => "Scene",
:TT_cu => :Scene,
],
),
PlantSimEngine.Examples.Beer(0.6),
MultiScaleModel(
model=ToyCAllocationModel(),
mapped_variables=[
:carbon_assimilation => ["Leaf"],
:carbon_demand => ["Leaf", "Internode"],
:carbon_allocation => ["Leaf", "Internode"]
:carbon_assimilation => [:Leaf],
:carbon_demand => [:Leaf, :Internode],
:carbon_allocation => [:Leaf, :Internode]
],
),
MultiScaleModel(
model=ToyPlantRmModel(),
mapped_variables=[:Rm_organs => ["Leaf" => :Rm, "Internode" => :Rm],],
mapped_variables=[:Rm_organs => [:Leaf => :Rm, :Internode => :Rm],],
),
),
"Internode" => (
:Internode => (
MultiScaleModel(
model=ToyCDemandModel(optimal_biomass=10.0, development_duration=200.0),
mapped_variables=[:TT => "Scene",],
mapped_variables=[:TT => :Scene,],
),
MultiScaleModel(
model=ToyInternodeCrazyEmergence(TT_emergence=1.0),
mapped_variables=[:TT_cu => "Scene"],
mapped_variables=[:TT_cu => :Scene],
),
ToyMaintenanceRespirationModel(1.5, 0.06, 25.0, 0.6, 0.004),
Status(carbon_biomass=1.0)
),
"Leaf" => (
:Leaf => (
MultiScaleModel(
model=ToyAssimModel(),
mapped_variables=[:soil_water_content => "Soil", :aPPFD => "Plant"],
mapped_variables=[:soil_water_content => :Soil, :aPPFD => :Plant],
),
MultiScaleModel(
model=ToyCDemandModel(optimal_biomass=10.0, development_duration=200.0),
mapped_variables=[:TT => "Scene",],
mapped_variables=[:TT => :Scene,],
),
ToyMaintenanceRespirationModel(2.1, 0.06, 25.0, 1.0, 0.025),
Status(carbon_biomass=1.0)
),
"Soil" => (
:Soil => (
ToySoilWaterModel(),
),
)

out_vars = Dict(
"Leaf" => (:carbon_assimilation, :carbon_demand, :soil_water_content, :carbon_allocation),
"Internode" => (:carbon_allocation, :TT_cu_emergence),
"Plant" => (:carbon_allocation,),
"Soil" => (:soil_water_content,),
:Leaf => (:carbon_assimilation, :carbon_demand, :soil_water_content, :carbon_allocation),
:Internode => (:carbon_allocation, :TT_cu_emergence),
:Plant => (:carbon_allocation,),
:Soil => (:soil_water_content,),
)

out = run!(mtg, mapping, meteo_day, tracked_outputs=out_vars, executor=SequentialEx())
Expand Down
26 changes: 13 additions & 13 deletions benchmark/test-multirate-buffer-benchmark.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ function PlantSimEngine.run!(::MRBenchConsumer24Model, models, status, meteo, co
end

function _build_multirate_benchmark_mtg(nleaves::Int)
mtg = Node(MultiScaleTreeGraph.NodeMTG("/", "Scene", 1, 0))
plant = Node(mtg, MultiScaleTreeGraph.NodeMTG("+", "Plant", 1, 1))
internode = Node(plant, MultiScaleTreeGraph.NodeMTG("/", "Internode", 1, 2))
mtg = Node(MultiScaleTreeGraph.NodeMTG("/", :Scene, 1, 0))
plant = Node(mtg, MultiScaleTreeGraph.NodeMTG("+", :Plant, 1, 1))
internode = Node(plant, MultiScaleTreeGraph.NodeMTG("/", :Internode, 1, 2))

for i in 1:nleaves
Node(internode, MultiScaleTreeGraph.NodeMTG("+", "Leaf", i, 2))
Node(internode, MultiScaleTreeGraph.NodeMTG("+", :Leaf, i, 2))
end

return mtg
Expand All @@ -46,30 +46,30 @@ function setup_multirate_buffer_benchmark(; nleaves=2000, ndays=30)
mtg = _build_multirate_benchmark_mtg(nleaves)

mapping = ModelMapping(
"Leaf" => (
:Leaf => (
ModelSpec(MRBenchSourceModel(Ref(0))) |> TimeStepModel(1.0),
),
"Plant" => (
:Plant => (
ModelSpec(MRBenchConsumer4Model()) |>
MultiScaleModel([:X => ["Leaf"]]) |>
MultiScaleModel([:X => [:Leaf]]) |>
TimeStepModel(ClockSpec(4.0, 1.0)) |>
InputBindings(; X=(process=:mrbenchsource, var=:X, scale="Leaf", policy=Integrate())),
InputBindings(; X=(process=:mrbenchsource, var=:X, scale=:Leaf, policy=Integrate())),
ModelSpec(MRBenchConsumer24Model()) |>
MultiScaleModel([:X => ["Leaf"]]) |>
MultiScaleModel([:X => [:Leaf]]) |>
TimeStepModel(ClockSpec(24.0, 1.0)) |>
InputBindings(; X=(process=:mrbenchsource, var=:X, scale="Leaf", policy=Integrate())),
InputBindings(; X=(process=:mrbenchsource, var=:X, scale=:Leaf, policy=Integrate())),
),
)

nsteps = 24 * ndays
meteo = Weather(repeat([Atmosphere(T=20.0, Wind=1.0, Rh=0.65)], nsteps))

reqs = [
OutputRequest("Leaf", :X; name=:x_hourly, process=:mrbenchsource, policy=HoldLast()),
OutputRequest("Leaf", :X; name=:x_daily_sum, process=:mrbenchsource, policy=Integrate(), clock=ClockSpec(24.0, 1.0)),
OutputRequest(:Leaf, :X; name=:x_hourly, process=:mrbenchsource, policy=HoldLast()),
OutputRequest(:Leaf, :X; name=:x_daily_sum, process=:mrbenchsource, policy=Integrate(), clock=ClockSpec(24.0, 1.0)),
]

tracked = Dict("Plant" => (:Y4, :Y24), "Leaf" => (:X,))
tracked = Dict(:Plant => (:Y4, :Y24), :Leaf => (:X,))
return mtg, mapping, meteo, reqs, tracked, nsteps
end

Expand Down
2 changes: 2 additions & 0 deletions benchmark/test-xpalm.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ function xpalm_default_param_convert_outputs(sim_outputs)
end


println(Pkg.status("XPalm"))

#=@testset "XPalm simple test" begin
# default number of seconds is 5
b_XP = @benchmark xpalm_default_param_run() seconds = 120
Expand Down
14 changes: 7 additions & 7 deletions docs/src/API/API_public.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ Scope selection detail:
### Exporting variables at requested rates

```julia
req_hold = OutputRequest("Leaf", :A; name=:A_hourly, process=:assim, policy=HoldLast())
req_day = OutputRequest("Leaf", :A; name=:A_daily_sum, process=:assim, policy=Integrate(), clock=ClockSpec(24.0, 1.0))
req_hold = OutputRequest(:Leaf, :A; name=:A_hourly, process=:assim, policy=HoldLast())
req_day = OutputRequest(:Leaf, :A; name=:A_daily_sum, process=:assim, policy=Integrate(), clock=ClockSpec(24.0, 1.0))
run!(sim, meteo; tracked_outputs=[req_hold, req_day], executor=SequentialEx())
out = collect_outputs(sim; sink=DataFrame)

Expand Down Expand Up @@ -126,23 +126,23 @@ Use `Integrate` for accumulation semantics and `Aggregate` for summary-statistic
```julia
ModelSpec(DailyModel()) |>
TimeStepModel(ClockSpec(24.0, 1.0)) |>
InputBindings(; a=(process=:hourly_assim, var=:A, scale="Leaf", policy=Integrate(SumReducer())))
InputBindings(; a=(process=:hourly_assim, var=:A, scale=:Leaf, policy=Integrate(SumReducer())))

ModelSpec(DailyModel()) |>
TimeStepModel(ClockSpec(24.0, 1.0)) |>
InputBindings(; a=(process=:hourly_assim, var=:A, scale="Leaf", policy=Aggregate(MaxReducer())))
InputBindings(; a=(process=:hourly_assim, var=:A, scale=:Leaf, policy=Aggregate(MaxReducer())))

ModelSpec(DailyModel()) |>
TimeStepModel(ClockSpec(24.0, 1.0)) |>
InputBindings(; a=(process=:hourly_assim, var=:A, scale="Leaf", policy=Integrate(vals -> maximum(vals) - minimum(vals))))
InputBindings(; a=(process=:hourly_assim, var=:A, scale=:Leaf, policy=Integrate(vals -> maximum(vals) - minimum(vals))))

ModelSpec(DailyModel()) |>
TimeStepModel(ClockSpec(24.0, 1.0)) |>
InputBindings(; a=(process=:hourly_assim, var=:A, scale="Leaf", policy=Integrate((vals, durations) -> sum(vals .* durations))))
InputBindings(; a=(process=:hourly_assim, var=:A, scale=:Leaf, policy=Integrate((vals, durations) -> sum(vals .* durations))))

ModelSpec(DailyModel()) |>
TimeStepModel(ClockSpec(24.0, 1.0)) |>
InputBindings(; a=(process=:hourly_assim, var=:A, scale="Leaf", policy=Integrate(PlantMeteo.DurationSumReducer())))
InputBindings(; a=(process=:hourly_assim, var=:A, scale=:Leaf, policy=Integrate(PlantMeteo.DurationSumReducer())))
```

Built-in reducer types are:
Expand Down
Loading
Loading