This vignette is a verification stub for genomic
structural equation modeling (GSEM) in umx via
umxGSEM().
It documents that a one-factor model on the built-in LDSC object
Psych_LDSC recovers the same DWLS point estimates
and standard errors (to printed precision) as GenomicSEM’s
commonfactor() on the same input.
Rails, not vibes. umx builds OpenMx summary WLS with modern
mxData(numObs = N, observedStats = list(cov = S, useWeight = W, asymCov = V))
after reordering \(V\) into OpenMx residual order (var_*,poly_*_*).
Legacy OpenMxtype = "acov"is not used or accepted.
Reference: Grotzinger et al. (2019). Genomic structural equation modeling. Nature Human Behaviour, 3, 513–525. doi:10.1038/s41562-019-0566-x.
Psych_LDSCFive traits from multivariate LDSC: SCZ, BIP, MDD, EA, INSOM.
data(Psych_LDSC, package = "umx")
str(Psych_LDSC, max.level = 1)
# names: V, S, I, N, m
# S is 5×5 genetic covariance; V is 15×15 sampling covariance of vech(S)
colnames(Psych_LDSC$S)| Slot | Role |
|---|---|
S |
Genetic covariance (heritabilities on diagonal) |
V |
Sampling covariance of non-redundant elements of S |
I |
LDSC intercepts |
N |
Effective sample sizes for each S element |
m |
SNP count used in LDSC |
umxGSEMUnit-variance identification (std.lv = TRUE by default).
Path-style ~= is accepted as lavaan =~.
m1 = umxGSEM(
model = "g ~= SCZ + BIP + MDD + EA + INSOM",
covstruc = Psych_LDSC,
estimation = "DWLS"
)
umxSummary(m1)Optional explicit lavaan syntax (same model):
m1b = umxGSEM(
model = "
g =~ NA*SCZ + BIP + MDD + EA + INSOM
g ~~ 1*g
",
covstruc = Psych_LDSC,
estimation = "DWLS",
std.lv = FALSE
)Inspect summary WLS data (modern names only — not
acov):
commonfactorVerified against GenomicSEM
commonfactor(Psych_LDSC, estimation = "DWLS") on the same
Psych_LDSC object (unstandardized loadings and residual
variances; unit variance on the factor).
| Path | GenomicSEM | umxGSEM | SE (both) |
|---|---|---|---|
| g → SCZ | 0.4314 | 0.4314 | 0.0408 |
| g → BIP | 0.4235 | 0.4235 | 0.0397 |
| g → MDD | 0.1310 | 0.1310 | 0.0148 |
| g → EA | 0.0087 | 0.0087 | 0.0058 |
| g → INSOM | 0.0165 | 0.0165 | 0.0055 |
| Residual | GenomicSEM | umxGSEM |
|---|---|---|
| SCZ | 0.0583 | 0.0583 |
| BIP | 0.0834 | 0.0834 |
| MDD | 0.0836 | 0.0836 |
| EA | 0.1123 | 0.1123 |
| INSOM | 0.0457 | 0.0457 |
Standardized loadings (GenomicSEM / same model structure) are
approximately SCZ 0.87, BIP 0.83, MDD
0.41, EA 0.03, INSOM
0.08 — SCZ and BIP dominate the genetic factor; EA and
INSOM barely load (as expected from S).
Omnibus \(\chi^2\), CFI, and related
indices can differ across packages because of how \(r'Wr\) is scaled, how the independence
model is built, and dummy numObs. Parameters and
SEs are the cross-check. For GSEM model comparison in umx,
prefer change in CFI / SRMR and nested tests via
umxCompare() (see package docs).
| Package | Example omnibus (illustrative) |
|---|---|
| umxGSEM | \(\chi^2(5) \approx 388.5\); fit
\(r'Wr \approx 407.3\) with
numObs = 1 |
GenomicSEM commonfactor |
\(\chi^2(5) \approx 504\); CFI \(\approx 0.45\); SRMR \(\approx 0.16\) |
observedStats = list(cov = S, useWeight = W, asymCov = V) —
never legacy type = "acov".tmx_show auto-bumps digits
for small matrices).umxGSEM defaults to tryHard = "yes" and
eigen-based starts.Re-run verification (maintainers): fit with eval = TRUE
above; optionally compare to GenomicSEM commonfactor when
that stack is available. No umx dependency on GenomicSEM or lavaan GSEM
helpers is required for users.
Adding SNPs (GenomicSEM’s sumstats →
commonfactorGWAS / userGWAS) needs
per-trait GWAS files plus a 1000 Genomes MAF
reference. Built-in Psych_LDSC /
Anthro_LDSC are LDSC-only (S,
V, …); they do not ship SNP betas.
| umx object | Traits | Closest workshop object | SNP tutorial files |
|---|---|---|---|
Psych_LDSC |
SCZ, BIP, MDD, EA, INSOM | PRAC_COV (5-trait user model) |
Workshop has no bundled EA/INSOM SNP subsets for the 5-trait path model |
| (3-trait subset of Psych) | SCZ, BIP, MDD only | PSYCH_COV |
Yes — tutorial multivariate GWAS uses these three |
Anthro_LDSC |
BMI, WHR, CO, Waist, Hip, Height, IHC, BL, BW | Anthro_LDSC.RData in workshop materials |
Full anthropometric GWAS from original papers / consortia (not in the 1k SNP toy pack) |
Workshop practical (IBG / Grotzinger materials):
From the practical (order must match ldsc /
sumstats):
SCZ_subset.txt
BIP_subset.txt
MDD_subset.txt
reference.1000G.subset.txt # drastically reduced 1000G ref for MAF
Notes from the tutorial authors:
PSYCH_COV LDSC object —
i.e. subset SNPs are for
sumstats/commonfactorGWAS smoke tests, not for
rebuilding LDSC from scratch with only 1k SNPs..subset file.Example (GenomicSEM naming; umx will mirror later):
files = c("SCZ_subset.txt", "BIP_subset.txt", "MDD_subset.txt")
ref = "reference.1000G.subset.txt"
trait.names = c("SCZ", "BIP", "MDD")
se.logit = c(TRUE, TRUE, TRUE)
# GenomicSEM::sumstats(files, ref, trait.names, se.logit = se.logit)
# commonfactorGWAS(covstruc = PSYCH_COV, SNPs = p_sumstats, estimation = "DWLS")For umx, the matching 3-trait genetic cov structure
is the SCZ/BIP/MDD block of Psych_LDSC (or a dedicated
3-trait LDSC when we ship one).
SNP,
A1, A2, effect, P,
…) — in umx: umxGSEM_dl_RefList() +
umxGSEM_munge() (OpenMx C++ munge). HapMap3 list: Zenodo
w_hm3.snplist (see ?umxGSEM_dl_RefList).eur_w_ld_chr/ (Bulik-Sullivan / LDSC standard bundle; also
linked from GenomicSEM install materials).covstruc
(S, V, I, N,
m) — same shape as Psych_LDSC.sumstats-equivalent): align alleles to a 1000
Genomes Phase 3 reference used for SNP variance / MAF.reference.1000G.maf.0.005.txt style; not the workshop
.subset.)se.logit = TRUE is common even when effects are ORs).
Continuous traits: OLS = TRUE or standardized betas as
appropriate.Minimum columns before munge: rsID, A1 (effect allele), A2, effect (beta or OR), P. Sample size \(N\) (or effective \(N\)) is required for scaling.
# Toy files under inst/developer/GenomicSEM/ (or workshop Box pack)
dir = system.file("developer", "GenomicSEM", package = "umx")
snps = umxGSEM_sumstats(
files = file.path(dir, c("SCZ_subset.txt", "BIP_subset.txt", "MDD_subset.txt")),
ref = file.path(dir, "reference.1000G.subset.txt"),
trait.names = c("SCZ", "BIP", "MDD"),
se.logit = TRUE
)
# Match SNP traits: pass full LDSC object + traits= (do not V[1:6,1:6] — wrong pairs)
gwas = umxGSEM_GWAS(covstruc = Psych_LDSC, SNPs = snps,
traits = c("SCZ", "BIP", "MDD"), maxSNPs = 50)
head(gwas)umxGSEM() — one structural model
(string or existing
umxRAM/mxModel).umxGSEM_sumstats() — allele-align +
continuous-scale betas for multivariate GWAS.umxGSEM_GWAS() — per-SNP expand
S/V, DWLS fit, return SNP table
(est = factor ~ SNP).sessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 26.04 LTS
#>
#> Matrix products: default
#> BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.32.so; LAPACK version 3.12.0
#>
#> locale:
#> [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
#> [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
#> [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
#> [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
#> [9] LC_ADDRESS=C LC_TELEPHONE=C
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
#>
#> time zone: Etc/UTC
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] umx_4.80.0 OpenMx_2.22.11 rmarkdown_2.31
#>
#> loaded via a namespace (and not attached):
#> [1] gtable_0.3.6 xfun_0.60 bslib_0.11.0
#> [4] ggplot2_4.0.3 htmlwidgets_1.6.4 visNetwork_2.1.4
#> [7] lattice_0.22-9 numDeriv_2016.8-1.1 quadprog_1.5-8
#> [10] vctrs_0.7.3 tools_4.6.1 generics_0.1.4
#> [13] stats4_4.6.1 curl_7.1.0 parallel_4.6.1
#> [16] tibble_3.3.1 xts_0.14.2 pkgconfig_2.0.3
#> [19] Matrix_1.7-6 MuMIn_1.48.19 RColorBrewer_1.1-3
#> [22] S7_0.2.2 RcppParallel_6.0.0 lifecycle_1.0.5
#> [25] compiler_4.6.1 farver_2.1.2 stringr_1.6.0
#> [28] textshaping_1.0.5 mnormt_2.1.2 htmltools_0.5.9
#> [31] sys_3.4.3 buildtools_1.0.0 sass_0.4.10
#> [34] yaml_2.3.12 pillar_1.11.1 jquerylib_0.1.4
#> [37] MASS_7.3-66 admisc_0.40 cachem_1.1.0
#> [40] nlme_3.1-170 lavaan_0.7-2 polycor_0.8-2
#> [43] tidyselect_1.2.1 digest_0.6.39 stringi_1.8.7
#> [46] dplyr_1.2.1 maketools_1.3.2 cowplot_1.2.0
#> [49] fastmap_1.2.0 grid_4.6.1 cli_3.6.6
#> [52] magrittr_2.0.5 DiagrammeR_1.0.12 pbivnorm_0.6.0
#> [55] scales_1.4.0 TTR_0.24.4 quantmod_0.4.29
#> [58] otel_0.2.0 zoo_1.8-15 kableExtra_1.4.1
#> [61] evaluate_1.0.5 knitr_1.51 viridisLite_0.4.3
#> [64] rlang_1.3.0 Rcpp_1.1.2 xtable_1.8-8
#> [67] glue_1.8.1 xml2_1.6.0 svglite_2.2.2
#> [70] rstudioapi_0.19.0 jsonlite_2.0.0 R6_2.6.1
#> [73] systemfonts_1.3.2