#
#   Copyright 2007-2018 by the individuals mentioned in the source code history
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
# 
#        http://www.apache.org/licenses/LICENSE-2.0
# 
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
#------------------------------------------------------------------------------

#------------------------------------------------------------------------------
# Author: Michael D. Hunter
# Date: 2016-02-03
# Filename: univACErSEM.R
# Purpose: Define a behavior genetics single-trait ACE model as a 
#  Relational SEM (rSEM)
#------------------------------------------------------------------------------


#------------------------------------------------------------------------------
require(OpenMx)


#------------------------------------------------------------------------------
# Prepare Data

data("twinData", package="OpenMx")
selVars <- c('bmi1','bmi2','zyg')
wideData <- subset(twinData, zyg %in% c(1, 3), selVars)
wideData$rel <- c(1, NA, .5)[wideData$zyg]
wideData$famID <- 1:nrow(wideData)
tallData <- reshape(wideData, varying=c('bmi1', 'bmi2'), v.names='bmi',
		    timevar='twin', times=1:2, idvar='famID', direction='long')
tallData$personID <- 1:nrow(tallData)
tallData$relsqrt <- sqrt(tallData$rel)
tallData$relu <- sqrt(1-tallData$rel)
tallData <- tallData[order(tallData$famID, tallData$twin),
		     c('famID', 'personID', 'twin', 'rel',
		       'relsqrt', 'relu', 'bmi')]
wData <- tallData
bData <- tallData[!duplicated(tallData$famID),
		  c('famID', 'rel', 'relsqrt')]


#------------------------------------------------------------------------------
# Between Model

bModel <- mxModel(
    'between', type="RAM",
    mxData(type="raw", observed=bData, primaryKey="famID"),
    latentVars = c("C", "AC"),
    mxPath("C", arrows=2, values=1, labels="v_C", lbound=1e-6),
    mxPath("AC", arrows=2, values=1, labels="v_A", lbound=1e-6))


#------------------------------------------------------------------------------
# Within Model

wModel <- mxModel(
    'within', type="RAM", bModel,
    mxData(type="raw", observed=wData),
    manifestVars = 'bmi',
    latentVars = c("E", "AU"),
    mxPath(from="one", to="bmi", arrows=1, free=TRUE, values=20, labels="mean"),
    mxPath('E', arrows=2, values=1, labels="v_E", lbound=1e-6),
    mxPath('AU', arrows=2, values=1, labels="v_A", lbound=1e-6),
    mxPath('AU', 'bmi', values=1, labels='data.relu', free=FALSE),
    mxPath('E', 'bmi', free=FALSE, values=1),
    mxPath('between.C', 'bmi', values=1,
	   free=FALSE, joinKey="famID"),
    mxPath('between.AC', 'bmi', values=1, arrows=1, free=FALSE,
	   labels='data.relsqrt', joinKey="famID"))


#------------------------------------------------------------------------------
# Run 'em
wRun <- mxRun(wModel)


#------------------------------------------------------------------------------
# Take a look

summary(wRun)

# Cf. inst/models/passing/univACEP.R

#Mx answers hard-coded
#1: Heterogeneity Model
Mx.A <- 0.6173023
Mx.C <- 5.595822e-14
Mx.E <- 0.1730462
Mx.M <- 21.39293
Mx.LL_ACE <- 4067.663

wparam <- mxEval(rbind(v_A, v_C, v_E, mean), wRun)
mparam <- rbind(Mx.A, Mx.C, Mx.E, Mx.M)
omxCheckCloseEnough(wparam, mparam, .001)

omxCheckCloseEnough(-2*logLik(wRun), Mx.LL_ACE, .001)


#------------------------------------------------------------------------------
# Same model, but with constant between-level transition matrix

bLatent <- c('C', 'AC')
bModel2 <- mxModel(
    'between',
    mxData(type="raw", observed=bData, primaryKey="famID"),
    latentVars = bLatent,
    mxMatrix(name="F", nrow=0, ncol=2, dimnames=list(NULL, bLatent)),
    mxAlgebra(data.rel * v_A, name="rel_v_A"),
    mxMatrix("Symm", name="S", nrow=2, ncol=2, dimnames=list(bLatent,bLatent),
	     free=c(TRUE,FALSE,FALSE), labels=c("v_C", NA, "rel_v_A[1,1]"),
	     values=c(1,0,1), lbound=c(1e-6,NA,1e-6)),
    mxMatrix(name="A", nrow=2, ncol=2, values=0,
	     dimnames=list(bLatent,bLatent)),
    mxFitFunctionML(),
    mxExpectationRAM())

#------------------------------------------------------------------------------
# Within Model

wModel2 <- mxModel(
    'within', type="RAM", bModel2,
    mxData(type="raw", observed=wData),
    manifestVars = 'bmi',
    latentVars = c("E", "AU"),
    mxPath(from="one", to="bmi", arrows=1, free=TRUE,
	   values=20, labels="mean"),
    mxPath('E', arrows=2, values=1, labels="v_E", lbound=1e-6),
    mxPath('AU', arrows=2, values=1, labels="v_A", lbound=1e-6),
    mxPath('AU', 'bmi', values=1, labels='data.relu', free=FALSE),
    mxPath('E', 'bmi', free=FALSE, values=1),
    mxPath('between.C', 'bmi', values=1,
	   free=FALSE, joinKey="famID"),
    mxPath('between.AC', 'bmi', values=1,
	   free=FALSE, joinKey="famID"))

# This isn't a huge speed-up because the per-cluster covariance matrix
# is already small in the version above.
wRun2 <- mxRun(wModel2)

wparam <- mxEval(rbind(v_A, v_C, v_E, mean), wRun2)
mparam <- rbind(Mx.A, Mx.C, Mx.E, Mx.M)
omxCheckCloseEnough(wparam, mparam, .001)

omxCheckCloseEnough(-2*logLik(wRun2), Mx.LL_ACE, .001)

omxCheckCloseEnough(wRun2$expectation$debug$rampartUsage, 867, 1)
