Exercise 07: Assimilation Efficiency
Assimilation efficiency controls how efficiently consumed prey biomass is converted into zooplankton biomass. This exercise mirrors the palatability matrix exercise: first inspect the derived assimilation matrices, then run each configuration in a box model.
Loading dependencies
using Agate
using Agate.Introspection: interaction_matrix
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(joinpath("outputs"))
mkpath(joinpath("figures"))
Construct assimilation-efficiency configurations
Palatability controls which prey are consumed. Assimilation efficiency controls how much consumed prey biomass becomes zooplankton biomass. In the default model, assimilation_efficiency is defined for each zooplankton type and is expanded into a consumer-by-prey assimilation matrix.
We compare three cases:
- the default model;
- a high-assimilation case, where both zooplankton types assimilate consumed prey more efficiently;
- a manual matrix case, where assimilation efficiency depends on both consumer and prey identity.
bgc = default_quickstart_bgc()
default_assimilation_efficiency = bgc.parameters.assimilation_efficiency
println("Default assimilation efficiency: ", default_assimilation_efficiency)
high_assimilation_bgc = Agate.Models.NiPiZD.construct(;
parameters = (assimilation_efficiency = (Z1 = 0.8, Z2 = 0.8),),
)
manual_matrix_bgc = Agate.Models.NiPiZD.construct(;
assimilation_matrix = Float32[0.9 0.25; 0.25 0.9],
)
bgcs = [bgc, high_assimilation_bgc, manual_matrix_bgc]
case_labels = ["default", "high assimilation", "manual matrix"]
Default assimilation efficiency: [0.32, 0.32, 0.0, 0.0]
Assimilation matrices
interaction_matrix(bgc, :assimilation) returns a labelled interaction table. Rows are consumers and columns are prey. The default and high-assimilation cases derive this matrix from the zooplankton assimilation_efficiency parameter. The manual-matrix case supplies the full matrix directly.
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
assimilation_figure_path = joinpath("figures", "07_assimilation_matrices.png")
fig_assimilation = Figure(; size = (760, 280), fontsize = 12)
assimilation_tables = [interaction_matrix(bgc, :assimilation) for bgc in bgcs]
hm = plot_interaction_matrix!(fig_assimilation, (1, 1), assimilation_tables[1]; title = case_labels[1])
plot_interaction_matrix!(fig_assimilation, (1, 2), assimilation_tables[2]; title = case_labels[2])
plot_interaction_matrix!(fig_assimilation, (1, 3), assimilation_tables[3]; title = case_labels[3])
Colorbar(fig_assimilation[1, 4], hm; label = "assimilation efficiency")
save(assimilation_figure_path, fig_assimilation; px_per_unit = 1)
display(fig_assimilation)
fig_assimilationRun box models
We use the same box-model wrapper as in Exercise 02 so the outputs can be read by the workshop diagnostics.
run = run_box_model(bgc; filename = joinpath("outputs", "07_assimilation_default.jld2"))
high_run = run_box_model(high_assimilation_bgc; filename = joinpath("outputs", "07_assimilation_high.jld2"))
manual_run = run_box_model(manual_matrix_bgc; filename = joinpath("outputs", "07_assimilation_manual_matrix.jld2"))
timeseries = read_box_tracer_timeseries(run.filename, run.tracer_syms)
high_timeseries = read_box_tracer_timeseries(high_run.filename, high_run.tracer_syms)
manual_timeseries = read_box_tracer_timeseries(manual_run.filename, manual_run.tracer_syms)
times = timeseries.times
data = timeseries.data
[ Info: Initializing simulation...
[ Info: ... simulation initialization complete (4.493 ms)
[ Info: Executing initial time step...
[ Info: ... initial time step complete (249.807 μs).
[ Info: Simulation is stopping after running for 4.886 seconds.
[ Info: Simulation time 1095 days equals or exceeds stop time 1095 days.
[ Info: Initializing simulation...
[ Info: ... simulation initialization complete (1.749 ms)
[ Info: Executing initial time step...
[ Info: ... initial time step complete (161.894 μs).
[ Info: Simulation is stopping after running for 4.704 seconds.
[ Info: Simulation time 1095 days equals or exceeds stop time 1095 days.
[ Info: Initializing simulation...
[ Info: ... simulation initialization complete (1.747 ms)
[ Info: Executing initial time step...
[ Info: ... initial time step complete (177.248 μs).
[ Info: Simulation is stopping after running for 4.580 seconds.
[ Info: Simulation time 1095 days equals or exceeds stop time 1095 days.
Tracer concentration comparison
The concentration diagnostic compares all three assimilation-efficiency configurations.
comparison_figure_path = joinpath("figures", "07_assimilation_timeseries_comparison.png")
fig_comparison = plot_box_timeseries(
[timeseries, high_timeseries, manual_timeseries];
labels = case_labels,
)
save(comparison_figure_path, fig_comparison; px_per_unit = 1)
display(fig_comparison)
fig_comparisonRelative nitrogen contributions: default assimilation
nitrogen_default_figure_path = joinpath("figures", "07_assimilation_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: high assimilation
nitrogen_high_figure_path = joinpath("figures", "07_assimilation_relative_nitrogen_high.png")
fig_nitrogen_high = plot_contributions(high_timeseries.times, high_timeseries.data)
save(nitrogen_high_figure_path, fig_nitrogen_high; px_per_unit = 1)
display(fig_nitrogen_high)
fig_nitrogen_highRelative nitrogen contributions: manual matrix
nitrogen_manual_figure_path = joinpath("figures", "07_assimilation_relative_nitrogen_manual_matrix.png")
fig_nitrogen_manual = plot_contributions(manual_timeseries.times, manual_timeseries.data)
save(nitrogen_manual_figure_path, fig_nitrogen_manual; px_per_unit = 1)
display(fig_nitrogen_manual)
fig_nitrogen_manualCommunity-weighted mean size comparison
Each time series is paired with its matching biogeochemistry object because plankton sizes are defined on the model configuration.
cwm_size_comparison_figure_path = joinpath("figures", "07_assimilation_cwm_size_comparison.png")
fig_size_comparison = plot_cwm_size(
[timeseries, high_timeseries, manual_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