Single crossover

21 views
Skip to first unread message

Daiki Tagami

unread,
Apr 16, 2024, 9:29:46 AMApr 16
to slim-discuss
Dear all,

I have a question regarding recombination in SLiM.
I'm interested in implementing the following recombination event in a WF simulation:
- With probability (1-y), a gamete is created from each parent without recombination
- With probability y, there will be a single crossover between parental haplotypes

Is there a way to efficiently implement this in SLiM?
I saw the manual in detail, but I was not able to find the answer to this.
Thank you for your support.

Sincerely,
Daiki Tagami

Ben Haller

unread,
Apr 16, 2024, 10:09:44 AMApr 16
to Daiki Tagami, slim-discuss
Hi Daiki!

SLiM's built-in recombination model doesn't support dynamics like this, so you need to script it.  There are two fairly simple ways to do this:

- Only in a nonWF simulation (so not an option for your WF simulation), you could generate the breakpoint (or not) as you wish, in your reproduction() callback's script, and call addRecombinant() to generate the offspring individual with the breakpoint (or not) that you generated.  Very straightforward.

- In a WF or nonWF simulation, you could write a recombination() callback.  In this case, you could set the recombination rate to 0.0; you won't be using SLiM's automatic recombination breakpoint generation.  Then, in your recombination() callback, you will be passed an empty vector of breakpoints; you'll draw with runif() and compare to y to decide whether or not to generate a breakpoint; and if you decided to generate a breakpoint, you'll presumably use rdunif() to draw the position of the breakpoint and add it to the breakpoints vector.  Section 26.6 of the SLiM manual discusses the details of implementing a recombination() callback.

It isn't entirely clear to me whether you want this decision (break or no break) to be correlated (i.e., the same) for both gametes that make a new offspring, or uncorrelated.  If you want the decision to be correlated, then note that your recombination() callback will be called twice per offspring (once per gamete), and you'll want it to make the same decision both times (but, presumably, draw different breakpoint positions for the two gametes).  To do this, you'll need to rely on the fact that SLiM always generates gametes in order – your callback will be called two times in a row, to generate the two gametes for an offspring.  You'll need to use global state to achieve what you want.  For example:

initialize() {

defineConstant("Y", 0.2); // probability of a crossover

defineConstant("L", 1e5); // chromosome length

initializeMutationRate(1e-7);

initializeMutationType("m1", 0.5, "f", 0.0);

initializeGenomicElementType("g1", m1, 1.0);

initializeGenomicElement(g1, 0, L-1);

initializeRecombinationRate(0.0); // rec. rate of 0.0!

}

1 early() {

sim.addSubpop("p1", 500);

// initialize the global flag used by recombination()

defineGlobal("FIRST_GAMETE", T);

}

recombination() {

// make the crossing decision once per offspring

if (FIRST_GAMETE)

{

defineGlobal("CROSSED", runif(1) < Y);

defineGlobal("FIRST_GAMETE", F);

}

else

{

defineGlobal("FIRST_GAMETE", T);

}

if (CROSSED)

{

// crossover positions are to the left of base positions,

// so start at 1, not 0, for the rdunif() call

breakpoints = rdunif(1, 1, L-1);

// return T to indicate that changes were made

return T;

}

// return F to indicate changes were not made

return F;

}

2000 late() { }


A bit ugly, but although it takes some script to achieve the desired effect, it's not particularly slow, since it gets called only once per new gamete.  As usual, having this level of control over the process of reproduction would be much simpler and easier in a nonWF model.  (Note that you can implement WF model dynamics in a nonWF model; see section 15.13.)

If you don't want the decision to be correlated for the two gametes of an offspring, then you don't need that global state, so the model reduces to:

initialize() {

defineConstant("Y", 0.2); // probability of a crossover

defineConstant("L", 1e5); // chromosome length

initializeMutationRate(1e-7);

initializeMutationType("m1", 0.5, "f", 0.0);

initializeGenomicElementType("g1", m1, 1.0);

initializeGenomicElement(g1, 0, L-1);

initializeRecombinationRate(0.0); // rec. rate of 0.0!

}

1 early() {

sim.addSubpop("p1", 500);

}

recombination() {

if (runif(1) < Y)

{

// crossover positions are to the left of base positions,

// so start at 1, not 0, for the rdunif() call

breakpoints = rdunif(1, 1, L-1);

// return T to indicate that changes were made

return T;

}

// return F to indicate changes were not made

return F;

}

2000 late() { }


Feel free to ask more questions if something is unclear.  :->

Cheers,
-B.

Benjamin C. Haller
Messer Lab
Cornell University




Daiki Tagami wrote on 4/16/24 9:29 AM:
--
SLiM forward genetic simulation: http://messerlab.org/slim/
---
You received this message because you are subscribed to the Google Groups "slim-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to slim-discuss...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/slim-discuss/4e6084bb-a563-496b-8841-0e1621fec1b8n%40googlegroups.com.

Daiki Tagami

unread,
Apr 17, 2024, 10:58:01 PMApr 17
to slim-discuss
Hi Ben,

Thank you very much for your prompt response, and it was super helpful for me.
I would also like to thank you for providing sample codes to me.

After thinking hard, I decided to adapt the second code that you wrote, as I'm not interested in producing correlated gametes.
SLiM has been very helpful in my research project, and I will let you know if I have any additional questions in the future.

Thanks,
Daiki Tagami

Reply all
Reply to author
Forward
0 new messages