ACE RAM model with ordinal manifest

Posted on
No user picture. Leo Joined: 01/09/2020
Hi.

I've been trying everything to get an ordinal manifest working in RAM models but I can't get it done. Also, didn't find anything online about this, as most examples have matrix specification. Would be very appreciated to get some help. Besides from the solution below, I have also tried every possible way with mxthreshold and umxthresholdmatrix.


obesityLevels = c('normal', 'obese')
cutPoints = quantile(twinData[, "bmi1"], probs = .2, na.rm = TRUE)
twinData$obese1 = cut(twinData$bmi1, breaks = c(-Inf, cutPoints, Inf), labels = obesityLevels)
twinData$obese2 = cut(twinData$bmi2, breaks = c(-Inf, cutPoints, Inf), labels = obesityLevels)
# Step 2: Make the ordinal variables into umxFactors (ordered, with the levels found in the data)
selVars = c("obese1", "obese2")
twinData[, selVars] = umxFactor(twinData[, selVars])
#tmp = umxThresholdMatrix(twinData, selDVs = selVars, sep = "", verbose = TRUE)

tmp = umx_make_twin_data_nice(data=twinData, sep="", zygosity="zygosity", numbering=1:2)

tmp = umx_scale_wide_twin_data(varsToScale= c("wt", "ht"), sep= "_T", data= tmp)
mzData = subset(tmp, zygosity %in% c("MZFF", "MZMM"))
dzData = subset(tmp, zygosity %in% c("DZFF", "DZMM"))

latents = c("A1", "C1", "E1", "A2", "C2", "E2")
manifests = c("obese_T1", "obese_T2")

latVariances <- mxPath( from=latents, arrows=2,
free=FALSE, values=1 )
manifestsVariances <- mxPath( from=manifests, arrows=2,
free=FALSE, values=1 )
# means of latent variables
latMeans <- mxPath( from="one", to=latents, arrows=1,
free=FALSE, values=0 )
# means of observed variables
obsMeans <- mxPath( from="one", to=manifests, arrows=1,
free=F, values=0, labels="mean" )
# path coefficients for twin 1
pathAceT1 <- mxPath( from=c("A1","C1","E1"), to="obese_T1", arrows=1,
free=TRUE, values = 1, label=c("a","c","e") )
# path coefficients for twin 2
pathAceT2 <- mxPath( from=c("A2","C2","E2"), to="obese_T2", arrows=1,
free=TRUE, values = 1, label=c("a","c","e") )
# covariance between C1 & C2
covC1C2 <- mxPath( from="C1", to="C2", arrows=2,
free=FALSE, values=1 )
# covariance between A1 & A2 in MZ twins
covA1A2_MZ <- mxPath( from="A1", to="A2", arrows=2,
free=FALSE, values=1 )
# covariance between A1 & A2 in DZ twins
covA1A2_DZ <- mxPath( from="A1", to="A2", arrows=2,
free=FALSE, values=.5 )

paths <- list( latVariances, latMeans, obsMeans,
pathAceT1, pathAceT2, covC1C2, manifestsVariances )

dataMZ <- mxData(observed=mzData, type = "raw")
dataDZ <- mxData(observed=dzData, type = "raw")

#threshold <- mxThreshold(vars=c("obese_T1", "obese_T2"), nThresh=c(1), free = T)

threshold <- mxMatrix("Full", nrow=1, ncol=2, byrow=T, name="thresh",
dimnames = list(c(), manifests),
free = c(T, T),
values = c(-.8, -.8),
)

expect <- mxExpectationRAM(A="A", S="S", F="F", M="M", thresholds = "thresh")

fitfunction = mxFitFunctionML()

modelMZ <- mxModel(model="MZ", type="RAM", manifestVars=manifests,
latentVars=latents, paths, covA1A2_MZ, dataMZ, threshold, expect, fitfunction)
modelDZ <- mxModel(model="DZ", type="RAM", manifestVars=manifests,
latentVars=latents, paths, covA1A2_DZ, dataDZ, threshold, expect, fitfunction)

obj <- mxFitFunctionMultigroup(c("MZ", "DZ"))

modelACE <- mxModel("ACE", modelMZ, modelDZ, obj)

fitACE <- mxRun(modelACE)

