---
title: "Working with the mplusModel Object"
author: "Michael Hallquist"
date: "`r Sys.Date()`"
output:
  rmarkdown::html_vignette:
    toc: true
    toc_depth: 3
vignette: >
  %\VignetteIndexEntry{Working with the mplusModel Object}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
library(MplusAutomation)

# Temporary working files for this vignette.
tmp_dir <- tempfile("mplusModel_vignette_")
dir.create(tmp_dir)

# A placeholder path so this vignette can run without Mplus installed.
fake_mplus <- tempfile("fake_mplus_")
file.create(fake_mplus)
```

# Overview

`mplusModel()` creates an R6 object that represents one Mplus model.
It stores:

- model syntax
- model data
- `.inp`, `.dat`, and `.out` paths
- parsed output sections (after reading/running a model)

Compared with the traditional `mplusObject`, `mplusModel` is designed around a single model lifecycle:
create, update, write files, run/submit, and inspect results.

# Three Ways to Start

There are three common entry points:

1. Start from syntax and data when you want to define a model in R and choose its file location with `dir` and `file_stem`.
2. Start from an existing `.inp` file when the input syntax already exists on disk.
3. Start from an existing `.out` file when you want to recover a model object from Mplus output, even if the `.inp` file is missing.

In all three cases, the object tracks a canonical file identity through `dir` and `file_stem`, and derives the `.inp`, `.out`, `.gh5`, and `.dat` paths from that state.

# Start from Syntax and Data

```{r}
model_syntax <- "
TITLE: OLS regression with mtcars data;
DATA: FILE IS mtcars_demo.dat;
VARIABLE:
  NAMES = mpg wt hp cyl qsec;
  USEVARIABLES = mpg wt hp;
ANALYSIS:
  ESTIMATOR = ML;
MODEL:
  mpg ON wt hp;
OUTPUT:
  STANDARDIZED;
"

model_data <- mtcars[, c("mpg", "wt", "hp", "cyl", "qsec")]

m <- mplusModel(
  syntax = model_syntax,
  data = model_data,
  dir = tmp_dir,
  file_stem = "mtcars_demo",
  Mplus_command = fake_mplus
)

m$dir
m$file_stem
m$model_dir
m$inp_file
m$dat_file
m$variables
```

The object uses active bindings, so values like `m$dir`, `m$file_stem`, `m$inp_file`, and `m$dat_file` are always synchronized with the current object state. To relocate the model files, update `m$dir` and/or `m$file_stem`; `write_dat()` and `write_inp()` always write to those canonical locations.

# Start from an Existing `.inp` File

If you already have an Mplus input file, initialize the object from `inp_file`.

```{r}
m$write_dat()
m$write_inp()

m_from_inp <- mplusModel(
  inp_file = m$inp_file,
  read = FALSE,
  Mplus_command = fake_mplus
)

head(m_from_inp$syntax, n = 8)
```

# Write Mplus Files

`write_dat()` writes the data file, and `write_inp()` writes the Mplus input syntax.

```{r}
m$write_dat()
m$write_inp()

file.exists(m$dat_file)
file.exists(m$inp_file)
```

# Update Syntax and Variables

There are two update styles:

- non-mutating: `update(m, ...)` returns an updated clone
- in place: `m$update(...)` mutates the current object

For syntax sections, formulas support replace and append semantics:

- `~ "new text"` replaces
- `~ . + "additional text"` appends

```{r}
m_clone <- update(
  m,
  MODEL = ~ . + "mpg ON cyl;",
  ANALYSIS = ~ "ESTIMATOR = MLR;"
)

any(grepl("mpg ON cyl;", m$syntax, fixed = TRUE))
any(grepl("mpg ON cyl;", m_clone$syntax, fixed = TRUE))
```

```{r}
m$update(MODEL = ~ . + "mpg ON qsec;")
any(grepl("mpg ON qsec;", m$syntax, fixed = TRUE))
```

The `variables` binding controls which columns are written to the `.dat` file:

```{r}
m$variables

m$variables <- c("mpg", "wt", "hp", "cyl")
m$variables

m$variables <- NULL
m$variables
```

# Start from an Existing `.out` File

This example uses an output file shipped with the package (`inst/extdata/ex3.1.out`). The constructor rebuilds syntax from the echoed input stored in the output file and, when `read = TRUE`, also loads the parsed results.

```{r}
out_file <- system.file("extdata", "ex3.1.out", package = "MplusAutomation")
file.copy(out_file, file.path(tmp_dir, "ex3.1.out"), overwrite = TRUE)

m_out <- mplusModel(
  out_file = file.path(tmp_dir, "ex3.1.out"),
  data = data.frame(y1 = 0, x1 = 0, x3 = 0),
  read = TRUE,
  Mplus_command = fake_mplus
)

m_out$inp_file
m_out$syntax[1:4]
m_out$summaries[c("AIC", "BIC", "CFI", "RMSEA_Estimate")]
head(m_out$parameters$unstandardized[, c("paramHeader", "param", "est", "se", "pval")])
```

`mplusModel` exposes all major sections returned by `readModels()`, including `input`, `summaries`, `parameters`, `mod_indices`, `errors`, and more.

# Run Locally or Submit to HPC

`mplusModel` wraps both local runs and scheduler submission.
These commands require a real Mplus executable.

```{r, eval=FALSE}
# Run locally
m$run(replaceOutfile = "modifiedDate")

# Submit to SLURM/Torque (arguments passed through to submitModels())
m$submit(
  scheduler = "slurm",
  replaceOutfile = "modifiedDate",
  memgb_per_model = 8L,
  cores_per_model = 1L,
  time_per_model = "01:00:00"
)
```

# Summary

Use `mplusModel` when you want an object-oriented workflow for a single model:

1. Start from `syntax` + `dir` + `file_stem`, an existing `inp_file`, or an existing `out_file`.
2. Work with canonical file paths through `dir`, `file_stem`, `inp_file`, `out_file`, and `dat_file`.
3. Write `.inp` / `.dat`, update syntax programmatically, and run or submit the model.
4. Read and inspect parsed output sections from the corresponding `.out` file.

```{r cleanup, include=FALSE}
unlink(tmp_dir, recursive = TRUE, force = TRUE)
unlink(fake_mplus, force = TRUE)
```
