diff --git a/.gitignore b/.gitignore index fd25973..d2c23c6 100644 --- a/.gitignore +++ b/.gitignore @@ -78,3 +78,7 @@ PhyloSim/inst/doc/PhyloSimManual.Rnw PhyloSim/inst/doc/PhyloSimManual.R PhyloSim/inst/doc/PhyloSimManual.pdf +*.aux +*.idea +CMakeFiles +cmake-build-debug diff --git a/PhyloSim/DESCRIPTION b/PhyloSim/DESCRIPTION index 36ca654..77efec2 100644 --- a/PhyloSim/DESCRIPTION +++ b/PhyloSim/DESCRIPTION @@ -27,7 +27,10 @@ Imports: adephylo, fields, shape, - foreach + foreach, + MESS, + apTreeshape, + PhyloMeasures Suggests: knitr LinkingTo: Rcpp diff --git a/PhyloSim/R/RcppExports.R b/PhyloSim/R/RcppExports.R index c7d5bfb..e29e6e7 100644 --- a/PhyloSim/R/RcppExports.R +++ b/PhyloSim/R/RcppExports.R @@ -3,7 +3,7 @@ #' Core phylosim model #' @export -callModel <- function(x, y, dispersal, runs, specRate, dens, env, neutral, mort, mortStrength, repro, dispersalCutoff, densityCutoff, seed, envStrength, compStrength, fission, redQueen, redQueenStrength, protracted, airmatR, soilmatR) { - .Call(`_PhyloSim_callModel`, x, y, dispersal, runs, specRate, dens, env, neutral, mort, mortStrength, repro, dispersalCutoff, densityCutoff, seed, envStrength, compStrength, fission, redQueen, redQueenStrength, protracted, airmatR, soilmatR) +callModel <- function(x, y, dispersal, runs, specRate, dens, env, neutral, mort, mortStrength, repro, dispersalCutoff, densityCutoff, seed, envStrength, compStrength, fission, redQueen, redQueenStrength, protracted, airmatR, soilmatR, prunePhylogeny) { + .Call(`_PhyloSim_callModel`, x, y, dispersal, runs, specRate, dens, env, neutral, mort, mortStrength, repro, dispersalCutoff, densityCutoff, seed, envStrength, compStrength, fission, redQueen, redQueenStrength, protracted, airmatR, soilmatR, prunePhylogeny) } diff --git a/PhyloSim/R/localPlots.R b/PhyloSim/R/localPlots.R index 635b99f..201aa15 100644 --- a/PhyloSim/R/localPlots.R +++ b/PhyloSim/R/localPlots.R @@ -4,9 +4,9 @@ #' @param which.result Integer, determines which result should be used. This argument is only usefull if your 'runs' argument in \code{\link{createCompletePar}} contains more than one element. By default, the last result is used. #' @param size A single value (or a vector) determining the edge length(s) of the generated subplots #' @param n The number of subplots to be generated -#' @param community Logical, determining whether to generate a communiy table or not. default is FALSE +#' @param community Logical, determining whether to generate a community table or not. default is FALSE #' @param plot Logical, determining whether the results should be shown graphically. Default is FALSE. -#' @param nested Logical, determinig whether the subplots should be nested (see Details). +#' @param nested Logical, determining whether the subplots should be nested (see Details). #' @return A list of subplots and (if coomunity = T) a community table with plots in rows and species in collumns #' @details If nested == TRUE the subplots are poduced in a sequential order. That means if your 'size' argument has the length 5 and your 'n' argument has the size 2 you will get ten subplots. The first five will be one group of nested plots and the last five the second group of nested plots. #' @example inst/examples/localPlots.R @@ -29,11 +29,16 @@ localPlots <- function(simu, which.result=NULL,size, n, community = FALSE, plot matrix <- simu$specMat env <- simu$envMat + comp <- simu$compMat + if(plot == T) plotmat <-matrix(0, ncol(matrix), nrow(matrix)) subPlots <- list() envPlots <- list() + compPlots <- list() + positions <- list() + communityTable <- data.frame("species"= numeric()) count <-0 @@ -75,7 +80,13 @@ localPlots <- function(simu, which.result=NULL,size, n, community = FALSE, plot subPlots[[count]] <- matrix[rsel, csel] - envPlots[[count]] <- env[rsel, csel] + envPlots[[count]] <- env[rsel, csel] + compPlots[[count]] <- comp[rsel, csel] + + # TODO: Is this the correct way to calculate the center of a rectangle in a matrix? + position <- c(rsel[1] + size[k] / 2 - 0.5, csel[1] + size[k] / 2 - 0.5) + positions[[count]] <- c(wrap_coordinates(position[1], limit=length(matrix[1,])), + wrap_coordinates(position[2], limit=length(matrix[,1]))) if(plot == T){ @@ -121,7 +132,9 @@ localPlots <- function(simu, which.result=NULL,size, n, community = FALSE, plot } if(community == T){ - return(list(subPlots=subPlots, communityTable=communityTable, envPlots=envPlots)) - } else return(list(subPlots=subPlots, envPlots=envPlots)) + return(list(subPlots=subPlots, communityTable=communityTable, envPlots=envPlots, compPlots=compPlots, positions=positions)) + } else return(list(subPlots=subPlots, envPlots=envPlots, compPlots=compPlots, positions=positions)) -} \ No newline at end of file +} + +wrap_coordinates <- function(x, limit) if (x > limit) x - limit else if (x <= 0) limit + x else x diff --git a/PhyloSim/R/parCreator.R b/PhyloSim/R/parCreator.R index da5e2df..b037551 100644 --- a/PhyloSim/R/parCreator.R +++ b/PhyloSim/R/parCreator.R @@ -20,6 +20,7 @@ #' @param scenario String, further information you want to add to the parameter set in order to refer to a model run more conveniently. #' @param calculateSummaries Logical, determining wheter summary statistics should be calculated #' @param convertToBinaryTree Logical, determining if the phylogeny should be converted into a binary tree +#' @param prunePhylogeny Logical, determining whether the phylogeny should be prune by the internal pruning function #' @details If runs is a sequence of generations the intermediate and end results are saved in the output of \code{runSimulation}. \cr\cr If type = "Rneutral" the model will run entirely in R. This model is to be seen only for test and teaching purpose. To be used in practice it is far too slow. Also the output is reduced. Only the species landscape and the parameter settings will be displayed in the output. #' @return A List with parameters #' @examples @@ -32,7 +33,7 @@ #' #' @export -createCompletePar <- function(x = 50, y = 50, dispersal = "global", runs = 100, specRate = 1.0, density = 0, environment = 0, fitnessActsOn = "mortality" , fitnessBaseMortalityRatio = 10, densityCut = 1, seed=NULL, type = "base", fission = 0, redQueen = 0, redQueenStrength = 0, protracted = 0, airmat = 1, scenario = NULL, calculateSummaries = FALSE, convertToBinaryTree = TRUE){ +createCompletePar <- function(x = 50, y = 50, dispersal = "global", runs = 100, specRate = 1.0, density = 0, environment = 0, fitnessActsOn = "mortality" , fitnessBaseMortalityRatio = 10, densityCut = 1, seed=NULL, type = "base", fission = 0, redQueen = 0, redQueenStrength = 0, protracted = 0, airmat = 1, scenario = NULL, calculateSummaries = FALSE, convertToBinaryTree = TRUE, prunePhylogeny = TRUE){ soilmat <- 1 # Needs to be defined here as long as it is not # implemented in the model @@ -62,7 +63,7 @@ createCompletePar <- function(x = 50, y = 50, dispersal = "global", runs = 100, seed = seed, type = type, scenario = scenario, fission = fission, redQueen = redQueen, redQueenStrength = redQueenStrength, protracted = protracted, airmatR = airmat, soilmatR=soilmat, calculateSummaries=calculateSummaries, - convertToBinaryTree = convertToBinaryTree) + convertToBinaryTree = convertToBinaryTree, prunePhylogeny = prunePhylogeny) diff --git a/PhyloSim/R/runSimulation.R b/PhyloSim/R/runSimulation.R index 8e8331b..ae18c5f 100644 --- a/PhyloSim/R/runSimulation.R +++ b/PhyloSim/R/runSimulation.R @@ -109,7 +109,8 @@ runSimulation <- function(par) redQueenStrength = par$redQueenStrength, protracted = par$protracted, airmatR = par$airmat, - soilmatR = par$soilmat) + soilmatR = par$soilmat, + prunePhylogeny = par$prunePhylogeny) runtime <- as.numeric((proc.time() - ptm)[3]) @@ -132,6 +133,8 @@ runSimulation <- function(par) phyloi <- 0 warning("Cannot build Phylogeny") }else{ + # TODO: ape can not read the tree if it is not pruned by prunePhylogenyR: + # Error in if (tp[3] != "") obj$node.label <- tp[3] : missing value where TRUE/FALSE needed phyloi <- ape::read.tree(text= out[[i]]$Phylogeny) } diff --git a/PhyloSim/R/runSimulationBatch.R b/PhyloSim/R/runSimulationBatch.R index b2c8792..b2d246e 100644 --- a/PhyloSim/R/runSimulationBatch.R +++ b/PhyloSim/R/runSimulationBatch.R @@ -14,7 +14,7 @@ #' par2 <- createCompletePar(x = 50, y = 50, dispersal = 0 , runs = c(500,1000), #' density = 1, environment = 0.5, specRate = 1) #' -#' ## Merge the parameter sets. It is important to note, that the funktion +#' ## Merge the parameter sets. It is important to note, that the function #' ## needs a list of parameter sets. #' par <- list(par1,par2) #' diff --git a/PhyloSim/R/summaryStatistics.R b/PhyloSim/R/summaryStatistics.R index 3cb3a2c..7609f6f 100644 --- a/PhyloSim/R/summaryStatistics.R +++ b/PhyloSim/R/summaryStatistics.R @@ -18,8 +18,13 @@ calculateSummaryStatistics <- function(simulation) { sacAuc=NA, alphaDiversity = NA, betaDiversity = NA, + gammaDiversity = NA, imbalance = NA, - dispersion = NA) + dispersion = NA, + gammaStatistics = NA, + meanNodeAge = NA, + varPart_1 = NA, + varPart_2 = NA) # TODO: implement special case: only 1 species if (is.double(simulation$Output[[1]]$phylogeny)) { @@ -62,6 +67,8 @@ calculateSummaryStatistics <- function(simulation) { summaryStatistics$betaDiversity <- mean(vegan::betadiver(plots$communityTable, method=method)) + # gamma diversity + summaryStatistics$gammaDiversity <- gammaDiversity(simulation) # phylogenetic imbalance # uses apTreeshape's colless function @@ -103,13 +110,71 @@ calculateSummaryStatistics <- function(simulation) { # phylogenetic dispersion # uses PhyloMeasures' implementation of the NRI - # Causes error. Drop fossil seems to drop clades that are no real fossils?! + # Commented code below causes error. Drop fossil seems to drop clades that are no real fossils?! #summaryStatistics$dispersion <- mean(PhyloMeasures::mpd.query(ape::drop.fossil(simulation$Output[[1]]$phylogeny), # plots$communityTable, # standardize = TRUE)) + summaryStatistics$dispersion <- mean(PhyloMeasures::mpd.query(simulation$Output[[1]]$phylogeny, plots$communityTable, standardize = TRUE)) + # gamma statistics + # uses ape's implementation of the gammaStatistics + # attention: only works on ultrametric trees + summaryStatistics$gammaStatistics <- ape::gammaStat(ape::drop.fossil(simulation$Output[[1]]$phylogeny)) + + # mean node age + #summaryStatistics$meanNodeAge <- ape::chronoMPL(simulation$Output[[1]]$phylogeny) + summaryStatistics$meanNodeAge <- mean(ape::drop.fossil(simulation$Output[[1]]$phylogeny)$edge.length) + + + # variation partitioning + #distance_matrix <- distances(plots$positions, limits=c(nrow(simulation$Output[[1]]$specMat), ncol(simulation$Output[[1]]$specMat))) + env <- data.frame(unlist(lapply(plots$envPlots, mean))) + comp <- data.frame(unlist(lapply(plots$compPlots, mean))) + + #mod <- vegan::varpart(plots$communityTable, as.dist(distance_matrix), env, comp) + mod <- vegan::varpart(plots$communityTable, env, comp) + + summaryStatistics$varPart_1 <- mod$part$fract$Adj.R.squared[1] + summaryStatistics$varPart_2 <- mod$part$fract$Adj.R.squared[1] + return(summaryStatistics) } + +gammaDiversity <- function(simulation, q=0){ + spec_vector <- c(simulation$Output[[1]]$specMat) + specs <- unique(spec_vector) + n_specs <- length(specs) + + if (q == 0) return(n_specs) + + n_individuals <- length(spec_vector) + + prop_abundances <- rep(NA, length(specs)) + + for(i in 1:length(specs)){ + prop_abundances[i] <- sum(spec_vector == specs[i]) / n_individuals + } + + gamma <- prop_abundances * prop_abundances^(q-1) + gamma <- sum(gamma)^(1/(q-1)) + gamma <- 1/gamma + return(gamma) +} + +distances <- function(positions, limits){ + distance <- function(a, b, limits){ + # sqrt(min(|x1 - x2|, w - |x1 - x2|)^2 + min(|y1 - y2|, h - |y1-y2|)^2) + return(sqrt(min(abs(a[1]-b[1]), limits[1] - abs(a[1]-b[1]))^2 + min(abs(a[2]-b[2]), limits[2] - abs(a[2]-b[2]))^2)) + } + dist_mat <- matrix(0, ncol=length(positions), nrow=length(positions)) + # TODO: maybe there is a better way to implement this instead of a for loop + for(i in 1:nrow(dist_mat)){ + for(j in 1:ncol(dist_mat)){ + dist_mat[i,j] <- distance(positions[[i]], positions[[j]], limits=limits) + } + } + return(dist_mat) +} diff --git a/PhyloSim/man/callModel.Rd b/PhyloSim/man/callModel.Rd index 3e6dce9..3ce4b49 100644 --- a/PhyloSim/man/callModel.Rd +++ b/PhyloSim/man/callModel.Rd @@ -7,7 +7,7 @@ callModel(x, y, dispersal, runs, specRate, dens, env, neutral, mort, mortStrength, repro, dispersalCutoff, densityCutoff, seed, envStrength, compStrength, fission, redQueen, redQueenStrength, protracted, airmatR, - soilmatR) + soilmatR, prunePhylogeny) } \description{ Core phylosim model diff --git a/PhyloSim/man/createCompletePar.Rd b/PhyloSim/man/createCompletePar.Rd index 248b517..999a348 100644 --- a/PhyloSim/man/createCompletePar.Rd +++ b/PhyloSim/man/createCompletePar.Rd @@ -9,7 +9,8 @@ createCompletePar(x = 50, y = 50, dispersal = "global", runs = 100, fitnessActsOn = "mortality", fitnessBaseMortalityRatio = 10, densityCut = 1, seed = NULL, type = "base", fission = 0, redQueen = 0, redQueenStrength = 0, protracted = 0, airmat = 1, - scenario = NULL, calculateSummaries = FALSE, convertToBinaryTree = TRUE) + scenario = NULL, calculateSummaries = FALSE, convertToBinaryTree = TRUE, + prunePhylogeny = TRUE) } \arguments{ \item{x}{Integer, Dimension of the model landscape in x-direction} @@ -51,6 +52,8 @@ createCompletePar(x = 50, y = 50, dispersal = "global", runs = 100, \item{calculateSummaries}{Logical, determining wheter summary statistics should be calculated} \item{convertToBinaryTree}{Logical, determining if the phylogeny should be converted into a binary tree} + +\item{prunePhylogeny}{Logical, determining whether the phylogeny should be prune by the internal pruning function} } \value{ A List with parameters diff --git a/PhyloSim/man/localPlots.Rd b/PhyloSim/man/localPlots.Rd index 1764464..b34075c 100644 --- a/PhyloSim/man/localPlots.Rd +++ b/PhyloSim/man/localPlots.Rd @@ -16,11 +16,11 @@ localPlots(simu, which.result = NULL, size, n, community = FALSE, \item{n}{The number of subplots to be generated} -\item{community}{Logical, determining whether to generate a communiy table or not. default is FALSE} +\item{community}{Logical, determining whether to generate a community table or not. default is FALSE} \item{plot}{Logical, determining whether the results should be shown graphically. Default is FALSE.} -\item{nested}{Logical, determinig whether the subplots should be nested (see Details).} +\item{nested}{Logical, determining whether the subplots should be nested (see Details).} } \value{ A list of subplots and (if coomunity = T) a community table with plots in rows and species in collumns diff --git a/PhyloSim/man/runSimulationBatch.Rd b/PhyloSim/man/runSimulationBatch.Rd index b0cf8a0..de483a0 100644 --- a/PhyloSim/man/runSimulationBatch.Rd +++ b/PhyloSim/man/runSimulationBatch.Rd @@ -31,7 +31,7 @@ par1 <- createCompletePar(x = 50, y = 50, dispersal = 0 , runs = c(500,1000), par2 <- createCompletePar(x = 50, y = 50, dispersal = 0 , runs = c(500,1000), density = 1, environment = 0.5, specRate = 1) -## Merge the parameter sets. It is important to note, that the funktion +## Merge the parameter sets. It is important to note, that the function ## needs a list of parameter sets. par <- list(par1,par2) diff --git a/PhyloSim/src/Main.cpp b/PhyloSim/src/Main.cpp index 56ccd48..509096f 100644 --- a/PhyloSim/src/Main.cpp +++ b/PhyloSim/src/Main.cpp @@ -72,6 +72,7 @@ int main() { int protracted = 0; std::vector airmat(1); std::vector soilmat(1); + bool prunePhylogeny = 1; RandomGen ran; ran.seedrand(seed); // seed is int while seedrand expects unsigned int @@ -89,8 +90,12 @@ int main() { redQueen, redQueenStrength, protracted, airmat, soilmat); Model.update(runs); - Model.m_Global->m_Phylogeny.prunePhylogeny(runs); - Model.m_Global->m_Phylogeny.writePhylogenyR(1, Model.m_Global->m_Phylogeny.m_PrunedPhylo); + if(prunePhylogeny){ + Model.m_Global->m_Phylogeny.prunePhylogeny(runs); + Model.m_Global->m_Phylogeny.writePhylogenyR(1, Model.m_Global->m_Phylogeny.m_PrunedPhylo); + } + + Model.m_Global->m_Phylogeny.writePhylogenyR(1, Model.m_Global->m_Phylogeny.m_FullPhylogeny); // Model.get_data(); // Model.getclimate(); diff --git a/PhyloSim/src/PhylSimModelInterface.cpp b/PhyloSim/src/PhylSimModelInterface.cpp index da2bd1d..6a9ece5 100644 --- a/PhyloSim/src/PhylSimModelInterface.cpp +++ b/PhyloSim/src/PhylSimModelInterface.cpp @@ -29,7 +29,7 @@ using namespace Rcpp; List callModel(int x, int y, int dispersal, IntegerVector runs, double specRate, bool dens, bool env, bool neutral, bool mort, int mortStrength, bool repro, int dispersalCutoff, int densityCutoff, int seed, double envStrength, double compStrength, int fission, double redQueen, double redQueenStrength, - int protracted, NumericVector airmatR, NumericVector soilmatR) { + int protracted, NumericVector airmatR, NumericVector soilmatR, bool prunePhylogeny) { #ifdef DEBUG std::ofstream debugFile; debugFile.open("debug.txt"); @@ -113,10 +113,16 @@ List callModel(int x, int y, int dispersal, IntegerVector runs, double specRate, #ifdef DEBUG std::cout << "before writePhylogenyR" << std::endl; + std::cout << prunePhylogeny << std::endl; // consistency checks -> length, etc #endif - phyloPass = phylSimModel.m_Global->m_Phylogeny.writePhylogenyR(1, - phylSimModel.m_Global->m_Phylogeny.m_PrunedPhylo); + if(prunePhylogeny){ + phyloPass = phylSimModel.m_Global->m_Phylogeny.writePhylogenyR(1, + phylSimModel.m_Global->m_Phylogeny.m_PrunedPhylo); + }else{ + phyloPass = phylSimModel.m_Global->m_Phylogeny.writePhylogenyR(1, + phylSimModel.m_Global->m_Phylogeny.m_FullPhylogeny); + } #ifdef DEBUG std::cout << "after writePhylogenyR" << std::endl; #endif @@ -138,9 +144,15 @@ List callModel(int x, int y, int dispersal, IntegerVector runs, double specRate, } phylSimModel.m_Local->m_Phylogeny.prunePhylogeny(runcount); - std::string phyloPass = phylSimModel.m_Local->m_Phylogeny.writePhylogenyR(1, - phylSimModel.m_Local->m_Phylogeny.m_PrunedPhylo); + std::string phyloPass("\0"); + if(prunePhylogeny){ + phyloPass = phylSimModel.m_Local->m_Phylogeny.writePhylogenyR(1, + phylSimModel.m_Local->m_Phylogeny.m_PrunedPhylo); + }else{ + phyloPass = phylSimModel.m_Local->m_Phylogeny.writePhylogenyR(1, + phylSimModel.m_Local->m_Phylogeny.m_FullPhylogeny); + } char *cstr = new char[phyloPass.length() + 1]; std::strcpy(cstr, phyloPass.c_str()); diff --git a/PhyloSim/src/RcppExportsIni.c b/PhyloSim/src/RcppExportsIni.c index 9fcba13..7a875e8 100644 --- a/PhyloSim/src/RcppExportsIni.c +++ b/PhyloSim/src/RcppExportsIni.c @@ -10,13 +10,15 @@ See also comments here https://github.com/florianhartig/BayesianTools/issues/31 */ /* .Call calls */ +// every parameter passed to callModel must be represented as SEXP here +// the number of parameters must be passed to CallEntries extern SEXP _PhyloSim_callModel(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, - SEXP, SEXP, SEXP, SEXP, SEXP); + SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); static const R_CallMethodDef CallEntries[] = { - {"_PhyloSim_callModel", (DL_FUNC) &_PhyloSim_callModel, 22}, + {"_PhyloSim_callModel", (DL_FUNC) &_PhyloSim_callModel, 23}, {NULL, NULL, 0} }; diff --git a/PhyloSim/src/debug.h b/PhyloSim/src/debug.h index b29d855..35b726d 100644 --- a/PhyloSim/src/debug.h +++ b/PhyloSim/src/debug.h @@ -5,6 +5,6 @@ * Author: Florian Hartig */ -//#ifndef DEBUG -//#define DEBUG -//#endif \ No newline at end of file +// #ifndef DEBUG +// #define DEBUG +// #endif \ No newline at end of file