Skip to content

Second-order plotting: draw bin averages at geometric bin centres (#382)#396

Open
gustavdelius wants to merge 1 commit into
masterfrom
second-order-plot-382
Open

Second-order plotting: draw bin averages at geometric bin centres (#382)#396
gustavdelius wants to merge 1 commit into
masterfrom
second-order-plot-382

Conversation

@gustavdelius

Copy link
Copy Markdown
Member

Part of #377 — the rendering counterpart of the bin-averaging programme. Once a
quantity is a bin average, plotting it at the bin boundary is wrong.

The problem

All size-resolved plots route their x-locations through get_ArraySpeciesBySize_w(),
which returns the grid nodes params@w / params@w_full — the left bin
edges
. A bin average N_j = (1/Δw_j)∫_{w_j}^{w_{j+1}} N dw does not live at
the boundary, so it is mis-placed by half a bin.

Where averaged values belong

The geometric bin centre w*_j = sqrt(w_j w_{j+1}) = w_j·sqrt(β) — log-symmetric,
second-order-correct, and exact for the community spectrum N ∝ w^{-2}. A
uniform half-bin shift to the right on the log axis.

Design

A representation tag ("point" / "average", default "point") on the
ArraySpeciesBySize and ArrayTimeBySpeciesBySize constructors:

  • Producers tag honestly. The bin-averaged sinks getPredMort(),
    getFMort(), getMort(), getExtMort() and the reproductive investment
    getERepro() tag themselves "average"; point-valued quantities (encounter,
    growth) keep the "point" default.
  • One placement point, gated on the flag. get_ArraySpeciesBySize_w() and
    the new get_ArrayTimeBySpeciesBySize_w() return the geometric bin centres
    (new internal bin_midpoints() helper) for "average" arrays only when
    second_order_w[["bin_average"]] is set. So first-order/default models, their
    as.data.frame() output and all vdiffr snapshots are unchanged; a
    second-order model is internally consistent across dynamics, diagnostics and
    plot placement.
  • The tag is preserved through the [ subset, the time-slice, and the
    MizerSim rate path (sim_size_rate / get_species_size_rate_from_sim thread a
    representation argument to the constructors). Everything downstream
    (prepare_*_plot_data, as.data.frame, plot2) follows the central helpers
    automatically.

Scope

plotSpectra/plotCDF build their own data frames and apply the w^power
weight; their centre placement (and the CDF's opposite, edge placement) is the
separate #383, which reuses bin_midpoints().

Tests

test-ArraySpeciesBySize.R / test-ArrayTimeBySpeciesBySize.R: producers tag
honestly; bin_midpoints are the geometric centres; the size axis shifts to the
centres only under second_order_w (point quantities stay on nodes);
as.data.frame x-values follow the tag; subsetting/slicing preserve it. The
rate-function and backwards-compat snapshots gained only the new benign
representation attribute (accepted). Full suite: 2824 pass.

Docs

NEWS entry; a "Plotting follows the same distinction" note in the
"Point values and bin averages" section of the numerical-details vignette.

🤖 Generated with Claude Code

Once a quantity is a finite-volume cell average N_j it no longer lives at the
left bin edge w_j but at the geometric bin centre w*_j = sqrt(w_j w_{j+1}) =
w_j sqrt(beta) (the log-midpoint, exact for the community spectrum w^-2).
Plotting it at the bin boundary mis-places it by half a bin.

This adds a `representation` tag ("point"/"average") to the
ArraySpeciesBySize and ArrayTimeBySpeciesBySize classes, threaded through the
constructors, subset/slice methods and the MizerSim rate path
(sim_size_rate / get_species_size_rate_from_sim). The central size-axis helpers
get_ArraySpeciesBySize_w() and the new get_ArrayTimeBySpeciesBySize_w() return
the geometric bin centres (new bin_midpoints() helper) for "average" arrays,
but only when the model uses second-order bin-averaging
(second_order_w[["bin_average"]]) -- so default plots, as.data.frame() output
and vdiffr snapshots are unchanged.

The bin-averaged sinks getPredMort/getFMort/getMort/getExtMort and the
reproductive investment getERepro tag themselves "average"; point-valued
quantities (encounter, growth) stay "point" and on the nodes. Everything
downstream (prepare_*_plot_data, as.data.frame, plot2) follows the central
helpers automatically.

plotSpectra/plotCDF build their own data frames and handle the w^power weight;
their centre placement is the separate #383. Snapshots gained only the new
benign `representation` attribute (accepted). Full suite: 2824 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant