diff --git a/NAMESPACE b/NAMESPACE index 07534a87..6b40eef6 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -140,6 +140,14 @@ exportClasses(TraitADG) exportClasses(TraitAE) exportClasses(TraitAEG) exportClasses(TraitAG) +exportMethods(makeCross) +exportMethods(makeCross2) +exportMethods(makeDH) +exportMethods(randCross) +exportMethods(randCross2) +exportMethods(selectCross) +exportMethods(self) +exportMethods(setPheno) import(Rcpp) importFrom(R6,R6Class) importFrom(Rdpack,reprompt) diff --git a/R/crossing.R b/R/crossing.R index 32495504..bc6bd14d 100644 --- a/R/crossing.R +++ b/R/crossing.R @@ -8,7 +8,7 @@ #' @param crossPlan a matrix with two column representing #' female and male parents. Either integers for the position in #' population or character strings for the IDs. -#' @param nProgeny number of progeny per cross. May be a single value for all +#' @param nProgeny number of progeny per cross. May be a single value for all #' crosses or a vector with values for each cross. #' @param simParam an object of class \code{\link{SimParam}}. If #' \code{NULL}, the function uses the object named \code{SP} from the @@ -40,22 +40,43 @@ #' pop3 = makeCross(pop, crossPlan, nProgeny=c(1,2),simParam=SP) #' getPed(pop3) #' @export -makeCross = function(pop, crossPlan, nProgeny=1, - simParam=NULL, nThreads=NULL){ +setGeneric( + "makeCross", + function(pop, crossPlan, nProgeny=1, simParam=NULL, nThreads=NULL){ + standardGeneric("makeCross") + } +) + +#' @describeIn makeCross Method for \code{\link{Pop-class}} +#' @export +setMethod( + "makeCross", + signature(pop = "Pop"), + function(pop, crossPlan, nProgeny=1, simParam=NULL, nThreads=NULL){ + .makeCross_internal( + pop=pop, crossPlan=crossPlan, nProgeny=nProgeny, simParam=simParam, + nThreads=nThreads) + } +) + +# Internal implementation shared by makeCross methods +#' @keywords internal +.makeCross_internal = function(pop,crossPlan,nProgeny=1, + simParam=NULL,nThreads=NULL){ if(is.null(simParam)){ simParam = get("SP",envir=.GlobalEnv) } - + if(is.null(nThreads)){ nThreads = simParam$nThreads }else{ nThreads = as.integer(nThreads) } - + if(pop@ploidy%%2L != 0L){ - stop("You can not cross indiviuals with odd ploidy levels") + stop("You can not cross individuals with odd ploidy levels") } - + if(is.character(crossPlan)){ #Match by ID crossPlan = cbind(match(crossPlan[,1], pop@id), match(crossPlan[,2], pop@id)) @@ -63,12 +84,12 @@ makeCross = function(pop, crossPlan, nProgeny=1, stop("Failed to match supplied IDs") } } - + if((max(crossPlan)>nInd(pop)) | (min(crossPlan)<1L)){ stop("Invalid crossPlan") } - + # Handle nProgeny if(length(nProgeny)==1){ if(nProgeny>1){ @@ -77,11 +98,11 @@ makeCross = function(pop, crossPlan, nProgeny=1, } }else{ stopifnot("Length of nProgeny must equal 1 or nrow(crossPlan)" = nrow(crossPlan)==length(nProgeny)) - + crossPlan = cbind(rep(crossPlan[,1], times=nProgeny), rep(crossPlan[,2], times=nProgeny)) } - + tmp = cross(pop@geno, crossPlan[,1], pop@geno, @@ -97,22 +118,22 @@ makeCross = function(pop, crossPlan, nProgeny=1, simParam$maleCentromere, simParam$quadProb, nThreads) - + dim(tmp$geno) = NULL # Account for matrix bug in RcppArmadillo - + rPop = new("RawPop", nInd=nrow(crossPlan), nChr=pop@nChr, ploidy=pop@ploidy, nLoci=pop@nLoci, geno=tmp$geno) - + if(simParam$isTrackRec){ hist = tmp$recHist }else{ hist = NULL } - + return(.newPop(rawPop=rPop, mother=pop@id[crossPlan[,1]], father=pop@id[crossPlan[,2]], @@ -129,12 +150,12 @@ makeCross = function(pop, crossPlan, nProgeny=1, #' #' @description #' A wrapper for \code{\link{makeCross}} that randomly -#' selects parental combinations for all possible combinantions. +#' selects parental combinations for all possible combinations. #' #' @param pop an object of \code{\link{Pop-class}} #' @param nCrosses total number of crosses to make -#' @param nProgeny number of progeny per cross. May be a single value for all -#' crosses or a vector with values equal to the number of crosses. If providing +#' @param nProgeny number of progeny per cross. May be a single value for all +#' crosses or a vector with values equal to the number of crosses. If providing #' a vector, the values are randomly assigned to each cross. #' @param balance if using sexes, this option will balance the number #' of progeny per parent @@ -163,37 +184,63 @@ makeCross = function(pop, crossPlan, nProgeny=1, #' pop2 = randCross(pop, 10, simParam=SP) #' #' @export -randCross = function(pop, nCrosses, nProgeny=1, - balance=TRUE, parents=NULL, +setGeneric( + "randCross", + function( + pop, nCrosses, nProgeny=1, balance=TRUE, parents=NULL, ignoreSexes=FALSE, + simParam=NULL, nThreads=NULL){ + standardGeneric("randCross") + } +) + +#' @describeIn randCross Method for \code{\link{Pop-class}} +#' @export +setMethod( + "randCross", + signature(pop = "Pop"), + function( + pop, nCrosses, nProgeny=1, balance=TRUE, parents=NULL, ignoreSexes=FALSE, + simParam=NULL, nThreads=NULL){ + .randCross_internal( + pop=pop, nCrosses=nCrosses, nProgeny=nProgeny, balance=balance, + parents=parents, ignoreSexes=ignoreSexes, simParam=simParam, + nThreads=nThreads) + } +) + +# Internal implementation shared by randCross methods +#' @keywords internal +.randCross_internal = function(pop,nCrosses,nProgeny=1, + balance=TRUE,parents=NULL, ignoreSexes=FALSE, simParam=NULL, nThreads=NULL){ if(is.null(simParam)){ simParam = get("SP",envir=.GlobalEnv) } - + if(is.null(nThreads)){ nThreads = simParam$nThreads }else{ nThreads = as.integer(nThreads) } - + if(is.null(parents)){ parents = 1:pop@nInd }else{ parents = as.integer(parents) } - + n = length(parents) if(n<=1){ stop("The population must contain more than 1 individual") } - + # Handle nProgeny if(length(nProgeny)>1){ stopifnot("Length of nProgeny must equal 1 or nCrosses" = nCrosses==length(nProgeny)) nProgeny = nProgeny[sample(nCrosses, nCrosses)] } - + if(simParam$sexes=="no" | ignoreSexes){ crossPlan = sampHalfDialComb(n, nCrosses) crossPlan[,1] = parents[crossPlan[,1]] @@ -229,7 +276,7 @@ randCross = function(pop, nCrosses, nProgeny=1, crossPlan[,2] = male[crossPlan[,2]] } } - + return(makeCross(pop=pop, crossPlan=crossPlan, nProgeny=nProgeny, simParam=simParam, nThreads=nThreads)) } @@ -294,9 +341,36 @@ randCross = function(pop, nCrosses, nProgeny=1, #' pop2 = selectCross(pop, nInd=4, nCrosses=8, simParam=SP) #' #' @export -selectCross = function(pop, nInd=NULL, nFemale=NULL, nMale=NULL, nCrosses, - nProgeny=1, trait=1, use="pheno", selectTop=TRUE, - simParam=NULL, nThreads=NULL, ..., balance=TRUE){ +setGeneric( + "selectCross", + function( + pop, nInd=NULL, nFemale=NULL, nMale=NULL, nCrosses, nProgeny=1, trait=1, + use="pheno", selectTop=TRUE, simParam=NULL, nThreads=NULL, ..., balance=TRUE){ + standardGeneric("selectCross") + } +) + + +#' @describeIn selectCross Method for \code{\link{Pop-class}} +#' @export +setMethod( + "selectCross", + signature(pop = "Pop"), + function( + pop, nInd=NULL, nFemale=NULL, nMale=NULL, nCrosses, nProgeny=1, trait=1, + use="pheno", selectTop=T, simParam=NULL, nThreads=NULL, ..., balance=TRUE){ + .selectCross_internal( + pop=pop, nInd=nInd, nFemale=nFemale, nMale=nMale, nCrosses=nCrosses, + nProgeny=nProgeny, trait=trait, use=use, selectTop=selectTop, + simParam=simParam, nThreads=nThreads, ..., balance=balance) + } +) + +# Internal implementation shared by selectCross methods +#' @keywords internal +.selectCross_internal = function(pop,nInd=NULL,nFemale=NULL,nMale=NULL,nCrosses, + nProgeny=1,trait=1,use="pheno",selectTop=TRUE, + simParam=NULL,nThreads=NULL,...,balance=TRUE){ if(is.null(simParam)){ simParam = get("SP",envir=.GlobalEnv) } @@ -327,7 +401,7 @@ selectCross = function(pop, nInd=NULL, nFemale=NULL, nMale=NULL, nCrosses, nThreads=nThreads, ...) parents = c(females,males) } - + return(randCross(pop=pop, nCrosses=nCrosses, nProgeny=nProgeny, balance=balance, parents=parents, ignoreSexes=FALSE, simParam=simParam, @@ -345,7 +419,7 @@ selectCross = function(pop, nInd=NULL, nFemale=NULL, nMale=NULL, nCrosses, #' @param crossPlan a matrix with two column representing #' female and male parents. Either integers for the position in #' population or character strings for the IDs. -#' @param nProgeny number of progeny per cross. May be a single value for all +#' @param nProgeny number of progeny per cross. May be a single value for all #' crosses or a vector with values for each cross. #' @param simParam an object of class \code{\link{SimParam}}. If #' \code{NULL}, the function uses the object named \code{SP} from the @@ -377,23 +451,44 @@ selectCross = function(pop, nInd=NULL, nFemale=NULL, nMale=NULL, nCrosses, #' pop3 = makeCross2(pop, pop, crossPlan, nProgeny=c(1,2),simParam=SP) #' getPed(pop3) #' @export -makeCross2 = function(females, males, crossPlan, nProgeny=1, simParam=NULL, +setGeneric( + "makeCross2", + function(females,males,crossPlan,nProgeny=1,simParam=NULL, nThreads=NULL){ + standardGeneric("makeCross2") + } +) + +#' @describeIn makeCross2 Method for \code{\link{Pop-class}} +#' @export +setMethod( + "makeCross2", + signature(females = "Pop", males = "Pop"), + function(females,males,crossPlan,nProgeny=1,simParam=NULL, nThreads=NULL){ + .makeCross2_internal( + females=females, males=males, crossPlan=crossPlan, nProgeny=nProgeny, + simParam=simParam, nThreads=nThreads) + } +) + +# Internal implementation shared by makeCross2 methods +#' @keywords internal +.makeCross2_internal = function(females,males,crossPlan,nProgeny=1,simParam=NULL, nThreads=NULL){ if(is.null(simParam)){ simParam = get("SP",envir=.GlobalEnv) } - + if(is.null(nThreads)){ nThreads = simParam$nThreads }else{ nThreads = as.integer(nThreads) } - + if((females@ploidy%%2L != 0L) | (males@ploidy%%2L != 0L)){ - stop("You can not cross indiviuals with odd ploidy levels") + stop("You can not cross individuals with odd ploidy levels") } - + if(is.character(crossPlan)){ #Match by ID crossPlan = cbind(match(crossPlan[,1],females@id), match(crossPlan[,2],males@id)) @@ -401,13 +496,13 @@ makeCross2 = function(females, males, crossPlan, nProgeny=1, simParam=NULL, stop("Failed to match supplied IDs") } } - + if((max(crossPlan[,1])>nInd(females)) | (max(crossPlan[,2])>nInd(males)) | (min(crossPlan)<1L)){ stop("Invalid crossPlan") } - + # Handle nProgeny if(length(nProgeny)==1){ if(nProgeny>1){ @@ -416,11 +511,11 @@ makeCross2 = function(females, males, crossPlan, nProgeny=1, simParam=NULL, } }else{ stopifnot("Length of nProgeny must equal 1 or nrow(crossPlan)" = nrow(crossPlan)==length(nProgeny)) - + crossPlan = cbind(rep(crossPlan[,1], times=nProgeny), rep(crossPlan[,2], times=nProgeny)) } - + tmp=cross(females@geno, crossPlan[,1], males@geno, @@ -436,22 +531,22 @@ makeCross2 = function(females, males, crossPlan, nProgeny=1, simParam=NULL, simParam$maleCentromere, simParam$quadProb, nThreads) - + dim(tmp$geno) = NULL # Account for matrix bug in RcppArmadillo - + rPop = new("RawPop", nInd=nrow(crossPlan), nChr=females@nChr, ploidy=as.integer((females@ploidy+males@ploidy)/2), nLoci=females@nLoci, geno=tmp$geno) - + if(simParam$isTrackRec){ hist = tmp$recHist }else{ hist = NULL } - + return(.newPop(rawPop=rPop, mother=females@id[crossPlan[,1]], father=males@id[crossPlan[,2]], @@ -468,14 +563,14 @@ makeCross2 = function(females, males, crossPlan, nProgeny=1, simParam=NULL, #' #' @description #' A wrapper for \code{\link{makeCross2}} that randomly -#' selects parental combinations for all possible combinantions between +#' selects parental combinations for all possible combinations between #' two populations. #' #' @param females an object of \code{\link{Pop-class}} for female parents. #' @param males an object of \code{\link{Pop-class}} for male parents. #' @param nCrosses total number of crosses to make -#' @param nProgeny number of progeny per cross. May be a single value for all -#' crosses or a vector with values equal to the number of crosses. If providing +#' @param nProgeny number of progeny per cross. May be a single value for all +#' crosses or a vector with values equal to the number of crosses. If providing #' a vector, the values are randomly assigned to each cross. #' @param balance this option will balance the number #' of progeny per parent @@ -507,33 +602,60 @@ makeCross2 = function(females, males, crossPlan, nProgeny=1, simParam=NULL, #' pop2 = randCross2(pop, pop, 10, simParam=SP) #' #' @export -randCross2 = function(females, males, nCrosses, nProgeny=1, - balance=TRUE, femaleParents=NULL, - maleParents=NULL, ignoreSexes=FALSE, - simParam=NULL, nThreads=NULL){ +setGeneric( + "randCross2", + function( + females, males, nCrosses, nProgeny=1, balance=TRUE, femaleParents=NULL, + maleParents=NULL, ignoreSexes=FALSE, simParam=NULL, nThreads=NULL){ + standardGeneric("randCross2") + } +) + +#' @describeIn randCross2 Method for \code{\link{Pop-class}} +#' @export +setMethod( + "randCross2", + signature(females = "Pop", males = "Pop"), + function( + females, males, nCrosses, nProgeny=1, balance=TRUE, femaleParents=NULL, + maleParents=NULL, ignoreSexes=FALSE, simParam=NULL, nThreads=NULL){ + .randCross2_internal( + females = females, males = males, nCrosses = nCrosses, + nProgeny = nProgeny, balance = balance, femaleParents = femaleParents, + maleParents = maleParents, ignoreSexes = ignoreSexes, + simParam = simParam, nThreads = nThreads) + } +) + +# Internal implementation shared by randCross2 methods +#' @keywords internal +.randCross2_internal = function( + females, males, nCrosses, nProgeny=1, balance=TRUE, femaleParents=NULL, + maleParents=NULL, ignoreSexes=FALSE, simParam=NULL, nThreads=NULL){ + if(is.null(simParam)){ simParam = get("SP",envir=.GlobalEnv) } - + if(is.null(nThreads)){ nThreads = simParam$nThreads }else{ nThreads = as.integer(nThreads) } - + #Set allowable parents if(is.null(femaleParents)){ femaleParents = 1:females@nInd }else{ femaleParents = as.integer(femaleParents) } - + if(is.null(maleParents)){ maleParents = 1:males@nInd }else{ maleParents = as.integer(maleParents) } - + if(simParam$sexes=="no" | ignoreSexes){ female = femaleParents male = maleParents @@ -549,16 +671,16 @@ randCross2 = function(females, males, nCrosses, nProgeny=1, stop("population doesn't contain any males") } } - + # Handle nProgeny if(length(nProgeny)>1){ stopifnot("Length of nProgeny must equal 1 or nCrosses" = nCrosses==length(nProgeny)) nProgeny = nProgeny[sample(nCrosses, nCrosses)] } - + nMale = length(male) nFemale = length(female) - + if(balance){ female = female[sample.int(nFemale, nFemale)] female = rep(female, length.out=nCrosses) @@ -578,7 +700,7 @@ randCross2 = function(females, males, nCrosses, nProgeny=1, crossPlan[,1] = female[crossPlan[,1]] crossPlan[,2] = male[crossPlan[,2]] } - + return(makeCross2(females=females, males=males, crossPlan=crossPlan, nProgeny=nProgeny, simParam=simParam, nThreads=nThreads)) @@ -591,7 +713,7 @@ randCross2 = function(females, males, nCrosses, nProgeny=1, #' population. Only works when sexes is "no". #' #' @param pop an object of \code{\link{Pop-class}} -#' @param nProgeny number of selfed progeny per individual. May be a single value +#' @param nProgeny number of selfed progeny per individual. May be a single value #' for all or a vector providing values for each individual. #' @param parents an optional vector of indices for allowable parents #' @param keepParents should previous parents be used for mother and @@ -619,19 +741,44 @@ randCross2 = function(females, males, nCrosses, nProgeny=1, #' pop2 = self(pop, simParam=SP) #' #' @export -self = function(pop, nProgeny=1, parents=NULL, keepParents=TRUE, - simParam=NULL, nThreads=NULL){ - +setGeneric( + "self", + function( + pop, nProgeny=1, parents=NULL, keepParents=TRUE, simParam=NULL, + nThreads=NULL){ + standardGeneric("self") + } +) + +#' @describeIn self Method for \code{\link{Pop-class}} +#' @export +setMethod( + "self", + signature(pop = "Pop"), + function( + pop, nProgeny=1, parents=NULL, keepParents=TRUE, simParam=NULL, + nThreads=NULL){ + .self_internal( + pop=pop, nProgeny=nProgeny, parents=parents, keepParents=keepParents, + simParam=simParam, nThreads = nThreads + ) + } +) + +# Internal implementation shared by self methods +#' @keywords internal +.self_internal = function( + pop,nProgeny=1,parents=NULL,keepParents=TRUE,simParam=NULL,nThreads=NULL){ if(is.null(simParam)){ simParam = get("SP",envir=.GlobalEnv) } - + if(is.null(nThreads)){ nThreads = simParam$nThreads }else{ nThreads = as.integer(nThreads) } - + if(is(pop,"MultiPop")){ stopifnot(is.null(parents)) pop@pops = lapply(pop@pops, self, nProgeny=nProgeny, @@ -639,29 +786,29 @@ self = function(pop, nProgeny=1, parents=NULL, keepParents=TRUE, simParam=simParam, nThreads=nThreads) return(pop) } - + if(is.null(parents)){ parents = 1:pop@nInd }else{ parents = as.integer(parents) } - + if(pop@ploidy%%2L != 0L){ stop("You can not self aneuploids") } - + # Handle nProgeny if(length(nProgeny)==1){ crossPlan = rep(parents, each=nProgeny) - + }else{ stopifnot("Length of nProgeny must equal 1 or nInd(pop)" = nInd(pop)==length(nProgeny)) - + crossPlan = rep(parents, times=nProgeny) } - + crossPlan = cbind(crossPlan,crossPlan) - + tmp = cross(pop@geno, crossPlan[,1], pop@geno, @@ -677,22 +824,22 @@ self = function(pop, nProgeny=1, parents=NULL, keepParents=TRUE, simParam$maleCentromere, simParam$quadProb, nThreads) - + dim(tmp$geno) = NULL # Account for matrix bug in RcppArmadillo - + rPop = new("RawPop", nInd=nrow(crossPlan), nChr=pop@nChr, ploidy=pop@ploidy, nLoci=pop@nLoci, geno=tmp$geno) - + if(simParam$isTrackRec){ hist = tmp$recHist }else{ hist = NULL } - + if(keepParents){ return(.newPop(rawPop=rPop, mother=pop@mother[crossPlan[,1]], @@ -752,29 +899,52 @@ self = function(pop, nProgeny=1, parents=NULL, keepParents=TRUE, #' pop2 = makeDH(pop, simParam=SP) #' #' @export -makeDH = function(pop, nDH=1, useFemale=TRUE, keepParents=TRUE, - simParam=NULL, nThreads=NULL){ +setGeneric( + "makeDH", + function( + pop,nDH=1,useFemale=TRUE,keepParents=TRUE,simParam=NULL,nThreads=NULL){ + standardGeneric("makeDH") + } +) + +#' @describeIn makeDH Method for \code{\link{Pop-class}} +#' @export +setMethod( + "makeDH", + signature(pop = "Pop"), + function( + pop,nDH=1,useFemale=TRUE,keepParents=TRUE,simParam=NULL,nThreads=NULL){ + .makeDH_internal( + pop=pop, nDH=nDH, useFemale=useFemale, keepParents=keepParents, + simParam=simParam, nThreads=nThreads) + } +) + +# Internal implementation shared by .makeDH_internal methods +#' @keywords internal +.makeDH_internal = function( + pop,nDH=1,useFemale=TRUE,keepParents=TRUE,simParam=NULL,nThreads=NULL){ if(is.null(simParam)){ simParam = get("SP",envir=.GlobalEnv) } - + if(is.null(nThreads)){ nThreads = simParam$nThreads }else{ nThreads = as.integer(nThreads) } - + if(is(pop,"MultiPop")){ pop@pops = lapply(pop@pops, makeDH, nDH=nDH, useFemale=useFemale, keepParents=keepParents, simParam=simParam, nThreads=nThreads) return(pop) } - + if(pop@ploidy!=2){ stop("Only works with diploids") } - + if(useFemale){ tmp = createDH2(pop@geno, nDH, simParam$femaleMap, @@ -790,22 +960,22 @@ makeDH = function(pop, nDH=1, useFemale=TRUE, keepParents=TRUE, simParam$isTrackRec, nThreads) } - + dim(tmp$geno) = NULL # Account for matrix bug in RcppArmadillo - + rPop = new("RawPop", nInd=as.integer(pop@nInd*nDH), nChr=pop@nChr, ploidy=pop@ploidy, nLoci=pop@nLoci, geno=tmp$geno) - + if(simParam$isTrackRec){ hist = tmp$recHist }else{ hist = NULL } - + if(keepParents){ return(.newPop(rawPop=rPop, mother=rep(pop@mother, each=nDH), @@ -848,9 +1018,9 @@ sortPed = function(id, mother, father, maxCycle=100){ father=match(father, id), motherID=as.character(mother), fatherID=as.character(father)) - + unsorted = rep(TRUE, nInd) - + for(gen in seq_len(maxCycle)){ for(i in which(unsorted)){ if(is.na(output$mother[i])&is.na(output$father[i])){ @@ -878,11 +1048,11 @@ sortPed = function(id, mother, father, maxCycle=100){ } } } - + if(any(unsorted)){ - stop("Failed to sort pedigree, may contain loops or require a higher maxGen") + stop("Failed to sort pedigree, may contain loops or require a higher maxCycle") } - + return(output) } @@ -894,7 +1064,7 @@ sortPed = function(id, mother, father, maxCycle=100){ #' #' @param founderPop a \code{\link{Pop-class}} #' @param id a vector of unique identifiers for individuals -#' in the pedigree. The values of these IDs are seperate from +#' in the pedigree. The values of these IDs are separate from #' the IDs in the founderPop if matchID=FALSE. #' @param mother a vector of identifiers for the mothers #' of individuals in the pedigree. Must match one of the @@ -949,17 +1119,17 @@ pedigreeCross = function(founderPop, id, mother, father, matchID=FALSE, if(is.null(simParam)){ simParam = get("SP",envir=.GlobalEnv) } - + if(is.null(nThreads)){ nThreads = simParam$nThreads }else{ nThreads = as.integer(nThreads) } - + if(simParam$sexes!="no"){ stop("pedigreeCross currently only works with sex='no'") } - + # Coerce input data id = as.character(id) mother = as.character(mother) @@ -972,21 +1142,21 @@ pedigreeCross = function(founderPop, id, mother, father, matchID=FALSE, if(is.null(nSelf)){ nSelf = rep(0, length(id)) } - + # Check input data stopifnot(!any(duplicated(id)), length(id)==length(mother), length(id)==length(father), length(id)==length(DH), length(id)==length(nSelf)) - + # Sort pedigree (identifies potential problems) ped = sortPed(id=id, mother=mother, father=father, maxCycle=maxCycle) - + # Create list for new population output = vector("list", length=length(id)) - + # Order and assign founders isFounder = is.na(ped$father) & is.na(ped$mother) motherIsFounder = is.na(ped$mother) & !is.na(ped$father) @@ -1006,17 +1176,17 @@ pedigreeCross = function(founderPop, id, mother, father, matchID=FALSE, if(nFounder>founderPop@nInd){ stop(paste("Pedigree requires",nFounder,"founders, but only",founderPop@nInd,"were supplied")) } - + # Randomly assign individuals as founders founderPop = founderPop[sample.int(founderPop@nInd,nFounder)] - + # isFounder n1 = 1 n2 = sum(isFounder) founderPop@id[n1:n2] = id[isFounder] founderPop@mother[n1:n2] = mother[isFounder] founderPop@father[n1:n2] = father[isFounder] - + # motherIsFounder n = sum(motherIsFounder) if(n>=1){ @@ -1026,7 +1196,7 @@ pedigreeCross = function(founderPop, id, mother, father, matchID=FALSE, founderPop@mother[n1:n2] = rep("0", n2-n1+1) founderPop@father[n1:n2] = rep("0", n2-n1+1) } - + # fatherIsFounder n = sum(fatherIsFounder) if(n>=1){ @@ -1037,7 +1207,7 @@ pedigreeCross = function(founderPop, id, mother, father, matchID=FALSE, founderPop@father[n1:n2] = rep("0", n2-n1+1) } } - + # Create individuals crossPlan = matrix(c(1,1),ncol=2) for(gen in seq_len(max(ped$gen))){ @@ -1069,14 +1239,14 @@ pedigreeCross = function(founderPop, id, mother, father, matchID=FALSE, nThreads=nThreads) } } - + # Self? for(j in seq_len(nSelf[i])){ output[[i]] = self(output[[i]], simParam=simParam, nThreads=nThreads) } - + # Make the individual a DH? if(DH[i]){ output[[i]] = makeDH(output[[i]], @@ -1086,14 +1256,14 @@ pedigreeCross = function(founderPop, id, mother, father, matchID=FALSE, } } } - + # Collapse list to a population output = mergePops(output) - + # Copy over names output@id = id output@mother = mother output@father = father - + return(output) } diff --git a/R/phenotypes.R b/R/phenotypes.R index 7af178ff..6d95f8aa 100644 --- a/R/phenotypes.R +++ b/R/phenotypes.R @@ -157,9 +157,50 @@ calcPheno = function(pop, varE, reps, p, traits, simParam=NULL){ #' pop = setPheno(pop, varE=1) #' #' @export -setPheno = function(pop, h2=NULL, H2=NULL, varE=NULL, corE=NULL, - reps=1, fixEff=1L, p=NULL, onlyPheno=FALSE, - traits=NULL, simParam=NULL, ...){ +setGeneric( + "setPheno", + function( + pop, h2=NULL, H2=NULL, varE=NULL, corE=NULL, reps=1, fixEff=1L, p=NULL, + onlyPheno=FALSE, traits=NULL, simParam=NULL){ + standardGeneric("setPheno") + } +) + +#' @describeIn setPheno Method for \code{\link{Pop-class}} +#' @export +setMethod( + "setPheno", + signature(pop = "Pop"), + function( + pop, h2=NULL, H2=NULL, varE=NULL, corE=NULL, reps=1, fixEff=1L, p=NULL, + onlyPheno=FALSE, traits=NULL, simParam=NULL) { + .setPheno_internal( + pop=pop, h2=h2, H2=H2, varE=varE, corE=corE, reps=reps, fixEff=fixEff, + p=p, onlyPheno=onlyPheno, traits=traits, simParam=simParam + ) + } +) + +#' @describeIn setPheno Method for \code{\link{MultiPop-class}} objects +#' @export +setMethod( + "setPheno", + signature(pop = "MultiPop"), + function( + pop, h2=NULL, H2=NULL, varE=NULL, corE=NULL, reps=1, fixEff=1L, p=NULL, + onlyPheno=FALSE, traits=NULL, simParam=NULL) { + .setPheno_internal( + pop=pop, h2=h2, H2=H2, varE=varE, corE=corE, reps=reps, fixEff=fixEff, + p=p, onlyPheno=onlyPheno, traits=traits,simParam=simParam + ) + } +) + +# Internal implementation shared by all setPheno methods. +# @keywords internal +.setPheno_internal = function( + pop, h2=NULL, H2=NULL, varE=NULL, corE=NULL, reps=1, fixEff=1L, p=NULL, + onlyPheno=FALSE, traits=NULL, simParam=NULL) { if(is.null(simParam)){ simParam = get("SP",envir=.GlobalEnv) } @@ -339,9 +380,9 @@ setPheno = function(pop, h2=NULL, H2=NULL, varE=NULL, corE=NULL, #' SP$setVarE(varE = trtVarELog) #' pop = newPop(founderPop) #' popLarge = randCross(pop, nCrosses = 1000) -#' +#' #' meanVarFun = function(x) list(mean = mean(x), var = var(x)) -#' +#' #' #Latent phenotypes and parameters #' (phenoLog = pheno(pop)) #' phenoLogLarge = pheno(popLarge) @@ -364,7 +405,7 @@ setPheno = function(pop, h2=NULL, H2=NULL, varE=NULL, corE=NULL, #' cbind(phenoLog = phenoLog[, 1], #' phenoExpMeanLog0 = phenoExpMeanLog0, #' phenoExpMeanExp1 = phenoExpMeanExp1) -#' +#' #' tmp = cbind(phenoLog = phenoLogLarge[, 1], #' phenoExpMeanLog0 = c(asLogNormal(phenoLogLarge[, 1])), #' phenoExpMeanExp1 = c(asLogNormal(phenoLogLarge[, 1], meanLogShift = -trtVarPLog[1]/2))) @@ -377,16 +418,16 @@ setPheno = function(pop, h2=NULL, H2=NULL, varE=NULL, corE=NULL, #' abline(v= tmp2$phenoExpMeanExp1$mean, col = "red") #' #' #Convert multiple input traits -#' asLogNormal(pheno(pop)) -#' try(asLogNormal(pheno(pop), meanLogShift = 0)) -#' asLogNormal(pheno(pop), meanLogShift = c(0, 1)) -#' asLogNormal(pheno(pop), meanLogShift = list(0, NULL)) -#' +#' asLogNormal(x = pheno(pop)) +#' try(asLogNormal(x = pheno(pop), meanlog = 0)) +#' asLogNormal(x = pheno(pop), meanlog = c(0, 1)) +#' asLogNormal(x = pheno(pop), meanlog = list(0, NULL)) +#' #' #Store the recoded trait manually #' pheno(pop) #' pop@pheno[, 1] = asLogNormal(pheno(pop)[, 1]) #' pheno(pop) -#' +#' #' #Apply and store the transformation automatically via SimParam$finalizePop() #' finalizePopDefault = SP$finalizePop #' SP$finalizePop = function(pop, simParam = SP, ...) { @@ -395,7 +436,7 @@ setPheno = function(pop, h2=NULL, H2=NULL, varE=NULL, corE=NULL, #' } #' pop = newPop(founderPop) #' pheno(pop) -#' +#' #' #Apply and store the transformation automatically via SimParam$finalizePheno() #' SP$finalizePop = finalizePopDefault #' SP$finalizePheno = function(pheno, pop, simParam = SP, ...) { @@ -533,12 +574,12 @@ asLogNormal <- function(x, meanLogShift = NULL) { #' p = list(c(0.5, 0.5), #' p), #' mean = trtMean, var = trtVarP) -#' +#' #' #Store the recoded trait manually #' pheno(pop) #' pop@pheno[, 1] = asCategorical(pheno(pop)[, 1]) #' pheno(pop) -#' +#' #' #Apply and store the transformation automatically via SimParam$finalizePop() #' finalizePopDefault = SP$finalizePop #' SP$finalizePop = function(pop, simParam = SP, ...) { @@ -547,7 +588,7 @@ asLogNormal <- function(x, meanLogShift = NULL) { #' } #' pop = newPop(founderPop) #' pheno(pop) -#' +#' #' #Apply and store the transformation automatically via SimParam$finalizePheno() #' SP$finalizePop = finalizePopDefault #' SP$finalizePheno = function(pheno, pop, simParam = SP, ...) { @@ -633,7 +674,7 @@ asCategorical = function(x, p = NULL, mean = 0, var = 1, #' @details If input trait is normal (Gaussian) then this function generates a #' count trait by sampling from the Poisson generalised linear model. #' As such, this function's output is stochastic. -#' +#' #' Specifically, it generates \code{y | x ~ Poisson(lambda)} with #' \code{lambda = exp(meanLogShift + x)}. If the supplied latent values #' \code{x} have mean \code{mu} and variance \code{sigma2}, then the @@ -648,7 +689,7 @@ asCategorical = function(x, p = NULL, mean = 0, var = 1, #' mean and to induce overdispersion, but it does not fully determine #' the observed variance. If \code{x} already contains an added Gaussian #' residual term, that latent variance contributes to the overdispersion as well. -#' +#' #' The name \code{meanLogShift} is used to emphasize that this argument #' is an additional shift applied during transformation, not the primary #' way to set the latent trait mean. In normal AlphaSimR workflow, the @@ -730,7 +771,7 @@ asCategorical = function(x, p = NULL, mean = 0, var = 1, #' pheno(pop) #' pop@pheno[, 1] = asPoisson(pheno(pop)[, 1]) #' pheno(pop) -#' +#' #' #Apply and store the transformation automatically via SimParam$finalizePop() #' finalizePopDefault = SP$finalizePop #' SP$finalizePop = function(pop, simParam = SP, ...) { @@ -739,7 +780,7 @@ asCategorical = function(x, p = NULL, mean = 0, var = 1, #' } #' pop = newPop(founderPop) #' pheno(pop) -#' +#' #' #Apply and store the transformation automatically via SimParam$finalizePheno() #' SP$finalizePop = finalizePopDefault #' SP$finalizePheno = function(pheno, pop, simParam = SP, ...) { diff --git a/man/asLogNormal.Rd b/man/asLogNormal.Rd index f6eb0e09..05df6eba 100644 --- a/man/asLogNormal.Rd +++ b/man/asLogNormal.Rd @@ -103,10 +103,10 @@ hist(tmp[, "phenoExpMeanExp1"], main = paste0("Mean: ", v=tmp2$phenoExpMeanExp1$ abline(v= tmp2$phenoExpMeanExp1$mean, col = "red") #Convert multiple input traits -asLogNormal(pheno(pop)) -try(asLogNormal(pheno(pop), meanLogShift = 0)) -asLogNormal(pheno(pop), meanLogShift = c(0, 1)) -asLogNormal(pheno(pop), meanLogShift = list(0, NULL)) +asLogNormal(x = pheno(pop)) +try(asLogNormal(x = pheno(pop), meanlog = 0)) +asLogNormal(x = pheno(pop), meanlog = c(0, 1)) +asLogNormal(x = pheno(pop), meanlog = list(0, NULL)) #Store the recoded trait manually pheno(pop) diff --git a/man/makeCross.Rd b/man/makeCross.Rd index c02cb1f3..a6dbcb32 100644 --- a/man/makeCross.Rd +++ b/man/makeCross.Rd @@ -2,9 +2,12 @@ % Please edit documentation in R/crossing.R \name{makeCross} \alias{makeCross} +\alias{makeCross,Pop-method} \title{Make designed crosses} \usage{ makeCross(pop, crossPlan, nProgeny = 1, simParam = NULL, nThreads = NULL) + +\S4method{makeCross}{Pop}(pop, crossPlan, nProgeny = 1, simParam = NULL, nThreads = NULL) } \arguments{ \item{pop}{an object of \code{\link{Pop-class}}} @@ -13,7 +16,7 @@ makeCross(pop, crossPlan, nProgeny = 1, simParam = NULL, nThreads = NULL) female and male parents. Either integers for the position in population or character strings for the IDs.} -\item{nProgeny}{number of progeny per cross. May be a single value for all +\item{nProgeny}{number of progeny per cross. May be a single value for all crosses or a vector with values for each cross.} \item{simParam}{an object of class \code{\link{SimParam}}. If @@ -30,6 +33,11 @@ Returns an object of \code{\link{Pop-class}} Makes crosses within a population using a user supplied crossing plan. } +\section{Functions}{ +\itemize{ +\item \code{makeCross(Pop)}: Method for \code{\link{Pop-class}} + +}} \examples{ #Create founder haplotypes founderPop = quickHaplo(nInd=10, nChr=1, segSites=10) diff --git a/man/makeCross2.Rd b/man/makeCross2.Rd index 785adb8f..0f6fec13 100644 --- a/man/makeCross2.Rd +++ b/man/makeCross2.Rd @@ -2,6 +2,7 @@ % Please edit documentation in R/crossing.R \name{makeCross2} \alias{makeCross2} +\alias{makeCross2,Pop,Pop-method} \title{Make designed crosses} \usage{ makeCross2( @@ -12,6 +13,15 @@ makeCross2( simParam = NULL, nThreads = NULL ) + +\S4method{makeCross2}{Pop,Pop}( + females, + males, + crossPlan, + nProgeny = 1, + simParam = NULL, + nThreads = NULL +) } \arguments{ \item{females}{an object of \code{\link{Pop-class}} for female parents.} @@ -22,7 +32,7 @@ makeCross2( female and male parents. Either integers for the position in population or character strings for the IDs.} -\item{nProgeny}{number of progeny per cross. May be a single value for all +\item{nProgeny}{number of progeny per cross. May be a single value for all crosses or a vector with values for each cross.} \item{simParam}{an object of class \code{\link{SimParam}}. If @@ -39,6 +49,11 @@ Returns an object of \code{\link{Pop-class}} Makes crosses between two populations using a user supplied crossing plan. } +\section{Functions}{ +\itemize{ +\item \code{makeCross2(females = Pop, males = Pop)}: Method for \code{\link{Pop-class}} + +}} \examples{ #Create founder haplotypes founderPop = quickHaplo(nInd=10, nChr=1, segSites=10) diff --git a/man/makeDH.Rd b/man/makeDH.Rd index 4413f81c..3407f85a 100644 --- a/man/makeDH.Rd +++ b/man/makeDH.Rd @@ -2,6 +2,7 @@ % Please edit documentation in R/crossing.R \name{makeDH} \alias{makeDH} +\alias{makeDH,Pop-method} \title{Generates DH lines} \usage{ makeDH( @@ -12,6 +13,15 @@ makeDH( simParam = NULL, nThreads = NULL ) + +\S4method{makeDH}{Pop}( + pop, + nDH = 1, + useFemale = TRUE, + keepParents = TRUE, + simParam = NULL, + nThreads = NULL +) } \arguments{ \item{pop}{an object of 'Pop' superclass} @@ -38,6 +48,11 @@ Creates DH lines from each individual in a population. Only works with diploid individuals. For polyploids, use \code{\link{reduceGenome}} and \code{\link{doubleGenome}}. } +\section{Functions}{ +\itemize{ +\item \code{makeDH(Pop)}: Method for \code{\link{Pop-class}} + +}} \examples{ #Create founder haplotypes founderPop = quickHaplo(nInd=2, nChr=1, segSites=10) diff --git a/man/pedigreeCross.Rd b/man/pedigreeCross.Rd index 48ecaee5..6244f0b9 100644 --- a/man/pedigreeCross.Rd +++ b/man/pedigreeCross.Rd @@ -22,7 +22,7 @@ pedigreeCross( \item{founderPop}{a \code{\link{Pop-class}}} \item{id}{a vector of unique identifiers for individuals -in the pedigree. The values of these IDs are seperate from +in the pedigree. The values of these IDs are separate from the IDs in the founderPop if matchID=FALSE.} \item{mother}{a vector of identifiers for the mothers diff --git a/man/randCross.Rd b/man/randCross.Rd index e5e4e290..c5546847 100644 --- a/man/randCross.Rd +++ b/man/randCross.Rd @@ -2,6 +2,7 @@ % Please edit documentation in R/crossing.R \name{randCross} \alias{randCross} +\alias{randCross,Pop-method} \title{Make random crosses} \usage{ randCross( @@ -14,14 +15,25 @@ randCross( simParam = NULL, nThreads = NULL ) + +\S4method{randCross}{Pop}( + pop, + nCrosses, + nProgeny = 1, + balance = TRUE, + parents = NULL, + ignoreSexes = FALSE, + simParam = NULL, + nThreads = NULL +) } \arguments{ \item{pop}{an object of \code{\link{Pop-class}}} \item{nCrosses}{total number of crosses to make} -\item{nProgeny}{number of progeny per cross. May be a single value for all -crosses or a vector with values equal to the number of crosses. If providing +\item{nProgeny}{number of progeny per cross. May be a single value for all +crosses or a vector with values equal to the number of crosses. If providing a vector, the values are randomly assigned to each cross.} \item{balance}{if using sexes, this option will balance the number @@ -43,8 +55,13 @@ Returns an object of \code{\link{Pop-class}} } \description{ A wrapper for \code{\link{makeCross}} that randomly -selects parental combinations for all possible combinantions. +selects parental combinations for all possible combinations. } +\section{Functions}{ +\itemize{ +\item \code{randCross(Pop)}: Method for \code{\link{Pop-class}} + +}} \examples{ #Create founder haplotypes founderPop = quickHaplo(nInd=10, nChr=1, segSites=10) diff --git a/man/randCross2.Rd b/man/randCross2.Rd index 8b2c00a5..8df069b0 100644 --- a/man/randCross2.Rd +++ b/man/randCross2.Rd @@ -2,6 +2,7 @@ % Please edit documentation in R/crossing.R \name{randCross2} \alias{randCross2} +\alias{randCross2,Pop,Pop-method} \title{Make random crosses} \usage{ randCross2( @@ -16,6 +17,19 @@ randCross2( simParam = NULL, nThreads = NULL ) + +\S4method{randCross2}{Pop,Pop}( + females, + males, + nCrosses, + nProgeny = 1, + balance = TRUE, + femaleParents = NULL, + maleParents = NULL, + ignoreSexes = FALSE, + simParam = NULL, + nThreads = NULL +) } \arguments{ \item{females}{an object of \code{\link{Pop-class}} for female parents.} @@ -24,8 +38,8 @@ randCross2( \item{nCrosses}{total number of crosses to make} -\item{nProgeny}{number of progeny per cross. May be a single value for all -crosses or a vector with values equal to the number of crosses. If providing +\item{nProgeny}{number of progeny per cross. May be a single value for all +crosses or a vector with values equal to the number of crosses. If providing a vector, the values are randomly assigned to each cross.} \item{balance}{this option will balance the number @@ -51,9 +65,14 @@ Returns an object of \code{\link{Pop-class}} } \description{ A wrapper for \code{\link{makeCross2}} that randomly -selects parental combinations for all possible combinantions between +selects parental combinations for all possible combinations between two populations. } +\section{Functions}{ +\itemize{ +\item \code{randCross2(females = Pop, males = Pop)}: Method for \code{\link{Pop-class}} + +}} \examples{ #Create founder haplotypes founderPop = quickHaplo(nInd=10, nChr=1, segSites=10) diff --git a/man/selectCross.Rd b/man/selectCross.Rd index b237928c..c467127f 100644 --- a/man/selectCross.Rd +++ b/man/selectCross.Rd @@ -2,6 +2,7 @@ % Please edit documentation in R/crossing.R \name{selectCross} \alias{selectCross} +\alias{selectCross,Pop-method} \title{Select and randomly cross} \usage{ selectCross( @@ -19,6 +20,22 @@ selectCross( ..., balance = TRUE ) + +\S4method{selectCross}{Pop}( + pop, + nInd = NULL, + nFemale = NULL, + nMale = NULL, + nCrosses, + nProgeny = 1, + trait = 1, + use = "pheno", + selectTop = T, + simParam = NULL, + nThreads = NULL, + ..., + balance = TRUE +) } \arguments{ \item{pop}{an object of \code{\link{Pop-class}}} @@ -75,6 +92,11 @@ of intermediate populations created. This reduces RAM usage and simplifies code writing. Note that this wrapper does not provide the full functionality of either function. } +\section{Functions}{ +\itemize{ +\item \code{selectCross(Pop)}: Method for \code{\link{Pop-class}} + +}} \examples{ #Create founder haplotypes founderPop = quickHaplo(nInd=10, nChr=1, segSites=10) diff --git a/man/self.Rd b/man/self.Rd index 1dc8f70b..eac7e4b0 100644 --- a/man/self.Rd +++ b/man/self.Rd @@ -2,6 +2,7 @@ % Please edit documentation in R/crossing.R \name{self} \alias{self} +\alias{self,Pop-method} \title{Self individuals} \usage{ self( @@ -12,11 +13,20 @@ self( simParam = NULL, nThreads = NULL ) + +\S4method{self}{Pop}( + pop, + nProgeny = 1, + parents = NULL, + keepParents = TRUE, + simParam = NULL, + nThreads = NULL +) } \arguments{ \item{pop}{an object of \code{\link{Pop-class}}} -\item{nProgeny}{number of selfed progeny per individual. May be a single value +\item{nProgeny}{number of selfed progeny per individual. May be a single value for all or a vector providing values for each individual.} \item{parents}{an optional vector of indices for allowable parents} @@ -38,6 +48,11 @@ Returns an object of \code{\link{Pop-class}} Creates selfed progeny from each individual in a population. Only works when sexes is "no". } +\section{Functions}{ +\itemize{ +\item \code{self(Pop)}: Method for \code{\link{Pop-class}} + +}} \examples{ #Create founder haplotypes founderPop = quickHaplo(nInd=2, nChr=1, segSites=10) diff --git a/man/setPheno.Rd b/man/setPheno.Rd index 9c107235..3395e20b 100644 --- a/man/setPheno.Rd +++ b/man/setPheno.Rd @@ -2,6 +2,8 @@ % Please edit documentation in R/phenotypes.R \name{setPheno} \alias{setPheno} +\alias{setPheno,Pop-method} +\alias{setPheno,MultiPop-method} \title{Set phenotypes} \usage{ setPheno( @@ -18,6 +20,34 @@ setPheno( simParam = NULL, ... ) + +\S4method{setPheno}{Pop}( + pop, + h2 = NULL, + H2 = NULL, + varE = NULL, + corE = NULL, + reps = 1, + fixEff = 1L, + p = NULL, + onlyPheno = FALSE, + traits = NULL, + simParam = NULL +) + +\S4method{setPheno}{MultiPop}( + pop, + h2 = NULL, + H2 = NULL, + varE = NULL, + corE = NULL, + reps = 1, + fixEff = 1L, + p = NULL, + onlyPheno = FALSE, + traits = NULL, + simParam = NULL +) } \arguments{ \item{pop}{an object of \code{\link{Pop-class}} or @@ -99,6 +129,13 @@ breeding programs. In this case, varE is set to the plot error and reps is set to the number of plots per entry. The resulting phenotype represents the entry-means. } +\section{Functions}{ +\itemize{ +\item \code{setPheno(Pop)}: Method for \code{\link{Pop-class}} + +\item \code{setPheno(MultiPop)}: Method for \code{\link{MultiPop-class}} objects + +}} \examples{ #Create founder haplotypes founderPop = quickHaplo(nInd=10, nChr=1, segSites=10)