python trait tests - #672
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## multitrait #672 +/- ##
==============================================
- Coverage 76.79% 76.77% -0.03%
==============================================
Files 117 117
Lines 78866 78866
Branches 14320 14316 -4
==============================================
- Hits 60565 60549 -16
- Misses 18301 18317 +16 🚀 New features to boost your workflow:
|
|
Okay, I know (part of?) what's going on: Options for accumulateBaseline and convertToSubstitution:
In the current code, I was including fixed mutations in trait computation if accumulate=T. But if we're not converting mutations, this is not correct. And, from the tree sequence I have no way of knowing whether (a) a given mutation was converted to a substitution, or (b) whether a given mutation type has convertToSubstitution turned on or not. For testing purposes, I could record the I guess this means that you could save out a tree sequence with I'm not sure if the inability to compute traits - in all situations, without extra information from the script - from the genotype information in the tree sequence is a problem. I suppose not. |
|
Hah! I got the logic right for convert/accumulate. Still one failing, and that's the one where I add mutations: |
|
Okay, there's something funny with if I uncomment the line that makes This is vaguely ringing a bell? Do addDrawnMutations interact with baseline offset differently or something? |
For (2) and (4), it's moot because if convert=F, no mutations get turned into substitutions. They stay mutations, and they continue to count towards the trait just like other mutations. Not sure if we're on the same page there or not.
So here I'm puzzled. As I commented above, if convert=F, mutations stay mutations, and continue to count; the value of accumulate then doesn't even matter, since substitution doesn't happen. But you say here "I was including fixed mutations in trait computation... this is not correct." In what way is it not correct?
I'm confused about this, too. Why do you even need to know whether a mutation was converted to a substitution or not? On the python side, they're all just mutations, and they all count; there is no distinction between mutations and substitutions on the python side. I thought you weren't using the "substitution offset" on the python side at all.
Yes, to get correct results it is required that the simulation be configured in the same way at save and load. SLiM doesn't check every possible way that that could be violated (because then we'd have to write everything out to metadata, just to be able to do that check), but it is required, and if the user goes off-piste the consequences are Somebody Else's Problem.
I am puzzled as to why this is not possible; I'm not following your logic above. Clarify please? |
|
By the way, you asked somewhere (Slack?) why case 3 is allowed, since it would appear to produce incorrect trait values; a mutation gets substituted, and its effects just go away. The reason is basically for backward compatibility. This is precisely how things worked before SLiM 6 when simulating quantitative traits, since there was no built-in support for them, just But pondering this, probably that combination should only be legal when using the default trait...? In models that use So maybe this case 3 is the source of a lot of your woes above? Sorry about that, if so! |
No, I don't think so...? So, hmm. Looking at your code: Parsing what this code is doing... It loops over the chromosomes and, for each chromosome, gets the vector of all haplosomes. Then it calls So I guess the question is, what's special about this code? What is it doing that pushes a weird button, either in SLiM or in your Python code? My first guess is that the problem occurs when two of the draws from Note that the SLiM core no longer produces this situation, ever; it uniques the mutation positions that it draws, specifically to avoid this kind of situation because it was giving us problems! I don't remember the details of the problems it caused, but it seems likely to me that the same problems are arising here. If so, then perhaps Anyhow, let's first figure out if positional collision is indeed the problem, then figure out why that's a problem, then figure out what to do about it. :-> |
I agree about the strongly worded warning! |
LOL sorry. My first pass here was "if a mutation is at frequency 1.0 then only include it if accumulate=T". This assumes that convert=T. In fact, I need to not include the effects of a mutation that I see at frequency 1.0 only if convert=T and we are not accumulating. In other words, in case (3). |
|
Nope, uniquing the mutation location (or just applying one mutation per hap) doesn't fix the problem. |
|
It's being very tricky to get this into a part of parameter space where either (a) it's totally minimal, or (b) the behavior doesn't depend on seed. But, this is pretty good (note it's only adding a single m2 mutation in the first generation): This has traits that differ from python. Changing the seed to 38 does not. What's the difference between those? In both those seeds, (a) there's both an m1 and an m2 mutation at the same position in a single individual; and (b) the m2 mutations are no longer around at the end of the simulation. The trait values in metadata agree with what SLiMgui reports on the fly. Making the number of generations smaller (tends to?) make the problem go away: for instance, at 20 total generations, the problem only occurs about half the time; here it occurs most of the time. A similar thing happens with the number of individuals. Here's the phenotypes: first column in python, second is as reported by SLiM in metadata, third is the difference: This is typical: across seeds, the last column is different, but all the values agree with each other in the first two decimals. (e.g., 0.026 in this seed, 0.015 in another). |
|
Okay, the problem is that SLiM thinks that these individuals have fewer mutations than python does! Now, which ones? |
|
And, the mutations in the first individual that python is counting that SLiM is not are For reference, here's the python code I used to investigate (note that in this model, fitness is And, here's the mutations carried by the first individual according to the tree sequence: |
|
OKAY THE PROBLEM IS IN PYTHON You know what my code thinks the frequency of SLiM mutation 13 is? 0.9999999999999997. (Thus, not fixed.) |
|
Sorry for all the noise there! That was very annoying. The problem was that I was adding up the frequencies of all the variants that carried mutation 13 to get the frequency of SLiM mutation 13; however, floating-point error. Changing to adding up the counts fixed the problem. |
|
Yeah, can't count frequencies due to roundoff. I had that bug in SLiM somewhere, at one point. Excellent detective work! |
|
Now I'm trying to get it to use development pyslim... |
use dev pyslim
|
what the heck, I swear this passed the tests before I squashed those commits |
Here's python code to test for trait consistency. Currently, I'm getting failures only for these two:
This is confusing to me - I should have more! - because I seem not to be triggering #671? And, why is "WF no substitutions" failing but not "nonWF" (which has no substitutions)?
There's probably some dumb errors, is why. But there's a lot going on here.