BoPeng / simuPOP

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

Monogamous mating without fixed offspring number #61

Closed MrLocuace closed 6 years ago

MrLocuace commented 6 years ago

Hi Bo, I have been struggling with an issue and would highly appreciate any suggestion. Let's take this example from the manual: http://simupop.sourceforge.net/manual_svn/build/monogamous.py

import simuPOP as sim
pop = sim.Population(20, infoFields=['father_idx', 'mother_idx'])
pop.evolve(
    initOps=sim.InitSex(sex=(sim.MALE, sim.FEMALE)),
    matingScheme=sim.MonogamousMating(
        numOffspring=2,
        sexMode=(sim.NUM_OF_MALES, 1),
        ops=[
            sim.MendelianGenoTransmitter(),
            sim.ParentsTagger(),
        ],
    ),
    gen = 5
)

I would like to estimate the numOffspring under a Monogamous Mating scheme after n generations using a specific demographic scenario. However, I do not want to fix the NUM_OF_MALES or the numOffspring, but rather obtain these parameter values using certain distributions or probabilities (e.g. Poisson distributed numOffspring, PROB_OF_MALES = 0.5). Whenever I change the sexMode (e.g. PROB_OF_MALES) or disable numOffspring, I get:

RuntimeError: All males (or females) have been chosen.

By using a large population size, I think there should be enough males and females to mate after several generations, like in real world populations.

Is there any way to achieve a monogamous mating of this kind with simuPOP?.

This question is related to another one posted 3 years ago: https://sourceforge.net/p/simupop/mailman/message/34414865/

Perhaps there has been changes since 2015 (?)

Thank you for your help, Luc

BoPeng commented 6 years ago

Monogamous mating scheme is tricky because each parent can only be chosen once. In a population with population growth there might not be enough parents and offspring to generate enough number of offspring, and sexual imbalance can only make things worse. The problem here is that simuPOP relies on the pre-determined population size so you can not find parents and generate offspring until all parents are exhausted.

If you really want to simulate monogamouse mating scheme with fixed demographic model, you will have to pre-determine number of parents (smaller of father and mother), calculate the exact number of offspring for each mating event, and pass the number of offspring to the evolving population, as explained at http://simupop.sourceforge.net/manual_svn/build/refManual_ch2_sec3.html#class-offspringgenerator

Parameter numOffspring is used to control the number of offspring per mating event, or in another word the number of offspring in each family. It can be a number, a Python function or generator, or a mode parameter followed by some optional arguments. If a number is given, given number of offspring will be generated at each mating event. If a Python function is given, it will be called each time when a mating event happens.

It will be very ugly but it can be something like (not tested at all):

g_numOff = []
g_index = 0

def demoModel(...):
    # get number of males and females, and size of offspring population
    # do some calculation
    global g_numOff, g_index
    g_numOff = [ ....]
    g_index = 0
    ...

def numOff():
    global g_numOff, g_index
    ret = g_numOff[g_index]
    g_index += 1
    return ret

pop.evolve(...
    numOffspring=numOff
)

In this way you know that the offspring will be filled right when all parents are exhausted.

MrLocuace commented 6 years ago

Thank you very much, Bo !. You are so helpful as always !