Add Model 2a: same-parameter cross-biomarker covariance as a JAGS extension of model.jags (strictly nests Chapter 1) + Chapter-1 comparison#245
Conversation
…AGS extension of model.jags Add Model 2a, an additive extension of model.jags that introduces same-parameter cross-biomarker covariance via a shared per-parameter latent factor, leaving every Chapter 1 within-biomarker block unchanged. Chapter 1 is recovered exactly when the loadings are zero (strict nesting). - model: inst/extdata/model_2a.jags - fit: run_mod_2a() with jags_data_2a, make_inits_2a, prep_priors_2a, add_factor_priors; reuses prep_data() unchanged - cross-biomarker summaries: summarize_cross_2a, cross_cov_from_loadings, marginal_var_2a, cross_cor_from_draw_2a (+ internal jags_node_utils) - comparison vs Chapter 1: compare_mod_2a, fit_chapter1_lean, summarize_curve_params_2a - simulation/validation: sim_params_2a, sim_case_data_2a, build_sigma_2a, validate_recovery_2a, validate_nesting_2a - tests: 7 pure-function unit tests + 1 JAGS-gated smoke test - example: run_mod_2a-examples.R (one fit on nepal_sees) No new dependencies; no Chapter 1 code modified.
This comment has been minimized.
This comment has been minimized.
Merge remote-tracking branch 'origin/main' into chapter2-extend # Conflicts: # DESCRIPTION # inst/WORDLIST
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
📖 https://ucd-serg.github.io/serodynamics/preview/pr245 |
Tooling/style only; model and functions unchanged. stop()->cli_abort, line/indent/semicolon fixes, object_name_linter exemption for *_2a files, sim_params tolerance 0.05, suppressWarnings on JAGS smoke tests,
This comment has been minimized.
This comment has been minimized.
|
Claude finished @Kwan-Jenny's task in 2m 11s —— View job Claude finished reviewing PR #245 — Tasks
Code Review: Model 2a PR #245 — after commits
|
|
@claude Please fix the remaining open review comments 1–3 on branch
The corrected join should follow this structure:
Use this single-line version:
Please only make these targeted changes for comments 1–3. |
|
Claude finished @Kwan-Jenny's task in 1m 8s —— View job Tasks
SummaryAll three targeted fixes applied and pushed as commit
Note on fix 1I kept |
- compare_mod_2a(): use join_by() and set relationship = "one-to-one" on the shared-parameter left_join (CLAUDE.md requirement). - jags_data_2a(): flatten the multi-biomarker warning to a single line so cli does not render an embedded newline plus indentation. - sim_case_data_2a(): drop the hardcoded n * 2 pre-allocation and for (k in 1:2) loop so the simulator honours length(biomarkers). Co-authored-by: Kwan-Jenny <Kwan-Jenny@users.noreply.github.com>
Summary
Adds Model 2a, an additive extension of
model.jagsthat introduces same-parameter cross-biomarker covariance into the subject-level antibody kinetic parameters while leaving every Chapter 1 within-biomarker block unchanged. Chapter 1 is recovered exactly when the new covariances are zero, so Model 2a strictly nests the current model. It also addscompare_mod_2a(), a head-to-head of Chapter 1 vs Model 2a on the same data.Nothing in the existing Chapter 1 pipeline is modified —
model.jags,prep_data(),prep_priors(),run_mod()are untouched; all code is new.What Model 2a is
Chapter 1 covariance is biomarker-separated (cross-biomarker = 0):
Model 2a keeps
Sigma_G,Sigma_Aand adds a diagonal cross-biomarkerblock
C = diag(c_1..c_P)(same-parameter only):c_pis the IgG~IgA covariance for the same kinetic parameterp; cross-parameter cross-biomarker terms stay 0;C = 0reproduces Chapter 1 (35 covariance parameters vs 30).Implementation (factor parameterization)
A Wishart precision cannot pin a sparse covariance's zero-pattern, so the exact pattern is generated with a shared latent factor per kinetic parameter:
For two biomarkers this gives
c_p = lambda[1,p] * lambda[2,p](derived from the loadings — this is a model quantity, independent of the sampler; it is the samec_pwhether implemented in JAGS or Stan), cross-parameter cross-biomarkercovariance 0, and — with all
lambda = 0— exactlymodel.jags. The first biomarker's loadings are constrained> 0for identifiability; the sign ofc_pstays free vialambda[2,p]. The model is general inn_antigen_isos: with 2 biomarkers it is exactly Model 2a; with more, the single per-parameter factor couples all of them (rank-1, same-parameter).inst/extdata/model_2a.jagsis identical tomodel.jagsexcept thisparconstruction and the loading priors.What's added
inst/extdata/model_2a.jags— the extended model.add_factor_priors(),prep_priors_2a()(reuse Chapter 1 priors).jags_data_2a(),make_inits_2a(),run_mod_2a()— a lean wrapper that reusesprep_data()unchanged and returns the MCMC plus a tidy cross-biomarker covariance/correlation summary (nosr_modelpost-processing).cross_cov_from_loadings(),marginal_var_2a(),cross_cor_from_draw_2a(),summarize_cross_2a(), shared-internaljags_node_utils_2a.R.build_sigma_2a(),sim_params_2a(),sim_case_data_2a(),validate_recovery_2a(),validate_nesting_2a().fit_chapter1_lean()(same posterior asrun_mod()),summarize_curve_params_2a(),compare_mod_2a().No new dependencies (all in Imports already); no new data (uses
nepal_sees).Chapter 1 vs Model 2a — what changes
compare_mod_2a()fits both models on the same data and reports:mu.parand the within-biomarker variances. Because Model 2a strictly nests Chapter 1, these should agree within MCMC error; a large difference would signal a problem, notan improvement.
c_p/ correlationrho_pper kinetic parameter, which Chapter 1 cannot represent (it is structurally 0 there).compare_mod_2a(dic = TRUE)offers a best-effort DIC as a first signal.Comparison results on
nepal_sees(full-length MCMC, run locally):(to be filled in from the local comparison run: convergence (max R-hat), the shared-parameter table with max |diff|, the cross-biomarker
c_p/rho_ptable and which CIs exclude 0, and themu.parCI-width summary)Verification
run_mod_2a()/compare_mod_2a()execute and return the expected structure (matching the existingtest-run_mod.Rstyle; CI installs JAGS).nepal_sees, are run locally at full MCMC length (validate_recovery_2a(),validate_nesting_2a(),compare_mod_2a()); results pasted above.How to try it
Scope
This PR is the "add the model + show it nests Chapter 1 + compare to Chapter 1" increment. Quantifying improvement (WAIC/LOO, joint posterior-predictive comparison, seroincidence coverage/width) is a follow-up, since WAIC needs a
model-file change and the seroincidence step needs the serocalculator integration.