I have tried fixing the threshold across twins and zygosity, but to no avail. The results either are extremely high estimates for the paths with high SEs, or they are just plainly wrong (if compared to umx results). Help is great appreciated,
thank you

Replied on Mon, 07/06/2020 - 10:15
Picture of user. jpritikin Joined: 05/23/2012

I think the issue is that your variances don't add up. You probably need to free the variances and add a constraint to target the ordinal variances at 1.0. If I fit these data with umx,


f1 <- umxACEv(selDVs='obese', sep="_T", dzData=dzData, mzData=mzData)

you can inspect the content of the model and find such a constraint,


f1$top$constrain_Bin_var_to_1

Replied on Mon, 07/06/2020 - 12:18
No user picture. Leo Joined: 01/09/2020

Thank you for your reply. I've added this now:


A <- mxAlgebra( expression=a*a, name="A" )
C <- mxAlgebra( expression=c*c, name="C" )
E <- mxAlgebra( expression=e*e, name="E" )
V <- mxAlgebra( expression=A+C+E, name="V" )
a2 <- mxAlgebra( expression=A/V, name="a2")
c2 <- mxAlgebra( expression=C/V, name="c2")
e2 <- mxAlgebra( expression=E/V, name="e2")

constraint <- mxConstraint(V == 1, name = "constraintbinary")

modelACE <- mxModel("ACE", modelMZ, modelDZ, obj, A, C, E, V, a2, c2, e2, constraint)

This addition is successful in constraining the variance to one. However, results are still vastly wrong and the standard errors can't be estimated. You mentioned freeing variances. I have tried that to no avail. Is there anything else to do? Thank you

P.S. the model is easily replicable as it's simply the twinData dataset in umx/OpenMx

Replied on Mon, 07/06/2020 - 12:50
No user picture. Leo Joined: 01/09/2020

I got it working now. In addition to the Mxconstraint, I had to delete the "manifestsVariances" path. What is the explanation for this? I just want to be sure to understand. Thank you

This is the working script:

latents = c("A1", "C1", "E1", "A2", "C2", "E2")
manifests = c("obese_T1", "obese_T2")

latVariances <- mxPath( from=latents, arrows=2,
free=F, values=1)
#manifestsVariances <- mxPath( from=manifests, arrows=2,
# free=F, values=1 )
# means of latent variables
latMeans <- mxPath( from="one", to=latents, arrows=1,
free=FALSE, values=0 )
# means of observed variables
obsMeans <- mxPath( from="one", to=manifests, arrows=1,
free=F, values=0, labels="mean" )
# path coefficients for twin 1
pathAceT1 <- mxPath( from=c("A1","C1","E1"), to="obese_T1", arrows=1,
free=TRUE, values = 1, label=c("a","c","e"), values=.5)
# path coefficients for twin 2
pathAceT2 <- mxPath( from=c("A2","C2","E2"), to="obese_T2", arrows=1,
free=TRUE, values = 1, label=c("a","c","e"), values=.5 )
# covariance between C1 & C2
covC1C2 <- mxPath( from="C1", to="C2", arrows=2,
free=FALSE, values=1 )
# covariance between A1 & A2 in MZ twins
covA1A2_MZ <- mxPath( from="A1", to="A2", arrows=2,
free=FALSE, values=1 )
# covariance between A1 & A2 in DZ twins
covA1A2_DZ <- mxPath( from="A1", to="A2", arrows=2,
free=FALSE, values=.5 )

paths <- list( latVariances, latMeans, obsMeans,
pathAceT1, pathAceT2, covC1C2 )

dataMZ <- mxData(observed=mzData, type = "raw")
dataDZ <- mxData(observed=dzData, type = "raw")

threshold <- mxThreshold(vars=c("obese_T1", "obese_T2"), nThresh=c(1, 1), free = T, labels = "true")

modelMZ <- mxModel(model="MZ", type="RAM", manifestVars=manifests,
latentVars=latents, paths, covA1A2_MZ, dataMZ, threshold)
modelDZ <- mxModel(model="DZ", type="RAM", manifestVars=manifests,
latentVars=latents, paths, covA1A2_DZ, dataDZ, threshold)

obj <- mxFitFunctionMultigroup(c("MZ", "DZ"))

