Pipeline that hands a per-block set of
GwasSumStats of GWAS Z-scores together with the matching
per-block per-gene TWAS weights and LD references to
ctwas::ctwas_sumstats, producing per-gene posterior inclusion
probabilities for causal genes. Optionally accepts a precomputed TWAS-Z
GRanges from causalInferencePipeline as the
z_gene input so the per-gene Z is not recomputed inside ctwas.
Usage
ctwasPipeline(
gwasSumStats,
twasWeights,
twasZ = NULL,
fineMappingResult = NULL,
method = NULL,
maxNumSingleEffects = 5L,
numThreads = 1L,
ctwasPriorParam = CtwasPriorParam(),
variantPruningParam = VariantPruningParam(),
boundaryMergeParam = BoundaryMergeParam(),
keepSnps = FALSE,
methodArgs = CtwasOptions()
)Arguments
- gwasSumStats
A
GwasSumStatswhose elements are LD blocks (at least two), keyed by itsblockIdcolumn, withqcInfo()non-empty. Build it withloadGwasSumStatsFromManifest(..., ldBlocks = <blocks>)and pass it throughsummaryStatsQc.- twasWeights
The per-gene weight source. Either (a) a FLAT
TwasWeights/QtlFineMappingResult(or a homogeneous list of them) carryingregionprovenance – each gene is placed into its home LD block internally bystart(region)(matching cTWAS'sp0assignment rule); or (b) a pre-bucketed NAMED LIST keyed byregion_id(keys a SUBSET ofgwasSumStats's), used as-is. Blocks without any TWAS weights still contribute their SNP-level signal to ctwas's joint group prior estimate (the legacy whole-chromosome pattern where only a few of many LD blocks carry gene weights). A gene whose cis span straddles a block boundary is homed by its single anchor; the cross-block signal is cTWAS's boundary-gene concern (mergeCtwasBoundaryRegions), not placement.- twasZ
Optional
GRangesof TWAS Z-scores (output ofcausalInferencePipeline). When supplied, the per-(trait, context) Z is used as thez_geneinput toctwas_sumstatsso it is not recomputed.- fineMappingResult
Optional
QtlFineMappingResultorGwasFineMappingResultcarrying the per-variant PIP and credible-set membership data used by the CS / PIP rescue filters (csMinCorandminPipCutoff). WhenNULL(default) the smart filters are no-ops; only the magnitude filter (twasWeightCutoff) and the per-gene cap (maxNumVariants, ordered by|weight|) apply.- method
Optional character (length 1). Picks which TWAS method's weights to feed into ctwas for each (study, context, trait) gene. When
NULL(default): use"ensemble"if that method is present across the weight sources; otherwise use the sole method when only one is present; otherwise run every method as an independent cTWAS run (oneCtwasResultrow-set per method). Passing the name explicitly (e.g."mrash") restricts the run to that single method.- maxNumSingleEffects
Integer. Max number of single effects in cTWAS fine-mapping. Default
5. Pass-through toctwas::ctwas_sumstats.- numThreads
Number of cores. Default
1.- ctwasPriorParam
The EM stage that estimates cTWAS's group priors, built with
CtwasPriorParam:thin,niterPrefit,niter,varStructureandfallbackToPrefit. Handed whole toestCtwasGroupPriors.- variantPruningParam
Which variants survive into each gene's weight matrix, built with
VariantPruningParam:weightCutoff,csMinCor,pipRescueandmaxVariants. Handed whole toassembleCtwasInputs. ThecsMinCor/pipRescuerescues need afineMappingResult.- boundaryMergeParam
Whether a high-PIP gene straddling an LD-block boundary has its regions merged and re-fine-mapped, built with
BoundaryMergeParam:enabled(defaultFALSE),pipThreshold,filterCsandmaxSnp.- keepSnps
Logical (length 1). When
TRUE, retain the context-agnostic SNP background of each run as one extraCtwasResultrow (study = context = "SNP", mirroring cTWAS's own"SNP"group) so the full ctwas output is reconstructable fromctwasPosteriors/susieAlpha. DefaultFALSE– the SNP rows are the null background and are dropped from the structured gene-level result.- methodArgs
Additional arguments forwarded to ctwas, built with
CtwasOptions. Names are checked against what the ctwas steps accept between them.
Value
A CtwasResult collection: one row per (gwasStudy,
study, context, method). A single-context run is one row per method; a
multi-context (joint) run emits per-context rows sharing the same
jointContexts set and the jointly-estimated group priors. Each row's
CtwasResultEntry payload carries that context's per-gene
fine-mapping posteriors (finemap), the run's param, and its
regionInfo. For the raw ctwas::finemap_regions list (e.g. to
feed mergeCtwasBoundaryRegions), call the granular
assembleCtwasInputs \(\to\)
estCtwasGroupPriors \(\to\)
screenCtwasRegions \(\to\)
finemapCtwasRegions path instead.
LD block convention
gwasSumStats is ONE
GwasSumStats whose elements are LD blocks, keyed by its
blockId column – build it with
loadGwasSumStatsFromManifest(..., ldBlocks = <blocks>). Per-block
region_info, LD_map, and snp_map entries are built
automatically from the LD reference and concatenated before the call to
ctwas::ctwas_sumstats. A single-block input is rejected: cTWAS's EM
cannot converge on a single region, so callers must supply at least two
blocks.
cTWAS's log
cTWAS narrates each of its steps through the
logging package, which writes to the console with cat(),
out of reach of suppressMessages(). The pipeline keeps that
narration off the console, cTWAS's warnings excepted. To keep the full
log, give a step a log file through its options, e.g.
CtwasEstParamOptions(logfile = "est_param.log").
LD reference compatibility check
Per block:
ldReference(twasWeights) (when non-NULL) must be the same LD
reference as ldReference(gwasSumStats).
The two must be the same kind of reference. Two genotype panels must
share their samples and allele orientation; two LdMatrix objects
must agree on the LD they share; two GenotypeMixture objects must
average the same panels with the same weights. The two need NOT carry the
same variants; a partial overlap, which is what QC-ing the two sides
separately produces, only warns. A mismatch of any of those, or no shared
variant at all, is a hard error.
Examples
data(ctwasWeightsExample)
ldDir <- system.file("extdata", "ld_reference", "chr22",
package = "pecotmr")
ldStem <- file.path(ldDir, "protocol_example.LD.chr22")
gwasTsv <- system.file("extdata", "manifests",
"protocol_example.twas.gwas_sumstats.chr22.tsv.gz", package = "pecotmr")
mani <- data.frame(study = "gwas1", sumStatsPath = gwasTsv)
blocks <- GenomicRanges::GRanges("chr22",
IRanges::IRanges(c(10000000, 15000001), c(15000000, 19000000)),
blockId = c("chr22_1", "chr22_2"))
gss <- loadGwasSumStatsFromManifest(manifest = mani, genome = "hg38",
ldReference = ldStem, region = "chr22:10000000-19000000",
ldBlocks = blocks)
#> Warning: GwasSumStats[study=gwas1]: no effect-allele frequency declared (map `af: <col>` to export a directional af); top_loci$af will be NA. A directionless `maf`/`FRQ` is used for QC only, never as af.
gwasByRegion <- summaryStatsQc(gss,
panelFilterParam = PanelFilterParam(mafCutoff = 0.0025))
#> [gwas1] QC track: harmonization kept 20 of 20 variant(s) (corrected: sign-flipped 0, strand-flipped 0; dropped 0).
#> [gwas1] QC summary: 20 in -> 20 out | corrected: sign-flip 0, strand-flip 0
#> [gwas1] QC track: harmonization kept 155 of 155 variant(s) (corrected: sign-flipped 0, strand-flipped 0; dropped 0).
#> [gwas1] QC summary: 155 in -> 155 out | corrected: sign-flip 0, strand-flip 0
ctwasPipeline(gwasSumStats = gwasByRegion,
twasWeights = list(ctwasWeightsExample),
ctwasPriorParam = CtwasPriorParam(thin = 1, niterPrefit = 3, niter = 10,
fallbackToPrefit = TRUE),
methodArgs = CtwasOptions(
regionData = CtwasRegionDataOptions(min_group_size = 1),
estParam = CtwasEstParamOptions(
min_group_size = 1, min_p_single_effect = 0
)
))
#> CtwasResult: 1 run(s)
#> 1 GWAS stud(y/ies), 1 method(s): susie