####ZIGDM_EM usage

####library(DMBC)
####library(Rlab)

#' @export
#'

####First step: generate pi
Bernoulli <- function(c.est, row) {

  #pi = exp(c.est %*% row)/(1+exp(c.est %*% row))
  pi = 0
  Delta = rbern(dim(c.est)[1], pi)
  return (Delta)
}

####Second step: generate Z
Zvalue_Generator <- function(Delta,Test_result, row2, row3) {

  Beta_mean = exp(Test_result$alpha.est %*% row2)/(1+exp(Test_result$alpha.est %*% row2))
  Beta_dispersion = exp(Test_result$beta.est %*% row3)/(1+exp(Test_result$beta.est %*% row3))
  Data_Matrix = cbind(as.matrix(Delta),Beta_mean,Beta_dispersion)

  test = apply(Data_Matrix, 1, RandomGenerate_beta)
  return(test)
}

RandomGenerate_beta <- function(input) {
    delta = input[1]
    beta_mean =input[2]
    beta_dispersion = input[3]

   if (delta ==1) {
      Z = 0
    }else{
      shape1= beta_mean*(1/beta_dispersion)-beta_mean
      shape2 = (1-beta_mean)*(1/beta_dispersion -1)
      Z = rbeta(1, shape1, shape2, ncp = 0)
    }
  return(Z)
  }

####Third step: generate p for multinormail distribution
multinormial_P <- function(Z) {
  P= list()
  P[1] = Z[1]
  if(length(Z)>1) {
    for (j in 2:length(Z)) {
      multiply =1
      for(k in 1:(j-1)) {
        multiply = multiply*(1-Z[k])
      }
      P[j] = Z[j]*multiply
    }
  }
  P= unlist(P)
  return(P)
}

################ Run below functions before calling
## The function ZIGDM.EM.PAR2 estimates three sets of regression coefficients "c", "alpha", and "beta" in the ZIGDM regression model.

## Input
# Y: taxa count matrix.
# Xc, Xa, Xb: design matrices for probability of absence model, mean model and dispersion model, respectively. The first column should contain "1" for the intercept. For intercept only model, the three matrices are simply contain vectors of 1.
# c0: initial values for regression coefficients "c" organized in a matrix (dim: K x d, K+1 is the #taxa (i.e. K+1 = ncol(Y)), d is the number of columns in the corresponding design matrix)
# alpha0: initial values for regression coefficients "alpha" organized in a matrix (dim: K x d)
# beta0: initial values for regression coefficients "beta" organized in a matrix (dim: K x d)
# tol: convergence tolerance
# max.iter: maximum number of iterations

## output
# c.est: regression coefficient for the probability of absence organized in a matrix. The probabilities of absence for all the taxa in sample i can then be calculated as exp(c.est %*% Xc[i,])/(1+exp(c.est %*% Xc[i,]))
# alpha.est: regression coefficient for the Beta mean parameter organized in a matrix. The Beta means for all the taxa in sample i  can then be calculated as exp(alpha.est %*% Xa[i,])/(1+exp(alpha.est %*% Xa[i,]))
# beta.est: regression coefficient for the Beta dispersion parameter organized in a matrix. The Beta dispersions for all the taxa in sample i can then be calculated as exp(beta.est %*% Xb[i,])/(1+exp(beta.est %*% Xb[i,]))

## Two important remarks:
## 1. Sort the taxa as Y = Y[,order( colSums(Y), decreasing = TRUE )] before run the analysis
## 2. If you don't want to have zero-inflation on a certain subset of taxa, just set the elements of the corresponding columns in c0 to -Inf.
##    So to fit the GDM model, all elements in c0 matrix should be set to -Inf

ZIGDM.EM.PAR2 <- function(Y, Xc, Xa, Xb, c0, alpha0, beta0, tol=0.0001, max.iter=1000){
  Y = Y[,order( colSums(Y), decreasing = TRUE )]
  CONV = 0
  CONV.iter = max.iter
  n = nrow(Y)
  K = ncol(Y)-1
  dc = ncol(Xc)
  da = ncol(Xa)
  db = ncol(Xb)

  c.last = c0; alpha.last = alpha0; beta.last = beta0;
  c.now = c0; alpha.now = alpha0; beta.now = beta0;

  Del.R = matrix(NA, n, K)
  A.R = matrix(NA, n, K)
  B.R = matrix(NA, n, K)

  for(l in 1:max.iter){

    # E-step

    # print(paste("====== ", l, "th ======", sep=""))
    for(i in 1:n){

      tmp = exp(c.last %*% Xc[i,])
      tmp[is.na(tmp)] = 0
      pv = as.numeric( tmp/(1+tmp) )
      pv[is.infinite(tmp) & tmp>0] =1  # positive inf

      tmp = exp(alpha.last %*% Xa[i,])
      mv = as.numeric( tmp/(1+tmp) )
      tmp = exp(beta.last %*% Xb[i,])
      sv = as.numeric( tmp/(1+tmp) )

      av = (1/sv - 1) * mv
      bv = (1/sv - 1) * (1-mv)

      par.post = rP.Y.par(pv, av, bv, Y[i,])

      Del.R[i, ] = par.post$pv.post
      tmp = par.post$av.post + par.post$bv.post
      #A.R[i, ] = digamma(par.post$av.post) - digamma(tmp)
      #B.R[i, ] = digamma(par.post$bv.post) - digamma(tmp)

      A.R[i, ] = as.matrix(digamma(par.post$av.post) - digamma(tmp))
      B.R[i, ] = as.matrix(digamma(par.post$bv.post) - digamma(tmp))

    }

    # M-step
    for(j in 1:K){

      if( !is.infinite(c.last[j,1]) ){
        c.now[j, ] = Logit.optim(Del.R[,j], Xc, c.last[j, ])
      }

      tmp = Beta.optim.PAR2(Del.R[,j], A.R[,j], B.R[,j], Xa, Xb, alpha.last[j, ], beta.last[j, ])
      alpha.now[j, ] = tmp[1:da]; beta.now[j, ] = tmp[-(1:da)]

    }

    diff = 0
    if( sum(!is.infinite(c.now))>0 ){

      diff = diff + sum(abs(c.now[!is.infinite(c.now)]-c.last[!is.infinite(c.now)]))

    }

    diff = diff + sum(abs(alpha.now-alpha.last))
    diff = diff + sum(abs(beta.now-beta.last))
    if( diff < tol ){

      CONV = 1; CONV.iter = l;
      break;

    }else{

      c.last = c.now; alpha.last = alpha.now; beta.last = beta.now;
    }

  }

  return(list(c.est = c.now, alpha.est = alpha.now, beta.est = beta.now, CONV=CONV, CONV.iter = CONV.iter))

}

