### Simulation of parameter estimation in GLMM
#     Copyright (C) 2022 anonymous authors
# 
# This program is only for anonymous peer review and not to be distributed or used for any other purpose.

#load libraries
library(lme4)
library(optimx)
library(statmod)

###functions

set.seed(12)

#generate dataset
#n - number of participants
#N - number of measurement categories in total
generateData=function(n,N) {
  #generate dataset for OWM with independent variables
  testdata=data.frame(ids=as.factor(rep(1:n,each=N/n)),
                      angle=rep(c(-72,0,72),N/3), #within subjects
                      blockNumeric=rep(c(0,1),each=3,N/6)) #within subjects (repeat 3 times each for each factor of angle)
  
  #normalize angle (already centered)
  testdata$angle=testdata$angle/144
  #random intercept for id (normally distributed for all distributions)
  testdata$randomIntercept=rep(rnorm(n),each=N/n)
  #generate vector of means for reaction time (values based on HL)
  #set values for fixed effects
  intercept=990
  factorAngle=220
  factorBlock=110
  factorBlockAngle=0
  #generate true means as linear combinations
  testdata$means=intercept+
    testdata$randomIntercept*50+
    factorAngle*testdata$angle+
    factorBlock*testdata$blockNumeric+
    factorBlockAngle*testdata$blockNumeric*testdata$angle
  #}
  #different means for log odds to create accuracy data based on HL
  intercept=3.3
  factorAngle=-1
  factorBlock=0
  factorBlockAngle=-1.5
  testdata$logOdds=intercept+
    testdata$randomIntercept+
    factorAngle*testdata$angle+
    factorBlock*testdata$blockNumeric+
    factorBlockAngle*testdata$blockNumeric*testdata$angle
  #convert to probability for binomial distribution
  testdata$prob=exp(testdata$logOdds)/(1+exp(testdata$logOdds))
  #generate dependent variable (with random error)
  testdata$binomial=rbinom(N,1,prob=testdata$prob)
  testdata$inverseGaussian=rinvgauss(N, testdata$means, 100000)
  testdata$gamma=rgamma(N, testdata$means/50,1/50) 

  return(testdata)
}

#get fixed effects of the binomial model for binomial distributed data
getFixefGLMMbinomial=function(testdata){
  glmmBinomial=glmer(binomial~angle*blockNumeric+(1|ids),
                     family=binomial(),data=testdata)
  return(fixef(glmmBinomial))
}
#get fixed effects of the inverse gaussian model for inverse gaussian  distributed data
getFixefGLMMinverseGaussian=function(testdata){
  glmmInvGauss=glmer(inverseGaussian~angle*blockNumeric+(1|ids),
                     family=inverse.gaussian(link=identity),data=testdata)
  return(fixef(glmmInvGauss))
}
#get fixed effects of the gamma model for gamma distributed data
getFixefGLMMgamma=function(testdata){
  glmmGamma=glmer(gamma~angle*blockNumeric+(1|ids),
                  family=Gamma(link=identity),data=testdata)
  return(fixef(glmmGamma))
}

###script 

#set seed for reproducibility
set.seed(12)
#set variables
numSims=100 #number of simulations
n=150 #participants
N=n*6*16 #6 times the number of measurements per condition (6 conditions)
#create arrays for saving data (4 fixed effects)
fixefBinoms=array(numeric(),dim=c(4,numSims))
fixefInvGauss=array(numeric(),dim=c(4,numSims))
fixefGamma=array(numeric(),dim=c(4,numSims))
#run simulations
for(i in 1:numSims){
  #generate dataset
  testdata=generateData(n,N)
  #get fixed effects and save to arrays
  fixefBinoms[,i]=getFixefGLMMbinomial(testdata)
  fixefInvGauss[,i]=getFixefGLMMinverseGaussian(testdata)
  fixefGamma[,i]=getFixefGLMMgamma(testdata)
}
#get mean parameter estimates 

rowMeans(fixefBinoms)

rowMeans(fixefInvGauss)

rowMeans(fixefGamma)

#get sd of estimates (i.e., SE since 100 simulations run)
library(matrixStats)
rowSds(fixefBinoms)

rowSds(fixefInvGauss)

rowSds(fixefGamma)