A <- mxAlgebra( expression=a*a, name="A" )
C <- mxAlgebra( expression=c*c, name="C" )
E <- mxAlgebra( expression=e*e, name="E" )
V <- mxAlgebra( expression=A+C+E, name="V" )
a2 <- mxAlgebra( expression=A/V, name="a2")
c2 <- mxAlgebra( expression=C/V, name="c2")
e2 <- mxAlgebra( expression=E/V, name="e2")

constraint <- mxConstraint(V == 1, name = "constraintbinary")

modelACE <- mxModel("ACE", modelMZ, modelDZ, obj, A, C, E, V, a2, c2, e2, constraint)

fitACE <- mxRun(modelACE)

Replied on Mon, 07/06/2020 - 13:11
Picture of user. jpritikin Joined: 05/23/2012

In reply to by Leo

> What is the explanation for this?

You are accounting for the error variance in the E component. There is no additional error variance to account for or estimate.

Replied on Fri, 07/10/2020 - 19:17
No user picture. Leo Joined: 01/09/2020

In reply to by jpritikin

Thank you for your helpful reply. When switching to the bivariate case (umxACEv style), how do I put in the constraint? Particularly if I add another continuous manifest, everything blows up.
Replied on Fri, 07/10/2020 - 20:14
No user picture. Leo Joined: 01/09/2020

This is my script: I have followed the documentation on Joint Ordinal continuous manifests.


mzData = subset(tmp, zygosity %in% c("MZFF", "MZMM"))
dzData = subset(tmp, zygosity %in% c("DZFF", "DZMM"))

latents = c("A1", "C1", "E1", "A2", "C2", "E2", "A3", "C3", "E3", "A4", "C4", "E4")
manifests = c("wt_T1", "obese_T1", "wt_T2", "obese_T2")

latVariances <- mxPath( from=c("A2", "C2", "E2", "A4", "C4", "E4"), arrows=2,
free=T, labels = c("A11", "C11", "E11", "A11", "C11", "E11"))
latVariances2 <- mxPath( from=c("A1", "C1", "E1", "A3", "C3", "E3"), arrows=2,
free=T, labels = c("A21", "C21", "E21", "A21", "C21", "E21"))
#manifestsVariances <- mxPath( from=c("obese_T1", "obese_T2"), arrows=2,
# free=F, values=1 )
# means of latent variables
latMeans <- mxPath( from="one", to=latents, arrows=1,
free=FALSE, values=0 )
# means of observed variables
obsMeans <- mxPath( from="one", to=c("obese_T1", "obese_T2"), arrows=1,
free=F, values=0, labels="mean" )
obsMeans2 <- mxPath( from="one", to=c("wt_T1", "wt_T2"), arrows=1,
free=T, values=0, labels="mean2" )
# path coefficients for twin 1
pathAceT1 <- mxPath( from=c("A1","C1","E1"), to="obese_T1", arrows=1,
free=F, values = 1)
# path coefficients for twin 2
pathAceT2 <- mxPath( from=c("A3","C3","E3"), to="obese_T2", arrows=1,
free=F, values = 1)

# path coefficients for twin 1
pathAceT1_2 <- mxPath( from=c("A2","C2","E2"), to="wt_T1", arrows=1,
free=F, values = 1)
# path coefficients for twin 2
pathAceT2_2 <- mxPath( from=c("A4","C4","E4"), to="wt_T2", arrows=1,
free=F, values = 1)

# covariance between C1 & C2
covC1C2 <- mxPath( from="C1", to="C3", arrows=2,
free=FALSE, values=1 )
# covariance between A1 & A2 in MZ twins
covA1A2_MZ <- mxPath( from="A1", to="A3", arrows=2,
free=FALSE, values=1 )
# covariance between A1 & A2 in DZ twins
covA1A2_DZ <- mxPath( from="A1", to="A3", arrows=2,
free=FALSE, values=.5 )

# covariance between C1 & C2
covC1C2_2 <- mxPath( from="C2", to="C4", arrows=2,
free=FALSE, values=1 )
# covariance between A1 & A2 in MZ twins
covA1A2_MZ_2 <- mxPath( from="A2", to="A4", arrows=2,
free=FALSE, values=1 )
# covariance between A1 & A2 in DZ twins
covA1A2_DZ_2 <- mxPath( from="A2", to="A4", arrows=2,
free=FALSE, values=.5 )

### gen cov

