8 double t,
double onset,
double duration,
double rise,
double fall,
double period)
noexcept
10 double local = t - onset;
14 double pulse = std::max(duration, 0.0);
16 local -= period * std::floor(local / period);
17 pulse = std::min(pulse, period);
20 const auto peak_at = [rise](
double s) {
21 return rise > 0.0 ? 1.0 - std::exp(-s / rise) : 1.0;
25 return peak_at(local);
29 return peak_at(pulse) * std::exp(-(local - pulse) / fall);
33 std::span<double>
out,
35 std::span<const double> onset,
36 std::span<const double> duration,
37 std::span<const double> rise,
38 std::span<const double> fall,
39 std::span<const double> period)
noexcept
41 const size_t count = std::min({
out.size(), onset.size(), duration.size(), rise.size(), fall.size(), period.size() });
42 for (
size_t i = 0; i <
count; ++i)
47 std::span<double> levels,
48 std::span<const double> growth,
49 std::span<const double> interaction,
52 const size_t n = std::min(levels.size(), growth.size());
53 if (n == 0 || interaction.size() < n * n)
56 thread_local std::vector<double> next;
59 for (
size_t i = 0; i < n; ++i) {
60 const double pressure =
weighted_sum(levels.first(n), interaction.subspan(i * n, n));
61 next[i] = std::max(levels[i] + dt * levels[i] * (growth[i] - pressure), 0.0);
64 for (
size_t i = 0; i < n; ++i)
Time evolution of arrays of independent levels.
Pure functions of a newest-first window and an array of numbers.
std::vector< float > * out
double pulse_response(double t, double onset, double duration, double rise, double fall, double period) noexcept
Level at a time of a leaky response to a rectangular pulse.
double weighted_sum(std::span< const double > window, std::span< const double > coefs) noexcept
Sum of window[k] * coefs[k] over the shorter of the two.
void lotka_volterra_step(std::span< double > levels, std::span< const double > growth, std::span< const double > interaction, double dt)
One explicit step of generalised Lotka-Volterra competition.