diff --git a/code/SoS/mnm_analysis/mnm_methods/rss_analysis.ipynb b/code/SoS/mnm_analysis/mnm_methods/rss_analysis.ipynb index 70b578ca0..5ed9fd0b6 100644 --- a/code/SoS/mnm_analysis/mnm_methods/rss_analysis.ipynb +++ b/code/SoS/mnm_analysis/mnm_methods/rss_analysis.ipynb @@ -99,7 +99,7 @@ "\n", "- `--methods` (default `susie`), `--coverage` (`0.95`), `--secondary-coverage` (`0.7,0.5`).\n", "- `--min-abs-corr` (`0.8`), `--median-abs-corr` (off; sets OR-logic purity), `--pip-cutoff` (`0.025`).\n", - "- `--L` (`20`) and `--L-greedy` (`5`): SuSiE fit defaults.\n", + "- `--L` (`10`) and `--L-greedy` (`none`; a positive int enables the greedy-L loop): SuSiE fit defaults.\n", "- `--method-args`: JSON overriding any of the above per method, e.g. `{\"susie\":{\"L\":10}}`.\n", "- `--ser-fallback` / `--no-ser-fallback` (default on), `--r-finite`, `--r-mismatch` (`eb_mix`), `--rss-control`: numerical safeguards for the RSS likelihood.\n", "- `--[no-]keep-original-fit` (default off): retain the pre-fallback multi-effect fit on SER-fallback regions (where it differs from the reported SER fit); off keeps none.\n", @@ -306,8 +306,8 @@ " --min-abs-corr 0.8 (as float)\n", " --median-abs-corr ''\n", " --pip-cutoff 0.025 (as float)\n", - " --L 20 (as int)\n", - " --L-greedy 5 (as int)\n", + " --L 10 (as int)\n", + " --L-greedy none (as str; positive int enables greedy-L)\n", " --method-args ''\n", " --[no-]ser-fallback (default to True)\n", " GWAS SuSiE-RSS fine-mapping: SER fallback is ON by\n", @@ -392,8 +392,8 @@ "parameter: min_abs_corr = 0.8\n", "parameter: median_abs_corr = '' # empty -> off (OR-logic purity; needs pecotmr step-1)\n", "parameter: pip_cutoff = 0.025\n", - "parameter: L = 20\n", - "parameter: L_greedy = 5\n", + "parameter: L = 10\n", + "parameter: L_greedy = 'none' # 'none'/'off' = greedy off (default); a positive int enables greedy-L\n", "parameter: method_args = '' # nested per-method JSON object\n", "# GWAS SuSiE-RSS fine-mapping: SER fallback is ON by default (reproduces the single-panel notebook):\n", "# fit finite-sample R + EB LD-mismatch SuSiE-RSS and fall back to the single-effect (SER) result for\n", diff --git a/code/script/pecotmr_integration/fine_mapping.R b/code/script/pecotmr_integration/fine_mapping.R index d4a8f5a0b..2b29029a7 100644 --- a/code/script/pecotmr_integration/fine_mapping.R +++ b/code/script/pecotmr_integration/fine_mapping.R @@ -95,11 +95,13 @@ parser <- add_argument(parser, "--pip-cutoff", help = "PIP signal cutoff (fineMappingPipeline signalCutoff)", type = "numeric", default = 0.025) parser <- add_argument(parser, "--L", - help = "SuSiE number of single effects (susie L); pipeline default 20", - type = "integer", default = 20L) + help = "SuSiE number of single effects (susie L); pipeline default 10", + type = "integer", default = 10L) parser <- add_argument(parser, "--L-greedy", - help = "SuSiE greedy init count (susie L_greedy); pipeline default 5", - type = "integer", default = 5L) + help = paste("SuSiE greedy init count (susie L_greedy): a positive integer to run", + "the greedy-L loop, or 'none'/'off' to disable it; pipeline default", + "none (greedy off)"), + type = "character", default = "none") parser <- add_argument(parser, "--method-args", help = "JSON object {token: {kwarg: value, ...}, ...} for fineMappingPipeline()", type = "character", default = "") @@ -245,6 +247,22 @@ secondary_cov <- as.numeric(trimws(strsplit(argv$secondary_coverage, ",", fixed median_abs_corr <- if (length(argv$median_abs_corr) != 1L || is.na(argv$median_abs_corr)) NULL else argv$median_abs_corr +# L_greedy: 'none'/'off'/'null'/empty (case-insensitive) -> NULL, i.e. greedy-L +# off (susie's own L_greedy default is NULL). Otherwise a positive integer. +# The NULL is kept via the inline list() in cs_args below, which preserves a +# named NULL through c()/do.call to fineMappingPipeline; only an x$Lgreedy <- NULL +# assignment would drop it (re-enabling pecotmr's default 5). +l_greedy_raw <- trimws(argv[["L_greedy"]]) +l_greedy_val <- if (tolower(l_greedy_raw) %in% c("none", "off", "null", "")) { + NULL +} else { + v <- suppressWarnings(as.integer(l_greedy_raw)) + if (is.na(v) || v < 1L) + stop("--L-greedy must be a positive integer or 'none'/'off' (got: '", + argv[["L_greedy"]], "')") + v +} + # Seed up front for reproducible fits (mirrors the legacy susie_twas set.seed). # NULL when --seed is unset. In QTL mode the value is ALSO forwarded to the # pipeline as seed= (below): set.seed() only touches this process's RNG, so it @@ -302,7 +320,7 @@ methods_arg <- if (is.null(parsed_method_args)) methods else # seeds the susie-family tokens and applies explicit --method-args overrides. cs_args <- list(methods = methods_arg, L = argv$L, - Lgreedy = argv[["L_greedy"]], + Lgreedy = l_greedy_val, coverage = argv$coverage, secondaryCoverage = secondary_cov, signalCutoff = argv$pip_cutoff,