covA1 <- mxPath(from = "A1", to = "A2", arrows=2, free = T, labels = "covA", lbound = 0, ubound = 1)
covA2 <- mxPath(from = "A3", to = "A4", arrows=2, free = T, labels = "covA", lbound = 0, ubound = 1)

covC1 <- mxPath(from = "C1", to = "C2", arrows=2, free = T, labels = "covC", lbound = 0, ubound = 1)
covC2 <- mxPath(from = "C3", to = "C4", arrows=2, free = T, labels = "covC", lbound = 0, ubound = 1)

covE1 <- mxPath(from = "E1", to = "E2", arrows=2, free = T, labels = "covE", lbound = 0, ubound = 1)
covE2 <- mxPath(from = "E3", to = "E4", arrows=2, free = T, labels = "covE", lbound = 0, ubound = 1)

paths <- list( latVariances, latVariances2, latMeans, obsMeans, obsMeans2,
pathAceT1, pathAceT2, covC1C2,
pathAceT1_2, pathAceT2_2, covC1C2_2,
covA1, covA2, covC1, covC2, covE1, covE2)

dataMZ <- mxData(observed=mzData, type = "raw")
dataDZ <- mxData(observed=dzData, type = "raw")

threshold <- mxThreshold(vars=c("obese_T1", "obese_T2"), nThresh=c(1, 1), free = T, labels = "true")

modelMZ <- mxModel(model="MZ", type="RAM", manifestVars=manifests,
latentVars=latents, paths, covA1A2_MZ, covA1A2_MZ_2, dataMZ, threshold)
modelDZ <- mxModel(model="DZ", type="RAM", manifestVars=manifests,
latentVars=latents, paths, covA1A2_DZ, covA1A2_DZ_2, dataDZ, threshold)

obj <- mxFitFunctionMultigroup(c("MZ", "DZ"))

constraint <- mxConstraint(A21+C21+E21 == 1, name = "constraintbinary")
constraint2 <- mxConstraint(A11+C11+E11 == 1, name = "constraintbinary2")

modelACE <- mxModel("ACE", modelMZ, modelDZ, obj)

fitACE <- mxRun(modelACE)

summary(fitACE)

# in umxacev?
blub = umxACEv(name = "blub", selDVs = c("wt", "obese"), mzData = mzData, dzData = dzData, sep = "_T")
umxSummary(blub, showRg = T, std = F)

Replied on Sun, 07/12/2020 - 05:57
No user picture. Leo Joined: 01/09/2020

I have been continuously working on it throughout the weekend but haven't been able to get it to work. So my aim is to build a bivariate ACE Ram model using the variance components approach. For simplicity I selected two ordinal variables now (2 for each twin).

In a first step I just want to replicate this:

test = umxACEv(name= "bla", selDVs = c("pop0100_w1", "pop0100_w3"), mzData = mzData, dzData = dzData, sep = "_T")

which works excellently.

What I think I can understand is the following:
- mean is not fixed
- variance is not fixed
- first two thresholds are fixed but third one is estimated
- paths from latents to manifests are fixed at 1

So I have tried integrating this, as well as trying different combinations, but they all results either in bogus results or errors. I have tried estimating paths, fixing means, fixing variance, different thresholds and combinations thereof but nothing is working. Any ideas?

Here is the code: Thank you very much


ordDVs = c("pop0100_w1_T1", "pop0100_w1_T2", "pop0100_w3_T1", "pop0100_w3_T2")
cgr2[, ordDVs] = umxFactor(cgr2[, ordDVs])

# subset MZ DZ data
mzData = subset(cgr2, zyg0102w1 == 1)
dzData = subset(cgr2, zyg0102w1 == 2)

manifests = c("pop0100_w1_T1", "pop0100_w1_T2", "pop0100_w3_T1", "pop0100_w3_T2")

latents = c("A1", "C1", "E1", "A2", "C2", "E2", "A3", "C3", "E3", "A4", "C4", "E4")

latVariances <- mxPath( from=c("A2", "C2", "E2", "A4", "C4", "E4"), arrows=2,
free=T, values = 1, labels = c("A11", "C11", "E11", "A11", "C11", "E11"))
latVariances2 <- mxPath( from=c("A1", "C1", "E1", "A3", "C3", "E3"), arrows=2,
free=T, values = 1, labels = c("A22", "C22", "E22", "A22", "C22", "E22"))