rP.Y.par <- function(pv, av, bv, Y){

  K = length(Y)-1
  N = sum(Y)

  pv.post = rep(0, K)

  av.prim = av + Y[1:K]
  bv.prim = bv
  for(j in 1:K){
    bv.prim[j] = bv.prim[j] + (N - sum(Y[1:j]))

    if(Y[j]==0){

      if(beta(av[j], bv[j])==0){

        pv.post[j] = pv[j]/(pv[j] + (1-pv[j]))

      }else{
        tmp = pv[j] + (1-pv[j])*beta(as.numeric(av.prim[j]), bv.prim[j])/beta(av[j], bv[j])
        #tmp = pv[j] + (1-pv[j])*beta(av.prim[j], bv.prim[j])/beta(av[j], bv[j])
        if(tmp==0){
          pv.post[j] = 1
        }else{
          pv.post[j] = pv[j]/tmp
        }

      }

    }

  }

  return(list(pv.post = pv.post, av.post = av.prim, bv.post = bv.prim))
}

lbeta2 <- function(a,b){
  a[a<0] = 0
  b[b<0] = 0
  return(lbeta(a,b))
}

Logit.neg.loglik <- function(par, data){

  tmp = as.numeric( exp(  data$X %*% par ) )
  p = tmp/(1+tmp)
  tmp = data$Del * log(p) + (1-data$Del) * log(1-p)
  index = which(p==0 | p==1)
  if(length(index)>0){
    tmp[index] = 0
  }

  return( -sum( tmp) )

}

Logit.neg.score <- function(par, data){

  tmp = as.numeric( exp(  data$X %*% par ) )
  p = tmp/(1+tmp)
  return( -colSums( (data$Del - p) * data$X ) )

}

Logit.optim <- function(Del, X, c.ini){

  Logit.par.ini = c.ini
  Logit.data = list(Del=Del, X=X)

  return( optim(par=Logit.par.ini, fn=Logit.neg.loglik, gr=Logit.neg.score, data = Logit.data, method="BFGS")$par)

}

Beta.neg.loglik.PAR2 <- function(par, data){

  da = ncol(data$Xa)
  alpha = par[1:da]
  beta = par[-(1:da)]

  tmp = as.numeric( exp( data$Xa %*% alpha) )
  mu.tmp = as.numeric( tmp/(1+tmp) )

  tmp = as.numeric( exp( data$Xb %*% beta) )
  sigma.tmp = as.numeric( tmp/(1+tmp) )

  a = (1/sigma.tmp - 1) * mu.tmp
  b = (1/sigma.tmp - 1) * (1-mu.tmp)
  a[a<0] = 0
  b[b<0] = 0

  return( -sum( (1-data$Del) * ( -lbeta2(a,b) + data$A * (a-1) + data$B *(b-1) )  ) )

}

Beta.neg.score.PAR2 <- function(par, data){

  da = ncol(data$Xa)
  alpha = par[1:da]
  beta = par[-(1:da)]

  tmp.a = as.numeric( exp( data$Xa %*% alpha) )
  mu.tmp = as.numeric( tmp.a/(1+tmp.a) )

  tmp.b = as.numeric( exp( data$Xb %*% beta) )
  sigma.tmp = as.numeric( tmp.b/(1+tmp.b) )

  a = (1/sigma.tmp - 1) * mu.tmp
  b = (1/sigma.tmp - 1) * (1-mu.tmp)
  a[a<0] = 0
  b[b<0] = 0

  a.a = (1/tmp.b) * mu.tmp * (1/(1+tmp.a))
  a.b = -(1/tmp.b) * mu.tmp
  b.a = - a.a
  b.b = -(1/tmp.b) *  (1/(1+tmp.a))

  one = (1-data$Del)*(digamma(a+b)-digamma(a) + data$A)
  two = (1-data$Del)*(digamma(a+b)-digamma(b) + data$B)

  return( -c( colSums( (one*a.a + two*b.a) * data$Xa ), colSums( (one*a.b + two*b.b) * data$Xb ) ) )
}

Beta.optim.PAR2 <- function(Del, A, B, Xa, Xb, alpha.ini, beta.ini){

  Beta.par.ini = c(alpha.ini, beta.ini)
  Beta.data = list(Del=Del, A=A, B=B, Xa=Xa, Xb=Xb)

  return( optim(par=Beta.par.ini, fn=Beta.neg.loglik.PAR2, gr=Beta.neg.score.PAR2, data = Beta.data, method="BFGS")$par)

}


score <- function(input) {
    var0 <- exp(subroutine0(input))
    var1 <- exp(subroutine1(input))
    var2 <- exp(subroutine2(input))
    var3 <- ((var0) + (var1)) + (var2)
    return(c((var0) / (var3), (var1) / (var3), (var2) / (var3)))
}
subroutine0 <- function(input) {
    return(((0.5) + (subroutine3(input))) + (subroutine4(input)))
}
subroutine1 <- function(input) {
    return(((0.5) + (subroutine5(input))) + (subroutine6(input)))
}
subroutine2 <- function(input) {
    return(((0.5) + (subroutine7(input))) + (subroutine8(input)))
}
subroutine3 <- function(input) {
    if ((input[3]) >= (2.45000005)) {
        var0 <- -0.0733167157
    } else {
        var0 <- 0.143414631
    }
    return(var0)
}
subroutine4 <- function(input) {
    if ((input[3]) >= (2.45000005)) {
        var0 <- -0.0706516728
    } else {
        var0 <- 0.125176534
    }
    return(var0)
}
subroutine5 <- function(input) {
    if ((input[3]) >= (2.45000005)) {
        if ((input[4]) >= (1.75)) {
            var0 <- -0.0668393895
        } else {
            var0 <- 0.123041473
        }
    } else {
        var0 <- -0.0717073306
    }
    return(var0)
}
subroutine6 <- function(input) {
    if ((input[3]) >= (2.45000005)) {
        if ((input[4]) >= (1.75)) {
            var0 <- -0.0642274022
        } else {
            var0 <- 0.10819874
        }
    } else {
        var0 <- -0.069036141
    }
    return(var0)
}
subroutine7 <- function(input) {
    if ((input[4]) >= (1.6500001)) {
        var0 <- 0.13432835
    } else {
        if ((input[3]) >= (4.94999981)) {
            var0 <- 0.0724137947
        } else {
            var0 <- -0.0732467622
        }
    }
    return(var0)
}
subroutine8 <- function(input) {
    if ((input[4]) >= (1.6500001)) {
        var0 <- 0.117797568
    } else {
        if ((input[3]) >= (4.94999981)) {
            var0 <- 0.0702545047
        } else {
            var0 <- -0.0706570372
        }
    }
    return(var0)
}


