Skip to content

Commit ed5ef14

Browse files
committed
add meanParentAge property, reduce Individual memory footprint
1 parent df7ed54 commit ed5ef14

15 files changed

Lines changed: 206 additions & 66 deletions

QtSLiM/QtSLiMIndividualsWidget.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -687,11 +687,11 @@ void QtSLiMIndividualsWidget::drawIndividualsFromSubpopulationInArea(Subpopulati
687687
float colorRed = 0.3f, colorGreen = 0.3f, colorBlue = 0.3f, colorAlpha = 1.0;
688688
Individual &individual = *subpop->parent_individuals_[static_cast<size_t>(individualArrayIndex)];
689689

690-
if (Individual::s_any_individual_color_set_ && !individual.color_.empty())
690+
if (Individual::s_any_individual_color_set_ && individual.color_set_)
691691
{
692-
colorRed = individual.color_red_;
693-
colorGreen = individual.color_green_;
694-
colorBlue = individual.color_blue_;
692+
colorRed = individual.colorR_ / 255.0F;
693+
colorGreen = individual.colorG_ / 255.0F;
694+
colorBlue = individual.colorB_ / 255.0F;
695695
}
696696
else
697697
{
@@ -1464,11 +1464,11 @@ void QtSLiMIndividualsWidget::drawSpatialIndividualsFromSubpopulationInArea(Subp
14641464
// dark gray default, for a fitness of NaN; should never happen
14651465
float colorRed = 0.3f, colorGreen = 0.3f, colorBlue = 0.3f, colorAlpha = 1.0;
14661466

1467-
if (Individual::s_any_individual_color_set_ && !individual.color_.empty())
1467+
if (Individual::s_any_individual_color_set_ && individual.color_set_)
14681468
{
1469-
colorRed = individual.color_red_;
1470-
colorGreen = individual.color_green_;
1471-
colorBlue = individual.color_blue_;
1469+
colorRed = individual.colorR_ / 255.0F;
1470+
colorGreen = individual.colorG_ / 255.0F;
1471+
colorBlue = individual.colorB_ / 255.0F;
14721472
}
14731473
else if (forceColor)
14741474
{

QtSLiM/help/SLiMHelpClasses.html

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<meta http-equiv="Content-Style-Type" content="text/css">
66
<title></title>
77
<meta name="Generator" content="Cocoa HTML Writer">
8-
<meta name="CocoaVersion" content="1894.6">
8+
<meta name="CocoaVersion" content="1894.7">
99
<style type="text/css">
1010
p.p1 {margin: 18.0px 0.0px 3.0px 0.0px; font: 11.0px Optima}
1111
p.p2 {margin: 6.0px 0.0px 3.0px 0.0px; font: 11.0px Optima}
@@ -340,7 +340,7 @@
340340
<p class="p3">age <span class="s6">&lt;–&gt;</span> (integer$)</p>
341341
<p class="p6">The age of the individual, measured in cycles.<span class="Apple-converted-space">  </span>A newly generated offspring individual will have an age of <span class="s1">0</span> in the same tick in which it was created.<span class="Apple-converted-space">  </span>The age of every individual is incremented by one at the same point that its species cycle counter is incremented, at the end of the tick cycle, <i>if and only if</i> its species was active in that tick.<span class="Apple-converted-space">  </span>The age of individuals may be changed; usually this only makes sense when setting up the initial state of a model, however.</p>
342342
<p class="p3">color &lt;–&gt; (string$)</p>
343-
<p class="p4">The color used to display the individual in SLiMgui.<span class="Apple-converted-space">  </span>Outside of SLiMgui, this property still exists, but is not used by SLiM.<span class="Apple-converted-space">  </span>Colors may be specified by name, or with hexadecimal RGB values of the form <span class="s1">"#RRGGBB"</span>.<span class="Apple-converted-space">  </span>If <span class="s1">color</span> is the empty string, <span class="s1">""</span>, SLiMgui’s default (fitness-based) color scheme is used; this is the default for new <span class="s1">Individual</span> objects.</p>
343+
<p class="p6">The color used to display the individual in SLiMgui.<span class="Apple-converted-space">  </span>Outside of SLiMgui, this property still exists, but is not used by SLiM.<span class="Apple-converted-space">  </span>Colors may be specified by name, or with hexadecimal RGB values of the form <span class="s1">"#RRGGBB"</span> (see the Eidos manual).<span class="Apple-converted-space">  </span>If <span class="s1">color</span> is the empty string, <span class="s1">""</span>, SLiMgui’s default (fitness-based) color scheme is used; this is the default for new <span class="s1">Individual</span> objects.<span class="Apple-converted-space">  </span>Note that named colors will be converted to RGB internally, so the value of this property will always be a hexadecimal RGB color string (or <span class="s1">""</span>).</p>
344344
<p class="p5"><span class="s3">fitnessScaling &lt;–&gt; (float$)</span></p>
345345
<p class="p6"><span class="s3">A </span><span class="s4">float</span><span class="s3"> scaling factor applied to the individual’s fitness (i.e., the fitness value computed for the individual will be multiplied by this value).<span class="Apple-converted-space">  </span>This provides a simple, fast way to modify the fitness of an individual; conceptually it is similar to returning a fitness effect for the individual from a </span><span class="s4">fitnessEffect()</span><span class="s3"> callback, but without the complexity and performance overhead of implementing such a callback.<span class="Apple-converted-space">  </span>To scale the fitness of all individuals in a subpopulation by the same factor, see the </span><span class="s4">fitnessScaling</span><span class="s3"> property of </span><span class="s4">Subpopulation</span><span class="s3">.</span></p>
346346
<p class="p6"><span class="s3">The value of </span><span class="s4">fitnessScaling</span><span class="s3"> is reset to </span><span class="s4">1.0</span><span class="s3"> every tick, so that any scaling factor set lasts for only a single tick.<span class="Apple-converted-space">  </span>This reset occurs immediately after fitness values are calculated, in both WF and nonWF models.</span></p>
@@ -354,6 +354,8 @@
354354
<p class="p6"><span class="s3">The second </span><span class="s4">Genome</span><span class="s3"> object associated with this individual.<span class="Apple-converted-space">  </span>This property is particularly useful when you want the second genome from each of a vector of individuals, as often arises in haploid models.</span></p>
355355
<p class="p3">index =&gt; (integer$)</p>
356356
<p class="p4">The index of the individual in the <span class="s1">individuals</span> vector of its <span class="s1">Subpopulation</span><span class="s2">.</span></p>
357+
<p class="p3">meanParentAge =&gt; (float$)</p>
358+
<p class="p6">The average age of the parents of this individual, measured in cycles.<span class="Apple-converted-space">  </span>Parentless individuals will have a <span class="s1">meanParentAge</span> of <span class="s1">0.0</span>.<span class="Apple-converted-space">  </span>The mean parent age is determined when a new offspring is generated, from the <span class="s1">age</span> property of the parent or parents involved in generating the offspring.<span class="Apple-converted-space">  </span>For <span class="s1">addRecombinant()</span> that is somewhat complex; see that method for details.</p>
357359
<p class="p5"><span class="s3">migrant =&gt; (logical$)</span></p>
358360
<p class="p6"><span class="s3">Set to </span><span class="s8">T</span><span class="s3"> if the individual is a recent migrant, </span><span class="s8">F</span><span class="s3"> otherwise.<span class="Apple-converted-space">  </span>The definition of “recent” depends upon the model type (WF or nonWF).</span></p>
359361
<p class="p6"><span class="s3">In WF models, this flag is set at the point when a new child is generated if it is a migrant (i.e., if its source subpopulation is not the same as its subpopulation), and remains valid, with the same value, for the rest of the individual’s lifetime.</span></p>
@@ -847,6 +849,7 @@
847849
<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>
848850
<p class="p6"><span class="s3">The </span><span class="s4">sex</span><span class="s3"> parameter is interpreted exactly as in </span><span class="s4">addCrossed()</span><span class="s3">; see that method for discussion.<span class="Apple-converted-space">  </span>If the offspring sex is specified in any way (i.e., if </span><span class="s4">sex</span><span class="s3"> is non-</span><span class="s4">NULL</span><span class="s3">), 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><span class="s4">sex</span><span class="s3"> is </span><span class="s4">NULL</span><span class="s3">), 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>Similarly, 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>When modeling the X or Y, </span><span class="s4">strand1</span><span class="s3"> and </span><span class="s4">strand2</span><span class="s3"> must be X genomes (or </span><span class="s4">NULL</span><span class="s3">), and </span><span class="s4">strand3</span><span class="s3"> and </span><span class="s4">strand4</span><span class="s3"> must both be X genomes or both be Y genomes (or </span><span class="s4">NULL</span><span class="s3">).</span></p>
849851
<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>
852+
<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>
850853
<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>
851854
<p class="p6"><span class="s3">Note that this method is only for use in nonWF models.<span class="Apple-converted-space">  </span>See </span><span class="s4">addCrossed()</span><span class="s3"> for further general notes on the addition of new offspring individuals.</span></p>
852855
<p class="p5"><span class="s3">– (No&lt;Individual&gt;$)addSelfed(object&lt;Individual&gt;$ parent)</span></p>

SLiMgui/PopulationView.mm

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -192,11 +192,11 @@ - (void)drawIndividualsFromSubpopulation:(Subpopulation *)subpop inArea:(NSRect)
192192
float colorRed = 0.3f, colorGreen = 0.3f, colorBlue = 0.3f, colorAlpha = 1.0;
193193
Individual &individual = *subpop->parent_individuals_[individualArrayIndex];
194194

195-
if (Individual::s_any_individual_color_set_ && !individual.color_.empty())
195+
if (Individual::s_any_individual_color_set_ && individual.color_set_)
196196
{
197-
colorRed = individual.color_red_;
198-
colorGreen = individual.color_green_;
199-
colorBlue = individual.color_blue_;
197+
colorRed = individual.colorR_ / 255.0F;
198+
colorGreen = individual.colorG_ / 255.0F;
199+
colorBlue = individual.colorB_ / 255.0F;
200200
}
201201
else
202202
{
@@ -1143,11 +1143,11 @@ - (void)drawSpatialIndividualsFromSubpopulation:(Subpopulation *)subpop inArea:(
11431143
// dark gray default, for a fitness of NaN; should never happen
11441144
float colorRed = 0.3f, colorGreen = 0.3f, colorBlue = 0.3f, colorAlpha = 1.0;
11451145

1146-
if (Individual::s_any_individual_color_set_ && !individual.color_.empty())
1146+
if (Individual::s_any_individual_color_set_ && individual.color_set_)
11471147
{
1148-
colorRed = individual.color_red_;
1149-
colorGreen = individual.color_green_;
1150-
colorBlue = individual.color_blue_;
1148+
colorRed = individual.colorR_ / 255.0F;
1149+
colorGreen = individual.colorG_ / 255.0F;
1150+
colorBlue = individual.colorB_ / 255.0F;
11511151
}
11521152
else
11531153
{

0 commit comments

Comments
 (0)