Exercise 05: Size range
This exercise changes the size ranges represented by the Agate.jl NiPiZD model. We compare the default two-phytoplankton, two-zooplankton community with a wider but physiologically realistic range for both trophic groups.
Loading dependencies
using Agate
using Agate.Introspection: tracer_names
using CairoMakie
workshop_script = let dir = @__DIR__
while !isfile(joinpath(dir, "src", "AgateWorkshop.jl"))
parent = dirname(dir)
parent == dir && error("Could not find src/AgateWorkshop.jl")
dir = parent
end
joinpath(dir, "src", "AgateWorkshop.jl")
end
include(workshop_script)
mkpath("outputs")
mkpath("figures")
Size-range cases
The wide-range case keeps two classes per trophic group and logarithmic spacing, but expands the endpoints to include small picophytoplankton through large microphytoplankton, and microzooplankton through small mesozooplankton.
bgc_default = default_quickstart_bgc()
bgc_wide_range = Agate.Models.NiPiZD.construct(;
phyto_size_structure = (n = 2, min_esd = 0.6, max_esd = 60.0, splitting = :log_splitting),
zoo_size_structure = (n = 2, min_esd = 6.0, max_esd = 600.0, splitting = :log_splitting),
)
bgcs = [bgc_default, bgc_wide_range]
case_labels = ["default size range", "wide realistic size range"]
for (label, bgc) in zip(case_labels, bgcs)
println(label)
println(tracer_names(bgc))
end
default size range
[:N, :D, :Z1, :Z2, :P1, :P2]
wide realistic size range
[:N, :D, :Z1, :Z2, :P1, :P2]
Run zero-dimensional ecosystem simulations
Total initial plankton biomass is the same in both cases and is split evenly across the plankton tracers.
runs = [
run_box_model(
bgc;
filename = joinpath("outputs", "05_size_range_$(i).jld2"),
initial_conditions = default_initial_conditions(bgc; nutrient = 8.0, total_plankton_biomass = 0.15),
)
for (i, bgc) in enumerate(bgcs)
]
timeseries = [read_box_tracer_timeseries(run.filename, run.tracer_syms) for run in runs]
[ Info: Initializing simulation...
[ Info: ... simulation initialization complete (3.165 ms)
[ Info: Executing initial time step...
[ Info: ... initial time step complete (160.282 μs).
[ Info: Simulation is stopping after running for 6.121 seconds.
[ Info: Simulation time 1095 days equals or exceeds stop time 1095 days.
[ Info: Initializing simulation...
[ Info: ... simulation initialization complete (1.804 ms)
[ Info: Executing initial time step...
[ Info: ... initial time step complete (202.786 μs).
[ Info: Simulation is stopping after running for 4.671 seconds.
[ Info: Simulation time 1095 days equals or exceeds stop time 1095 days.
Tracer concentration comparison
comparison_figure_path = joinpath("figures", "05_size_range_timeseries_comparison.png")
fig_comparison = plot_box_timeseries(timeseries; labels = case_labels)
save(comparison_figure_path, fig_comparison; px_per_unit = 1)
display(fig_comparison)
fig_comparisonRelative nitrogen contributions: default size range
nitrogen_default_figure_path = joinpath("figures", "05_size_range_relative_nitrogen_default.png")
fig_nitrogen_default = plot_contributions(timeseries[1].times, timeseries[1].data)
save(nitrogen_default_figure_path, fig_nitrogen_default; px_per_unit = 1)
display(fig_nitrogen_default)
fig_nitrogen_defaultRelative nitrogen contributions: wide realistic size range
nitrogen_wide_figure_path = joinpath("figures", "05_size_range_relative_nitrogen_wide.png")
fig_nitrogen_wide = plot_contributions(timeseries[2].times, timeseries[2].data)
save(nitrogen_wide_figure_path, fig_nitrogen_wide; px_per_unit = 1)
display(fig_nitrogen_wide)
fig_nitrogen_wideCommunity-weighted mean size comparison
size_comparison_figure_path = joinpath("figures", "05_size_range_cwm_size_comparison.png")
fig_size_comparison = plot_cwm_size(timeseries, bgcs; labels = case_labels)
save(size_comparison_figure_path, fig_size_comparison; px_per_unit = 1)
display(fig_size_comparison)
fig_size_comparison