#Title: Estimate fitting decay curve
#Auther: Naoto Imamachi
#ver: 1.0.0
#Date: 2015-10-08

###Estimate_normalization_factor_function###
BridgeRHalfLifeCalcModel3 <- function(filename = "BridgeR_4_Normalized_expression_dataset.txt", group, hour, InforColumn = 4, CutoffRelExp = 0.1, CutoffDataPoint = 3, OutputFile = "BridgeR_5B_HalfLife_calculation_3model.txt"){
    ###Prepare_file_infor###
    time_points <- length(hour)
    group_number <- length(group)
    input_file <- fread(filename, header=T)
    output_file <- OutputFile

    ###print_header###
    cat("",file=output_file)
    hour_label <- NULL
    for(a in 1:group_number){
        if(!is.null(hour_label)){
            cat("\t", file=output_file, append=T)
        }
        hour_label <- NULL
        for(x in hour){
            hour_label <- append(hour_label, paste("T", x, "_", a, sep=""))
        }
        infor_st <- 1 + (a - 1)*(time_points + InforColumn)
        infor_ed <- (InforColumn)*a + (a - 1)*time_points
        infor <- colnames(input_file)[infor_st:infor_ed]
        cat(infor,hour_label, sep="\t", file=output_file, append=T)
        cat("\t", sep="", file=output_file, append=T)
        cat("status","model1","cor1","a_1","half1_1","half1_2","AIC1","model2","cor2","a_2","b_2","half2",
            "AIC2","model3","cor3","a_3","b_3","c_3","half3","AIC3","selected_model","Selected_R2","Selected_HalfLife",sep="\t",file=output_file, append=T)
    }
    cat("\n", sep="", file=output_file, append=T)

    ###calc_RNA_half_lives###
    gene_number <- length(input_file[[1]])
    for(x in 1:gene_number){
        data <- as.vector(as.matrix(input_file[x,]))
        for(a in 1:group_number){
            if(a != 1){
                cat("\t", sep="", file=output_file, append=T)
            }
            infor_st <- 1 + (a - 1)*(time_points + InforColumn)
            infor_ed <- (InforColumn)*a + (a - 1)*time_points
            exp_st <- infor_ed + 1
            exp_ed <- infor_ed + time_points

            #Write_gene_infor
            gene_infor <- data[infor_st:infor_ed]
            cat(gene_infor, sep="\t", file=output_file, append=T)
            cat("\t", file=output_file, append=T)

            #Write_time_point_data
            exp <- as.numeric(data[exp_st:exp_ed])
            cat(exp, sep="\t", file=output_file, append=T)
            cat("\t", file=output_file, append=T)

            #make_hour-exp_dataframe
            time_point_exp <- data.frame(hour,exp)
            time_point_exp <- time_point_exp[time_point_exp$exp >= CutoffRelExp, ]
            data_point <- length(time_point_exp$exp)

            if(!is.null(time_point_exp)){
                if(data_point >= CutoffDataPoint){
                    cat("ok","\t",sep="",file=output_file,append=T)

                    ###Model1: f(t) = exp(-a * t)###
                    optim1 <- function(x){
                        mRNA_exp <- exp(-x * time_point_exp$hour)
                        sum((time_point_exp$exp - mRNA_exp)^2)
                    }

                    out1 <- optim(1,optim1)
                    min1 <- out1$value
                    a_1 <- out1$par[1]
                    half1_1 <- log(2) / a_1

                    model1_pred <- function(x){
                        mRNA_exp <- exp(-x * time_point_exp$hour)
                        (cor(mRNA_exp, time_point_exp$exp, method="pearson"))^2
                    }

                    cor1 <- model1_pred(a_1)

                    model1_half <- function(x){
                        mRNA_half <- exp(-a_1 * x)
                        (mRNA_half - 0.5)^2
                    }

                    out1 <- optim(1,model1_half)
                    half1_2 <- out1$par
                    mRNA_pred <- exp(-a_1 * time_point_exp$hour)
                    s2 <- sum((time_point_exp$exp - mRNA_pred)^2) / data_point
                    AIC1 <- data_point * log(s2) + (2 * 0)

                    cat(min1,cor1,a_1,half1_1,half1_2,AIC1,sep="\t",file=output_file,append=T)
                    cat("\t",file=output_file,append=T)
                    ############################################

                    ###Model2: f(t) = (1 - b)exp(-a * t) + b###
                    optim2 <- function(x){
                        mRNA_exp <- (1.0 - x[2]) * exp(-x[1] * time_point_exp$hour) + x[2]
                        sum((time_point_exp$exp - mRNA_exp)^2)
                    }

                    out2 <- optim(c(1,0),optim2)
                    min2 <- out2$value
                    a_2 <- out2$par[1]
                    b_2 <- out2$par[2]

                    model2_pred <- function(a,b){
                        mRNA_exp <- (1.0 - b) * exp(-a * time_point_exp$hour) + b
                        (cor(mRNA_exp, time_point_exp$exp, method="pearson"))^2
                    }

                    cor2 <- model2_pred(a_2, b_2)

                    model2_half <- function(x){
                        mRNA_half <- (1.0 - b_2) * exp(-a_2 * x) + b_2
                        (mRNA_half - 0.5)^2
                    }

                    out2 <- optim(1,model2_half)
                    half2 <- out2$par

                    if(b_2 >= 0.5){
                        half2 <- Inf
                    }

                    mRNA_pred <- (1.0 - b_2) * exp(-a_2 * time_point_exp$hour) + b_2
                    s2 <- sum((time_point_exp$exp - mRNA_pred)^2) / data_point
                    AIC2 <- data_point * log(s2) + (2 * 1)

                    cat(min2,cor2,a_2,b_2,half2,AIC2,sep="\t",file=output_file,append=T)
                    cat("\t",file=output_file,append=T)
                    ############################################################

                    ###Model3: f(t) = c * exp(-a * t) + (1 - c) * exp(-b * t)###
                    optim3 <- function(x){
                        mRNA_exp <- x[3] * exp(-x[1] * time_point_exp$hour) + (1.0 - x[3]) * exp(-x[2] * time_point_exp$hour)
                        sum((time_point_exp$exp - mRNA_exp)^2)
                    }

                    out3 <- optim(c(1,1,0.1),optim3)
                    min3 <- out3$value
                    a_3 <- out3$par[1]
                    b_3 <- out3$par[2]
                    c_3 <- out3$par[3]

                    model3_pred <- function(a,b,c){
                        mRNA_exp <- c * exp(-a * time_point_exp$hour) + (1.0 - c) * exp(- b * time_point_exp$hour)
                        (cor(mRNA_exp, time_point_exp$exp, method="pearson"))^2
                    }

                    cor3 <- model3_pred(a_3,b_3,c_3)

                    model3_half <- function(x){
                        mRNA_half <- c_3 * exp(-a_3 * x) + (1.0 - c_3) * exp(-b_3 * x)
                        (mRNA_half - 0.5)^2
                    }

                    out3 <- optim(1,model3_half)
                    half3 <- out3$par
                    mRNA_pred <- c_3 * exp(-a_3 * time_point_exp$hour) + (1.0 - c_3) * exp(-b_3 * time_point_exp$hour)
                    s2 <- sum((time_point_exp$exp - mRNA_pred)^2) / data_point
                    AIC3 <- data_point * log(s2) + (2 * 2)

                    cat(min3,cor3,a_3,b_3,c_3,half3,AIC3,sep="\t",file=output_file,append=T)
                    cat("\t",file=output_file,append=T)
                    ############################################################

                    half_table <- data.frame(half=c(as.numeric(half1_2),as.numeric(half2),as.numeric(half3)),AIC=c(as.numeric(AIC1),as.numeric(AIC2),as.numeric(AIC3)))
                    AIC_list <- order(half_table$AIC)
                    #selected_half <- half_table$half[min_AIC_index]

                    AIC_flg <- 0
                    for(min_AIC_index in AIC_list){
                        ###Model1###
                        if(min_AIC_index == 1){
                            selected_half <- half1_2
                            if(selected_half > 24){
                                selected_half <- 24
                            }
                            if(a_1 > 0){
                                cat("model1",cor1,selected_half,sep="\t",file=output_file,append=T)
                                AIC_flg <- 1
                                break
                            }
                        }
                        ###Model2###
                        if(min_AIC_index == 2){
                            selected_half <- half2
                            if(selected_half == "Inf"){
                                selected_half <- 24
                            }else if(selected_half > 24){
                                selected_half <- 24
                            }
                            if(a_2 > 0 && b_2 > 0 && b_2 < 1){
                                cat("model2",cor2,selected_half,sep="\t",file=output_file,append=T)
                                AIC_flg <- 1
                                break
                            }
                        }
                        ###Model3###
                        if(min_AIC_index == 3){
                            selected_half <- half3
                            if(selected_half > 24){
                                selected_half <- 24
                            }
                            if(a_3 > 0 && b_3 > 0 && c_3 > 0 && c_3 < 1){
                                cat("model3",cor3,selected_half,sep="\t",file=output_file,append=T)
                                AIC_flg <- 1
                                break
                            }
                        }
                    }

                    if(AIC_flg == 0){
                        if(a_1 < 0){
                            cat("model1",cor1,24,sep="\t",file=output_file,append=T)
                            next
                        }else{
                            cat("no_good_model","NA",24,sep="\t",file=output_file,append=T)
                            next
                        }
                    }

                }else{
                    cat("few_data","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA",
                        "NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA", sep="\t", file=output_file, append=T)
                }
            }else{
                cat("low_expresion","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA",
                    "NA","NA","NA","NA","NA","NA","NA","NA","NA","NA","NA", sep="\t", file=output_file, append=T)
            }
        }
        cat("\n", file=output_file, append=T)
    }
}


