├── .Rbuildignore ├── .github ├── .gitignore ├── ISSUE_TEMPLATE │ ├── describe-issue.md │ └── feature_request.md └── workflows │ ├── R-CMD-check.yaml │ ├── rhub.yaml │ └── test-coverage.yaml ├── .gitignore ├── DESCRIPTION ├── LICENSE ├── LICENSE.note ├── NAMESPACE ├── NEWS.md ├── R ├── cAIC.R ├── data.R ├── family.R ├── fit.R ├── internal.R ├── make_dsem_ram.R ├── make_eof_ram.R ├── make_sem_ram.R ├── methods.R ├── predict.R ├── sfnetwork.R └── utility.R ├── README.Rmd ├── README.md ├── _pkgdown.yml ├── codecov.yml ├── data-raw ├── download_sea_ice.R ├── format_condition_and_density.R ├── format_red_snapper.R ├── format_salmon_returns.R └── mcf210023-sup-0001-tables1-s24 -- ST 13-16 Tot ret (bioma) 52-15.csv ├── data ├── bering_sea.rda ├── bering_sea_pollock_ages.rda ├── bering_sea_pollock_vast.rda ├── condition_and_density.rda ├── red_snapper.rda ├── red_snapper_shapefile.rda ├── salmon_returns.rda └── sea_ice.rda ├── header.md ├── inst ├── CITATION └── stream_network │ ├── East_Fork_Lewis_basin.dbf │ ├── East_Fork_Lewis_basin.prj │ ├── East_Fork_Lewis_basin.shp │ └── East_Fork_Lewis_basin.shx ├── man ├── GetResponse.tinyVAST.Rd ├── add_predictions.Rd ├── bering_sea.Rd ├── bering_sea_pollock_ages.Rd ├── bering_sea_pollock_vast.Rd ├── cAIC.Rd ├── classify_variables.Rd ├── condition_and_density.Rd ├── deviance_explained.Rd ├── families.Rd ├── get_data.tinyVAST.Rd ├── integrate_output.Rd ├── logLik.tinyVAST.Rd ├── make_dsem_ram.Rd ├── make_eof_ram.Rd ├── make_sem_ram.Rd ├── parse_path.Rd ├── predict.tinyVAST.Rd ├── print.tinyVAST.Rd ├── red_snapper.Rd ├── red_snapper_shapefile.Rd ├── reexports.Rd ├── reload_model.Rd ├── residuals.tinyVAST.Rd ├── rmvnorm_prec.Rd ├── rotate_pca.Rd ├── salmon_returns.Rd ├── sample_variable.Rd ├── sea_ice.Rd ├── sfnetwork_evaluator.Rd ├── sfnetwork_mesh.Rd ├── simulate.tinyVAST.Rd ├── simulate_sfnetwork.Rd ├── summary.tinyVAST.Rd ├── term_covariance.Rd ├── tinyVAST.Rd ├── tinyVASTcontrol.Rd └── vcov.tinyVAST.Rd ├── scratch ├── Upload_to_CRAN.R ├── VAST.Rmd ├── age_composition_expansion.Rmd ├── build_pkgdown_website.R ├── build_r-devel_in_WSL.R ├── condition.Rmd ├── crossvalidation.R ├── empirical_orthogonal_functions.Rmd ├── fit.R ├── network_precision_check.R ├── pkgdown.yaml ├── run_docker_and_UBSAN.R ├── run_linux_and_valgrind.R ├── run_openblas_via_WSL.R ├── run_readme.R ├── run_tests_locally.R ├── run_vignettes_locally.R ├── save_compile_messages.R ├── setup_codecov.R ├── setup_rhub.R ├── stream_networks.Rmd ├── tensor_spline.R ├── test.R ├── tinyVAST_1.0.0.tar.gz └── tinyVAST_1.1.1.tar.gz ├── src ├── Makevars └── tinyVAST.cpp ├── tests ├── testthat.R └── testthat │ ├── test-SAR.R │ ├── test-SVC.R │ ├── test-basic-fits.R │ ├── test-deviance-residuals.R │ ├── test-dsem.R │ ├── test-index-standardization.R │ ├── test-platform.R │ ├── test-sfa.R │ ├── test-sfnetworks.R │ └── test-smooths.R └── vignettes ├── .Rhistory ├── .gitignore ├── dsem.Rmd ├── mgcv.Rmd ├── model-description.Rmd ├── multiple_data.Rmd ├── spatial.Rmd ├── spatial_factor_analysis.Rmd └── web_only ├── VAST.Rmd ├── age_composition_expansion.Rmd ├── condition.Rmd ├── empirical_orthogonal_functions.Rmd ├── overview.Rmd ├── simultaneous_autoregressive_process.Rmd └── stream_networks.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^data-raw$ 2 | ^_pkgdown\.yml$ 3 | ^docs$ 4 | ^pkgdown$ 5 | ^scratch$ 6 | ^.*\.Rproj$ 7 | ^\.Rproj\.user$ 8 | ^\.github$ 9 | ^CRAN-SUBMISSION$ 10 | ^CRAN-RELEASE$ 11 | ^cran-comments\.md$ 12 | ^LICENSE$ 13 | ^vignettes/web_only$ 14 | ^vignettes/figure$ 15 | ^codecov\.yml$ 16 | ^figure$ 17 | ^README\.Rmd$ 18 | ^README\.md$ 19 | ^README\.html$ 20 | ^header\.md$ 21 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/describe-issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Describe issue 3 | about: Use this template to submit an issue. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | For questions about user-interface or existing functionality, please use the Discussions tab. 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Use this to suggest a new feature 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, dev, add_header] 6 | pull_request: 7 | branches: [main, dev, add_header] 8 | 9 | name: R-CMD-check 10 | 11 | jobs: 12 | R-CMD-check: 13 | if: "! contains(github.event.head_commit.message, '[skip ci]')" 14 | runs-on: ${{ matrix.config.os }} 15 | 16 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 17 | 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | config: 22 | - {os: macos-latest, r: 'release'} 23 | - {os: windows-latest, r: 'release'} 24 | # - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 25 | - {os: ubuntu-latest, r: 'release'} 26 | # - {os: ubuntu-latest, r: 'oldrel-1'} 27 | 28 | env: 29 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 30 | R_KEEP_PKG_SOURCE: yes 31 | 32 | steps: 33 | - uses: actions/checkout@v3 34 | 35 | - uses: r-lib/actions/setup-pandoc@v2 36 | 37 | - uses: r-lib/actions/setup-r@v2 38 | with: 39 | r-version: ${{ matrix.config.r }} 40 | http-user-agent: ${{ matrix.config.http-user-agent }} 41 | use-public-rspm: true 42 | 43 | - name: Install dependencies Ubuntu 44 | if: runner.os == 'Linux' 45 | run: | 46 | install.packages('remotes') 47 | remotes::install_deps(dependencies = TRUE) 48 | remotes::install_cran("knitr") 49 | remotes::install_cran("rmarkdown") 50 | remotes::install_cran("rcmdcheck") 51 | install.packages("Matrix", type = "source") 52 | install.packages("TMB", type = "source") 53 | shell: Rscript {0} 54 | 55 | - name: Install dependencies macOS 56 | if: runner.os == 'macOS' 57 | run: | 58 | install.packages('remotes') 59 | remotes::install_deps(dependencies = TRUE) 60 | remotes::install_cran("rcmdcheck") 61 | install.packages("Matrix", type = "source") 62 | install.packages("TMB", type = "source") 63 | shell: Rscript {0} 64 | 65 | - name: Install dependencies Windows 66 | if: runner.os == 'Windows' 67 | run: | 68 | install.packages('remotes') 69 | remotes::install_deps(dependencies = TRUE) 70 | remotes::install_cran("knitr") 71 | remotes::install_cran("rmarkdown") 72 | remotes::install_cran("rcmdcheck") 73 | install.packages("Matrix", type = "source") 74 | install.packages("TMB", type = "source") 75 | shell: Rscript {0} 76 | 77 | - uses: r-lib/actions/setup-r-dependencies@v2 78 | with: 79 | extra-packages: any::rcmdcheck 80 | needs: check 81 | 82 | - uses: r-lib/actions/check-r-package@v2 83 | with: 84 | upload-snapshots: true 85 | args: 'c("--no-manual", "--as-cran", "--ignore-vignettes", "--no-build-vignettes")' 86 | build_args: 'c("--no-manual", "--no-build-vignettes")' 87 | -------------------------------------------------------------------------------- /.github/workflows/rhub.yaml: -------------------------------------------------------------------------------- 1 | # R-hub's generic GitHub Actions workflow file. It's canonical location is at 2 | # https://github.com/r-hub/actions/blob/v1/workflows/rhub.yaml 3 | # You can update this file to a newer version using the rhub2 package: 4 | # 5 | # rhub::rhub_setup() 6 | # 7 | # It is unlikely that you need to modify this file manually. 8 | 9 | name: R-hub 10 | run-name: "${{ github.event.inputs.id }}: ${{ github.event.inputs.name || format('Manually run by {0}', github.triggering_actor) }}" 11 | 12 | on: 13 | workflow_dispatch: 14 | inputs: 15 | config: 16 | description: 'A comma separated list of R-hub platforms to use.' 17 | type: string 18 | default: 'linux,windows,macos' 19 | name: 20 | description: 'Run name. You can leave this empty now.' 21 | type: string 22 | id: 23 | description: 'Unique ID. You can leave this empty now.' 24 | type: string 25 | 26 | jobs: 27 | 28 | setup: 29 | runs-on: ubuntu-latest 30 | outputs: 31 | containers: ${{ steps.rhub-setup.outputs.containers }} 32 | platforms: ${{ steps.rhub-setup.outputs.platforms }} 33 | 34 | steps: 35 | # NO NEED TO CHECKOUT HERE 36 | - uses: r-hub/actions/setup@v1 37 | with: 38 | config: ${{ github.event.inputs.config }} 39 | id: rhub-setup 40 | 41 | linux-containers: 42 | needs: setup 43 | if: ${{ needs.setup.outputs.containers != '[]' }} 44 | runs-on: ubuntu-latest 45 | name: ${{ matrix.config.label }} 46 | strategy: 47 | fail-fast: false 48 | matrix: 49 | config: ${{ fromJson(needs.setup.outputs.containers) }} 50 | container: 51 | image: ${{ matrix.config.container }} 52 | 53 | steps: 54 | - uses: r-hub/actions/checkout@v1 55 | - name: Install missing dependencies 56 | run: | 57 | sudo apt-get update 58 | sudo apt-get install -y gawk 59 | - uses: r-hub/actions/platform-info@v1 60 | with: 61 | token: ${{ secrets.RHUB_TOKEN }} 62 | job-config: ${{ matrix.config.job-config }} 63 | - uses: r-hub/actions/setup-deps@v1 64 | with: 65 | token: ${{ secrets.RHUB_TOKEN }} 66 | job-config: ${{ matrix.config.job-config }} 67 | - uses: r-hub/actions/run-check@v1 68 | with: 69 | token: ${{ secrets.RHUB_TOKEN }} 70 | job-config: ${{ matrix.config.job-config }} 71 | 72 | other-platforms: 73 | needs: setup 74 | if: ${{ needs.setup.outputs.platforms != '[]' }} 75 | runs-on: ${{ matrix.config.os }} 76 | name: ${{ matrix.config.label }} 77 | strategy: 78 | fail-fast: false 79 | matrix: 80 | config: ${{ fromJson(needs.setup.outputs.platforms) }} 81 | 82 | steps: 83 | - uses: r-hub/actions/checkout@v1 84 | - uses: r-hub/actions/setup-r@v1 85 | with: 86 | job-config: ${{ matrix.config.job-config }} 87 | token: ${{ secrets.RHUB_TOKEN }} 88 | - uses: r-hub/actions/platform-info@v1 89 | with: 90 | token: ${{ secrets.RHUB_TOKEN }} 91 | job-config: ${{ matrix.config.job-config }} 92 | - uses: r-hub/actions/setup-deps@v1 93 | with: 94 | job-config: ${{ matrix.config.job-config }} 95 | token: ${{ secrets.RHUB_TOKEN }} 96 | - uses: r-hub/actions/run-check@v1 97 | with: 98 | job-config: ${{ matrix.config.job-config }} 99 | token: ${{ secrets.RHUB_TOKEN }} 100 | -------------------------------------------------------------------------------- /.github/workflows/test-coverage.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, dev, add_header] 6 | pull_request: 7 | branches: [main, dev, add_header] 8 | 9 | name: test-coverage 10 | 11 | jobs: 12 | test-coverage: 13 | runs-on: ubuntu-latest 14 | env: 15 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | 20 | - uses: r-lib/actions/setup-r@v2 21 | with: 22 | use-public-rspm: true 23 | 24 | - name: Install dependencies Ubuntu 25 | if: runner.os == 'Linux' 26 | run: | 27 | install.packages('remotes') 28 | remotes::install_deps(dependencies = TRUE) 29 | remotes::install_cran("knitr") 30 | remotes::install_cran("rmarkdown") 31 | remotes::install_cran("rcmdcheck") 32 | install.packages("Matrix", type = "source") 33 | install.packages("TMB", type = "source") 34 | shell: Rscript {0} 35 | 36 | - uses: r-lib/actions/setup-r-dependencies@v2 37 | with: 38 | extra-packages: any::covr 39 | needs: coverage 40 | 41 | - name: Test coverage 42 | run: | 43 | covr::codecov( 44 | quiet = FALSE, 45 | clean = FALSE, 46 | install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") 47 | ) 48 | shell: Rscript {0} 49 | 50 | - name: Show testthat output 51 | if: always() 52 | run: | 53 | ## -------------------------------------------------------------------- 54 | find ${{ runner.temp }}/package -name 'testthat.Rout*' -exec cat '{}' \; || true 55 | shell: bash 56 | 57 | - name: Upload test results 58 | if: failure() 59 | uses: actions/upload-artifact@v4 60 | with: 61 | name: coverage-test-failures 62 | path: ${{ runner.temp }}/package 63 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.dll 3 | *.so 4 | inst/doc 5 | ^.*\.Rproj$ 6 | ^\.Rproj\.user$ 7 | .Rproj.user 8 | docs 9 | *.pdf 10 | 11 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Type: Package 2 | Package: tinyVAST 3 | Title: Multivariate Spatio-Temporal Models using Structural Equations 4 | Version: 1.1.1 5 | Date: 2025-05-05 6 | Authors@R: c( 7 | person(c("James", "T."), "Thorson", , "James.Thorson@noaa.gov", 8 | role = c("aut", "cre"), 9 | comment = c(ORCID = "0000-0001-7415-1010")), 10 | person(c("Sean", "C."), "Anderson", , "sean@seananderson.ca", 11 | role = c("aut"), 12 | comment = c(ORCID = "0000-0001-9563-1937")) 13 | ) 14 | Description: Fits a wide variety of multivariate spatio-temporal models 15 | with simultaneous and lagged interactions among variables (including 16 | vector autoregressive spatio-temporal ('VAST') dynamics) 17 | for areal, continuous, or network spatial domains. 18 | It includes time-variable, space-variable, and space-time-variable 19 | interactions using dynamic structural equation models ('DSEM') 20 | as expressive interface, and the 'mgcv' package to specify splines 21 | via the formula interface. See Thorson et al. (2024) 22 | for more details. 23 | License: GPL-3 24 | Depends: 25 | R (>= 4.1.0) 26 | Imports: 27 | corpcor, 28 | fmesher, 29 | igraph, 30 | Matrix (>= 1.3.0), 31 | methods, 32 | mgcv, 33 | sem, 34 | sf, 35 | sfnetworks, 36 | TMB (>= 1.9.17), 37 | units, 38 | checkmate, 39 | abind, 40 | sdmTMB, 41 | dsem (>= 1.6.0), 42 | insight, 43 | cv 44 | Suggests: 45 | ggplot2, 46 | knitr, 47 | lattice, 48 | mvtnorm, 49 | pdp, 50 | rmarkdown, 51 | rnaturalearth, 52 | rnaturalearthdata, 53 | testthat, 54 | tweedie, 55 | viridisLite, 56 | visreg, 57 | plyr, 58 | DHARMa, 59 | glmmTMB, 60 | tibble, 61 | LinkingTo: 62 | RcppEigen, 63 | TMB 64 | VignetteBuilder: 65 | knitr 66 | Config/testthat/edition: 3 67 | Config/testthat/parallel: true 68 | Encoding: UTF-8 69 | LazyData: true 70 | Roxygen: list(markdown = TRUE) 71 | RoxygenNote: 7.3.2 72 | URL: https://vast-lib.github.io/tinyVAST/ 73 | BugReports: https://github.com/vast-lib/tinyVAST/issues 74 | -------------------------------------------------------------------------------- /LICENSE.note: -------------------------------------------------------------------------------- 1 | The tinyVAST package as a whole is distributed under GPL-3. The tinyVAST package includes other open source software components. The following is a list of these components: 2 | 3 | * sem: GPL-2 | GPL-3 4 | * sdmTMB: GPL-3 5 | 6 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(GetResponse,tinyVAST) 4 | S3method(fitted,tinyVAST) 5 | S3method(get_data,tinyVAST) 6 | S3method(logLik,tinyVAST) 7 | S3method(predict,tinyVAST) 8 | S3method(print,tinyVAST) 9 | S3method(residuals,tinyVAST) 10 | S3method(simulate,tinyVAST) 11 | S3method(summary,tinyVAST) 12 | S3method(vcov,tinyVAST) 13 | export(add_predictions) 14 | export(cAIC) 15 | export(delta_gamma) 16 | export(delta_lognormal) 17 | export(deviance_explained) 18 | export(integrate_output) 19 | export(lognormal) 20 | export(make_dsem_ram) 21 | export(make_eof_ram) 22 | export(make_sem_ram) 23 | export(nbinom1) 24 | export(nbinom2) 25 | export(reload_model) 26 | export(rmvnorm_prec) 27 | export(rotate_pca) 28 | export(sample_variable) 29 | export(sfnetwork_evaluator) 30 | export(sfnetwork_mesh) 31 | export(simulate_sfnetwork) 32 | export(term_covariance) 33 | export(tinyVAST) 34 | export(tinyVASTcontrol) 35 | export(tweedie) 36 | import(methods) 37 | importFrom(Matrix,Cholesky) 38 | importFrom(Matrix,Diagonal) 39 | importFrom(Matrix,Matrix) 40 | importFrom(Matrix,diag) 41 | importFrom(Matrix,mat2triplet) 42 | importFrom(Matrix,solve) 43 | importFrom(Matrix,sparseMatrix) 44 | importFrom(Matrix,t) 45 | importFrom(TMB,MakeADFun) 46 | importFrom(TMB,sdreport) 47 | importFrom(abind,abind) 48 | importFrom(checkmate,assertClass) 49 | importFrom(checkmate,assertDataFrame) 50 | importFrom(checkmate,assertNumeric) 51 | importFrom(checkmate,checkInteger) 52 | importFrom(checkmate,checkNumeric) 53 | importFrom(corpcor,pseudoinverse) 54 | importFrom(cv,GetResponse) 55 | importFrom(cv,cv) 56 | importFrom(dsem,make_matrices) 57 | importFrom(fmesher,fm_evaluator) 58 | importFrom(fmesher,fm_fem) 59 | importFrom(fmesher,fm_mesh_2d) 60 | importFrom(igraph,as_adjacency_matrix) 61 | importFrom(igraph,ecount) 62 | importFrom(insight,get_data) 63 | importFrom(insight,get_response) 64 | importFrom(methods,as) 65 | importFrom(methods,is) 66 | importFrom(sdmTMB,lognormal) 67 | importFrom(sdmTMB,nbinom1) 68 | importFrom(sdmTMB,nbinom2) 69 | importFrom(sdmTMB,tweedie) 70 | importFrom(sem,specifyEquations) 71 | importFrom(sem,specifyModel) 72 | importFrom(sf,st_as_sf) 73 | importFrom(sf,st_crs) 74 | importFrom(sf,st_distance) 75 | importFrom(sf,st_geometry) 76 | importFrom(sf,st_length) 77 | importFrom(sf,st_nearest_feature) 78 | importFrom(sfnetworks,activate) 79 | importFrom(stats,.getXlevels) 80 | importFrom(stats,Gamma) 81 | importFrom(stats,binomial) 82 | importFrom(stats,fitted) 83 | importFrom(stats,gaussian) 84 | importFrom(stats,lm) 85 | importFrom(stats,logLik) 86 | importFrom(stats,model.frame) 87 | importFrom(stats,model.matrix) 88 | importFrom(stats,model.offset) 89 | importFrom(stats,model.response) 90 | importFrom(stats,na.omit) 91 | importFrom(stats,nlminb) 92 | importFrom(stats,optimHess) 93 | importFrom(stats,pnorm) 94 | importFrom(stats,poisson) 95 | importFrom(stats,predict) 96 | importFrom(stats,rnorm) 97 | importFrom(stats,simulate) 98 | importFrom(stats,terms) 99 | importFrom(stats,update) 100 | importFrom(stats,update.formula) 101 | importFrom(stats,vcov) 102 | importFrom(units,drop_units) 103 | useDynLib(tinyVAST, .registration = TRUE) 104 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # tinyVAST 1.1.1 2 | 3 | * Adding option for geometric anisotropy when using the SPDE method 4 | * For some reason, the CPP edits also address an error message 5 | during `devtools::check_win_devel` "array subscript 'const __m128i[0]' is 6 | partly outside array bounds of 'unsigned char [12]'" 7 | 8 | # tinyVAST 1.1.0 9 | 10 | * Adding `term_covariance` to calculate the covariance among variables for SEM term, 11 | or covariance among variables-and-lags for DSEM terms 12 | * Adding Restricted Spatial Regression estimator for covariates `alphaprime_j` and `alphaprime2_j` 13 | to `fit$rep` output. 14 | * Adding methods to allow use of `cv` to calculate crossvalidation skill 15 | * Add `bias.correct` option to predict (but still no flag for SEs for anything except p_i) 16 | * Switch `sample_variable` from using `obj$env$MC` to `obj$env$spHess(random=TRUE)` 17 | which seems more stable as dependency 18 | * Add functionality for `te` and `ti` splines, although they remain poorly tested 19 | * Add error check to `sfnetwork_mesh` to detect if the stream network is not ordered 20 | as a tree 21 | * Improve stream network vignette to use matrix notation for joint precision, and 22 | modify `simulate_sfnetwork` to use that 23 | * Change `tinyVAST.cpp` to use matrix notation constructor and fix bug in previous 24 | constructor where the covariance between first and second nodes was not right 25 | * Expand `test-sfnetworks.R` integrated test to confirm that matrix-notation 26 | precision constructor is identical to the inverse of Ornstein-Uhlenbeck covariance 27 | as intended. 28 | 29 | # tinyVAST 1.0.1 30 | 31 | * Modify examples for `simulate.tinyVAST` and `sample_variable` to try to avoid 32 | terminal output giving error in valgrind check 33 | * Add `ivector_minus_one` function to satisfy clang-UBSAN 34 | * Swap `GMRF(Q).Quadform(x)` to `x.matrix().transpose() * (Q * x.matrix())` to 35 | avoid calculating log-determinant of `Q` in the smoothers penalty, to avoid 36 | valgrind errors 37 | * Add tinyVASTcontrol option that suppresses nlminb warning messages by default, 38 | which are typically not informative to casual users 39 | 40 | # tinyVAST 1.0.0 41 | 42 | * Adding nbinom1 and nbinom2 families 43 | * Simplify argument names, by changing `sem` to `space_term`, `dsem` to `spacetime_term` 44 | and `spatial_graph` to `spatial_domain`, and eliminating `delta_` in the names 45 | for arguments to `delta_options` 46 | * Add `time_term` to allow time-variable interaction (e.g., AR1 intercepts) 47 | * Adding overview and model-description vignettes 48 | * Add `simulate` S3 generic 49 | 50 | # tinyVAST 0.7.1 51 | 52 | * Fixed bug (wrong output) when using `predict(fit, what="mu_g")` and 53 | a Poisson-linked delta model 54 | * Fixed bug (cryptic error message) when using `integrate_output` 55 | * Add `cAIC` (but disabling EDF calculation for now) 56 | 57 | # tinyVAST 0.7.0 58 | 59 | * Adding option for spatially-varying-coefficient (SVC) models 60 | * Add error-check for when `data` has a factor with extra levels, which 61 | conflicted with the logic of adding all `origdata` levels to `newdata` 62 | when calling `predict`, and hence caused an uniformative error previously 63 | 64 | # tinyVAST 0.6.0 65 | 66 | * Change `integrate_output` interface by splitting `W_gz` and `V_gz` 67 | into four vectors `area`, `type`, `covariate`, and `weighting_index` 68 | to simplify documentations and improve naming 69 | * Fix bug where cloglog and logit links were not previously implemented 70 | for use in `predict` and `integrate_output` 71 | 72 | # tinyVAST 0.5.0 73 | 74 | * Adding vignette showing how to fit multiple data types in an SDM 75 | * Adding `deviance_explained` and calculating this by default 76 | 77 | # tinyVAST 0.4.0 78 | 79 | * Adding code for simulation residuals, and examples to vignettes 80 | 81 | # tinyVAST 0.3.0 82 | 83 | * Adding `sdmTMB` as dependency, and importing family options from it 84 | * Adding vignette for joint analysis of condition and density 85 | 86 | # tinyVAST 0.2.0 87 | 88 | * Add option to specify covariance in SEM and DSEM notation 89 | 90 | # tinyVAST 0.1.0 91 | 92 | * Initial public alpha release 93 | -------------------------------------------------------------------------------- /R/cAIC.R: -------------------------------------------------------------------------------- 1 | #' Calculate conditional AIC 2 | #' 3 | #' Calculates the conditional Akaike Information criterion (cAIC). 4 | #' 5 | #' @param object Output from [tinyVAST()]. 6 | #' 7 | #' @details cAIC is designed to optimize the expected out-of-sample predictive 8 | #' performance for new data that share the same random effects as the in-sample 9 | #' (fitted) data, e.g., spatial interpolation. In this sense, it should be a 10 | #' fast approximation to optimizing the model structure based on k-fold 11 | #' cross-validation. 12 | #' 13 | #' By contrast, [AIC()] calculates the marginal Akaike Information Criterion, 14 | #' which is designed to optimize expected predictive performance for new data 15 | #' that have new random effects, e.g., extrapolation, or inference about 16 | #' generative parameters. 17 | #' 18 | #' Both cAIC and EDF are calculated using Eq. 6 of Zheng, Cadigan, and Thorson 19 | #' (2024). 20 | #' 21 | #' For models that include profiled fixed effects, these profiles are turned 22 | #' off. 23 | #' 24 | #' @return 25 | #' cAIC value 26 | #' 27 | #' @references 28 | #' Zheng, N., Cadigan, N., & Thorson, J. T. (2024). 29 | #' A note on numerical evaluation of conditional Akaike information for 30 | #' nonlinear mixed-effects models (arXiv:2411.14185). arXiv. 31 | #' \doi{10.48550/arXiv.2411.14185} 32 | #' 33 | #' @examples 34 | #' data( red_snapper ) 35 | #' red_snapper = droplevels(subset(red_snapper, Data_type=="Biomass_KG")) 36 | #' 37 | #' # Define mesh 38 | #' mesh = fmesher::fm_mesh_2d( red_snapper[,c('Lon','Lat')], 39 | #' cutoff = 1 ) 40 | #' 41 | #' # define formula with a catchability covariate for gear 42 | #' formula = Response_variable ~ factor(Year) + offset(log(AreaSwept_km2)) 43 | #' 44 | #' # make variable column 45 | #' red_snapper$var = "logdens" 46 | # 47 | #' # fit using tinyVAST 48 | #' fit = tinyVAST( data = red_snapper, 49 | #' formula = formula, 50 | #' sem = "logdens <-> logdens, sd_space", 51 | #' space_columns = c("Lon",'Lat'), 52 | #' spatial_graph = mesh, 53 | #' family = tweedie(link="log"), 54 | #' variable_column = "var", 55 | #' control = tinyVASTcontrol( getsd = FALSE, 56 | #' profile = "alpha_j" ) ) 57 | #' 58 | #' cAIC(fit) # conditional AIC 59 | #' AIC(fit) # marginal AIC 60 | #' 61 | #' @export 62 | cAIC <- 63 | function( object ){ 64 | 65 | #what = match.arg(what) 66 | #requireNamespace(Matrix) 67 | data = object$tmb_inputs$tmb_data 68 | 69 | # Make sure profile = NULL 70 | if( is.null(object$internal$control$profile) ){ 71 | obj = object$obj 72 | }else{ 73 | obj = TMB::MakeADFun( data = data, 74 | parameters = object$internal$parlist, 75 | map = object$tmb_inputs$tmb_map, 76 | random = object$tmb_inputs$tmb_random, 77 | DLL = "tinyVAST", 78 | profile = NULL ) 79 | } 80 | 81 | # Make obj_new 82 | data$weights_i[] = 0 83 | obj_new = TMB::MakeADFun( data = data, 84 | parameters = object$internal$parlist, 85 | map = object$tmb_inputs$tmb_map, 86 | random = object$tmb_inputs$tmb_random, 87 | DLL = "tinyVAST", 88 | profile = NULL ) 89 | 90 | # 91 | par = obj$env$parList() 92 | parDataMode <- obj$env$last.par 93 | indx = obj$env$lrandom() 94 | q = sum(indx) 95 | p = length(object$opt$par) 96 | 97 | ## use - for Hess because model returns negative loglikelihood; 98 | #cov_Psi_inv = -Hess_new[indx,indx]; ## this is the marginal prec mat of REs; 99 | Hess_new = -Matrix::Matrix(obj_new$env$f(parDataMode,order=1,type="ADGrad"),sparse = TRUE) 100 | Hess_new = Hess_new[indx,indx] 101 | 102 | ## Joint hessian etc 103 | Hess = -Matrix::Matrix(obj$env$f(parDataMode,order=1,type="ADGrad"),sparse = TRUE) 104 | Hess = Hess[indx,indx] 105 | negEDF = Matrix::diag(Matrix::solve(Hess, Hess_new)) 106 | 107 | #if(what == "cAIC"){ 108 | jnll = obj$env$f(parDataMode) 109 | cnll = jnll - obj_new$env$f(parDataMode) 110 | cAIC = 2*cnll + 2*(p+q) - 2*sum(negEDF) 111 | return(cAIC) 112 | #} 113 | #if(what == "EDF"){ 114 | # group = colnames(object$tmb_inputs$tmb_data$Z_ik) 115 | # group = sapply(group, FUN=\(char)strsplit(char,split=".",fixed=TRUE)[[1]][1]) 116 | # group = factor(group) 117 | # EDF = tapply(negEDF,INDEX=group,FUN=length) - tapply(negEDF,INDEX=group,FUN=sum) 118 | # return(EDF) 119 | #} 120 | } 121 | -------------------------------------------------------------------------------- /R/data.R: -------------------------------------------------------------------------------- 1 | 2 | #' Arctic September sea ice concentrations 3 | #' 4 | #' Data used to demonstrate and test empirical orthogonal function 5 | #' generalized linear latent variable model (EOF-GLLVM) 6 | #' 7 | #' @name sea_ice 8 | #' @docType data 9 | #' @usage data(sea_ice) 10 | #' @keywords data 11 | NULL 12 | 13 | #' North Pacific salmon returns 14 | #' 15 | #' Data used to demonstrate and test multivariate second-order autoregressive 16 | #' models using a simultaneous autoregressive (SAR) process across regions. 17 | #' Data are from \doi{10.1002/mcf2.10023} 18 | #' 19 | #' @name salmon_returns 20 | #' @docType data 21 | #' @usage data(salmon_returns) 22 | #' @keywords data 23 | NULL 24 | 25 | #' Condition and density example 26 | #' 27 | #' Data used to demonstrate and test a bivariate model for morphometric condition 28 | #' (i.e., residuals in a weight-at-length relationship) and density for fishes, using 29 | #' the same example as was provided as a wiki example for VAST. 30 | #' Data are from \doi{10.3354/meps13213} 31 | #' 32 | #' @name condition_and_density 33 | #' @docType data 34 | #' @usage data(condition_and_density) 35 | #' @keywords data 36 | NULL 37 | 38 | #' Survey catch-rates at age for Alaska pollock in the Eastern and Northern Bering Sea 39 | #' 40 | #' Data used to demonstrate and test model-based age expansion, using density= 41 | #' dependence corrected survey catch rates after first=stage expansion 42 | #' from the bottom trawl survey for ages 1-15, conducted by 43 | #' by the Alaska Fisheries Science Center, including annual surveys in the eastern 44 | #' Bering Sea 1982-2019 and 2021-2023, as well as the northern Bering Sea 45 | #' in 1982/85/88/91 and 2010/17/18/19/21/22/23. 46 | #' 47 | #' @name bering_sea_pollock_ages 48 | #' @docType data 49 | #' @usage data(bering_sea_pollock_ages) 50 | #' @keywords data 51 | NULL 52 | 53 | #' Survey domain for the eastern and northern Bering Sea surveys 54 | #' 55 | #' Shapefile defining the spatial domain for the eastern and northern 56 | #' Bering Sea bottom trawl surveys. 57 | #' 58 | #' @name bering_sea 59 | #' @docType data 60 | #' @usage data(bering_sea) 61 | #' @keywords data 62 | NULL 63 | 64 | #' Estimated proportion-at-age for Alaska pollock using VAST 65 | #' 66 | #' Estimated proporrtion-at-age for Alaska pollock using the 67 | #' package VAST, for comparison with output using tinyVAST. 68 | #' 69 | #' @name bering_sea_pollock_vast 70 | #' @docType data 71 | #' @usage data(bering_sea_pollock_vast) 72 | #' @keywords data 73 | NULL 74 | 75 | #' Presence/absence, count, and biomass data for red snapper 76 | #' 77 | #' Data used to demonstrate and test analysis using multiple data types 78 | #' 79 | #' @name red_snapper 80 | #' @docType data 81 | #' @usage data(red_snapper) 82 | #' @keywords data 83 | NULL 84 | 85 | #' Shapefile for red snapper analysis 86 | #' 87 | #' Spatial extent used for red snapper analysis, derived from Chap-7 of \doi{10.1201/9781003410294} 88 | #' 89 | #' @name red_snapper_shapefile 90 | #' @docType data 91 | #' @usage data(red_snapper_shapefile) 92 | #' @keywords data 93 | NULL 94 | 95 | -------------------------------------------------------------------------------- /R/family.R: -------------------------------------------------------------------------------- 1 | # modified from glmmTMB 2 | # extra stuff for Effects package, class, etc. 3 | add_to_family <- function(x) { 4 | # x <- c(x, list(link = link), make.link(link)) 5 | # Effect.default/glm.fit 6 | if (is.null(x$aic)) { 7 | x <- c(x, list(aic = function(...) NA_real_)) 8 | } 9 | if (is.null(x$initialize)) { 10 | x <- c(x, list(initialize = expression({ 11 | mustart <- y + 0.1 12 | }))) 13 | } 14 | if (is.null(x$dev.resids)) { 15 | # can't return NA, glm.fit is unhappy 16 | x <- c(x, list(dev.resids = function(y, mu, wt) { 17 | rep(0, length(y)) 18 | })) 19 | } 20 | class(x) <- "family" 21 | x 22 | } 23 | 24 | #' @export 25 | #' @importFrom sdmTMB lognormal 26 | sdmTMB::lognormal 27 | 28 | #' @export 29 | #' @importFrom sdmTMB nbinom2 30 | sdmTMB::nbinom2 31 | 32 | #' @export 33 | #' @importFrom sdmTMB nbinom1 34 | sdmTMB::nbinom1 35 | 36 | #' @export 37 | #' @importFrom sdmTMB tweedie 38 | sdmTMB::tweedie 39 | 40 | #' Additional families 41 | #' 42 | #' Additional families compatible with [tinyVAST()]. 43 | #' 44 | #' @param link Link. 45 | #' @export 46 | #' @rdname families 47 | #' @name Families 48 | #' 49 | #' @return 50 | #' A list with elements common to standard R family objects including `family`, 51 | #' `link`, `linkfun`, and `linkinv`. Delta/hurdle model families also have 52 | #' elements `delta` (logical) and `type` (standard vs. Poisson-link). 53 | #' 54 | #' @references 55 | #' *Poisson-link delta families*: 56 | #' 57 | #' Thorson, J.T. 2018. Three problems with the conventional delta-model for 58 | #' biomass sampling data, and a computationally efficient alternative. Canadian 59 | #' Journal of Fisheries and Aquatic Sciences, 75(9), 1369-1382. 60 | #' \doi{10.1139/cjfas-2017-0266} 61 | #' 62 | delta_lognormal <- function(link1, link2 = "log", type = c("standard", "poisson-link")) { 63 | type <- match.arg(type) 64 | if( missing(link1) ){ 65 | if(type=="standard") link1 = "logit" 66 | if(type=="poisson-link") link1 = "log" 67 | } 68 | l1 <- substitute(link1) 69 | if (!is.character(l1)) l1 <- deparse(l1) 70 | l2 <- substitute(link2) 71 | if (!is.character(l2)) l2 <- deparse(l2) 72 | f1 <- binomial(link = l1) 73 | f2 <- lognormal(link = l2) 74 | if (type == "poisson-link") { 75 | .type <- "poisson_link_delta" 76 | clean_name <- paste0("delta_lognormal(link1 = '", l1, "', link2 = '", l2, "', type = 'poisson-link')") 77 | } else { 78 | .type <- "standard" 79 | clean_name <- paste0("delta_lognormal(link1 = '", l1, "', link2 = '", l2, "')") 80 | } 81 | structure(list(f1, f2, delta = TRUE, link = c("log", "log"), 82 | family = c("binomial", "lognormal"), type = .type, 83 | clean_name = clean_name), class = "family") 84 | } 85 | 86 | #' @param link1 Link for first part of delta/hurdle model. 87 | #' @param link2 Link for second part of delta/hurdle model. 88 | #' @param type Delta/hurdle family type. `"standard"` for a classic hurdle 89 | #' model. `"poisson-link"` for a Poisson-link delta model (Thorson 2018). 90 | #' @export 91 | #' @importFrom stats Gamma binomial 92 | #' @rdname families 93 | #' @references 94 | #' *Poisson-link delta families*: 95 | #' 96 | #' Thorson, J.T. 2018. Three problems with the conventional delta-model for 97 | #' biomass sampling data, and a computationally efficient alternative. Canadian 98 | #' Journal of Fisheries and Aquatic Sciences, 75(9), 1369-1382. 99 | #' \doi{10.1139/cjfas-2017-0266} 100 | delta_gamma <- function(link1, link2 = "log", type = c("standard", "poisson-link")) { 101 | type <- match.arg(type) 102 | if( missing(link1) ){ 103 | if(type=="standard") link1 = "logit" 104 | if(type=="poisson-link") link1 = "log" 105 | } 106 | l1 <- substitute(link1) 107 | if (!is.character(l1)) l1 <- deparse(l1) 108 | l2 <- substitute(link2) 109 | if (!is.character(l2)) l2 <- deparse(l2) 110 | f1 <- binomial(link = l1) 111 | f2 <- Gamma(link = l2) 112 | if (type == "poisson-link") { 113 | .type <- "poisson_link_delta" 114 | clean_name <- paste0("delta_gamma(link1 = '", l1, "', link2 = '", l2, "', type = 'poisson-link')") 115 | } else { 116 | .type <- "standard" 117 | clean_name <- paste0("delta_gamma(link1 = '", l1, "', link2 = '", l2, "')") 118 | } 119 | structure(list(f1, f2, delta = TRUE, link = c(l1, l2), 120 | type = .type, family = c("binomial", "Gamma"), 121 | clean_name = clean_name), class = "family") 122 | } 123 | 124 | -------------------------------------------------------------------------------- /R/internal.R: -------------------------------------------------------------------------------- 1 | .onAttach <- function(libname, pkgname) { 2 | } 3 | 4 | ivector_minus_one <- function( ivector ){ 5 | if( any(is.na(ivector)) ) stop("Check ivector for NAs") 6 | if( length(ivector) > 0 ){ 7 | ivector = as.integer( ivector - 1 ) 8 | } 9 | return(ivector) 10 | } 11 | 12 | # Modified from sdmTMB::make_anisotropy_spde 13 | make_anisotropy_spde <- 14 | function( inla_mesh ){ 15 | 16 | spde = fm_fem( inla_mesh ) 17 | Dset <- 1:2 18 | TV <- inla_mesh$graph$tv 19 | V0 <- inla_mesh$loc[TV[, 1], Dset] 20 | V1 <- inla_mesh$loc[TV[, 2], Dset] 21 | V2 <- inla_mesh$loc[TV[, 3], Dset] 22 | E0 <- V2 - V1 23 | E1 <- V0 - V2 24 | E2 <- V1 - V0 25 | TmpFn <- function(Vec1, Vec2) abs(det(rbind(Vec1, Vec2))) 26 | Tri_Area <- rep(NA, nrow(E0)) 27 | for (i in seq_len(length(Tri_Area))){ 28 | Tri_Area[i] <- TmpFn(E0[i,], E1[i,])/2 29 | } 30 | ret <- list( n_s = inla_mesh$n, 31 | n_tri = nrow(TV), 32 | Tri_Area = Tri_Area, 33 | E0 = E0, 34 | E1 = E1, 35 | E2 = E2, 36 | TV = TV - 1, 37 | G0 = spde$c0, 38 | G0_inv = as(Matrix::diag(1/Matrix::diag(spde$c0)),"TsparseMatrix") ) 39 | return(ret) 40 | } 41 | 42 | 43 | #rm_wsp <- function (x) { 44 | # # from brms:::rm_wsp() 45 | # # VIA sdmTMB smoothers.R 46 | # out <- gsub("[ \t\r\n]+", "", x, perl = TRUE) 47 | # dim(out) <- dim(x) 48 | # out 49 | #} 50 | 51 | #all_terms <- function (x) { 52 | # # from brms:::all_terms() 53 | # # VIA sdmTMB smoothers.R 54 | # if (!length(x)) { 55 | # return(character(0)) 56 | # } 57 | # if (!inherits(x, "terms")) { 58 | # x <- terms(stats::as.formula(x)) 59 | # } 60 | # rm_wsp(attr(x, "term.labels")) 61 | #} 62 | 63 | #get_smooth_terms <- function(terms) { 64 | # # from brms:::all_terms() 65 | # # VIA sdmTMB smoothers.R 66 | # x1 <- grep("s\\(", terms) 67 | # x2 <- grep("t2\\(", terms) 68 | # c(x1, x2) 69 | #} 70 | 71 | 72 | -------------------------------------------------------------------------------- /R/make_eof_ram.R: -------------------------------------------------------------------------------- 1 | #' @title Make a RAM (Reticular Action Model) 2 | #' 3 | #' @description \code{make_eof_ram} converts SEM arrow notation to \code{ram} describing SEM parameters 4 | #' 5 | #' @param times A character vector listing the set of times in order 6 | #' @param variables A character vector listing the set of variables 7 | #' @param n_eof Number of EOF modes of variability to estimate 8 | #' @param remove_na Boolean indicating whether to remove NA values from RAM (default) or not. 9 | #' \code{remove_NA=FALSE} might be useful for exploration and diagnostics for 10 | #' advanced users 11 | #' @param standard_deviations One of `"equal"`, `"unequal"`, or a numeric vector 12 | #' indicating fixed values. 13 | #' 14 | #' @return A reticular action module (RAM) describing dependencies 15 | #' 16 | #' @examples 17 | #' # Two EOFs for two variables 18 | #' make_eof_ram( times = 2010:2020, variables = c("pollock","cod"), n_eof=2 ) 19 | #' 20 | #' @export 21 | make_eof_ram <- 22 | function( times, 23 | variables, 24 | n_eof, 25 | remove_na = TRUE, 26 | standard_deviations = "unequal" ){ 27 | # Docs : https://roxygen2.r-lib.org/articles/formatting.html 28 | 29 | ####### Error checks 30 | 31 | if( isFALSE((standard_deviations %in% c("equal","unequal")) || is.numeric(standard_deviations)) ){ 32 | stop("Check `standard_deviations` in `make_eof_ram`") 33 | } 34 | 35 | ######## Step 1 -- Make model 36 | EOF_names = paste0("EOF_",seq_len(n_eof)) 37 | L_tz = matrix(NA, nrow=length(times), ncol=n_eof, dimnames=list(times,EOF_names)) 38 | L_tz[lower.tri(L_tz, diag=TRUE)] = 1:sum(lower.tri(L_tz, diag=TRUE)) 39 | 40 | # 41 | model = data.frame( expand.grid("to"=rownames(L_tz),"from"=colnames(L_tz)), "parameter"=as.vector(L_tz) ) 42 | variances = data.frame( "to" = c(EOF_names,as.character(variables)), 43 | "from" = c(EOF_names,as.character(variables)), 44 | "parameter" = c(rep(0,n_eof),max(model[,3],na.rm=TRUE)+1:length(variables)) ) 45 | if( standard_deviations == "equal" ){ 46 | variances$parameter = ifelse( variances$parameter==0, 0, min(ifelse(variances$parameter==0,NA,variances$parameter),na.rm=TRUE) ) 47 | }else if( is.numeric(standard_deviations) ){ 48 | variances$parameter = ifelse( variances$parameter==0, 0, NA ) 49 | } 50 | #model = rbind( model, variances ) 51 | 52 | ####### Step 2 -- Make RAM 53 | 54 | # Global stuff 55 | Q_names = expand.grid( "times"=c(EOF_names,times), "variables"=variables ) 56 | ram = NULL # heads, to, from, parameter, start 57 | 58 | # Loop through paths 59 | for( from in seq_len(nrow(Q_names)) ){ 60 | for( to in seq_len(nrow(Q_names)) ){ 61 | if( (as.character(Q_names[to,1]) %in% rownames(L_tz)) & (as.character(Q_names[from,1]) %in% colnames(L_tz)) ){ 62 | if( !is.na(L_tz[as.character(Q_names[to,1]),as.character(Q_names[from,1])]) ){ 63 | ram_new = c( 1, to, from, L_tz[as.character(Q_names[to,1]),as.character(Q_names[from,1])], 0.01 ) 64 | ram = rbind( ram, ram_new ) 65 | } 66 | } 67 | }} 68 | 69 | # Loop through variances 70 | for( from in seq_len(nrow(Q_names)) ){ 71 | varnum = ifelse( Q_names[from,'times'] %in% times, 72 | variances[ match(Q_names[from,'variables'], variances[,'to']), 'parameter'], 73 | variances[ match(Q_names[from,'times'], variances[,'to']), 'parameter'] ) 74 | ram_new = c( 2, from, from, varnum, ifelse(varnum==0, 1, NA) ) 75 | if( is.na(ram_new[4]) ){ 76 | ram_new[4:5] = c(0, standard_deviations) 77 | } 78 | ram = rbind( ram, ram_new ) 79 | } 80 | dimnames(ram) = list(NULL, c('heads','to','from','parameter','start')) 81 | 82 | if( isTRUE(remove_na) ){ 83 | which_keep = which(apply( ram[,1:4], MARGIN=1, FUN=\(x)!any(is.na(x)) )) 84 | ram = ram[ which_keep, ] 85 | } 86 | 87 | # 88 | out = list( "model" = model, 89 | "ram" = ram, 90 | "variances" = variances, 91 | "standard_deviations" = standard_deviations ) 92 | class(out) = "eof_ram" 93 | return(out) 94 | } 95 | -------------------------------------------------------------------------------- /R/make_sem_ram.R: -------------------------------------------------------------------------------- 1 | #' @title Make a RAM (Reticular Action Model) from a SEM (structural equation model) 2 | #' 3 | #' @description \code{make_sem_ram} converts SEM arrow notation to \code{ram} describing SEM parameters 4 | #' 5 | #' @param sem structural equation model structure, passed to either \code{\link[sem]{specifyModel}} 6 | #' or \code{\link[sem]{specifyEquations}} and then parsed to control 7 | #' the set of path coefficients and variance-covariance parameters 8 | #' @param variables A character vector listing the set of variables 9 | #' 10 | #' @inheritParams sem::specifyModel 11 | #' 12 | #' @return An S3-class \code{"sem_ram"} containing: 13 | #' \describe{ 14 | #' \item{\code{model}}{Output from \code{\link[sem]{specifyEquations}} or \code{\link[sem]{specifyModel}} 15 | #' that defines paths and parameters} 16 | #' \item{\code{ram}}{reticular action module (RAM) describing dependencies} 17 | #' } 18 | #' 19 | #' @export 20 | make_sem_ram <- 21 | function( sem, 22 | variables, 23 | quiet = FALSE, 24 | covs = variables ){ 25 | 26 | # 27 | model = tryCatch( 28 | specifyModel( text=sem, exog.variances=TRUE, endog.variances=TRUE, covs=as.character(covs), quiet=quiet ), 29 | error = function(e) e 30 | ) 31 | if( isFALSE("semmod" %in% class(model)) ){ 32 | model = tryCatch( 33 | specifyEquations( text=sem, exog.variances=TRUE, endog.variances=TRUE, covs=as.character(covs) ), 34 | error = function(e) e 35 | ) 36 | } 37 | if( isFALSE("semmod" %in% class(model)) ){ 38 | stop("Must supply either input for `sem::specifyModel` or `sem::specifyEquations`") 39 | } 40 | 41 | #vars = sapply( vars, FUN=function(char){gsub("-", "", gsub(" ", "", char))} ) 42 | n.paths = nrow(model) 43 | par.names = model[, 2] 44 | startvalues = model[,3] 45 | 46 | # EXCERPT FROM `getAnywhere("sem.semmod")` 47 | heads = from = to = rep(0, n.paths) 48 | for (p in 1:n.paths) { 49 | #path = sem:::parse.path(model[p, 1]) 50 | path = parse_path(model[p, 1]) 51 | heads[p] = abs(path$direction) 52 | to[p] = path$second 53 | from[p] = path$first 54 | if (path$direction == -1) { 55 | to[p] = path$first 56 | from[p] = path$second 57 | } 58 | } 59 | missing_vars = setdiff( c(from,to), variables ) 60 | if( length(missing_vars) > 0 ) stop( "Check `build_ram`:", paste0(missing_vars,sep=", ") ) 61 | 62 | ram = data.frame(matrix(0, nrow=p, ncol=5)) 63 | pars = na.omit(unique(par.names)) 64 | ram[, 1] = heads 65 | ram[, 2] = apply(outer(variables, to, "=="), 2, which) 66 | ram[, 3] = apply(outer(variables, from, "=="), 2, which) 67 | par.nos = apply(outer(pars, par.names, "=="), 2, which) 68 | if(length(par.nos) > 0){ 69 | ram[, 4] = unlist(lapply(par.nos, function(x) if (length(x)==0){0}else{x})) 70 | } 71 | ram[, 5] = startvalues 72 | colnames(ram) = c("heads", "to", "from", "parameter", "start") 73 | 74 | # 75 | out = list( "ram"=ram, "model"=model ) 76 | class(out) = "sem_ram" 77 | return(out) 78 | } 79 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: 3 | github_document: 4 | toc: true 5 | toc_depth: 3 6 | df_print: "tibble" 7 | includes: 8 | in_header: header.md 9 | --- 10 | 11 | ```{r setup, include = FALSE} 12 | knitr::opts_chunk$set( 13 | collapse = TRUE, 14 | comment = "#>", 15 | fig.path = "man/figures/README-", 16 | out.width = "50%", 17 | cache = FALSE, 18 | autodep = TRUE, 19 | dpi = 72 20 | ) 21 | ``` 22 | 23 | ## Installation 24 | 25 | tinyVAST can be installed from GitHub: 26 | 27 | ```{r, eval=FALSE} 28 | library(devtools) 29 | install_github("vast-lib/tinyVAST", dependencies = TRUE) 30 | ``` 31 | 32 | 33 | ## Citation 34 | 35 | To cite tinyVAST in publications use: 36 | 37 | ```r 38 | citation("tinyVAST") 39 | ``` 40 | 41 | Thorson, J. T., Anderson, S. C., Goddard, P., & Rooper, C. N. (2024). 42 | tinyVAST: R package with an expressive interface to specify lagged 43 | and simultaneous effects in multivariate spatio-temporal models 44 | (arXiv:2401.10193). arXiv. 45 | 46 | 47 | 48 | ## Related software 49 | 50 | tinyVAST is builds upon many packages. This includes [VAST](https://github.com/James-Thorson-NOAA/VAST) R package: 51 | 52 | Thorson, J.T. 2019. Guidance for decisions using the Vector Autoregressive Spatio-Temporal (VAST) package in stock, ecosystem, habitat and climate assessments. Fisheries Research 210: 143–161. . 53 | 54 | and [sdmTMB](https://github.com/pbs-assess/sdmTMB) R package: 55 | 56 | Anderson, S.C., E.J. Ward, P.A. English, L.A.K. Barnett. 2022. sdmTMB: an R package for fast, flexible, and user-friendly generalized linear mixed effects models with spatial and spatiotemporal random fields. bioRxiv 2022.03.24.485545; doi: https://doi.org/10.1101/2022.03.24.485545 57 | 58 | and the [glmmTMB](https://github.com/glmmTMB/glmmTMB) R package: 59 | 60 | Brooks, M.E., Kristensen, K., van Benthem, K.J., Magnusson, A., Berg, C.W., Nielsen, A., Skaug, H.J., Maechler, M., and Bolker, B.M. 2017. glmmTMB balances speed and flexibility among packages for zero-inflated generalized linear mixed modeling. The R Journal 9(2): 378–400. . 61 | 62 | [INLA](https://www.r-inla.org/) and [inlabru](https://sites.google.com/inlabru.org/inlabru) can fit many of the same models as sdmTMB (and many more) in an approximate Bayesian inference framework. 63 | 64 | [mgcv](https://cran.r-project.org/package=mgcv) can fit similar SPDE-based Gaussian random field models with code included in [Miller et al. (2019)](https://doi.org/10.1007/s13253-019-00377-z). 65 | 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # tinyVAST 5 | 6 | > Multivariate spatio-temporal models using dynamic structural equations 7 | 8 | 9 | [![R-CMD-check](https://github.com/James-Thorson-NOAA/tinyVAST/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/James-Thorson-NOAA/tinyVAST/actions/workflows/R-CMD-check.yaml) 10 | [![Codecov test coverage](https://codecov.io/gh/vast-lib/tinyVAST/branch/main/graph/badge.svg)](https://app.codecov.io/gh/vast-lib/tinyVAST?branch=main) 11 | [![Documentation](https://img.shields.io/badge/documentation-tinyVAST-orange.svg?colorB=E91E63)](https://vast-lib.github.io/tinyVAST/) 12 | [![DOI](https://zenodo.org/badge/704919773.svg)](https://doi.org/10.5281/zenodo.15001856) 13 | [![](https://www.r-pkg.org/badges/version/tinyVAST)](https://cran.r-project.org/package=tinyVAST) 14 | [![](https://cranlogs.r-pkg.org/badges/tinyVAST)](https://cran.r-project.org/package=tinyVAST) 15 | [![](https://cranlogs.r-pkg.org/badges/grand-total/tinyVAST)](https://cran.r-project.org/package=tinyVAST) 16 | 17 | 18 | tinyVAST is an R package that fits multivariate spatio-temporal models while using Gaussian Markov random fields to represent nonseparable interactions among variables over time. See a preprint: 19 | 20 | Thorson, J. T., Anderson, S. C., Goddard, P., & Rooper, C. N. (2024). tinyVAST: R package with an expressive interface to specify lagged and simultaneous effects in multivariate spatio-temporal models (arXiv:2401.10193). arXiv. http://arxiv.org/abs/2401.10193 21 | 22 | ## Table of contents 23 | 24 | - [Installation](#installation) 25 | - [Citation](#citation) 26 | - [Related software](#related-software) 27 | 28 | ## Installation 29 | 30 | tinyVAST can be installed from GitHub: 31 | 32 | ``` r 33 | library(devtools) 34 | install_github("vast-lib/tinyVAST", dependencies = TRUE) 35 | ``` 36 | 37 | ## Citation 38 | 39 | To cite tinyVAST in publications use: 40 | 41 | ``` r 42 | citation("tinyVAST") 43 | ``` 44 | 45 | Thorson, J. T., Anderson, S. C., Goddard, P., & Rooper, C. N. (2025). 46 | tinyVAST: R package with an expressive interface to specify lagged and 47 | simultaneous effects in multivariate spatio-temporal models. 48 | Global Ecology and Biogeography. 34(4): e70035. 49 | 50 | ## Related software 51 | 52 | tinyVAST is builds upon many packages. This includes 53 | [VAST](https://github.com/James-Thorson-NOAA/VAST) R package: 54 | 55 | Thorson, J.T. 2019. Guidance for decisions using the Vector 56 | Autoregressive Spatio-Temporal (VAST) package in stock, ecosystem, 57 | habitat and climate assessments. Fisheries Research 210: 143–161. 58 | . 59 | 60 | and [sdmTMB](https://github.com/pbs-assess/sdmTMB) R package: 61 | 62 | Anderson, S.C., E.J. Ward, P.A. English, L.A.K. Barnett. 2022. sdmTMB: 63 | an R package for fast, flexible, and user-friendly generalized linear 64 | mixed effects models with spatial and spatiotemporal random fields. 65 | bioRxiv 2022.03.24.485545; doi: 66 | 67 | 68 | and the [glmmTMB](https://github.com/glmmTMB/glmmTMB) R package: 69 | 70 | Brooks, M.E., Kristensen, K., van Benthem, K.J., Magnusson, A., Berg, 71 | C.W., Nielsen, A., Skaug, H.J., Maechler, M., and Bolker, B.M. 2017. 72 | glmmTMB balances speed and flexibility among packages for zero-inflated 73 | generalized linear mixed modeling. The R Journal 9(2): 378–400. 74 | . 75 | 76 | [INLA](https://www.r-inla.org/) and 77 | [inlabru](https://sites.google.com/inlabru.org/inlabru) can fit many of 78 | the same models as sdmTMB (and many more) in an approximate Bayesian 79 | inference framework. 80 | 81 | [mgcv](https://cran.r-project.org/package=mgcv) can fit similar 82 | SPDE-based Gaussian random field models with code included in [Miller et 83 | al. (2019)](https://doi.org/10.1007/s13253-019-00377-z). 84 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | url: https://vast-lib.github.io/tinyVAST/ 2 | template: 3 | bootstrap: 5 4 | 5 | articles: 6 | - title: Articles 7 | navbar: ~ 8 | contents: 9 | - web_only/overview 10 | - model-description 11 | - mgcv 12 | - spatial 13 | - multiple_data 14 | - dsem 15 | - web_only/simultaneous_autoregressive_process 16 | - web_only/stream_networks 17 | - web_only/age_composition_expansion 18 | - web_only/condition 19 | - web_only/empirical_orthogonal_functions 20 | - spatial_factor_analysis 21 | - web_only/VAST 22 | 23 | reference: 24 | - title: internal 25 | contents: 26 | - rmvnorm_prec 27 | - add_predictions 28 | - classify_variables 29 | - parse_path 30 | - get_data.tinyVAST 31 | - GetResponse.tinyVAST 32 | 33 | - title: 'Fitting and diagnostics' 34 | desc: | 35 | Core tools for model fitting and diagnostics. 36 | contents: 37 | - tinyVAST 38 | - tinyVASTcontrol 39 | - residuals.tinyVAST 40 | - logLik.tinyVAST 41 | - cAIC 42 | - deviance_explained 43 | - Families 44 | - simulate.tinyVAST 45 | - print.tinyVAST 46 | 47 | - title: 'SEM and DSEM constructors' 48 | desc: | 49 | Tools to specify interactions among variables and over time. 50 | contents: 51 | - make_sem_ram 52 | - make_dsem_ram 53 | - make_eof_ram 54 | 55 | - title: 'Predicting' 56 | desc: | 57 | Core tools for model predictions. 58 | contents: 59 | - predict.tinyVAST 60 | - integrate_output 61 | - sample_variable 62 | 63 | - title: 'Interpret output' 64 | desc: | 65 | Tools for interpreting output. 66 | contents: 67 | - summary.tinyVAST 68 | - reload_model 69 | - term_covariance 70 | - vcov.tinyVAST 71 | - rotate_pca 72 | 73 | - title: 'Stream network utilities' 74 | desc: | 75 | Tools to work with stream networks. 76 | contents: 77 | - sfnetwork_evaluator 78 | - sfnetwork_mesh 79 | - simulate_sfnetwork 80 | 81 | - title: 'Data sets' 82 | desc: | 83 | Data sets used for illustration and testing. 84 | contents: 85 | - sea_ice 86 | - salmon_returns 87 | - condition_and_density 88 | - bering_sea_pollock_ages 89 | - bering_sea 90 | - bering_sea_pollock_vast 91 | - red_snapper 92 | - red_snapper_shapefile 93 | 94 | 95 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | informational: true 10 | patch: 11 | default: 12 | target: auto 13 | threshold: 1% 14 | informational: true 15 | -------------------------------------------------------------------------------- /data-raw/download_sea_ice.R: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vast-lib/tinyVAST/3e18f543926a8936f6517cdd7cd605c2fdc56258/data-raw/download_sea_ice.R -------------------------------------------------------------------------------- /data-raw/format_condition_and_density.R: -------------------------------------------------------------------------------- 1 | 2 | library(VAST) 3 | 4 | data(condition_and_density_example) 5 | 6 | condition = subset( condition_and_density_example, !is.na(Individual_length_cm) ) 7 | condition = condition[,c('Year',"Lat","Lon","Individual_length_cm","Individual_weight_Grams")] 8 | 9 | density = subset( condition_and_density_example, is.na(Individual_length_cm) ) 10 | density = density[,c('Year',"Lat","Lon","Sample_biomass_KG")] 11 | colnames(density)[4] = "Sample_biomass_KGperHectare" 12 | 13 | # 14 | library(sf) 15 | eastern_bering_sea = st_read( R'(C:\Users\James.Thorson\Desktop\Git\FishStatsUtils\inst\region_shapefiles\EBSshelf)' ) 16 | eastern_bering_sea = st_geometry(eastern_bering_sea) 17 | eastern_bering_sea = st_transform( eastern_bering_sea, crs = 4326 ) 18 | 19 | condition_and_density = list( 20 | "condition" = condition, 21 | "density" = density, 22 | "eastern_bering_sea" = eastern_bering_sea 23 | ) 24 | 25 | setwd( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)' ) 26 | usethis::use_data( condition_and_density, overwrite=TRUE ) 27 | -------------------------------------------------------------------------------- /data-raw/format_red_snapper.R: -------------------------------------------------------------------------------- 1 | 2 | # Load packages 3 | library(VAST) 4 | library(sf) 5 | 6 | # load data set 7 | # see `?load_example` for list of stocks with example data 8 | # that are installed automatically with `FishStatsUtils`. 9 | example = load_example( data_set="multimodal_red_snapper" ) 10 | 11 | # 12 | red_snapper = example$sampling_data 13 | 14 | shape_dir = R'(C:\Users\James.Thorson\Desktop\Git\Spatio-temporal-models-for-ecologists\Chap_7)' 15 | red_snapper_shapefile = read_sf( file.path(shape_dir,"red_snapper_extent.shp") ) 16 | 17 | setwd( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)' ) 18 | usethis::use_data( red_snapper ) 19 | usethis::use_data( red_snapper_shapefile ) 20 | -------------------------------------------------------------------------------- /data-raw/format_salmon_returns.R: -------------------------------------------------------------------------------- 1 | 2 | setwd( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)' ) 3 | 4 | # Download Excel: 5 | # https://afspubs.onlinelibrary.wiley.com/action/downloadSupplement?doi=10.1002%2Fmcf2.10023&file=mcf210023-sup-0001-TableS1-S24.xlsx 6 | # and then export tab "ST 13-16 Tot ret (bioma) 52-15.csv" as CSV 7 | 8 | # Read CSV 9 | CSV = read.csv( file.path( getwd(), "data-raw", "mcf210023-sup-0001-tables1-s24 -- ST 13-16 Tot ret (bioma) 52-15.csv"), 10 | skip=4, sep="\t") 11 | 12 | # Exclude unknown Management.Area 13 | Pink = CSV[,2:15] 14 | dimnames(Pink) = list( "Year"=CSV[,1], "Region"=colnames(Pink) ) 15 | Chum = CSV[,19:32] 16 | dimnames(Chum) = list( "Year"=CSV[,18], "Region"=colnames(Pink) ) 17 | Sockeye = CSV[,36:49] 18 | dimnames(Sockeye) = list( "Year"=CSV[,35], "Region"=colnames(Pink) ) 19 | f = \(x,sp) data.frame( "Species"=sp, expand.grid(dimnames(x)), "Biomass"=unlist(x) ) 20 | salmon_returns = rbind( f(Pink,"pink"), f(Chum,"chum"), f(Sockeye,"sockeye") ) 21 | 22 | # Fix formatting 23 | colnames(salmon_returns)[2:3] = c("Year","Region") 24 | salmon_returns$Year = as.numeric(as.character(salmon_returns$Year)) 25 | 26 | # 27 | usethis::use_data(salmon_returns) 28 | -------------------------------------------------------------------------------- /data/bering_sea.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vast-lib/tinyVAST/3e18f543926a8936f6517cdd7cd605c2fdc56258/data/bering_sea.rda -------------------------------------------------------------------------------- /data/bering_sea_pollock_ages.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vast-lib/tinyVAST/3e18f543926a8936f6517cdd7cd605c2fdc56258/data/bering_sea_pollock_ages.rda -------------------------------------------------------------------------------- /data/bering_sea_pollock_vast.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vast-lib/tinyVAST/3e18f543926a8936f6517cdd7cd605c2fdc56258/data/bering_sea_pollock_vast.rda -------------------------------------------------------------------------------- /data/condition_and_density.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vast-lib/tinyVAST/3e18f543926a8936f6517cdd7cd605c2fdc56258/data/condition_and_density.rda -------------------------------------------------------------------------------- /data/red_snapper.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vast-lib/tinyVAST/3e18f543926a8936f6517cdd7cd605c2fdc56258/data/red_snapper.rda -------------------------------------------------------------------------------- /data/red_snapper_shapefile.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vast-lib/tinyVAST/3e18f543926a8936f6517cdd7cd605c2fdc56258/data/red_snapper_shapefile.rda -------------------------------------------------------------------------------- /data/salmon_returns.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vast-lib/tinyVAST/3e18f543926a8936f6517cdd7cd605c2fdc56258/data/salmon_returns.rda -------------------------------------------------------------------------------- /data/sea_ice.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vast-lib/tinyVAST/3e18f543926a8936f6517cdd7cd605c2fdc56258/data/sea_ice.rda -------------------------------------------------------------------------------- /header.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # tinyVAST 4 | 5 | > Multivariate spatio-temporal models using dynamic structural equations 6 | 7 | 8 | [![R-CMD-check](https://github.com/James-Thorson-NOAA/tinyVAST/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/James-Thorson-NOAA/tinyVAST/actions/workflows/R-CMD-check.yaml) 9 | [![Codecov test coverage](https://codecov.io/gh/vast-lib/tinyVAST/branch/add_codecov/graph/badge.svg)](https://app.codecov.io/gh/vast-lib/tinyVAST?branch=add_codecov) 10 | [![Documentation](https://img.shields.io/badge/documentation-dsem-orange.svg?colorB=E91E63)](https://vast-lib.github.io/tinyVAST/) 11 | 12 | 13 | tinyVAST is an R package that fits multivariate spatio-temporal models while using Gaussian Markov random fields to represent nonseparable interactions among variables over time. See a preprint: 14 | 15 | Thorson, J. T., Anderson, S. C., Goddard, P., & Rooper, C. N. (2024). tinyVAST: R package with an expressive interface to specify lagged and simultaneous effects in multivariate spatio-temporal models (arXiv:2401.10193). arXiv. http://arxiv.org/abs/2401.10193 16 | 17 | ## Table of contents 18 | -------------------------------------------------------------------------------- /inst/CITATION: -------------------------------------------------------------------------------- 1 | bibentry( 2 | bibtype = "Article", 3 | title = paste0("tinyVAST: R package with an expressive interface to ", 4 | "specify lagged and simultaneous effects in multivariate ", 5 | "spatio-temporal models"), 6 | author = c( 7 | person(c("James", "T."), "Thorson"), 8 | person(c("Sean", "C."), "Anderson"), 9 | person(c("Pamela"), "Goddard"), 10 | person(c("Christopher", "N."), "Rooper") 11 | ), 12 | volume = "34", 13 | number = "4", 14 | pages = "e70035", 15 | year = "2025", 16 | url = "https://doi.org/10.1111/geb.70035", 17 | journal = "Global Ecology and Biogeography", 18 | doi = "10.1111/geb.70035" 19 | ) 20 | -------------------------------------------------------------------------------- /inst/stream_network/East_Fork_Lewis_basin.dbf: -------------------------------------------------------------------------------- 1 | { UaWfromN toN 1 2 3 4 5 6 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 22 22 18 18 14 14 12 12 31 32 33 34 35 36 37 38 39 40 41 6 42 43 44 45 46 47 5 5 40 40 32 32 48 49 50 51 49 49 45 45 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 61 61 74 75 76 77 69 69 78 79 80 81 82 83 84 85 83 83 81 81 79 79 77 77 75 75 20 20 73 73 71 71 67 67 65 65 63 63 59 59 57 57 55 55 53 53 51 51 47 47 43 43 38 38 36 36 34 34 30 30 28 28 26 26 24 24 16 16 10 10 1 1 8 8 3 3 86 -------------------------------------------------------------------------------- /inst/stream_network/East_Fork_Lewis_basin.prj: -------------------------------------------------------------------------------- 1 | PROJCS["NAD_1983_StatePlane_Washington_South_FIPS_4602_Feet",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Lambert_Conformal_Conic"],PARAMETER["False_Easting",1640416.667],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-120.5],PARAMETER["Standard_Parallel_1",47.3333333333333],PARAMETER["Standard_Parallel_2",45.8333333333333],PARAMETER["Latitude_Of_Origin",45.3333333333333],UNIT["US survey foot",0.304800609601219]] -------------------------------------------------------------------------------- /inst/stream_network/East_Fork_Lewis_basin.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vast-lib/tinyVAST/3e18f543926a8936f6517cdd7cd605c2fdc56258/inst/stream_network/East_Fork_Lewis_basin.shp -------------------------------------------------------------------------------- /inst/stream_network/East_Fork_Lewis_basin.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vast-lib/tinyVAST/3e18f543926a8936f6517cdd7cd605c2fdc56258/inst/stream_network/East_Fork_Lewis_basin.shx -------------------------------------------------------------------------------- /man/GetResponse.tinyVAST.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{GetResponse.tinyVAST} 4 | \alias{GetResponse.tinyVAST} 5 | \title{Get response} 6 | \usage{ 7 | \method{GetResponse}{tinyVAST}(model, ...) 8 | } 9 | \arguments{ 10 | \item{model}{output from \code{\link[=tinyVAST]{tinyVAST()}}} 11 | 12 | \item{...}{not used} 13 | } 14 | \description{ 15 | S3 generic from package cv, used for crossvalidation 16 | } 17 | -------------------------------------------------------------------------------- /man/add_predictions.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/predict.R 3 | \name{add_predictions} 4 | \alias{add_predictions} 5 | \title{Add predictions to data-list} 6 | \usage{ 7 | add_predictions(object, newdata, remove_origdata = FALSE) 8 | } 9 | \arguments{ 10 | \item{object}{Output from \code{\link[=tinyVAST]{tinyVAST()}}.} 11 | 12 | \item{newdata}{New data-frame of independent variables used to predict the response.} 13 | 14 | \item{remove_origdata}{Whether to remove original-data to allow faster evaluation. 15 | \code{remove_origdata=TRUE} eliminates information about the distribution 16 | for random effects, and cannot be combined with epsilon bias-correction. 17 | WARNING: feature is experimental and subject to change.} 18 | } 19 | \value{ 20 | the object \code{fit$tmb_inputs$tmb_data} representing data used during fitting, 21 | but with updated values for slots associated with predictions, where this 22 | updated object can be recompiled by TMB to provide predictions 23 | } 24 | \description{ 25 | Given user-provided \code{newdata}, expand the object \code{tmb_data} 26 | to include predictions corresponding to those new observations 27 | } 28 | -------------------------------------------------------------------------------- /man/bering_sea.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{bering_sea} 5 | \alias{bering_sea} 6 | \title{Survey domain for the eastern and northern Bering Sea surveys} 7 | \usage{ 8 | data(bering_sea) 9 | } 10 | \description{ 11 | Shapefile defining the spatial domain for the eastern and northern 12 | Bering Sea bottom trawl surveys. 13 | } 14 | \keyword{data} 15 | -------------------------------------------------------------------------------- /man/bering_sea_pollock_ages.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{bering_sea_pollock_ages} 5 | \alias{bering_sea_pollock_ages} 6 | \title{Survey catch-rates at age for Alaska pollock in the Eastern and Northern Bering Sea} 7 | \usage{ 8 | data(bering_sea_pollock_ages) 9 | } 10 | \description{ 11 | Data used to demonstrate and test model-based age expansion, using density= 12 | dependence corrected survey catch rates after first=stage expansion 13 | from the bottom trawl survey for ages 1-15, conducted by 14 | by the Alaska Fisheries Science Center, including annual surveys in the eastern 15 | Bering Sea 1982-2019 and 2021-2023, as well as the northern Bering Sea 16 | in 1982/85/88/91 and 2010/17/18/19/21/22/23. 17 | } 18 | \keyword{data} 19 | -------------------------------------------------------------------------------- /man/bering_sea_pollock_vast.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{bering_sea_pollock_vast} 5 | \alias{bering_sea_pollock_vast} 6 | \title{Estimated proportion-at-age for Alaska pollock using VAST} 7 | \usage{ 8 | data(bering_sea_pollock_vast) 9 | } 10 | \description{ 11 | Estimated proporrtion-at-age for Alaska pollock using the 12 | package VAST, for comparison with output using tinyVAST. 13 | } 14 | \keyword{data} 15 | -------------------------------------------------------------------------------- /man/cAIC.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cAIC.R 3 | \name{cAIC} 4 | \alias{cAIC} 5 | \title{Calculate conditional AIC} 6 | \usage{ 7 | cAIC(object) 8 | } 9 | \arguments{ 10 | \item{object}{Output from \code{\link[=tinyVAST]{tinyVAST()}}.} 11 | } 12 | \value{ 13 | cAIC value 14 | } 15 | \description{ 16 | Calculates the conditional Akaike Information criterion (cAIC). 17 | } 18 | \details{ 19 | cAIC is designed to optimize the expected out-of-sample predictive 20 | performance for new data that share the same random effects as the in-sample 21 | (fitted) data, e.g., spatial interpolation. In this sense, it should be a 22 | fast approximation to optimizing the model structure based on k-fold 23 | cross-validation. 24 | 25 | By contrast, \code{\link[=AIC]{AIC()}} calculates the marginal Akaike Information Criterion, 26 | which is designed to optimize expected predictive performance for new data 27 | that have new random effects, e.g., extrapolation, or inference about 28 | generative parameters. 29 | 30 | Both cAIC and EDF are calculated using Eq. 6 of Zheng, Cadigan, and Thorson 31 | (2024). 32 | 33 | For models that include profiled fixed effects, these profiles are turned 34 | off. 35 | } 36 | \examples{ 37 | data( red_snapper ) 38 | red_snapper = droplevels(subset(red_snapper, Data_type=="Biomass_KG")) 39 | 40 | # Define mesh 41 | mesh = fmesher::fm_mesh_2d( red_snapper[,c('Lon','Lat')], 42 | cutoff = 1 ) 43 | 44 | # define formula with a catchability covariate for gear 45 | formula = Response_variable ~ factor(Year) + offset(log(AreaSwept_km2)) 46 | 47 | # make variable column 48 | red_snapper$var = "logdens" 49 | # fit using tinyVAST 50 | fit = tinyVAST( data = red_snapper, 51 | formula = formula, 52 | sem = "logdens <-> logdens, sd_space", 53 | space_columns = c("Lon",'Lat'), 54 | spatial_graph = mesh, 55 | family = tweedie(link="log"), 56 | variable_column = "var", 57 | control = tinyVASTcontrol( getsd = FALSE, 58 | profile = "alpha_j" ) ) 59 | 60 | cAIC(fit) # conditional AIC 61 | AIC(fit) # marginal AIC 62 | 63 | } 64 | \references{ 65 | Zheng, N., Cadigan, N., & Thorson, J. T. (2024). 66 | A note on numerical evaluation of conditional Akaike information for 67 | nonlinear mixed-effects models (arXiv:2411.14185). arXiv. 68 | \doi{10.48550/arXiv.2411.14185} 69 | } 70 | -------------------------------------------------------------------------------- /man/classify_variables.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utility.R 3 | \name{classify_variables} 4 | \alias{classify_variables} 5 | \title{Classify variables path} 6 | \usage{ 7 | classify_variables(model) 8 | } 9 | \arguments{ 10 | \item{model}{syntax for structural equation model} 11 | } 12 | \value{ 13 | Tagged-list defining exogenous and endogenous variables 14 | } 15 | \description{ 16 | \code{classify_variables} is copied from \code{sem:::classifyVariables} 17 | } 18 | \details{ 19 | Copied from package \code{sem} under licence GPL (>= 2) with permission from John Fox 20 | } 21 | -------------------------------------------------------------------------------- /man/condition_and_density.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{condition_and_density} 5 | \alias{condition_and_density} 6 | \title{Condition and density example} 7 | \usage{ 8 | data(condition_and_density) 9 | } 10 | \description{ 11 | Data used to demonstrate and test a bivariate model for morphometric condition 12 | (i.e., residuals in a weight-at-length relationship) and density for fishes, using 13 | the same example as was provided as a wiki example for VAST. 14 | Data are from \doi{10.3354/meps13213} 15 | } 16 | \keyword{data} 17 | -------------------------------------------------------------------------------- /man/deviance_explained.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utility.R 3 | \name{deviance_explained} 4 | \alias{deviance_explained} 5 | \title{Calculate deviance explained} 6 | \usage{ 7 | deviance_explained(x, null_formula, null_delta_formula = ~1) 8 | } 9 | \arguments{ 10 | \item{x}{output from \verb{\code{tinyVAST()}}} 11 | 12 | \item{null_formula}{formula for the null model. If missing, it uses 13 | \code{null_formula = response ~ 1}. For multivariate models, it 14 | might make sense to use \code{null_formula = response ~ category}} 15 | 16 | \item{null_delta_formula}{formula for the null model for the delta component. 17 | If missing, it uses 18 | \code{null_formula = response ~ 1}. For multivariate models, it 19 | might make sense to use \code{null_delta_formula = response ~ category}} 20 | } 21 | \value{ 22 | the proportion of conditional deviance explained. 23 | } 24 | \description{ 25 | \code{deviance_explained} fits a null model, calculates the deviance relative to 26 | a saturated model for both the original and the null model, and uses these 27 | to calculate the proportion of deviance explained. 28 | 29 | This implementation conditions upon the maximum likelihood estimate of fixed effects 30 | and the empirical Bayes ("plug-in") prediction of random effects. It can 31 | be described as "conditional deviance explained". A state-space model that 32 | estimates measurement error variance approaching zero (i.e., collapses to 33 | a process-error-only model) will have a conditional deviance explained 34 | that approaches 1.0 35 | } 36 | -------------------------------------------------------------------------------- /man/families.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/family.R 3 | \name{Families} 4 | \alias{Families} 5 | \alias{delta_lognormal} 6 | \alias{delta_gamma} 7 | \title{Additional families} 8 | \usage{ 9 | delta_lognormal(link1, link2 = "log", type = c("standard", "poisson-link")) 10 | 11 | delta_gamma(link1, link2 = "log", type = c("standard", "poisson-link")) 12 | } 13 | \arguments{ 14 | \item{link1}{Link for first part of delta/hurdle model.} 15 | 16 | \item{link2}{Link for second part of delta/hurdle model.} 17 | 18 | \item{type}{Delta/hurdle family type. \code{"standard"} for a classic hurdle 19 | model. \code{"poisson-link"} for a Poisson-link delta model (Thorson 2018).} 20 | 21 | \item{link}{Link.} 22 | } 23 | \value{ 24 | A list with elements common to standard R family objects including \code{family}, 25 | \code{link}, \code{linkfun}, and \code{linkinv}. Delta/hurdle model families also have 26 | elements \code{delta} (logical) and \code{type} (standard vs. Poisson-link). 27 | } 28 | \description{ 29 | Additional families compatible with \code{\link[=tinyVAST]{tinyVAST()}}. 30 | } 31 | \references{ 32 | \emph{Poisson-link delta families}: 33 | 34 | Thorson, J.T. 2018. Three problems with the conventional delta-model for 35 | biomass sampling data, and a computationally efficient alternative. Canadian 36 | Journal of Fisheries and Aquatic Sciences, 75(9), 1369-1382. 37 | \doi{10.1139/cjfas-2017-0266} 38 | 39 | \emph{Poisson-link delta families}: 40 | 41 | Thorson, J.T. 2018. Three problems with the conventional delta-model for 42 | biomass sampling data, and a computationally efficient alternative. Canadian 43 | Journal of Fisheries and Aquatic Sciences, 75(9), 1369-1382. 44 | \doi{10.1139/cjfas-2017-0266} 45 | } 46 | -------------------------------------------------------------------------------- /man/get_data.tinyVAST.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{get_data.tinyVAST} 4 | \alias{get_data.tinyVAST} 5 | \title{Get data} 6 | \usage{ 7 | \method{get_data}{tinyVAST}(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{output from \code{\link[=tinyVAST]{tinyVAST()}}} 11 | 12 | \item{...}{not used} 13 | } 14 | \description{ 15 | S3 generic from package insight, used for crossvalidation 16 | } 17 | -------------------------------------------------------------------------------- /man/logLik.tinyVAST.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{logLik.tinyVAST} 4 | \alias{logLik.tinyVAST} 5 | \title{Extract the (marginal) log-likelihood of a tinyVAST model} 6 | \usage{ 7 | \method{logLik}{tinyVAST}(object, ...) 8 | } 9 | \arguments{ 10 | \item{object}{output from \code{tinyVAST}} 11 | 12 | \item{...}{not used} 13 | } 14 | \value{ 15 | object of class \code{logLik} with attributes 16 | \item{val}{log-likelihood} 17 | \item{df}{number of parameters} 18 | } 19 | \description{ 20 | Extract the (marginal) log-likelihood of a tinyVAST model 21 | } 22 | -------------------------------------------------------------------------------- /man/make_eof_ram.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/make_eof_ram.R 3 | \name{make_eof_ram} 4 | \alias{make_eof_ram} 5 | \title{Make a RAM (Reticular Action Model)} 6 | \usage{ 7 | make_eof_ram( 8 | times, 9 | variables, 10 | n_eof, 11 | remove_na = TRUE, 12 | standard_deviations = "unequal" 13 | ) 14 | } 15 | \arguments{ 16 | \item{times}{A character vector listing the set of times in order} 17 | 18 | \item{variables}{A character vector listing the set of variables} 19 | 20 | \item{n_eof}{Number of EOF modes of variability to estimate} 21 | 22 | \item{remove_na}{Boolean indicating whether to remove NA values from RAM (default) or not. 23 | \code{remove_NA=FALSE} might be useful for exploration and diagnostics for 24 | advanced users} 25 | 26 | \item{standard_deviations}{One of \code{"equal"}, \code{"unequal"}, or a numeric vector 27 | indicating fixed values.} 28 | } 29 | \value{ 30 | A reticular action module (RAM) describing dependencies 31 | } 32 | \description{ 33 | \code{make_eof_ram} converts SEM arrow notation to \code{ram} describing SEM parameters 34 | } 35 | \examples{ 36 | # Two EOFs for two variables 37 | make_eof_ram( times = 2010:2020, variables = c("pollock","cod"), n_eof=2 ) 38 | 39 | } 40 | -------------------------------------------------------------------------------- /man/make_sem_ram.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/make_sem_ram.R 3 | \name{make_sem_ram} 4 | \alias{make_sem_ram} 5 | \title{Make a RAM (Reticular Action Model) from a SEM (structural equation model)} 6 | \usage{ 7 | make_sem_ram(sem, variables, quiet = FALSE, covs = variables) 8 | } 9 | \arguments{ 10 | \item{sem}{structural equation model structure, passed to either \code{\link[sem]{specifyModel}} 11 | or \code{\link[sem]{specifyEquations}} and then parsed to control 12 | the set of path coefficients and variance-covariance parameters} 13 | 14 | \item{variables}{A character vector listing the set of variables} 15 | 16 | \item{quiet}{if \code{FALSE}, the default, then the number of input lines is reported and 17 | a message is printed suggesting that \code{specifyEquations} or \code{cfa} be used.} 18 | 19 | \item{covs}{optional: a character vector of one or more elements, with each element 20 | giving a string of variable names, separated by commas. Variances and covariances 21 | among all variables in each such string are added to the model. For confirmatory 22 | factor analysis models specified via \code{cfa}, \code{covs} defaults to all of 23 | the factors in the model, thus specifying all variances and covariances among these factors. 24 | \emph{Warning}: \code{covs="x1, x2"} and \code{covs=c("x1", "x2")} are \emph{not} 25 | equivalent: \code{covs="x1, x2"} specifies the variance of \code{x1}, the variance 26 | of \code{x2}, \emph{and} their covariance, while \code{covs=c("x1", "x2")} specifies 27 | the variance of \code{x1} and the variance of \code{x2} \emph{but not} their covariance.} 28 | } 29 | \value{ 30 | An S3-class \code{"sem_ram"} containing: 31 | \describe{ 32 | \item{\code{model}}{Output from \code{\link[sem]{specifyEquations}} or \code{\link[sem]{specifyModel}} 33 | that defines paths and parameters} 34 | \item{\code{ram}}{reticular action module (RAM) describing dependencies} 35 | } 36 | } 37 | \description{ 38 | \code{make_sem_ram} converts SEM arrow notation to \code{ram} describing SEM parameters 39 | } 40 | -------------------------------------------------------------------------------- /man/parse_path.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utility.R 3 | \name{parse_path} 4 | \alias{parse_path} 5 | \title{Parse path} 6 | \usage{ 7 | parse_path(path) 8 | } 9 | \arguments{ 10 | \item{path}{character string indicating a one-headed or two-headed path 11 | in a structural equation model} 12 | } 13 | \value{ 14 | Tagged-list defining variables and direction for a specified path coefficient 15 | } 16 | \description{ 17 | \code{parse_path} is copied from \code{sem::parse.path} 18 | } 19 | \details{ 20 | Copied from package \code{sem} under licence GPL (>= 2) with permission from John Fox 21 | } 22 | -------------------------------------------------------------------------------- /man/predict.tinyVAST.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/predict.R 3 | \name{predict.tinyVAST} 4 | \alias{predict.tinyVAST} 5 | \title{Predict using vector autoregressive spatio-temporal model} 6 | \usage{ 7 | \method{predict}{tinyVAST}( 8 | object, 9 | newdata, 10 | remove_origdata = FALSE, 11 | what = c("mu_g", "p_g", "palpha_g", "pgamma_g", "pepsilon_g", "pomega_g", "pdelta_g", 12 | "pxi_g", "p2_g", "palpha2_g", "pgamma2_g", "pepsilon2_g", "pomega2_g", "pdelta2_g", 13 | "pxi2_g"), 14 | se.fit = FALSE, 15 | bias.correct = FALSE, 16 | ... 17 | ) 18 | } 19 | \arguments{ 20 | \item{object}{Output from \code{\link[=tinyVAST]{tinyVAST()}}.} 21 | 22 | \item{newdata}{New data-frame of independent variables used to predict the response.} 23 | 24 | \item{remove_origdata}{Whether to eliminate the original data 25 | from the TMB object, thereby speeding up the TMB object construction. However, this 26 | also eliminates information about random-effect variance, and is not 27 | appropriate when requesting predictive standard errors or epsilon 28 | bias-correction.} 29 | 30 | \item{what}{What REPORTed object to output, where 31 | \code{mu_g} is the inverse-linked transformed predictor including both linear components, 32 | \code{p_g} is the first linear predictor, 33 | \code{palpha_g} is the first predictor from fixed covariates in \code{formula}, 34 | \code{pgamma_g} is the first predictor from random covariates in \code{formula} (e.g., splines), 35 | \code{pomega_g} is the first predictor from spatial variation, 36 | \code{pepsilon_g} is the first predictor from spatio-temporal variation, 37 | \code{pxi_g} is the first predictor from spatially varying coefficients, 38 | \code{p2_g} is the second linear predictor, 39 | \code{palpha2_g} is the second predictor from fixed covariates in \code{formula}, 40 | \code{pgamma2_g} is the second predictor from random covariates in \code{formula} (e.g., splines), 41 | \code{pomega2_g} is the second predictor from spatial variation, 42 | \code{pepsilon2_g} is the second predictor from spatio-temporal variation, and 43 | \code{pxi2_g} is the second predictor from spatially varying coefficients.} 44 | 45 | \item{se.fit}{Calculate standard errors?} 46 | 47 | \item{bias.correct}{whether to epsilon bias-correct the predicted value} 48 | 49 | \item{...}{Not used.} 50 | } 51 | \value{ 52 | Either a vector with the prediction for each row of \code{newdata}, or a named list 53 | with the prediction and standard error (when \code{se.fit = TRUE}). 54 | } 55 | \description{ 56 | Predicts values given new covariates using a \pkg{tinyVAST} model 57 | } 58 | -------------------------------------------------------------------------------- /man/print.tinyVAST.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{print.tinyVAST} 4 | \alias{print.tinyVAST} 5 | \title{print summary of tinyVAST model} 6 | \usage{ 7 | \method{print}{tinyVAST}(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{output from \code{tinyVAST}} 11 | 12 | \item{...}{not used} 13 | } 14 | \value{ 15 | invisibly returns a named list of key model outputs and summary 16 | statements 17 | } 18 | \description{ 19 | print summary of tinyVAST model 20 | } 21 | -------------------------------------------------------------------------------- /man/red_snapper.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{red_snapper} 5 | \alias{red_snapper} 6 | \title{Presence/absence, count, and biomass data for red snapper} 7 | \usage{ 8 | data(red_snapper) 9 | } 10 | \description{ 11 | Data used to demonstrate and test analysis using multiple data types 12 | } 13 | \keyword{data} 14 | -------------------------------------------------------------------------------- /man/red_snapper_shapefile.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{red_snapper_shapefile} 5 | \alias{red_snapper_shapefile} 6 | \title{Shapefile for red snapper analysis} 7 | \usage{ 8 | data(red_snapper_shapefile) 9 | } 10 | \description{ 11 | Spatial extent used for red snapper analysis, derived from Chap-7 of \doi{10.1201/9781003410294} 12 | } 13 | \keyword{data} 14 | -------------------------------------------------------------------------------- /man/reexports.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/family.R 3 | \docType{import} 4 | \name{reexports} 5 | \alias{reexports} 6 | \alias{lognormal} 7 | \alias{nbinom2} 8 | \alias{nbinom1} 9 | \alias{tweedie} 10 | \title{Objects exported from other packages} 11 | \keyword{internal} 12 | \description{ 13 | These objects are imported from other packages. Follow the links 14 | below to see their documentation. 15 | 16 | \describe{ 17 | \item{sdmTMB}{\code{\link[sdmTMB:families]{lognormal}}, \code{\link[sdmTMB:families]{nbinom1}}, \code{\link[sdmTMB:families]{nbinom2}}, \code{\link[sdmTMB:families]{tweedie}}} 18 | }} 19 | 20 | -------------------------------------------------------------------------------- /man/reload_model.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utility.R 3 | \name{reload_model} 4 | \alias{reload_model} 5 | \title{Reload a previously fitted model} 6 | \usage{ 7 | reload_model(x, check_gradient = TRUE) 8 | } 9 | \arguments{ 10 | \item{x}{Output from \code{\link{tinyVAST}}, potentially with DLLs not linked} 11 | 12 | \item{check_gradient}{Whether to check the gradients of the reloaded model} 13 | } 14 | \value{ 15 | Output from \code{\link{tinyVAST}} with DLLs relinked 16 | } 17 | \description{ 18 | \code{reload_model} allows a user to save a fitted model, reload it in a new 19 | R terminal, and then relink the DLLs so that it functions as expected. 20 | } 21 | -------------------------------------------------------------------------------- /man/residuals.tinyVAST.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{residuals.tinyVAST} 4 | \alias{residuals.tinyVAST} 5 | \title{Calculate deviance or response residuals for tinyVAST} 6 | \usage{ 7 | \method{residuals}{tinyVAST}(object, type = c("deviance", "response"), ...) 8 | } 9 | \arguments{ 10 | \item{object}{Output from \code{\link[=tinyVAST]{tinyVAST()}}} 11 | 12 | \item{type}{which type of residuals to compute (only option is \code{"deviance"} or \code{"response"} for now)} 13 | 14 | \item{...}{Note used} 15 | } 16 | \value{ 17 | a vector residuals, associated with each row of \code{data} supplied during fitting 18 | } 19 | \description{ 20 | Calculate residuals 21 | } 22 | -------------------------------------------------------------------------------- /man/rmvnorm_prec.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utility.R 3 | \name{rmvnorm_prec} 4 | \alias{rmvnorm_prec} 5 | \title{Multivariate Normal Random Deviates using Sparse Precision} 6 | \usage{ 7 | rmvnorm_prec(Q, n = 1, mean = rep(0, nrow(Q))) 8 | } 9 | \arguments{ 10 | \item{Q}{sparse precision (inverse-covariance) matrix.} 11 | 12 | \item{n}{number of observations.} 13 | 14 | \item{mean}{mean vector.} 15 | } 16 | \value{ 17 | a matrix with dimension \code{length(mean)} by 18 | \code{n}, containing realized draws from the specified 19 | mean and precision 20 | } 21 | \description{ 22 | This function provides a random number generator for 23 | the multivariate normal distribution with mean equal 24 | to \code{mean} and sparse precision matrix \code{Q}. 25 | } 26 | -------------------------------------------------------------------------------- /man/rotate_pca.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utility.R 3 | \name{rotate_pca} 4 | \alias{rotate_pca} 5 | \title{Rotate factors to match Principal-Components Analysis} 6 | \usage{ 7 | rotate_pca( 8 | L_tf, 9 | x_sf = matrix(0, nrow = 0, ncol = ncol(L_tf)), 10 | order = c("none", "increasing", "decreasing") 11 | ) 12 | } 13 | \arguments{ 14 | \item{L_tf}{Loadings matrix with dimension \eqn{T \times F}.} 15 | 16 | \item{x_sf}{Spatial response with dimensions \eqn{S \times F}.} 17 | 18 | \item{order}{Options for resolving label-switching via reflecting 19 | each factor to achieve a given order across dimension \eqn{T}.} 20 | } 21 | \value{ 22 | List containing the rotated loadings \code{L_tf}, 23 | the inverse-rotated response matrix \code{x_sf}, 24 | and the rotation \code{H} 25 | } 26 | \description{ 27 | Rotate lower-triangle loadings matrix 28 | to order factors from largest to smallest variance. 29 | } 30 | -------------------------------------------------------------------------------- /man/salmon_returns.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{salmon_returns} 5 | \alias{salmon_returns} 6 | \title{North Pacific salmon returns} 7 | \usage{ 8 | data(salmon_returns) 9 | } 10 | \description{ 11 | Data used to demonstrate and test multivariate second-order autoregressive 12 | models using a simultaneous autoregressive (SAR) process across regions. 13 | Data are from \doi{10.1002/mcf2.10023} 14 | } 15 | \keyword{data} 16 | -------------------------------------------------------------------------------- /man/sample_variable.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utility.R 3 | \name{sample_variable} 4 | \alias{sample_variable} 5 | \title{Sample from predictive distribution of a variable} 6 | \usage{ 7 | sample_variable( 8 | object, 9 | newdata = NULL, 10 | variable_name = "mu_i", 11 | n_samples = 100, 12 | sample_fixed = TRUE, 13 | seed = 123456 14 | ) 15 | } 16 | \arguments{ 17 | \item{object}{output from \verb{\code{tinyVAST()}}} 18 | 19 | \item{newdata}{data frame of new data, used to sample model components for predictions e.g., \code{mu_g}} 20 | 21 | \item{variable_name}{name of variable available in report using \code{Obj$report()} or parameters using \code{Obj$env$parList()}} 22 | 23 | \item{n_samples}{number of samples from the joint predictive distribution for fixed and random effects. Default is 100, which is slow.} 24 | 25 | \item{sample_fixed}{whether to sample fixed and random effects, \code{sample_fixed=TRUE} as by default, or just sample random effects, \code{sample_fixed=FALSE}} 26 | 27 | \item{seed}{integer used to set random-number seed when sampling variables, as passed to \code{set.seed(.)}} 28 | } 29 | \value{ 30 | A matrix with a row for each \code{data} supplied during fitting, and 31 | \code{n_samples} columns, where each column in a vector of samples 32 | for a requested quantity given sampled uncertainty in fixed and/or random effects 33 | } 34 | \description{ 35 | \code{sample_variable} samples from the joint distribution of random and fixed effects to approximate the predictive distribution for a variable 36 | 37 | Using \code{sample_fixed=TRUE} (the default) in \code{\link{sample_variable}} propagates variance in both fixed and random effects, while 38 | using \code{sample_fixed=FALSE} does not. 39 | Sampling fixed effects will sometimes cause numerical under- or overflow (i.e., output values of \code{NA}) in cases when 40 | variance parameters are estimated imprecisely. In these cases, the multivariate normal approximation being used is a poor 41 | representation of the tail probabilities, and results in some samples with implausibly high (or negative) variances, 42 | such that the associated random effects then have implausibly high magnitude. 43 | } 44 | \examples{ 45 | set.seed(101) 46 | x = runif(n = 100, min = 0, max = 2*pi) 47 | y = 1 + sin(x) + 0.1 * rnorm(100) 48 | 49 | # Do fit with getJointPrecision=TRUE 50 | fit = tinyVAST( formula = y ~ s(x), 51 | data = data.frame(x=x,y=y) ) 52 | 53 | # samples from distribution for the mean 54 | # excluding fixed effects due to CRAN checks 55 | samples = sample_variable(fit, sample_fixed = FALSE) 56 | 57 | } 58 | -------------------------------------------------------------------------------- /man/sea_ice.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{sea_ice} 5 | \alias{sea_ice} 6 | \title{Arctic September sea ice concentrations} 7 | \usage{ 8 | data(sea_ice) 9 | } 10 | \description{ 11 | Data used to demonstrate and test empirical orthogonal function 12 | generalized linear latent variable model (EOF-GLLVM) 13 | } 14 | \keyword{data} 15 | -------------------------------------------------------------------------------- /man/sfnetwork_evaluator.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sfnetwork.R 3 | \name{sfnetwork_evaluator} 4 | \alias{sfnetwork_evaluator} 5 | \title{Construct projection matrix for stream network} 6 | \usage{ 7 | sfnetwork_evaluator(stream, loc, tolerance = 0.01) 8 | } 9 | \arguments{ 10 | \item{stream}{\pkg{sfnetworks} object representing stream network} 11 | 12 | \item{loc}{\pkg{sf} object representing points to which are being projected} 13 | 14 | \item{tolerance}{error-check tolerance} 15 | } 16 | \value{ 17 | the sparse interpolation matrix, with rows for each row of \code{data} 18 | supplied during fitting and columns for each spatial random effect. 19 | } 20 | \description{ 21 | Make sparse matrix to project from stream-network nodes 22 | to user-supplied points 23 | } 24 | -------------------------------------------------------------------------------- /man/sfnetwork_mesh.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sfnetwork.R 3 | \name{sfnetwork_mesh} 4 | \alias{sfnetwork_mesh} 5 | \title{Make mesh for stream network} 6 | \usage{ 7 | sfnetwork_mesh(stream) 8 | } 9 | \arguments{ 10 | \item{stream}{\pkg{sfnetworks} object representing stream network} 11 | } 12 | \value{ 13 | An object (list) of class \code{sfnetwork_mesh}. Elements include: 14 | \describe{ 15 | \item{N}{The number of random effects used to represent the network} 16 | \item{table}{a table containing a description of parent nodes (from), 17 | childen nodes (to), and the distance separating them} 18 | \item{stream}{copy of the stream network object passed as argument} 19 | } 20 | } 21 | \description{ 22 | make an object representing spatial information required 23 | to specify a stream-network spatial domain, similar in usage to 24 | \code{link[fmesher]{fm_mesh_2d}} for a 2-dimensional continuous domain 25 | } 26 | -------------------------------------------------------------------------------- /man/simulate.tinyVAST.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{simulate.tinyVAST} 4 | \alias{simulate.tinyVAST} 5 | \title{Simulate new data from a fitted model} 6 | \usage{ 7 | \method{simulate}{tinyVAST}( 8 | object, 9 | nsim = 1L, 10 | seed = sample.int(1e+06, 1L), 11 | type = c("mle-eb", "mle-mvn"), 12 | ... 13 | ) 14 | } 15 | \arguments{ 16 | \item{object}{output from \code{\link[=tinyVAST]{tinyVAST()}}} 17 | 18 | \item{nsim}{how many simulations to do} 19 | 20 | \item{seed}{random seed} 21 | 22 | \item{type}{How parameters should be treated. \code{"mle-eb"}: fixed effects 23 | are at their maximum likelihood (MLE) estimates and random effects are at 24 | their empirical Bayes (EB) estimates. \code{"mle-mvn"}: fixed effects are at 25 | their MLEs but random effects are taken from a single approximate sample. 26 | This latter option is a suggested approach if these simulations will be 27 | used for goodness of fit testing (e.g., with the DHARMa package).} 28 | 29 | \item{...}{not used} 30 | } 31 | \value{ 32 | A matrix with row for each row of \code{data} in the fitted model and \code{nsim} 33 | columns, containing new samples from the fitted model. 34 | } 35 | \description{ 36 | \code{simulate.tinyVAST} is an S3 method for producing a matrix of simulations from 37 | a fitted model. It can be used with the \pkg{DHARMa} package 38 | among other uses. Code is modified from the version in sdmTMB 39 | } 40 | \examples{ 41 | set.seed(101) 42 | x = seq(0, 2*pi, length=100) 43 | y = sin(x) + 0.1*rnorm(length(x)) 44 | fit = tinyVAST( data=data.frame(x=x,y=y), formula = y ~ s(x) ) 45 | sims = simulate(fit, nsim=100, type="mle-mvn") 46 | 47 | if(requireNamespace("DHARMa")){ 48 | # simulate new data conditional on fixed effects 49 | # and sampling random effects from their predictive distribution 50 | y_iz = simulate(fit, nsim=500, type="mle-mvn") 51 | 52 | # Visualize using DHARMa 53 | res = DHARMa::createDHARMa( simulatedResponse = y_iz, 54 | observedResponse = y, 55 | fittedPredictedResponse = fitted(fit) ) 56 | plot(res) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /man/simulate_sfnetwork.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sfnetwork.R 3 | \name{simulate_sfnetwork} 4 | \alias{simulate_sfnetwork} 5 | \title{Simulate GMRF for stream network} 6 | \usage{ 7 | simulate_sfnetwork(sfnetwork_mesh, theta, n = 1, what = c("samples", "Q")) 8 | } 9 | \arguments{ 10 | \item{sfnetwork_mesh}{Output from \code{\link{sfnetwork_mesh}}} 11 | 12 | \item{theta}{Decorrelation rate} 13 | 14 | \item{n}{number of simulated GMRFs} 15 | 16 | \item{what}{Whether to return the simulated GMRF or its precision matrix} 17 | } 18 | \value{ 19 | a matrix of simulated values for a Gaussian Markov random field 20 | arising from a stream-network spatial domain, with row for each spatial random 21 | effect and \code{n} columns, using the sparse precision matrix 22 | defined in Charsley et al. (2023) 23 | } 24 | \description{ 25 | Simulate values from a GMRF using a tail-up exponential 26 | model on a stream network 27 | } 28 | \references{ 29 | Charsley, A. R., Gruss, A., Thorson, J. T., Rudd, M. B., Crow, S. K., 30 | David, B., Williams, E. K., & Hoyle, S. D. (2023). Catchment-scale 31 | stream network spatio-temporal models, applied to the freshwater stages 32 | of a diadromous fish species, longfin eel (Anguilla dieffenbachii). 33 | Fisheries Research, 259, 106583. \doi{10.1016/j.fishres.2022.106583} 34 | } 35 | -------------------------------------------------------------------------------- /man/summary.tinyVAST.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{summary.tinyVAST} 4 | \alias{summary.tinyVAST} 5 | \title{summarize tinyVAST} 6 | \usage{ 7 | \method{summary}{tinyVAST}( 8 | object, 9 | what = c("space_term", "time_term", "spacetime_term", "fixed"), 10 | predictor = c("one", "two"), 11 | ... 12 | ) 13 | } 14 | \arguments{ 15 | \item{object}{Output from \code{\link[=tinyVAST]{tinyVAST()}}} 16 | 17 | \item{what}{What component to summarize, whether \code{space_term}, \code{spacetime_term}, or 18 | \code{fixed} for the fixed effects included in the GAM formula} 19 | 20 | \item{predictor}{whether to get the 1st or 2nd linear predictor (the latter is 21 | only applicable in delta models)} 22 | 23 | \item{...}{Not used} 24 | } 25 | \value{ 26 | A data-frame containing the estimate (and standard errors, two-sided Wald-test 27 | z-value, and associated p-value if the standard errors are available) for 28 | model parameters, including the fixed-effects specified via \code{formula}, 29 | or the path coefficients for the spatial SEM specified via \code{space_term}, 30 | the dynamic SEM specified via \code{time_term}, or the spatial dynamic SEM 31 | specified via \code{spacetime_term} 32 | } 33 | \description{ 34 | summarize parameters from a fitted tinyVAST 35 | } 36 | \details{ 37 | \code{tinyVAST} includes three components: 38 | \describe{ 39 | \item{Space-variable interaction}{a separable Gaussian Markov random field (GMRF) 40 | constructed from a structural equation model (SEM) and a spatial variable} 41 | \item{Space-variable-time interaction}{a separable GMRF constructed from a 42 | a dynamic SEM (a nonseparable time-variable interaction) and a spatial variable} 43 | \item{Additive variation}{a generalized additive model (GAM), representing exogenous 44 | covariates } 45 | } 46 | Each of these are summarized and interpreted differently, and \code{summary.tinyVAST} 47 | facilitates this. 48 | 49 | Regarding the DSEM componennt, tinyVAST includes an "arrow and lag" 50 | notation, which specifies the set of 51 | path coefficients and exogenous variance parameters to be estimated. Function \code{tinyVAST} 52 | then estimates the maximum likelihood value for those coefficients and parameters 53 | by maximizing the log-marginal likelihood. 54 | 55 | However, many users will want to associate individual parameters and standard errors 56 | with the path coefficients that were specified using the "arrow and lag" notation. 57 | This task is complicated in 58 | models where some path coefficients or variance parameters are specified to share a single value a priori, 59 | or were assigned a name of NA and hence assumed to have a fixed value a priori (such that 60 | these coefficients or parameters have an assigned value but no standard error). 61 | The \code{summary} function therefore compiles the MLE for coefficients (including duplicating 62 | values for any path coefficients that assigned the same value) and standard error 63 | estimates, and outputs those in a table that associates them with the user-supplied path and parameter names. 64 | It also outputs the z-score and a p-value arising from a two-sided Wald test (i.e. 65 | comparing the estimate divided by standard error against a standard normal distribution). 66 | } 67 | -------------------------------------------------------------------------------- /man/term_covariance.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utility.R 3 | \name{term_covariance} 4 | \alias{term_covariance} 5 | \title{Extract covariance} 6 | \usage{ 7 | term_covariance( 8 | object, 9 | what = c("space_term", "time_term", "spacetime_term"), 10 | pred = c("one", "two"), 11 | n_times = NULL 12 | ) 13 | } 14 | \arguments{ 15 | \item{object}{Output from \code{\link{tinyVAST}}} 16 | 17 | \item{what}{Which SEM or DSEM term to extract} 18 | 19 | \item{pred}{Extract the term \code{what} for which linear predictor} 20 | 21 | \item{n_times}{The number of times to include when calculating covariance for a DSEM 22 | component, i.e., \code{time_term} or \code{spacetime_term}. If missing, the default 23 | is to use the one more than the maximum specified lag (e.g., \code{n_times=2} 24 | by default when the maximum \code{lag=1})} 25 | } 26 | \value{ 27 | The covariance matrix among variables 28 | } 29 | \description{ 30 | Extract the covariance resulting from a specified path structure 31 | and estimated parameters for a SEM or DSEM term in tinyVAST 32 | } 33 | \details{ 34 | tinyVAST constructs the covariance from specified path structure and estimated parameters 35 | } 36 | \examples{ 37 | # Extract covariance for spatial factor analysis (too slow for CRAN) 38 | \donttest{ 39 | # Simulate settings 40 | set.seed(101) 41 | theta_xy = 0.4 42 | n_x = n_y = 10 43 | n_c = 3 # Number of species 44 | n_f = 1 # Number of factors 45 | rho = 0.8 46 | resid_sd = 0.5 47 | 48 | # Simulate GMRFs 49 | R_s = exp(-theta_xy * abs(outer(1:n_x, 1:n_y, FUN="-")) ) 50 | R_ss = kronecker(X=R_s, Y=R_s) 51 | delta_fs = mvtnorm::rmvnorm(n_c, sigma=R_ss ) 52 | 53 | # Simulate loadings for two factors 54 | L_cf = matrix( rnorm(n_c^2), nrow=n_c ) 55 | L_cf[,seq(from=n_f+1, to=n_c)] = 0 56 | L_cf = L_cf + resid_sd * diag(n_c) 57 | 58 | # Simulate correlated densities 59 | d_cs = L_cf \%*\% delta_fs 60 | 61 | # Shape into longform data-frame and add error 62 | Data = data.frame( expand.grid(species=1:n_c, x=1:n_x, y=1:n_y), 63 | "var"="logn", "z"=exp(as.vector(d_cs)) ) 64 | Data$n = rnorm( n=nrow(Data), mean=Data$z, sd=1 ) 65 | 66 | # make mesh 67 | mesh = fmesher::fm_mesh_2d( Data[,c('x','y')] ) 68 | 69 | # Specify factor model with two factors and additional independent variance with shared SD 70 | sem = " 71 | # Loadings matrix 72 | f1 -> 1, l1 73 | f1 -> 2, l2 74 | f1 -> 3, l3 75 | 76 | # Factor variance = 1 77 | f1 <-> f1, NA, 1 78 | 79 | # Shared residual variance 80 | 1 <-> 1, sd, 1 81 | 2 <-> 2, sd, 1 82 | 3 <-> 3, sd, 1 83 | " 84 | 85 | # fit model 86 | out = tinyVAST( space_term = sem, 87 | data = Data, 88 | formula = n ~ 0 + factor(species), 89 | spatial_domain = mesh, 90 | variables = c( "f1", "f2", 1:n_c ), 91 | space_columns = c("x","y"), 92 | variable_column = "species", 93 | time_column = "time", 94 | distribution_column = "dist" ) 95 | 96 | # Extract covariance among species and factors, where 97 | # estimated covariance is obtained by ignoring factors 98 | V = term_covariance( out, what = "space_term", pred = "one" ) 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /man/tinyVASTcontrol.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/fit.R 3 | \name{tinyVASTcontrol} 4 | \alias{tinyVASTcontrol} 5 | \title{Control parameters for tinyVAST} 6 | \usage{ 7 | tinyVASTcontrol( 8 | nlminb_loops = 1, 9 | newton_loops = 0, 10 | eval.max = 1000, 11 | iter.max = 1000, 12 | getsd = TRUE, 13 | silent = getOption("tinyVAST.silent", TRUE), 14 | trace = getOption("tinyVAST.trace", 0), 15 | verbose = getOption("tinyVAST.verbose", FALSE), 16 | profile = c(), 17 | tmb_par = NULL, 18 | tmb_map = NULL, 19 | gmrf_parameterization = c("separable", "projection"), 20 | reml = FALSE, 21 | getJointPrecision = FALSE, 22 | calculate_deviance_explained = TRUE, 23 | run_model = TRUE, 24 | suppress_nlminb_warnings = TRUE, 25 | get_rsr = FALSE, 26 | extra_reporting = FALSE, 27 | use_anisotropy = FALSE 28 | ) 29 | } 30 | \arguments{ 31 | \item{nlminb_loops}{Integer number of times to call \code{\link[stats:nlminb]{stats::nlminb()}}.} 32 | 33 | \item{newton_loops}{Integer number of Newton steps to do after running 34 | \code{\link[stats:nlminb]{stats::nlminb()}}.} 35 | 36 | \item{eval.max}{Maximum number of evaluations of the objective function 37 | allowed. Passed to \code{control} in \code{\link[stats:nlminb]{stats::nlminb()}}.} 38 | 39 | \item{iter.max}{Maximum number of iterations allowed. Passed to \code{control} in 40 | \code{\link[stats:nlminb]{stats::nlminb()}}.} 41 | 42 | \item{getsd}{Boolean indicating whether to call \code{\link[TMB:sdreport]{TMB::sdreport()}}} 43 | 44 | \item{silent}{Disable terminal output for inner optimizer?} 45 | 46 | \item{trace}{Parameter values are printed every \code{trace} iteration 47 | for the outer optimizer. Passed to 48 | \code{control} in \code{\link[stats:nlminb]{stats::nlminb()}}.} 49 | 50 | \item{verbose}{Output additional messages about model steps during fitting?} 51 | 52 | \item{profile}{Parameters to profile out of the likelihood (this subset will be appended to \code{random} with Laplace approximation disabled).} 53 | 54 | \item{tmb_par}{list of parameters for starting values, with shape identical 55 | to \code{tinyVAST(...)$internal$parlist}} 56 | 57 | \item{tmb_map}{input passed to \link[TMB:MakeADFun]{TMB::MakeADFun} as argument \code{map}, over-writing 58 | the version \code{tinyVAST(...)$tmb_inputs$tmb_map} and allowing detailed control 59 | over estimated parameters (advanced feature)} 60 | 61 | \item{gmrf_parameterization}{Parameterization to use for the Gaussian Markov 62 | random field, where the default \code{separable} constructs a full-rank and 63 | separable precision matrix, and the alternative \code{projection} constructs 64 | a full-rank and IID precision for variables over time, and then projects 65 | this using the inverse-cholesky of the precision, where this projection 66 | allows for rank-deficient covariance.} 67 | 68 | \item{reml}{Logical: use REML (restricted maximum likelihood) estimation rather than 69 | maximum likelihood? Internally, this adds the fixed effects to the 70 | list of random effects to integrate over.} 71 | 72 | \item{getJointPrecision}{whether to get the joint precision matrix. Passed 73 | to \code{\link[TMB]{sdreport}}.} 74 | 75 | \item{calculate_deviance_explained}{whether to calculate proportion of deviance 76 | explained. See \code{\link[=deviance_explained]{deviance_explained()}}} 77 | 78 | \item{run_model}{whether to run the model of export TMB objects prior to compilation 79 | (useful for debugging)} 80 | 81 | \item{suppress_nlminb_warnings}{whether to suppress uniformative warnings 82 | from \code{nlminb} arising when a function evaluation is NA, which 83 | are then replaced with Inf and avoided during estimation} 84 | 85 | \item{get_rsr}{Experimental option, whether to report restricted spatial 86 | regression (RSR) adjusted estimator for covariate responses} 87 | 88 | \item{extra_reporting}{Whether to report a much larger set of quantities via 89 | \code{obj$env$report()}} 90 | 91 | \item{use_anisotropy}{Whether to estimate two parameters representing 92 | geometric anisotropy} 93 | } 94 | \value{ 95 | An object (list) of class \code{tinyVASTcontrol}, containing either default or 96 | updated values supplied by the user for model settings 97 | } 98 | \description{ 99 | Control parameters for tinyVAST 100 | } 101 | -------------------------------------------------------------------------------- /man/vcov.tinyVAST.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/methods.R 3 | \name{vcov.tinyVAST} 4 | \alias{vcov.tinyVAST} 5 | \title{Extract Variance-Covariance Matrix} 6 | \usage{ 7 | \method{vcov}{tinyVAST}(object, which = c("fixed", "random", "both"), ...) 8 | } 9 | \arguments{ 10 | \item{object}{output from \code{\link[=tinyVAST]{tinyVAST()}}} 11 | 12 | \item{which}{whether to extract the covariance among fixed effects, random effects, or both} 13 | 14 | \item{...}{ignored, for method compatibility} 15 | } 16 | \value{ 17 | A square matrix containing the estimated covariances among the parameter estimates in the model. 18 | The dimensions dependend upon the argument \code{which}, to determine whether fixed, random effects, 19 | or both are outputted. 20 | } 21 | \description{ 22 | extract the covariance of fixed effects, or both fixed and random effects. 23 | } 24 | -------------------------------------------------------------------------------- /scratch/Upload_to_CRAN.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | library(devtools) 4 | #pandoc::pandoc_install() 5 | 6 | setwd( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)' ) 7 | #setwd( R'(C:\Users\james\OneDrive\Desktop\Git\tinyVAST)') 8 | 9 | # Compile 10 | if( FALSE ){ 11 | document() 12 | } 13 | 14 | # Test install 15 | install_local(force=TRUE, dep=TRUE, build_vignettes=TRUE, upgrade=FALSE) 16 | #install_local(force=TRUE, dep=TRUE, build_vignettes=FALSE, upgrade=FALSE) 17 | browseVignettes("tinyVAST") 18 | 19 | # 20 | if( FALSE ){ 21 | library(TMB) 22 | setwd( R'(C:\Users\James.Thorson\Desktop\Git\dsem\src)' ) 23 | compile("dsem.cpp") 24 | } 25 | 26 | # Try building vignetttes 27 | if( FALSE ){ 28 | library(rmarkdown) 29 | setwd( R'(C:\Users\James.Thorson\Desktop\Git\dsem\vignettes)' ) 30 | devtools::build_rmd("vignettes/vignette.Rmd") 31 | render( file.path(getwd(),"vignette.Rmd"), pdf_document()) 32 | } 33 | 34 | # Try mapping dependencies 35 | if( FALSE ){ 36 | # Simple way 37 | library(renv) 38 | x = dependencies() 39 | 40 | # Listed dependencies 41 | tools::package_dependencies("dsem") 42 | tools::package_dependencies("dynlm") 43 | 44 | # All 45 | pack <- available.packages() 46 | pack["dynlm","Depends"] 47 | packrat:::recursivePackageDependencies("dynlm", ignore = "", lib.loc = .libPaths()[1], fields="Imports") 48 | } 49 | 50 | # Run checks ... doesn't seem to work 51 | file.remove( file.path("vignettes","vignette.pdf") ) 52 | #check( remote = TRUE, manual=TRUE ) 53 | check( manual=TRUE ) 54 | 55 | # Check manual 56 | if( FALSE ){ 57 | tools::texi2pdf 58 | } 59 | 60 | # Check online but document first! 61 | document() 62 | check_win_devel() 63 | check_win_release() 64 | check_win_oldrelease() 65 | check_mac_release() 66 | #check_rhub() 67 | 68 | 69 | # Submit to CRAN via devtools .. not preferred! 70 | if( FALSE ){ 71 | file.remove( file.path("vignettes","vignette.pdf") ) 72 | release() 73 | } 74 | 75 | # Build for uploading via web interface 76 | root_dir = R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST\scratch)' 77 | # https://cran.r-project.org/submit.html 78 | build( path=root_dir, manual=TRUE ) 79 | 80 | # 81 | tools::check_packages_in_dir( root_dir ) 82 | 83 | -------------------------------------------------------------------------------- /scratch/age_composition_expansion.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Age composition expansion" 3 | author: "James T. Thorson" 4 | output: rmarkdown::html_vignette 5 | #output: rmarkdown::pdf_document 6 | vignette: > 7 | %\VignetteIndexEntry{Age composition expansion} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | --- 11 | 12 | 13 | 14 | 15 | ``` r 16 | library(tinyVAST) 17 | library(fmesher) 18 | library(sf) 19 | ``` 20 | 21 | tinyVAST is an R package for fitting vector autoregressive spatio-temporal (VAST) models. 22 | We here explore the capacity to use area-expansion to calculate proportion-at-age using spatially unbalanced sampling data. 23 | 24 | # Expanding age-composition data 25 | To start, we load sampling data that has undergone first-stage expansion. This arises when each primary sampling unit includes secondary subsampling of ages, and the subsampled proporrtion-at-age in each primary unit has been expanded to the total abundance in that primary sample: 26 | 27 | 28 | ``` r 29 | data( bering_sea_pollock_ages ) 30 | 31 | # subset to Years 2010-2023 (to speed up the example) 32 | Data = subset( bering_sea_pollock_ages, Year >= 2010 ) 33 | 34 | # Add Year-_Age interaction 35 | Data$Age = factor( paste0("Age_",Data$Age) ) 36 | Data$Year_Age = interaction( Data$Year, Data$Age ) 37 | 38 | # Project data to UTM 39 | Data = st_as_sf( Data, 40 | coords = c('Lon','Lat'), 41 | crs = st_crs(4326) ) 42 | Data = st_transform( Data, 43 | crs = st_crs("+proj=utm +zone=2 +units=km") ) 44 | # Add UTM coordinates as columns X & Y 45 | Data = cbind( st_drop_geometry(Data), st_coordinates(Data) ) 46 | ``` 47 | 48 | Next, we construct the various inputs to _tinyVAST_ 49 | 50 | 51 | ``` r 52 | # adds different variances for each age 53 | sem = "" 54 | 55 | # Constant AR1 spatio-temporal term across ages 56 | # and adds different variances for each age 57 | dsem = " 58 | Age_1 -> Age_1, 1, lag1 59 | Age_2 -> Age_2, 1, lag1 60 | Age_3 -> Age_3, 1, lag1 61 | Age_4 -> Age_4, 1, lag1 62 | Age_5 -> Age_5, 1, lag1 63 | Age_6 -> Age_6, 1, lag1 64 | Age_7 -> Age_7, 1, lag1 65 | Age_8 -> Age_8, 1, lag1 66 | Age_9 -> Age_9, 1, lag1 67 | Age_10 -> Age_10, 1, lag1 68 | Age_11 -> Age_11, 1, lag1 69 | Age_12 -> Age_12, 1, lag1 70 | Age_13 -> Age_13, 1, lag1 71 | Age_14 -> Age_14, 1, lag1 72 | Age_15 -> Age_15, 1, lag1 73 | " 74 | 75 | mesh = fm_mesh_2d( loc = Data[,c("X","Y")], 76 | cutoff = 50 ) 77 | control = tinyVASTcontrol( getsd = FALSE, 78 | profile = c("alpha_j"), 79 | trace = 0 ) 80 | ``` 81 | 82 | We could run the model with a log-linked Tweedie distribution and a single linear predictor: 83 | 84 | 85 | ``` r 86 | family = list( 87 | Age_1 = tweedie(), 88 | Age_2 = tweedie(), 89 | Age_3 = tweedie(), 90 | Age_4 = tweedie(), 91 | Age_5 = tweedie(), 92 | Age_6 = tweedie(), 93 | Age_7 = tweedie(), 94 | Age_8 = tweedie(), 95 | Age_9 = tweedie(), 96 | Age_10 = tweedie(), 97 | Age_11 = tweedie(), 98 | Age_12 = tweedie(), 99 | Age_13 = tweedie(), 100 | Age_14 = tweedie(), 101 | Age_15 = tweedie() 102 | ) 103 | 104 | #Data$Year = factor(Data$Year) 105 | myfit = tinyVAST( 106 | data = Data, 107 | formula = Abundance_per_hectare ~ 0 + Year_Age, 108 | space_term = sem, 109 | spacetime_term = dsem, 110 | family = family, 111 | space_column = c("X", "Y"), 112 | variable_column = "Age", 113 | time_column = "Year", 114 | distribution_column = "Age", 115 | spatial_domain = mesh, 116 | control = control 117 | ) 118 | ``` 119 | 120 | After the model is fitted, we then apply area-expansion and the epsilon bias-correction method to predict abundance-at-age, and convert that to a proportion: 121 | 122 | 123 | ``` r 124 | # Get shapefile for survey extent 125 | data( bering_sea ) 126 | 127 | # Make extrapolation grid based on shapefile 128 | bering_sea = st_transform( bering_sea, 129 | st_crs("+proj=utm +zone=2 +units=km") ) 130 | grid = st_make_grid( bering_sea, n=c(50,50) ) 131 | grid = st_intersection( grid, bering_sea ) 132 | grid = st_make_valid( grid ) 133 | loc_gz = st_coordinates(st_centroid( grid )) 134 | 135 | # Get area for extrapolation grid 136 | library(units) 137 | areas = set_units(st_area(grid), "hectares") # / 100^2 # Hectares 138 | 139 | # Get abundance 140 | N_jz = expand.grid( Age=myfit$internal$variables, Year=sort(unique(Data$Year)) ) 141 | N_jz = cbind( N_jz, "Biomass"=NA, "SE"=NA ) 142 | for( j in seq_len(nrow(N_jz)) ){ 143 | if( N_jz[j,'Age']==1 ){ 144 | message( "Integrating ", N_jz[j,'Year'], " ", N_jz[j,'Age'], ": ", Sys.time() ) 145 | } 146 | if( is.na(N_jz[j,'Biomass']) ){ 147 | newdata = data.frame( loc_gz, Year=N_jz[j,'Year'], Age=N_jz[j,'Age']) 148 | newdata$Year_Age = paste( newdata$Year, newdata$Age, sep="." ) 149 | # Area-expansion 150 | index1 = integrate_output( myfit, 151 | area = areas, 152 | newdata = newdata, 153 | apply.epsilon = TRUE, 154 | bias.correct = FALSE, 155 | intern = TRUE ) 156 | N_jz[j,'Biomass'] = index1[3] / 1e9 157 | } 158 | } 159 | N_ct = array( N_jz$Biomass, dim=c(length(myfit$internal$variables),length(unique(Data$Year))), 160 | dimnames=list(myfit$internal$variables,sort(unique(Data$Year))) ) 161 | N_ct = N_ct / outer( rep(1,nrow(N_ct)), colSums(N_ct) ) 162 | ``` 163 | 164 | Finally, we can compare these estimates with those from package _VAST_. Estimates differ somewhat 165 | because VAST used a delta-gamma distribution with spatio-temporal variation in two linear predictors, 166 | and also used a different mesh. 167 | 168 | 169 | ``` r 170 | # Load VAST results for same data 171 | data(bering_sea_pollock_vast) 172 | myvast = bering_sea_pollock_vast 173 | rownames(myvast) = 1:15 174 | 175 | # Reformat tinyVAST output with same dimnames 176 | mytiny = N_ct 177 | rownames(mytiny) = 1:15 178 | 179 | # 180 | longvast = cbind( expand.grid(dimnames(myvast)), "p"=as.numeric(myvast), "method"="VAST" ) 181 | longtiny = cbind( expand.grid(dimnames(mytiny)), "p"=as.numeric(mytiny), "method"="tinyVAST" ) 182 | long = rbind( longvast, longtiny ) 183 | 184 | library(ggplot2) 185 | ggplot( data=long, aes(x=Var2, y=p, col=method) ) + 186 | facet_grid( rows=vars(Var1), scales="free" ) + 187 | geom_point( ) + 188 | scale_y_log10() 189 | ``` 190 | 191 | ![plot of chunk agecomp](figure/agecomp-1.png) 192 | 193 | 194 | -------------------------------------------------------------------------------- /scratch/build_pkgdown_website.R: -------------------------------------------------------------------------------- 1 | # Author: Kevin See 2 | # Purpose: Build a website for this package using pkgdown 3 | # Created: 5/17/2021 4 | # Last Modified: 5/17/2021 5 | # Notes: Based on instructions found here: https://pkgdown.r-lib.org/index.html 6 | 7 | #----------------------------------------------------------------- 8 | # Install locally if needed 9 | # devtools::install_local( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)', force=TRUE ) 10 | 11 | # load needed libraries 12 | library(pkgdown) 13 | 14 | # Precompute vignettes 15 | # https://ropensci.org/blog/2019/12/08/precompute-vignettes/ 16 | # NOT DOING THIS ANYMORE 17 | # Now running them via pkgdown::build_site at the same time and disabled _yaml 18 | if( FALSE ){ 19 | setwd(R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST\vignettes)') 20 | 21 | #knitr::knit( "web_only/stream_networks.Rmd.orig", 22 | # output = "web_only/stream_networks.Rmd" ) 23 | # 24 | #knitr::knit( "web_only/age_composition_expansion.Rmd.orig", 25 | # output = "web_only/age_composition_expansion.Rmd" ) 26 | # 27 | #knitr::knit( "web_only/condition.Rmd.orig", 28 | # output = "web_only/condition.Rmd" ) 29 | # 30 | #knitr::knit( "web_only/empirical_orthogonal_functions.Rmd.orig", 31 | # output = "web_only/empirical_orthogonal_functions.Rmd" ) 32 | # 33 | #knitr::knit( "web_only/VAST.Rmd.orig", 34 | # output = "web_only/VAST.Rmd" ) 35 | } 36 | 37 | setwd(R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)') 38 | 39 | # Only needed once 40 | if( FALSE ){ 41 | # set up to automatically publish pkgdown site to GitHub 42 | # usethis::create_github_token() 43 | # gitcreds::gitcreds_set(url = "https://github.com") 44 | usethis::use_pkgdown_github_pages() 45 | 46 | 47 | # Run once to configure your package to use pkgdown 48 | usethis::use_pkgdown() 49 | 50 | # check that _pkgdown.yml looks good 51 | pkgdown::check_pkgdown() 52 | } 53 | 54 | # Run to build the website 55 | pkgdown::build_site( examples=TRUE ) 56 | # build_articles( lazy = FALSE ) 57 | 58 | # to look at the site 59 | pkgdown::preview_site() 60 | 61 | #----------------------------------------------------------------- 62 | # deploy site to gh-pages branch on GitHub 63 | pkgdown::deploy_to_branch() 64 | -------------------------------------------------------------------------------- /scratch/build_r-devel_in_WSL.R: -------------------------------------------------------------------------------- 1 | 2 | # Get dependencies 3 | sudo apt update 4 | sudo apt install -y \ 5 | build-essential \ 6 | gfortran \ 7 | libreadline-dev \ 8 | libx11-dev \ 9 | libxt-dev \ 10 | libpng-dev \ 11 | libjpeg-dev \ 12 | libcairo2-dev \ 13 | libbz2-dev \ 14 | libzstd-dev \ 15 | liblzma-dev \ 16 | libcurl4-openssl-dev \ 17 | libssl-dev \ 18 | libxml2-dev \ 19 | texinfo \ 20 | texlive \ 21 | texlive-fonts-extra \ 22 | texlive-latex-extra \ 23 | wget \ 24 | git \ 25 | subversion \ 26 | gdebi-core 27 | 28 | # Get R-devel 29 | svn checkout https://svn.r-project.org/R/trunk R-devel 30 | cd R-devel 31 | 32 | -------------------------------------------------------------------------------- /scratch/condition.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Condition and density" 3 | author: "James T. Thorson" 4 | output: rmarkdown::html_vignette 5 | #output: rmarkdown::pdf_document 6 | vignette: > 7 | %\VignetteIndexEntry{Condition and density} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | --- 11 | 12 | 13 | 14 | 15 | ``` r 16 | library(tinyVAST) 17 | library(fmesher) 18 | library(sf) 19 | library(ggplot2) 20 | ``` 21 | 22 | `tinyVAST` is an R package for fitting vector autoregressive spatio-temporal (VAST) models using a minimal and user-friendly interface. 23 | We here show how it can fit a bivariate spatio-temporal model representing density dependence in physiological condition for fishes. 24 | This replicates a similar vignette provided for the VAST package, but showcases several improvements in interpretation and interface. 25 | 26 | We first load and combine the two data sets: 27 | 28 | 29 | ``` r 30 | data( condition_and_density ) 31 | 32 | # Combine both parts 33 | combo_data = plyr::rbind.fill( condition_and_density$condition, 34 | condition_and_density$density ) 35 | 36 | # Reformat data in expected format 37 | formed_data = cbind( combo_data[,c("Year","Lat","Lon")], 38 | "Type" = factor(ifelse( is.na(combo_data[,'Individual_length_cm']), 39 | "Biomass", "Condition" )), 40 | "Response" = ifelse( is.na(combo_data[,'Individual_length_cm']), 41 | combo_data[,'Sample_biomass_KGperHectare'], 42 | log(combo_data[,'Individual_weight_Grams']) ), 43 | "log_length" = ifelse( is.na(combo_data[,'Individual_length_cm']), 44 | rep(0,nrow(combo_data)), 45 | log(combo_data[,'Individual_length_cm'] / 10) )) 46 | 47 | # 48 | #formed_data$Year_Type = paste0( formed_data$Year, "_", formed_data$Type ) 49 | ``` 50 | 51 | We then construct the SPDE mesh 52 | 53 | ``` r 54 | # make mesh 55 | mesh = fm_mesh_2d( formed_data[,c('Lon','Lat')], cutoff=1 ) 56 | ``` 57 | 58 | Next, we specify spatial and spatio-temporal variance in both condition and density. 59 | 60 | ``` r 61 | # 62 | sem = " 63 | Biomass <-> Biomass, sdB 64 | Condition <-> Condition, sdC 65 | Biomass -> Condition, dens_dep 66 | " 67 | 68 | # 69 | dsem = " 70 | Biomass <-> Biomass, 0, sdB 71 | Condition <-> Condition, 0, sdC 72 | Biomass -> Condition, 0, dens_dep 73 | " 74 | ``` 75 | 76 | Finally, we define the distribution for each data set using the `family` argument: 77 | 78 | ``` r 79 | # 80 | family = list( 81 | Biomass = tweedie(), 82 | Condition = gaussian() 83 | ) 84 | ``` 85 | 86 | Finally, we fit the model using tinyVAST 87 | 88 | ``` r 89 | # fit model 90 | fit = tinyVAST( data = formed_data, 91 | formula = Response ~ interaction(Year,Type) + log_length, 92 | spatial_domain = mesh, 93 | control = tinyVASTcontrol( trace=0, verbose=TRUE, profile="alpha_j" ), 94 | space_term = sem, 95 | spacetime_term = dsem, 96 | family = family, 97 | variables = c("Biomass","Condition"), 98 | variable_column = "Type", 99 | space_columns = c("Lon", "Lat"), 100 | time_column = "Year", 101 | distribution_column = "Type", 102 | times = 1982:2016 ) 103 | ``` 104 | 105 | We can look at structural parameters using summary functions: 106 | 107 | ``` r 108 | # spatial terms 109 | summary(fit, "space_term") 110 | #> heads to from parameter start Estimate Std_Error z_value p_value 111 | #> 1 2 Biomass Biomass 1 1.423877e+00 0.133046888 10.70207257 9.952681e-27 112 | #> 2 2 Condition Condition 2 -3.316228e-02 0.004167473 -7.95740912 1.756791e-15 113 | #> 3 1 Condition Biomass 3 9.320889e-05 0.004855054 0.01919832 9.846829e-01 114 | 115 | # spatio-temporal terms 116 | summary(fit, "spacetime_term") 117 | #> heads to from parameter start lag Estimate Std_Error z_value p_value 118 | #> 1 2 Biomass Biomass 1 0 0.966428902 0.024274955 39.811769 0.000000e+00 119 | #> 2 2 Condition Condition 2 0 -0.040541656 0.002723390 -14.886465 4.035502e-50 120 | #> 3 1 Condition Biomass 3 0 0.008201844 0.003339305 2.456153 1.404335e-02 121 | ``` 122 | 123 | # Abundance-weighted expansion 124 | 125 | To explore output, we can plot output using the survey extent: 126 | 127 | 128 | ``` r 129 | # Extract shapefile 130 | region = condition_and_density$eastern_bering_sea 131 | 132 | # make extrapolation-grid 133 | sf_grid = st_make_grid( region, cellsize=c(0.2,0.2) ) 134 | sf_grid = st_intersection( sf_grid, region ) 135 | sf_grid = st_make_valid( sf_grid ) 136 | 137 | # 138 | grid_coords = st_coordinates( st_centroid(sf_grid) ) 139 | areas_km2 = st_area( sf_grid ) / 1e6 140 | 141 | # Condition in 142 | newdata = data.frame( "Lat" = grid_coords[,'Y'], 143 | "Lon" = grid_coords[,'X'], 144 | "Year" = 1982, 145 | "Type" = "Condition", 146 | #"Year_Type" = "1982_Condition", 147 | "log_length" = 0 ) 148 | cond_1982 = predict(fit, newdata=newdata, what="p_g") 149 | 150 | # Repeat for density 151 | newdata2 = newdata 152 | newdata2$Type = "Biomass" 153 | #newdata2$Year_Type = "1982_Biomass" 154 | dens_1982 = predict(fit, newdata=newdata2, what="p_g") 155 | 156 | # Plot on map 157 | plot_grid = st_sf( sf_grid, 158 | "Condition.1982" = cond_1982, 159 | "Density.1982" = dens_1982 ) 160 | 161 | plot( plot_grid, border=NA ) 162 | ``` 163 | 164 | ![plot of chunk condition-maps](figure/condition-maps-1.png) 165 | 166 | # Density-weighted condition 167 | 168 | Finally, we can calculate density-weighted condition 169 | 170 | 171 | ``` r 172 | # 173 | expand_data = rbind( newdata2, newdata ) 174 | W_gz = cbind( c(as.numeric(areas_km2),rep(0,length(areas_km2))), 0 ) 175 | V_gz = cbind( rep(c(0,3),each=length(areas_km2)), seq_along(areas_km2)-1 ) 176 | 177 | # 178 | cond_tz = data.frame( "Year"=1998:2016, "Est"=NA, "SE"=NA ) 179 | for( yearI in seq_len(nrow(cond_tz)) ){ 180 | expand_data[,'Year'] = cond_tz[yearI,"Year"] 181 | out = integrate_output( fit, 182 | newdata = expand_data, 183 | V_gz = V_gz, 184 | W_gz = W_gz, 185 | bias.correct = TRUE ) 186 | cond_tz[yearI,c("Est","SE")] = out[c("Estimate","Std. Error")] 187 | } 188 | #> Error in integrate_output(fit, newdata = expand_data, V_gz = V_gz, W_gz = W_gz, : unused arguments (V_gz = V_gz, W_gz = W_gz) 189 | 190 | # plot time-series 191 | ggplot( cond_tz ) + 192 | geom_line( aes(x=Year, y=Est) ) + 193 | geom_ribbon( aes(x=Year, ymin=Est-SE, ymax=Est+SE), alpha=0.2 ) 194 | #> Warning in max(ids, na.rm = TRUE): no non-missing arguments to max; returning -Inf 195 | ``` 196 | 197 | ![plot of chunk condition-timeseries](figure/condition-timeseries-1.png) 198 | -------------------------------------------------------------------------------- /scratch/crossvalidation.R: -------------------------------------------------------------------------------- 1 | 2 | # Simulate a seperable two-dimensional AR1 spatial process 3 | n_x = n_y = 25 4 | n_w = 10 5 | R_xx = exp(-0.4 * abs(outer(1:n_x, 1:n_x, FUN="-")) ) 6 | R_yy = exp(-0.4 * abs(outer(1:n_y, 1:n_y, FUN="-")) ) 7 | z = mvtnorm::rmvnorm(1, sigma=kronecker(R_xx,R_yy) ) 8 | 9 | # Simulate nuissance parameter z from oscillatory (day-night) process 10 | w = sample(1:n_w, replace=TRUE, size=length(z)) 11 | Data = data.frame( expand.grid(x=1:n_x, y=1:n_y), w=w, z=as.vector(z) + cos(w/n_w*2*pi)) 12 | Data$n = Data$z + rnorm(nrow(Data), sd=1) 13 | Data$c = rpois( nrow(Data), lambda = exp(Data$n) ) 14 | 15 | # Add columns for multivariate and/or temporal dimensions 16 | Data$var = "n" 17 | 18 | # make SPDE mesh for spatial term 19 | mesh = fmesher::fm_mesh_2d( Data[,c('x','y')], n=100 ) 20 | 21 | # fit model with cyclic confounder as GAM term 22 | Family = gaussian() 23 | out = tinyVAST( data = Data, 24 | formula = c ~ s(w), 25 | space_columns = c("x", "y"), 26 | #data = dat, 27 | #formula = d ~ 1, 28 | #space_columns = c("X1", "X2"), 29 | family = Family, 30 | spatial_domain = mesh, 31 | space_term = "n <-> n, sd_n" ) 32 | cv(out) 33 | 34 | library(cv) 35 | CV = cv(out) 36 | 37 | ######### 38 | # update works 39 | ######### 40 | 41 | logLik(out) 42 | logLik(update(out)) 43 | 44 | Data2 = Data[ sample(1:nrow(Data),size=100),] 45 | logLik(update(out,data=Data2)) 46 | 47 | 48 | ########### 49 | # Explore cv 50 | # https://cran.r-project.org/web/packages/cv/vignettes/cv-extend.html 51 | ########### 52 | 53 | GetResponse.tinyVAST <- function(model, ...) { 54 | insight::get_response(model) 55 | } 56 | get_data.tinyVAST <- 57 | function( x, 58 | ...){ 59 | x$data 60 | } 61 | 62 | cv( out ) 63 | 64 | insight::get_data(out) 65 | 66 | -------------------------------------------------------------------------------- /scratch/empirical_orthogonal_functions.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Empirical orthogonal functions" 3 | author: "James T. Thorson" 4 | output: rmarkdown::html_vignette 5 | #output: rmarkdown::pdf_document 6 | vignette: > 7 | %\VignetteIndexEntry{Empirical orthogonal functions} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | --- 11 | 12 | 13 | 14 | 15 | ``` r 16 | library(tinyVAST) 17 | library(fmesher) 18 | set.seed(101) 19 | ``` 20 | 21 | tinyVAST is an R package for fitting vector autoregressive spatio-temporal (VAST) models. 22 | We here explore the capacity to specify a generalized linear latent variable model that is configured to 23 | generalize an empirical orthogonal function analysis. 24 | 25 | # Empirical Orthogonal Function (EOF) analysis 26 | To start, we reformat data on September Sea ice concentrations: 27 | 28 | 29 | ``` r 30 | data( sea_ice ) 31 | library(sf) 32 | library(rnaturalearth) 33 | 34 | # project data 35 | sf_ice = st_as_sf( sea_ice, coords = c("lon","lat") ) 36 | st_crs(sf_ice) = "+proj=longlat +datum=WGS84" 37 | sf_ice = st_transform( sf_ice, 38 | crs=st_crs("+proj=laea +lat_0=90 +lon_0=-30 +units=km") ) 39 | 40 | # 41 | sf_pole = st_point( c(0,90) ) 42 | sf_pole = st_sfc( sf_pole, crs="+proj=longlat +datum=WGS84" ) 43 | sf_pole = st_transform( sf_pole, crs=st_crs(sf_ice) ) 44 | sf_pole = st_buffer( sf_pole, dist=3000 ) 45 | sf_ice = st_intersection( sf_ice, sf_pole ) 46 | 47 | Data = data.frame( st_drop_geometry(sf_ice), 48 | st_coordinates(sf_ice), 49 | var = "Ice" ) 50 | ``` 51 | 52 | Next, we construct the various inputs to _tinyVAST_ 53 | 54 | 55 | ``` r 56 | n_eof = 2 57 | dsem = make_eof_ram( variables = "Ice", 58 | times = sort(unique(Data[,'year'])), 59 | n_eof = 2, 60 | standard_deviations = 0 ) 61 | mesh = fm_mesh_2d( Data[,c('X','Y')], cutoff=1.5 ) 62 | 63 | # fit model 64 | out = tinyVAST( spacetime_term = dsem, 65 | space_term = "", 66 | data = as.data.frame(Data), 67 | formula = ice_concentration ~ 1, 68 | spatial_domain = mesh, 69 | space_column = c("X","Y"), 70 | variable_column = "var", 71 | time_column = "year", 72 | distribution_column = "dist", 73 | times = c(paste0("EOF_",seq_len(n_eof)), sort(unique(Data[,'year']))), 74 | control = tinyVASTcontrol( profile="alpha_j", 75 | gmrf_parameterization="projection") ) 76 | #> Warning in tinyVAST(spacetime_term = dsem, space_term = "", data = as.data.frame(Data), : `spatial_domain` has over 1000 components, so 77 | #> the model may be extremely slow 78 | ``` 79 | 80 | Finally, we can extract, rotate, and plot the dominant modes of variability and associated spatial responses: 81 | 82 | 83 | ``` r 84 | # Country shapefiles for plotting 85 | sf_maps = ne_countries( return="sf", scale="medium", continent=c("north america","europe","asia") ) 86 | sf_maps = st_transform( sf_maps, crs=st_crs(sf_ice) ) 87 | sf_maps = st_union( sf_maps ) 88 | 89 | # Shapefile for water 90 | sf_water = st_difference( st_as_sfc(st_bbox(sf_maps)), sf_maps ) 91 | 92 | # Create extrapolation grid 93 | cellsize = 50 94 | sf_grid = st_make_grid( sf_pole, cellsize=cellsize ) 95 | # Restrict to water 96 | grid_i = st_intersects( sf_water, sf_grid ) 97 | sf_grid = sf_grid[ unique(unlist(grid_i)) ] 98 | # Restrict to 3000 km from North Pole 99 | grid_i = st_intersects( sf_pole, sf_grid ) 100 | sf_grid = sf_grid[ unique(unlist(grid_i)) ] 101 | 102 | # 103 | newdata = data.frame( st_coordinates(st_centroid(sf_grid)), 104 | var = "Ice" ) 105 | 106 | # Extract loadings 107 | L_tf = matrix( 0, nrow=length(unique(Data$year)), ncol=2, 108 | dimnames=list(unique(Data$year),c("EOF_1","EOF_2")) ) 109 | L_tf[lower.tri(L_tf,diag=TRUE)] = out$opt$par[names(out$opt$par)=="beta_z"] 110 | 111 | # Extract factor-responses 112 | EOF1_g = predict( out, cbind(newdata, year="EOF_1"), what="pepsilon_g" ) 113 | EOF2_g = predict( out, cbind(newdata, year="EOF_2"), what="pepsilon_g" ) 114 | omega_g = predict( out, cbind(newdata, year="EOF_2"), what="pomega_g" ) 115 | 116 | # Rotate responses and loadings 117 | rotated_results = rotate_pca( L_tf=L_tf, x_sf=cbind(EOF1_g,EOF2_g), order="decreasing" ) 118 | #> Warning in sqrt(Eigen$values): NaNs produced 119 | EOF1_g = rotated_results$x_sf[,1] 120 | EOF2_g = rotated_results$x_sf[,2] 121 | L_tf = rotated_results$L_tf 122 | 123 | # Plot on map 124 | sf_plot = st_sf( sf_grid, "EOF1_g"=EOF1_g, "EOF2_g"=EOF2_g, "omega_g"=omega_g ) 125 | par(mfrow=c(2,2), oma=c(2,2,0,0) ) 126 | plot( sf_plot[,'EOF1_g'], reset=FALSE, key.pos=NULL, border=NA ) 127 | plot( st_geometry(sf_maps), add=TRUE, border=NA, col="grey" ) 128 | plot( sf_plot[,'EOF2_g'], reset=FALSE, key.pos=NULL, border=NA ) 129 | plot( st_geometry(sf_maps), add=TRUE, border=NA, col="grey" ) 130 | plot( sf_plot[,'omega_g'], reset=FALSE, key.pos=NULL, border=NA ) 131 | plot( st_geometry(sf_maps), add=TRUE, border=NA, col="grey" ) 132 | matplot( y=L_tf, x=unique(Data$year), type="l", 133 | col=viridisLite::viridis(n_eof), lwd=2, lty="solid" ) 134 | legend( "top", ncol=n_eof, legend=paste0("EOF",1:n_eof), 135 | fill=viridisLite::viridis(n_eof) ) 136 | ``` 137 | 138 | ![plot of chunk EOF](figure/EOF-1.png) 139 | -------------------------------------------------------------------------------- /scratch/network_precision_check.R: -------------------------------------------------------------------------------- 1 | 2 | # See: C:\Users\James.Thorson\Desktop\Work files\Collaborations\2025 -- Generalized graphical additive mixed model\mammal_traits 3 | 4 | Q_network <- 5 | function( log_theta, 6 | tree, 7 | method = 0 ){ 8 | 9 | # Locals 10 | parent_s = tree$edge[,1] # max(table(tree$edge[,1])) = 2 11 | child_s = tree$edge[,2] # max(table(tree$edge[,2])) = 1 12 | dist_s = tree$edge.length 13 | n_node = max( tree$edge ) 14 | n_edge = length(parent_s) 15 | theta = exp( log_theta ); 16 | if(any(table(child_s))>1) stop("Not a tree or stream") 17 | 18 | if( is.na(method) ){ 19 | # Drops edge lengths 20 | #graph = as.igraph.phylo( tree ) 21 | graph = graph_from_edgelist( tree$edge ) 22 | dist_ss = igraph::distances( graph, weights = graph ) 23 | } 24 | 25 | # Assemble pieces 26 | if( method == 0 ){ 27 | # NOTE: tmp_s is different than before 28 | v1_s = exp(-theta * dist_s) / (1 - exp(-2 * theta * dist_s)) 29 | v2_s = exp(-2 * theta * dist_s) / (1 - exp(-2 * theta * dist_s)) 30 | # Make components 31 | P_ss = sparseMatrix( i = child_s, j = parent_s, x = v1_s, dims = c(n_node,n_node) ) 32 | D_ss = Diagonal( n_node ) + sparseMatrix( i = child_s, j = child_s, x = v2_s, dims = c(n_node,n_node) ) 33 | # Assemble 34 | DminusP_ss = D_ss - P_ss 35 | Q = (t(DminusP_ss) %*% solve(D_ss) %*% DminusP_ss) 36 | } 37 | if( method == 3 ){ 38 | # Previous method 39 | tmp_s = -exp(-theta * dist_s) / (1 - exp(-2 * theta * dist_s)) 40 | tmp2_s = exp(-2 * theta * dist_s) / (1 - exp(-2 * theta * dist_s)) 41 | # Start withdiagonal 42 | Q = sparseMatrix( i = seq_len(n_node), j = seq_len(n_node), x = 1, dims = c(n_node,n_node) ) 43 | # Add extras 44 | for( s in seq_len(n_edge) ){ 45 | tmp = -exp(-theta*dist_s[s]) / (1-exp(-2*theta*dist_s[s])); 46 | tmp2 = exp(-2*theta*dist_s[s]) / (1-exp(-2*theta*dist_s[s])); 47 | Q[parent_s[s], child_s[s]] = tmp; # Q[parent_s[s], child_s[s]] + 48 | Q[child_s[s], parent_s[s]] = tmp; # Q[child_s[s], parent_s[s]] + 49 | Q[parent_s[s], parent_s[s]] = Q[parent_s[s], parent_s[s]] + tmp2; 50 | Q[child_s[s], child_s[s]] = Q[child_s[s], child_s[s]] + tmp2; 51 | } 52 | } 53 | #i = c( parent_s, child_s, parent_s, child_s, seq_len(n_node) ) 54 | #j = c( child_s, parent_s, parent_s, child_s, seq_len(n_node) ) 55 | #x = c( tmp_s, tmp_s, tmp2_s, tmp2_s, rep(1,n_node) ) 56 | #Q = sparseMatrix( i = i, j = j, x = x, dims = c(n_node, n_node), repr = "C" ) 57 | return(Q) 58 | } 59 | 60 | library(ape) 61 | library(Matrix) 62 | library(igraph) 63 | 64 | tree = rtree(2) 65 | theta = 0.2 66 | #tree$edge = tree$edge[,2:1] # data.frame( tree$edge[,2], tree$edge[,1] ) 67 | 68 | # Existing method 69 | Q3 = Q_network( log_theta = log(theta), 70 | tree = tree, 71 | method = 3 ) 72 | Q0 = Q_network( log_theta = log(theta), 73 | tree = tree, 74 | method = 0 ) 75 | range( Q0 - Q3 ) 76 | -------------------------------------------------------------------------------- /scratch/pkgdown.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | release: 9 | types: [published] 10 | workflow_dispatch: 11 | 12 | name: pkgdown 13 | 14 | jobs: 15 | pkgdown: 16 | runs-on: ubuntu-latest 17 | # Only restrict concurrency for non-PR jobs 18 | concurrency: 19 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} 20 | env: 21 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 22 | permissions: 23 | contents: write 24 | steps: 25 | - uses: actions/checkout@v3 26 | 27 | - uses: r-lib/actions/setup-pandoc@v2 28 | 29 | - uses: r-lib/actions/setup-r@v2 30 | with: 31 | use-public-rspm: true 32 | 33 | 34 | - name: Install dependencies Ubuntu 35 | if: runner.os == 'Linux' 36 | run: | 37 | install.packages('remotes') 38 | remotes::install_deps(dependencies = TRUE) 39 | remotes::install_cran("knitr") 40 | remotes::install_cran("rmarkdown") 41 | remotes::install_cran("rcmdcheck") 42 | install.packages("Matrix", type = "source") 43 | install.packages("TMB", type = "source") 44 | shell: Rscript {0} 45 | 46 | - uses: r-lib/actions/setup-r-dependencies@v2 47 | with: 48 | extra-packages: any::pkgdown, local::. 49 | needs: website 50 | 51 | - name: Build site 52 | run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) 53 | shell: Rscript {0} 54 | 55 | - name: Deploy to GitHub pages 🚀 56 | if: github.event_name != 'pull_request' 57 | uses: JamesIves/github-pages-deploy-action@v4.4.1 58 | with: 59 | clean: false 60 | branch: gh-pages 61 | folder: docs 62 | -------------------------------------------------------------------------------- /scratch/run_docker_and_UBSAN.R: -------------------------------------------------------------------------------- 1 | 2 | ############# 3 | # Option-1 ... working 4 | ############# 5 | 6 | # search "cmd" to open Powershell 7 | 8 | # Update stuff by typing in powershell 9 | wsl 10 | sudo apt update 11 | sudo apt install r-base build-essential clang 12 | 13 | # Use development version if needed 14 | sudo apt install r-base-dev 15 | 16 | # Set compiler flags for Clang 17 | mkdir -p ~/.R 18 | nano ~/.R/Makevars 19 | # and copy-paste the following into nano 20 | CFLAGS += -fsanitize=undefined -fno-omit-frame-pointer -fno-sanitize-recover=all 21 | CXXFLAGS += -fsanitize=undefined -fno-omit-frame-pointer -fno-sanitize-recover=all 22 | # and then hit "ctrl+O" and then "Enter" to save, and "ctrl+X" to exit Nano 23 | 24 | # Make a tar.gz of the current build 25 | 26 | # navigate to that directory 27 | cd [tar.gz directory] 28 | 29 | # Run R CMD check 30 | R CMD check [tar.gz name, e.g., tinyVAST_1.0.0.tar.gz] 31 | 32 | 33 | 34 | 35 | ############# 36 | # Option-2 not working 37 | ############# 38 | 39 | # Search "cmd" to open Powershell 40 | 41 | # Install Docker from CRAN folks 42 | # Only necessary once, and then shows in Docker Desktop 43 | docker pull rocker/r-devel-ubsan-clang 44 | 45 | # 46 | docker run --cap-add SYS_PTRACE --rm -ti --security-opt seccomp=unconfined -v ~c/Users/james/OneDrive/Desktop/Git/tinyVAST:/pkg rocker/r-devel-ubsan-clang 47 | # then use RD which is linked to Rdevel 48 | 49 | cd pkg 50 | apt update 51 | apt install cmake 52 | apt install libssl-dev 53 | apt-get install gdal-bin 54 | apt-get install libgdal-dev 55 | apt install libudunits2-dev 56 | apt install libgeos-dev geos-bin 57 | apt install proj-bin 58 | apt install libproj-dev 59 | RD -e "install.packages('remotes')" 60 | RD -e "install.packages('sf')" 61 | RD -e "install.packages('BiocManager'); BiocManager::install('graph')" 62 | RD -e "remotes::install_deps(dependencies = TRUE)" 63 | RD CMD INSTALL --preclean . 64 | -------------------------------------------------------------------------------- /scratch/run_linux_and_valgrind.R: -------------------------------------------------------------------------------- 1 | 2 | # Start -> Search "cmd" 3 | # To install R in command-line: 4 | # 1. "wsl --install" 5 | # 2. "wsl sudo apt update" 6 | # 3. "wsl sudo apt install r-base" 7 | # 4. "wsl sudo apt install cmake" # CPP compiles 8 | # 5. "wsl sudo apt install libssl-dev" # Unknown 9 | # 5B. "wsl sudo apt install libudunits2-dev" # units dependency 10 | # 5C. "wsl sudo apt install proj-bin libproj-dev" # PROJ 11 | # 6. "wsl sudo apt-get install gdal-bin" # GDAL for spatial stuff 12 | # 7. "wsl sudo apt-get install libgdal-dev" # ditto 13 | # 8. "wsl sudo apt install valgrind" # valgrind 14 | # 9. "wsl git clone https://github.com/vast-lib/tinyVAST" 15 | # To open R in command-line: "wsl R" 16 | # Then use R as normal 17 | 18 | # To RUN valgrind 19 | # Start -> Search "cmd" 20 | # cd [copy windows explorer, e.g., C:\Users\james\OneDrive\Desktop\Git\tinyVAST] 21 | # wsl R -d "valgrind" -f scratch/test.R # remove --leak-check=full to match CRAN 22 | -------------------------------------------------------------------------------- /scratch/run_openblas_via_WSL.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Instructions here: https://herbhuang.com/en/posts/old/using-r-on-wsl/ 4 | 5 | # Open Powershell using search "cmd" 6 | # Enter WSL using 7 | wsl 8 | # check BLAS and LAPACK using 9 | sudo update-alternatives --config libblas.so.3-x86_64-linux-gnu 10 | sudo update-alternatives --config liblapack.so.3-x86_64-linux-gnu 11 | # and check R versions using 12 | R 13 | sessionInfo() 14 | q() 15 | # Should show original libraries 16 | # Matrix products: default 17 | # BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.12.0 18 | # LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.12.0 19 | 20 | # Install openblas using 21 | sudo apt install libopenblas-dev 22 | # update libraries priority 23 | sudo update-alternatives --config libblas.so.3-x86_64-linux-gnu 24 | sudo update-alternatives --config liblapack.so.3-x86_64-linux-gnu 25 | # and check R versions using 26 | R 27 | sessionInfo() 28 | q() 29 | # Matrix products: default 30 | BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 31 | LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so; LAPACK version 3.12.0 32 | 33 | # Install MKL using 34 | 35 | -------------------------------------------------------------------------------- /scratch/run_readme.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | setwd( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)' ) 4 | devtools::build_readme() 5 | -------------------------------------------------------------------------------- /scratch/run_tests_locally.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | test_dir = R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST\tests\testthat)' 4 | save_dir = R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST\scratch)' 5 | 6 | library(tinyVAST) 7 | library(testthat) 8 | 9 | tests = list.files(test_dir) 10 | 11 | sink( file.path(save_dir,"test_output.txt") ) 12 | #zzfil <- tempfile(fileext=".txt", tmpdir = save_dir ) 13 | #zz <- file(zzfil, "w") # open an output file connection 14 | for(i in seq_along(tests) ){ 15 | source( file.path(test_dir, tests[i]) ) 16 | } 17 | #close(zz) 18 | sink() 19 | 20 | test_package( "tinyVAST" ) 21 | -------------------------------------------------------------------------------- /scratch/run_vignettes_locally.R: -------------------------------------------------------------------------------- 1 | 2 | setwd( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST\src)') 3 | library(TMB) 4 | compile("tinyVAST.cpp", framework="TMBad") 5 | 6 | devtools::document( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)') 7 | devtools::install_local( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)', 8 | force=TRUE, dep=FALSE ) 9 | ?tinyVAST::tinyVAST 10 | 11 | setwd( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST\vignettes)' ) 12 | vignettes = list.files( pattern="Rmd") 13 | for( vign in vignettes ){ 14 | message( "Running " , vign) 15 | devtools::build_rmd( file.path(getwd(), vign) ) 16 | rmarkdown::render( file.path(getwd(), vign), rmarkdown::pdf_document()) 17 | } 18 | -------------------------------------------------------------------------------- /scratch/save_compile_messages.R: -------------------------------------------------------------------------------- 1 | 2 | setwd( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST\src)' ) 3 | #setwd( R'(C:\Users\james\OneDrive\Desktop\Git\tinyVAST\src)' ) 4 | 5 | file.remove( "tinyVAST.dll" ) 6 | file.remove( "tinyVAST.o" ) 7 | file.remove( "compile_output.txt" ) 8 | 9 | sink( file = "compile_output.txt" ) 10 | sink( type = "message" ) 11 | TMB::compile("tinyVAST.cpp", framework = "TMBad", flags = "-pedantic -O2 -Wall" ) # eigen.disable.warning = FALSE ) 12 | sink(type = "message") 13 | sink() 14 | #compile_cmd <- TMB::compile("tinyVAST.cpp", framework = "TMBad", eigen.disable.warning = FALSE, flag = TRUE) 15 | 16 | # Instead of using TMB::compile directly, we'll run system2 17 | # First, extract compiler command and flags 18 | #compiler <- Sys.getenv("CXX") # e.g., "g++" 19 | #flags <- paste(compile_cmd$compile, collapse = " ") # Flags and file 20 | 21 | system2( 22 | command = "TMB::compile", 23 | args = c( "tinyVAST.cpp", "framework = 'TMBad'" ) 24 | ) 25 | -------------------------------------------------------------------------------- /scratch/setup_codecov.R: -------------------------------------------------------------------------------- 1 | 2 | setwd( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)' ) 3 | 4 | usethis::use_coverage() 5 | -------------------------------------------------------------------------------- /scratch/setup_rhub.R: -------------------------------------------------------------------------------- 1 | 2 | # Directions from: https://r-hub.github.io/rhub/articles/rhubv2.html 3 | setwd( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)' ) 4 | 5 | library(rhub) 6 | 7 | # Options 8 | rhub_platforms() 9 | 10 | # Setup 11 | rhub_setup(overwrite = FALSE) 12 | 13 | # Check 14 | rhub::rhub_doctor() 15 | 16 | # Run 17 | #platforms = c( "m1-san", "clang-ubsan", "valgrind" ) 18 | platforms = c( "gcc15", "windows" ) 19 | # 2 -- UBSAN 20 | # 5 -- Windows latest 21 | # 9 -- clang-ubsan 22 | # 19 -- Fedora gcc15 ... hopefully "r-devel-linux-x86_64-fedora-gcc" 23 | # 30 -- valgrind 24 | rhub::rhub_check( platforms = platforms ) 25 | 26 | # Check valgrind on dev 27 | if( FALSE ){ 28 | rhub::rhub_check( platforms = "valgrind", branch = "dev" ) 29 | rhub::rhub_check( platforms = "clang-ubsan", branch = "dev" ) 30 | # Or main 31 | rhub::rhub_check( platforms = "clang-ubsan", branch = "main" ) 32 | } 33 | 34 | # HOW TO CHECK `valgrind` FOR ISSUES 35 | # Click Actions tab -> click R-hub tab on left-hand side -> 36 | # click action -> job -> "Run r-hub/actions/run-check@v1" 37 | # SEARCH: "Artifact download URL" to find URL to download errors 38 | # e.g., here: https://github.com/vast-lib/tinyVAST/actions/runs/13868485634/job/38811880343 39 | # -> Check tinyVAST-Ex.Rout and search "tinyVAST.cpp" for errors 40 | -------------------------------------------------------------------------------- /scratch/stream_networks.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Stream network models" 3 | author: "James T. Thorson" 4 | output: rmarkdown::html_vignette 5 | #output: rmarkdown::pdf_document 6 | vignette: > 7 | %\VignetteIndexEntry{Stream network models} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | %\VignetteDepends{ggraph} 11 | --- 12 | 13 | 14 | 15 | 16 | ``` r 17 | library(sf) 18 | library(sfnetworks) 19 | library(tinyVAST) 20 | library(viridisLite) 21 | set.seed(101) 22 | options("tinyVAST.verbose" = FALSE) 23 | ``` 24 | 25 | `tinyVAST` is an R package for fitting vector autoregressive spatio-temporal (VAST) models using a minimal and user-friendly interface. 26 | We here show how it can fit a stream network model, where spatial correlations arise from stream distances along a network. 27 | 28 | First, we load a shapefile representing a stream network, and convert it to _sfnetwork_ format. This format includes 29 | edges representing stream segments, and nodes where edges connect. 30 | 31 | ``` r 32 | stream <- st_read( file.path(system.file("stream_network",package="tinyVAST"), 33 | "East_Fork_Lewis_basin.shp"), quiet=TRUE ) 34 | stream = as_sfnetwork(stream) 35 | plot(stream, main="East Fork Lewis Basin") 36 | ``` 37 | 38 | ![plot of chunk stream-shape](figure/stream-shape-1.png) 39 | 40 | We then convert it to an S3 class "sfnetwork_mesh" defined by _tinyVAST_ for stream networks, 41 | and rescale distances to 1000 ft (to ensure that distances are 0.01 to 100, avoiding 42 | issues of numerical under or overflow). 43 | 44 | ``` r 45 | # Rescale 46 | graph = sfnetwork_mesh( stream ) 47 | graph$table$dist = graph$table$dist / 1000 # Convert distance scale 48 | ``` 49 | 50 | Next, we'll simulate a Gaussian Markov random field at stream vertices using `simulate_sfnetwork`, 51 | sample evenly spaced locations along the stream using `st_line_sample`, 52 | project the GMRF to those locations using `sfnetwork_evaluator`, and 53 | simulate data at those locations: 54 | 55 | ``` r 56 | # Parameters 57 | alpha = 2 58 | kappa = 0.05 59 | # mean(graph$table$dist) * kappa = 0.63 -> exp(-0.63) = 0.5 average correlation 60 | 61 | # simulate 62 | omega_s = simulate_sfnetwork( n=1, sfnetwork_mesh=graph, theta=kappa)[,1] 63 | 64 | # sample locations along network 65 | extrap = st_union( st_line_sample( activate(stream,"edges"), density=1/10000)) 66 | extrap = st_cast( extrap, "POINT" ) 67 | 68 | # Project to sampled locations 69 | A_is = sfnetwork_evaluator( stream = graph$stream, 70 | loc = st_coordinates(extrap) ) 71 | omega_i = (A_is %*% omega_s)[,1] 72 | 73 | # Simulate sampling 74 | #Count = rpois( n=graph$n, lambda=exp(alpha + omega) ) 75 | Count_i = rnorm( n=length(omega_i), mean=alpha + omega_i, sd=0.5 ) 76 | 77 | # Format into long-form data frame expected by tinyVAST 78 | Data = data.frame( Count = Count_i, 79 | st_coordinates(extrap), 80 | var = "species", # Univariate model so only one value 81 | time = "2020", # no time-dynamics, so only one value 82 | dist = "obs" ) # only one type of sampling in data 83 | ``` 84 | 85 | We can visualize the GMRF at those locations using _sfnetwork_ 86 | 87 | ``` r 88 | # Plot stream 89 | plot(stream) 90 | # Extract nodes and plot on network 91 | plot( st_sf(st_geometry(activate(stream,"nodes")), "omega"=omega_s), 92 | add=TRUE, pch=19, cex=2) 93 | ``` 94 | 95 | ![plot of chunk stream-dens](figure/stream-dens-1.png) 96 | 97 | Finally, we can fit the model, interpolate the GMRF along at dense locations along 98 | the stream network, and plot those with the true (simulated) values at the 99 | location of simulated samples. 100 | 101 | ``` r 102 | # fit model 103 | out = tinyVAST( data = Data, 104 | formula = Count ~ 1, 105 | spatial_domain = graph, 106 | space_column = c("X","Y"), 107 | variable_column = "var", 108 | time_column = "time", 109 | distribution_column = "dist", 110 | space_term = "" ) 111 | 112 | # 113 | sf_plot = st_union( st_line_sample( activate(stream,"edges"), density=1/1000)) 114 | sf_plot = st_cast( sf_plot, "POINT" ) 115 | newdata = data.frame( Count = NA, 116 | st_coordinates(sf_plot), 117 | var = "species", # Univariate model so only one value 118 | time = "2020", # no time-dynamics, so only one value 119 | dist = "obs" ) # only one type of sampling in data 120 | omega_plot = predict( out, newdata = newdata ) 121 | 122 | # Plot estimated GMRF at sampled locations 123 | plot( stream, main="omegahat_i") 124 | plot( st_sf(sf_plot,"omega"=omega_plot), add=TRUE, pch=19, cex=0.5, pal=viridis ) 125 | plot( st_sf(extrap,"omega"=omega_i), add=TRUE, pch=19, cex=2, pal=viridis ) 126 | ``` 127 | 128 | ![plot of chunk stream-pred](figure/stream-pred-1.png) 129 | -------------------------------------------------------------------------------- /scratch/tensor_spline.R: -------------------------------------------------------------------------------- 1 | 2 | #devtools::install_local( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)', force=TRUE, dep = FALSE ) 3 | library(tinyVAST) 4 | 5 | set.seed(1) 6 | dat <- mgcv::gamSim(1, n = 400, scale = 2) 7 | dat$fac <- fac <- as.factor(sample(1:20, 400, replace = TRUE)) 8 | dat$y <- dat$y + model.matrix(~ fac - 1) %*% rnorm(20) * .5 9 | dat$y <- as.numeric(dat$y) 10 | 11 | form = y ~ s(x1) + s(x2) + ti(x1, x2) 12 | m_m <- mgcv::gam( form, data = dat) 13 | m_v <- tinyVAST( form, data = dat) 14 | 15 | # 16 | form = y ~ te(x1, x2) 17 | m_m <- mgcv::gam( form, data = dat) 18 | m_v <- tinyVAST( form, data = dat) 19 | 20 | 21 | # Fix add predictions 22 | if( FALSE ){ 23 | object = m_v 24 | newdata = object$data 25 | remove_origdata = FALSE 26 | 27 | add_predictions( m_v, newdata ) 28 | 29 | } 30 | 31 | 32 | formula = y ~ t2(x1, x2) 33 | data = dat 34 | 35 | library(tinyVAST) 36 | time_term = NULL 37 | space_term = NULL 38 | spacetime_term = NULL 39 | family = gaussian() 40 | space_columns = c("x","y") 41 | spatial_domain = NULL 42 | time_column = "time" 43 | times = NULL 44 | variable_column = "var" 45 | variables = NULL 46 | distribution_column = "dist" 47 | delta_options = list(formula = ~ 1) 48 | spatial_varying = NULL 49 | weights = NULL 50 | control = tinyVASTcontrol() 51 | 52 | library(checkmate) 53 | library(Matrix) 54 | 55 | ################## 56 | # After saving image 57 | ################## 58 | 59 | setwd( R'(C:\Users\James.Thorson\Desktop\Temporary (can be deleted!))' ) 60 | load( "debugging.RData" ) 61 | 62 | library(TMB) 63 | 64 | setwd(R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST\src)') 65 | dyn.unload(dynlib("tinyVAST")) 66 | compile("tinyVAST.cpp" , framework = "TMBad" ) 67 | dyn.load(dynlib("tinyVAST")) 68 | 69 | # Local fix 70 | #tmb_data$S2dims = numeric(0) 71 | #tmb_data$S2block = numeric(0) 72 | 73 | obj = MakeADFun( data = tmb_data, 74 | parameters = tmb_par, 75 | map = tmb_map, 76 | random = tmb_random, 77 | DLL = "tinyVAST", 78 | profile = control$profile, 79 | silent = control$silent ) # 80 | 81 | opt = nlminb( obj$par, obj$fn, obj$gr ) 82 | sdrep = sdreport(obj) 83 | 84 | # Compare 85 | tmp <- mgcv::gam(formula, data = dat) 86 | -------------------------------------------------------------------------------- /scratch/test.R: -------------------------------------------------------------------------------- 1 | # 2 | library(tinyVAST) 3 | set.seed(123) # HAS ERRORS 4 | 5 | ############### 6 | # tinyVAST 7 | ############### 8 | 9 | # Simulate a seperable two-dimensional AR1 spatial process 10 | n_x = n_y = 25 11 | n_w = 10 12 | R_xx = exp(-0.4 * abs(outer(1:n_x, 1:n_x, FUN="-")) ) 13 | R_yy = exp(-0.4 * abs(outer(1:n_y, 1:n_y, FUN="-")) ) 14 | z = mvtnorm::rmvnorm(1, sigma=kronecker(R_xx,R_yy) ) 15 | 16 | # Simulate nuissance parameter z from oscillatory (day-night) process 17 | w = sample(1:n_w, replace=TRUE, size=length(z)) 18 | Data = data.frame( expand.grid(x=1:n_x, y=1:n_y), w=w, z=as.vector(z) + cos(w/n_w*2*pi)) 19 | Data$n = Data$z + rnorm(nrow(Data), sd=1) 20 | 21 | # Add columns for multivariate and/or temporal dimensions 22 | Data$var = "n" 23 | 24 | # make SPDE mesh for spatial term 25 | mesh = fmesher::fm_mesh_2d( Data[,c('x','y')], n=100 ) 26 | 27 | # fit model with cyclic confounder as GAM term 28 | out = tinyVAST( data = Data, 29 | formula = n ~ s(w), 30 | spatial_domain = mesh, 31 | space_term = "n <-> n, sd_n" ) 32 | 33 | ############### 34 | # cAIC 35 | ############### 36 | 37 | data( red_snapper ) 38 | red_snapper = droplevels(subset(red_snapper, Data_type=="Biomass_KG")) 39 | 40 | # Define mesh 41 | mesh = fmesher::fm_mesh_2d( red_snapper[,c('Lon','Lat')], 42 | cutoff = 1 ) 43 | 44 | # define formula with a catchability covariate for gear 45 | formula = Response_variable ~ factor(Year) + offset(log(AreaSwept_km2)) 46 | 47 | # make variable column 48 | red_snapper$var = "logdens" 49 | # fit using tinyVAST 50 | fit = tinyVAST( data = red_snapper, 51 | formula = formula, 52 | sem = "logdens <-> logdens, sd_space", 53 | space_columns = c("Lon",'Lat'), 54 | spatial_graph = mesh, 55 | family = tweedie(link="log"), 56 | variable_column = "var", 57 | control = tinyVASTcontrol( getsd = FALSE, 58 | profile = "alpha_j" ) ) 59 | 60 | cAIC(fit) # conditional AIC 61 | AIC(fit) # marginal AIC 62 | 63 | ############### 64 | # make_dsem_ram 65 | ############### 66 | 67 | 68 | # Univariate AR1 69 | dsem = " 70 | X -> X, 1, rho 71 | X <-> X, 0, sigma 72 | " 73 | make_dsem_ram( dsem=dsem, variables="X", times=1:4 ) 74 | 75 | # Univariate AR2 76 | dsem = " 77 | X -> X, 1, rho1 78 | X -> X, 2, rho2 79 | X <-> X, 0, sigma 80 | " 81 | make_dsem_ram( dsem=dsem, variables="X", times=1:4 ) 82 | 83 | # Bivariate VAR 84 | dsem = " 85 | X -> X, 1, XtoX 86 | X -> Y, 1, XtoY 87 | Y -> X, 1, YtoX 88 | Y -> Y, 1, YtoY 89 | X <-> X, 0, sdX 90 | Y <-> Y, 0, sdY 91 | " 92 | make_dsem_ram( dsem=dsem, variables=c("X","Y"), times=1:4 ) 93 | 94 | # Dynamic factor analysis with one factor and two manifest variables 95 | # (specifies a random-walk for the factor, and miniscule residual SD) 96 | dsem = " 97 | factor -> X, 0, loadings1 98 | factor -> Y, 0, loadings2 99 | factor -> factor, 1, NA, 1 100 | X <-> X, 0, NA, 0 # No additional variance 101 | Y <-> Y, 0, NA, 0 # No additional variance 102 | " 103 | make_dsem_ram( dsem=dsem, variables=c("X","Y","factor"), times=1:4 ) 104 | 105 | # ARIMA(1,1,0) 106 | dsem = " 107 | factor -> factor, 1, rho1 # AR1 component 108 | X -> X, 1, NA, 1 # Integrated component 109 | factor -> X, 0, NA, 1 110 | X <-> X, 0, NA, 0 # No additional variance 111 | " 112 | make_dsem_ram( dsem=dsem, variables=c("X","factor"), times=1:4 ) 113 | 114 | # ARIMA(0,0,1) 115 | dsem = " 116 | factor -> X, 0, NA, 1 117 | factor -> X, 1, rho1 # MA1 component 118 | X <-> X, 0, NA, 0 # No additional variance 119 | " 120 | make_dsem_ram( dsem=dsem, variables=c("X","factor"), times=1:4 ) 121 | 122 | ############### 123 | # make_eof_ram 124 | ############### 125 | 126 | make_eof_ram( times = 2010:2020, variables = c("pollock","cod"), n_eof=2 ) 127 | 128 | ############### 129 | # simulate.tinyVAST 130 | ############### 131 | 132 | set.seed(101) 133 | x = seq(0, 2*pi, length=100) 134 | y = sin(x) + 0.1*rnorm(length(x)) 135 | fit = tinyVAST( data=data.frame(x=x,y=y), formula = y ~ s(x) ) 136 | simulate(fit, nsim=100, type="mle-mvn") 137 | 138 | if(requireNamespace("DHARMa")){ 139 | # simulate new data conditional on fixed effects 140 | # and sampling random effects from their predictive distribution 141 | y_iz = simulate(fit, nsim=500, type="mle-mvn") 142 | 143 | # Visualize using DHARMa 144 | res = DHARMa::createDHARMa( simulatedResponse = y_iz, 145 | observedResponse = y, 146 | fittedPredictedResponse = fitted(fit) ) 147 | plot(res) 148 | } 149 | 150 | 151 | ############### 152 | # sample_variable 153 | ############### 154 | 155 | set.seed(101) 156 | x = runif(n = 100, min = 0, max = 2*pi) 157 | y = 1 + sin(x) + 0.1 * rnorm(100) 158 | 159 | # Do fit with getJointPrecision=TRUE 160 | fit = tinyVAST( formula = y ~ s(x), 161 | data = data.frame(x=x,y=y), 162 | control = tinyVASTcontrol(getJointPrecision = TRUE) ) 163 | 164 | # samples from distribution for the mean 165 | sample_variable(fit) 166 | 167 | -------------------------------------------------------------------------------- /scratch/tinyVAST_1.0.0.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vast-lib/tinyVAST/3e18f543926a8936f6517cdd7cd605c2fdc56258/scratch/tinyVAST_1.0.0.tar.gz -------------------------------------------------------------------------------- /scratch/tinyVAST_1.1.1.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vast-lib/tinyVAST/3e18f543926a8936f6517cdd7cd605c2fdc56258/scratch/tinyVAST_1.1.1.tar.gz -------------------------------------------------------------------------------- /src/Makevars: -------------------------------------------------------------------------------- 1 | PKG_CPPFLAGS = -DTMBAD_FRAMEWORK 2 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | library(testthat) 4 | library(tinyVAST) 5 | 6 | # Run tests 7 | testthat::test_check("tinyVAST") 8 | 9 | # Run from local directory 10 | # testthat::test_dir( "C:/Users/James.Thorson/Desktop/Git/tinyVAST/tests/testthat/", reporter="check" ) 11 | # testthat::test_local(path = "C:/Users/James.Thorson/Desktop/Git/tinyVAST" ) 12 | -------------------------------------------------------------------------------- /tests/testthat/test-SAR.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | test_that("SAR model with spatio-temporal dynamics works", { 5 | library(igraph) 6 | options("tinyVAST.verbose" = FALSE) 7 | data( salmon_returns ) 8 | 9 | # Transform data 10 | salmon_returns$Biomass_nozeros = ifelse( salmon_returns$Biomass==0, 11 | NA, salmon_returns$Biomass ) 12 | Data = na.omit(salmon_returns) 13 | 14 | # Define graph for SAR process 15 | unconnected_graph = make_empty_graph( nlevels(Data$Region) ) 16 | V(unconnected_graph)$name = levels(Data$Region) 17 | 18 | # Define SEM for AR2 process 19 | dsem = " 20 | sockeye -> sockeye, -1, lag1_sockeye 21 | sockeye -> sockeye, -2, lag2_sockeye 22 | 23 | pink -> pink, -1, lag1_pink 24 | pink -> pink, -2, lag2_pink 25 | 26 | chum -> chum, -1, lag1_chum 27 | chum -> chum, -2, lag2_chum 28 | " 29 | 30 | # Fit tinyVAST model 31 | suppressWarnings({ 32 | mytiny0 = tinyVAST( 33 | formula = Biomass_nozeros ~ 0 + Species + Region, 34 | data = Data, 35 | spacetime_term = dsem, 36 | variable_column = "Species", 37 | time_column = "Year", 38 | space_column = "Region", 39 | distribution_column = "Species", 40 | family = list( "chum" = lognormal(), 41 | "pink" = lognormal(), 42 | "sockeye" = lognormal() ), 43 | spatial_domain = unconnected_graph, 44 | control = tinyVASTcontrol( profile="alpha_j" ) ) 45 | }) 46 | 47 | # Summarize output 48 | Summary = summary(mytiny0, what="spacetime_term") 49 | expect_equal(sum(is.na(Summary$Std_Error)), 0L) 50 | expect_equal(Summary$Estimate[1:5], 51 | c(0.8075069, 0.1946127, 0.05004454, 0.8819951, 0.6749841), tolerance = 1e-3) 52 | }) 53 | -------------------------------------------------------------------------------- /tests/testthat/test-SVC.R: -------------------------------------------------------------------------------- 1 | test_that("SVC works", { 2 | library(fmesher) 3 | set.seed(101) 4 | options("tinyVAST.verbose" = FALSE) 5 | 6 | # Simulate settings 7 | theta_xy = 0.4 8 | n_x = n_y = 10 9 | spatial_sd = 0.5 10 | 11 | # Simulate GMRFs 12 | R_s = exp(-theta_xy * abs(outer(1:n_x, 1:n_y, FUN="-")) ) 13 | V_ss = spatial_sd^2 * kronecker(R_s, R_s) 14 | xi_s = mvtnorm::rmvnorm(1, sigma=V_ss )[1,] 15 | logd_s = 1 + xi_s 16 | 17 | # Shape into longform data-frame and add error 18 | Data = data.frame( expand.grid(x=1:n_x, y=1:n_y), 19 | "var"="logn", 20 | d_s = exp(as.vector(logd_s)) ) 21 | Data$n = tweedie::rtweedie( n = nrow(Data), 22 | mu = Data$d_s, 23 | phi = 0.5, 24 | power = 1.5 ) 25 | mean(Data$n==0) 26 | 27 | # make mesh 28 | mesh = fm_mesh_2d( Data[,c('x','y')] ) 29 | 30 | # fit model with random walk using GMRF-projection 31 | my1 = tinyVAST( space_term = "logn <-> logn, sd", 32 | data = Data, 33 | formula = n ~ 1, 34 | spatial_domain = mesh, 35 | family = tweedie(), 36 | control = tinyVASTcontrol() ) 37 | # fit model with random walk using standard GMRF 38 | my2 = tinyVAST( spatial_varying = ~ 1, 39 | data = Data, 40 | formula = n ~ 1, 41 | spatial_domain = mesh, 42 | family = tweedie(), 43 | control = tinyVASTcontrol() ) 44 | expect_equal( my1$opt$objective, my2$opt$objective, tolerance=0.001 ) 45 | 46 | # Compare predictions 47 | pred1 = predict(my1) 48 | pred2 = predict(my2) 49 | expect_equal( pred1, pred2, tolerance=0.001 ) 50 | }) 51 | -------------------------------------------------------------------------------- /tests/testthat/test-basic-fits.R: -------------------------------------------------------------------------------- 1 | sim_dat1 <- function(seed = 192838) { 2 | set.seed(seed) 3 | n_x <- n_y <- 25 4 | n_w <- 10 5 | R_xx <- exp(-0.4 * abs(outer(1:n_x, 1:n_x, FUN = "-"))) 6 | R_yy <- exp(-0.4 * abs(outer(1:n_y, 1:n_y, FUN = "-"))) 7 | z <- mvtnorm::rmvnorm(1, sigma = kronecker(R_xx, R_yy)) 8 | # Simulate nuisance parameter z from oscillatory (day-night) process 9 | w <- sample(1:n_w, replace = TRUE, size = length(z)) 10 | Data <- data.frame(expand.grid(x = 1:n_x, y = 1:n_y), w = w, z = as.vector(z) + cos(w / n_w * 2 * pi)) 11 | Data$n <- Data$z + rnorm(nrow(Data), sd = 1) 12 | # Add columns for multivariate and temporal dimensions 13 | Data$var <- "n" 14 | Data$time <- 2020 15 | Data 16 | } 17 | dat <- sim_dat1() 18 | 19 | require(fmesher) 20 | mesh <- fm_mesh_2d(dat[, c("x", "y")], n = 100) 21 | out <- tinyVAST( 22 | data = dat, 23 | formula = n ~ s(w), 24 | spatial_domain = mesh, 25 | space_term = "", 26 | control = tinyVASTcontrol( 27 | verbose = TRUE, 28 | newton_loops = 1, 29 | silent = FALSE 30 | ) 31 | ) 32 | 33 | test_that("Basic tinyVAST works", { 34 | expect_s3_class(out, "tinyVAST") 35 | s <- summary(out$sdrep) 36 | expect_true(sum(is.na(s[,2])) == 0L) 37 | }) 38 | 39 | test_that("cv::cv works", { 40 | skip_on_ci() 41 | skip_on_cran() 42 | skip_on_covr() 43 | 44 | # Run cv::cv 45 | CV = cv::cv(out, seed = 123) 46 | expect_equal( as.numeric(CV[['CV crit']]), 1.607874, tolerance = 0.0001 ) 47 | }) 48 | 49 | # test_that("data_colnames are robust", { 50 | # 51 | # expect_error({out <- tinyVAST( 52 | # data = dat, 53 | # formula = n ~ s(w), 54 | # spatial_domain = mesh, 55 | # control = tinyVASTcontrol(quiet = TRUE, trace = 0), 56 | # data_colnames = list( 57 | # space = c("x", "y"), 58 | # variable = "banana", 59 | # time = "time", 60 | # distribution = "dist" 61 | # ), 62 | # space_term = "" 63 | # ) 64 | # }, regexp = "variable") 65 | # 66 | # mesh <- fmesher::fm_mesh_2d(dat[, c("x", "y")], n = 100) 67 | # expect_error({out <- tinyVAST( 68 | # data = dat, 69 | # formula = n ~ s(w), 70 | # spatial_domain = mesh, 71 | # space_columns = c("x", "y"), 72 | # variable_column = "var", 73 | # time_column = "time", 74 | # distribution_column = "dist", 75 | # space_term = "" 76 | # ) 77 | # }, regexp = "data_colnames") 78 | # }) 79 | 80 | test_that("tinyVAST works as dsem", { 81 | library(tinyVAST) 82 | data(isle_royale, package="dsem") 83 | 84 | # Convert to long-form 85 | data = expand.grid( "time"=isle_royale[,1], "var"=colnames(isle_royale[,2:3]) ) 86 | data$logn = unlist(log(isle_royale[2:3])) 87 | 88 | # Define cross-lagged DSEM 89 | dsem = " 90 | # Link, lag, param_name 91 | wolves -> wolves, 1, arW 92 | moose -> wolves, 1, MtoW 93 | wolves -> moose, 1, WtoM 94 | moose -> moose, 1, arM 95 | #wolves -> moose, 0, corr 96 | wolves <-> moose, 0, corr 97 | " 98 | 99 | # fit model ... spacetime_term 100 | fit1 = tinyVAST( spacetime_term = dsem, 101 | data = data, 102 | times = isle_royale[,1], 103 | variables = colnames(isle_royale[,2:3]), 104 | formula = logn ~ 0 + var ) 105 | # fit model ... time_term 106 | fit2 = tinyVAST( time_term = dsem, 107 | data = data, 108 | times = isle_royale[,1], 109 | variables = colnames(isle_royale[,2:3]), 110 | formula = logn ~ 0 + var ) 111 | 112 | expect_equal( as.numeric(fit1$opt$obj), as.numeric(fit2$opt$obj), tolerance = 1e-3 ) 113 | expect_equal( as.numeric(fit1$opt$obj), 5.781919, tolerance = 1e-3 ) 114 | 115 | } ) 116 | -------------------------------------------------------------------------------- /tests/testthat/test-dsem.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | test_that("dsem and tinyVAST give identical results without lags", { 4 | 5 | library(dsem) 6 | library(igraph) 7 | 8 | # Simulate data 9 | set.seed(101) 10 | n_rows = 100 11 | X = 1 + rnorm(n_rows) 12 | Y = 2 + 0.5 * X + rnorm(n_rows) 13 | 14 | # Format wide-form for DSEM and long-form fot tinyVAST 15 | tsdat = ts( data.frame(X=X, Y=Y) ) 16 | dat = expand.grid( times = time(tsdat), var = c("X","Y") ) 17 | dat$site = "a" 18 | dat$z = as.vector(tsdat) 19 | 20 | # 21 | f1 = tinyVAST( 22 | data = dat, 23 | formula = z ~ 0 + factor(var), 24 | variable_column = "var", 25 | time_term = "X -> Y, 0, beta", 26 | time_column = "times" 27 | ) 28 | 29 | # dsem build inputs 30 | f2 = dsem( 31 | tsdata = tsdat, 32 | family = c( "normal", "normal" ), 33 | sem = "X -> Y, 0, beta", 34 | control = dsem_control( run_model = FALSE, use_REML = FALSE ) 35 | ) 36 | 37 | # Refit with same measurement error as tinyVAST 38 | map = f2$tmb_inputs$map 39 | map$lnsigma_j = factor( c(NA,NA) ) 40 | pars = f2$tmb_inputs$parameters 41 | pars$lnsigma_j = rep( f1$internal$parlist$log_sigma, 2 ) 42 | f2 = dsem( 43 | tsdata = ts( data.frame(X=X, Y=Y) ), 44 | family = c( "normal", "normal" ), 45 | sem = "X -> Y, 0, beta", 46 | control = dsem_control( parameters = pars, map = map, use_REML = FALSE ) 47 | ) 48 | 49 | # 50 | unconnected_graph = make_empty_graph( 1 ) 51 | V(unconnected_graph)$name = "a" 52 | f3 = tinyVAST( 53 | data = dat, 54 | formula = z ~ 0 + factor(var), 55 | variable_column = "var", 56 | spacetime_term = "X -> Y, 0, beta", 57 | time_column = "times", 58 | space_column = "site", 59 | spatial_domain = unconnected_graph 60 | ) 61 | 62 | # tinyVAST vs. DSEM 63 | expect_equal( as.numeric(f1$opt$par[1:5]), 64 | as.numeric(f2$opt$par[c(4:5,1:3)]), 65 | tolerance = 0.01 ) 66 | # Different specification for tinyVAST 67 | expect_equal( as.numeric(f1$opt$par[1:5]), 68 | as.numeric(f3$opt$par[1:5]), 69 | tolerance = 0.01 ) 70 | }) 71 | 72 | test_that("dsem and tinyVAST give identical results with lags", { 73 | # Simulate data 74 | set.seed(101) 75 | n_rows = 100 76 | X = 1 + rnorm(n_rows - 1) 77 | Y = 2 + 0.5 * X + rnorm(n_rows - 1) 78 | 79 | # Add NAs for manually lagged effect 80 | X = c(X, NA ) 81 | Y = c(NA, Y ) 82 | 83 | # Format wide-form for DSEM and long-form fot tinyVAST 84 | tsdat = ts( data.frame(X=X, Y=Y) ) 85 | dat = expand.grid( times = time(tsdat), var = c("X","Y") ) 86 | dat$site = "a" 87 | dat$z = as.vector(tsdat) 88 | dat = na.omit(dat) 89 | 90 | # 91 | f1 = tinyVAST( 92 | data = dat, 93 | formula = z ~ 0 + factor(var), 94 | variable_column = "var", 95 | time_term = "X -> Y, 1, beta", 96 | time_column = "times", 97 | control = tinyVASTcontrol( extra_reporting = TRUE ) 98 | ) 99 | 100 | # dsem build inputs 101 | f2 = dsem( 102 | tsdata = tsdat, 103 | family = c( "normal", "normal" ), 104 | sem = "X -> Y, 1, beta", 105 | control = dsem_control( run_model = TRUE, use_REML = FALSE, nlminb_loops = 0, newton_loops = 0, 106 | getsd = FALSE, extra_convergence_checks = FALSE ) 107 | ) 108 | 109 | # Refit with same measurement error as tinyVAST 110 | map = f2$tmb_inputs$map 111 | map$lnsigma_j = factor( c(NA,NA) ) 112 | pars = f2$tmb_inputs$parameters 113 | pars$lnsigma_j = rep( f1$internal$parlist$log_sigma, 2 ) 114 | f2 = dsem( 115 | tsdata = tsdat, 116 | family = c( "normal", "normal" ), 117 | sem = "X -> Y, 1, beta", 118 | control = dsem_control( parameters = pars, map = map, use_REML = FALSE, extra_convergence_checks = FALSE ) 119 | ) 120 | 121 | expect_equal( as.numeric(f1$opt$par[1:5]), 122 | as.numeric(f2$opt$par[c(4:5,1:3)]), 123 | tolerance = 0.01 ) 124 | }) 125 | -------------------------------------------------------------------------------- /tests/testthat/test-platform.R: -------------------------------------------------------------------------------- 1 | # context("Testing cross platform and R version compatibility") 2 | # platform test 3 | test_that("tinyVAST example is working ", { 4 | # Simulate a 2D AR1 spatial process with a cyclic confounder w 5 | n_x = n_y = 25 6 | n_w = 10 7 | R_xx = exp(-0.4 * abs(outer(1:n_x, 1:n_x, FUN="-")) ) 8 | R_yy = exp(-0.4 * abs(outer(1:n_y, 1:n_y, FUN="-")) ) 9 | z = mvtnorm::rmvnorm(1, sigma=kronecker(R_xx,R_yy) ) 10 | 11 | # Simulate nuisance parameter z from oscillatory (day-night) process 12 | w = sample(1:n_w, replace=TRUE, size=length(z)) 13 | Data = data.frame( expand.grid(x=1:n_x, y=1:n_y), w=w, z=as.vector(z) + cos(w/n_w*2*pi)) 14 | Data$n = Data$z + rnorm(nrow(Data), sd=1) 15 | 16 | # Add columns for multivariate and temporal dimensions 17 | Data$var = "n" 18 | Data$time = 2020 19 | 20 | # make mesh 21 | mesh = fmesher::fm_mesh_2d( Data[,c('x','y')], n=100 ) 22 | 23 | # fit model 24 | out = tinyVAST( data = Data, 25 | formula = n ~ s(w), 26 | spatial_domain = mesh, 27 | space_term = "", 28 | control = tinyVASTcontrol(getJointPrecision=TRUE) ) 29 | expect_s3_class(out, "tinyVAST") 30 | 31 | # 32 | vcov( out, which="fixed") 33 | vcov( out, which="random") 34 | vcov( out, which="both") 35 | 36 | # 37 | predict( out ) 38 | predict( out, newdata = Data[1:10,] ) 39 | predict( out, se.fit = TRUE, what="p_g" ) 40 | 41 | # 42 | print(out) 43 | 44 | # 45 | AIC(out) 46 | logLik(out) 47 | 48 | }) 49 | 50 | -------------------------------------------------------------------------------- /tests/testthat/test-sfa.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | test_that("Basic spatial factor analysis works", { 4 | library(fmesher) 5 | set.seed(101) 6 | 7 | # Simulate settings 8 | theta_xy = 0.4 9 | n_x = n_y = 10 10 | n_c = 5 11 | rho = 0.8 12 | resid_sd = 0.5 13 | 14 | # Simulate GMRFs 15 | R_s = exp(-theta_xy * abs(outer(1:n_x, 1:n_y, FUN="-")) ) 16 | R_ss = kronecker(X=R_s, Y=R_s) 17 | delta_fs = mvtnorm::rmvnorm(n_c, sigma=R_ss ) 18 | 19 | # 20 | L_cf = matrix( rnorm(n_c^2), nrow=n_c ) 21 | L_cf[,3:5] = 0 22 | L_cf = L_cf + resid_sd * diag(n_c) 23 | 24 | # 25 | d_cs = L_cf %*% delta_fs 26 | 27 | # Shape into longform data-frame and add error 28 | Data = data.frame( expand.grid(species=1:n_c, x=1:n_x, y=1:n_y), 29 | "var"="logn", "z"=exp(as.vector(d_cs)) ) 30 | Data$n = tweedie::rtweedie( n=nrow(Data), mu=Data$z, phi=0.5, power=1.5 ) 31 | mean(Data$n==0) 32 | 33 | # make mesh 34 | mesh = fm_mesh_2d( Data[,c('x','y')] ) 35 | 36 | # 37 | sem = " 38 | f1 -> 1, l1 39 | f1 -> 2, l2 40 | f1 -> 3, l3 41 | f1 -> 4, l4 42 | f1 -> 5, l5 43 | f2 -> 2, l6 44 | f2 -> 3, l7 45 | f2 -> 4, l8 46 | f2 -> 5, l9 47 | f1 <-> f1, NA, 1 48 | f2 <-> f2, NA, 1 49 | 1 <-> 1, NA, 0 50 | 2 <-> 2, NA, 0 51 | 3 <-> 3, NA, 0 52 | 4 <-> 4, NA, 0 53 | 5 <-> 5, NA, 0 54 | " 55 | 56 | # fit model 57 | out = tinyVAST( space_term = sem, 58 | data = Data, 59 | formula = n ~ 0 + factor(species), 60 | spatial_domain = mesh, 61 | family = tweedie(), 62 | variables = c( "f1", "f2", 1:n_c ), 63 | space_columns = c("x","y"), 64 | variable_column = "species", 65 | time_column = "time", 66 | distribution_column = "dist", 67 | control = tinyVASTcontrol(gmrf="proj") ) 68 | # 69 | summary( out, what="space_term" ) 70 | expect_s3_class(out, "tinyVAST") 71 | }) 72 | -------------------------------------------------------------------------------- /tests/testthat/test-sfnetworks.R: -------------------------------------------------------------------------------- 1 | 2 | test_that("Basic sfnetworks works", { 3 | library(sf) 4 | library(sfnetworks) 5 | set.seed(101) 6 | 7 | stream <- st_read( file.path(system.file("stream_network",package="tinyVAST"), 8 | "East_Fork_Lewis_basin.shp"), quiet=TRUE ) 9 | 10 | suppressWarnings({stream = as_sfnetwork(stream)}) 11 | 12 | # Rescale 13 | graph = sfnetwork_mesh( stream ) 14 | graph$table$dist = graph$table$dist / 1000 # Convert distance scale 15 | graph$Dist_ss = graph$Dist_ss / 1000 16 | 17 | # Parameters 18 | alpha = 2 19 | kappa = 0.05 20 | 21 | # simulate 22 | omega_s = simulate_sfnetwork( n=1, sfnetwork_mesh=graph, theta=kappa)[,1] 23 | 24 | # sample locations along network 25 | extrap = st_union( st_line_sample( activate(stream,"edges"), density=1/10000)) 26 | extrap = st_cast( extrap, "POINT" ) 27 | 28 | # Project to sampled locations 29 | A_is = sfnetwork_evaluator( stream = graph$stream, 30 | loc = st_coordinates(extrap) ) 31 | omega_i = (A_is %*% omega_s)[,1] 32 | 33 | # Simulate sampling 34 | #Count = rpois( n=graph$n, lambda=exp(alpha + omega) ) 35 | Count_i = rnorm( n=length(omega_i), mean=alpha + omega_i, sd=0.5 ) 36 | 37 | # Format into long-form data frame expected by tinyVAST 38 | Data = data.frame( Count = Count_i, 39 | st_coordinates(extrap), 40 | var = "species", # Univariate model so only one value 41 | time = "2020", # no time-dynamics, so only one value 42 | dist = "obs" ) # only one type of sampling in data 43 | 44 | # fit model 45 | out = tinyVAST( data = Data, 46 | formula = Count ~ 1, 47 | spatial_domain = graph, 48 | space_column = c("X","Y"), 49 | variable_column = "var", 50 | time_column = "time", 51 | distribution_column = "dist", 52 | space_term = "" ) 53 | #expect_equal( out$opt$obj, 119.3909, tolerance=0.01 ) 54 | expect_equal( out$opt$obj, 119.4153, tolerance=0.01 ) # AFTER FIXING BUG in v1.1.0 55 | 56 | # 57 | integrate_output( out, 58 | newdata = Data, 59 | bias.correct = TRUE ) 60 | integrate_output( out, 61 | newdata = Data, 62 | bias.correct = FALSE, 63 | apply.epsilon = TRUE, 64 | intern = TRUE ) 65 | 66 | # Check OU precision 67 | theta = exp(out$internal$parlist$log_kappa) 68 | edges = activate(stream,"edges") 69 | Dist_ss = igraph::distances( edges, weights = sf::st_length(edges) / 1000 ) 70 | V_ss = 1 / (2*theta) * exp( -theta * Dist_ss ) 71 | Q_ss = Matrix::Matrix(zapsmall(solve(V_ss))) 72 | # Compare 73 | Q2_ss = out$rep$Q_ss * exp(out$rep$log_tau)^2 74 | diff_z = (Q_ss - Q2_ss)@x 75 | expect_equal( diff_z, rep(0,length(diff_z)), tolerance = 0.001 ) 76 | }) 77 | -------------------------------------------------------------------------------- /vignettes/.Rhistory: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vast-lib/tinyVAST/3e18f543926a8936f6517cdd7cd605c2fdc56258/vignettes/.Rhistory -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *.R -------------------------------------------------------------------------------- /vignettes/dsem.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Dynamic structural equation models" 3 | author: "James T. Thorson" 4 | output: rmarkdown::html_vignette 5 | #output: rmarkdown::pdf_document 6 | vignette: > 7 | %\VignetteIndexEntry{Dynamic structural equation models} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | %\VignetteDepends{dsem} 11 | --- 12 | 13 | ```{r, include = FALSE} 14 | has_dsem = requireNamespace("dsem", quietly = TRUE) 15 | EVAL <- has_dsem 16 | knitr::opts_chunk$set( 17 | collapse = TRUE, 18 | comment = "#>", 19 | eval = EVAL, 20 | purl = EVAL 21 | ) 22 | # Install locally 23 | # devtools::install_local( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)', force=TRUE ) 24 | # Build and PDF 25 | # setwd(R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)'); devtools::build_rmd("vignettes/dsem.Rmd"); rmarkdown::render( "vignettes/dsem.Rmd", rmarkdown::pdf_document()) 26 | ``` 27 | 28 | ```{r setup, echo=TRUE, warning=FALSE, message=FALSE} 29 | library(tinyVAST) 30 | set.seed(101) 31 | options("tinyVAST.verbose" = FALSE) 32 | ``` 33 | 34 | `tinyVAST` includes features to fit a dynamic structural equation model. We here show this using a bivariate vector autoregressive model for wolf and moose abundance on Isle Royale. 35 | 36 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6, warning=FALSE} 37 | data(isle_royale, package="dsem") 38 | 39 | # Convert to long-form 40 | data = expand.grid( "time"=isle_royale[,1], "var"=colnames(isle_royale[,2:3]) ) 41 | data$logn = unlist(log(isle_royale[2:3])) 42 | 43 | # Define cross-lagged DSEM 44 | dsem = " 45 | # Link, lag, param_name 46 | wolves -> wolves, 1, arW 47 | moose -> wolves, 1, MtoW 48 | wolves -> moose, 1, WtoM 49 | moose -> moose, 1, arM 50 | #wolves -> moose, 0, corr 51 | wolves <-> moose, 0, corr 52 | " 53 | 54 | # fit model 55 | mytiny = tinyVAST( spacetime_term = dsem, 56 | data = data, 57 | times = isle_royale[,1], 58 | variables = colnames(isle_royale[,2:3]), 59 | formula = logn ~ 0 + var ) 60 | mytiny 61 | 62 | # Deviance explained relative to both intercepts 63 | # Note that a process-error-only estimate with have devexpl -> 1 64 | deviance_explained( mytiny, 65 | null_formula = logn ~ 0 + var ) 66 | 67 | # See summary 68 | knitr::kable( summary(mytiny,"spacetime_term"), digits=3 ) 69 | ``` 70 | 71 | And we can specifically inspect the estimated interaction matrix: 72 | 73 | ```{r, eval=TRUE, echo=FALSE, message=FALSE, fig.width=6, fig.height=6} 74 | B = matrix( mytiny$internal$parlist$beta_z[1:4], nrow=2, 75 | dimnames=list(colnames(isle_royale[,2:3]),colnames(isle_royale[,2:3])) ) 76 | knitr::kable( B, digits=3) 77 | ``` 78 | 79 | We can then compare this with package `dsem` 80 | 81 | ```{r, eval=requireNamespace("dsem"), echo=TRUE, message=FALSE, fig.width=6, fig.height=6, warning=FALSE} 82 | library(dsem) 83 | 84 | # Keep in wide-form 85 | dsem_data = ts( log(isle_royale[,2:3]), start=1959) 86 | Family = c("normal", "normal") 87 | 88 | # fit without delta0 89 | # SEs aren't available because measurement errors goes to zero 90 | mydsem = dsem::dsem( sem = dsem, 91 | tsdata = dsem_data, 92 | control = dsem_control(getsd=FALSE), 93 | family = Family ) 94 | mydsem 95 | 96 | # See summary 97 | knitr::kable( summary(mydsem), digits=3 ) 98 | ``` 99 | 100 | where we again inspect the estimated interaction matrix: 101 | 102 | ```{r, eval=TRUE, echo=FALSE, message=FALSE, fig.width=6, fig.height=6} 103 | B = matrix( mydsem$obj$env$parList()$beta_z[1:4], nrow=2, 104 | dimnames=list(colnames(isle_royale[,2:3]),colnames(isle_royale[,2:3])) ) 105 | knitr::kable( B, digits=3) 106 | ``` 107 | 108 | -------------------------------------------------------------------------------- /vignettes/mgcv.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Comparison with mgcv" 3 | author: "James T. Thorson" 4 | output: rmarkdown::html_vignette 5 | #output: rmarkdown::pdf_document 6 | vignette: > 7 | %\VignetteIndexEntry{Comparison with mgcv} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | %\VignetteDepends{pdp} 11 | --- 12 | 13 | ```{r, include = FALSE} 14 | has_pdp = requireNamespace("pdp", quietly = TRUE) 15 | has_lattice = requireNamespace("lattice", quietly = TRUE) 16 | has_visreg = requireNamespace("visreg", quietly = TRUE) 17 | EVAL <- has_pdp && has_lattice && has_visreg 18 | knitr::opts_chunk$set( 19 | collapse = TRUE, 20 | comment = "#>", 21 | eval = EVAL, 22 | purl = EVAL 23 | ) 24 | # Install locally 25 | # devtools::install_local( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)', force=TRUE ) 26 | # Build 27 | # setwd(R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)'); devtools::build_rmd("vignettes/mgcv.Rmd"); rmarkdown::render( "vignettes/mgcv.Rmd", rmarkdown::pdf_document()) 28 | ``` 29 | 30 | ```{r setup, echo=TRUE, warning=FALSE, message=FALSE} 31 | library(tinyVAST) 32 | library(pdp) # approx = TRUE gives effects for average of other covariates 33 | library(lattice) 34 | library(visreg) 35 | library(mgcv) 36 | set.seed(101) 37 | options("tinyVAST.verbose" = FALSE) 38 | ``` 39 | 40 | `tinyVAST` is an R package for fitting vector autoregressive spatio-temporal (VAST) models using a minimal and user-friendly interface. 41 | We here show how it can replicate analysis using splines specified via `mgcv` 42 | 43 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 44 | # Simulate 45 | n_obs = 1000 46 | x = rnorm(n_obs) 47 | group = sample( x=1:5, size=n_obs, replace=TRUE ) 48 | w = runif(n_obs, min=0, max=2) 49 | z = 1 + x^2 + cos((w+group/5)*2*pi) + rnorm(5)[group] 50 | a = exp(0.1*rnorm(n_obs)) 51 | y = z + a + rnorm(n_obs, sd=0.2) 52 | Data = data.frame( x=x, y=y, w=w, z=z, group=factor(group), a=a ) 53 | 54 | # fit model 55 | Formula = y ~ 1 + s(group, bs="re") + poly(x, 2, raw=TRUE) + s(w, by=group, bs="ts") # + offset(a) 56 | myfit = tinyVAST( data = Data, 57 | formula = Formula, 58 | control = tinyVASTcontrol( getsd=FALSE ) ) 59 | ``` 60 | 61 | We can then compute the percent deviance explained, and confirm that it is identical to that calculated using mgcv 62 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 63 | # By default 64 | myfit$deviance_explained 65 | 66 | # 67 | mygam_reduced = gam( Formula, data=Data ) # 68 | summary(mygam_reduced)$dev.expl 69 | ``` 70 | 71 | We can also use the `DHARMa` package to visualize simulation residuals: 72 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 73 | # simulate new data conditional on fixed and random effects 74 | y_ir = replicate( n = 100, 75 | expr = myfit$obj$simulate()$y_i ) 76 | 77 | # 78 | res = DHARMa::createDHARMa( simulatedResponse = y_ir, 79 | observedResponse = Data$y, 80 | fittedPredictedResponse = fitted(myfit) ) 81 | plot(res) 82 | ``` 83 | 84 | `tinyVAST` then has a standard `predict` function: 85 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 86 | predict(myfit, newdata=data.frame(x=0, y=1, w=0.4, group=2, a=1) ) 87 | ``` 88 | 89 | and this is used to compute partial-dependence plots using package `pdp` 90 | 91 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 92 | # compute partial dependence plot 93 | Partial = partial( object = myfit, 94 | pred.var = c("w","group"), 95 | pred.fun = \(object,newdata) predict(object,newdata), 96 | train = Data, 97 | approx = TRUE ) 98 | 99 | # Lattice plots as default option 100 | plotPartial( Partial ) 101 | ``` 102 | 103 | Alternatively, we can use `visreg` to visualize output, although it is disabled for CRAN vignette checks: 104 | 105 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 106 | visreg(myfit, xvar="group", what="p_g") 107 | visreg(myfit, xvar="x", what="p_g") 108 | visreg(myfit, xvar="w", by="group", what="p_g") 109 | ``` 110 | 111 | Alternatively, we can calculate derived quantities via Monte Carlo integration of the estimated density function: 112 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 113 | # Predicted sample-weighted total 114 | integrate_output(myfit) 115 | 116 | # True (latent) sample-weighted total 117 | sum( Data$z ) 118 | ``` 119 | 120 | 121 | Similarly, we can fit a grouped 2D spline 122 | 123 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 124 | # Simulate 125 | R = exp(-0.4 * abs(outer(1:10, 1:10, FUN="-")) ) 126 | z = mvtnorm::rmvnorm(3, sigma=kronecker(R,R) ) 127 | Data = data.frame( expand.grid(x=1:10, y=1:10, group=1:3), z=as.vector(t(z))) 128 | Data$n = Data$z + rnorm(nrow(Data), sd=0.1) 129 | Data$group = factor(Data$group) 130 | 131 | # fit model 132 | Formula = n ~ s(x, y, by=group) 133 | myfit = tinyVAST( data = Data, 134 | formula = Formula ) 135 | 136 | # compute partial dependence plot 137 | mypartial = partial( object = myfit, 138 | pred.var = c("x","y","group"), 139 | pred.fun = \(object,newdata) predict(object,newdata), 140 | train = Data, 141 | approx = TRUE ) 142 | 143 | # Lattice plots as default option 144 | plotPartial( mypartial ) 145 | 146 | # Lattice plot of true values 147 | mypartial$yhat = Data$z 148 | plotPartial( mypartial ) 149 | ``` 150 | 151 | We can again use `visreg` to visualize response surfaces, although it doesn't seem possible to extract a grouped spatial term, so we here show only a single term: 152 | 153 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 154 | out = visreg2d( myfit, "x", "y", cond=list("group"=1), plot=FALSE ) 155 | plot( out, main="f(x,y) for group=1") 156 | ``` 157 | -------------------------------------------------------------------------------- /vignettes/multiple_data.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Multiple data types" 3 | author: "James T. Thorson" 4 | output: rmarkdown::html_vignette 5 | #output: rmarkdown::pdf_document 6 | vignette: > 7 | %\VignetteIndexEntry{Multiple data types} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | %\VignetteDepends{sf} 11 | --- 12 | 13 | ```{r, include = FALSE} 14 | has_lattice = requireNamespace("lattice", quietly = TRUE) 15 | has_pdp = requireNamespace("pdp", quietly = TRUE) 16 | EVAL <- has_lattice && has_pdp 17 | knitr::opts_chunk$set( 18 | collapse = TRUE, 19 | comment = "#>", 20 | eval = EVAL, 21 | purl = EVAL 22 | ) 23 | # Install locally 24 | # devtools::install_local( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)', force=TRUE ) 25 | # Build 26 | # setwd(R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)'); devtools::build_rmd("vignettes/multiple_data.Rmd"); rmarkdown::render( "vignettes/multiple_data.Rmd", rmarkdown::pdf_document()) 27 | ``` 28 | 29 | ```{r setup, echo=TRUE, warning=FALSE, message=FALSE} 30 | library(tinyVAST) 31 | library(sf) 32 | library(fmesher) 33 | library(ggplot2) 34 | ``` 35 | 36 | `tinyVAST` is an R package for fitting vector autoregressive spatio-temporal (VAST) models using a minimal and user-friendly interface. 37 | We here show how it can fit a species distribution model fitted to multiple data types. In this specific case, we fit to presence/absence, count, and biomass samples for red snapper in the Gulf of Mexico. However, the interface is quite general and allows combining a wide range of data types. 38 | 39 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 40 | # Load data 41 | data( red_snapper ) 42 | data( red_snapper_shapefile ) 43 | 44 | # Plot data extent 45 | plot( x = red_snapper$Lon, 46 | y = red_snapper$Lat, 47 | col = rainbow(3)[red_snapper$Data_type] ) 48 | plot( red_snapper_shapefile, col=rgb(0,0,0,0.2), add=TRUE ) 49 | legend( "bottomleft", bty="n", 50 | legend=levels(red_snapper$Data_type), 51 | fill = rainbow(3) ) 52 | ``` 53 | 54 | To fit these data, we first define the `family` for each datum. Critically, we define the cloglog link for the Presence/Absence data, so that the linear predictor is proportional to numerical density for each data type. See [Gruss and Thorson (2019)](https://doi.org/10.1093/icesjms/fsz075) or [Thorson and Kristensen (2024) Chap-7](https://doi.org/10.1201/9781003410294) for more details 55 | 56 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 57 | # Define link and distribution for each data type 58 | Family = list( 59 | "Encounter" = binomial(link="cloglog"), 60 | "Count" = poisson(link="log"), 61 | "Biomass_KG" = tweedie(link="log") 62 | ) 63 | 64 | # Relevel gear factor so Biomass_KG is base level 65 | red_snapper$Data_type = relevel( red_snapper$Data_type, 66 | ref = "Biomass_KG" ) 67 | ``` 68 | 69 | We then proceed with the other inputs as per usual: 70 | 71 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 72 | # Define mesh 73 | mesh = fm_mesh_2d( red_snapper[,c('Lon','Lat')], cutoff = 0.5 ) 74 | 75 | # define formula with a catchability covariate for gear 76 | formula = Response_variable ~ Data_type + factor(Year) + offset(log(AreaSwept_km2)) 77 | 78 | # make variable column 79 | red_snapper$var = "logdens" 80 | 81 | # fit using tinyVAST 82 | fit = tinyVAST( data = red_snapper, 83 | formula = formula, 84 | space_term = "logdens <-> logdens, sd_space", 85 | spacetime_term = "logdens <-> logdens, 0, sd_spacetime", 86 | space_columns = c("Lon",'Lat'), 87 | spatial_domain = mesh, 88 | time_column = "Year", 89 | distribution_column = "Data_type", 90 | family = Family, 91 | variable_column = "var" ) 92 | ``` 93 | 94 | We then plot density estimates for each year: 95 | 96 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 97 | # make extrapolation-grid 98 | sf_grid = st_make_grid( red_snapper_shapefile, cellsize=c(0.2,0.2) ) 99 | sf_grid = st_intersection( sf_grid, red_snapper_shapefile ) 100 | sf_grid = st_make_valid( sf_grid ) 101 | 102 | # Extract coordinates for grid 103 | grid_coords = st_coordinates( st_centroid(sf_grid) ) 104 | areas_km2 = st_area( sf_grid ) / 1e6 105 | 106 | # Calcualte log-density for each year and grid-cell 107 | index = plot_grid = NULL 108 | for( year in sort(unique(red_snapper$Year)) ){ 109 | # compile predictive data frame 110 | newdata = data.frame( "Lat" = grid_coords[,'Y'], 111 | "Lon" = grid_coords[,'X'], 112 | "Year" = year, 113 | "Data_type" = "Biomass_KG", 114 | "AreaSwept_km2" = mean(red_snapper$AreaSwept_km2), 115 | "var" = "logdens" ) 116 | 117 | # predict 118 | log_dens = predict( fit, 119 | newdata = newdata, 120 | what = "p_g") 121 | log_dens = ifelse( log_dens < max(log_dens-log(100)), NA, log_dens ) 122 | 123 | # Compile densities 124 | plot_grid = cbind( plot_grid, log_dens ) 125 | 126 | # Estimate and compile total 127 | total = integrate_output( fit, 128 | newdata = newdata, 129 | area = areas_km2 ) 130 | index = cbind( index, total[c('Est. (bias.correct)','Std. Error')] ) 131 | 132 | } 133 | colnames(plot_grid) = colnames(index) = sort(unique(red_snapper$Year)) 134 | ``` 135 | 136 | We then plot densities in each year 137 | 138 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 139 | # Convert to sf and plot 140 | plot_grid = st_sf( sf_grid, 141 | plot_grid ) 142 | plot( plot_grid, 143 | border = NA ) 144 | ``` 145 | 146 | Similarly, we can plot the abundance index and standard errors 147 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 148 | ggplot( data.frame("Year"=colnames(index),"Est"=index[1,],"SE"=index[2,]) ) + 149 | geom_point( aes(x=Year, y=Est)) + 150 | geom_errorbar( aes(x=Year, ymin=Est-SE, ymax=Est+SE) ) 151 | ``` -------------------------------------------------------------------------------- /vignettes/spatial.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Spatial modeling" 3 | author: "James T. Thorson" 4 | output: rmarkdown::html_vignette 5 | #output: rmarkdown::pdf_document 6 | vignette: > 7 | %\VignetteIndexEntry{Spatial modeling} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | %\VignetteDepends{pdp} 11 | --- 12 | 13 | ```{r, include = FALSE} 14 | has_lattice = requireNamespace("lattice", quietly = TRUE) 15 | has_pdp = requireNamespace("pdp", quietly = TRUE) 16 | EVAL <- has_lattice && has_pdp 17 | knitr::opts_chunk$set( 18 | collapse = TRUE, 19 | comment = "#>", 20 | eval = EVAL, 21 | purl = EVAL 22 | ) 23 | # Install locally 24 | # devtools::install_local( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)', force=TRUE ) 25 | # Build 26 | # setwd(R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)'); devtools::build_rmd("vignettes/spatial.Rmd"); rmarkdown::render( "vignettes/spatial.Rmd", rmarkdown::pdf_document()) 27 | ``` 28 | 29 | ```{r setup, echo=TRUE, warning=FALSE, message=FALSE} 30 | library(tinyVAST) 31 | library(mgcv) 32 | library(fmesher) 33 | library(pdp) # approx = TRUE gives effects for average of other covariates 34 | library(lattice) 35 | library(ggplot2) 36 | set.seed(101) 37 | options("tinyVAST.verbose" = FALSE) 38 | ``` 39 | 40 | `tinyVAST` is an R package for fitting vector autoregressive spatio-temporal (VAST) models using a minimal and user-friendly interface. 41 | We here show how it can fit spatial autoregressive model. We first simulate a spatial random field and a confounder variable, and simulate data from this simulated process. 42 | 43 | ```{r simulate_data, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 44 | # Simulate a 2D AR1 spatial process with a cyclic confounder w 45 | n_x = n_y = 25 46 | n_w = 10 47 | R_xx = exp(-0.4 * abs(outer(1:n_x, 1:n_x, FUN="-")) ) 48 | R_yy = exp(-0.4 * abs(outer(1:n_y, 1:n_y, FUN="-")) ) 49 | z = mvtnorm::rmvnorm(1, sigma=kronecker(R_xx,R_yy) ) 50 | 51 | # Simulate nuissance parameter z from oscillatory (day-night) process 52 | w = sample(1:n_w, replace=TRUE, size=length(z)) 53 | Data = data.frame( expand.grid(x=1:n_x, y=1:n_y), w=w, z=as.vector(z) + cos(w/n_w*2*pi)) 54 | Data$n = Data$z + rnorm(nrow(Data), sd=1) 55 | 56 | # Add columns for multivariate and temporal dimensions 57 | Data$var = "density" 58 | Data$time = 2020 59 | ``` 60 | 61 | We next construct a triangulated mesh that represents our continuous spatial domain 62 | 63 | ```{r make_mesh, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 64 | # make mesh 65 | mesh = fm_mesh_2d( Data[,c('x','y')], cutoff = 2 ) 66 | 67 | # Plot it 68 | plot(mesh) 69 | ``` 70 | 71 | Finally, we can fit these data using `tinyVAST` 72 | ```{r fit_tinyVAST, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 73 | # Define sem, with just one variance for the single variable 74 | sem = " 75 | density <-> density, spatial_sd 76 | " 77 | 78 | # fit model 79 | out = tinyVAST( data = Data, 80 | formula = n ~ s(w), 81 | spatial_domain = mesh, 82 | control = tinyVASTcontrol(getsd=FALSE), 83 | space_term = sem) 84 | ``` 85 | 86 | We can then calculate the area-weighted total abundance: 87 | ```{r calculate_total, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 88 | # Predicted sample-weighted total 89 | integrate_output(out, newdata = out$data) 90 | # integrate_output(out, apply.epsilon=TRUE ) 91 | # predict(out) 92 | 93 | # True (latent) sample-weighted total 94 | sum( Data$z ) 95 | ``` 96 | 97 | 98 | # Percent deviance explained 99 | 100 | We can compute deviance residuals and percent-deviance explained: 101 | 102 | ```{r show_deviance_explained, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 103 | # Percent deviance explained 104 | out$deviance_explained 105 | ``` 106 | 107 | We can then compare this with the PDE reported by `mgcv` 108 | ```{r run_gam, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 109 | start_time = Sys.time() 110 | mygam = gam( n ~ s(w) + s(x,y), data=Data ) # 111 | Sys.time() - start_time 112 | summary(mygam)$dev.expl 113 | ``` 114 | 115 | where this comparison shows that using the SPDE method in tinyVAST results in higher percent-deviance-explained. This reduced performance for splines relative to the SPDE method presumably arises due to the reduced rank of the spline basis expansion, and the better match for the Matern function (in the SPDE method) relative to the true (simulated) exponential semivariogram. 116 | 117 | It is then easy to confirm that mgcv and tinyVAST give (essentially) identical PDE when switching tinyVAST to use the same bivariate spline for space. 118 | 119 | ```{r run_reduced_tinyVAST, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 120 | out_reduced = tinyVAST( data = Data, 121 | formula = n ~ s(w) + s(x,y) ) 122 | 123 | # Extract PDE for GAM-style spatial smoother in tinyVAST 124 | out_reduced$deviance_explained 125 | ``` 126 | 127 | # Visualize spatial response 128 | 129 | `tinyVAST` then has a standard `predict` function: 130 | ```{r show_predict, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 131 | predict(out, newdata=data.frame(x=1, y=1, time=1, w=1, var="density") ) 132 | ``` 133 | 134 | and this is used to compute the spatial response 135 | ```{r show_image, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 136 | # Prediction grid 137 | pred = outer( seq(1,n_x,len=51), 138 | seq(1,n_y,len=51), 139 | FUN=\(x,y) predict(out,newdata=data.frame(x=x,y=y,w=1,time=1,var="density")) ) 140 | image( x=seq(1,n_x,len=51), y=seq(1,n_y,len=51), z=pred, main="Predicted response" ) 141 | 142 | # True value 143 | image( x=1:n_x, y=1:n_y, z=matrix(Data$z,ncol=n_y), main="True response" ) 144 | ``` 145 | 146 | We can also compute the marginal effect of the cyclic confounder 147 | ```{r show_partial, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 148 | # compute partial dependence plot 149 | Partial = partial( object = out, 150 | pred.var = "w", 151 | pred.fun = \(object,newdata) predict(object,newdata), 152 | train = Data, 153 | approx = TRUE ) 154 | 155 | # Lattice plots as default option 156 | plotPartial( Partial ) 157 | ``` 158 | 159 | Alternatively, we can use the `predict` function to plot confidence intervals for marginal effects, although this is disabled on CRAN vignettes: 160 | 161 | ```{r show_ggplot, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 162 | # create new data frame 163 | newdata <- data.frame(w = seq(min(Data$w), max(Data$w), length.out = 100)) 164 | newdata = cbind( newdata, 'x'=13, 'y'=13, 'var'='density', 'time'=2020 ) 165 | 166 | # make predictions 167 | p <- predict( out, newdata=newdata, se.fit=TRUE, what="p_g" ) 168 | 169 | # Format as data frame and plot 170 | p = data.frame( newdata, as.data.frame(p) ) 171 | ggplot(p, aes(x=w, y=fit, 172 | ymin = fit - 1.96 * se.fit, ymax = fit + 1.96 * se.fit)) + 173 | geom_line() + geom_ribbon(alpha = 0.4) 174 | ``` 175 | -------------------------------------------------------------------------------- /vignettes/spatial_factor_analysis.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Spatial factor analysis" 3 | author: "James T. Thorson" 4 | output: rmarkdown::html_vignette 5 | #output: rmarkdown::pdf_document 6 | vignette: > 7 | %\VignetteIndexEntry{Spatial factor analysis} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | --- 11 | 12 | ```{r, include = FALSE} 13 | has_knitr = requireNamespace("knitr", quietly = TRUE) 14 | EVAL <- has_knitr 15 | knitr::opts_chunk$set( 16 | collapse = TRUE, 17 | comment = "#>", 18 | eval = EVAL, 19 | purl = EVAL 20 | ) 21 | # Install locally 22 | # devtools::install_local( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)', force=TRUE ) 23 | # Build 24 | # setwd(R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)'); devtools::build_rmd("vignettes/spatial_factor_analysis.Rmd"); rmarkdown::render( "vignettes/spatial_factor_analysis.Rmd", rmarkdown::pdf_document()) 25 | ``` 26 | 27 | ```{r setup, echo=TRUE, warning=FALSE, message=FALSE} 28 | library(tinyVAST) 29 | library(fmesher) 30 | set.seed(101) 31 | options("tinyVAST.verbose" = FALSE) 32 | ``` 33 | 34 | `tinyVAST` is an R package for fitting vector autoregressive spatio-temporal (VAST) models. 35 | We here explore the capacity to specify a spatial factor analysis, where the spatial pattern for multiple variables is described via 36 | their estimated association with a small number of spatial latent variables. 37 | 38 | # Spatial factor analysis 39 | We first explore the ability to specify two latent variables for five manifest variables. To start we simulate two spatial latent variables, 40 | project via a simulated loadings matrix, and then simulate a Tweedie response for each manifest variable: 41 | 42 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 43 | # Simulate settings 44 | theta_xy = 0.4 45 | n_x = n_y = 10 46 | n_c = 5 47 | rho = 0.8 48 | resid_sd = 0.5 49 | 50 | # Simulate GMRFs 51 | R_s = exp(-theta_xy * abs(outer(1:n_x, 1:n_y, FUN="-")) ) 52 | R_ss = kronecker(X=R_s, Y=R_s) 53 | delta_fs = mvtnorm::rmvnorm(n_c, sigma=R_ss ) 54 | 55 | # 56 | L_cf = matrix( rnorm(n_c^2), nrow=n_c ) 57 | L_cf[,3:5] = 0 58 | L_cf = L_cf + resid_sd * diag(n_c) 59 | 60 | # 61 | d_cs = L_cf %*% delta_fs 62 | ``` 63 | 64 | Where we can inspect the simulated loadings matrix 65 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 66 | dimnames(L_cf) = list( paste0("Var ", 1:nrow(L_cf)), 67 | paste0("Factor ", 1:ncol(L_cf)) ) 68 | knitr::kable( L_cf, 69 | digits=2, caption="True loadings") 70 | ``` 71 | 72 | We then specify the model as expected by _tinyVAST_: 73 | 74 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 75 | # Shape into longform data-frame and add error 76 | Data = data.frame( expand.grid(species=1:n_c, x=1:n_x, y=1:n_y), 77 | "var"="logn", "z"=exp(as.vector(d_cs)) ) 78 | Data$n = tweedie::rtweedie( n=nrow(Data), mu=Data$z, phi=0.5, power=1.5 ) 79 | mean(Data$n==0) 80 | 81 | # make mesh 82 | mesh = fm_mesh_2d( Data[,c('x','y')] ) 83 | 84 | # 85 | sem = " 86 | f1 -> 1, l1 87 | f1 -> 2, l2 88 | f1 -> 3, l3 89 | f1 -> 4, l4 90 | f1 -> 5, l5 91 | f2 -> 2, l6 92 | f2 -> 3, l7 93 | f2 -> 4, l8 94 | f2 -> 5, l9 95 | f1 <-> f1, NA, 1 96 | f2 <-> f2, NA, 1 97 | 1 <-> 1, NA, 0 98 | 2 <-> 2, NA, 0 99 | 3 <-> 3, NA, 0 100 | 4 <-> 4, NA, 0 101 | 5 <-> 5, NA, 0 102 | " 103 | 104 | # fit model 105 | out = tinyVAST( space_term = sem, 106 | data = Data, 107 | formula = n ~ 0 + factor(species), 108 | spatial_domain = mesh, 109 | family = tweedie(), 110 | variables = c( "f1", "f2", 1:n_c ), 111 | space_columns = c("x","y"), 112 | variable_column = "species", 113 | time_column = "time", 114 | distribution_column = "dist", 115 | control = tinyVASTcontrol(gmrf="proj") ) 116 | out 117 | ``` 118 | 119 | We can compare the true loadings (rotated to optimize comparison): 120 | 121 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 122 | Lrot_cf = rotate_pca( L_cf )$L_tf 123 | dimnames(Lrot_cf) = list( paste0("Var ", 1:nrow(Lrot_cf)), 124 | paste0("Factor ", 1:ncol(Lrot_cf)) ) 125 | knitr::kable( Lrot_cf, 126 | digits=2, caption="Rotated true loadings") 127 | ``` 128 | 129 | with the estimated loadings 130 | 131 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 132 | # Extract and rotate estimated loadings 133 | Lhat_cf = matrix( 0, nrow=n_c, ncol=2 ) 134 | Lhat_cf[lower.tri(Lhat_cf,diag=TRUE)] = as.list(out$sdrep, what="Estimate")$theta_z 135 | Lhat_cf = rotate_pca( L_tf=Lhat_cf, order="decreasing" )$L_tf 136 | ``` 137 | 138 | Where we can compared the estimated and true loadings matrices: 139 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 140 | dimnames(Lhat_cf) = list( paste0("Var ", 1:nrow(Lhat_cf)), 141 | paste0("Factor ", 1:ncol(Lhat_cf)) ) 142 | knitr::kable( Lhat_cf, 143 | digits=2, caption="Rotated estimated loadings" ) 144 | ``` 145 | 146 | 147 | Or we can specify the model while ensuring that residual spatial variation is also captured: 148 | 149 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 150 | # 151 | sem = " 152 | f1 -> 1, l1 153 | f1 -> 2, l2 154 | f1 -> 3, l3 155 | f1 -> 4, l4 156 | f1 -> 5, l5 157 | f2 -> 2, l6 158 | f2 -> 3, l7 159 | f2 -> 4, l8 160 | f2 -> 5, l9 161 | f1 <-> f1, NA, 1 162 | f2 <-> f2, NA, 1 163 | 1 <-> 1, sd_resid 164 | 2 <-> 2, sd_resid 165 | 3 <-> 3, sd_resid 166 | 4 <-> 4, sd_resid 167 | 5 <-> 5, sd_resid 168 | " 169 | 170 | # fit model 171 | out = tinyVAST( space_term = sem, 172 | data = Data, 173 | formula = n ~ 0 + factor(species), 174 | spatial_domain = mesh, 175 | family = list( "obs"=tweedie() ), 176 | variables = c( "f1", "f2", 1:n_c ), 177 | space_columns = c("x","y"), 178 | variable_column = "species", 179 | time_column = "time", 180 | distribution_column = "dist", 181 | control = tinyVASTcontrol(gmrf="proj") ) 182 | 183 | # Extract and rotate estimated loadings 184 | Lhat_cf = matrix( 0, nrow=n_c, ncol=2 ) 185 | Lhat_cf[lower.tri(Lhat_cf,diag=TRUE)] = as.list(out$sdrep, what="Estimate")$theta_z 186 | Lhat_cf = rotate_pca( L_tf=Lhat_cf, order="decreasing" )$L_tf 187 | ``` 188 | 189 | Where we can again compared the estimated and true loadings matrices: 190 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 191 | dimnames(Lhat_cf) = list( paste0("Var ", 1:nrow(Lhat_cf)), 192 | paste0("Factor ", 1:ncol(Lhat_cf)) ) 193 | knitr::kable( Lhat_cf, 194 | digits=2, caption="Rotated estimated loadings with full rank" ) 195 | ``` 196 | 197 | -------------------------------------------------------------------------------- /vignettes/web_only/empirical_orthogonal_functions.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Empirical orthogonal functions" 3 | author: "James T. Thorson" 4 | output: rmarkdown::html_vignette 5 | #output: rmarkdown::pdf_document 6 | vignette: > 7 | %\VignetteIndexEntry{Empirical orthogonal functions} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | --- 11 | 12 | ```{r, include = FALSE} 13 | has_rnaturalearth = requireNamespace("rnaturalearth", quietly = TRUE) 14 | EVAL <- has_rnaturalearth 15 | knitr::opts_chunk$set( 16 | collapse = TRUE, 17 | comment = "#>", 18 | eval = EVAL, 19 | purl = EVAL 20 | ) 21 | # Install locally 22 | # devtools::install_local( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)', force=TRUE ) 23 | # Build 24 | # setwd(R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)'); devtools::build_rmd("vignettes/empirical_orthogonal_functions.Rmd"); rmarkdown::render( "vignettes/empirical_orthogonal_functions.Rmd", rmarkdown::pdf_document()) 25 | ``` 26 | 27 | ```{r setup, echo=TRUE, warning=FALSE, message=FALSE} 28 | library(tinyVAST) 29 | library(fmesher) 30 | set.seed(101) 31 | ``` 32 | 33 | tinyVAST is an R package for fitting vector autoregressive spatio-temporal (VAST) models. 34 | We here explore the capacity to specify a generalized linear latent variable model that is configured to 35 | generalize an empirical orthogonal function analysis. 36 | 37 | # Empirical Orthogonal Function (EOF) analysis 38 | To start, we reformat data on September Sea ice concentrations: 39 | 40 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6, warning=FALSE} 41 | data( sea_ice ) 42 | library(sf) 43 | library(rnaturalearth) 44 | 45 | # project data 46 | sf_ice = st_as_sf( sea_ice, coords = c("lon","lat") ) 47 | st_crs(sf_ice) = "+proj=longlat +datum=WGS84" 48 | sf_ice = st_transform( sf_ice, 49 | crs=st_crs("+proj=laea +lat_0=90 +lon_0=-30 +units=km") ) 50 | 51 | # 52 | sf_pole = st_point( c(0,90) ) 53 | sf_pole = st_sfc( sf_pole, crs="+proj=longlat +datum=WGS84" ) 54 | sf_pole = st_transform( sf_pole, crs=st_crs(sf_ice) ) 55 | sf_pole = st_buffer( sf_pole, dist=3000 ) 56 | sf_ice = st_intersection( sf_ice, sf_pole ) 57 | 58 | Data = data.frame( st_drop_geometry(sf_ice), 59 | st_coordinates(sf_ice), 60 | var = "Ice" ) 61 | ``` 62 | 63 | Next, we construct the various inputs to _tinyVAST_ 64 | 65 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 66 | n_eof = 2 67 | dsem = make_eof_ram( variables = "Ice", 68 | times = sort(unique(Data[,'year'])), 69 | n_eof = 2, 70 | standard_deviations = 0 ) 71 | mesh = fm_mesh_2d( Data[,c('X','Y')], cutoff=1.5 ) 72 | 73 | # fit model 74 | out = tinyVAST( spacetime_term = dsem, 75 | space_term = "", 76 | data = as.data.frame(Data), 77 | formula = ice_concentration ~ 1, 78 | spatial_domain = mesh, 79 | space_column = c("X","Y"), 80 | variable_column = "var", 81 | time_column = "year", 82 | distribution_column = "dist", 83 | times = c(paste0("EOF_",seq_len(n_eof)), sort(unique(Data[,'year']))), 84 | control = tinyVASTcontrol( profile="alpha_j", 85 | gmrf_parameterization="projection") ) 86 | ``` 87 | 88 | Finally, we can extract, rotate, and plot the dominant modes of variability and associated spatial responses: 89 | 90 | ```{r EOF, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 91 | # Country shapefiles for plotting 92 | sf_maps = ne_countries( return="sf", scale="medium", continent=c("north america","europe","asia") ) 93 | sf_maps = st_transform( sf_maps, crs=st_crs(sf_ice) ) 94 | sf_maps = st_union( sf_maps ) 95 | 96 | # Shapefile for water 97 | sf_water = st_difference( st_as_sfc(st_bbox(sf_maps)), sf_maps ) 98 | 99 | # Create extrapolation grid 100 | cellsize = 50 101 | sf_grid = st_make_grid( sf_pole, cellsize=cellsize ) 102 | # Restrict to water 103 | grid_i = st_intersects( sf_water, sf_grid ) 104 | sf_grid = sf_grid[ unique(unlist(grid_i)) ] 105 | # Restrict to 3000 km from North Pole 106 | grid_i = st_intersects( sf_pole, sf_grid ) 107 | sf_grid = sf_grid[ unique(unlist(grid_i)) ] 108 | 109 | # 110 | newdata = data.frame( st_coordinates(st_centroid(sf_grid)), 111 | var = "Ice" ) 112 | 113 | # Extract loadings 114 | L_tf = matrix( 0, nrow=length(unique(Data$year)), ncol=2, 115 | dimnames=list(unique(Data$year),c("EOF_1","EOF_2")) ) 116 | L_tf[lower.tri(L_tf,diag=TRUE)] = out$opt$par[names(out$opt$par)=="beta_z"] 117 | 118 | # Extract factor-responses 119 | EOF1_g = predict( out, cbind(newdata, year="EOF_1"), what="pepsilon_g" ) 120 | EOF2_g = predict( out, cbind(newdata, year="EOF_2"), what="pepsilon_g" ) 121 | omega_g = predict( out, cbind(newdata, year="EOF_2"), what="pomega_g" ) 122 | 123 | # Rotate responses and loadings 124 | rotated_results = rotate_pca( L_tf=L_tf, x_sf=cbind(EOF1_g,EOF2_g), order="decreasing" ) 125 | EOF1_g = rotated_results$x_sf[,1] 126 | EOF2_g = rotated_results$x_sf[,2] 127 | L_tf = rotated_results$L_tf 128 | 129 | # Plot on map 130 | sf_plot = st_sf( sf_grid, "EOF1_g"=EOF1_g, "EOF2_g"=EOF2_g, "omega_g"=omega_g ) 131 | par(mfrow=c(2,2), oma=c(2,2,0,0) ) 132 | plot( sf_plot[,'EOF1_g'], reset=FALSE, key.pos=NULL, border=NA ) 133 | plot( st_geometry(sf_maps), add=TRUE, border=NA, col="grey" ) 134 | plot( sf_plot[,'EOF2_g'], reset=FALSE, key.pos=NULL, border=NA ) 135 | plot( st_geometry(sf_maps), add=TRUE, border=NA, col="grey" ) 136 | plot( sf_plot[,'omega_g'], reset=FALSE, key.pos=NULL, border=NA ) 137 | plot( st_geometry(sf_maps), add=TRUE, border=NA, col="grey" ) 138 | matplot( y=L_tf, x=unique(Data$year), type="l", 139 | col=viridisLite::viridis(n_eof), lwd=2, lty="solid" ) 140 | legend( "top", ncol=n_eof, legend=paste0("EOF",1:n_eof), 141 | fill=viridisLite::viridis(n_eof) ) 142 | ``` 143 | -------------------------------------------------------------------------------- /vignettes/web_only/overview.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Overview of vignettes" 3 | author: "James T. Thorson" 4 | output: rmarkdown::html_vignette 5 | #output: rmarkdown::pdf_document 6 | vignette: > 7 | %\VignetteIndexEntry{Overview of vignettes} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | --- 11 | 12 | ```{r, include = FALSE} 13 | EVAL <- TRUE 14 | knitr::opts_chunk$set( 15 | collapse = TRUE, 16 | comment = "#>", 17 | eval = EVAL, 18 | purl = EVAL 19 | ) 20 | # Install locally 21 | # devtools::install_local( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)', force=TRUE ) 22 | # Build and PDF 23 | # setwd(R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)'); devtools::build_rmd("vignettes/aaa.Rmd"); rmarkdown::render( "vignettes/aaa.Rmd", rmarkdown::pdf_document()) 24 | ``` 25 | 26 | `tinyVAST` can implement many analyses as nested submodels. For this reason, it can be difficult to organize materials to orient users who are interested in one or another type of analysis. To improve organization, we summarize the different features that are available in vignettes: 27 | 28 | ### Background materials: 29 | * *tinyVAST Model description*: Describes equations and notation 30 | * *Comparison with mgcv*: Shows that tinyVAST smoothers are (approximately) identical to those using package mgcv, despite replacing the generalized additive model wiggliness parameter with a mixed-effects variance parameter (i.e., replacing the* Spatial modeling: Shows how to fit a simple spatial model, including covariates, and then visualize model output, deviance explained, and other diagnostics; 31 | * *Spatial models* 32 | * *Multiple data types*: Shows how to integrate data following different distributions, in this case showing presence/absence, count, and biomass samples for red snapper; 33 | * *Dynamic structural equation models*: Shows how tinyVAST can be reduced down to a time-series model with simultaneous and lagged effects (e.g., a vector autoregressive model) 34 | 35 | ### Alternative spatial domains 36 | * *Simulatenous autoregressive process*: Shows how to to use an areal spatial domain (a simultaneous autoregressive SAR process) instead of the two-dimensional smoother; 37 | * *Stream network models*: Shows how to use a stream network spatial domain (i.e., an Ornstein-Uhlenbeck process on flow-unconnected sites in an acyclic graph); 38 | 39 | ### Multivariate spatio-temporal models 40 | * *Age composition expansion*: Shows how to fit a multivariate spatio-temporal model to standardize age composition data; 41 | * *Condition and density*: Shows how to jointly analyze different types of data which are then combined in a single estimator. In this case, we use a joint analysis of numerical density and animal condition to calculate per-capita average condition 42 | * *Empirical orthogonal functions*: Shows how to fit an empirical orthogonal function (EOF) analysis, i.e., a model where spatio-temporal variation is the product of one or more time-series, each associated with a spatial response map 43 | additive penalty in a generalized additive model with the log-determinant of the Hessian for the approximated marginal likelihood) 44 | * *Spatial factor analysis*: Shows how to specify spatial factors to represent the covariance among multiple variables, including the identifiability requirement and the post-hoc rotation of estimated loadings; 45 | * *Vector autoregressive spatio-temporal*: Shows how to fit a simple (two-variable) spatial version of a vector autoregressive model. 46 | -------------------------------------------------------------------------------- /vignettes/web_only/stream_networks.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Stream network models" 3 | author: "James T. Thorson" 4 | output: rmarkdown::html_vignette 5 | #output: rmarkdown::pdf_document 6 | vignette: > 7 | %\VignetteIndexEntry{Stream network models} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | %\VignetteDepends{ggraph} 11 | --- 12 | 13 | ```{r, include = FALSE} 14 | has_viridisLite = requireNamespace("viridisLite", quietly = TRUE) 15 | EVAL <- has_viridisLite 16 | knitr::opts_chunk$set( 17 | collapse = TRUE, 18 | comment = "#>", 19 | eval = EVAL, 20 | purl = EVAL 21 | ) 22 | # Install locally 23 | # devtools::install_local( R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)', force=TRUE, dep=FALSE ) 24 | # Build 25 | # setwd(R'(C:\Users\James.Thorson\Desktop\Git\tinyVAST)'); devtools::build_rmd("vignettes/web_only/stream_networks.Rmd"); rmarkdown::render( "vignettes/web_only/stream_networks.Rmd", rmarkdown::pdf_document()) 26 | ``` 27 | 28 | ```{r setup, echo=TRUE, warning=FALSE, message=FALSE} 29 | library(sf) 30 | library(sfnetworks) 31 | library(tinyVAST) 32 | library(viridisLite) 33 | set.seed(101) 34 | options("tinyVAST.verbose" = FALSE) 35 | ``` 36 | 37 | `tinyVAST` is an R package for fitting vector autoregressive spatio-temporal (VAST) models using a minimal and user-friendly interface. 38 | We here show how it can fit a stream network model, where spatial correlations arise from stream distances along a network. 39 | 40 | First, we load a shapefile representing a stream network, and convert it to _sfnetwork_ format. This format includes 41 | edges representing stream segments, and nodes where edges connect. 42 | ```{r stream-shape, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6, warning=FALSE} 43 | stream <- st_read( file.path(system.file("stream_network",package="tinyVAST"), 44 | "East_Fork_Lewis_basin.shp"), quiet=TRUE ) 45 | stream = as_sfnetwork(stream) 46 | plot(stream, main="East Fork Lewis Basin") 47 | ``` 48 | 49 | We then convert it to an S3 class "sfnetwork_mesh" defined by _tinyVAST_ for stream networks, 50 | and rescale distances to 1000 ft (to ensure that distances are 0.01 to 100, avoiding 51 | issues of numerical under or overflow). 52 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 53 | # Rescale 54 | graph = sfnetwork_mesh( stream ) 55 | graph$table$dist = graph$table$dist / 1000 # Convert distance scale 56 | ``` 57 | 58 | Next, we'll simulate a Gaussian Markov random field at stream vertices using `simulate_sfnetwork`, 59 | sample evenly spaced locations along the stream using `st_line_sample`, 60 | project the GMRF to those locations using `sfnetwork_evaluator`, and 61 | simulate data at those locations: 62 | ```{r, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 63 | # Parameters 64 | alpha = 2 65 | kappa = 0.05 66 | # mean(graph$table$dist) * kappa = 0.63 -> exp(-0.63) = 0.5 average correlation 67 | 68 | # simulate 69 | omega_s = simulate_sfnetwork( n=1, sfnetwork_mesh=graph, theta=kappa)[,1] 70 | 71 | # sample locations along network 72 | extrap = st_union( st_line_sample( activate(stream,"edges"), density=1/10000)) 73 | extrap = st_cast( extrap, "POINT" ) 74 | 75 | # Project to sampled locations 76 | A_is = sfnetwork_evaluator( stream = graph$stream, 77 | loc = st_coordinates(extrap) ) 78 | omega_i = (A_is %*% omega_s)[,1] 79 | 80 | # Simulate sampling 81 | #Count = rpois( n=graph$n, lambda=exp(alpha + omega) ) 82 | Count_i = rnorm( n=length(omega_i), mean=alpha + omega_i, sd=0.5 ) 83 | 84 | # Format into long-form data frame expected by tinyVAST 85 | Data = data.frame( Count = Count_i, 86 | st_coordinates(extrap), 87 | var = "species", # Univariate model so only one value 88 | time = "2020", # no time-dynamics, so only one value 89 | dist = "obs" ) # only one type of sampling in data 90 | ``` 91 | 92 | We can visualize the GMRF at those locations using _sfnetwork_ 93 | ```{r stream-dens, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 94 | # Plot stream 95 | plot(stream) 96 | # Extract nodes and plot on network 97 | plot( st_sf(st_geometry(activate(stream,"nodes")), "omega"=omega_s), 98 | add=TRUE, pch=19, cex=2) 99 | ``` 100 | 101 | Finally, we can fit the model, interpolate the GMRF along at dense locations along 102 | the stream network, and plot those with the true (simulated) values at the 103 | location of simulated samples. 104 | ```{r stream-pred, eval=TRUE, echo=TRUE, message=FALSE, fig.width=6, fig.height=6} 105 | # fit model 106 | out = tinyVAST( data = Data, 107 | formula = Count ~ 1, 108 | spatial_domain = graph, 109 | space_column = c("X","Y"), 110 | variable_column = "var", 111 | time_column = "time", 112 | distribution_column = "dist", 113 | space_term = "" ) 114 | 115 | # 116 | sf_plot = st_union( st_line_sample( activate(stream,"edges"), density=1/1000)) 117 | sf_plot = st_cast( sf_plot, "POINT" ) 118 | newdata = data.frame( Count = NA, 119 | st_coordinates(sf_plot), 120 | var = "species", # Univariate model so only one value 121 | time = "2020", # no time-dynamics, so only one value 122 | dist = "obs" ) # only one type of sampling in data 123 | omega_plot = predict( out, newdata = newdata ) 124 | 125 | # Plot estimated GMRF at sampled locations 126 | plot( stream, main="omegahat_i") 127 | plot( st_sf(sf_plot,"omega"=omega_plot), add=TRUE, pch=19, cex=0.5, pal=viridis ) 128 | plot( st_sf(extrap,"omega"=omega_i), add=TRUE, pch=19, cex=2, pal=viridis ) 129 | ``` 130 | --------------------------------------------------------------------------------