Exercise 06: Palatability
Predator-prey palatability controls how strongly each zooplankton type grazes each phytoplankton type. This exercise follows the Agate.jl matrix example: first inspect the palatability matrices, then run each configuration in a box model.
Loading dependencies
using Agate
using Agate.Introspection: interaction_matrix
using CairoMakie
using Oceananigans.Units: day
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(joinpath("outputs"))
mkpath(joinpath("figures"))
Construct palatability configurations
The default model derives its palatability matrix allometrically. By default, zooplankton prefer prey that are 10 times smaller than themselves. We compare that default with two alternatives:
- a different preferred predator:prey size ratio,
Vopt = 5, for both zooplankton types; - an explicit custom palatability matrix supplied directly.
bgc = default_quickstart_bgc()
vopt_bgc = Agate.Models.NiPiZD.construct(;
parameters = (optimum_predator_prey_ratio = (Z1 = 5.0, Z2 = 5.0),),
)
custom_bgc = Agate.Models.NiPiZD.construct(;
palatability_matrix = [0.0 1.0; 1.0 0.0],
)
bgcs = [bgc, vopt_bgc, custom_bgc]
case_labels = ["Vopt = 10", "Vopt = 5", "custom palatability"]
Palatability matrices
interaction_matrix(bgc, :palatability) returns a labelled interaction table. Rows are consumers and columns are prey.
function plot_interaction_matrix!(fig, position, table; title)
matrix = Matrix(table.matrix)
nrows, ncols = size(matrix)
ax = Axis(
fig[position...];
title,
xlabel = string(table.column_axis),
ylabel = string(table.row_axis),
xticks = (1:ncols, string.(table.columns)),
yticks = (1:nrows, string.(table.rows)),
yreversed = true,
aspect = DataAspect(),
)
hm = heatmap!(ax, 1:ncols, 1:nrows, matrix'; colorrange = (0, 1))
for row in 1:nrows, col in 1:ncols
text!(
ax,
col,
row;
text = string(round(matrix[row, col]; digits = 2)),
align = (:center, :center),
fontsize = 11,
)
end
return hm
end
palatability_figure_path = joinpath("figures", "06_palatability_matrices.png")
fig_palatability = Figure(; size = (760, 280), fontsize = 12)
palatability_tables = [interaction_matrix(bgc, :palatability) for bgc in bgcs]
hm = plot_interaction_matrix!(fig_palatability, (1, 1), palatability_tables[1]; title = case_labels[1])
plot_interaction_matrix!(fig_palatability, (1, 2), palatability_tables[2]; title = case_labels[2])
plot_interaction_matrix!(fig_palatability, (1, 3), palatability_tables[3]; title = case_labels[3])
Colorbar(fig_palatability[1, 4], hm; label = "palatability")
save(palatability_figure_path, fig_palatability; px_per_unit = 1)
display(fig_palatability)
fig_palatabilityRun box models
We use the same box-model wrapper as in Exercise 02 so the output can be read by the workshop diagnostics.
run = run_box_model(bgc; filename = joinpath("outputs", "06_palatability_default.jld2"))
vopt_run = run_box_model(vopt_bgc; filename = joinpath("outputs", "06_palatability_vopt5.jld2"))
custom_run = run_box_model(custom_bgc; filename = joinpath("outputs", "06_palatability_custom.jld2"))
timeseries = read_box_tracer_timeseries(run.filename, run.tracer_syms)
vopt_timeseries = read_box_tracer_timeseries(vopt_run.filename, vopt_run.tracer_syms)
custom_timeseries = read_box_tracer_timeseries(custom_run.filename, custom_run.tracer_syms)
times = timeseries.times
data = timeseries.data
[ Info: Initializing simulation...
[ Info: ... simulation initialization complete (4.098 ms)
[ Info: Executing initial time step...
[ Info: ... initial time step complete (212.181 μs).
[ Info: Simulation is stopping after running for 4.770 seconds.
[ Info: Simulation time 1095 days equals or exceeds stop time 1095 days.
[ Info: Initializing simulation...
[ Info: ... simulation initialization complete (1.856 ms)
[ Info: Executing initial time step...
[ Info: ... initial time step complete (224.299 μs).
[ Info: Simulation is stopping after running for 4.749 seconds.
[ Info: Simulation time 1095 days equals or exceeds stop time 1095 days.
[ Info: Initializing simulation...
[ Info: ... simulation initialization complete (1.805 ms)
[ Info: Executing initial time step...
[ Info: ... initial time step complete (229.226 μs).
[ Info: Simulation is stopping after running for 4.889 seconds.
[ Info: Simulation time 1095 days equals or exceeds stop time 1095 days.
Tracer concentration comparison
The concentration diagnostic compares all three palatability configurations.
comparison_figure_path = joinpath("figures", "06_palatability_timeseries_comparison.png")
fig_comparison = plot_box_timeseries(
[timeseries, vopt_timeseries, custom_timeseries];
labels = case_labels,
)
save(comparison_figure_path, fig_comparison; px_per_unit = 1)
display(fig_comparison)
fig_comparisonRelative nitrogen contributions: default palatability
nitrogen_default_figure_path = joinpath("figures", "06_palatability_relative_nitrogen_default.png")
fig_nitrogen_default = plot_contributions(timeseries.times, timeseries.data)
save(nitrogen_default_figure_path, fig_nitrogen_default; px_per_unit = 1)
display(fig_nitrogen_default)
fig_nitrogen_defaultRelative nitrogen contributions: Vopt = 5
nitrogen_vopt_figure_path = joinpath("figures", "06_palatability_relative_nitrogen_vopt5.png")
fig_nitrogen_vopt = plot_contributions(vopt_timeseries.times, vopt_timeseries.data)
save(nitrogen_vopt_figure_path, fig_nitrogen_vopt; px_per_unit = 1)
display(fig_nitrogen_vopt)
fig_nitrogen_voptRelative nitrogen contributions: custom palatability
nitrogen_custom_figure_path = joinpath("figures", "06_palatability_relative_nitrogen_custom.png")
fig_nitrogen_custom = plot_contributions(custom_timeseries.times, custom_timeseries.data)
save(nitrogen_custom_figure_path, fig_nitrogen_custom; px_per_unit = 1)
display(fig_nitrogen_custom)
fig_nitrogen_customCommunity-weighted mean size comparison
Each time series is paired with its matching biogeochemistry object because the plankton sizes are defined on the model configuration.
cwm_size_comparison_figure_path = joinpath("figures", "06_palatability_cwm_size_comparison.png")
fig_size_comparison = plot_cwm_size(
[timeseries, vopt_timeseries, custom_timeseries],
bgcs;
labels = case_labels,
)
save(cwm_size_comparison_figure_path, fig_size_comparison; px_per_unit = 1)
display(fig_size_comparison)
fig_size_comparison