pp.fit2 <- function (xdat, threshold, npy = 365, ydat = NULL, mul = NULL, sigl = NULL, shl = NULL, mulink = identity, siglink = identity, shlink = identity, muinit = NULL, siginit = NULL, shinit = NULL, show = TRUE, method = "Nelder-Mead", maxit = 10000, ndeps = 1e-3, exceedancesOnly = TRUE, nBlocks = NULL, propMissingByBlock = 0, ydatByBlock = NULL, thresholdByBlock = NULL, ...)
{
  # modification of pp.fit() from ismev by C. Paciorek
  # differences from pp.fit()
  # (1) modifies default initial values to be calculated only using exceedances, and modifies initial values for log link
  # (2) allows NA in data, adjusting intensity function calculation in likelihood to account for missing values
  # (3) allows user to provide only the exceedances for computational efficiency; in this case, for nonstationary models, the covariates must not vary within block (e.g., year) as the likelihood needs to calculate the intensity measure appropriate for every timepoint at which an observation is possible. The covariate values, proportion of missing values, and threshold for each block must be supplied when these are relevant
  # (4) returns data values and location, scale and shape values only for the exceedances
  # (5) adds 'flag' output that indicates if MLE or standard errors may not be legitimate
  # (6) allows one to change the default step size of the finite difference approximation to the gradient in the optimization

  # Note that this function operates in two fashions. First (exceedancesOnly = FALSE) it replicates pp.fit() but allows for missing data. In this case the data, threshold values, and covariates supplied should be given for every timepoint. Missing values are not allowed in the covariates or the threshold values as these are need for calculation of the intensity function in the likelihood.  In this case, information about the blocks is ignored. Second (exceedancesOnly = TRUE), it allows one to improve computational efficiency by providing only the exceedances.  In this case, the user is required to provide nBlocks and should provide propMissingByBlock, ydatByBlock, and thresholdByBlock as appropriate.  When only exceedances are supplied there should be no missing values in xdat.

  # for strict accuracy, one should specify npy to be equal to the total number of observation units in the number of blocks to be considered for analysis divided by the number of blocks; e.g., the total number of days in the years of the analysis divided by the number of years; note that blocks in general should be equal size for the parameter estimates and return values to be meaningful across multiple blocks, but slight deviations from, e.g., leap years should have limited effects

  # probably want to have sc and threshold checks for all timepoints not just exceedances, unlike in pp.fit(); for now I'm keeping the checks just for the exceedances, as in pp.fit()

  # note possible errors in pp.fit checking of legitimacy of parameters in terms of obs/thresholds not outside domain of distribution

  # add upper.tail? no, probably not; but if so give msg that says: provide me the maxima of negative data and that this will handle the results correctly?

  z <- list()
  npmu <- length(mul) + 1
  npsc <- length(sigl) + 1
  npsh <- length(shl) + 1

  z$trans <- FALSE
  if (is.function(threshold))
    stop("`threshold' cannot be a function")

  covars = FALSE
  if(!is.null(mul) || !is.null(sigl) || !is.null(shl))
    covars = TRUE  #

  if(covars || length(threshold) > 1)
    z$trans <- TRUE  # nonstationary model

  if(exceedancesOnly & is.null(nBlocks))
    stop("number of blocks (e.g., years) (nBlocks) is required for calculation of the likelihood when only exceedances are supplied")

  if(exceedancesOnly){ # check that nBlocks matches dimensionality of byBlock objects
    nBlocksError = FALSE
    if(length(propMissingByBlock) > 1 && length(propMissingByBlock) != nBlocks)
      nBlocksError = TRUE
    if(!is.null(ydatByBlock) && nrow(ydatByBlock) != nBlocks)
      nBlocksError = TRUE
    if(!is.null(thresholdByBlock) && length(thresholdByBlock) != nBlocks)
      nBlocksError = TRUE
    if(nBlocksError)
      stop("number of blocks indicated by nBlocks and one of {propMissingByBlock, ydatByBlock, thresholdByBlock} are in conflict")
  }

  if(exceedancesOnly && covars && is.null(ydatByBlock))
    stop("nonstationary modeling when providing only exceedances requires ydatByBlock to calculate the intensity function portion of the likelihood")

  if(exceedancesOnly &&  is.null(thresholdByBlock)){
    if(length(threshold) > 1){
      stop("require thresholdByBlock when threshold varies and only exceedances are supplied")
    } else{
      thresholdByBlock <- rep(threshold, nBlocks)
    }
  }

  if(exceedancesOnly && length(propMissingByBlock) == 1)
    propMissingByBlock = rep(propMissingByBlock, nBlocks)

  n <- length(xdat)
  if(exceedancesOnly){
    ny <- nBlocks # code below uses 'ny' since this is used in original pp.fit
    # nyEff <- sum(1-propMissingByBlock)
  } else{
    ny <- n/npy
    nyEff <- sum(!is.na(xdat))/npy
  }

  if(n == 1)
    stop("fitting will not be done correctly with a single observation or single exceedance")

  u <- threshold
  if(length(threshold) == 1)
    u <- rep(threshold, n)
  if(length(u) > 1 & length(u) != n)
    stop("number of threshold values should match number of observations, unless threshold does not vary")

  uInd <- !is.na(xdat) & xdat > u  # indicator of exceedances
  xdatu <- xdat[uInd]
  u[is.na(xdat)] = NA # sets things up so that intensity is not calculated when data are missing
  nu <- length(xdatu)
  in2 <- sqrt(6 * var(xdatu))/pi  # modified from pp.fit to make use only of exceedances
  in1 <- mean(xdatu) - 0.57722 * in2  # modified from pp.fit to make use only of exceedances

  if(identical(mulink, exp))
    in1 = log(in1)
  if(!identical(mulink, exp) && !identical(mulink, identity))
    warning("Default initial value for location is on incorrect scale; please supply your own.")
  if(identical(siglink, exp))
    in2 = log(in2)
  if(!identical(siglink, exp) && !identical(siglink, identity))
    warning("Default initial value for scale is on incorrect scale; please supply your own.")
  shinit.default = 0.1
  if(identical(shlink, exp))
    shinit.default = log(shinit.default)
  if(!identical(shlink, exp) && !identical(shlink, identity))
    warning("Default initial value for shape is on incorrect scale; please supply your own.")

  if(is.null(mul)) {
    mumat <- as.matrix(rep(1, n))
    if(is.null(muinit))
      muinit <- in1
    mumatByBlock <- matrix(rep(1, ny), nc = 1)
  } else {
    mumat <- cbind(rep(1, n), ydat[ , mul])
    mumatByBlock <- cbind(rep(1, ny), ydatByBlock[, mul])
    if(is.null(muinit))
      muinit <- c(in1, rep(0, length(mul)))
  }
  if(is.null(sigl)) {
    sigmat <- as.matrix(rep(1, n))
    if(is.null(siginit))
      siginit <- in2
    sigmatByBlock <- matrix(rep(1, ny), nc = 1)
  } else {
    sigmat <- cbind(rep(1, n), ydat[ , sigl])
    sigmatByBlock <- cbind(rep(1, ny), ydatByBlock[, sigl])
    if(is.null(siginit))
      siginit <- c(in2, rep(0, length(sigl)))
  }
  if(is.null(shl)) {
    shmat <- as.matrix(rep(1, n))
    if(is.null(shinit))
      shinit <- shinit.default
    shmatByBlock <- matrix(rep(1, ny), nc = 1)
  } else {
    shmat <- cbind(rep(1, n), ydat[ , shl])
    shmatByBlock <- cbind(rep(1, ny), ydatByBlock[, shl])
    if(is.null(shinit))
      shinit <- c(shinit.default, rep(0, length(shl)))
  }
  init <- c(muinit, siginit, shinit)
  z$model <- list(mul, sigl, shl)
  z$link <- deparse(substitute(c(mulink, siglink, shlink)))
  z$threshold <- threshold
  z$npy <- npy
  z$nexc <- nu
  z$data <- xdatu

  pp.lik <- function(a) {
    mu <- c(mulink(mumat %*% (a[1:npmu])))
    sc <- c(siglink(sigmat %*% (a[seq(npmu + 1, length = npsc)])))
    xi <- c(shlink(shmat %*% (a[seq(npmu + npsc + 1, length = npsh)])))
    if(exceedancesOnly){ # calculate parameters for each block for use in intensity function in likelihood
      muByBlock <- c(mulink(mumatByBlock %*% (a[1:npmu])))
      scByBlock <- c(siglink(sigmatByBlock %*% (a[seq(npmu + 1, length = npsc)])))
      xiByBlock <- c(shlink(shmatByBlock %*% (a[seq(npmu + npsc + 1, length = npsh)])))
    }

    # basic logic of the checks below is that the quantities that are exponentiated in (7.9) of Coles (p. 134) should be positive - i.e., for all exceedances and for all threshold values for all timepoints

    if(min(sc[uInd]) <= 0 || (exceedancesOnly && min(scByBlock) <= 0))
      return(10^6)  # note that pp.fit() only checks min(sc[uInd]) <=0, but presumably the scale should be positive for all potential observations

    # check that thresholds do not exceed the bounds of the distribution; pp.fit() does this only for the threshold values corresponding to the exceedances, but it's not clear why this shouldn't be checked for all timepoints
    if (min((1 + xi * (u - mu)/sc)[uInd]) <= 0)
      return(10^6)
    if(exceedancesOnly && min(1 + (xiByBlock * (thresholdByBlock - muByBlock))/scByBlock) <= 0)
      return(10^6)

    y <- (xdatu - mu[uInd])/sc[uInd]
    y <- 1 + xi[uInd] * y
    if(min(y) <= 0){  # check that exceedances do not exceed the bounds of the distribution; note that pp.fit() checks all observations, even those below the threshold, for reasons that are unclear
      l <- 10^6;
    } else{
      l <- sum(log(sc[uInd])) + sum(log(y) * (1/xi[uInd] + 1))  # PP density of the exceedances
      if(exceedancesOnly){  # calculate intensity function for all timepoints; using sum gives parameter estimates that correspond to GEV modeling of single block extrema (this is equivalent to multiplying by ny as in Coles (2001, p. 133) but ignoring the intensity values corresponding to the missing values)
        l <- l + sum( (1 - propMissingByBlock) * (1 + (xiByBlock * (thresholdByBlock - muByBlock))/scByBlock)^(-1/xiByBlock))
      } else{
        l <- l + nyEff * mean((1 + (xi * (u - mu))/sc)^(-1/xi), na.rm = TRUE) # need scaled mean if per-time-point intensity so that parameters correspond GEV modeling of single block extrema
      }
    }
    return(l)
  }
  x <- optim(init, pp.lik, hessian = TRUE, method = method,
             control = list(maxit = maxit, ndeps = rep(ndeps, length = length(init)), ...))
  # calculate parameters only for the exceedances, unlike pp.fit()
  mu <- mulink(c(mumat[uInd, , drop = FALSE] %*% (x$par[1:npmu])))
  sc <- siglink(c(sigmat[uInd, , drop = FALSE] %*% (x$par[seq(npmu + 1, length = npsc)])))
  xi <- shlink(c(shmat[uInd, , drop = FALSE] %*% (x$par[seq(npmu + npsc + 1, length = npsh)])))
  z$conv <- x$convergence
  z$nllh <- x$value
  z$vals <- cbind(mu, sc, xi, u[uInd])
  z$gpd <- apply(z$vals, 1, ppp, npy)
  if(z$trans) {
    z$data <- as.vector((1 + (xi * (xdatu - u[uInd]))/z$gpd[2, ])^(-1/xi))
  }
  z$mle <- x$par
  z$cov <- solve(x$hessian)
  z$se <- sqrt(diag(z$cov))
  if(show) {
    if(z$trans)
      print(z[c(2, 3)])
    if(length(z[[4]]) == 1)
      print(z[4])
    print(z[c(5, 6, 8)])
    if(!z$conv)
      print(z[c(9, 12, 14)])
  }
  z$flag = 0
  if(sum(is.na(c(z$mle, z$se))) || min(xi) < -1 || min(z$se) < 1e-5){
    z$flag = 1
    warning("MLEs and standard errors may not be reliable; please check convergence, estimates, standard errors, and input data.")
  }
  class(z) <- "pp.fit"
  invisible(z)
}