# means of latent variables
latMeans <- mxPath( from="one", to=latents, arrows=1,
free=FALSE, values=0 )
# means of observed variables
obsMeans <- mxPath( from="one", to=c("pop0100_w1_T1", "pop0100_w1_T2"), arrows=1,
free=T, values=0, labels="mean" )
obsMeans2 <- mxPath( from="one", to=c("pop0100_w3_T1", "pop0100_w3_T2"), arrows=1,
free=T, values=0, labels="mean2" )
# path coefficients for twin 1
pathAceT1 <- mxPath( from=c("A1","C1","E1"), to="pop0100_w1_T1", arrows=1,
free=F, values = 1)
# path coefficients for twin 2
pathAceT2 <- mxPath( from=c("A3","C3","E3"), to="pop0100_w1_T2", arrows=1,
free=F, values = 1)

# path coefficients for twin 1
pathAceT1_2 <- mxPath( from=c("A2","C2","E2"), to="pop0100_w3_T1", arrows=1,
free=F, values = 1)
# path coefficients for twin 2
pathAceT2_2 <- mxPath( from=c("A4","C4","E4"), to="pop0100_w3_T2", arrows=1,
free=F, values = 1)

# covariance between C1 & C2
covC1C2 <- mxPath( from="C1", to="C3", arrows=2,
free=FALSE, values=1 )
# covariance between A1 & A2 in MZ twins
covA1A2_MZ <- mxPath( from="A1", to="A3", arrows=2,
free=FALSE, values=1 )
# covariance between A1 & A2 in DZ twins
covA1A2_DZ <- mxPath( from="A1", to="A3", arrows=2,
free=FALSE, values=.5 )

# covariance between C1 & C2
covC1C2_2 <- mxPath( from="C2", to="C4", arrows=2,
free=FALSE, values=1 )
# covariance between A1 & A2 in MZ twins
covA1A2_MZ_2 <- mxPath( from="A2", to="A4", arrows=2,
free=FALSE, values=1 )
# covariance between A1 & A2 in DZ twins
covA1A2_DZ_2 <- mxPath( from="A2", to="A4", arrows=2,
free=FALSE, values=.5 )

### gen cov

covA1 <- mxPath(from = "A1", to = "A2", arrows=2, free = T, labels = "covA")
covA2 <- mxPath(from = "A3", to = "A4", arrows=2, free = T, labels = "covA")

covC1 <- mxPath(from = "C1", to = "C2", arrows=2, free = T, labels = "covC")
covC2 <- mxPath(from = "C3", to = "C4", arrows=2, free = T, labels = "covC")

covE1 <- mxPath(from = "E1", to = "E2", arrows=2, free = T, labels = "covE")
covE2 <- mxPath(from = "E3", to = "E4", arrows=2, free = T, labels = "covE")

paths <- list( latVariances, latVariances2, latMeans, obsMeans, obsMeans2,
pathAceT1, pathAceT2, covC1C2,
pathAceT1_2, pathAceT2_2, covC1C2_2,
covA1, covA2, covC1, covC2, covE1, covE2)

dataMZ <- mxData(observed=mzData, type = "raw")
dataDZ <- mxData(observed=dzData, type = "raw")

threshold <- mxThreshold(vars=c("pop0100_w1_T1", "pop0100_w1_T2"), nThresh=c(3, 3), free = c(F, F, T),
labels = c("true1", "true2", "true3"), values = c(-0.33, 1.36, 2),
lbound = c(NA, 0.01, 0.01))
threshold2 <- mxThreshold(vars=c("pop0100_w3_T1", "pop0100_w3_T2"), nThresh=c(3, 3), free = c(F, F, T),
labels = c("true4", "true5", "true6"), values = c(-0.8, 1.5, 3),
lbound = c(NA, 0.01, 0.01))

modelMZ <- mxModel(model="MZ", type="RAM", manifestVars=manifests,
latentVars=latents, paths, covA1A2_MZ, covA1A2_MZ_2, dataMZ, threshold, threshold2)
modelDZ <- mxModel(model="DZ", type="RAM", manifestVars=manifests,
latentVars=latents, paths, covA1A2_DZ, covA1A2_DZ_2, dataDZ, threshold, threshold2)

obj <- mxFitFunctionMultigroup(c("MZ", "DZ"))

