2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
"Mean fitness: " "1.86225"
Frequencies:
0.5085 0.4915
initialize() {
// fast recurrent mutation, \theta = 4 * 1000 * 6e-6 = 0.024
initializeMutationRate(6e-6);
// m1 mutation type: strong positive selection (dominant), 2Nes = 1000
// Note: things work as expected if h is set to 0.0 or 0.5
initializeMutationType("m1", 1.0, "f", 0.5);
// don't convert to substitution
m1.convertToSubstitution=F;
// don't stack mutations
m1.mutationStackPolicy = "f";
// g1 genomic element type: uses m1 for all mutations
initializeGenomicElementType("g1", m1, 1.0);
// uniform chromosome of length 1 bp with "uniform recombination"
initializeGenomicElement(g1, 0, 0);
// set recombination to be ~ free
initializeRecombinationRate(0);
}
fitness(m1) {
// UGLY HACK: whenever we hit frequency=1, introduce a return to frequency=0
if (sim.mutationFrequencies(p1, mut) == 1.0) {
print("Fixation occurred. Murdering the population to return freq to 0.");
p1.genomes.removeMutations( sim.mutationsOfType(m1), T );
}
// standard fitness return
if (homozygous)
return 1.0 + mut.selectionCoeff;
else
return 1.0 + mut.mutationType.dominanceCoeff * mut.selectionCoeff;
}
// create a population of 500 individuals
1 {
sim.addSubpop("p1", 1000);
}
1:40000 {
if (sim.generation % 1000 == 0) {
// print mutation counts
allIndividuals = sim.subpopulations.individuals;
print(allIndividuals.countOfMutationsOfType(m1));
// print individual fitnesses
print(c("Mean fitness: ", mean(p1.cachedFitness(NULL))));
// print mutant freqs
cat("Frequencies:\n");
print(sim.mutationFrequencies(p1, sim.mutationsOfType(m1)));
}
}
40000 late() { sim.outputFixedMutations(); }
1: late()
{
// UGLY HACK: whenever we hit frequency=1, introduce a return to frequency=0
muts = sim.mutations;
freqs = sim.mutationFrequencies(p1, muts);
if (any(freqs == 1.0)) {
print("Fixation occurred. Murdering the population to return freq to 0.");
p1.genomes.removeMutations( sim.mutationsOfType(m1), T );
}
}
To view this discussion on the web visit https://groups.google.com/d/msgid/slim-discuss/7750b13b-52e4-4f49-9634-3d3c903235dc%40googlegroups.com.--
SLiM forward genetic simulation: http://messerlab.org/slim/
---
You received this message because you are subscribed to the Google Groups "slim-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to slim-discuss+unsubscribe@googlegroups.com.
To post to this group, send email to slim-d...@googlegroups.com.
Hi all,
After a somewhat lengthy off-list discussion, this issue has been resolved. Many thanks to Ben and Philipp for clarifying a number of points.
In summary:
Problem: We wanted to simulate a single biallelic locus and were interested in measuring properties of trajectories that ended in fixation. We encountered two problems with this. First, our populations were often getting “stuck” at 50% allele frequency, which was mysterious. Second, when this occurred, SLiM went from reporting one mutant (when calling sim.mutationFrequencies() ) to reporting two mutants. We did not expect this behavior when mutationStacking was turned off.
Explanation: As explained by Ben below, the issue is that SLiM tracks mutant lineages not simply the frequency of the mutant state. So, what we were observing was the de novo origination of a second mutant lineage while a first was already segregating. Because we had only one mutation type, with strong positive selection, the two mutant forms would together come to dominate the population, and they would reach an equilibrium of 50:50 frequency, since they had identical selection coefficients.
Solution: To avoid this scenario, we introduced a return process that identifies when the mutant state takes over the population (i.e., when the sum of the mutant frequencies reaches 1, or equivalently, when the sum of the mutant allele counts hits 2N). When this occurs, we reset the population and allow it to start again from a monomorphic wildtype population. The code for this follows:
// If running the simulation for 40,000 generations
1:40000 {
// Return process: whenever we hit frequency=1, introduce a return to frequency=0
muts = sim.mutations;
counts = sim.mutationCounts(p1, muts);
if (sum(counts) == 2N) {
print("Fixation occurred. Murdering the population to return freq to 0.");
p1.genomes.removeMutations( sim.mutationsOfType(m1), T );
}
}
This gives results as expected. I include edited excerpts of my conversations with Ben, below, in case it will be useful to the list.
Cheers,
- Jason
--
A.P. Jason de Koning, Ph.D.
Assistant Professor
University of Calgary, Cumming School of Medicine
Dept. of Biochemistry and Molecular Biology
Dept. of Medical Genetics
Alberta Children's Hospital Research Institute for Child and Maternal Health
and Arnie Charbonneau Cancer Institute
3330 Hospital Drive N.W.
Health Sciences Centre HSC 1151
Calgary, Alberta T2N 4N1 Canada
Office: 403-210-7638 | Fax: 403-270-8928
Email: jason.d...@ucalgary.ca
Web: http://lab.jasondk.io
---
Setting mutationStackPolicy to “f” specifically makes it so that if SLiM is considering introducing a new mutation at a given position, but a mutation of the same type already exists at that location in that individual, then the new mutation is suppressed. But only if one already exists in that individual! The location is not somehow “reserved” by the fact that a mutation already exists at that position in other individuals. There is no such concept in SLiM. So in your model as written, it is possible for two different mutations to be in circulation at the locus, and then it is perhaps clear how/why they might tend to “stick” at around 50% frequency, for the reasons Philipp described.
Is the idea that the model is still biallelic in the sense that there is one circulating mutant state, but that if a secondary mutant arises from a non-mutant during the segregation of an initial mutant, that SLiM considers the lineage arising from the second mutant a “different mutation”? I could see how this could be useful for tracking lineages during soft sweep scenarios, but as far as a (biallelic) WF model with mutation is concerned, reaching 100% frequency for the mutant state is fixation (regardless of whether the population arrived there via a ‘hard’ or ‘soft’ process). Perhaps this is where our thinking diverges. So to simulate a biallelic model should we be considering the frequency of the mutant state as the sum of the frequencies returned by `sim.mutationFrequencies()`? Or are you instead saying that SLiM is effectively modelling some kind of finite-sites infinite-alleles situation?
Every mutation that arises in SLiM is tracked separately. There is no concept of a generic “mutant state”; there are just actual mutations. Each mutation that arises is distinct. Two mutations that have the same mutation type and the same selection coefficient are nevertheless considered distinct mutations; they do not get “merged” by the SLiM engine. You can certainly do such merging yourself, if that is what you want; you can look for mutations that satisfy whatever your merging criteria are, and when you find a mutation B that you wish to merge into mutation A, remove B from all genomes where it occurs and add A to those genomes instead. In fact, I have written a recipe for the next version of the SLiM manual that does exactly that; I can send you that draft if you like. Or, as you say, if you want all mutations of a given type to be considered the same mutation, then you can simply add up their frequencies (or even better, to avoid possible floating-point roundoff issues, add up their counts, which are also available from SLiM). Recipe 10.5.1 in the existing cookbook has a presentation of a soft sweep model that handles this, so you might look at that recipe for some example code.
It is also true that in a sense, with the default stacking behavior, SLiM models a sort of finite-sites infinite-alleles model, since new mutations and stacked mutations can produce what are effectively new alleles at each base position. But since your model sets the stacking policy to “f”, that would then no longer be the case.
In either case, hanging out at 50:50 for the two mutants may make sense if they have identical large selection coefficients (as they do in our case). This perhaps raises an issue about how frequencies are displayed in the GUI. Until a second mutant lineage arises, frequency corresponds to frequency of the single mutant state. But after the second lineage arises, it continues to refer only to the frequency of the first mutant state. Is that right?
Each mutation is displayed with its own bar in the chromosome view. If two mutations are at the same base position, their bars will overlap. If they have different selection coefficients, then you might see a short bar of one color in front of a taller bar of the other color. If they have the same selection coefficient, and are thus displayed in the same color, then you will, in effect, see just a single bar with a height corresponding to the higher frequency among the two mutations. Again, SLiM in no way merges the two mutations together, conceptually or actually. They are two separate mutations that just happen to be at the same location, use the same mutation type, and have the same selection coefficient. So they are displayed independently in the GUI as well.
If you want to control new mutations completely, as you apparently do, then simply set the mutation rate to zero and introduce new mutations yourself using addNewMutation() or addNewDrawnMutation(). You can detect when there is no mutation existing (by checking sim.mutations) and introduce one. If you want the introductions to occur stochastically, with some mutation rate, you can use the random functions provided by Eidos, such as rpois(), to do so, but with a check to prevent one from being added when one already exists, as you want.
Thanks!
mutation(m1) {
m = sim.subsetMutations(position=mut.position);
if (m.length())
return m;
return T;
}
--
SLiM forward genetic simulation: http://messerlab.org/slim/
---
You received this message because you are subscribed to a topic in the Google Groups "slim-discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/slim-discuss/iHrVKX6qWco/unsubscribe.
To unsubscribe from this group and all its topics, send an email to slim-discuss...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/slim-discuss/383ba2d0-b2e0-4632-b37a-e4711378d9d1n%40googlegroups.com.