Quantitative Genetics Practical 8: Genetic gain and diversity across generations
Learning objectives
Simulate offspring from phased parents; retain one genetic architecture and reporting base; distinguish phenotypes from genetic truth; compare phenotype-based and random selection; and interpret gain, genetic variance and marker diversity across generations.
Continue from Practical 7 and the slides on selection on complex traits. This is a small, hypothetical simulation, not an analysis of the mouse dataset or a qualification of a breeding strategy. It uses base R and the existing gsim package, with no biological downloads or predictor fitting. See Practical 7 for installation.
1. Declare the biological and programme assumptions
We use 32 diploid founders, six linked biallelic markers on one chromosome, and one additive trait measured in arbitrary trait units. The genome has no dominance, mutation or migration in this example. Marker effects remain fixed. gsim models chromosome-wise meiosis with Poisson crossovers and no interference, using the supplied cumulative genetic map.
Each generation has 16 candidates per parental role. Select four sires and four dams, then draw 32 offspring by uniform independent parent sampling with replacement. Every new cohort replaces the previous cohort as the candidate population; no parents are carried over. Offspring sex alternates by identity so that role counts remain fixed. This is a deliberate programme simplification.
2. Create a synthetic phased founder panel
Use R’s RNG only to create this tiny synthetic input. Calls explicitly contain phase: 0|1 and 1|0 identify different parental copies. Here allele 1 is VCF ALT, G; gsim retains it as BIM A1 and dosage counts this allele. File outputs go to a new temporary folder on each run.
The two founder exports use the same stored founder alleles. They provide phased input for transmission and dosage input for reporting. They do not independently redraw founders.
3. Freeze the architecture and reporting base
For dosage \(d_{ij}\) of allele G at marker \(j\), define genetic value
\[g_i=\sum_j(d_{ij}-c_j)\beta_j,\]
where effects \(\beta_j\) are in trait units per allele and centers \(c_j\) remain fixed at one. With this additive architecture, these genetic values supply the simulation’s additive merit. No cohort-specific variance normalization is applied.
We will also report allele frequencies and heterozygosity at these same six markers. For this tiny teaching panel, applying an identity effect matrix with zero center returns six dosage columns through the public accumulation interface. This deliberately materializes only 32 by 6 values; it is not a whole-genome extraction workflow.
Show R code
dosage_effects <-diag(length(markers))dimnames(dosage_effects) <-list(markers,markers)dosage_state <-gsim_trait_state(dosage_effects,center=0)d0 <-gsim_genetic_values(bed0,dosage_state)stopifnot(identical(dimnames(d0),dimnames(h1)),max(abs(d0-(h1+h2)))==0)summarize_cohort <-function(bed,policy,generation) { g <-gsim_genetic_values(bed,state) d <-gsim_genetic_values(bed,dosage_state)stopifnot(all(d %in%0:2)) p <-colMeans(d)/2# A second route to the mean, independent of individual aggregation. mean_from_p <-sum((2*p-1)*effects[,"trait"])stopifnot(abs(mean(g)-mean_from_p)<1e-12)data.frame(policy=policy,generation=generation,mean_genetic=mean(g),gain=mean(g)-base_mean,genetic_variance=var(drop(g)),mean_HE=mean(2*p*(1-p)),mean_HO=mean(colMeans(d==1)),polymorphic=sum(p>0& p<1))}knitr::kable(summarize_cohort(bed0,"Founders",0),digits=4,row.names=FALSE)
policy
generation
mean_genetic
gain
genetic_variance
mean_HE
mean_HO
polymorphic
Founders
0
0.0187
0
0.0459
0.4935
0.5208
6
Here \(H_E=2p(1-p)\) describes two independent gene copies drawn with replacement from the cohort’s marker frequencies. \(H_O\) is the observed fraction of heterozygous individuals. Their difference does not by itself identify inbreeding. We keep all six markers in the denominator, including any that later fix. No independent-copy finite-sample correction is used for related offspring.
Question 1. Why not center marker dosages separately in every generation?
Suggested answer
Using each cohort’s own mean dosage would force the cohort mean genetic value to zero and hide gain. One architecture and one reporting base let us compare genetic values over time. Marker frequencies may change; the centers used for reporting do not.
4. Generate records, select parents and simulate offspring
Generate one phenotype per candidate as \(y_i=g_i+e_i\), with residual variance 0.04 trait units squared and no fixed or permanent-environment contribution. Select on this observable phenotype, not hidden genetic truth. Genetic truth is read separately to evaluate outcomes after the decision.
The comparison selects parents randomly with the same role quotas. It shares founder inputs and numbered seed schedules with the phenotype strategy. Diverging selected pools and pedigrees still produce different later populations; the comparison is one illustrative realization per policy.
Show R code
run_programme <-function(policy,generations=3L) { current <- phase0; bed <- bed0; pedigree <- pedigree0 animals <- ids; sex <- parent_table$sex history <-list(summarize_cohort(bed,policy,0)) transitions <-list()for(t inseq_len(generations)) { g <-gsim_genetic_values(bed,state) records <-gsim_records(g,residual_covariance=.04,seed=200+t) observed <- records$recordsstopifnot(all(observed$trait=="trait"),!anyDuplicated(observed$animal)) scores <-setNames(observed$value,observed$animal) selection <-if(policy=="Phenotype") {gsim_select(animals,c(M=4,F=4),scores=scores,method="score",strata=sex) } else {gsim_select(animals,c(M=4,F=4),method="random",strata=sex,seed=400+t) } sires <- selection$animal[selection$selected & selection$stratum=="M"] dams <- selection$animal[selection$selected & selection$stratum=="F"] children <-sprintf("g%d-%02d",t,1:32) mating <-gsim_mate(pedigree,sires,dams,children,seed=300+t,sex=setNames(rep(c("M","F"),16),children)) plan <- mating$offspring# Truth evaluates the already specified parentage; it did not select parents. parent_expectation <-mean((g[plan$sire,"trait"]+g[plan$dam,"trait"])/2) next_cohort <-gsim_simulate_cohort(current,mating,seed=500+t,output=file.path(work,paste0(policy,"-generation",t))) offspring_g <-gsim_genetic_values(next_cohort,state)# At every marker, each parent transmits one of its two alleles. parental_d <-gsim_genetic_values(bed,dosage_state) child_d <-gsim_genetic_values(next_cohort,dosage_state) sire_d <- parental_d[plan$sire,,drop=FALSE] dam_d <- parental_d[plan$dam,,drop=FALSE] lower <- (sire_d==2)+(dam_d==2) upper <- (sire_d>0)+(dam_d>0)stopifnot(all(child_d>=lower & child_d<=upper),identical(attr(offspring_g,"trait_state_checksum"),state$checksum)) transitions[[t]] <-data.frame(policy=policy,generation=t,parent_expectation=parent_expectation,offspring_mean=mean(offspring_g),mendelian_mean=mean(offspring_g)-parent_expectation) history[[t+1L]] <-summarize_cohort(next_cohort,policy,t) pedigree <- mating$pedigree; current <- next_cohort; bed <- next_cohort animals <- children; sex <- plan$sex }list(history=do.call(rbind,history),transitions=do.call(rbind,transitions))}phenotype <-run_programme("Phenotype")random <-run_programme("Random")history <-rbind(phenotype$history,random$history)transitions <-rbind(phenotype$transitions,random$transitions)stopifnot(all(history$mean_HE>=0& history$mean_HE<=.5),all(history$mean_HO>=0& history$mean_HO<=1),all(history$polymorphic>=0& history$polymorphic<=6),all(history$gain[history$generation==0]==0))knitr::kable(history,digits=4,row.names=FALSE)
policy
generation
mean_genetic
gain
genetic_variance
mean_HE
mean_HO
polymorphic
Phenotype
0
0.0187
0.0000
0.0459
0.4935
0.5208
6
Phenotype
1
0.1688
0.1500
0.0266
0.4614
0.5625
6
Phenotype
2
0.2922
0.2734
0.0337
0.3799
0.4167
6
Phenotype
3
0.4078
0.3891
0.0289
0.2299
0.2448
5
Random
0
0.0187
0.0000
0.0459
0.4935
0.5208
6
Random
1
0.0547
0.0359
0.0197
0.4809
0.5052
6
Random
2
-0.0047
-0.0234
0.0267
0.4789
0.5260
6
Random
3
-0.0078
-0.0266
0.0226
0.4270
0.4740
6
gsim_simulate_cohort() reuses phased parents and writes only the new cohort. All used parents must be in that one phased dataset. The full pedigree is retained separately. Recombination redistributes existing alleles; it does not introduce new marker alleles here.
Figure 1: One three-generation realization for each policy, on the same founder base and six-marker reporting panel. These curves are illustrative outcomes, not estimated expected responses.
Question 2. Must phenotype selection increase genetic merit in every realized generation?
Suggested answer
No. Phenotype selection uses noisy records, and finite parent use and Mendelian sampling add variation. The genetic architecture is fixed but allele frequencies, genetic variance and linkage disequilibrium can change. One trajectory cannot establish the expected advantage or risk of a policy. Replicated simulations would be needed for that comparison.
5. Explain offspring deviations from parental expectations
For additive inheritance, each offspring’s conditional genetic expectation is the parental mean. The realized offspring value includes Mendelian sampling. Consequently, a finite cohort mean can differ from the parentage-weighted expectation even when inheritance is implemented correctly.
The difference column is a realized mean Mendelian-sampling deviation. It is not a prediction-error estimate or a test that the simulator is unbiased. The neutral selection policy can also show realized gain or loss through finite sampling.
6. Read gain and diversity together
Genetic variance is the sample variance of simulated additive values in each cohort. It can change through allele-frequency shifts and associations between linked markers. Mean marker \(H_E\) measures a different aspect of variation. One marker has zero trait effect but still contributes to the marker-diversity summary.
These six synthetic markers do not estimate genome-wide diversity, effective population size or pedigree inbreeding. Neither higher gain nor a family quota alone establishes a better programme. Programme comparisons also need declared constraints, generation intervals and costs. Generations here are not calendar years.
Exercises
Verify the founder mean from allele frequencies and fixed effects. Explain why this identity continues to hold after selection.
Recalculate founder values using founder sample allele frequencies as fixed centers. Show that the founder mean becomes zero, while gain relative to that founder mean is unchanged if those centers stay fixed.
Explain what changes if selection uses simulated genetic truth rather than phenotypes, and how that decision should be labelled.
With fixed effects, changing fixed centers adds the same constant to every individual’s value in every cohort, leaving differences from the founder mean unchanged. Selecting on true genetic values removes evaluation uncertainty from the decision and creates an oracle strategy. Pass oracle=TRUE to gsim_select() when deliberately supplying truth scores; it is not a feasible real-population evaluation.
Package connection and next topic
gsim supplies inheritance, persistent genetic values and observable records through its existing breeding building blocks. gsel owns programme policies and objectives; gpop owns population summaries and their assumptions. No package interfaces are added here.
Continue with Practical 9: Relationships, mating and inbreeding, then examine prediction targets and validation in Practical 10. An externally fitted genetic evaluation would be a further extension of this simulation. Keep simulated truth reserved for evaluation and retain the same reporting base.