Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/staar/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,11 @@ pub struct IndividualRow {
pub fn write_individual_results(
rows: &[IndividualRow],
output_dir: &Path,
is_conditional: bool,
out: &dyn Output,
) -> Result<(), CohortError> {
let out_path = output_dir.join("individual.parquet");
let stem = if is_conditional { "individual_cond" } else { "individual" };
let out_path = output_dir.join(format!("{stem}.parquet"));
let n = rows.len();

// R orders by POS ascending before returning (Individual_Analysis.R:450).
Expand Down Expand Up @@ -381,8 +383,10 @@ pub fn write_results(
trait_type: TraitType,
n: usize,
n_rare: i64,
is_conditional: bool,
out: &dyn Output,
) -> Result<(), CohortError> {
let cond_suffix = if is_conditional { "_cond" } else { "" };
out.status("Writing results...");
let mut significant_genes: Vec<serde_json::Value> = Vec::new();

Expand All @@ -397,7 +401,8 @@ pub fn write_results(
if results.is_empty() {
continue;
}
let out_path = output_dir.join(format!("{}.parquet", mask_type.file_stem()));
let out_path =
output_dir.join(format!("{}{cond_suffix}.parquet", mask_type.file_stem()));

let nan_pvals = results.iter().filter(|r| r.staar.staar_o.is_nan()).count();
if nan_pvals > 0 {
Expand Down Expand Up @@ -453,6 +458,7 @@ pub fn write_results(
"cohort_staar_version": 1,
"traits": trait_names, "trait_type": format!("{:?}", trait_type),
"n_samples": n, "n_rare_variants": n_rare, "maf_cutoff": maf_cutoff,
"conditional": is_conditional,
"significant_genes": significant_genes,
});
// Merge null-model summary fields (sigma2 for single-trait, or the
Expand Down
16 changes: 15 additions & 1 deletion src/staar/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,7 @@ impl<'a> StaarPipeline<'a> {
TraitType::Continuous,
n,
n_rare,
self.config.known_loci.is_some(),
self.out,
)
}
Expand Down Expand Up @@ -986,8 +987,15 @@ impl<'a> StaarPipeline<'a> {
))
})?;

let is_conditional = self.config.known_loci.is_some();

if self.config.individual && !scoring.individual.is_empty() {
write_individual_results(&scoring.individual, &results_dir, self.out)?;
write_individual_results(
&scoring.individual,
&results_dir,
is_conditional,
self.out,
)?;
}

write_results(
Expand All @@ -1001,6 +1009,7 @@ impl<'a> StaarPipeline<'a> {
trait_type,
n,
n_rare,
is_conditional,
self.out,
)
}
Expand All @@ -1019,6 +1028,11 @@ impl<'a> StaarPipeline<'a> {
"--spa with --kinship: SPA is applied at the score-test layer; the kinship-aware path provides exact variance via the GLMM projection.",
);
}
if self.config.known_loci.is_some() && mode == ScoringMode::Spa {
self.out.warn(
"--spa with --known-loci: the known-loci adjustment is absorbed into the fitted null, but the SPA saddlepoint reads raw G; gene-mask p-values from this run are SPA-adjusted but not conditional. A separate --cond-spa path is tracked in STAARpipeline as Gene_Centric_*_cond_spa.",
);
}
}

fn cohort(&self) -> CohortHandle<'_> {
Expand Down
Loading