I'm trying to replicate this example two-level SEM from lavaan in OpenMx http://lavaan.ugent.be/tutorial/multilevel.html
Lavaan's log-likelihood is -23309.87 but with the following OpenMx code I get only -26495.56. I have also tried to use the estimated parameters from lavaan as fixed parameters in the OpenMx model - the log-likelihood gets even worse then. I assume that the model structure in OpenMx is not the same as the structure model in lavaan.
A few notes on the code: lavaan doesn't allow a connection from an observed variable to a latent variable (I introduced 'pseudo-latent' variables (I prefixed them with '_'): they have have one loading (with factor 1) to the observed variable, have its mean, its (co)variance, and the observed variable has no residual - lavaan does the same internally, see inspect(lavaan_fit, what='est')); lavaan seems to use the biased (co)variance (I resale the covariance matrix with scale/cluster_scale).
library('lavaan') library('OpenMx') data <- Demo.twolevel data$cluster <- sapply(data$cluster, as.factor) y <- c('y1', 'y2', 'y3') x <- c('x1', 'x2', 'x3') x_ <- c('_x1', '_x2', '_x3') w <- c('w1', 'w2') w_ <- c('_w1', '_w2') manifest_l1 <- c(y, x) latent_l1 <- c('fw', x_) manifest_l2 <- c(y, w) latent_l2 <- c('fb', w_) level2 <- data[!duplicated(data$cluster),] scale <- (dim(data)[1] - 1.0) / dim(data)[1] cluster_scale <- (dim(level2)[1] - 1.0) / dim(level2)[1] between <- mxModel( "between", type="RAM", manifestVars=manifest_l2, latentVars=latent_l2, mxData(observed=level2, type="raw", primaryKey="cluster"), mxPath(from=y, arrows=2, free=TRUE, values=diag(var(data[y], na.rm=TRUE)) / 2), mxPath(from=w, arrows=2, free=FALSE, values=0), mxPath(from='fb', arrows=2, free=FALSE, values=1), mxPath(from=w_, to=w, arrows=1, free=FALSE, values=1), mxPath(from=w_, arrows=2, free=FALSE, values=diag(var(level2[w], na.rm=TRUE)) * cluster_scale), mxPath(from='_w1', to='_w2', arrows=2, free=FALSE, values=var(level2[w], na.rm=TRUE)['w1', 'w2'] * cluster_scale), mxPath(from='fb', to=y, arrows=1, free=TRUE, values=1, labels=c('fb_y1', 'fb_y2', 'fb_y3')), mxPath(from=w_, to='fb', arrows=1, free=TRUE, values=1, labels=c('w1_fb', 'w2_fb')), mxPath(from='one', to=y, free=TRUE, values=colMeans(data[y], na.rm=TRUE)), mxPath(from='one', to=w, free=FALSE, values=0), mxPath(from='one', to=w_, free=FALSE, values=colMeans(level2[w], na.rm=TRUE))) within <- mxModel( "Demo_twolevel", type="RAM", between, manifestVars=manifest_l1, latentVars=latent_l1, mxData(observed=data, type="raw"), mxPath(from=y, arrows=2, free=TRUE, values=diag(var(data[y], na.rm=TRUE)) / 2), mxPath(from=x, arrows=2, free=FALSE, values=0), mxPath(from='fw', arrows=2, free=FALSE, values=1), mxPath(from=x_, to=x, arrows=1, free=FALSE, values=1), mxPath(from=x_, arrows=2, free=FALSE, values=diag(var(data[x], na.rm=TRUE)) * scale), mxPath(from='_x1', to='_x2', arrows=2, free=FALSE, values=var(data[x], na.rm=TRUE)['x1', 'x2'] * scale), mxPath(from='_x1', to='_x3', arrows=2, free=FALSE, values=var(data[x], na.rm=TRUE)['x1', 'x3'] * scale), mxPath(from='_x2', to='_x3', arrows=2, free=FALSE, values=var(data[x], na.rm=TRUE)['x2', 'x3'] * scale), mxPath(from='fw', to=y, arrows=1, free=TRUE, values=1, labels=c('fw_y1', 'fw_y2', 'fw_y3')), mxPath(from=x_, to='fw', arrows=1, free=TRUE, values=1, labels=c('x1_fw', 'x2_fw', 'x3_fw')), mxPath('between.y1', 'y1', values=1, free=FALSE, joinKey="cluster"), mxPath('between.y2', 'y2', values=1, free=FALSE, joinKey="cluster"), mxPath('between.y3', 'y3', values=1, free=FALSE, joinKey="cluster"), mxPath(from='one', to=manifest_l1, free=FALSE, values=0), mxPath(from='one', to=x_, free=FALSE, values=colMeans(data[x], na.rm=TRUE))) fit <- mxRun(within) summary(fit)