Interpolated Production
Not all production curves follow the Bosscher & Schlager model. In some cases it is more natural to specify the curve directly, as a set of depth knots and multipliers applied to a peak rate. The InterpolatedProduction type supports this:
\[g(t, w) = g_{\max} f(w),\]
where $f(w)$ is a piecewise-linear function defined by (depth_knots, multipliers) pairs, with flat extrapolation outside the knot range.
This curve is independent of insolation — the per-depth shape is fixed by the user. To vary the overall scale over time, wrap it in MultiplyProduction.
Example
using CarboKitten.Production: InterpolatedProduction
# Shallow reef builder: peaks at 5–15 m, dies off by 50 m
InterpolatedProduction(
maximum_production = 500.0u"m/Myr",
depth_knots = [0.0u"m", 5.0u"m", 15.0u"m", 30.0u"m", 50.0u"m"],
multipliers = [0.0, 1.0, 1.0, 0.4, 0.0])Implementation
file:src/Production/Interpolated.jl
module Interpolated
using Unitful
using ...Utility: in_units_of
using Interpolations
import ..Abstract: AbstractInput, AbstractProduction, production_profile
# =============================================================================
# Interpolated (knot-based) production curve
# =============================================================================
"""
InterpolatedProduction(; maximum_production, depth_knots, multipliers)
A depth-only production curve defined by a peak rate and a piecewise-linear
shape over `(depth, multiplier)` knots. Independent of insolation.
rate(t, w) = maximum_production × interpolate(depth_knots, multipliers; w)
`depth_knots` need not be sorted; they are sorted internally.
# Example
InterpolatedProduction(
maximum_production = 500.0u"m/Myr",
depth_knots = [0.0u"m", 5.0u"m", 20.0u"m", 50.0u"m"],
multipliers = [0.0, 1.0, 0.6, 0.0])
"""
@kwdef struct InterpolatedProduction <: AbstractProduction
maximum_production::typeof(1.0u"m/Myr") = 0.0u"m/Myr"
depth_knots::Vector{typeof(1.0u"m")} = typeof(1.0u"m")[]
multipliers::Vector{Float64} = Float64[]
end
is_benthic(::InterpolatedProduction) = false
is_pelagic(::InterpolatedProduction) = false
is_interpolated(::InterpolatedProduction) = true
function production_profile(::AbstractInput, p::InterpolatedProduction)
@assert length(p.depth_knots) == length(p.multipliers)
@assert length(p.depth_knots) >= 2
depths_m = [d |> in_units_of(u"m") for d in p.depth_knots]
order = sortperm(depths_m)
itp = linear_interpolation(depths_m[order], p.multipliers[order], extrapolation_bc=Flat())
max_rate = p.maximum_production
return (_, w) -> max_rate * itp(w |> in_units_of(u"m"))
end
end