Skip to content

Commit

Permalink
add "randomizeStrands" flag to addRecombinant()
Browse files Browse the repository at this point in the history
  • Loading branch information
bhaller committed Oct 29, 2023
1 parent ce8b283 commit e7a03d5
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 8 deletions.
3 changes: 2 additions & 1 deletion QtSLiM/help/SLiMHelpClasses.html
Original file line number Diff line number Diff line change
Expand Up @@ -955,11 +955,12 @@
<p class="p6">By default – when <span class="s1">genome1Null</span> and <span class="s1">genome2Null</span> are both <span class="s1">NULL</span> – null genomes will be generated instead of empty genomes only in sex-chromosome simulations, where the sex chromosome that is not being simulated is represented by a null genome; otherwise, empty genomes rather than null genomes will be created.<span class="Apple-converted-space">  </span>This default behavior can be changed by passing <span class="s1">T</span> or <span class="s1">F</span> for <span class="s1">genome1Null</span> or <span class="s1">genome2Null</span>, which will force the corresponding offspring genome to be null (<span class="s1">T</span>) or non-null (<span class="s1">F</span>).<span class="Apple-converted-space">  </span>The behavior in sex-chromosome simulations cannot be changed, since the presence of null genomes there is dictated by sex, but <span class="s1">T</span> or <span class="s1">F</span> may be passed as long as it matches what SLiM would do anyway.<span class="Apple-converted-space">  </span>In all other simulations there is little point in passing <span class="s1">F</span> (since that would be the default behavior anyway), but passing <span class="s1">T</span> can be used to make one or both genomes be null genomes, which can be useful for, e.g., modeling haploids (for which, by convention, the <i>second</i> genome is usually a null genome in SLiM).</p>
<p class="p6">Beginning in SLiM 5.0, the <span class="s1">count</span> parameter dictates how many offspring will be generated (previously, exactly one offspring was generated).<span class="Apple-converted-space">  </span>Each offspring is generated independently, based upon the given parameters.<span class="Apple-converted-space">  </span>The returned vector contains all generated offspring, except those that were rejected by a <span class="s1">modifyChild()</span> callback.<span class="Apple-converted-space">  </span>If all offspring are rejected, <span class="s1">object&lt;Individual&gt;(0)</span> is returned, which is a zero-length <span class="s1">object</span> vector of class <span class="s1">Individual</span>; note that this is a change in behavior from earlier versions, which would return <span class="s1">NULL</span>.</p>
<p class="p6">Note that this method is only for use in nonWF models.<span class="Apple-converted-space">  </span>See <span class="s1">addCrossed()</span> for further general notes on the addition of new offspring individuals.</p>
<p class="p5"><span class="s3">– (object&lt;Individual&gt;)addRecombinant(No&lt;Genome&gt;$ strand1, No&lt;Genome&gt;$ strand2, Ni breaks1, No&lt;Genome&gt;$ strand3, No&lt;Genome&gt;$ strand4, Ni breaks2, [Nfs$ sex = NULL], [No&lt;Individual&gt;$ parent1 = NULL], [No&lt;Individual&gt;$ parent2 = NULL], [integer$ count = 1], [logical$ defer = F])</span></p>
<p class="p5"><span class="s3">– (object&lt;Individual&gt;)addRecombinant(No&lt;Genome&gt;$ strand1, No&lt;Genome&gt;$ strand2, Ni breaks1, No&lt;Genome&gt;$ strand3, No&lt;Genome&gt;$ strand4, Ni breaks2, [Nfs$ sex = NULL], [No&lt;Individual&gt;$ parent1 = NULL], [No&lt;Individual&gt;$ parent2 = NULL], [logical$ randomizeStrands = F], [integer$ count = 1], [logical$ defer = F])</span></p>
<p class="p6"><span class="s3">Generates a new offspring individual from the given parental genomes with the specified crossover breakpoints, queues it for addition to the target subpopulation, and returns it.<span class="Apple-converted-space">  </span>The new offspring will not be visible as a member of the target subpopulation until the end of the offspring generation tick cycle stage.<span class="Apple-converted-space">  </span>The target subpopulation will be used to locate applicable </span><span class="s4">mutation()</span><span class="s3"> and </span><span class="s4">modifyChild()</span><span class="s3"> callbacks governing the generation of the offspring individual (unlike the other </span><span class="s4">addX()</span><span class="s3"> methods, because there are potentially up to four parental individuals to reference); </span><span class="s4">recombination()</span><span class="s3"> callbacks will not be called by this method.<span class="Apple-converted-space">  </span>This method is an advanced feature; most models will use </span><span class="s4">addCrossed()</span><span class="s3">, </span><span class="s4">addSelfed()</span><span class="s3">, or </span><span class="s4">addCloned()</span><span class="s3"> instead.</span></p>
<p class="p6"><span class="s3">This method supports several possible configurations for </span><span class="s4">strand1</span><span class="s3">, </span><span class="s4">strand2</span><span class="s3">, and </span><span class="s4">breaks1</span><span class="s3"> (and the same applies for </span><span class="s4">strand3</span><span class="s3">, </span><span class="s4">strand4</span><span class="s3">, and </span><span class="s4">breaks2</span><span class="s3">).<span class="Apple-converted-space">  </span>If </span><span class="s4">strand1</span><span class="s3"> and </span><span class="s4">strand2</span><span class="s3"> are both </span><span class="s4">NULL</span><span class="s3">, the corresponding genome in the generated offspring will be empty, as from </span><span class="s4">addEmpty()</span><span class="s3">, with no parental genomes and no added mutations; in this case, </span><span class="s4">breaks1</span><span class="s3"> must be </span><span class="s4">NULL</span><span class="s3"> or zero-length.<span class="Apple-converted-space">  </span>If </span><span class="s4">strand1</span><span class="s3"> is non-</span><span class="s4">NULL</span><span class="s3"> but </span><span class="s4">strand2</span><span class="s3"> is </span><span class="s4">NULL</span><span class="s3">, the corresponding genome in the generated offspring will be a clonal copy of </span><span class="s4">strand1</span><span class="s3"> with mutations added, as from </span><span class="s4">addCloned()</span><span class="s3">; in this case, </span><span class="s4">breaks1</span><span class="s3"> must similarly be </span><span class="s4">NULL</span><span class="s3"> or zero-length.<span class="Apple-converted-space">  </span>If </span><span class="s4">strand1</span><span class="s3"> and </span><span class="s4">strand2</span><span class="s3"> are both non-</span><span class="s4">NULL</span><span class="s3">, the corresponding genome in the generated offspring will result from recombination between </span><span class="s4">strand1</span><span class="s3"> and </span><span class="s4">strand2</span><span class="s3"> with mutations added, as from </span><span class="s4">addCrossed()</span><span class="s3">, with </span><span class="s4">strand1</span><span class="s3"> being the initial copy strand; copying will switch between strands at each breakpoint in </span><span class="s4">breaks1</span><span class="s3">, which must be non-</span><span class="s4">NULL</span><span class="s3"> but need not be sorted or uniqued (SLiM will sort and unique the supplied breakpoints internally).<span class="Apple-converted-space">  </span>(It is not currently legal for </span><span class="s4">strand1</span><span class="s3"> to be </span><span class="s4">NULL</span><span class="s3"> and </span><span class="s4">strand2</span><span class="s3"> non-</span><span class="s4">NULL</span><span class="s3">; that variant may be assigned some meaning in future.)<span class="Apple-converted-space">  </span>Again, this discussion applies equally to </span><span class="s4">strand3</span><span class="s3">, </span><span class="s4">strand4</span><span class="s3">, and </span><span class="s4">breaks2</span><span class="s3">, <i>mutatis mutandis</i>.<span class="Apple-converted-space">  </span>Note that when new mutations are generated by </span><span class="s4">addRecombinant()</span><span class="s3">, their </span><span class="s4">subpopID</span><span class="s3"> property will be the </span><span class="s4">id</span><span class="s3"> of the offspring’s subpopulation, since the parental subpopulation is ambiguous; this behavior differs from the other </span><span class="s4">add...()</span><span class="s3"> methods.</span></p>
<p class="p6">The <span class="s1">sex</span> parameter is interpreted exactly as in <span class="s1">addCrossed()</span>; see that method for discussion.<span class="Apple-converted-space">  </span>If the offspring sex is specified in any way (i.e., if <span class="s1">sex</span> is non-<span class="s1">NULL</span>), the strands provided must be compatible with the sex chosen.<span class="Apple-converted-space">  </span>If the offspring sex is not specified (i.e., if <span class="s1">sex</span> is <span class="s1">NULL</span>), the sex will be inferred from the strands provided where possible (when modeling an X or Y chromosome), or will be chosen randomly otherwise (when modeling autosomes); it will <i>not</i> be inferred from the sex of the individuals possessing the parental strands, even when the reproductive mode is essentially clonal from a single parent, since such inference would be ambiguous in the general case.<span class="Apple-converted-space">  </span>When modeling the X or Y, <span class="s1">strand1</span> and <span class="s1">strand2</span> must be X genomes (or <span class="s1">NULL</span>), and <span class="s1">strand3</span> and <span class="s1">strand4</span> must both be X genomes or both be Y genomes (or <span class="s1">NULL</span>).</p>
<p class="p6">By default, the offspring is considered to have no parents for the purposes of pedigree tracking, since there may be more than two “parents” in the general case.<span class="Apple-converted-space">  </span>If pedigree tracking of parentage is desired, <span class="s1">parent1</span> and/or <span class="s1">parent2</span> may be passed to explicitly establish particular individuals as the parents of the offspring for purposes of pedigree tracking.<span class="Apple-converted-space">  </span>In this case, if only one of <span class="s1">parent1</span> and <span class="s1">parent2</span> is non-<span class="s1">NULL</span>, that individual will be set as <i>both</i> of the parents of the offspring, mirroring the way that parentage is tracked for other cases such as <span class="s1">addCloned()</span> and <span class="s1">addSelfed()</span>.<span class="Apple-converted-space">  </span>It is not required for <span class="s1">parent1</span> or <span class="s1">parent2</span> to actually be a genetic parent of the offspring at all, although typically they would be.</p>
<p class="p6">If <span class="s1">randomizeStrands</span> is <span class="s1">F</span> (the default), <span class="s1">strand1</span> will be the initial copy strand when generating the first gamete to form the offspring, and <span class="s1">strand3</span> will be the initial copy strand when generating the second gamete.<span class="Apple-converted-space">  </span>If <span class="s1">randomizeStrands</span> is T, then if <span class="s1">strand1</span> and <span class="s1">strand2</span> are both non-<span class="s1">NULL</span>, 50% of the time they will be swapped, making <span class="s1">strand2</span> the initial copy strand for the first gamete; and similarly, if <span class="s1">strand3</span> and <span class="s1">strand4</span> are both non-<span class="s1">NULL</span>, 50% of the time they will be swapped, making <span class="s1">strand4</span> the initial copy strand for the second gamete.<span class="Apple-converted-space">  </span>This is probably usually the desired behavior, to avoid an inheritance bias due to a lack of randomization in the initial copy strand, so passing <span class="s1">T</span> for <span class="s1">randomizeStrands</span> is recommended unless you specifically desire otherwise.<span class="Apple-converted-space">  </span>It is not the default behavior only for reasons of backward compatibility.</p>
<p class="p6"><span class="s3">These semantics allow several uses for </span><span class="s4">addRecombinant()</span><span class="s3">.<span class="Apple-converted-space">  </span>When all strands are non-</span><span class="s4">NULL</span><span class="s3">, it is similar to </span><span class="s4">addCrossed()</span><span class="s3"> except that the recombination breakpoints are specified explicitly, allowing very precise offspring generation without having to override SLiM’s breakpoint generation with a </span><span class="s4">recombination()</span><span class="s3"> callback.<span class="Apple-converted-space">  </span>When only </span><span class="s4">strand1</span><span class="s3"> and </span><span class="s4">strand3</span><span class="s3"> are supplied, it is very similar to </span><span class="s4">addCloned()</span><span class="s3">, creating a clonal offspring, except that the two parental genomes need not belong to the same individual (whatever that might mean biologically).<span class="Apple-converted-space">  </span>Supplying only </span><span class="s4">strand1</span><span class="s3"> is useful for modeling clonally reproducing haploids; the second genome of every offspring will be kept empty and will not receive new mutations.<span class="Apple-converted-space">  </span>For a model of clonally reproducing haploids that undergo horizontal gene transfer (HGT), supplying only </span><span class="s4">strand1</span><span class="s3"> and </span><span class="s4">strand2</span><span class="s3"> will allow HGT from </span><span class="s4">strand2</span><span class="s3"> to replace segments of an otherwise clonal copy of </span><span class="s4">strand1</span><span class="s3">, while the second genome of the generated offspring will again be kept empty; this could be useful for modeling bacterial conjugation, for example.<span class="Apple-converted-space">  </span>Other variations are also possible.</span></p>
<p class="p6">The value of the <span class="s1">meanParentAge</span> property of the generated offspring is calculated from the mean parent age of each of its two genomes (whether they turn out to be null genomes or not); that may be an average of two values (if both offspring genomes have at least one parent), a single value (if one offspring genome has no parent), or no values (if both offspring genomes have no parent, in which case <span class="s1">0.0</span> results).<span class="Apple-converted-space">  </span>The mean parent age of a given offspring genome is the mean of the ages of the parents of the two strands used to generate that offspring genome; if one strand is <span class="s1">NULL</span> then the mean parent age for that offspring genome is the age of the parent of the non-<span class="s1">NULL</span> strand, while if both strands are <span class="s1">NULL</span> then that offspring genome is parentless and is not used in the final calculation.<span class="Apple-converted-space">  </span>In other words, if one offspring genome has two parents with ages A and B, and the other offspring genome has one parent with age C, the <span class="s1">meanParentAge</span> of the offspring will be (A+B+C+C) / 4, not (A+B+C) / 3.</p>
<p class="p6"><span class="s3">Note that gene conversion tracts are not explicitly supported by this method; the </span><span class="s4">breaks</span><span class="s3"> vectors provide crossover breakpoints, which may be used to implement crossovers or simple gene conversion tracts.<span class="Apple-converted-space">  </span>There is no way to specify complex gene conversion tracts with heteroduplex mismatch repair.</span></p>
Expand Down
33 changes: 32 additions & 1 deletion SLiMgui/SLiMHelpClasses.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -8414,7 +8414,7 @@ Note that this method is only for use in nonWF models. See
\pard\pardeftab397\li720\fi-446\ri720\sb180\sa60\partightenfactor0
\f3\fs18 \cf2 \expnd0\expndtw0\kerning0
\'96\'a0(object<Individual>)addRecombinant(No<Genome>$\'a0strand1, No<Genome>$\'a0strand2, Ni\'a0breaks1, No<Genome>$\'a0strand3, No<Genome>$\'a0strand4, Ni\'a0breaks2, [Nfs$\'a0sex\'a0=\'a0NULL], [No<Individual>$\'a0parent1\'a0=\'a0NULL], [No<Individual>$\'a0parent2\'a0=\'a0NULL], [integer$\'a0count\'a0=\'a01], [logical$\'a0defer\'a0=\'a0F])\
\'96\'a0(object<Individual>)addRecombinant(No<Genome>$\'a0strand1, No<Genome>$\'a0strand2, Ni\'a0breaks1, No<Genome>$\'a0strand3, No<Genome>$\'a0strand4, Ni\'a0breaks2, [Nfs$\'a0sex\'a0=\'a0NULL], [No<Individual>$\'a0parent1\'a0=\'a0NULL], [No<Individual>$\'a0parent2\'a0=\'a0NULL], [logical$\'a0randomizeStrands\'a0=\'a0F], [integer$\'a0count\'a0=\'a01], [logical$\'a0defer\'a0=\'a0F])\
\pard\pardeftab720\li547\ri720\sb60\sa60\partightenfactor0
\f4\fs20 \cf2 Generates a new offspring individual from the given parental genomes with the specified crossover breakpoints, queues it for addition to the target subpopulation, and returns it. The new offspring will not be visible as a member of the target subpopulation until the end of the offspring generation tick cycle stage. The target subpopulation will be used to locate applicable
Expand Down Expand Up @@ -8564,6 +8564,37 @@ By default, the offspring is considered to have no parents for the purposes of p
\f4\fs20 or
\f3\fs18 parent2
\f4\fs20 to actually be a genetic parent of the offspring at all, although typically they would be.\
If
\f3\fs18 randomizeStrands
\f4\fs20 is
\f3\fs18 F
\f4\fs20 (the default),
\f3\fs18 strand1
\f4\fs20 will be the initial copy strand when generating the first gamete to form the offspring, and
\f3\fs18 strand3
\f4\fs20 will be the initial copy strand when generating the second gamete. If
\f3\fs18 randomizeStrands
\f4\fs20 is T, then if
\f3\fs18 strand1
\f4\fs20 and
\f3\fs18 strand2
\f4\fs20 are both non-
\f3\fs18 NULL
\f4\fs20 , 50% of the time they will be swapped, making
\f3\fs18 strand2
\f4\fs20 the initial copy strand for the first gamete; and similarly, if
\f3\fs18 strand3
\f4\fs20 and
\f3\fs18 strand4
\f4\fs20 are both non-
\f3\fs18 NULL
\f4\fs20 , 50% of the time they will be swapped, making
\f3\fs18 strand4
\f4\fs20 the initial copy strand for the second gamete. This is probably usually the desired behavior, to avoid an inheritance bias due to a lack of randomization in the initial copy strand, so passing
\f3\fs18 T
\f4\fs20 for
\f3\fs18 randomizeStrands
\f4\fs20 is recommended unless you specifically desire otherwise. It is not the default behavior only for reasons of backward compatibility.\
\pard\pardeftab720\li547\ri720\sb60\sa60\partightenfactor0
\cf2 \expnd0\expndtw0\kerning0
These semantics allow several uses for
Expand Down
1 change: 1 addition & 0 deletions VERSIONS
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ development head (in the master branch):
add Laplace DFE for MutationType, type "p"; contributed by Nick O'Brien
extend sampleIndividuals() and subsetIndividuals() to support constraining by tagL0 - tagL4
policy change: if tag is specified (non-NULL), the tag property must now have a defined value on all individuals; previously this was not checked, and individuals with an undefined tag value were simply excluded
add [logical$ randomizeStrands = F] flag to addRecombinant; if T, strand1/strand2 and strand3/strand4 will be randomized for each offspring generated


version 4.0.1 (Eidos version 3.0.1):
Expand Down
Loading

0 comments on commit e7a03d5

Please sign in to comment.