MesserLab / SLiM

SLiM is a genetically explicit forward simulation software package for population genetics and evolutionary biology. It is highly flexible, with a built-in scripting language, and has a cross-platform graphical modeling environment called SLiMgui.
https://messerlab.org/slim/
GNU General Public License v3.0
161 stars 33 forks source link

spatial locations outside of population bounds #480

Closed ShyamieG closed 1 month ago

ShyamieG commented 1 month ago

Hi! I posted this issue on the tskit github first and was asked to post here instead.

I'm seeing strange spatial location values in a tree sequence produced by SLiM in continuous space. I have set the spatial bounds of p0 in the x dimension to be -10 and 10. Within my SLiM code, I verified that no one has x values outside of this interval. However, when I examine the resulting tree sequence, I often see values lying well outside of these bounds. I am not sure what could be going wrong here.

import tskit

ts = tskit.load('loc_test.ts')
x_locs = [x[0] for x in ts.individuals_location]
np.nanmin(x_locs)
np.nanmax(x_locs)

See attached for my SLiM model and an example tree sequence file. Thanks in advance!

petrelharp commented 1 month ago

Hm, when I run your code I get

>>> np.min(x_locs)
np.float64(-9.999556506860776)
>>> np.max(x_locs)
np.float64(9.999672307767545)

But - I figured the problem was going to be because of uninitialized spatial locations; and indeed, looking at the code it seems that the individuals in the initial generation are Remembered before their spatial locations are set. Spatial location is one of those mutable-through-an-individual's-life things, so the policy is that the info that's recorded in the tree sequence is the info that is valid at the time the individual was last Remembered (or the tree sequence was written out). So, I'm actually surprised that I didn't get weird values.

Ah, I see why that is - if spatial locations are uninitialized, then their values are "whatever was in that hunk of memory"; and indeed it seems the spatial locations of those intial individuals were all set to zero (ie the memory was previously zero-ed):

>>> ts.node(0)
Node(id=0, flags=1, time=1000.0, population=0, individual=1000, metadata={'slim_id': 0, 'is_null': False, 'genome_type': 0})
>>> ts.individual(1000)
Individual(id=1000, flags=131072, location=array([0., 0., 0.]), parents=array([], dtype=int32), nodes=array([0, 1], dtype=int32), metadata={'pedigree_id': 0, 'pedigree_p1': -1, 'pedigree_p2': -1, 'age': 0, 'subpopulation': 0, 'sex': -1, 'flags': 0})

However, it is not guaranteed that is the case.

So - to fix this, set the initial generation's spatial locations before Remembering them.

petrelharp commented 1 month ago

I'll close this; please re-open if I've missed something.

ShyamieG commented 1 month ago

Thank you! That seems to have fixed the issue.