BoPeng / simuPOP

A general-purpose forward-time population genetics simulation environment.
http://bopeng.github.io/simuPOP/
GNU General Public License v2.0
30 stars 12 forks source link

Pair crosses in simuPOP #89

Closed khornick1 closed 2 years ago

khornick1 commented 2 years ago

Hi Bo,

I am trying to set up simulations that involve pair crosses (24 parents; 19 males and 5 females; 95 crosses) with 10,000 offspring per pair.

It seems like there isn't an option within simuPOP (maybe a parentchooser?) to create pair crosses and control offspring per pair, though I could be wrong. I've seen that this could potentially be done within saegus, though I'm not simulating linkage. Any guidance would be much appreciated. Thanks!

BoPeng commented 2 years ago

pyParentChooser might be the one you are looking for. doc.

Basically, you will need to pre-calculate and set the size of the offspring generation then use something like

def pairedChooser(pop, subPop):
    males = ...
    females = ...
    pairs = .....
    for parents in pairs:
        for off in range(10,000):
            yield parents

Essentially speaking, simuPOP calls this function to get the parents of each offspring so you will have to yield the same parents 10,000 times before turning to the next set of manually-paired parents.

khornick1 commented 2 years ago

Thanks! That's really helpful.

I was then going to kill offspring from specific parents (1 of 5 males and 4 of 19 females yield no or very few offspring). I was going to use some sort of kill function that I specify for this purpose or a fitness function (I am tracking mother_id and father_id), as DiscardIf might be tricky in this case? I'll note that mortality for individuals will be a product of their age-specific mortality rates as well as their family-specific mortality rates. I'm not simulating natural selection so maybe simulating this as some sort of defined kill function is the best approach?

BoPeng commented 2 years ago

DiscardIf as a during mating operator can do this (get the parent IDs using some tagger before using DiscardIf to kill offspring). This is not particularly hard but it could be tricky to set the size of the offspring generation since pyParentChooser need to produce more pairs in preparation for deceased offspring.

Regardless how you call this, this is some sort of natural selection and can be even simulated with during-mating selection operator.

khornick1 commented 2 years ago

Hi Bo,

Thank you, that is helpful. Yes, indeed it is some sort of natural selection, I just wanted to be clear that I am simulating only neutral loci.

Just to clarify, I plan to kill offspring from specific parents after mating (was thinking this could be done as postOps). This is to represent drop out of certain parents throughout larval stages. So, offspring from certain parents will be killed prior to reaching the next larval stage (which I have set up as vsps). So, I don't think I would need to produce more pairs in prep for the deceased offspring, right? And with the DiscardIf function, wouldn't I have to get mother_id and father_id of offspring first in order to create this mortality?

BoPeng commented 2 years ago

According to the doc, you can pass a function with paramter dad, mom, so that you can discard offspring according to IDs of parents.

Yes, you do not need to prepare "size" for killed offspring, but you do need to plan ahead and decide on the size of the offspring population since the mating scheme will continue (will need pairs of parents) until the offspring generation is filled.

khornick1 commented 2 years ago

Thanks! That makes sense. Sorry, I'm having trouble figuring out how to write that kill function without IDing parents first?

BoPeng commented 2 years ago

You will need to use IDTagger to tag IDs and use other operators to maintain the information fields that you need. Then you need to define a function that accepts parameters such as mom and dad, and use its return value to determine if you want to discard the offspring. Finally use that function to create a DiscardIf operator that actually discard offspring. You can use PyOutput and print functions inside the discardif function for debugging.