…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.
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.