# Function for generating NOEC distributions for each species taking into account trophic levels
#
# Yields a matrix with dimensions number of species * number of iterations in the simulation
#
# Arguments:   - DP : matrix of endpoints
#              - UFt : matrix of uncertainty factors for the exposure time
#              - UFdd : matrix of uncertainty factors for the dose-descriptor
#              - SIM : number of iterations in the simulation
#              - CV.DP : coefficient of variation for the interlaboratory variation
#              - CV.UF : coefficient of variation for the use of non-substance-specific
#                uncertainty factors
#              - TrophLevel : Trophic levels of each species. 1 for primary producers, 2 for herbivores and 3 for carnivores
#              - Troph.Perc.Typ : Typical fractions in which each trophic level is represented in freshwater communities.
#
# Date of last modification: 03.07.2019
#
# Associated publication: Systematic consideration of parameter uncertainty and variability in
#                         probabilistic species sensitivity distributions
#
# Authors: Henning Wigger, Delphine Kawecki, Bernd Nowack and Veronique Adam
#
# Institute: Empa, Swiss Federal Laboratories for Materials Science and Technology,
#            Technology and Society Laboratory, Lerchenfeldstrasse 5, 9014 St. Gallen, Switzerland
#
# submitted to Integrated Environmental Assessment and Management in July 2019

