FAQ¶
My species is not human — what do I need to change?¶
The prior on the population size. It is the one default that is genuinely tuned to humans, and it is easy to miss because it is never printed as a warning.
SweepLink samples log10N under a Gamma prior in shape–rate form, whose
hyperparameters default to:
Argument |
Default |
|
|---|---|---|
|
|
shape |
|
|
rate |
That puts the mean of log10N at 16/4 = 4, i.e. N = 10,000, with a standard
deviation of 1 — a full order of magnitude. 95% of the prior mass sits
between roughly N = 190 and N = 1,500,000.
If your species sits comfortably inside that range you can leave it alone. If it does not — an inbred crop line, an experimental population, a domesticated animal, or anything with N in the hundreds or in the tens of millions — the prior will pull the estimate towards 10,000 and you should re-centre it.
To centre the prior on N = 10^k with a standard deviation of σ on the log10
scale:
alpha = k² / σ²
lambda = k / σ²
Some worked values:
Target N |
σ (log10) |
|
|
95% of prior mass |
|---|---|---|---|---|
500 |
0.5 |
|
|
N = 64 – 5,800 |
1,000 |
0.5 |
|
|
N = 126 – 11,400 |
100,000 |
0.5 |
|
|
N = 11,700 – 1,060,000 |
1,000,000 |
0.75 |
|
|
N = 42,000 – 36,000,000 |
$ ./sweeplink infer ... --log10N.alpha 36 --log10N.lambda 12
Warning
--N does not change the prior. It only sets the value the chain starts
from. To move the prior you must set --log10N.alpha and --log10N.lambda.
Two things worth knowing before you pick numbers:
N is the diploid effective size. The drift term is
x(1-x)/2N, so there are2Nchromosomes. Do not halve or double your literature value to compensate.You can look before you choose. The
calculateLLForNtask evaluates the likelihood over a grid of population sizes without running an MCMC, which shows where your data alone put N:$ ./sweeplink calculateLLForN --counts counts.txt --meta meta.txt \ --mu_a_A 1e-8 --minN 100 --maxN 1e7 --numN 100 --logN --sumLL --out probe
The result is a single row in
probe_LL.txt; the largest value marks the best-supported N. Use it to sanity-check the prior, not to replace it.
Everything else in the model is species-agnostic. You will of course also want a
mutation rate appropriate to your organism (--mu_a_A), and generation times
that match how you filled the meta file.
I do not know which allele is ancestral¶
This is common — without an outgroup there is no way to polarise, so you have only REF and ALT.
Use whichever assignment you have, and change two defaults, both of which quietly assume that you do know the direction:
$ ./sweeplink infer ... \
--mu_a_A 1e-8 --mu_A_a 1e-8 \
--forwardPrior uniform --newMutPrior uniform
--mu_A_a 1e-8Make the mutation rates symmetric. The default
--mu_A_ais 0, which hard-codes “the derived allele can arise but never revert” — a statement about a direction you have not established. Setting both rates equal removes it.--newMutPrior uniformThe default is
neutral, a 1/x density describing a derived variant entering at low frequency. That is also a polarisation assumption, so make both priors uniform.
With those set, any REF/ALT assignment gives a valid run. What changes is the interpretation:
Important
The sign of s becomes arbitrary — it tells you which of your two arbitrary
labels is rising, not whether the derived allele is favoured. The magnitude
|s| is unaffected, and so is the evidence that the locus is under selection at
all. Both panels of sweeplink-plot remain meaningful; the bottom one already
plots |s|.
Does my data need to be phased?¶
No. SweepLink never resolves haplotypes. Its only input is a count c/n
per locus, time point and population, so unphased genotypes are fine — you just
need to count copies of an allele at each site.
How long does a run take, and how to make it faster?¶
Runtime scales with loci × time points × iterations. The tutorial’s 413 loci and 100,000 iterations take about 13 minutes on 4 threads.
--numThreads is the main lever — the likelihood parallelises across loci:
$ ./sweeplink infer ... --numThreads 8 # or 'all', or 'allButOne'
Warning
The default is one thread, not all cores. That is deliberate: the parallel
sums do not accumulate in a fixed order, so a multi-threaded run is not
reproducible bit-for-bit even with --fixedSeed. Use threads for speed, and
one thread when you need an exactly repeatable run.
For a whole genome, run one job per chromosome rather than one enormous job.
The companion scripts are built for that layout — put each run in its own
directory with a shared name and use --dirs:
$ sweeplink-plot --dirs chr1 chr2 chr3 --run-name sweeplink
How many iterations do I need?¶
The defaults (100,000 iterations, 10 burn-in rounds of 1,000, thinning 10) are a reasonable starting point. To judge whether they were enough:
Watch the acceptance rates printed after each burn-in round. SweepLink retunes proposals between rounds, so you do not need to touch anything — but rates near 0 or near 1 after tuning mean the chain is struggling.
Look at the trace, not just the summary.
<out>_trace.txtholds the retained samples; plotlog10Nwithsweeplink-plot-posteriorsand check the posterior is a sensible unimodal shape rather than drifting.Compare two seeds. Two runs with different
--fixedSeedthat disagree have not converged.
Raise --iterations first; raise --numBurnin if the chain is still moving
towards its final region when the main chain starts.
My run was killed. Do I have to start over?¶
Not from scratch. Every run writes <out>_state.txt, holding the current value
and jump size of every parameter, so you can carry on from there — and skip
burn-in, because the tuned jump sizes come back with it:
$ ./sweeplink infer ... --initVals dead_state.txt --numBurnin 0 --out rerun
Two things to know. If the state file is 0 bytes the run died during
burn-in and there is nothing to resume from. And the dead run’s
_statePosteriors.txt is empty regardless — those are only written at the end —
so the resumed run still needs the full number of iterations you want the
posterior built from. It saves the converging, not the sampling.
Full details in resuming an interrupted run.
What counts as missing data?¶
Write it as 0/0 — a locus with n = 0 at a time point simply contributes
nothing there.
sweeplink-vcf2input writes 0/0 for you. It also offers filters for the cases
where too much is missing to be useful — --max-missing-recent,
--max-missing-total, --min-segregating-timepoints. Ancient DNA time series
are usually thinnest at the oldest time points, which is worth checking in the
table the script prints before you rely on those samples.
Common errors¶
Argument 'mu_a_A' must be defined--mu_a_Ais mandatory; there is no sensible default mutation rate.String 'NA' is not a number!Missing data in the counts file must be
0/0, notNA.Size of grid (...) does not match the number of states for abs(s)--grid_abs_smust have exactly--numStatesAbsSentries.Neither or both 'betaMean' and 'betaESS' should be specified!Give both, or neither and let them be estimated from the data.
the state posteriors are not multiples of 1/<n>A companion script was told the wrong number of MCMC iterations. Normally it reads this from
<prefix>.parameters; pass--iterationsonly for runs made by older versions that did not record it.no locus of the second run is present in the first--round2-prefixpoints at a run that is not a refinement of--prefix.