
Version 3.0
sbt 3.0.0
sbt_fit_save()andsbt_fit_read()can now externalise large portable fits to checksum-verified GitHub Release assets when a project opts in through a.sbt-artifacts.dcfconfiguration. Ordinary local RDS behaviour is unchanged elsewhere.Renamed
sbt_simulate_example()tosbt_example_simulate()so the public simulated-example functions share thesbt_example_*()prefix.Removed
get_mcmc_profile(). Posterior likelihood profiling will be maintained outsidesbt.Added a fully simulated, full-scale assessment example for public articles and tests.
sbt_example_data()returns the processed model inputs, andsbt_example_fit()returns the corresponding 1,559-parameter MLE. The new example files contain only simulated observations and fitted output.get_loo()now takes a single sampledsbt_fitand obtains its model data, transient objective, and posterior draws internally.Added
sbt_add_msy()and a validatedmsyslot to portablesbt_fitobjects. Named MLE or posterior calculations are bound to the fitted-model and posterior identities, survive save/read round trips, and are cleared when their upstream fit or posterior changes. The lower-levelrun_msy()interface remains available for derived posteriors assembled from multiple fits.The current model now reports legacy comparable biomass (
B10_plus_y) as season-1 numbers aged 10 and older weighted by the LL1 weight-at-age schedule, together with its draw-wise ratio to the initial model year.Standardised plural observation-family plot names:
plot_tags_residuals(),plot_tags_fits_pooled(),plot_tags_recaptures_pooled(),plot_pops_residuals(), andplot_hsps_residuals(). The former singular aliases have been removed.Added pooled conventional-tag diagnostics for assessment reporting.
plot_tags_fits_pooled()compares observed and expected recaptures by release year, release age, and recapture age after pooling tagger groups, with 95% posterior credible intervals calculated after pooling within each retained draw;plot_tags_recaptures_pooled()summarises total observed recaptures at age for each calendar release year.Future gene-tagging release and harvest sample sizes in
run_projections()can now be supplied as release-year-specific vectors as well as scalars. This supports programme comparisons that preserve known cohorts already in the release/recapture pipeline before future effort scenarios diverge.Long-horizon closed-loop CTP projections now stage catch only through the TAC blocks already calculated. Catch in not-yet-calculated CTP years is held at zero while generating the observations available to the current update, then every final year is populated by its calculated CTP TAC. This avoids an infeasible artificial continuation of the last fixed TAC across the entire horizon.
run_projections()now has an explicit, opt-in catch-realisation rule for operating-model paths where nominal CTP advice cannot physically be taken. The default"error"behavior remains fail-closed. With"cap", all seasonal and fishery allocations in an affected draw-year are reduced by one common factor until the configured raw-harvest ceiling is met. Nominal TAC advice, realized nominal catch, and biological removals are retained separately and revalidated when projection caches are read.Aligned the projection CTP with the adopted specification and made its end-to-end calculation independently auditable. The gene-tagging upper threshold is now 2.6 million fish, projection CKMR fits use the assessment-data HSP detection/retention multiplier, and terminal-age HSP survival applies exactly one term per cohort-gap year. CKMR input cutoffs now apply symmetrically to historical and projected rows, and projection caches retain checksum-bound snapshots of the complete raw simulated GT, CPUE, HSP, and POP observation arrays available at every update. This lets an external implementation apply the calendar lags independently and compare the CKMR, multiplier, unconstrained-TAC, final-TAC, and allocation calculations. The CTP CKMR optimizer now requires a maximum absolute gradient no larger than
5e-4, rather than accepting materially less-refined fits below0.01; a tightly controllednlminb()polish with recorded deterministic numerical nudges is used when BFGS stalls above that gate, followed by a final code-zero BFGS verification pass. A safeguarded exact-Hessian Newton proposal and final BFGS certification are available only if that route remains marginally above the gate; the proposal normalizes RTMB’s vector, row-matrix, and column-matrix gradient representations before solving the Newton system.Completed a pre-sign-off maintenance pass across the package, tests, articles, and website configuration. Several row-index loops now handle empty inputs safely, obsolete interactive scripts are archived outside the installed package, orphaned data-weighting optimizer caches are no longer bundled, public references and installation examples are current, and CI actions are updated. These maintenance changes do not alter the scientific model contract.
Restored autocorrelated CPUE observations in management projections. Each posterior draw now carries its final fitted historical log-CPUE residual forward with the empirical historical lag-one correlation and the legacy stationary AR(1) innovation scaling. Projected observations remain lognormal, and projection cache/signature versions were advanced so caches produced by the former independent-error implementation cannot be reused.
Projection caches now distinguish scientific validity from execution provenance. Exact package/dependency versions and implementation hashes are retained for audit but no longer invalidate a cache when the explicit projection scientific contract and all numerical inputs are unchanged.
legacy_cache_signaturesprovides an opt-in, fully revalidated one-time migration for audited caches from the immediately preceding contract.get_loo()now documents and tests its existing policy of retaining zero-effective-N composition rows in model I/O while excluding them from the pointwise LOO calculation. Fractional multinomial composition likelihoods now use one gamma-function implementation in both AD fitting and numeric reporting, so pointwise LOO values match the fitted objective.plot_loo()can include or exclude named components, uses data-type shapes in its legend, and omits non-finite Pareto shape diagnostics rather than assigning them an artificial finite plotting coordinate.Added
plot_prior_posterior()to compare every estimated parameter with an explicit scalar prior against its retained marginal posterior, on either model or natural scale. Explicitly selected posterior-only parameters can also be included.Added the Francis LN1 logistic-normal likelihood for age compositions as
af_switch = 4. It compresses only the leading and trailing tails, replaces exact internal zeros with a configurable epsilon, applies the Francis relative-sample-size weighting, and conditionally profiles one dispersion parameter per age-composition fishery. The Gaussian log-ratio kernel is evaluated with RTMB’s AD-safe multivariate-normal density. Length compositions are unchanged.Standardized the portable-fit lifecycle API around the
sbt_fit_*prefix:sbt_fit_validate(),sbt_fit_save(),sbt_fit_read(),sbt_fit_upgrade(), andsbt_fit_rebuild()replace the former verb-first names.Active package, development-script, and vignette code now uses R’s native
|>pipe. The minimum supported R version is therefore 4.1. Frozen version-1 scientific behaviour and archived historical source remain unchanged.sbt_fit(data_in = ...)now runs the appropriate model-data preprocessor before creating the staged fit, so a current-model workflow can begin directly from the reviewable input list. Supplying already processeddataremains fully supported.sbt_fitschema 6 adds a staged fitted-model lifecycle. Start withsbt_fit(data), optionally configure it with thesbt_add_*()setters, and callsbt_optimise()andsbt_mcmc(); missing parameters, priors, map, and bounds are resolved automatically. Repeated optimization starts from RTMB’s authoritativelast.par.best, while repeated MCMC retains every attempt and selects the diagnostically best compatible posterior.sbt_add_priors(fit)andsbt_add_map(fit)now resolve their package defaults directly, so callers only need to supply those arguments when overriding the defaults. Specialized external optimizers can attach their selected result withsbt_add_optimisation()without reverting to the completed-fit constructor.Removed the dead
catch_UR_oncompatibility input.get_data()andget_data_v1()now reject it with an explanatory error. The old ADMB I42 robustness-trial multiplier was inactive in the previous base assessment and is separate from the activecatch_UAUAM/NCNM additions and historical LL1/surface catch-scenario inputs.Removed the non-operational
get_posterior2()and legacyget_posterior3()extractors, the unsafesave_grid()/load_grid()serializers, the redundantplot_aerial_survey()wrapper, the unusedget_POP_like_v2(), and the test-only.save_grid_mcmc_cell()helper. Useget_posterior(), portablesbt_fitgrid cells, andplot_aerial(). The frozen V1 model now calls its ownget_recruitment_v1()helper so future changes to current recruitment cannot alter the V1 benchmark.Replaced the thin development article with
CONTRIBUTING.mdand removed the obsolete duplicate model specification.equations_rtmb.qmdis the sole active scientific specification.MLE and MCMC checks can be deferred with
check = FALSEand run later withcheck_mle()orcheck_mcmc(). Failed checks preserve expensive results for inspection. MCMC no longer requires an MLE, configuration changes invalidate downstream state, and re-optimizing a sampled fit preserves but clearly marks its earlier posterior.sbt_obj()is now the sole public runtime-object accessor.Supported schema-3, schema-4, and schema-5 fits upgrade to schema 6 in memory. Migration is representation-only and never runs optimization or sampling; optimizer and posterior payloads are preserved.
sbt_fitschema 5 stores payload-bound MLE and MCMC validation records.check_mle()andcheck_mcmc()now reuse matching records by default, support an explicit full audit, and can explicitly skip checking. Records are invalidated by changed fits, posterior samples, sampler diagnostics, scientific contracts, thresholds, or stored diagnostic results.Portable fits now declare an explicit scientific model contract separately from their exact implementation checksum. Strict reads still validate the payload, schema, parameter layout, and rebuilt objective, but source-only changes within an unchanged scientific contract no longer force a refit. Recognized pre-contract schema-2 fits are upgraded in memory.
Standardized comma spacing and explicit integer literals throughout the active R implementation. Continuous initial values retain explicit double storage, and the frozen version-1 model behaviour remains unchanged.
Updated the fixed additional aerial-survey standard-deviation default to 0.59 following ESC31 residual calibration. Conventional-tag randomized quantile residuals now use a reproducible seed by default while preserving the caller’s random-number state.
find_msy()now retries a failed finalnlminb()step with bounded L-BFGS-B, avoiding isolated PORT false-convergence codes at otherwise stable posterior solutions.find_msy()also restarts the catch-split optimization when its first phase identifies the near-zero-yield basin, even if the final penalized objective is marginally negative.Added a model-data
M_switch: direct mortality anchors (1) or length-based mortality (2). The length-based form estimates M10 and M30, fixes its length exponent at -1 by default, and applies the M10-scaled curve from age 0.Reworked
sbt_fitschema 3 as a lean portable checkpoint. The constructor now derives the fitted parameter state, map, and random effects from a required transient RTMB objective; it no longer stores the objective, report, optimizer start, duplicate fitted parameters, or duplicate parameter layouts. Strict reads validate compatibility and rebuild a fresh objective into a session-only cache used by plotting and reporting functions.sbt_obj()exposes that cached runtime object only when an external API requires it, withfresh = TRUEfor isolated mutable work.make_parameter_table()now accepts ansbt_fitdirectly. Schema-1 and schema-2 files are migrated in memory and can be resaved in the compact format.Added a configurable, smooth preventive harvest wall on raw combined seasonal harvest at age. Its four fixed model-data settings are validated together and are now fully defaulted by
get_data()before model execution. The wall is normalized to the requested objective contribution for one cell at the retained biological ceiling. It is reported separately from the feasibility-onlyposfuncontinuation and does not alter conditioned catches or population dynamics. Omitting all four settings keeps the wall disabled for backward-compatible package data.Restored the conditional legacy
posfun()continuation and applied a fixed, age-specific feasibility penalty to combined ordinary and direct LL4 removals. Conditioned catches remain exact, raw harvest is retained for validation, and only a positive numerical continuation is propagated when a trial parameter vector is infeasible. New biological-state diagnostics require every accepted MLE and posterior draw to have raw seasonal harvest no greater than 0.9, strictly positive populated abundance, zero material harvest penalty, and exact catch accounting.Simplified
get_initial_numbers()with the equivalent cumulative-survival calculation and a numerically stable terminal plus-group denominator. This improves direct numeric-call overhead but does not materially change full model objective or gradient timing.
Enhancements
-
run_projections()can now keep nominal future TAC allocations separate from fishery-specific biological removals. The optionalprojection_removal_multiplier_fapplies only after the terminal assessment year, CTP updates remain on the nominal-TAC scale, and projection caches validate both representations and their totals. -
project_selectivity()now supports retaining fitted posterior selectivity through a specified terminal year before applying the selected projection rule to later years. - Added
check_mle()andcheck_mcmc()for portablesbt_fitobjects. They recalculate numerical and biological-state diagnostics, including natural mortality at every age, and store the checked results back in the fit. -
run_msy()now evaluates the legacy annual equilibrium MSY calculation for every retained posterior iteration, chain, and fitted catch year in ansbt_fit. It preserves draw/year identity, supports draw and year subsets plus forked parallel execution, and returns compact scalar diagnostics with separate fishery- and age-specific arrays. Each row also retains the fitted spawning output, age-2–15 fishing mortality, unfished spawning output, and the correspondingBmsy/B0,B/Bmsy, andF/Fmsystatus ratios from the already evaluated posterior state. - Fitted-output and residual
plot_*()functions now take ansbt_fitobject as their primary input. Posterior-capable plots use the fit’s stored MCMC by default; setposterior = FALSEto request point estimates only. Legacy(data, object)calls remain supported. - Derived-data plots for growth, weight, sliced age frequencies, and PALY now also accept
sbt_fitas their primary input while retaining a named legacydataalias. -
run_projections(cache_only = TRUE)now loads only a signature-compatible cache and otherwise stops before simulation, allowing report renders to be fail-closed by default. -
run_grid_mcmc()now writes portablegrid<N>.sbt.rdscell fits, supports explicit cell subsets and validated resume, and updates aggregate diagnostics after every skipped or completed cell. Resume identities include bounds and sampler-global implementations. Canonical grid posterior conversion rejects mixed model, input, or run signatures; legacy.rdacells remain readable with an explicit unverifiable-provenance warning. - Model data can set
cpue_sel_fisheryto choose the selectivity used by the CPUE abundance index. It defaults to the existing dedicated CPUE selectivity (row 7); CPUE length compositions continue to use row 7.
Bug fixes
find_msy()now honors the legacyphase_Factive-fishery mask and restores the TPL’s two-stage catch-allocation optimization. The stiff final phase is solved on log harvest rates, avoiding false convergence in the recruitment-floor basin and a pathological 60,000-iteration raw-scale case.The experimental
msy_model()stub, whose objective and reports were commented out and which always returned zero, is no longer exported. Usefind_msy()for one prepared state orrun_msy()for fitted posteriors.CPUE length-frequency fit and residual plots now use their dedicated
cpue_lf_yearsvector rather than the CPUE abundance-index years.Balanced-grid
tmbfitobjects no longer retain first-cell unbounded draws or classifylp__as a model parameter, and support requested draw counts below the number of cells.Projection cache signatures now cover the transitive package-function graph; corrupt or incomplete caches are misses and successful writes are atomic.
Grid diagnostics now fail closed when any R-hat, ESS, divergence, or treedepth diagnostic is undefined. Named lower and upper grid bounds are validated and aligned independently.
Projection cache identity now explicitly includes the assessment model and CTP implementation. Grid, projection, and fixture replacements use atomic same-directory renames with a portable backup-and-restore fallback.
Refit the bundled example optimum against the current likelihood and data contract. The fixture no longer serializes a transient RTMB objective; consumers rebuild it from the saved data, parameters, and map.
Mark cached posterior, profile, and projection examples that predate the current likelihood as legacy outputs that require regeneration for inference.