#constraint <- mxConstraint(A11+C11+E11 == 1, name = "constraintordinal")
#constraint2 <- mxConstraint(A22+C22+E22 == 1, name = "constraintordinal2")

modelACE <- mxModel("ACE", modelMZ, modelDZ, obj)

fitACE <- mxRun(modelACE)

summary(fitACE)

Replied on Sun, 07/12/2020 - 16:42
Picture of user. AdminRobK Joined: 01/24/2014

In reply to by Leo

I don't see anyplace in your syntax where you put the MxConstraints into an `mxModel()` statement. They won't do anything if they're sitting in R's workspace, and aren't part of `modelACE`'s namespace. I'd suggest creating them before creating `modelMZ` and `modelDZ`, and putting them into only one of those two MxModels.

Edit: well, I guess that doesn't apply if you're trying to identify the model by fixing thresholds. If you're going to fix two of the thresholds, you can freely estimate both the means and the variances of the ordinal phenotypes. Also, when people fix two thresholds, they usually fix them to 0 and 1 (but that's arbitrary).

Specifically what "bogus results or errors" are you getting?

Replied on Sun, 07/12/2020 - 18:39
No user picture. Leo Joined: 01/09/2020

In reply to by AdminRobK

Hi Rob,

thanks for your reply.

I'm aware that I have to put the mxconstraints into the actual mxmodel, they were just leftovers from a previous version. I have tried two versions:

1. Fixing means to zero and variance of the latents to 1, as well as putting one mxconstraint for each variable in place and estimating all thresholds freely.
2. Estimating variance and means freely and fixing the first two tresholds as well as fixing the paths from latents to manifests to one. As far as I can tell, this is the way umxacev does it?

Method 2 produces the error message "In model 'ACE' Optimizer returned a non-zero status code 5. The Hessian at the solution does not appear to be convex. See ?mxCheckIdentification for possible diagnosis (Mx status RED). "
mxcheckidentification:

> fitACE <- mxRun(modelACE)
Running ACE with 13 parameters
Warning message:
In model 'ACE' Optimizer returned a non-zero status code 5. The Hessian at the solution does not appear to be convex. See ?mxCheckIdentification for possible diagnosis (Mx status RED).
> mxCheckIdentification(modelACE)
Model is not locally identified
$status
[1] FALSE

