Getting traits into slim_engine.py - #1860
Conversation
I'm assuming that this is not going to work, but it's a first rough implementation.
will remove them later because they don't belong here.
unclear whether it is actually doing what we want or not though...
plus some formatting stuff to make it look nice
no way this works, and have not tested in slim yet...
again, totally unclear if they're doing what I think they're doing, but at least they're doing
should be more efficient, I think, than looping over in SLiM to see at each generation whether a given fitness function applies.
Should let users set environments and fitness functions that apply throughout burn-in
still need to check the interval arithmetic bit
update test to reflect that TraitsModel always includes fitness
For both Environment and FitnessFunction classes. Plus catching an error in slim_engine related to converting string population IDs to integers, and a minor issue in traits where the order of some checks was backward and could cause one of the checks to error instead of raising the intended error.
…psim into traits_into_slim_engine
|
Tick the box to add this pull request to the merge queue (same as
|
|
Also, we'd love input on certain decisions we've made about how generation times get interpreted since we newly allow users to specify generation times for both environments and fitness functions. In general, the decisions can be summarized as:
For some concrete examples, suppose we have a demographic model that begins 5,000 generations ago.
Also suppose that in this demographic model, pop B splits 3,000 generations ago, i.e. only exists on the interval
|
instead of directly updating phenotypes, environments now modify the individual offsets.
| for pop_id in env.population_list: | ||
| pop_ind_str.append(f'sim.subpopulations[{pop_id}].individuals') | ||
| pop_ind_str = ", ".join(pop_ind_str) |
There was a problem hiding this comment.
i'm a bit worried about this implementation choice. here subpopulations are referred to by index, so e.g., SLiM will go and pull subpop '2'. But if the number of active populations is changing over time, this could be an issue.
elsewhere I see that pop_ids (strings) are used, for example in the fitness function generator. I think that's the thing to do here too?
Like line 1831 could use f'p{pop_id}.individuals'?
| # the present. | ||
| accessible_demes = demographic_model.model.debug().possible_lineage_locations( | ||
| [ | ||
| msprime.SampleSet(1, population=p.id, time=0) |
There was a problem hiding this comment.
the TODO note is right here-- I think this will fail if the population isn't active, like with models with ancestral populations not present at sampling time. I think the fix is to set time=None and then msprime will sample each population at its default sampling time. I think....
There was a problem hiding this comment.
actually i went and tested this and I'm wrong about time=None -- that doesn't help.
instead i think we need to use demography.debug().epochs to walk through each to see which population is around
| raise ValueError( | ||
| "Intervals must start at the present or some more ancient time." | ||
| ) | ||
| if interval[0] > interval[1]: |
There was a problem hiding this comment.
i think we want to check that interval[0] is finite -- this would be a user error that hopefully we wouldn't see, but stuff would blow up if the user handed [inf, inf)
also we should check for zero length intervals like [4, 4) -- those would slip by, but probably not affect things?
|
generally this looks really good! I like the decisions you've outlined above @roshnipatel. I've placed some comments on some nitpicks I saw along the way, but haven't done a complete review of the code. Happy to do that whenever |
|
and yeah -- i could take a swing at the decorated demography thing @jeffspence. are you thinking a function that produces a table a la msprime's demography debugger? |
|
@andrewkern yeah! something like that would be great. Just something showing the populations and times of events (both demographic and traits related). |
|
Hi folks! A few superficial comments, not having looked at the underlying code:
That's all I see for right now. Great to see the progress! :-> You guys are kind of the guinea pigs for SLiM 6, since I haven't managed to get the SLiM 6 beta out yet; basically nobody is using it yet except you. So feedback on anything that seems non-optimal would be super useful. Thanks! |
|
@bhaller thanks for all of this!! We are very happy to be guinea pigs, and everything has been going pretty smoothly so far.
I believe that we're discussing that in this issue: #1830 . I'm inclined to stick with DME for now here, but am open to changing it in another PR.
Crossed out because I committed some changes to switch everything over to using the individual offsets. We rolled our own because I didn't read the SLiM documentation carefully enough, and then we switched it over when @petrelharp pointed us to the offsets. I think that the existing offset mechanism in SLiM works perfectly for us.
Yes, sorry -- I was a bit sloppy writing this up. We use the SLiM built-ins for mutations that only affect one trait and mutation callbacks for mutations that affect multiple traits.
Thanks for pointing this out. I'll take a look and see if we can switch to using
I think we settled on switching over all of the traits stuff to also use various Thanks again!! |
Work in progress (not ready for primetime yet)
This is where @roshnipatel and I have been working on getting traits implemented in slim_engine.
This is what we've done:
slim_engine.py:contigandTraitsModelTraitsModeland demographic modelEnvironmentandFitnessFunctionintraits.pyto specify the times and populations to which they apply (which is then used inslim_engine.py)traits.py, and have some hacky, non-functional tests for a couple ofslim_engine.pythings.Here are our TODOs:
late()blocks orfitnessEffect()code blocks. This is inconsistent with the ethos of the rest ofslim_engine.pywhich usesregisterLateEvent()to programmatically register demographic events based on tables of values defined at the beginning of the SLiM script.late()code blocks. This is a problem when new populations are created by population splits, because we want to access traits in populations that don't exist yet in their first generation. For now we've switch population splits toregisterEarlyEvent()s but this is probably bad.Environments andFitnessFunctions are consistent with the demography, but it would be cool to be able to print out a "decorated" demography somewhere, where it prints out simultaneously the demography and fitness functions and environments. @andrewkern -- would you be interested in tackling this?Update environments to use SLiM's individual offsets instead of doing it all ourselves.Other things:
generate_slim.pyandgenerate_slim.shwhich maketest_script.slim(all in thestdpopsim/directory. These are just temporary and I'm using them to look at the SLiM code generated byslim_engine.py. Once the PR is ready, they'll get removed.