OpenMx is a Structural Equation Modeling package that encourages users to treat model specifications as something to be generated and manipulated programmatically.

OpenMx is the next generation of the Mx structural equation modeling tool. It is an R package activelly maintained and supported with the work of developers around the globe. It is designed to allow the user the most freedom possible while specifying structural equation models, therefore providing minimal defaults. This helps the user know that each specification/optimization decision comes with their own assumptions and influences model interpretation.

The package is on CRAN and should be installed with:

`install.packages("OpenMx")`

Developers commit to the `master`

branch. Intrepid users
are encouraged to install the `master`

branch. In order to
install locally clone this repo and run:

```
-install # for the CRAN version
make cran# for the version with the proprietary NPSOL optimizer make install
```

The `stable`

branch can be considered our current alpha
release.

The `stable`

branch is updated automatically when all
`models/passing`

and `models/nightly`

tests pass
along with `make cran-check`

.

On macOS, this can be installed as a binary via travis:

```
install.packages("https://vipbg.vcu.edu/vipbg/OpenMx2/software/bin/macosx/travis/OpenMx_latest.tgz")
```

OpenMx can fit everything from confirmatory factor analyses, through multiple group, mixture distribution, categorical threshold, modern test theory, differential equations, state space, and many others. Models may be specified as RAM or LISREL paths, or directly in matrix algebra. Fit functions include ML (summary and full information) and WLS.

The package manual can be accessed online in the link, and as a pdf from the link. The manual includes example models and scripts for the most common cases.

Path specifications are matematically complete and is often considered an easier approach to teaching and analysis. The path below represents a simple regression:

One can specify the above model using the following code:

```
require(OpenMx)
data(myRegDataRaw) # load data
names(myRegDataRaw) # get names
<- myRegDataRaw[,c("x","y")] # take only what is needed
SimpleDataRaw
<- mxData( observed=SimpleDataRaw, type="raw" )
dataRaw # variance paths
<- mxPath( from=c("x","y"), arrows=2,
varPaths free=TRUE, values = c(1,1), labels=c("varx","residual") )
# regression weights
<- mxPath( from="x", to="y", arrows=1,
regPaths free=TRUE, values=1, labels="beta1" )
# means and intercepts
<- mxPath( from="one", to=c("x","y"), arrows=1,
means free=TRUE, values=c(1,1), labels=c("meanx","beta0") )
<- mxModel(model="Simple Regression Path Specification", type="RAM",
uniRegModel manifestVars=c("x","y"), varPaths, regPaths, means)
dataRaw,
<- mxRun(uniRegModel) # run it
uniRegFit summary(uniRegFit)
```

And the following output should appear in your R environment:

```
Summary of Simple Regression Path Specification
free parameters:
name matrix row col Estimate Std.Error A
1 beta1 A y x 0.48311962 0.07757687
2 varx S x x 1.10531952 0.15631652
3 residual S y y 0.66520320 0.09407411
4 meanx M 1 x 0.05415975 0.10513428
5 beta0 M 1 y 2.54776414 0.08166814
Model Statistics:
| Parameters | Degrees of Freedom | Fit (-2lnL units)
Model: 5 195 536.8226
Saturated: 5 195 NA
Independence: 4 196 NA
Number of observations/statistics: 100/200
Information Criteria:
| df Penalty | Parameters Penalty | Sample-Size Adjusted
AIC: 146.8226 546.8226 547.4609
BIC: -361.1856 559.8484 544.0572
CFI: NA
TLI: 1 (also known as NNFI)
RMSEA: 0 [95% CI (NA, NA)]
Prob(RMSEA <= 0.05): NA
To get additional fit indices, see help(mxRefModels)
timestamp: 2022-05-01 09:53:24
```

Since OpenMx is considered the specialist tool, you are probably more interested in the flexibility provided by the fact that you can build your own formulas. So going back to the simple regression, now in the formula (equivalent to the path specified in previous section):

It can be implemented with the following code:

```
require(OpenMx)
data(myRegDataRaw) # load data
<- myRegDataRaw[,c("x","y")] # take only what is needed
SimpleDataRaw
# create a data object
<- mxData( observed=SimpleDataRaw, type="raw" )
dataRaw
# A matrix
<- mxMatrix( type="Full", nrow=2, ncol=2,
matrA free=c(F,F,T,F), values=c(0,0,1,0),
labels=c(NA,NA,"beta1",NA), byrow=TRUE, name="A" )
# S matrix
<- mxMatrix( type="Symm", nrow=2, ncol=2,
matrS free=c(T,F,F,T), values=c(1,0,0,1),
labels=c("varx",NA,NA,"residual"), byrow=TRUE, name="S" )
# Filter matrix
<- mxMatrix( type="Iden", nrow=2, ncol=2, name="F" )
matrF
# M matrix
<- mxMatrix( type="Full", nrow=1, ncol=2,
matrM free=c(T,T), values=c(0,0),
labels=c("meanx","beta0"), name="M")
# Which expectation? RAM in this case
<- mxExpectationRAM("A","S","F","M", dimnames=c("x","y"))
expRAM
# Run a maximum likelihood
<- mxFitFunctionML()
funML
# Name it, pass the objects on to a final model object
<- mxModel("Simple Regression Matrix Specification",
uniRegModel
dataRaw, matrA, matrS, matrF, matrM, expRAM, funML)
# Run it!
<- mxRun(uniRegModel)
uniRegFit
summary(uniRegFit)
```

Now the output looks like:

```
Running Simple Regression Matrix Specification with 5 parameters
Summary of Simple Regression Matrix Specification
free parameters:
name matrix row col Estimate Std.Error A
1 beta1 A 2 1 0.48311963 0.07757699
2 varx S 1 1 1.10531937 0.15631498
3 residual S 2 2 0.66520312 0.09407369
4 meanx M 1 x 0.05416001 0.10513400
5 beta0 M 1 y 2.54776424 0.08166812
Model Statistics:
| Parameters | Degrees of Freedom | Fit (-2
Model: 5 195
Saturated: 5 195
Independence: 4 196
Number of observations/statistics: 100/200
Information Criteria:
| df Penalty | Parameters Penalty | Sample-Size Adju
AIC: 146.8226 546.8226 547.
BIC: -361.1856 559.8484 544.
CFI: NA
TLI: 1 (also known as NNFI)
RMSEA: 0 [95% CI (NA, NA)]
Prob(RMSEA <= 0.05): NA
To get additional fit indices, see help(mxRefModels)
timestamp: 2022-05-01 10:04:52
Wall clock time: 0.3507566 secs
optimizer: SLSQP
OpenMx version number: 2.19.6.6
Need help? See help(mxSummary)
```

umx() is a sister R package that bridges the gap between lavaan and OpenMx. If you are coming from lavaan it is perhaps useful to check umx() too.

- The support communication is centered around the OpenMx forum
- Also, but less often, at the StackOverflow OpenMx tag.

We gather annually in beautiful Boulder, CO for the international workshop for traning in behavioral genetics applications of OpenMx.