$jacobian
A22 C22 E22 covA A11 covC C11 covE E11 mean mean2 true3 true6
MZ.cov1_1 1 1 1 0 0 0 0 0 0 0 0 0 0
MZ.cov2_1 0 0 0 0 0 0 0 0 0 0 0 0 0
MZ.cov3_1 0 0 0 1 0 1 0 1 0 0 0 0 0
MZ.cov4_1 0 0 0 0 0 0 0 0 0 0 0 0 0
MZ.cov2_2 1 1 1 0 0 0 0 0 0 0 0 0 0
MZ.cov3_2 0 0 0 0 0 0 0 0 0 0 0 0 0
MZ.cov4_2 0 0 0 1 0 1 0 1 0 0 0 0 0
MZ.cov3_3 0 0 0 0 1 0 1 0 1 0 0 0 0
MZ.cov4_3 0 0 0 0 0 0 0 0 0 0 0 0 0
MZ.cov4_4 0 0 0 0 1 0 1 0 1 0 0 0 0
MZ.mean1 0 0 0 0 0 0 0 0 0 1 0 0 0
MZ.mean2 0 0 0 0 0 0 0 0 0 1 0 0 0
MZ.mean3 0 0 0 0 0 0 0 0 0 0 1 0 0
MZ.mean4 0 0 0 0 0 0 0 0 0 0 1 0 0
MZ.thr1_1 0 0 0 0 0 0 0 0 0 0 0 0 0
MZ.thr2_1 0 0 0 0 0 0 0 0 0 0 0 0 0
MZ.thr3_1 0 0 0 0 0 0 0 0 0 0 0 1 0
MZ.thr1_2 0 0 0 0 0 0 0 0 0 0 0 0 0
MZ.thr2_2 0 0 0 0 0 0 0 0 0 0 0 0 0
MZ.thr3_2 0 0 0 0 0 0 0 0 0 0 0 1 0
MZ.thr1_3 0 0 0 0 0 0 0 0 0 0 0 0 0
MZ.thr2_3 0 0 0 0 0 0 0 0 0 0 0 0 0
MZ.thr3_3 0 0 0 0 0 0 0 0 0 0 0 0 1
MZ.thr1_4 0 0 0 0 0 0 0 0 0 0 0 0 0
MZ.thr2_4 0 0 0 0 0 0 0 0 0 0 0 0 0
MZ.thr3_4 0 0 0 0 0 0 0 0 0 0 0 0 1
DZ.cov1_1 1 1 1 0 0 0 0 0 0 0 0 0 0
DZ.cov2_1 0 0 0 0 0 0 0 0 0 0 0 0 0
DZ.cov3_1 0 0 0 1 0 1 0 1 0 0 0 0 0
DZ.cov4_1 0 0 0 0 0 0 0 0 0 0 0 0 0
DZ.cov2_2 1 1 1 0 0 0 0 0 0 0 0 0 0
DZ.cov3_2 0 0 0 0 0 0 0 0 0 0 0 0 0
DZ.cov4_2 0 0 0 1 0 1 0 1 0 0 0 0 0
DZ.cov3_3 0 0 0 0 1 0 1 0 1 0 0 0 0
DZ.cov4_3 0 0 0 0 0 0 0 0 0 0 0 0 0
DZ.cov4_4 0 0 0 0 1 0 1 0 1 0 0 0 0
DZ.mean1 0 0 0 0 0 0 0 0 0 1 0 0 0
DZ.mean2 0 0 0 0 0 0 0 0 0 1 0 0 0
DZ.mean3 0 0 0 0 0 0 0 0 0 0 1 0 0
DZ.mean4 0 0 0 0 0 0 0 0 0 0 1 0 0
DZ.thr1_1 0 0 0 0 0 0 0 0 0 0 0 0 0
DZ.thr2_1 0 0 0 0 0 0 0 0 0 0 0 0 0
DZ.thr3_1 0 0 0 0 0 0 0 0 0 0 0 1 0
DZ.thr1_2 0 0 0 0 0 0 0 0 0 0 0 0 0
DZ.thr2_2 0 0 0 0 0 0 0 0 0 0 0 0 0
DZ.thr3_2 0 0 0 0 0 0 0 0 0 0 0 1 0
DZ.thr1_3 0 0 0 0 0 0 0 0 0 0 0 0 0
DZ.thr2_3 0 0 0 0 0 0 0 0 0 0 0 0 0
DZ.thr3_3 0 0 0 0 0 0 0 0 0 0 0 0 1
DZ.thr1_4 0 0 0 0 0 0 0 0 0 0 0 0 0
DZ.thr2_4 0 0 0 0 0 0 0 0 0 0 0 0 0
DZ.thr3_4 0 0 0 0 0 0 0 0 0 0 0 0 1

$non_identified_parameters
[1] "A22" "C22" "E22" "covA" "A11" "covC" "C11" "covE" "E11"

Replied on Sun, 07/12/2020 - 18:00
Picture of user. tbates Joined: 07/31/2009

If I read correctly,
1. You're trying to implement an ACE model in path specification.
2. You're struggling with thresholds.

In answer to 1, The `umxTwinMaker` function is really helpful for this; You just describe the model for one twin, and the relationship between the twins (defaults mostly work for this) and you get back a two-group twin model implementing the proper paths connecting twins in a pair and differences in relationships between pairs. It's great!

ordinal variables and thresholds introduce a handful of things to handle, with different decisions to be made for binary, ordinal, continuous, the thresholds matrix, offsets matrix, algebras, and implications to keep straight for constrained latent variables in the model that will map out to your thresholds. Additional concerns about modelling covariates on the means etc. etc. Can give head aches.

umxACE and umxACEv take care of all of this for you.

Replied on Thu, 07/16/2020 - 07:26
Picture of user. tbates Joined: 07/31/2009

In reply to by Leo

gotcha: I've not followed this long thread closely. But might be useful to look inside the xmuRAM2Ordinal and umxThresholdMatrix functions to see how factor variables with 2, 3, and more levels are handled, creating lowerOnes_for_thresh, deviations_for_thresh, and thresholdsAlgebra. Also see the implications for the model implementation that depend on these - in terms of fixed variance and means in dummy latent variables. You could adapt that approach to your long-form script.