# -------------------------------------------------------------------------------------------------

do.pSSD.troph <- function(DP,
                          UFt,
                          UFdd,
                          SIM,
                          CV.DP,
                          CV.UF,
                          TrophLevel,
                          Troph.Perc.Typ = c(0.65, 0.25, 0.1)){

  # test if there is no data available for one species
  if(any(apply(DP,2,function(x) length(which(!is.na(x)))) == 0)){
    warning("No data is available for one or more species, it/they won't contribute to the PSSD calculation.")
    # find which species has no data
    ind.sp.rem <- which(apply(DP, 2, function(x) length(which(!is.na(x)))) == 0)
    # remove those columns
    DP <- DP[,-ind.sp.rem]
    UFt <- UFt[,-ind.sp.rem]
    UFdd <- UFdd[,-ind.sp.rem]
  }

  # Create the step distributions (or triangular or trapezoidal) for each species
  # Create an empty matrix in which step distributions will be compiled
  NOEC_comb <- matrix(NA, ncol(DP), SIM,
                      dimnames = list(colnames(DP), NULL))

  # Fill in the matrix. If there is only one data point, NOEC stays the same. If  there are
  # 2 endpoints, a uniform distribution is produced. If  there are more than 2 endpoints, a step
  # distribution is produced. One line is for one species.
  require(trapezoid)
  require(mc2d)

  # store the corrected endpoints
  corr.endpoints <- DP/(UFdd*UFt)
  sort.endpoints <- apply(corr.endpoints, 2, sort)

  for (sp in colnames(DP)){

    # store the indices of the minimal and maximal data point
    ind.min <- which.min(corr.endpoints[,sp])
    ind.max <- which.max(corr.endpoints[,sp])

    # calculate the theoretical minimum and maximum of the distribution we are looking for
    sp.min <- corr.endpoints[ind.min,sp]*(1-(sqrt((CV.DP/2.45)^2 + (CV.UF/2.45)^2 + (CV.UF/2.45)^2)*2.45))
    sp.max <- corr.endpoints[ind.max,sp]*(1+(sqrt((CV.DP/2.45)^2 + (CV.UF/2.45)^2 + (CV.UF/2.45)^2)*2.45))

    # For species with one unique data point, NOEC stays the same:
    if(length(unique(sort.endpoints[[sp]])) == 1){
      NOEC_comb[sp,] <- rtrunc("rtriang", min = sp.min,
                               mode = sort.endpoints[[sp]][1],
                               max = sp.max,
                               n = SIM, linf = 0)

      # For species with two endpoints:
    } else if(length(sort.endpoints[[sp]]) == 2){
      # Create a trapezoidal distribution including both endpoints
      NOEC_comb[sp,] <- rtrunc("rtrapezoid", SIM,
                               mode1 = sort.endpoints[[sp]][1],
                               mode2 = sort.endpoints[[sp]][2],
                               min = sp.min, max = sp.max,
                               linf = 0)

      # For species with three endpoints or more:
    } else {

      # Sample from this step distribution for each species
      NOEC_comb[sp,] <- rmore(values = sort.endpoints[[sp]], max = sp.max, min = sp.min, N = SIM, linf = 0)

    }
  }

  # Sample species with typical proportions representative of a typical community (if terrestrial or marine, Troph.Perc need to be changed)
  Nb_Troph <- c(length(which(TrophLevel == 1)),
                length(which(TrophLevel == 2)),
                length(which(TrophLevel == 3)))
  # calculate the shares of the different trophic levels in the data
  Troph.Perc.Data <- Nb_Troph/ncol(DP)

  # identify the trophic level that will be unchanged
  if(length(which(Troph.Perc.Data < Troph.Perc.Typ)) == 1){
    lev.fix <- which(Troph.Perc.Data < Troph.Perc.Typ)
  } else {
    lev.fix <- which.max((Troph.Perc.Typ - Troph.Perc.Data)/Troph.Perc.Typ)
  }

  # create an empty vector to contain the corrected number of species for the species being corrected
  Nb_points <- rep(NA,3)
  # create an empty list with an element per trophic level
  NOEC_lev <- vector("list", 3)

  for(lev in 1:3){

    # for fix level, take as such
    if(lev == lev.fix){
      Nb_points[lev] <- Nb_Troph[lev.fix]

      # identify species corresponding to level lev
      ind.sp <- which(TrophLevel == lev) # vector of all indices for which the species level is the fixed one
      # store in list
      NOEC_lev[[lev]] <- NOEC_comb[ind.sp,]

    } else {

      # change the remaining levels
      Nb_points[lev] <- round(Nb_Troph[lev.fix] * Troph.Perc.Typ[lev] / Troph.Perc.Data[lev.fix]) # Nouveau nombre de lignes

      ind.sp <- which(TrophLevel == lev) # vector of all indices of the level
      # store in temporary matrix the NOEC distributions of all species of the level
      temp <- NOEC_comb[ind.sp,]

      NOEC_lev[[lev]] <- matrix(NA, Nb_points[lev],SIM)
      for(i in 1:SIM){
        NOEC_lev[[lev]][,i] <- sample(temp[,i], Nb_points[lev])
      }
    }

  }

  # combine that stuff
  NOEC_TrophCorr <- do.call(rbind,NOEC_lev)

  # return the whole matrix
  return(NOEC_TrophCorr)

}


#!/usr/bin/Rscript
# version 20130821

arg <- commandArgs(trailingOnly=TRUE)

mcmc_BiSSE <- function(
	infile1, # tree
	infile2, # trait table
	wd="default",
	TDI=0,
	out_file_stem="default",
	rho0=1,
	rho1=1,
	BD_model_0=1,
	BD_model_1=1,
	Trait_model=0,
	link_speciation=0,
	link_extinction=0,
	link_trait=0,
	prior_r=5,
	prior_a=1,
	prior_b=1,
	prior_q=1,
	trees=1,
	IT=20000,
	sampling_freq=100,
	print_freq=100,
	burnin=1000,
	win_1=0.5,
	win_2=0.25,
	win_3=0.05,
	categories=10,
	beta_shape=0.3,
	path_lib="default"
	) {	# end args

	if (wd=="default"){
		wd=dirname(infile1)
		}else{setwd(wd)}

	if (out_file_stem=="default"){
		st=basename(infile2)
		out_file= paste(st,"_BiSSEBMA.log", sep="")
		}else{out_file= paste(out_file_stem,".log", sep="")}

	if (path_lib=="default") {
		library(diversitree)
		}else{library(diversitree, , lib.loc=path_lib)}

	options(warn=-1) # hide warnings

	rhos=c(rho0, rho1)  #sampling fractions for state 0 and 1
	#out_file="boh.log"   #!!change in each analysis
	#TDI=0     # 0 parameter estimation, 1 TD integration (not real estimates)
	#trees=5  # one tree for TDI is advised

	#burnin=0   # run test to check the proportion
	#sampling_freq=25
	#print_freq=10
	#IT=200  # mcmc iterations (per tree)
	#categories=20

	use_exp=1 # 0: uniform priors; 1: exponential priors (extinction fraction has always uniform prior 0-1)
	M=c(5,5,1,1,5,5) # max parameter values (if uniform priors)
	# if exp no limit (max =1000)
	if (prior_r>0){M[1:2]=1000}
	if (prior_q>0){M[5:6]=1000}
	#shape_prior=c(2,2,1,1) # shape parameters of exp prior (net diversification and q rates)
	#constraints=c() # constant sp. [2], ex. [4], q. [6] const sp + ex is 2,4
	#PB=c() # 3: pb clade 1, 4: pb clade 2, 5: q0->1 =0; 6: q1->0 =0  # pure birth / irreversible rate models

	PB=NULL
	if (BD_model_0==0){PB=append(PB,3)}
	if (BD_model_1==0){PB=append(PB,4)}
	if (Trait_model==1){PB=append(PB,6)}
	if (Trait_model==2){PB=append(PB,5)}

	constraints=NULL
	if (link_speciation==1){constraints=append(constraints,2)}
	if (link_extinction==1){constraints=append(constraints,4)}
	if (link_trait==1)     {constraints=append(constraints,6)}

	shape_prior=c(prior_r,prior_a,prior_b,prior_q)
	win_size=c(win_1,win_1,win_2,win_2,win_3,win_3)

	Tree=read.nexus(file=infile1)
	traits=read.csv(file=infile2, header=TRUE, sep="\t")  #one single trait or create a vector
	states<-traits[,2]
	names(states)<-as.character(traits[,1])

	update_parameter <- function(i,d,M) {
		if (length(i)==1) {
			ii=abs(i+(runif(length(i),0,1)-.5)*d)
			if (ii>M) {ii=abs((M-(ii-M)))}
			if (ii>M) {ii=i}
			}
		ii}
	if (TDI>0)	{
		K=categories-1.
		k=0:K # K+1 categories
		beta=k/K
		alpha=beta_shape # categories are beta distributed
		temps=rev(beta^(1./alpha))
	} else{temps=c(1)}

	exp_prior = function(value,l,Mv) {
		if (l>0){
			l=1./l
			log(l)-l*(value)
			}else{log(1/Mv)}
	}

	beta_prior = function(a,b,value){
		dbeta(value, a, b, log = TRUE)
	}

	true_iteration=1
	cat(sprintf("it\tlikelihood\tprior\tacceptance\tl0\tl1\tm0\tm1\tr0\tr1\ta0\ta1\tq0\tq1\ttemp\ttree\n"), append=FALSE, file=out_file)
	cat(sprintf("it\tlikelihood\tprior\tacc\tl0\tl1\tm0\tm1\ttemp\ttree\n"))
	for (J in 1:length(temps)) { # Loop temperatures
		temperature=temps[J]
		d= win_size*(4 - 3*temperature)

		for  (t_index in 1:trees) { # loop trees

			if (class(Tree)=="multiPhylo"){current_tree=Tree[[J]]}
			else{current_tree=Tree}

			BISSE=make.bisse(current_tree, states, strict=F, sampling.f=rhos)
			pars=runif(min=.1,max=.5, 6) # initialize parameters

			if (temperature<1) {burnin=0}
			LIK=0
			acc=0
			for (iteration in 1:(IT+burnin)) { # MCMC loop
				if (iteration==1){
					likA = BISSE(pars)[1]
					parsA=pars}
				pars=parsA
				ind=sample(1:6,1)
				pars[ind]=update_parameter(pars[ind],d[ind],M[ind])
				pars[PB]=0
				if (length(constraints)>0) {
					if (is.element(2, constraints) & is.element(4, constraints)) {pars[constraints] = pars[constraints-1]}
					else if (is.element(2, constraints)) {pars[2]=(pars[1]/(1-pars[3]))*(1-pars[4])}
					else if (is.element(4, constraints)) {pars[4]=pars[3]*pars[1]/(pars[2]-pars[3]*pars[2]+pars[3]*pars[1])}
					if (is.element(6, constraints)) {pars[6] = pars[5]}
					}
				#cat("pars:", pars)
				l=pars[1:2]/(1-pars[3:4])
				m=-pars[3:4]*pars[1:2]/(pars[3:4]-1)
				#lik=BISSE(c(l,m,pars[5:6]))[1]

				# CALC PRIORS # exponential
				if (use_exp==1) {
					prior=sum(exp_prior(pars[1:2],shape_prior[1],M[1:2])) + sum(exp_prior(pars[5:6],shape_prior[4],M[5:6])) + sum(beta_prior(shape_prior[2],shape_prior[3],pars[3:4]))
				} else{
					prior=sum(log(1/M))
					if (min(M-temp)<0) {prior = -Inf}
					}  # uniform

				# CALC LIKELIHOOD
				if (prior> -Inf) {
					lik=try(BISSE(c(l,m,pars[5:6])))
					if (is.na(lik) | (class(lik) == "try-error" )) {lik=-Inf}
					} else{lik= -Inf}

				if (iteration==1){priorA=prior}

				tryCatch(
				{
				if ( (lik-likA)*temperature + (prior-priorA) >= log(runif(1,0,1)) ){
					likA=lik
					priorA=prior
					parsA=pars
					acc =acc + 1.
				}
				}
				,error = function(e) NULL
				)

				if (iteration %% print_freq ==0) {cat(sprintf("%s\t", round(c(true_iteration, likA, priorA, parsA, temperature, t_index),2)), "\n")}

				if (true_iteration %% sampling_freq ==0 & iteration>=burnin) {
					l=parsA[1:2]/(1-parsA[3:4])
					m=-parsA[3:4]*parsA[1:2]/(parsA[3:4]-1)
					LIK= LIK+likA
					cat(sprintf("%s\t", c(true_iteration, likA, priorA, acc/iteration, l, m, parsA, temperature, t_index)), "\n", append=TRUE, file=out_file)
				}

				if (iteration>burnin) {true_iteration = true_iteration+1}
				}
			}
		}

	if (TDI>0)	{

		out_marg= paste(out_file_stem,"_marginal.txt",sep="")

		d<-read.table(out_file, header=T) #, stringsAsFactors=F,sep="\t") #, row.names = NULL)
		trapezia<-aggregate(d$lik, list(d$temp),FUN="mean")
		stds<-aggregate(d$lik, list(d$temp),FUN="sd")

		ml=0
		for (i in 1:(dim(trapezia)[[1]]-1)){
			ml=ml+( (trapezia[i,2] + trapezia[(i+1),2])/2 * (trapezia[(i+1),1] - trapezia[(i),1]))
		}
		cat("\nmean log likelihoods:", trapezia[,2], file=out_marg, append=TRUE)
		cat("\ntemperatures:", unique(d$temp), file=out_marg, append=TRUE)
		cat("\nstd(lnL):", stds[,2], file=out_marg, append=TRUE)
		cat("\n\nLog Marginal Likelihood:", ml, file=out_marg, append=TRUE)

		cat("\n\n Log Marginal Likelihood:", ml)
		cat("
 The marginal likelihood can be used to compare different analyses and to perform model selection
 and hypothesis testing via Bayes factors.

 The marginal likelihood was saved to file:", out_marg,"\n\n")
		}

		cat("\n")
	}

mcmc_BiSSE(
	as.character(arg[1]),       # infile1, # tree
	as.character(arg[2]),       # infile2, # trait table
	as.character(arg[3]),       # wd,
	as.integer(arg[4]),         # TDI,
        as.character(arg[5]),       # out_file,
	as.double(arg[6]),	    # rho0,
	as.double(arg[7]),          # rho1,
        as.integer(arg[8]),         # BD_model_0,
        as.integer(arg[9]),         # BD_model_1,
        as.integer(arg[10]),        # Trait_model,
        as.integer(arg[11]),        # link_speciation,
        as.integer(arg[12]),        # link_extinction,
        as.double(arg[13]),         # link_trait,
        as.double(arg[14]),         # prior_r,
        as.double(arg[15]),         # prior_a,
        as.double(arg[16]),         # prior_b,
        as.double(arg[17]),         # prior_q,
        as.integer(arg[18]),        # trees,
        as.integer(arg[19]),        # iterations,
        as.integer(arg[20]),        # sampling_freq,
        as.integer(arg[21]),        # print_freq,
        as.integer(arg[22]),        # burnin,
        as.double(arg[23]),         # win_1,
        as.double(arg[24]),         # win_2,
        as.double(arg[25]),         # win_3,
        as.integer(arg[26]),        # categories,
        as.double(arg[27]),         # beta_shape
	as.character(arg[28])	    # path to diversitree library
	)