Repository: TheoreticalEcology/s-jSDM (language: python)

Issue:
Dependencies not found for windows

I tried to install  automatically by "install_sjSDM(version = c("cpu"))",
such error arose: The following packages are not available from current channels:

  - python=3.1
  
Then I tried to install manually in cmd, but it seemed like that: 
library(sjSDM)
√ torch 
x torch_optimizer 
x pyro 
x madgrad



installation error in macOS
Hi, 
I'm reinstalling R and everything following a migration to an M1 Mac.  

The following code did not work for installation, and it looks like the sjSDM_env is incomplete?

doug

`
#### in terminal
conda create --name sjSDM_env python=3.7 # choose py3
conda activate sjSDM_env # now in py3 env
conda install pytorch torchvision cpuonly -c pytorch # cpu

#### in R
devtools::install_github("https://github.com/TheoreticalEcology/s-jSDM", subdir = "sjSDM")
library(sjSDM)
packageVersion("sjSDM") # [1] ‘0.1.8’
set.seed(42)
community <- simulate_SDM(sites = 100, species = 10, env = 3, se = TRUE)
Env <- community$env_weights
Occ <- community$response
SP <- matrix(rnorm(200, 0, 0.3), 100, 2) # spatial coordinates (no effect on species occurences)

model <- sjSDM(Y = Occ, env = linear(data = Env, formula = ~X1+X2+X3), spatial = linear(data = SP, formula = ~0+X1:X2), se = TRUE, family=binomial("probit"), sampling = 100L)
`

> ── Attaching sjSDM ────────────────────────────────────────────── 0.1.8 ──
> x torch 
> x torch_optimizer 
> x pyro 
> x madgrad 
> 
> Torch or other dependencies not found:
> 	1. Use install_sjSDM() to install Pytorch and conda automatically 
> 	2. Installation trouble shooting guide: ?installation_help 
> 	3. If 1) and 2) did not help, please create an issue on <https://github.com/TheoreticalEcology/s-jSDM/issues> (see ?install_diagnostic) 
> Error: PyTorch not installed



#### install_diagnostic()

> 
> EnvironmentLocationNotFound: Not a conda environment: /Users/Negorashi2011/opt/miniconda3/envs/miniconda3
> 
> 
> EnvironmentLocationNotFound: Not a conda environment: /Users/Negorashi2011/opt/miniconda3/envs/miniconda3
> 
>         name
> 1 miniconda3
> 2  sjSDM_env
>                                                          python
> 1                /Users/Negorashi2011/opt/miniconda3/bin/python
> 2 /Users/Negorashi2011/opt/miniconda3/envs/sjSDM_env/bin/python
> 
> 
> 
> ENV: miniconda3
> 
> 
> torch:
> 
> 
> 
> numpy:
> 
> 
> 
> ENV: sjSDM_env
> 
> 
> torch:
> # packages in environment at /Users/Negorashi2011/opt/miniconda3/envs/sjSDM_env:
> #
> # Name                    Version                   Build  Channel
> pytorch                   1.9.1                   py3.7_0    pytorch
> torchvision               0.10.1                 py37_cpu    pytorch
> 
> 
> numpy:
> # packages in environment at /Users/Negorashi2011/opt/miniconda3/envs/sjSDM_env:
> #
> # Name                    Version                   Build  Channel
> 
> 
> python:         /usr/bin/python
> libpython:      /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/config/libpython2.7.dylib
> pythonhome:     /System/Library/Frameworks/Python.framework/Versions/2.7:/System/Library/Frameworks/Python.framework/Versions/2.7
> version:        2.7.16 (default, Aug 30 2021, 14:43:11)  [GCC Apple LLVM 12.0.5 (clang-1205.0.19.59.6) [+internal-os, ptrauth-isa=deploy
> numpy:          /System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/numpy
> numpy_version:  1.8.0
> torch:          [NOT FOUND]
> 
> python versions found: 
>  /usr/bin/python3
>  /usr/bin/python
> 
> 
> 
> 
>      active environment : None
>        user config file : /Users/Negorashi2011/.condarc
>  populated config files : /Users/Negorashi2011/.condarc
>           conda version : 4.10.3
>     conda-build version : not installed
>          python version : 3.9.5.final.0
>        virtual packages : __osx=10.16=0
>                           __unix=0=0
>                           __archspec=1=x86_64
>        base environment : /Users/Negorashi2011/opt/miniconda3  (writable)
>       conda av data dir : /Users/Negorashi2011/opt/miniconda3/etc/conda
>   conda av metadata url : None
>            channel URLs : https://repo.anaconda.com/pkgs/main/osx-64
>                           https://repo.anaconda.com/pkgs/main/noarch
>                           https://repo.anaconda.com/pkgs/r/osx-64
>                           https://repo.anaconda.com/pkgs/r/noarch
>           package cache : /Users/Negorashi2011/opt/miniconda3/pkgs
>                           /Users/Negorashi2011/.conda/pkgs
>        envs directories : /Users/Negorashi2011/opt/miniconda3/envs
>                           /Users/Negorashi2011/.conda/envs
>                platform : osx-64
>              user-agent : conda/4.10.3 requests/2.25.1 CPython/3.9.5 Darwin/20.6.0 OSX/10.16
>                 UID:GID : 502:20
>              netrc file : None
>            offline mode : False


Install error sh: line 1: 79672 Killed: 9
Some users get error messages such as the following during install

```
sh: line 1: 79672 Killed: 9               R_TESTS= '/Library/Frameworks/R.framework/Resources/bin/R' --no-save --no-restore --no-echo 2>&1 < '/var/folders/m_/zb7c8p_13k59p3zrpw84c4hm0000gq/T//Rtmpc0CxFQ/file13725537e4ec1'
ERROR: loading failed
* removing ‘/Library/Frameworks/R.framework/Versions/4.0/Resources/library/sjSDM’
Warning in install.packages :
  installation of package ‘/Users/pedro/Desktop/sjSDM_0.0.6.9000.tar.gz’ had non-zero exit status​
```
reference for importance() / documentation of variation partitioning in general 
Hi Max,

for another paper, we are just discussing where the idea for the importance() function originated. Is there are reference for this? I think you mentioned to me once that you saw it first in Gleb's HMSC implementation? 

Maybe add whatever detail you can provide (also regarding advantages / disadvantages wrt to our ANOVA implementation) in the help? This might also have prevented this recent question with the ANOVA for other variables. 

Could possibly also extend the Vignette by adding / extending the discussion on how to compare importance of different variables / compartments. 
reference for importance() / documentation of variation partitioning in general 
Hi Max,

for another paper, we are just discussing where the idea for the importance() function originated. Is there are reference for this? I think you mentioned to me once that you saw it first in Gleb's HMSC implementation? 

Maybe add whatever detail you can provide (also regarding advantages / disadvantages wrt to our ANOVA implementation) in the help? This might also have prevented this recent question with the ANOVA for other variables. 

Could possibly also extend the Vignette by adding / extending the discussion on how to compare importance of different variables / compartments. 


Discussion / hints:
Hi @Zinco-Li,

it seems that the installation fails again 

for a hot fix, do:

1) restart RStudio
2) reticulate::conda_remove('r-reticulate')
3) reticulate::conda_create('r-reticulate', python_version='3.8')
4) reticulate::conda_install('r-reticulate',packages = c("pytorch", "torchvision", "torchaudio" ,"-c", "pytorch"))
5) reticulate::conda_install('r-reticulate',packages = c("pyro-ppl", "torch_optimizer", "madgrad"), pip=TRUE)



Hi Doug,
yes, you're right, the environment is not complete and might be even missing. Strange. Try this:
1. rerun the sjSDM_install() function
2. restart RStudio
3. if the error persists:
     a) reticulate::conda_create('r-reticulate', python_version='3.6')
     b) rerun sjSDM_install()
     c) reticulate::conda_install('r-reticulate',packages = c("pytorch", "torchvision", "torchaudio" ,"-c", "pytorch"))
     d) reticulate::conda_install('r-reticulate',packages = c("pyro-ppl", "torch_optimizer", "madgrad"), pip=TRUE)
Thanks for this.  I ran commands a-d, and i still get this error when i run this:


`
> model <- sjSDM(Y = Occ, env = linear(data = Env, formula = ~X1+X2+X3), spatial = linear(data = SP, formula = ~0+X1:X2), se = TRUE, family=binomial("probit"), sampling = 100L)
── Attaching sjSDM ────────────────────────────────────────────── 0.1.8 ──
x torch 
x torch_optimizer 
x pyro 
x madgrad 

Torch or other dependencies not found:
	1. Use install_sjSDM() to install Pytorch and conda automatically 
	2. Installation trouble shooting guide: ?installation_help 
	3. If 1) and 2) did not help, please create an issue on <https://github.com/TheoreticalEcology/s-jSDM/issues> (see ?install_diagnostic) 
Error: PyTorch not installed
`

I think i have a clue about the problem.  when i run `python -V` in my terminal, i get Python 3.9.5, but when i run it in the Terminal _inside_ RStudio, i get Python 2.7.16, which is the default Apple Python installation.

This is very strange!



`
> sjSDM::install_diagnostic()

EnvironmentLocationNotFound: Not a conda environment: /Users/Negorashi2011/opt/miniconda3/envs/miniconda3


EnvironmentLocationNotFound: Not a conda environment: /Users/Negorashi2011/opt/miniconda3/envs/miniconda3

          name
1   miniconda3
2 r-reticulate
                                                            python
1                   /Users/Negorashi2011/opt/miniconda3/bin/python
2 /Users/Negorashi2011/opt/miniconda3/envs/r-reticulate/bin/python



ENV: miniconda3


torch:



numpy:



ENV: r-reticulate


torch:
# packages in environment at /Users/Negorashi2011/opt/miniconda3/envs/r-reticulate:
#
# Name                    Version                   Build  Channel
pytorch                   1.9.1                   py3.6_0    pytorch
pytorch-ranger            0.1.1                    pypi_0    pypi
torch-optimizer           0.1.0                    pypi_0    pypi
torchaudio                0.9.1                      py36    pytorch
torchvision               0.10.1                 py36_cpu    pytorch


numpy:
# packages in environment at /Users/Negorashi2011/opt/miniconda3/envs/r-reticulate:
#
# Name                    Version                   Build  Channel
numpy                     1.17.0           py36hacdab7b_0  
numpy-base                1.17.0           py36h6575580_0  


python:         /usr/bin/python
libpython:      /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/config/libpython2.7.dylib
pythonhome:     /System/Library/Frameworks/Python.framework/Versions/2.7:/System/Library/Frameworks/Python.framework/Versions/2.7
version:        2.7.16 (default, Aug 30 2021, 14:43:11)  [GCC Apple LLVM 12.0.5 (clang-1205.0.19.59.6) [+internal-os, ptrauth-isa=deploy
numpy:          /System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/numpy
numpy_version:  1.8.0
torch:          [NOT FOUND]

python versions found: 
 /usr/bin/python3
 /usr/bin/python




     active environment : None
       user config file : /Users/Negorashi2011/.condarc
 populated config files : /Users/Negorashi2011/.condarc
          conda version : 4.10.3
    conda-build version : not installed
         python version : 3.9.5.final.0
       virtual packages : __osx=10.16=0
                          __unix=0=0
                          __archspec=1=x86_64
       base environment : /Users/Negorashi2011/opt/miniconda3  (writable)
      conda av data dir : /Users/Negorashi2011/opt/miniconda3/etc/conda
  conda av metadata url : None
           channel URLs : https://repo.anaconda.com/pkgs/main/osx-64
                          https://repo.anaconda.com/pkgs/main/noarch
                          https://repo.anaconda.com/pkgs/r/osx-64
                          https://repo.anaconda.com/pkgs/r/noarch
          package cache : /Users/Negorashi2011/opt/miniconda3/pkgs
                          /Users/Negorashi2011/.conda/pkgs
       envs directories : /Users/Negorashi2011/opt/miniconda3/envs
                          /Users/Negorashi2011/.conda/envs
               platform : osx-64
             user-agent : conda/4.10.3 requests/2.25.1 CPython/3.9.5 Darwin/20.6.0 OSX/10.16
                UID:GID : 502:20
             netrc file : None
           offline mode : False
`
okay, let's try this:

1. remove miniconda, e.g. by (in terminal)
    ` $rm -rf /Users/Negorashi2011/opt/miniconda3`
2. restart Rstudio
3. sjSDM setup (within R):
  a)reticulate::install_miniconda() 
  b) reticulate::conda_create('r-reticulate', python_version='3.7')
  c) rerun sjSDM_install()
  d) reticulate::conda_install('r-reticulate',packages = c("pytorch", "torchvision", "torchaudio" ,"-c", "pytorch"))
  e) reticulate::conda_install('r-reticulate',packages = c("pyro-ppl", "torch_optimizer", "madgrad"), pip=TRUE)
4. reticulate::use_condaenv("r-reticulate")
sadly did not work.  

let's revisit this in Leipzig?

doug


> On 4 Oct 2021, at 12:55, MaximilianPi ***@***.***> wrote:
> 
> 
> okay, let's try this:
> 
> remove miniconda, e.g. by (in terminal)
> $rm -rf /Users/Negorashi2011/opt/miniconda3
> restart Rstudio
> sjSDM setup (within R):
> a) reticulate::conda_create('r-reticulate', python_version='3.7')
> b) rerun sjSDM_install()
> c) reticulate::conda_install('r-reticulate',packages = c("pytorch", "torchvision", "torchaudio" ,"-c", "pytorch"))
> d) reticulate::conda_install('r-reticulate',packages = c("pyro-ppl", "torch_optimizer", "madgrad"), pip=TRUE)
> reticulate::use_condaenv("r-reticulate")
> —
> You are receiving this because you authored the thread.
> Reply to this email directly, view it on GitHub <https://github.com/TheoreticalEcology/s-jSDM/issues/78#issuecomment-933409510>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/ADB4EP3NKIGXDLE72S244L3UFGIZTANCNFSM5FGTDXIQ>.
> Triage notifications on the go with GitHub Mobile for iOS <https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675> or Android <https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub>. 
> 


Oh no, we have to find a way to simplify the installation... 

Yes, let's revisit it next week. One last question, can you please post the output of sessionInfo()?
by the way, i'm using `install_sjSDM()` instead of `sjSDM_install()`

> sessionInfo()
R version 4.1.1 (2021-08-10)
Platform: aarch64-apple-darwin20 (64-bit)
Running under: macOS Big Sur 11.6

Matrix products: default
LAPACK: /Library/Frameworks/R.framework/Versions/4.1-arm64/Resources/lib/libRlapack.dylib

locale:
[1] en_GB.UTF-8/en_GB.UTF-8/en_GB.UTF-8/C/en_GB.UTF-8/en_GB.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] sjSDM_0.1.8

loaded via a namespace (and not attached):
 [1] nlme_3.1-153        fs_1.5.0            usethis_2.0.1      
 [4] ordinal_2019.12-10  devtools_2.4.2      insight_0.14.4     
 [7] rprojroot_2.0.2     numDeriv_2016.8-1.1 tools_4.1.1        
[10] backports_1.2.1     utf8_1.2.2          R6_2.5.1           
[13] sjlabelled_1.1.8    DBI_1.1.1           colorspace_2.0-2   
[16] withr_2.4.2         gridExtra_2.3       tidyselect_1.1.1   
[19] prettyunits_1.1.1   mnormt_2.0.2        processx_3.5.2     
[22] compiler_4.1.1      git2r_0.28.0        cli_3.0.1          
[25] desc_1.4.0          scales_1.1.1        checkmate_2.0.0    
[28] mvtnorm_1.1-2       psych_2.1.9         callr_3.7.0        
[31] stringr_1.4.0       digest_0.6.28       minqa_1.2.4        
[34] pkgconfig_2.0.3     parallelly_1.28.1   lme4_1.1-27.1      
[37] sessioninfo_1.1.1   fastmap_1.1.0       rlang_0.4.11       
[40] rstudioapi_0.13     generics_0.1.0      jsonlite_1.7.2     
[43] dplyr_1.0.7         zip_2.2.0           magrittr_2.0.1     
[46] Matrix_1.3-4        Rcpp_1.0.7          munsell_0.5.0      
[49] fansi_0.5.0         reticulate_1.22     lifecycle_1.0.1    
[52] furrr_0.2.3         ucminf_1.1-4        stringi_1.7.4      
[55] MASS_7.3-54         pkgbuild_1.2.0      plyr_1.8.6         
[58] grid_4.1.1          parallel_4.1.1      listenv_0.8.0      
[61] sjmisc_2.8.7        crayon_1.4.1        lattice_0.20-45    
[64] splines_4.1.1       tmvnsim_1.0-2       ps_1.6.0           
[67] pillar_1.6.3        boot_1.3-28         reshape2_1.4.4     
[70] codetools_0.2-18    pkgload_1.2.2       glue_1.4.2         
[73] data.table_1.14.2   remotes_2.4.1       BiocManager_1.30.16
[76] png_0.1-7           vctrs_0.3.8         nloptr_1.2.2.2     
[79] testthat_3.0.4      gtable_0.3.0        purrr_0.3.4        
[82] tidyr_1.1.4         future_1.22.1       assertthat_0.2.1   
[85] cachem_1.0.6        ggplot2_3.3.5       xfun_0.26          
[88] openxlsx_4.2.4      hablar_0.3.0        broom_0.7.9        
[91] tibble_3.1.5        tinytex_0.34        memoise_2.0.0      
[94] globals_0.14.0      ellipsis_0.3.2      here_1.0.1  



> sjSDM::install_diagnostic()

EnvironmentLocationNotFound: Not a conda environment: /Users/Negorashi2011/opt/anaconda3/envs/anaconda3


EnvironmentLocationNotFound: Not a conda environment: /Users/Negorashi2011/opt/anaconda3/envs/anaconda3

          name
1    anaconda3
2 r-reticulate
                                                           python
1                   /Users/Negorashi2011/opt/anaconda3/bin/python
2 /Users/Negorashi2011/opt/anaconda3/envs/r-reticulate/bin/python



ENV: anaconda3


torch:



numpy:



ENV: r-reticulate


torch:
# packages in environment at /Users/Negorashi2011/opt/anaconda3/envs/r-reticulate:
#
# Name                    Version                   Build  Channel
pytorch                   1.9.1                   py3.7_0    pytorch
pytorch-ranger            0.1.1                    pypi_0    pypi
torch-optimizer           0.1.0                    pypi_0    pypi
torchaudio                0.9.1                      py37    pytorch
torchvision               0.10.1                 py37_cpu    pytorch


numpy:
# packages in environment at /Users/Negorashi2011/opt/anaconda3/envs/r-reticulate:
#
# Name                    Version                   Build  Channel
numpy                     1.20.3           py37h4b4dc7a_0  
numpy-base                1.20.3           py37he0bd621_0  


Error in py_initialize(config$python, config$libpython, config$pythonhome,  : 
  /Users/Negorashi2011/opt/anaconda3/envs/r-reticulate/lib/libpython3.7m.dylib - dlopen(/Users/Negorashi2011/opt/anaconda3/envs/r-reticulate/lib/libpython3.7m.dylib, 10): no suitable image found.  Did find:
	/Users/Negorashi2011/opt/anaconda3/envs/r-reticulate/lib/libpython3.7m.dylib: mach-o, but wrong architecture
	/Users/Negorashi2011/opt/anaconda3/envs/r-reticulate/lib/libpython3.7m.dylib: mach-o, but wrong architecture
Ah, I found the issue. You have installed the arm64 R-version (Platform: aarch64-apple-darwin20 (64-bit)) which is not compatible with the x86 python stuff. I'm still running the x86 R-version because many R packages and python packages are not yet compatible with arm. 

So in short, to run sjSDM (and other deep learning frameworks) you need to install the x86 R-version (https://cran.r-project.org/bin/macosx/) (using the x86 instead of the arm version has (almost) no negative side effects)


I haven't tried, but can you run them side by side and switch when needed?
Hm, switch when needed... Theoretically yes (it's the same situation when you have different R versions installed), but you need always to change first the R path variable so that RStudio starts with the intended R-version (I guess it's different for each OS...)
i just installed the Intel version of R, but i got this when trying to install sjSDM

`
Warning message:
In file.symlink(target, symlink) :
  cannot symlink '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/config' to '/var/folders/3y/gxvqrxx968j9b8f6_4vcg7vm0000gp/T/rstudio-fallback-library-path-y31BVP', reason 'File exists'
`

let's debug this in person? 

my computer is brand new, and we can use this computer as a test machine for a simpler installation script.  
We do not understand why the problem occurs, but in the past, it helped to install via 

`install.packages("<path to tar.gz>/sjSDM_0.0.2.9000.tar.gz", repos=NULL, INSTALL_opts = "--no-test-load")`


That worked. Note though, that after I installed the package and run the model I got the following error:
```
Error in py_call_impl(callable, dots$args, dots$keywords) : TypeError: 'NoneType' object is not callable
```
After quitting R and reloading the package, it seems to be working fine now.
Hi both,

On a related note, I find that I've been hitting my head against a wall trying to make sense of both the `Rsquared` and `anova` implementations. I've scoured the code and the Nakagawa (2013) article and I still feel like I'm missing some important assumption. So, my questions persist:

1. How are the individual (species) R2 so unbelievably small? (And, for that matter, in `anova`, why are the R2 so small?)
2. How do some of the R2 in `anova` end up negative? I realize that the R2 of the modules has to sum up to whatever the estimate is for the full model, but even so, a negative R2 doesn't make sense to me.

Some extra documentation to guide the user through the interpretation of these outputs would be really helpful.

Thanks,
Kara
Hi,

Thanks for bringing up this issue, I'm also having some difficulties to understand what the anova results mean. Since my spatial fraction has a number of -2.2, I assume that the interpretation of the Venn diagram is not the same as in case of a traditional variation partitioning where the sum of each fractions should below 1 and the residuals (unexplained) is 1-Rsquare. How should we interpret these results and what is the link between your anova plot and a traditional variation partitioning? 
Thanks for your help in advance!
/Máté
Hi both,

On a related note, I find that I've been hitting my head against a wall trying to make sense of both the `Rsquared` and `anova` implementations. I've scoured the code and the Nakagawa (2013) article and I still feel like I'm missing some important assumption. So, my questions persist:

1. How are the individual (species) R2 so unbelievably small? (And, for that matter, in `anova`, why are the R2 so small?)
2. How do some of the R2 in `anova` end up negative? I realize that the R2 of the modules has to sum up to whatever the estimate is for the full model, but even so, a negative R2 doesn't make sense to me.

Some extra documentation to guide the user through the interpretation of these outputs would be really helpful.

Thanks,
Kara
Hi,

Thanks for bringing up this issue, I'm also having some difficulties to understand what the anova results mean. Since my spatial fraction has a number of -2.2, I assume that the interpretation of the Venn diagram is not the same as in case of a traditional variation partitioning where the sum of each fractions should below 1 and the residuals (unexplained) is 1-Rsquare. How should we interpret these results and what is the link between your anova plot and a traditional variation partitioning? 
Thanks for your help in advance!
/Máté

Fix patch:
diff --git a/.DS_Store b/.DS_Store
index d810888..ab7a5ab 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/.github/workflows/check-standard.yaml b/.github/workflows/check-standard.yaml
index e19a124..263212c 100644
--- a/.github/workflows/check-standard.yaml
+++ b/.github/workflows/check-standard.yaml
@@ -1,6 +1,8 @@
 # For help debugging build failures open an issue on the RStudio community with the 'github-actions' tag.
 # https://community.rstudio.com/new-topic?category=Package%20development&tags=github-actions
 on:
+  schedule:
+  - cron: '0 0 * * *'
   push:
     branches:
       - main
@@ -23,8 +25,10 @@ jobs:
       matrix:
         config:
           - {os: macOS-latest, r: 'release'}
+          - {os: windows-latest, r: 'release'}
           - {os: ubuntu-20.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"}
           - {os: ubuntu-20.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"}
+          - {os: ubuntu-20.04, r: 'oldrel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"}
 
     env:
       R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
@@ -39,13 +43,17 @@ jobs:
           r-version: ${{ matrix.config.r }}
 
       - uses: r-lib/actions/setup-pandoc@v1
+      
+      - uses: r-lib/actions/setup-tinytex@master
+      
+      - name: Install makeindex
+        run: tlmgr install makeindex
 
       - name: Query dependencies
         run: |
           setwd("sjSDM")
-          install.packages('remotes')
-          saveRDS(remotes::dev_package_deps(dependencies = TRUE), "../.github/depends.Rds", version = 2)
-          writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), "../.github/R-version")
+          install.packages("pak", repos = "https://r-lib.github.io/p/pak/dev/")
+          saveRDS(pak::pkg_deps("local::.", dependencies = TRUE), "../.github/r-depends.rds")
         shell: Rscript {0}
 
       - name: Cache R packages
@@ -53,65 +61,70 @@ jobs:
         uses: actions/cache@v2
         with:
           path: ${{ env.R_LIBS_USER }}
-          key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }}
-          restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-
+          key: ${{ matrix.config.os }}-${{ steps.install-r.outputs.installed-r-version }}-1-${{ hashFiles('.github/r-depends.rds') }}
+          restore-keys: ${{ matrix.config.os }}-${{ steps.install-r.outputs.installed-r-version }}-1-
+
+      - name: Install curl for r-devel version
+        if: runner.os == 'Linux'
+        run: |
+          sudo apt-get install -y curl
+          sudo apt-get install -y texlive texlive-fonts-extra
 
       - name: Install system dependencies
         if: runner.os == 'Linux'
         run: |
-          cd sjSDM
-          while read -r cmd
-          do
-            eval sudo $cmd
-          done < <(Rscript -e 'writeLines(remotes::system_requirements("ubuntu", "20.04"))')
+          setwd("sjSDM")
+          pak::local_system_requirements(execute = TRUE)
+          pak::pkg_system_requirements("rcmdcheck", execute = TRUE)
+        shell: Rscript {0}
+          
+      - name: Install miniconda r-sjsdm env # taken from gluonts R package
+        uses: conda-incubator/setup-miniconda@v2
+        with:
+          activate-environment: r-sjsdm
+          python-version: 3.7.1
+          environment-file: _environment.yml
 
       - name: Install dependencies
         run: |
           setwd("sjSDM")
-          remotes::install_deps(dependencies = TRUE)
-          remotes::install_cran("rcmdcheck")
+          pak::local_install_dev_deps(upgrade = TRUE)
+          pak::pkg_install("rcmdcheck")
         shell: Rscript {0}
         
       - name: Install Pkg
         run: |
           cd sjSDM
-          Rscript -e "remotes::install_local()"
-          Rscript -e "remotes::install_github('rstudio/reticulate')"
-          Rscript -e "reticulate::install_miniconda()"
+          Rscript -e "pak::local_install()"
+          Rscript -e "pak::pkg_install('rstudio/reticulate')"
+          Rscript -e "sjSDM::install_sjSDM(version='cpu')"
           
-      - if: runner.os == 'macOS'
-        run: echo "options(reticulate.conda_binary = reticulate:::miniconda_conda())" >> .Rprofile
-        
-      - name: Set conda path
-        if: runner.os != 'Windows'
-        run: |
-          conda_binary = reticulate:::miniconda_conda()
-          export = paste0("echo \"export conda='", conda_binary, "'\" >> ~/.bashrc")
-          system(export)
-          system("source ~/.bashrc")
-        shell: Rscript {0}
-          
-      - name: Install PyTorch
+      - name: Check I
         env:
-          RETICULATE_AUTOCONFIGURE: true
+          _R_CHECK_CRAN_INCOMING_REMOTE_: false
+          CI: true
         run: |
-          Rscript -e "sjSDM::install_sjSDM()"
-          Rscript -e "reticulate::conda_install(envname='r-reticulate', packages='tqdm')"
-          Rscript -e "reticulate::conda_install(envname='r-reticulate', packages='pytest')"
-          Rscript -e "reticulate::conda_install(envname='r-reticulate', package=c('pyro-ppl', 'torch-optimizer'), pip=TRUE)"
-          Rscript -e "try({ sjSDM::install_sjSDM() }, silent = TRUE)"
-          
-      - name: Check
+          options(crayon.enabled = TRUE)
+          rcmdcheck::rcmdcheck("sjSDM", args = c("--no-multiarch", "--no-manual"), error_on = "error", check_dir = "check")
+        shell: Rscript {0}
+        
+      - name: testthat output
+        if: always()
+        run: find check -name 'testthat.Rout*' -exec cat '{}' \; || true
+        shell: bash
+        
+      - name: Check II
         env:
           _R_CHECK_CRAN_INCOMING_REMOTE_: false
           CI: true
         run: |
-          rcmdcheck::rcmdcheck("sjSDM", args = c("--no-multiarch", "--no-manual"), error_on = "error", check_dir = "check")
+          options(crayon.enabled = TRUE)
+          rcmdcheck::rcmdcheck("sjSDM", args = c("--no-manual", "--as-cran"), error_on = "note", check_dir = "check")
         shell: Rscript {0}
-
+        
       - name: Upload check results
         if: failure()
         uses: actions/upload-artifact@main
         with:
-          name: ${{ runner.os }}-r${{ matrix.config.r }}-results
+          name: ${{ matrix.config.os }}-r${{ matrix.config.r }}-results
           path: check
diff --git a/.github/workflows/main b/.github/workflows/main
deleted file mode 100644
index defc05e..0000000
--- a/.github/workflows/main
+++ /dev/null
@@ -1,95 +0,0 @@
-# This is a basic workflow to help you get started with Actions
-
-name: R-CMD-check
-
-# Controls when the action will run. Triggers the workflow on push or pull request 
-# events but only for the master branch
-on:
-  push:
-    branches: 
-      - master
-      - devel
-  pull_request:
-    branches: 
-      - master
-      - devel
-  schedule:
-    - cron: '0 1 * * *'
-
-jobs:
-  R-CMD-check:
-    strategy:
-      fail-fast: false
-      matrix:
-        os: ['windows-latest', 'ubuntu-18.04', 'macos-latest']
-        include:
-          - os: ubuntu-18.04
-            cran: https://demo.rstudiopm.com/all/__linux__/bionic/latest
-    runs-on: ${{ matrix.os }}
-    name: ${{ matrix.os }}
-    env:
-      R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
-      PIP_NO_WARN_SCRIPT_LOCATION: false
-      RETICULATE_AUTOCONFIGURE: 'FALSE'
-      CRAN: ${{ matrix.cran }}
-
-    steps:
-      - uses: actions/checkout@v2
-      - uses: r-lib/actions/setup-r@master
-      - uses: r-lib/actions/setup-pandoc@master
-      - name: Install system dependencies
-        if: runner.os == 'Linux'
-        env:
-          RHUB_PLATFORM: linux-x86_64-ubuntu-gcc
-        run: |
-          cd sjSDM
-          Rscript -e "install.packages('remotes')" -e "remotes::install_github('r-hub/sysreqs')"
-          sysreqs=$(Rscript -e "cat(sysreqs::sysreq_commands('DESCRIPTION'))")
-          sudo -s eval "$sysreqs"
-      - name: Install dependencies
-        run: |
-          cd sjSDM
-          Rscript -e "install.packages('remotes')" -e "remotes::install_deps(dependencies = TRUE)" -e "remotes::install_cran('rcmdcheck')"
-      - name: Install Python
-        run: |
-          cd sjSDM
-          Rscript -e "remotes::install_github('rstudio/reticulate')" 
-          Rscript -e "remotes::install_cran('devtools')"
-      - name: Install miniconda mac
-        if: matrix.os == 'macos-latest'
-        run: |
-          wget  https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -O miniconda.sh
-          bash miniconda.sh -b -p $HOME/miniconda
-          export PATH="$HOME/miniconda/bin:$PATH"
-          hash -r
-          rm miniconda.sh
-          conda config --set auto_update_conda false
-          sudo purge
-          cd sjSDM
-          Rscript -e "remotes::install_local()"
-          Rscript -e "sjSDM::install_sjSDM(env = 'r-reticulate')"
-      - name: Install PyTorch
-        run: |
-          cd sjSDM
-          Rscript -e "remotes::install_local()"
-          Rscript -e "sjSDM::install_sjSDM(env = 'r-reticulate')"
-          Rscript -e "reticulate::conda_install(envname='r-reticulate', packages='pytest')"
-          Rscript -e "reticulate::conda_install(envname='r-reticulate', packages='tqdm')"
-      - name: free Mem mac
-        if: matrix.os == 'macos-latest'
-        run: |
-          sudo purge
-      - name: tests ubuntu
-        if: matrix.os == 'ubuntu-18.04-non'
-        run: |
-          cd sjSDM
-          Rscript -e "Sys.setenv(RETICULATE_AUTOCONFIGURE = TRUE);try(Sys.setenv(RETICULATE_PYTHON = '/usr/share/miniconda/envs/r-reticulate/bin/python'));library(reticulate);try({torch = import('torch')});use_condaenv(condaenv = 'r-reticulate');library(sjSDM);py_config();try({testthat::test_dir('tests/testthat/')})"
-      - name: tests windows
-        if: matrix.os == 'windows-latest'
-        run: |
-          cd sjSDM
-          Rscript -e "Sys.setenv(RETICULATE_AUTOCONFIGURE = TRUE);library(reticulate);try({torch = import('torch')});use_condaenv(condaenv = 'r-reticulate');library(sjSDM);py_config();install_diagnostic();try({testthat::test_dir('tests/testthat/')})"
-      - name: Check
-        continue-on-error: ${{ contains(matrix.allow_failure, 'true') }}
-        run: |
-          Rscript -e "rcmdcheck::rcmdcheck(path = 'sjSDM/', args = '--no-manual', error_on = 'warning', check_dir = 'check')"
diff --git a/.gitignore b/.gitignore
index 89f915d..93ed5ab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,4 @@ sjSDM/vignettes/sjSDM.R
 README.html
 sjSDM/vignettes/sjSDM.R
 sjSDM.Rproj
+.DS_Store
\ No newline at end of file
diff --git a/sjSDM/inst/python/sjSDM_py/model_LVM.py b/Code/sLVM/model_LVM.py
similarity index 100%
rename from sjSDM/inst/python/sjSDM_py/model_LVM.py
rename to Code/sLVM/model_LVM.py
diff --git a/sjSDM/inst/python/sjSDM_py/model_svi.py b/Code/sLVM/model_svi.py
similarity index 100%
rename from sjSDM/inst/python/sjSDM_py/model_svi.py
rename to Code/sLVM/model_svi.py
diff --git a/sjSDM/R/sLVM.R b/Code/sLVM/sLVM.R
similarity index 95%
rename from sjSDM/R/sLVM.R
rename to Code/sLVM/sLVM.R
index 5350a70..233a776 100644
--- a/sjSDM/R/sLVM.R
+++ b/Code/sLVM/sLVM.R
@@ -299,3 +299,18 @@ plot.sLVM = function(x, ...) {
   text(lvs[,1], lvs[,2], labels = as.character(1:nrow(lvs)))
 }
 
+
+
+serialize_state = function(model) {
+  tmp = tempfile(pattern = "svi state")
+  on.exit(unlink(tmp), add = TRUE)
+  model$pyro$get_param_store()$save(tmp)
+  return(readBin(tmp, what = "raw", n = file.size(tmp), size=1))
+}
+
+unserialize_state = function(model, state) {
+  tmp = tempfile(pattern = "svi state")
+  on.exit(unlink(tmp), add = TRUE)
+  writeBin(state, tmp)
+  model$model$pyro$get_param_store()$load(tmp)
+}
diff --git a/Code/sjSDM with random effects/EM sjSDM.ipynb b/Code/sjSDM with random effects/EM sjSDM.ipynb
new file mode 100644
index 0000000..6376cbd
--- /dev/null
+++ b/Code/sjSDM with random effects/EM sjSDM.ipynb
@@ -0,0 +1,352 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 697,
+   "id": "8f34bc58-a745-4b0a-b6ac-ff46115fe65e",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import torch\n",
+    "import numpy as np\n",
+    "import matplotlib.pyplot as plt\n",
+    "from dataclasses import dataclass\n",
+    "import statsmodels.api as sm\n",
+    "import statsmodels.formula.api as smf\n",
+    "import pandas as pd\n",
+    "from scipy.optimize import minimize\n",
+    "from dataclasses import dataclass\n",
+    "import numpy as np\n",
+    "@dataclass\n",
+    "class Simulation:\n",
+    "    X: np.ndarray\n",
+    "    Y: np.ndarray\n",
+    "    Sigma: np.ndarray\n",
+    "    W: np.ndarray\n",
+    "    scale_re: float\n",
+    "    g: np.ndarray\n",
+    "    G: float\n",
+    "    re: np.ndarray\n",
+    "    D: np.ndarray\n",
+    "    \n",
+    "\n",
+    "def correlation_from_covariance(covariance):\n",
+    "    v = np.sqrt(np.diag(covariance))\n",
+    "    outer_v = np.outer(v, v)\n",
+    "    correlation = covariance / outer_v\n",
+    "    correlation[covariance == 0] = 0\n",
+    "    return correlation\n",
+    "\n",
+    "import numpy as np,numpy.linalg\n",
+    "\n",
+    "def _getAplus(A):\n",
+    "    eigval, eigvec = np.linalg.eig(A)\n",
+    "    Q = np.matrix(eigvec)\n",
+    "    xdiag = np.matrix(np.diag(np.maximum(eigval, 0)))\n",
+    "    return Q*xdiag*Q.T\n",
+    "\n",
+    "def _getPs(A, W=None):\n",
+    "    W05 = np.matrix(W**.5)\n",
+    "    return  W05.I * _getAplus(W05 * A * W05) * W05.I\n",
+    "\n",
+    "def _getPu(A, W=None):\n",
+    "    Aret = np.array(A.copy())\n",
+    "    Aret[W > 0] = np.array(W)[W > 0]\n",
+    "    return np.matrix(Aret)\n",
+    "\n",
+    "def nearPD(A, nit=50):\n",
+    "    n = A.shape[0]\n",
+    "    W = np.identity(n) \n",
+    "# W is the matrix used for the norm (assumed to be Identity matrix here)\n",
+    "# the algorithm should work for any diagonal W\n",
+    "    deltaS = 0\n",
+    "    Yk = A.copy()\n",
+    "    for k in range(nit):\n",
+    "        Rk = Yk - deltaS\n",
+    "        Xk = _getPs(Rk, W=W)\n",
+    "        deltaS = Xk - Rk\n",
+    "        Yk = _getPu(Xk, W=W)\n",
+    "    return Yk\n",
+    "\n",
+    "def simulate(N=100, E=2, SP=3, G = 20, scale_re = 0.5, CAR=False):\n",
+    "    if CAR is not True:\n",
+    "        re = np.random.normal(0, scale_re, [G,1])\n",
+    "        g = np.repeat(np.arange(0,G), np.round(N/G))\n",
+    "        D = np.NaN\n",
+    "    else:\n",
+    "        D, Sigma, re = simulate_CAR(G, scale_re)\n",
+    "        g = np.arange(0, G**2)\n",
+    "        re = re.reshape([-1, 1])\n",
+    "    \n",
+    "    X = np.random.uniform(-1, 1, size=[N,E] )\n",
+    "    W = np.random.normal(size=[E,SP])\n",
+    "    Y = X@W + np.reshape(re[g,:], newshape=[N,1])\n",
+    "    \n",
+    "    SS = np.random.uniform(-1,1,size=[SP, SP])\n",
+    "    SS = correlation_from_covariance(SS@np.transpose(SS))\n",
+    "    YY = np.concatenate([np.random.multivariate_normal(Y[i,:], cov = SS, size=[1,]) for i in range(N)], 0)\n",
+    "    YY = YY > 0\n",
+    "    YY = YY.astype(np.float64)\n",
+    "    return Simulation(X, YY, SS, W, scale_re, g, G, re, D)\n",
+    "\n",
+    "def simulate_CAR(sides = 10, l = 0.7):\n",
+    "    row_coords = np.tile(np.arange(0, sides), sides).reshape([-1, 1])\n",
+    "    col_coords = np.tile(np.arange(0, sides), sides).reshape([-1, 1])\n",
+    "    d = np.concatenate([row_coords, col_coords], axis= 1)\n",
+    "    D = np.sum((d[:, np.newaxis, :] - d[np.newaxis, :, :]) ** 2, axis = -1)\n",
+    "    Sigma = nearPD(np.exp(-l*D))+np.eye(sides**2)*0.01\n",
+    "    re= np.random.multivariate_normal(np.zeros([sides**2]), cov=Sigma,size=[1])\n",
+    "    return D, Sigma, re"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 375,
+   "id": "2bb720b4-535b-428a-a406-1079548d61a8",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "data = simulate(SP=4,N=1000,scale_re=0.01,G = 10)\n",
+    "E = data.X.shape[1]\n",
+    "N = data.X.shape[0]\n",
+    "SP = data.Y.shape[1]\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 716,
+   "id": "b7bbb930-6320-4ab0-9f33-61f6bec25d2e",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def fit_model(data, \n",
+    "              outer_epochs=12, \n",
+    "              inner_epochs=3, \n",
+    "              device = \"cpu:0\", \n",
+    "              optim = \"torch\", \n",
+    "              likelihood_type=\"mvp\", \n",
+    "              det=True,\n",
+    "              CAR=False\n",
+    "             ):\n",
+    "    E = data.X.shape[1]\n",
+    "    N = data.X.shape[0]\n",
+    "    SP = data.Y.shape[1]\n",
+    "    X, Y, G, indices, D = data.X, data.Y, data.G, data.g, data.D\n",
+    "    if CAR is True:\n",
+    "        G = G**2\n",
+    "    dev = torch.device(device)\n",
+    "    XT = torch.tensor(X, dtype=torch.float32, device=dev)\n",
+    "    YT = torch.tensor(Y, dtype=torch.float32, device=dev)\n",
+    "    torch.autograd.set_detect_anomaly(True)\n",
+    "    W = torch.tensor(np.random.normal(0., 0.001, size=(XT.shape[1],Y.shape[1])), dtype=torch.float32, requires_grad=True, device=dev)\n",
+    "    r_dim = Y.shape[1]\n",
+    "    df = int(np.rint(Y.shape[1]/2))\n",
+    "    low = -np.sqrt(6.0/(r_dim+df)) # type: ignore\n",
+    "    high = np.sqrt(6.0/(r_dim+df)) # type: ignore      \n",
+    "    sigma = torch.tensor(np.random.uniform(low, high, [r_dim, df]), requires_grad = True, dtype=torch.float32, device=dev) # type: ignore\n",
+    "\n",
+    "    #@torch.jit.script\n",
+    "    def likelihood(mu: torch.Tensor, Ys: torch.Tensor, sigma: torch.Tensor, batch_size: int, sampling: int, df: int, alpha: float, device: str, dtype: torch.dtype):\n",
+    "        noise = torch.randn(size = [sampling, batch_size, df], device=torch.device(device), dtype=dtype)\n",
+    "        E = torch.sigmoid(   torch.einsum(\"ijk, lk -> ijl\", [noise, sigma]).add(mu).mul(alpha)   ).mul(0.999999).add(0.0000005)\n",
+    "        logprob = E.log().mul(Ys).add((1.0 - E).log().mul(1.0 - Ys)).neg().sum(dim = 2).neg()\n",
+    "        maxlogprob = logprob.max(dim = 0).values\n",
+    "        Eprob = logprob.sub(maxlogprob).exp().mean(dim = 0)\n",
+    "        loss = Eprob.log().neg().sub(maxlogprob)\n",
+    "        return loss\n",
+    "\n",
+    "    res = torch.tensor(np.random.normal(0, 0.01, size=(G, 1)), dtype=torch.float32, requires_grad=True, device=dev)\n",
+    "    scale_log = torch.tensor(np.random.normal(0.0,0.001, [1]), dtype=torch.float32, requires_grad=True, device=dev)\n",
+    "    zero_intercept = torch.zeros([1], dtype=torch.float32, device=dev)\n",
+    "    zero_CAR = torch.zeros([G], dtype=torch.float32, device=dev)\n",
+    "\n",
+    "    opt1 = torch.optim.RMSprop([W, scale_log, sigma],lr=0.01)\n",
+    "\n",
+    "    if CAR is True:\n",
+    "        D = torch.tensor(D, dtype=torch.float32, device=dev)\n",
+    "    opt2 = torch.optim.LBFGS([res], lr = 0.1)\n",
+    "    \n",
+    "    const_val = torch.tensor(0.0, dtype=torch.float32, device=dev)\n",
+    "    const_cov = torch.eye(G, dtype=torch.float32, device=dev)*0.01\n",
+    "\n",
+    "    soft = lambda t: torch.nn.functional.softplus(t)+0.0001\n",
+    "\n",
+    "    indices_T = torch.tensor(indices, dtype=torch.long)\n",
+    "    \n",
+    "    def re_loss():\n",
+    "        if CAR is not True:\n",
+    "            loss = -torch.distributions.Normal(zero_intercept, soft(scale_log)).log_prob(res).sum()\n",
+    "        else:\n",
+    "            loss = -torch.distributions.MultivariateNormal(zero_CAR, (-soft(scale_log)*D).exp()+const_cov).log_prob(res.reshape([1,-1])).sum()\n",
+    "        return loss\n",
+    "\n",
+    "    \n",
+    "    def ll(res, W,sigma, XT, YT, indices_T):\n",
+    "        pred = XT@W+res[indices_T,:]#*scale_log.exp()\n",
+    "        #loss = -torch.distributions.Normal(loc=pred, scale=soft(scale_log_2) ).log_prob(YT).sum()\n",
+    "        if likelihood_type == \"mvp\":\n",
+    "            loss = likelihood(pred, YT, sigma, XT.shape[0], 100, df, 1.7012, device, torch.float32).sum()\n",
+    "        else:\n",
+    "            loss = -torch.distributions.Binomial(total_count=1, probs= torch.sigmoid(pred*1.7012) ).log_prob(YT).sum()\n",
+    "        loss += re_loss()\n",
+    "        return loss\n",
+    "    \n",
+    "    def torch_optim(epoch):\n",
+    "        if epoch % inner_epochs == 0:\n",
+    "            for i in range(20):\n",
+    "                opt2.zero_grad()\n",
+    "                loss = ll(res, W,sigma, XT, YT, indices_T)\n",
+    "                loss.backward()\n",
+    "                opt2.step(lambda: ll(res, W,sigma, XT, YT, indices_T))\n",
+    "            opt2.zero_grad()\n",
+    "    \n",
+    "    def minimize_func(res2):\n",
+    "        res2 = torch.tensor(res2, dtype=torch.float32, device=dev).reshape([G, 1])\n",
+    "        loss = ll(res2, W,sigma, XT, YT, indices_T)\n",
+    "        return loss.cpu().data.numpy()\n",
+    "    \n",
+    "    def hessian(res2):\n",
+    "        res2 = torch.tensor(res2, dtype=torch.float32, requires_grad=True, device=dev)\n",
+    "        loss = ll(res2.reshape([G, 1]), W, sigma, XT, YT, indices_T)\n",
+    "        loss.backward()\n",
+    "        return res2.grad.cpu().data.numpy()\n",
+    "    \n",
+    "    def scipy_optim(res, epoch, const_val):\n",
+    "        if epoch % inner_epochs == 0:\n",
+    "            res_new = minimize(\n",
+    "                        minimize_func, \n",
+    "                        res.cpu().data.numpy().reshape([-1]), \n",
+    "                        jac=hessian, \n",
+    "                        method=\"BFGS\"\n",
+    "                    )\n",
+    "            res = torch.tensor(res_new.x, dtype=torch.float32, requires_grad=True, device=dev).reshape([G, 1])\n",
+    "            #const_val = torch.tensor( 0.5*(np.log((2*np.pi)**(res_new.hess_inv.shape[0])) - np.log(np.linalg.det(res_new.hess_inv))), dtype=torch.float32, device=dev)\n",
+    "            #print(const_val)\n",
+    "        return res, const_val\n",
+    "    \n",
+    "    if det is not True:\n",
+    "        const_val = torch.tensor(0.0, dtype=torch.float32, device=dev)\n",
+    "\n",
+    "    for epoch in range(outer_epochs):\n",
+    "        if optim == \"torch\": \n",
+    "            torch_optim(epoch)\n",
+    "        else:\n",
+    "            res, const_val = scipy_optim(res, epoch, const_val)\n",
+    "        \n",
+    "        sample_indices = np.random.randint(0, XT.shape[0], size = 20)\n",
+    "\n",
+    "        opt1.zero_grad()        \n",
+    "        pred = XT[sample_indices,:]@W+res[indices,:][sample_indices,:]#*scale_log.exp()\n",
+    "        loss = likelihood(pred, YT[sample_indices,:], sigma, pred.shape[0], 100, df, 1.7012, device, torch.float32).mean() + const_val\n",
+    "        loss += re_loss()\n",
+    "        loss.backward()\n",
+    "        opt1.step()\n",
+    "        opt1.zero_grad()\n",
+    "    avg_scale = soft(scale_log).mean().cpu().data.numpy()\n",
+    "    avg_acc = np.mean((np.sign(correlation_from_covariance((sigma @ sigma.t()).data.cpu().numpy())) == np.sign(data.Sigma) )[np.triu_indices(SP)])\n",
+    "    del opt1\n",
+    "    del W\n",
+    "    del XT\n",
+    "    del YT\n",
+    "    del sigma\n",
+    "    #torch.cuda.empty_cache()\n",
+    "    return avg_scale.tolist(), avg_acc"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 723,
+   "id": "4ea51833-7de6-46a3-a2b2-caa8b64d247c",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "/var/folders/5c/9lp9691n1g15x6vj_bm1fjbm0000gn/T/ipykernel_72226/3649358109.py:89: ComplexWarning: Casting complex values to real discards the imaginary part\n",
+      "  re= np.random.multivariate_normal(np.zeros([sides**2]), cov=Sigma,size=[1])\n"
+     ]
+    }
+   ],
+   "source": [
+    "data = simulate(SP=2,N=400,scale_re=0.3,G = 20, CAR=True)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 725,
+   "id": "35ec11ba-4e1f-4d31-8910-fbd995505155",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(0.6581300497055054, 0.6666666666666666)"
+      ]
+     },
+     "execution_count": 725,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "fit_model(data, 550, 20, optim=\"scipy\", likelihood_type=\"mvp\", CAR=True)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 580,
+   "id": "bd167e91-bea3-4ba9-bf79-8ba3004442e5",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "results_y = [fit_model(data, 200, 12, optim=\"scipy\", likelihood_type=\"mvp\", det=True)  for _ in range(15)]\n",
+    "#results_n = [fit_model(data, 60, 5, optim=\"scipy\", likelihood_type=\"mvp\", det=False) for _ in range(60)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 581,
+   "id": "19adb7ac-a9d5-4f97-8621-e47ee8834fc5",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[4.13961991 0.51632461]\n",
+      "[0.3287191 0.0027272]\n"
+     ]
+    }
+   ],
+   "source": [
+    "print( np.mean(np.asarray( results_y ), axis = 0) )\n",
+    "print( np.std(np.asarray( results_y ), axis = 0) )\n"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3 (ipykernel)",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.8.12"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/sjSDM/R/torch_generics.R b/Code/utils/torch_generics.R
similarity index 100%
rename from sjSDM/R/torch_generics.R
rename to Code/utils/torch_generics.R
diff --git a/README.Rmd b/README.Rmd
index f4dedb1..74c7da6 100644
--- a/README.Rmd
+++ b/README.Rmd
@@ -1,11 +1,9 @@
 ---
-title: "README"
-author: "Max Pichler"
-output: 
-  html_document: 
-    keep_md: yes
+output: github_document
 ---
 
+<!-- README.md is generated from README.Rmd. Please edit that file -->
+
 ```{r setup, include=FALSE}
 knitr::opts_chunk$set(echo = TRUE)
 ```
@@ -95,7 +93,7 @@ print(an)
 plot(an)
 ```
 
-The anova shows the relative changes in the logLik of the groups and their intersections.
+The anova shows the relative changes in the deviance of the groups and their intersections.
 
 
 
diff --git a/README.md b/README.md
index db4e1f8..0dc7b20 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,29 @@
-[![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](http://www.repostatus.org/badges/latest/active.svg)](http://www.repostatus.org/#active)
-[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
-![R-CMD-check](https://github.com/TheoreticalEcology/s-jSDM/workflows/R-CMD-check/badge.svg?branch=master)
-[![Publication](https://img.shields.io/badge/Publication-10.1111/2041-green.svg)](https://besjournals.onlinelibrary.wiley.com/doi/abs/10.1111/2041-210X.13687)
 
+<!-- README.md is generated from README.Rmd. Please edit that file -->
 
+[![Project Status: Active – The project has reached a stable, usable
+state and is being actively
+developed.](http://www.repostatus.org/badges/latest/active.svg)](http://www.repostatus.org/#active)
+[![License: GPL
+v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
+![R-CMD-check](https://github.com/TheoreticalEcology/s-jSDM/workflows/R-CMD-check/badge.svg?branch=master)
+[![Publication](https://img.shields.io/badge/Publication-10.1111/2041-green.svg)](https://besjournals.onlinelibrary.wiley.com/doi/abs/10.1111/2041-210X.13687)
 
 # s-jSDM - Fast and accurate Joint Species Distribution Modeling
 
 ## About the method
 
-The method is described in Pichler & Hartig (2021) A new joint species distribution model for faster and more accurate inference of species associations from big community data, https://doi.org/10.1111/2041-210X.13687. The code for producing the results in this paper is available under the subfolder publications in this repo.
+The method is described in Pichler & Hartig (2021) A new joint species
+distribution model for faster and more accurate inference of species
+associations from big community data,
+<https://doi.org/10.1111/2041-210X.13687>. The code for producing the
+results in this paper is available under the subfolder publications in
+this repo.
 
-The method itself is wrapped into an R package, available under subfolder sjSDM. You can also use it stand-alone under Python (see instructions below). Note: for both the R and the python package, python >= 3.6 and pytorch must be installed (more details below).
+The method itself is wrapped into an R package, available under
+subfolder sjSDM. You can also use it stand-alone under Python (see
+instructions below). Note: for both the R and the python package, python
+\>= 3.6 and pytorch must be installed (more details below).
 
 ## Installing the R / Python package
 
@@ -19,47 +31,44 @@ The method itself is wrapped into an R package, available under subfolder sjSDM.
 
 Install the package via
 
-
-```r
+``` r
 devtools::install_github("https://github.com/TheoreticalEcology/s-jSDM", subdir = "sjSDM")
 ```
 
-Depencies for the package can be installed before or after installing the package. Detailed explanations of the dependencies are provided in vignette("Dependencies", package = "sjSDM"), source code [here](https://github.com/TheoreticalEcology/s-jSDM/blob/master/sjSDM/vignettes/Dependencies.Rmd). Very briefly, the dependencies can be automatically installed from within R:
+Depencies for the package can be installed before or after installing
+the package. Detailed explanations of the dependencies are provided in
+vignette(“Dependencies”, package = “sjSDM”), source code
+[here](https://github.com/TheoreticalEcology/s-jSDM/blob/master/sjSDM/vignettes/Dependencies.Rmd).
+Very briefly, the dependencies can be automatically installed from
+within R:
 
-
-```r
+``` r
 sjSDM::install_sjSDM(version = "gpu") # or
 sjSDM::install_sjSDM(version = "cpu")
 ```
 
-
 To cite sjSDM, please use the following citation:
 
-```r
+``` r
 citation("sjSDM")
 ```
 
-
 Once the dependencies are installed, the following code should run:
 
 Simulate a community and fit model:
 
-```r
+``` r
 library(sjSDM)
 ```
 
-```
-## ── Attaching sjSDM ──────────────────────────────────────────────────── 0.1.8 ──
-```
+    ## ── Attaching sjSDM ──────────────────────────────────────────────────── 0.1.9 ──
 
-```
-## ✓ torch 1.9.0 
-## ✓ torch_optimizer  
-## ✓ pyro  
-## ✓ madgrad
-```
+    ## ✓ torch <environment> 
+    ## ✓ torch_optimizer  
+    ## ✓ pyro  
+    ## ✓ madgrad
 
-```r
+``` r
 set.seed(42)
 community <- simulate_SDM(sites = 100, species = 10, env = 3, se = TRUE)
 Env <- community$env_weights
@@ -70,255 +79,239 @@ model <- sjSDM(Y = Occ, env = linear(data = Env, formula = ~X1+X2+X3), spatial =
 summary(model)
 ```
 
-```
-## LogLik:  -521.6559 
-## Deviance:  1043.312 
-## 
-## Regularization loss:  0 
-## 
-## Species-species correlation matrix: 
-## 
-## 	sp1	 1.0000									
-## 	sp2	-0.3550	 1.0000								
-## 	sp3	-0.1370	-0.3560	 1.0000							
-## 	sp4	-0.1490	-0.3190	 0.6960	 1.0000						
-## 	sp5	 0.5980	-0.3380	-0.0930	-0.0980	 1.0000					
-## 	sp6	-0.2140	 0.3800	 0.1480	 0.1320	-0.0620	 1.0000				
-## 	sp7	 0.4640	-0.1500	 0.1330	 0.1140	 0.5180	 0.2360	 1.0000			
-## 	sp8	 0.2880	 0.1210	-0.4110	-0.4260	 0.2170	-0.0310	 0.1270	 1.0000		
-## 	sp9	-0.0960	-0.0590	 0.0620	 0.0650	-0.3180	-0.2570	-0.2460	-0.0910	 1.0000	
-## 	sp10	 0.1910	 0.3840	-0.6080	-0.5700	 0.2390	 0.1010	 0.1240	 0.3890	-0.2280	 1.0000
-## 
-## 
-## 
-## Spatial: 
-##             sp1        sp2       sp3         sp4       sp5      sp6       sp7
-## X1:X2 0.2116772 -0.5360333 0.5232622 0.008332695 0.3565705 0.180108 0.4192475
-##            sp8       sp9      sp10
-## X1:X2 0.473037 0.2719108 0.2562078
-## 
-## 
-## 
-##                  Estimate  Std.Err Z value Pr(>|z|)    
-## sp1 (Intercept)  -0.03177  0.20968   -0.15  0.87955    
-## sp1 X1            0.81680  0.40515    2.02  0.04379 *  
-## sp1 X2           -1.62852  0.37989   -4.29  1.8e-05 ***
-## sp1 X3           -0.12715  0.34814   -0.37  0.71494    
-## sp2 (Intercept)  -0.02736  0.21477   -0.13  0.89864    
-## sp2 X1            0.88439  0.40578    2.18  0.02929 *  
-## sp2 X2            0.18309  0.39785    0.46  0.64538    
-## sp2 X3            0.42769  0.35764    1.20  0.23174    
-## sp3 (Intercept)  -0.34305  0.22798   -1.50  0.13240    
-## sp3 X1            1.03899  0.42114    2.47  0.01362 *  
-## sp3 X2           -0.26187  0.40653   -0.64  0.51948    
-## sp3 X3           -0.68567  0.39507   -1.74  0.08264 .  
-## sp4 (Intercept)  -0.05341  0.20209   -0.26  0.79157    
-## sp4 X1           -0.99991  0.38088   -2.63  0.00866 ** 
-## sp4 X2           -1.30519  0.38755   -3.37  0.00076 ***
-## sp4 X3           -0.29711  0.33797   -0.88  0.37936    
-## sp5 (Intercept)  -0.16683  0.20947   -0.80  0.42577    
-## sp5 X1            0.48812  0.40224    1.21  0.22494    
-## sp5 X2            0.43646  0.37802    1.15  0.24826    
-## sp5 X3           -0.43820  0.35445   -1.24  0.21635    
-## sp6 (Intercept)   0.20027  0.20509    0.98  0.32883    
-## sp6 X1            1.66526  0.42341    3.93  8.4e-05 ***
-## sp6 X2           -0.68414  0.39862   -1.72  0.08611 .  
-## sp6 X3            0.18311  0.34733    0.53  0.59805    
-## sp7 (Intercept)  -0.00229  0.20182   -0.01  0.99093    
-## sp7 X1           -0.26273  0.37531   -0.70  0.48389    
-## sp7 X2            0.27684  0.35667    0.78  0.43764    
-## sp7 X3           -1.03507  0.34031   -3.04  0.00235 ** 
-## sp8 (Intercept)   0.15549  0.16257    0.96  0.33884    
-## sp8 X1            0.24234  0.31080    0.78  0.43556    
-## sp8 X2            0.29605  0.30469    0.97  0.33122    
-## sp8 X3           -1.10672  0.28354   -3.90  9.5e-05 ***
-## sp9 (Intercept)   0.03493  0.16276    0.21  0.83008    
-## sp9 X1            1.07005  0.31712    3.37  0.00074 ***
-## sp9 X2           -0.78384  0.30910   -2.54  0.01122 *  
-## sp9 X3            0.59471  0.27136    2.19  0.02841 *  
-## sp10 (Intercept) -0.09433  0.18507   -0.51  0.61027    
-## sp10 X1          -0.45735  0.33925   -1.35  0.17762    
-## sp10 X2          -0.96954  0.33834   -2.87  0.00416 ** 
-## sp10 X3          -0.38647  0.31582   -1.22  0.22106    
-## ---
-## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
-```
-
-```r
+    ## LogLik:  -519.8163 
+    ## Regularization loss:  0 
+    ## 
+    ## Species-species correlation matrix: 
+    ## 
+    ##  sp1  1.0000                                 
+    ##  sp2 -0.3550  1.0000                             
+    ##  sp3 -0.1510 -0.3470  1.0000                         
+    ##  sp4 -0.1480 -0.3310  0.6990  1.0000                     
+    ##  sp5  0.6040 -0.3410 -0.1090 -0.1000  1.0000                 
+    ##  sp6 -0.2230  0.3840  0.1500  0.1360 -0.0580  1.0000             
+    ##  sp7  0.4750 -0.1500  0.1310  0.1190  0.5030  0.2330  1.0000         
+    ##  sp8  0.2790  0.1390 -0.4310 -0.4230  0.2430 -0.0510  0.1300  1.0000     
+    ##  sp9 -0.0870 -0.0390  0.0780  0.0720 -0.3040 -0.2450 -0.2010 -0.1020  1.0000 
+    ##  sp10     0.1910  0.3930 -0.6080 -0.5730  0.2340  0.1140  0.1180  0.4120 -0.2270  1.0000
+    ## 
+    ## 
+    ## 
+    ## Spatial: 
+    ##             sp1        sp2       sp3         sp4       sp5       sp6       sp7
+    ## X1:X2 0.2142437 -0.5476772 0.5437201 0.002491096 0.3480671 0.1982483 0.4338585
+    ##             sp8       sp9      sp10
+    ## X1:X2 0.4867004 0.2601053 0.2501999
+    ## 
+    ## 
+    ## 
+    ##                  Estimate  Std.Err Z value Pr(>|z|)    
+    ## sp1 (Intercept)  -0.01163  0.20988   -0.06  0.95581    
+    ## sp1 X1            0.83841  0.41912    2.00  0.04546 *  
+    ## sp1 X2           -1.62395  0.38268   -4.24  2.2e-05 ***
+    ## sp1 X3           -0.15777  0.35500   -0.44  0.65675    
+    ## sp2 (Intercept)   0.00235  0.22054    0.01  0.99149    
+    ## sp2 X1            0.86883  0.43860    1.98  0.04760 *  
+    ## sp2 X2            0.18605  0.40632    0.46  0.64702    
+    ## sp2 X3            0.44304  0.36211    1.22  0.22114    
+    ## sp3 (Intercept)  -0.39657  0.21566   -1.84  0.06593 .  
+    ## sp3 X1            1.03265  0.39402    2.62  0.00877 ** 
+    ## sp3 X2           -0.25486  0.39149   -0.65  0.51504    
+    ## sp3 X3           -0.67251  0.36580   -1.84  0.06599 .  
+    ## sp4 (Intercept)  -0.09546  0.20690   -0.46  0.64453    
+    ## sp4 X1           -1.02157  0.39517   -2.59  0.00973 ** 
+    ## sp4 X2           -1.32603  0.39183   -3.38  0.00071 ***
+    ## sp4 X3           -0.26311  0.34662   -0.76  0.44781    
+    ## sp5 (Intercept)  -0.14047  0.20111   -0.70  0.48490    
+    ## sp5 X1            0.46950  0.38842    1.21  0.22676    
+    ## sp5 X2            0.43398  0.36234    1.20  0.23102    
+    ## sp5 X3           -0.44771  0.34862   -1.28  0.19906    
+    ## sp6 (Intercept)   0.19213  0.20023    0.96  0.33730    
+    ## sp6 X1            1.69016  0.41060    4.12  3.9e-05 ***
+    ## sp6 X2           -0.67460  0.38242   -1.76  0.07773 .  
+    ## sp6 X3            0.17613  0.32990    0.53  0.59342    
+    ## sp7 (Intercept)  -0.00412  0.20962   -0.02  0.98432    
+    ## sp7 X1           -0.27936  0.39252   -0.71  0.47666    
+    ## sp7 X2            0.28909  0.37268    0.78  0.43792    
+    ## sp7 X3           -1.06336  0.36108   -2.94  0.00323 ** 
+    ## sp8 (Intercept)   0.15611  0.15379    1.02  0.31007    
+    ## sp8 X1            0.25123  0.29255    0.86  0.39047    
+    ## sp8 X2            0.29725  0.28860    1.03  0.30302    
+    ## sp8 X3           -1.03698  0.26935   -3.85  0.00012 ***
+    ## sp9 (Intercept)   0.03160  0.16450    0.19  0.84767    
+    ## sp9 X1            1.08679  0.31940    3.40  0.00067 ***
+    ## sp9 X2           -0.81630  0.31191   -2.62  0.00887 ** 
+    ## sp9 X3            0.60194  0.27875    2.16  0.03082 *  
+    ## sp10 (Intercept) -0.06137  0.18320   -0.34  0.73762    
+    ## sp10 X1          -0.47306  0.33833   -1.40  0.16205    
+    ## sp10 X2          -0.95175  0.33596   -2.83  0.00461 ** 
+    ## sp10 X3          -0.40204  0.31031   -1.30  0.19512    
+    ## ---
+    ## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
+
+``` r
 plot(model)
 ```
 
-```
-## LogLik:  -521.6559 
-## Deviance:  1043.312 
-## 
-## Regularization loss:  0 
-## 
-## Species-species correlation matrix: 
-## 
-## 	sp1	 1.0000									
-## 	sp2	-0.3550	 1.0000								
-## 	sp3	-0.1370	-0.3560	 1.0000							
-## 	sp4	-0.1490	-0.3190	 0.6960	 1.0000						
-## 	sp5	 0.5980	-0.3380	-0.0930	-0.0980	 1.0000					
-## 	sp6	-0.2140	 0.3800	 0.1480	 0.1320	-0.0620	 1.0000				
-## 	sp7	 0.4640	-0.1500	 0.1330	 0.1140	 0.5180	 0.2360	 1.0000			
-## 	sp8	 0.2880	 0.1210	-0.4110	-0.4260	 0.2170	-0.0310	 0.1270	 1.0000		
-## 	sp9	-0.0960	-0.0590	 0.0620	 0.0650	-0.3180	-0.2570	-0.2460	-0.0910	 1.0000	
-## 	sp10	 0.1910	 0.3840	-0.6080	-0.5700	 0.2390	 0.1010	 0.1240	 0.3890	-0.2280	 1.0000
-## 
-## 
-## 
-## Spatial: 
-##             sp1        sp2       sp3         sp4       sp5      sp6       sp7
-## X1:X2 0.2116772 -0.5360333 0.5232622 0.008332695 0.3565705 0.180108 0.4192475
-##            sp8       sp9      sp10
-## X1:X2 0.473037 0.2719108 0.2562078
-## 
-## 
-## 
-##                  Estimate  Std.Err Z value Pr(>|z|)    
-## sp1 (Intercept)  -0.03177  0.20968   -0.15  0.87955    
-## sp1 X1            0.81680  0.40515    2.02  0.04379 *  
-## sp1 X2           -1.62852  0.37989   -4.29  1.8e-05 ***
-## sp1 X3           -0.12715  0.34814   -0.37  0.71494    
-## sp2 (Intercept)  -0.02736  0.21477   -0.13  0.89864    
-## sp2 X1            0.88439  0.40578    2.18  0.02929 *  
-## sp2 X2            0.18309  0.39785    0.46  0.64538    
-## sp2 X3            0.42769  0.35764    1.20  0.23174    
-## sp3 (Intercept)  -0.34305  0.22798   -1.50  0.13240    
-## sp3 X1            1.03899  0.42114    2.47  0.01362 *  
-## sp3 X2           -0.26187  0.40653   -0.64  0.51948    
-## sp3 X3           -0.68567  0.39507   -1.74  0.08264 .  
-## sp4 (Intercept)  -0.05341  0.20209   -0.26  0.79157    
-## sp4 X1           -0.99991  0.38088   -2.63  0.00866 ** 
-## sp4 X2           -1.30519  0.38755   -3.37  0.00076 ***
-## sp4 X3           -0.29711  0.33797   -0.88  0.37936    
-## sp5 (Intercept)  -0.16683  0.20947   -0.80  0.42577    
-## sp5 X1            0.48812  0.40224    1.21  0.22494    
-## sp5 X2            0.43646  0.37802    1.15  0.24826    
-## sp5 X3           -0.43820  0.35445   -1.24  0.21635    
-## sp6 (Intercept)   0.20027  0.20509    0.98  0.32883    
-## sp6 X1            1.66526  0.42341    3.93  8.4e-05 ***
-## sp6 X2           -0.68414  0.39862   -1.72  0.08611 .  
-## sp6 X3            0.18311  0.34733    0.53  0.59805    
-## sp7 (Intercept)  -0.00229  0.20182   -0.01  0.99093    
-## sp7 X1           -0.26273  0.37531   -0.70  0.48389    
-## sp7 X2            0.27684  0.35667    0.78  0.43764    
-## sp7 X3           -1.03507  0.34031   -3.04  0.00235 ** 
-## sp8 (Intercept)   0.15549  0.16257    0.96  0.33884    
-## sp8 X1            0.24234  0.31080    0.78  0.43556    
-## sp8 X2            0.29605  0.30469    0.97  0.33122    
-## sp8 X3           -1.10672  0.28354   -3.90  9.5e-05 ***
-## sp9 (Intercept)   0.03493  0.16276    0.21  0.83008    
-## sp9 X1            1.07005  0.31712    3.37  0.00074 ***
-## sp9 X2           -0.78384  0.30910   -2.54  0.01122 *  
-## sp9 X3            0.59471  0.27136    2.19  0.02841 *  
-## sp10 (Intercept) -0.09433  0.18507   -0.51  0.61027    
-## sp10 X1          -0.45735  0.33925   -1.35  0.17762    
-## sp10 X2          -0.96954  0.33834   -2.87  0.00416 ** 
-## sp10 X3          -0.38647  0.31582   -1.22  0.22106    
-## ---
-## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
-```
-
-![](README_files/figure-html/unnamed-chunk-4-1.png)<!-- -->
-
-We also support also other response families:
-Count data:
-
-```r
+    ## LogLik:  -519.8163 
+    ## Regularization loss:  0 
+    ## 
+    ## Species-species correlation matrix: 
+    ## 
+    ##  sp1  1.0000                                 
+    ##  sp2 -0.3550  1.0000                             
+    ##  sp3 -0.1510 -0.3470  1.0000                         
+    ##  sp4 -0.1480 -0.3310  0.6990  1.0000                     
+    ##  sp5  0.6040 -0.3410 -0.1090 -0.1000  1.0000                 
+    ##  sp6 -0.2230  0.3840  0.1500  0.1360 -0.0580  1.0000             
+    ##  sp7  0.4750 -0.1500  0.1310  0.1190  0.5030  0.2330  1.0000         
+    ##  sp8  0.2790  0.1390 -0.4310 -0.4230  0.2430 -0.0510  0.1300  1.0000     
+    ##  sp9 -0.0870 -0.0390  0.0780  0.0720 -0.3040 -0.2450 -0.2010 -0.1020  1.0000 
+    ##  sp10     0.1910  0.3930 -0.6080 -0.5730  0.2340  0.1140  0.1180  0.4120 -0.2270  1.0000
+    ## 
+    ## 
+    ## 
+    ## Spatial: 
+    ##             sp1        sp2       sp3         sp4       sp5       sp6       sp7
+    ## X1:X2 0.2142437 -0.5476772 0.5437201 0.002491096 0.3480671 0.1982483 0.4338585
+    ##             sp8       sp9      sp10
+    ## X1:X2 0.4867004 0.2601053 0.2501999
+    ## 
+    ## 
+    ## 
+    ##                  Estimate  Std.Err Z value Pr(>|z|)    
+    ## sp1 (Intercept)  -0.01163  0.20988   -0.06  0.95581    
+    ## sp1 X1            0.83841  0.41912    2.00  0.04546 *  
+    ## sp1 X2           -1.62395  0.38268   -4.24  2.2e-05 ***
+    ## sp1 X3           -0.15777  0.35500   -0.44  0.65675    
+    ## sp2 (Intercept)   0.00235  0.22054    0.01  0.99149    
+    ## sp2 X1            0.86883  0.43860    1.98  0.04760 *  
+    ## sp2 X2            0.18605  0.40632    0.46  0.64702    
+    ## sp2 X3            0.44304  0.36211    1.22  0.22114    
+    ## sp3 (Intercept)  -0.39657  0.21566   -1.84  0.06593 .  
+    ## sp3 X1            1.03265  0.39402    2.62  0.00877 ** 
+    ## sp3 X2           -0.25486  0.39149   -0.65  0.51504    
+    ## sp3 X3           -0.67251  0.36580   -1.84  0.06599 .  
+    ## sp4 (Intercept)  -0.09546  0.20690   -0.46  0.64453    
+    ## sp4 X1           -1.02157  0.39517   -2.59  0.00973 ** 
+    ## sp4 X2           -1.32603  0.39183   -3.38  0.00071 ***
+    ## sp4 X3           -0.26311  0.34662   -0.76  0.44781    
+    ## sp5 (Intercept)  -0.14047  0.20111   -0.70  0.48490    
+    ## sp5 X1            0.46950  0.38842    1.21  0.22676    
+    ## sp5 X2            0.43398  0.36234    1.20  0.23102    
+    ## sp5 X3           -0.44771  0.34862   -1.28  0.19906    
+    ## sp6 (Intercept)   0.19213  0.20023    0.96  0.33730    
+    ## sp6 X1            1.69016  0.41060    4.12  3.9e-05 ***
+    ## sp6 X2           -0.67460  0.38242   -1.76  0.07773 .  
+    ## sp6 X3            0.17613  0.32990    0.53  0.59342    
+    ## sp7 (Intercept)  -0.00412  0.20962   -0.02  0.98432    
+    ## sp7 X1           -0.27936  0.39252   -0.71  0.47666    
+    ## sp7 X2            0.28909  0.37268    0.78  0.43792    
+    ## sp7 X3           -1.06336  0.36108   -2.94  0.00323 ** 
+    ## sp8 (Intercept)   0.15611  0.15379    1.02  0.31007    
+    ## sp8 X1            0.25123  0.29255    0.86  0.39047    
+    ## sp8 X2            0.29725  0.28860    1.03  0.30302    
+    ## sp8 X3           -1.03698  0.26935   -3.85  0.00012 ***
+    ## sp9 (Intercept)   0.03160  0.16450    0.19  0.84767    
+    ## sp9 X1            1.08679  0.31940    3.40  0.00067 ***
+    ## sp9 X2           -0.81630  0.31191   -2.62  0.00887 ** 
+    ## sp9 X3            0.60194  0.27875    2.16  0.03082 *  
+    ## sp10 (Intercept) -0.06137  0.18320   -0.34  0.73762    
+    ## sp10 X1          -0.47306  0.33833   -1.40  0.16205    
+    ## sp10 X2          -0.95175  0.33596   -2.83  0.00461 ** 
+    ## sp10 X3          -0.40204  0.31031   -1.30  0.19512    
+    ## ---
+    ## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
+
+![](README_files/figure-gfm/unnamed-chunk-4-1.png)<!-- -->
+
+We also support also other response families: Count data:
+
+``` r
 model <- sjSDM(Y = Occ, env = linear(data = Env, formula = ~X1+X2+X3), spatial = linear(data = SP, formula = ~0+X1:X2), se = TRUE, family=poisson("log"))
 ```
 
 Gaussian (normal):
 
-```r
+``` r
 model <- sjSDM(Y = Occ, env = linear(data = Env, formula = ~X1+X2+X3), spatial = linear(data = SP, formula = ~0+X1:X2), se = TRUE, family=gaussian("identity"))
 ```
 
+Let’s have a look at the importance of the three groups (environment,
+associations, and space) on the occurences:
 
-
-Let's have a look at the importance of the three groups (environment, associations, and space) on the occurences:
-
-```r
+``` r
 imp = importance(model)
 print(imp)
 ```
 
-```
-##    sp       env      spatial     biotic
-## 1   1 0.8512507 3.235598e-04 0.14842576
-## 2   2 0.5535324 3.788728e-03 0.44267890
-## 3   3 0.7185561 3.539847e-03 0.27790397
-## 4   4 0.8885156 5.296470e-07 0.11148381
-## 5   5 0.4769188 2.544400e-03 0.52053678
-## 6   6 0.8595052 2.418374e-04 0.14025287
-## 7   7 0.5184419 1.667692e-03 0.47989047
-## 8   8 0.9243904 3.566132e-03 0.07204356
-## 9   9 0.7220337 6.654685e-04 0.27730072
-## 10 10 0.9641129 1.151201e-03 0.03473605
-```
-
-```r
+    ##    sp       env      spatial     biotic
+    ## 1   1 0.8613918 3.332460e-04 0.13827495
+    ## 2   2 0.5592634 4.024107e-03 0.43671250
+    ## 3   3 0.7120238 3.872615e-03 0.28410360
+    ## 4   4 0.8904814 4.630398e-08 0.10951868
+    ## 5   5 0.4853966 2.508080e-03 0.51209527
+    ## 6   6 0.8550296 2.856218e-04 0.14468490
+    ## 7   7 0.5291853 1.717124e-03 0.46909758
+    ## 8   8 0.9103805 4.177628e-03 0.08544178
+    ## 9   9 0.7522822 6.079319e-04 0.24710977
+    ## 10 10 0.9754393 1.112162e-03 0.02344848
+
+``` r
 plot(imp)
 ```
 
-![](README_files/figure-html/unnamed-chunk-7-1.png)<!-- -->
-
+![](README_files/figure-gfm/unnamed-chunk-7-1.png)<!-- -->
 
 As expected, space has no effect on occurences.
 
-Let's have a look on community level how the three groups contribute to the overall explained variance 
+Let’s have a look on community level how the three groups contribute to
+the overall explained variance
 
-```r
+``` r
 an = anova(model)
 print(an)
 ```
 
-```
-## Changes relative to empty model (without modules):
-## 
-##  Modules       LogLik            R2   marginal R2          R2ll
-##        _  693.1472015  0.000000e+00  0.000000e+00  0.0000000000
-##        A  -21.2049255  2.576520e-02  1.682891e-02  0.0305922400
-##        B  -55.2553113  9.658548e-06  4.844455e-06  0.0797165612
-##        S   -0.4988708  3.544428e-04  2.202305e-04  0.0007197185
-##      A+B  -30.3583012 -1.836237e-03 -9.200357e-03  0.0437977693
-##      A+S   -1.4909744 -5.084443e-05  8.346787e-06  0.0021510213
-##      B+S    1.2818292 -3.086277e-04 -2.047642e-04 -0.0018492886
-##    A+B+S    0.9275459  1.017823e-04  9.642144e-05 -0.0013381659
-##     Full -106.5990082  2.403537e-02  7.753627e-03  0.1537898558
-```
+    ## Analysis of Deviance Table
+    ## 
+    ## Terms added sequentially:
+    ## 
+    ##          Deviance Residual deviance R2 Nagelkerke R2 McFadden
+    ## Biotic  156.48193         515.99884       0.79087      0.1132
+    ## Abiotic 172.37183         343.62701       0.96269      0.2379
+    ## Spatial  13.97729         329.64972       0.96756      0.2480
 
-```r
+``` r
 plot(an)
 ```
 
-![](README_files/figure-html/unnamed-chunk-8-1.png)<!-- -->
-
-The anova shows the relative changes in the logLik of the groups and their intersections.
+![](README_files/figure-gfm/unnamed-chunk-8-1.png)<!-- -->
 
+The anova shows the relative changes in the deviance of the groups and
+their intersections.
 
-
-
-If it fails, check out the help of ?install_sjSDM, ?installation_help, and vignette("Dependencies", package = "sjSDM"). 
+If it fails, check out the help of ?install_sjSDM, ?installation_help,
+and vignette(“Dependencies”, package = “sjSDM”).
 
 #### Installation workflow:
-1. Try install_sjSDM()
-2. New session, if no 'PyTorch not found' appears it should work, otherwise see ?installation_help
-3. If do not get the pkg to run, create an issue [issue tracker](https://github.com/TheoreticalEcology/s-jSDM/issues) or write an email to maximilian.pichler at ur.de
 
+1.  Try install_sjSDM()
+2.  New session, if no ‘PyTorch not found’ appears it should work,
+    otherwise see ?installation_help
+3.  If do not get the pkg to run, create an issue [issue
+    tracker](https://github.com/TheoreticalEcology/s-jSDM/issues) or
+    write an email to maximilian.pichler at ur.de
 
 ### Python Package
 
-```bash
+``` bash
 pip install sjSDM_py
 ```
-Python example
 
+Python example
 
-```python
+``` python
 import sjSDM_py as fa
 import numpy as np
 import torch
@@ -333,26 +326,11 @@ model.fit(Env, Occ, batch_size = 20, epochs = 10)
 # print(model.covariance)
 ```
 
-```
-## 
-Iter: 0/10   0%|          | [00:00, ?it/s]
-Iter: 0/10   0%|          | [00:00, ?it/s, loss=7.18]
-Iter: 0/10   0%|          | [00:00, ?it/s, loss=7.178]
-Iter: 0/10   0%|          | [00:00, ?it/s, loss=7.163]
-Iter: 0/10   0%|          | [00:00, ?it/s, loss=7.183]
-Iter: 0/10   0%|          | [00:00, ?it/s, loss=7.172]
-Iter: 0/10   0%|          | [00:00, ?it/s, loss=7.175]
-Iter: 0/10   0%|          | [00:00, ?it/s, loss=7.155]
-Iter: 0/10   0%|          | [00:00, ?it/s, loss=7.137]
-Iter: 0/10   0%|          | [00:00, ?it/s, loss=7.165]
-Iter: 9/10  90%|######### | [00:00, 87.36it/s, loss=7.165]
-Iter: 9/10  90%|######### | [00:00, 87.36it/s, loss=7.141]
-Iter: 10/10 100%|##########| [00:00, 90.60it/s, loss=7.141]
-```
+    ## Iter: 0/10   0%|          | [00:00, ?it/s]Iter: 0/10   0%|          | [00:00, ?it/s, loss=7.226]Iter: 1/10  10%|#         | [00:00,  5.77it/s, loss=7.226]Iter: 1/10  10%|#         | [00:00,  5.77it/s, loss=7.237]Iter: 1/10  10%|#         | [00:00,  5.77it/s, loss=7.231]Iter: 1/10  10%|#         | [00:00,  5.77it/s, loss=7.254]Iter: 1/10  10%|#         | [00:00,  5.77it/s, loss=7.222]Iter: 1/10  10%|#         | [00:00,  5.77it/s, loss=7.213]Iter: 1/10  10%|#         | [00:00,  5.77it/s, loss=7.213]Iter: 7/10  70%|#######   | [00:00, 29.96it/s, loss=7.213]Iter: 7/10  70%|#######   | [00:00, 29.96it/s, loss=7.211]Iter: 7/10  70%|#######   | [00:00, 29.96it/s, loss=7.231]Iter: 7/10  70%|#######   | [00:00, 29.96it/s, loss=7.201]Iter: 10/10 100%|##########| [00:00, 30.39it/s, loss=7.201]
 
 Calculate Importance:
 
-```python
+``` python
 Beta = np.transpose(model.env_weights[0])
 Sigma = ( model.sigma @ model.sigma.t() + torch.diag(torch.ones([1])) ).data.cpu().numpy()
 covX = fa.covariance( torch.tensor(Env).t() ).data.cpu().numpy()
@@ -360,28 +338,25 @@ covX = fa.covariance( torch.tensor(Env).t() ).data.cpu().numpy()
 fa.importance(beta=Beta, covX=covX, sigma=Sigma)
 ```
 
-```
-## {'env': array([[ 4.1893846e-03,  5.5393800e-03,  1.3987868e-02,  5.1057325e-03,
-##          3.2040334e-04],
-##        [ 4.8073977e-03,  2.1980505e-04,  5.5616826e-04,  2.2618828e-04,
-##          1.4837000e-02],
-##        [ 9.5910449e-03, -2.6523434e-05,  8.9576719e-03,  1.4117245e-02,
-##          2.6826796e-04],
-##        [ 1.5072384e-02,  6.0981540e-03,  8.1819193e-03,  1.1266603e-03,
-##          1.3036386e-02],
-##        [ 1.2810972e-02,  4.9146665e-03,  7.0648100e-03,  6.1532706e-03,
-##         -6.2168780e-04],
-##        [ 3.5765194e-04,  1.5423226e-03,  9.0936786e-03,  1.5325662e-02,
-##          2.8687348e-03],
-##        [-2.5524709e-05,  8.9721283e-04,  1.2243549e-02,  1.3080860e-02,
-##          1.8863674e-03],
-##        [ 2.7550785e-05,  1.3295179e-03,  1.2515844e-02,  3.7936254e-03,
-##          2.0696187e-02],
-##        [ 3.4044436e-03,  2.0984237e-03,  2.9508309e-03,  2.3899646e-03,
-##          1.5562433e-03],
-##        [ 3.7611238e-04,  6.6016875e-03,  1.4190309e-04,  1.0578999e-02,
-##          5.1813303e-03]], dtype=float32), 'biotic': array([0.97085726, 0.9793535 , 0.9670923 , 0.95648456, 0.969678  ,
-##        0.97081196, 0.9719175 , 0.96163726, 0.98760015, 0.97712   ],
-##       dtype=float32)}
-```
-
+    ## {'env': array([[ 2.38658884e-03,  2.33276398e-03,  8.66574410e-05,
+    ##          3.59020615e-03,  1.17936805e-02],
+    ##        [ 1.26053428e-03,  3.90947284e-03,  1.43610043e-02,
+    ##          1.66442655e-02,  4.86387825e-03],
+    ##        [ 3.67451721e-04,  1.93770081e-02,  4.62013390e-03,
+    ##          7.03087449e-03, -2.45641364e-04],
+    ##        [ 3.78302590e-04,  7.70199997e-03,  3.79969226e-03,
+    ##          1.90878427e-03,  7.78316474e-03],
+    ##        [-3.36568119e-05,  1.48856193e-02,  8.28362827e-05,
+    ##          7.90147856e-03,  1.44283113e-03],
+    ##        [ 2.35467160e-05,  1.85834360e-03,  2.65803654e-03,
+    ##          6.93821697e-04,  1.56040723e-03],
+    ##        [ 1.20119955e-02,  4.54227789e-04,  4.49610781e-03,
+    ##          1.70819985e-04,  7.15113478e-03],
+    ##        [ 1.88462622e-02,  1.56420525e-02,  2.18130555e-03,
+    ##          7.79829780e-03,  7.54316454e-04],
+    ##        [ 1.95460692e-02,  2.35415604e-02,  1.90228559e-02,
+    ##          1.81235757e-03,  1.79336704e-02],
+    ##        [ 1.32896658e-02,  5.67754870e-03,  1.95635785e-03,
+    ##          1.09617296e-03,  4.17500007e-04]], dtype=float32), 'biotic': array([0.97981006, 0.95896083, 0.9688502 , 0.97842807, 0.9757209 ,
+    ##        0.99320585, 0.97571576, 0.9547777 , 0.91814345, 0.9775628 ],
+    ##       dtype=float32)}
diff --git a/README_files/figure-gfm/unnamed-chunk-4-1.png b/README_files/figure-gfm/unnamed-chunk-4-1.png
new file mode 100644
index 0000000..a92d5f7
Binary files /dev/null and b/README_files/figure-gfm/unnamed-chunk-4-1.png differ
diff --git a/README_files/figure-gfm/unnamed-chunk-7-1.png b/README_files/figure-gfm/unnamed-chunk-7-1.png
new file mode 100644
index 0000000..185af38
Binary files /dev/null and b/README_files/figure-gfm/unnamed-chunk-7-1.png differ
diff --git a/README_files/figure-gfm/unnamed-chunk-8-1.png b/README_files/figure-gfm/unnamed-chunk-8-1.png
new file mode 100644
index 0000000..02f2b5a
Binary files /dev/null and b/README_files/figure-gfm/unnamed-chunk-8-1.png differ
diff --git a/README_files/figure-html/unnamed-chunk-3-1.png b/README_files/figure-html/unnamed-chunk-3-1.png
deleted file mode 100644
index 9ae5744..0000000
Binary files a/README_files/figure-html/unnamed-chunk-3-1.png and /dev/null differ
diff --git a/README_files/figure-html/unnamed-chunk-4-1.png b/README_files/figure-html/unnamed-chunk-4-1.png
deleted file mode 100644
index e9905a4..0000000
Binary files a/README_files/figure-html/unnamed-chunk-4-1.png and /dev/null differ
diff --git a/README_files/figure-html/unnamed-chunk-5-1.png b/README_files/figure-html/unnamed-chunk-5-1.png
deleted file mode 100644
index 8216a91..0000000
Binary files a/README_files/figure-html/unnamed-chunk-5-1.png and /dev/null differ
diff --git a/README_files/figure-html/unnamed-chunk-6-1.png b/README_files/figure-html/unnamed-chunk-6-1.png
deleted file mode 100644
index d1cc4df..0000000
Binary files a/README_files/figure-html/unnamed-chunk-6-1.png and /dev/null differ
diff --git a/README_files/figure-html/unnamed-chunk-7-1.png b/README_files/figure-html/unnamed-chunk-7-1.png
deleted file mode 100644
index 917bbca..0000000
Binary files a/README_files/figure-html/unnamed-chunk-7-1.png and /dev/null differ
diff --git a/README_files/figure-html/unnamed-chunk-8-1.png b/README_files/figure-html/unnamed-chunk-8-1.png
deleted file mode 100644
index 878cfea..0000000
Binary files a/README_files/figure-html/unnamed-chunk-8-1.png and /dev/null differ
diff --git a/README_files/figure-markdown_strict/unnamed-chunk-4-1.png b/README_files/figure-markdown_strict/unnamed-chunk-4-1.png
deleted file mode 100644
index e2f4bf1..0000000
Binary files a/README_files/figure-markdown_strict/unnamed-chunk-4-1.png and /dev/null differ
diff --git a/README_files/figure-markdown_strict/unnamed-chunk-5-1.png b/README_files/figure-markdown_strict/unnamed-chunk-5-1.png
deleted file mode 100644
index 31ccb15..0000000
Binary files a/README_files/figure-markdown_strict/unnamed-chunk-5-1.png and /dev/null differ
diff --git a/_environment.yml b/_environment.yml
new file mode 100644
index 0000000..099ca15
--- /dev/null
+++ b/_environment.yml
@@ -0,0 +1,14 @@
+name: r-sjsdm
+channels:
+  - anaconda
+  - conda-forge
+  - defaults
+  - pytorch
+dependencies:
+  - pip
+  - pip:
+    - pyro-ppl
+    - madgrad
+    - torch_optimizer
+    - torch
+    - pytest
\ No newline at end of file
diff --git a/sjSDM/.Rbuildignore b/sjSDM/.Rbuildignore
index 66c48e1..bffcfe4 100644
--- a/sjSDM/.Rbuildignore
+++ b/sjSDM/.Rbuildignore
@@ -1,11 +1,13 @@
-^.*\.Rproj$
-^\.Rproj\.user$
-^LICENSE\.md$
-^.travis\.yml$
-inst/python/.pytest_cache
-inst/.pytest_cache
-inst/python/.vscode
-inst/python/.eggs
-^doc$
-^Meta$
-CRAN.md
\ No newline at end of file
+^.*\.Rproj$
+^\.Rproj\.user$
+^LICENSE\.md$
+^.travis\.yml$
+inst/python/.pytest_cache
+inst/.pytest_cache
+inst/python/.vscode
+inst/python/.eggs
+inst/python/build
+^doc$
+^Meta$
+^cran-comments\.md$
+^README\.Rmd$
\ No newline at end of file
diff --git a/sjSDM/CRAN.md b/sjSDM/CRAN.md
deleted file mode 100644
index c1e5bf1..0000000
--- a/sjSDM/CRAN.md
+++ /dev/null
@@ -1,15 +0,0 @@
-This file contains CRAN submission info / communication
-
-## Version 0.1.0
-
-### Submission 1
-
-This is a new submission. 
-
-The R package 'sjSDM' contains a scalable method to estimates joint Species Distribution Models (jSDMs) based on the multivariate probit model through Monte-Carlo approximation of the joint likelihood. The numerical approximation is based on PyTorch and reticulate, and can be calculated on CPUs and GPUs alike.
-
-### Tested without problems under
-
-* MacOS
-* ubuntu 16.04
-* windows (latest)
\ No newline at end of file
diff --git a/sjSDM/DESCRIPTION b/sjSDM/DESCRIPTION
index acdeb37..341338d 100644
--- a/sjSDM/DESCRIPTION
+++ b/sjSDM/DESCRIPTION
@@ -1,18 +1,29 @@
 Package: sjSDM
 Type: Package
 Title: Scalable Joint Species Distribution Modeling
-Version: 0.1.8
-Date: 2021-07-03
-Authors@R: c(person("Maximilian", "Pichler", email = "maximilian.pichler@biologie.uni-regensburg.de", role = c("aut", "cre")),
-             person("Florian", "Hartig", email = "florian.hartig@biologie.uni-regensburg.de", role = c("aut"), comment=c(ORCID="0000-0002-6255-9059")),
-             person("Wang", "Cai", email = "caiwang0503@163.com", role = c("ctb")))
-Description: A scalable method to estimates joint Species Distribution Models (jSDMs) based on 
-    the multivariate probit model through Monte-Carlo approximation of the joint likelihood. 
-    The numerical approximation is based on PyTorch and reticulate, and can be calculated
-    on CPUs and GPUs alike. 
+Version: 1.0.0
+Date: 2022-01-05
+Authors@R: 
+    c(person(given = "Maximilian",
+             family = "Pichler",
+             role = c("aut", "cre"),
+             email = "maximilian.pichler@biologie.uni-regensburg.de",
+             comment = c(ORCID = "0000-0003-2252-8327")),
+      person(given = "Florian",
+             family = "Hartig",
+             role = "aut",
+             email = "florian.hartig@biologie.uni-regensburg.de",
+             comment = c(ORCID = "0000-0002-6255-9059")),
+      person(given = "Wang",
+             family = "Cai",
+             role = "ctb",
+             email = "caiwang0503@163.com"))
+Description: A scalable method to estimate joint Species Distribution Models (jSDMs) for big community datasets based on a Monte Carlo approximation of the joint likelihood.  The numerical approximation is based on 'PyTorch' and 'reticulate', and can be run on CPUs and GPUs alike. The method is described in Pichler & Hartig (2021) <doi:10.1111/2041-210X.13687>. The package contains various extensions, including support for different response families, ability to account for spatial autocorrelation, and deep neural networks instead of the linear predictor in jSDMs.
 License: GPL-3
 Encoding: UTF-8
 LazyData: true
+Depends:
+    R (>= 3.0)
 Imports:
     reticulate,
     stats,
@@ -24,23 +35,20 @@ Imports:
     grDevices,
     Metrics,
     parallel,
-    scales,
     mgcv,
     Ternary,
     cli,
     crayon,
-    tidyr,
-    dplyr,
-    magrittr,
     ggplot2,
-    RColorBrewer,
-    checkmate
+    checkmate,
+    mathjaxr
 Suggests:
     testthat,
     knitr,
     rmarkdown
-RoxygenNote: 7.1.1
+RoxygenNote: 7.1.2
 URL: https://theoreticalecology.github.io/s-jSDM/
 BugReports: https://github.com/TheoreticalEcology/s-jSDM/issues
-Roxygen: list(old_usage = TRUE)
+Roxygen: list(old_usage = FALSE)
 VignetteBuilder: knitr
+RdMacros: mathjaxr
diff --git a/sjSDM/NAMESPACE b/sjSDM/NAMESPACE
index 1d290a9..4204086 100644
--- a/sjSDM/NAMESPACE
+++ b/sjSDM/NAMESPACE
@@ -1,62 +1,42 @@
 # Generated by roxygen2: do not edit by hand
 
-S3method("*",torch.Tensor)
-S3method("+",torch.Tensor)
-S3method("-",torch.Tensor)
-S3method("/",torch.Tensor)
-S3method("^",torch.Tensor)
 S3method(anova,sjSDM)
-S3method(coef,sLVM)
 S3method(coef,sjSDM)
-S3method(dim,torch.Tensor)
-S3method(exp,torch.Tensor)
-S3method(getCov,sLVM)
 S3method(getCov,sjSDM)
 S3method(getWeights,sjSDM)
-S3method(logLik,sLVM)
 S3method(logLik,sjSDM)
-S3method(mean,torch.Tensor)
-S3method(plot,sLVM)
 S3method(plot,sjSDM)
 S3method(plot,sjSDM_cv)
 S3method(plot,sjSDManova)
-S3method(plot,sjSDManovaIndividual)
 S3method(plot,sjSDMimportance)
-S3method(predict,sLVM)
 S3method(predict,sjSDM)
 S3method(print,DNN)
 S3method(print,bioticStruct)
 S3method(print,linear)
-S3method(print,sLVM)
 S3method(print,sjSDM)
 S3method(print,sjSDM_cv)
 S3method(print,sjSDManova)
-S3method(print,sjSDManovaIndividual)
 S3method(print,sjSDMimportance)
 S3method(print,spatialRE)
 S3method(setWeights,sjSDM)
 S3method(simulate,sjSDM)
-S3method(sqrt,torch.Tensor)
-S3method(summary,sLVM)
 S3method(summary,sjSDM)
 S3method(summary,sjSDM_cv)
+S3method(update,sjSDM)
 export(AccSGD)
 export(AdaBound)
 export(Adamax)
 export(DNN)
 export(RMSprop)
 export(Rsquared)
-export(Rsquared2)
 export(SGD)
 export(add_legend)
 export(add_species_arrows)
 export(bioticStruct)
 export(curve_text)
+export(fa)
 export(generateSpatialEV)
-export(getCI)
 export(getCov)
-export(getLF)
-export(getLV)
 export(getSe)
 export(getWeights)
 export(importance)
@@ -67,18 +47,17 @@ export(linear)
 export(madgrad)
 export(plotAssociations)
 export(plotsjSDMcoef)
-export(sLVM)
 export(setWeights)
 export(simulate_SDM)
 export(sjSDM)
+export(sjSDM.tune)
 export(sjSDMControl)
 export(sjSDM_cv)
 export(spatialRE)
+export(torch)
 import(checkmate)
-import(dplyr)
 import(ggplot2)
 import(graphics)
-import(tidyr)
-import(utils)
-importFrom(magrittr,`%>%`)
+import(mathjaxr)
+import(stats)
 importFrom(stats,simulate)
diff --git a/sjSDM/NEWS.md b/sjSDM/NEWS.md
new file mode 100644
index 0000000..8046acf
--- /dev/null
+++ b/sjSDM/NEWS.md
@@ -0,0 +1,19 @@
+# sjSDM 1.0.0
+
+## Major changes
+
+* revised anova: `sjSDM::anova(...)` corresponds now to a type I anova (removed CV) #76
+* `sjSDM::Rsquared()` uses now Nagelkerke or McFadden R-squared (which is also used in the anova) #76
+* deprecated `sjSDM::sLVM` because of instability issues and other reasons
+* revised `sjSDM::install_sjSDM()`, it works now for all x64 systems/versions #81 #79 #71
+
+## Minor changes
+
+* removed several unnecessary dependencies (e.g. dplyr)
+* improved documentation of all functions, e.g. see `?sjSDM`
+* new `sjSDM::update.sjSDM` method to re-fit model with different formula(s)
+* new `sjSDM::sjSDM.tune` method to fit quickly a model with optimized regularization parameters (from `sjSDM::sjSDM_cv`)
+
+## Bug fixes
+
+* revised memory problem in `sjSDM::sjSDM_cv()` #84
\ No newline at end of file
diff --git a/sjSDM/R/Rsquared.R b/sjSDM/R/Rsquared.R
index f2a1b22..a0c97c5 100644
--- a/sjSDM/R/Rsquared.R
+++ b/sjSDM/R/Rsquared.R
@@ -1,104 +1,51 @@
-#' Rsquared2
-#' 
-#' claculate Rsquared following Nakagawa 
-#' @param model model
-#' @param X new environmental covariates
-#' @param Y new species occurences
-#' @param SP new spatial covariates
-#' @param individual R squared for each site
-#' @param ... additional parameters
-#' 
-#' @author Maximilian Pichler
-#' @export
-Rsquared2 = function(model, X = NULL, Y = NULL, SP = NULL,individual=TRUE,...) {
-  
-  if(model$family$link == "probit") varDist = 1
-  else varDist = pi^2/3
-  
-  sigma = model$model$get_sigma
-  df = model$settings$biotic$df
-  #model$model$set_sigma(copyRP(matrix(0.0, nrow(sigma), ncol(sigma))))
-  preds = apply(abind::abind(lapply(1:50, function(i) predict.sjSDM(model, link ="raw") ), along = -1L), 2:3, mean)#,newdata = X,SP=SP, link ="raw"))
-  #model$model$set_sigma(copyRP(sigma))
-  if(!individual) vv = stats::var(as.vector(preds))
-  else vv = apply(preds,1,stats::var)
-  Assocation = getCov(model)
-  
-  re = sum(diag(diag(1, nrow(Assocation), ncol(Assocation)) %*% Assocation))/(ncol(Assocation))
-  return(list(
-    marginal = vv/(vv+  re +varDist),
-    conditional = (vv + re)/(vv+  re +varDist)
-  ))
-}
-
-
-
-
-#' Rsquared
-#' 
-#' claculate Rsquared following Nakagawa 
-#' @param model model
-#' @param X new environmental covariates
-#' @param Y new species occurences
-#' @param SP new spatial covariates
-#' @param adjust adjust R squared or not
-#' @param averageSP average R squared over species
-#' @param averageSite average R squared over sites
-#' 
-#' @author Maximilian Pichler
-#' @export
-
-Rsquared = function(model, X = NULL, Y = NULL, SP=NULL, adjust=FALSE, averageSP = TRUE, averageSite=TRUE){
-  
-  if(!is.null(model$spatial_weights)) sp = TRUE
-  else sp = FALSE
-  
-  if(is.null(X)){
-    X = model$data$X
-    if(sp) SP = model$settings$spatial$X
-    Y = model$data$Y
-  } 
-
-  nsite = nrow(Y)
-  nsp = ncol(Y)
-  preds = lapply(1:100, function(i) predict.sjSDM(model, link ="raw"))#,newdata = X,SP=SP, link ="raw"))
-  Ypred = apply(abind::abind(preds, along = 0L), 2:3, mean)
-  link = model$family$family
-  if(model$family$link == "probit") varDist = 1
-  else varDist = pi^2/3
-  
-  #if(sp) Xvar = c(Xvar, SPvar)
-  
-  YMeans = matrix(colMeans(Ypred), nrow = nsite, ncol = nsp, byrow = TRUE)
-  varModelSite = (Ypred - YMeans)^2/(nsite - 1)
-  varModel = colSums(varModelSite)
-  varAdd = diag(stats::var(Y - link$linkinv(Ypred)))
-  varTot = matrix(varModel + varAdd + varDist, nrow = nsite, ncol = nsp, byrow = TRUE)#+ colSums(getCov(model)^2)
-  R2 = (varModelSite)/varTot
-  if(averageSite) {
-    R2 = colSums(varModelSite)/varTot[1, ]
-    if(averageSP) R2 = mean(R2)
-  }
-  else {
-    if(averageSP) R2 = rowMeans(R2)
-  }
-  if (adjust) {
-    nexp = ncol(X)
-    if(sp) nexp=nexp+ncol(SP)
-    if (!averageSite) {
-      if(!averageSP) R2Cum = colSums(R2)
-      else R2Cum = R2
-      R2CumAdj = 1 - ((nsite - 3)/(nsite - nexp - 2)) * (1 - R2Cum)
-      Corr = R2Cum - R2CumAdj
-      R2 = R2 - Corr/nsite
-    }
-    else {
-      R2 = 1 - ((nsite - 3)/(nsite - nexp - 2)) * (1 - R2)
-    }
-  }
-  return(R2)
-}
-
-
-
+#' R-squared
+#' 
+#' calculate R-squared following Nagelkerke or McFadden
+#' @param model model
+#' @param method Nagelkerke or McFadden
+#' 
+#' @details
+#' \loadmathjax 
+#' 
+#' Calculate R-squared following Nagelkerke or McFadden:
+#' 
+#' \itemize{
+#' \item Nagelkerke: \mjeqn{R^2 = 1 - \exp(2/N \cdot (log\mathcal{L}_0 - log\mathcal{L}_1 ) )}{}
+#' \item McFadden: \mjeqn{R^2 = 1 - log\mathcal{L}_1 / log\mathcal{L}_0  }{}
+#'} 
+#'
+#' @return 
+#' 
+#' R-squared as numeric value
+#' 
+#' @author Maximilian Pichler
+#' @import stats
+#' @export
+
+Rsquared = function(model, method = c("Nagelkerke", "McFadden")) {
+  
+  method = match.arg(method)
+  
+  if(is.null(model$Null)) {
+    if(inherits(model, "spatial")) {
+      spatial_formula=stats::as.formula(~0)
+    } else {
+      spatial_formula=NULL
+    }
+    model$Null = update(model, env_formula=~1, spatial_formula=spatial_formula)
+  }
+  N0 = -logLik(model$Null)[[1]]
+  N1 = -logLik(model)[[1]]
+  
+  if(method == "McFadden") {
+    R2 = 1 - (N1/N0)
+  } else {
+    R2 = 1-exp(2/(nrow(model$data$Y))*(-N1+N0))
+  }
+  print(R2)
+  return(invisible(R2))
+}
+
+
+
  
\ No newline at end of file
diff --git a/sjSDM/R/anova.R b/sjSDM/R/anova.R
index 743d409..750d735 100644
--- a/sjSDM/R/anova.R
+++ b/sjSDM/R/anova.R
@@ -1,376 +1,176 @@
-#' Anova
-#' 
-#' Compute analysis of variance via cross-validation for environmental, associations, and spatial effects 
-#' 
-#' @param object model of object \code{\link{sjSDM}}
-#' @param cv number of cross-validation splits
-#' @param individual compute analysis of variance on species and site level
-#' @param sampling number of sampling steps for Monte Carlo integreation
-#' @param ... optional arguments for compatibility with the generic function, no function implemented
-#'  
-#' @seealso \code{\link{plot.sjSDManova}}, \code{\link{print.sjSDManova}}
-#' @export
-
-anova.sjSDM = function(object, cv = 5L,individual=FALSE, sampling = 5000L, ...) {
-  
-  if(is.logical(cv)) cv = 0
-  
-  if(cv > 0) splits = createSplit(nrow(object$settings$env$X), cv)
-  else splits = list(NULL)
-  
-  out = list()
-  
-  
-  if(!individual) {
-  
-    fit_and_form = function(mod) {
-      .tmp = sapply(splits, function(sp) turnOn(object, modules = mod, test = sp, individual = individual, sampling = sampling))
-      return(list(ll = sum(unlist(.tmp[1,])), R = mean(unlist(.tmp[2,])),R2 = mean(unlist(.tmp[3,])) ))
-    }
-  
-  } else {
-    
-    fit_and_form = function(mod) {
-      .tmp = lapply(splits, function(sp) turnOn(object, modules = mod, test = sp, individual = individual, sampling = sampling))
-      return(list(ll = unlist(lapply(.tmp, function(l) l$ll)), 
-                  R =  unlist(lapply(.tmp, function(l) l$R)),
-                  R2 = unlist(lapply(.tmp, function(l) l$R2)) ))
-    }
-    
-  }
-  
-  if(!is.null(object$spatial_weights)){
-    modules = list("", "ABS", "A", "B", "S", "AB", "AS", "BS")
-    results = lapply(modules, function(m) fit_and_form(m))
-    names(results) = c("empty", "full","A", "B", "S", "AB", "AS", "BS")
-    
-    if(!individual) {
-    
-      res = data.frame(matrix(NA, 9,5))
-      colnames(res) = c("Modules", "LogLik","R2", "marginal R2", "condtional R2")    
-      res$Modules = c("_", "A", "B", "S", "A+B", "A+S", "B+S", "A+B+S", "Full")
-      res[1,2:4] = unlist(results$empty)
-      
-      res[2,2] = -results$empty$ll + results$A$ll # A
-      res[3,2] = -results$empty$ll + results$B$ll # B
-      res[4,2] = -results$empty$ll + results$S$ll # S
-      res[5,2] = -results$empty$ll + results$AB$ll - (res[2,2] + res[3,2] )# A+B
-      res[6,2] = -results$empty$ll + results$AS$ll - (res[2,2] + res[4,2] )# A+S
-      res[7,2] = -results$empty$ll + results$BS$ll - (res[4,2] + res[3,2] )# B+S
-      res[8,2] = -results$empty$ll + results$full$ll - sum(res[2:7,2]) # A+B+S
-      res[9,2] = -results$empty$ll + results$full$ll # Full
-      res[2,3] = results$empty$R + results$A$R
-      res[3,3] = results$empty$R + results$B$R
-      res[4,3] = results$empty$R + results$S$R
-      res[5,3] = results$empty$R + results$AB$R - res[2,3] - res[3,3]
-      res[6,3] = results$empty$R + results$AS$R - res[2,3] - res[4,3]
-      res[7,3] = results$empty$R + results$BS$R - res[4,3] - res[3,3]
-      res[8,3] = results$empty$R + results$full$R - sum(res[2:7,3])
-      res[9,3] = results$empty$R + results$full$R
-      res[2,4] = results$empty$R2 + results$A$R2
-      res[3,4] = results$empty$R2 + results$B$R2
-      res[4,4] = results$empty$R2 + results$S$R2
-      res[5,4] = results$empty$R2 + results$AB$R2 - res[2,4] - res[3,4]
-      res[6,4] = results$empty$R2 + results$AS$R2 - res[2,4] - res[4,4]
-      res[7,4] = results$empty$R2 + results$BS$R2 - res[4,4] - res[3,4]
-      res[8,4] = results$empty$R2 + results$full$R2 - sum(res[2:7,4])
-      res[9,4] = results$empty$R2 + results$full$R2
-      res$R2ll = res$LogLik
-      res$R2ll[-1] = res$LogLik[-1] + res$LogLik[1]
-      res$R2ll = 1 - (res$R2ll / res$R2ll[1])
-      out$spatial = TRUE
-    } else {
-      
-      res = array(NA, dim = c(nrow(object$data$Y),9,5))
-      #colnames(res) = c("Modules", "LogLik", "R2", "marginal R2", "condtional R2")    
-      #res$Modules = c("_", "A", "B", "S", "A+B", "A+S", "B+S", "A+B+S", "Full")
-      res[,1,1:3] = do.call(cbind, results$empty)
-      
-      res[,2,1] = -results$empty$ll + results$A$ll # A
-      res[,3,1] = -results$empty$ll + results$B$ll # B
-      res[,4,1] = -results$empty$ll + results$S$ll # S
-      res[,5,1] = -results$empty$ll + results$AB$ll - (res[,2,1] + res[,3,1] )# A+B
-      res[,6,1] = -results$empty$ll + results$AS$ll - (res[,2,1] + res[,4,1] )# A+S
-      res[,7,1] = -results$empty$ll + results$BS$ll - (res[,4,1] + res[,3,1] )# B+S
-      res[,8,1] = -results$empty$ll + results$full$ll - sum(res[,2:7,1]) # A+B+S
-      res[,9,1] = -results$empty$ll + results$full$ll # Full
-      res[,2,2] = results$empty$R + results$A$R
-      res[,3,2] = results$empty$R + results$B$R
-      res[,4,2] = results$empty$R + results$S$R
-      res[,5,2] = results$empty$R + results$AB$R - res[,2,2] - res[,3,2]
-      res[,6,2] = results$empty$R + results$AS$R - res[,2,2] - res[,4,2]
-      res[,7,2] = results$empty$R + results$BS$R - res[,4,2] - res[,3,2]
-      res[,8,2] = results$empty$R + results$full$R - sum(res[,2:7,2])
-      res[,9,2] = results$empty$R + results$full$R
-      res[,2,3] = results$empty$R2 + results$A$R2
-      res[,3,3] = results$empty$R2 + results$B$R2
-      res[,4,3] = results$empty$R2 + results$S$R2
-      res[,5,3] = results$empty$R2 + results$AB$R2 - res[,2,3] - res[,3,3]
-      res[,6,3] = results$empty$R2 + results$AS$R2 - res[,2,3] - res[,4,3]
-      res[,7,3] = results$empty$R2 + results$BS$R2 - res[,4,3] - res[,3,3]
-      res[,8,3] = results$empty$R2 + results$full$R2 - sum(res[,2:7,3])
-      res[,9,3] = results$empty$R2 + results$full$R2
-      res[,,5] = res[,,1]
-      res[,-1,5] = res[,-1,5] + res[,1,5]
-      res[,,5] = 1 - (res[,,5] / res[,1,5])
-      
-    }
-    
-  } else {
-    modules = list("","A", "B", "AB")
-    results = lapply(modules, function(m) fit_and_form(m))
-    names(results) = c("empty", "A", "B", "AB")
-    
-    if(!individual) {
-      res = data.frame(matrix(NA, 5,5))
-      colnames(res) = c("Modules", "LogLik", "R2", "marginal R2", "condtional R2")    
-      res$Modules = c("_", "A", "B", "A+B", "Full")
-      res[1,2:4] = unlist(results$empty)
-      res[2,2] = -results$empty$ll + results$A$ll # A
-      res[3,2] = -results$empty$ll + results$B$ll # B
-      res[4,2] = -results$empty$ll + results$AB$ll - (res[2,2] + res[3,2] )# A+B
-      res[5,2] = -results$empty$ll + results$AB$ll  # Full
-      res[2,3] = results$empty$R + results$A$R
-      res[3,3] = results$empty$R + results$B$R
-      res[4,3] = results$empty$R + results$AB$R - res[2,3] - res[3,3]
-      res[5,3] = results$empty$R + results$AB$R
-      res[2,4] = results$empty$R2 +results$A$R2
-      res[3,4] = results$empty$R2 +results$B$R2
-      res[4,4] = results$empty$R2 +results$AB$R2 - res[2,4] - res[3,4]
-      res[5,4] = results$empty$R2 +results$AB$R2
-      res$R2ll = res$LogLik
-      res$R2ll[-1] = res$LogLik[-1] + res$LogLik[1]
-      res$R2ll = 1 - (res$R2ll / res$R2ll[1])
-      out$spatial = FALSE
-    } else {
-      
-      res = array(NA, dim = c(nrow(object$data$Y),5,5))
-      #colnames(res) = c("Modules", "LogLik", "R2", "marginal R2", "condtional R2")    
-      #res$Modules = c("_", "A", "B", "S", "A+B", "A+S", "B+S", "A+B+S", "Full")
-      res[,1,1:3] = do.call(cbind, results$empty)
-      
-      res[,2,2-1] = -results$empty$ll + results$A$ll # A
-      res[,3,2-1] = -results$empty$ll + results$B$ll # B
-      res[,4,2-1] = -results$empty$ll + results$AB$ll - (res[,2,1] + res[,3,1] )# A+B
-      res[,5,2-1] = -results$empty$ll + results$AB$ll  # Full
-      res[,2,3-1] = results$empty$R + results$A$R
-      res[,3,3-1] = results$empty$R + results$B$R
-      res[,4,3-1] = results$empty$R + results$AB$R - res[,2,2] - res[,3,2]
-      res[,5,3-1] = results$empty$R + results$AB$R
-      res[,2,4-1] = results$empty$R2 +results$A$R2
-      res[,3,4-1] = results$empty$R2 +results$B$R2
-      res[,4,4-1] = results$empty$R2 +results$AB$R2 - res[,2,3] - res[,3,3]
-      res[,5,4-1] = results$empty$R2 +results$AB$R2
-      
-      res[,,5] = res[,,1]
-      res[,-1,5] = res[,-1,5] + res[,1,5]
-      res[,,5] = 1 - (res[,,5] / res[,1,5])
-      out$spatial = FALSE
-    }
-  }
-  if(!individual) out$result = res[,-5]
-  else out$result = res
-  
-  if(!individual) class(out) = c("sjSDManova")
-  else class(out) = c("sjSDManovaIndividual")
-  return(out)
-}
-
-#' Print sjSDM anova
-#' 
-#' @param x an object of \code{\link{anova.sjSDM}}
-#' @param ... optional arguments for compatibility with the generic function, no function implemented
-#' @export
-print.sjSDManova = function(x, ...) {
-  cat("Changes relative to empty model (without modules):\n\n")
-  print(x$result,row.names = FALSE)
-}
-
-
-#' Print sjSDM anova
-#' 
-#' @param x an object of \code{\link{anova.sjSDM}}
-#' @param ... optional arguments for compatibility with the generic function, no function implemented
-#' @export
-print.sjSDManovaIndividual = function(x, ...) {
-  cat("Site specific changes relative to empty model (without modules), see plot(x)")
-}
-
-
-#' Plot anova
-#' 
-#' @param x anova object from \code{\link{anova.sjSDM}}
-#' @param y unused argument
-#' @param perf performance measurement to plot
-#' @param cols colors for the groups
-#' @param alpha alpha for colors
-#' @param percent use relative instead of absolute values (currently not supported)
-#' @param ... Additional arguments to pass to \code{plot()}
-#' @export
-plot.sjSDManova = function(x, y, perf = c("LogLik", "R2"),cols = c("#7FC97F","#BEAED4","#FDC086"),alpha=0.15,percent=TRUE, ...) {
-  lineSeq = 0.3
-  nseg = 100
-  dr = 1.0
-  perf = match.arg(perf)
-  
-  #if(percent) x$result[,-1] = x$result[,-1] / do.call(rbind, rep(list(x$result[nrow(x$result),-1]), nrow(x$result)))
-  #if(percent)
-  if(perf == "LogLik") perf = "R2ll"
-  graphics::plot(NULL, NULL, xlim = c(0,1), ylim =c(0,1),pty="s", axes = FALSE, xlab = "", ylab = "")
-  xx = 1.1*lineSeq*cos( seq(0,2*pi, length.out=nseg))
-  yy = 1.1*lineSeq*sin( seq(0,2*pi, length.out=nseg))
-  graphics::polygon(xx+lineSeq,yy+(1-lineSeq), col= addA(cols[1],alpha = alpha), border = "black", lty = 1, lwd = 1)
-  graphics::text(lineSeq-0.1, (1-lineSeq),labels = round(x$result[[perf]][x$result$Modules=="A"], 3))
-  graphics::text(mean(xx+lineSeq), 0.9,labels = "Environmental", pos = 3)
-  
-  graphics::polygon(xx+1-lineSeq,yy+1-lineSeq, col= addA(cols[2],alpha = alpha), border = "black", lty = 1, lwd = 1)
-  graphics::text(1-lineSeq+0.1, (1-lineSeq),labels = round(x$result[[perf]][x$result$Modules=="B"], 3))
-  graphics::text(1-mean(xx+lineSeq), 0.9,labels = "Associations", pos = 3)
-  graphics::text(0.5, (1-lineSeq),labels = round(x$result[[perf]][x$result$Modules=="A+B"], 3))
-  
-  if(x$spatial) {
-    graphics::polygon(xx+0.5,yy+lineSeq, col= addA(cols[3],alpha = alpha), border = "black", lty = 1, lwd = 1)
-    graphics::text(0.5, lineSeq+0.0,pos = 1,labels = round(x$result[[perf]][x$result$Modules=="S"], 3))
-    graphics::text(0.5, 0.1,labels = "Spatial", pos = 1)
-    graphics::text(0.5, (1-lineSeq),labels = round(x$result[[perf]][x$result$Modules=="A+B"], 3))
-    graphics::text(0.3, 0.5,pos=1,labels = round(x$result[[perf]][x$result$Modules=="A+S"], 3))
-    graphics::text(1-0.3, 0.5,pos=1,labels = round(x$result[[perf]][x$result$Modules=="B+S"], 3))
-    graphics::text(0.5, 0.5+0.05,labels = round(x$result[[perf]][x$result$Modules=="A+B+S"], 3))
-  }
-}
-
-#' Plot anova
-#' 
-#' @param x anova object from \code{\link{anova.sjSDM}}
-#' @param y unused argument
-#' @param contour plot contour or not
-#' @param col.points point color
-#' @param cex.points point size
-#' @param pch point symbol
-#' @param ... Additional arguments to pass to \code{plot()}
-#' @export
-plot.sjSDManovaIndividual= function(x, y,contour=FALSE,col.points="#24526e",cex.points=1.2,pch=19, ...) {
-  
-  print("not yet supported")
-  # if(dim(an$result)[2] > 5 ) {
-  #   
-  #   #tt = x$result[,9,]
-  #   #attributes(tt) = list(dim = c(dim(x$result)[1], 1, 4))
-  #   
-  #   
-  #   
-  #   #x$result = x$result / abind::abind(rep(list(tt), 9), along = 2L)
-  #   data = x$result[,2:4,1] /apply(x$result[,9,],2,sum)[1]
-  #   Ternary::TernaryPlot(grid.lines = 2, 
-  #                        axis.labels = c(round(min(data), 3), "", round(max(data), 3)), 
-  #                        alab = 'Environmental', blab = 'Spatial', clab = 'Biotic',
-  #                        grid.col = "grey")
-  #   data = scales::rescale(data)
-  #   
-  #   Ternary::TernaryPoints(data,  col = col.points, pch = pch, cex=cex.points)
-  # } else {
-  #   graphics::barplot(t(data[,2:3]), las = 2, names.arg=data$sp)
-  # }
-  # return(invisible(data))
-  
-}
-
-
-turnOn = function(model, modules = c("AB"), test= NULL,individual=FALSE, sampling = 1000L, ...) {
-  modules = strsplit(modules,split = "")[[1]]
-  
-  env = model$settings$env
-  spatial = model$settings$spatial
-  
-  if(!is.null(test)) {
-    env$X = env$X[-test,,drop=FALSE]
-    if(!is.null(spatial)) {
-      spatial$X = spatial$X[-test,,drop=FALSE]
-    }
-    Y = model$data$Y[-test,,drop=FALSE]
-  } else {
-    Y = model$data$Y
-  }
-  env2 = env
-  
-  
-  # if(length(modules) == 0) env2$X = cbind(env2$X[,1,drop=FALSE], matrix(0.0, nrow(env2$X),ncol(env2$X)-1L ))
-  # else 
-  env2$X =  matrix(0.0, nrow(env2$X),ncol(env2$X))
-  
-  biotic2 = bioticStruct(diag = TRUE)
-  spatial2 = spatial
-  if(!is.null(spatial2)) {
-    spatial2$X = matrix(0.0, nrow(spatial2$X),ncol(spatial2$X))
-    if(!is.null(test)) test_sp = matrix(0.0, nrow(model$settings$spatial$X[test,,drop=FALSE]),ncol(spatial2$X))
-  }
-  if(!is.null(test)) {
-    # if(length(modules) == 0) test_env = cbind(matrix(1.0,  nrow(model$settings$env$X[test,,drop=FALSE]),1), 
-    #                                           matrix(0.0, nrow(model$settings$env$X[test,,drop=FALSE]),ncol(env2$X)-1))
-    test_env = matrix(0.0, nrow(model$settings$env$X[test,,drop=FALSE]),ncol(env2$X))
-    #test_env = matrix(0.0, nrow(model$settings$env$X[test,,drop=FALSE]),ncol(env2$X))
-    
-  }
-  
-
-  for(i in modules){
-    if(i == "A") {
-      env2 = env
-      if(!is.null(test)) test_env = model$settings$env$X[test,,drop=FALSE]
-    }
-    if(i == "B") biotic2 = model$settings$biotic
-    if(i == "S") {
-      spatial2 = spatial
-      if(!is.null(test)) test_sp = model$settings$spatial$X[test,,drop=FALSE]
-    }
-  }
-  
-  m2 = sjSDM(Y = Y, 
-             env = env2, 
-             biotic = biotic2,
-             spatial= spatial2,
-             iter = model$settings$iter, 
-             step_size = model$settings$step_size, 
-             family = model$family$family, 
-             learning_rate = model$settings$learning_rate,
-             device = model$settings$device,
-             sampling= sampling
-  )
-  
-  if(!individual) mean_func = function(f) mean(sapply(1:50, function(i) f() ))
-  else mean_func = function(f) apply(do.call(cbind, lapply(1:50, function(i) f() ) ), 1, mean)
-    
-  if(is.null(test)) {
-    if(is.null(spatial)) {
-      return(list(ll = mean_func( function() m2$model$logLik(X=m2$data$X,Y=m2$data$Y,individual=individual, sampling= sampling)[[1]] ),  
-                  R=Rsquared(model=m2,averageSite=!individual,...),
-                  R2 = Rsquared2(model=m2,individual=individual,...)$marginal ))
-    } else {
-      return(list(ll = mean_func( function() m2$model$logLik(X=m2$data$X,Y=m2$data$Y, SP=m2$settings$spatial$X,individual=individual, sampling = sampling )[[1]] ),  
-                  R=Rsquared(model=m2,averageSite=!individual,...),
-                  R2 = Rsquared2(model=m2,individual=individual,...)$marginal ))
-    }
-  } else {
-    
-    m2$data$X = test_env 
-    m2$data$Y = model$data$Y[test,,drop=FALSE]
-    
-    if(!is.null(spatial)) {
-      
-      m2$spatial$X = test_sp
-      
-      return(list(ll= mean_func( function() m2$model$logLik(X=test_env,Y=model$data$Y[test,,drop=FALSE], SP=test_sp,individual=individual, sampling = sampling )[[1]] ), 
-                  R=Rsquared(model=m2,averageSite=!individual,...), 
-                  R2 = Rsquared2(model=m2,individual=individual,...)$marginal ))
-    } else {
-
-      return(list(ll= mean_func( function() m2$model$logLik(X=test_env,Y=model$data$Y[test,,drop=FALSE],individual=individual, sampling = sampling)[[1]] ), 
-                  R=Rsquared(m2,averageSite=!individual,...), 
-                  R2 = Rsquared2(model=m2,individual=individual,...)$marginal))      
-      
-      
-    }
-  }
-}
-
-
+#' Anova
+#' 
+#' Compute analysis of variance
+#' 
+#' @param object model of object \code{\link{sjSDM}}
+#' @param ... optional arguments for compatibility with the generic function, no function implemented
+#' 
+#' @description
+#' 
+#' Calculate type I anova in the following order:
+#' 
+#' Null, biotic, abiotic (environment), and spatial (if present).
+#' 
+#' Deviance for interactions (e.g. between space and environment) are also calculated and can be visualized via \code{\link{plot.sjSDManova}}.
+#' 
+#' @return 
+#' An S3 class of type 'sjSDManova'. Implemented S3 methods are \code{\link{print.sjSDManova}} and \code{\link{plot.sjSDManova}}
+#'  
+#' @seealso \code{\link{plot.sjSDManova}}, \code{\link{print.sjSDManova}}
+#' @import stats
+#' @export
+
+anova.sjSDM = function(object, ...) {
+  out = list()
+  full_m = logLik(object)[[1]]
+  ### fit different models ###
+  #e_form = stats::as.formula(paste0(as.character(object$settings$env$formula), collapse = ""))
+  if(!inherits(object, "spatial")) {
+    out$spatial = FALSE
+    null_m = logLik(update(object, env_formula = ~1, biotic=bioticStruct(diag = TRUE )))[[1]]
+    A_m =    logLik(update(object, env_formula = NULL, biotic=bioticStruct(diag = TRUE )))[[1]]
+    B_m =    logLik(update(object, env_formula = ~1, biotic=bioticStruct(diag = FALSE)))[[1]]
+    SAT_m =  logLik(update(object, env_formula = ~as.factor(1:nrow(object$data$X)), biotic=bioticStruct(diag = TRUE )))[[1]]
+    
+    A =    A_m
+    B =    B_m
+    full = full_m
+    AB =   null_m - ((null_m-full_m) - (null_m - A + null_m - B))
+    sat =  SAT_m
+    null = null_m
+    anova_rows = c("Null", "B", "Full")
+    names(anova_rows) = c("Null", "Biotic", "Abiotic")
+    results = data.frame(models = c("A", "B","AB", "Full", "Saturated", "Null"),
+                         ll = -c(A, B,AB, full, sat, null))
+  } else {
+    out$spatial = TRUE
+    s_form = stats::as.formula(paste0(as.character(object$settings$spatial$formula), collapse = ""))
+    null_m = logLik(update(object, env_formula = ~1, spatial_formula= ~0, biotic=bioticStruct(diag = TRUE )))[[1]]
+    A_m =    logLik(update(object, env_formula = NULL, spatial_formula= ~0, biotic=bioticStruct(diag = TRUE )))[[1]]
+    B_m =    logLik(update(object, env_formula = ~1, spatial_formula= ~0, biotic=bioticStruct(diag = FALSE)))[[1]]
+    S_m =    logLik(update(object, env_formula = ~1, spatial_formula= NULL, biotic=bioticStruct(diag = TRUE)))[[1]]
+    AB_m =   logLik(update(object, env_formula = NULL, spatial_formula= ~0, biotic=bioticStruct(diag = FALSE )))[[1]]
+    AS_m =   logLik(update(object, env_formula = NULL, spatial_formula= NULL, biotic=bioticStruct(diag = FALSE )))[[1]]
+    BS_m =   logLik(update(object, env_formula = ~1, spatial_formula= NULL, biotic=bioticStruct(diag = TRUE )))[[1]]
+    SAT_m =  logLik(update(object, env_formula = ~as.factor(1:nrow(object$data$X)), spatial_formula= ~0, biotic=bioticStruct(diag = TRUE )))[[1]]
+    
+    A =    A_m
+    B =    B_m
+    S =    S_m
+    AB =   null_m - ((null_m-AB_m) - (null_m- A + null_m-B))
+    AS =   null_m - ((null_m-AB_m) - (null_m- A + null_m-S))
+    BS =   null_m - ((null_m-BS_m) - (null_m- B + null_m-S))
+    ABS =  null_m - ((null_m-full_m) - (null_m- B + null_m-S+null_m-A))
+    full = full_m
+    null = null_m
+    sat =  SAT_m
+    
+    results = data.frame(models = c("A", "B","S","B+A","B+S","A+S","AB","AS", "BS", "ABS", "Full", "Saturated", "Null"),
+                         ll = -c(A, B,S,AB_m,BS_m, AS_m, AB, AS, BS, ABS, full, sat, null))
+    
+    
+    #1-exp(2/nrow(object$data$Y)*(-A))
+    anova_rows = c("Null", "B", "B+A", "Full")
+    names(anova_rows) = c("Null", "Biotic", "Abiotic", "Spatial")
+  }
+  
+  results$`Residual deviance` = -2*(results$ll - results$ll[which(results$models == "Saturated", arr.ind = TRUE)])
+  
+  results$Deviance = results$`Residual deviance`[which(results$models == "Null", arr.ind = TRUE)] - results$`Residual deviance`
+  R2 = function(a, b) return(1-exp(2/(nrow(object$data$Y))*(-a+b)))
+  results$`R2 Nagelkerke` = R2(rep(-results$ll[which(results$models == "Null", arr.ind = TRUE)], length(results$ll)), - results$ll)
+  R2 = function(a, b) 1 - (b/a)
+  results$`R2 McFadden`= R2(rep(-results$ll[which(results$models == "Null", arr.ind = TRUE)], length(results$ll)), - results$ll)
+  
+  to_print = results
+  rownames(to_print) = to_print$models
+  to_print = to_print[anova_rows,]
+  to_print$models = names(anova_rows)
+  to_print$Deviance = c(0,-diff(to_print$`Residual deviance`))
+  to_print = to_print[-1,c(1, 4, 3,5,6)]
+  rownames(to_print) = to_print$models
+  to_print = to_print[,-1]
+  out$results = results
+  out$to_print = to_print
+  out$N = nrow(object$data$Y)
+  class(out) = "sjSDManova"
+  return(invisible(out))
+}
+
+
+
+
+#' Print sjSDM anova
+#' 
+#' @param x an object of \code{\link{anova.sjSDM}}
+#' @param ... optional arguments for compatibility with the generic function, no function implemented
+#' @export
+print.sjSDManova = function(x, ...) {
+  cat("Analysis of Deviance Table\n\n")
+  cat("Terms added sequentially:\n\n")
+  stats::printCoefmat(x$to_print)
+  return(invisible(x$to_print))
+}
+
+
+#' Plot anova results
+#' 
+#' 
+#' @param x anova object from \code{\link{anova.sjSDM}}
+#' @param y unused argument
+#' @param type use of deviance or of Nagelkerke or McFadden R-squareds
+#' @param cols colors for the groups
+#' @param alpha alpha for colors
+#' @param ... Additional arguments to pass to \code{plot()}
+#' 
+#' @return 
+#' 
+#' Matrix of results
+#' 
+#' @export
+plot.sjSDManova = function(x, y, type = c("Deviance", "Nagelkerke", "McFadden"), cols = c("#7FC97F","#BEAED4","#FDC086"),alpha=0.15, ...) {
+  lineSeq = 0.3
+  nseg = 100
+  dr = 1.0
+  type = match.arg(type)
+  
+  values = x$results
+  select_rows = 
+    if(x$spatial) { 
+      sapply(c("A", "B", "AB","S", "AS", "BS", "ABS"), function(i) which(values$models == i, arr.ind = TRUE))
+    } else {
+      sapply(c("A", "B", "AB"), function(i) which(values$models == i, arr.ind = TRUE))
+    }
+  
+  values = values[select_rows,]
+  col_index = 
+    switch (type,
+      Deviance = 4,
+      Nagelkerke = 5,
+      McFadden = 6
+    )
+  
+  
+  graphics::plot(NULL, NULL, xlim = c(0,1), ylim =c(0,1),pty="s", axes = FALSE, xlab = "", ylab = "")
+  xx = 1.1*lineSeq*cos( seq(0,2*pi, length.out=nseg))
+  yy = 1.1*lineSeq*sin( seq(0,2*pi, length.out=nseg))
+  graphics::polygon(xx+lineSeq,yy+(1-lineSeq), col= addA(cols[1],alpha = alpha), border = "black", lty = 1, lwd = 1)
+  graphics::text(lineSeq-0.1, (1-lineSeq),labels = round(values[1,col_index],3))
+  graphics::text(mean(xx+lineSeq), 0.9,labels = "Environmental", pos = 3)
+  
+  graphics::polygon(xx+1-lineSeq,yy+1-lineSeq, col= addA(cols[2],alpha = alpha), border = "black", lty = 1, lwd = 1)
+  graphics::text(1-lineSeq+0.1, (1-lineSeq),labels = round(values[2,col_index],3))
+  graphics::text(1-mean(xx+lineSeq), 0.9,labels = "Associations", pos = 3)
+  graphics::text(0.5, (1-lineSeq),labels = round(values[3,col_index],3))
+  
+  if(x$spatial) {
+    graphics::polygon(xx+0.5,yy+lineSeq, col= addA(cols[3],alpha = alpha), border = "black", lty = 1, lwd = 1)
+    graphics::text(0.5, lineSeq+0.0,pos = 1,labels = round(values[4,col_index],3))
+    graphics::text(0.5, 0.1,labels = "Spatial", pos = 1)
+    graphics::text(0.3, 0.5,pos=1,labels   = round(values[5,col_index],3)) # AS
+    graphics::text(1-0.3, 0.5,pos=1,labels = round(values[6,col_index],3)) # BS
+    graphics::text(0.5, 0.5+0.05,labels    = round(values[7,col_index],3)) # ABS
+  }
+  return(invisible(values))
+}
+
diff --git a/sjSDM/R/importance.R b/sjSDM/R/importance.R
index bd0b0db..97aa692 100644
--- a/sjSDM/R/importance.R
+++ b/sjSDM/R/importance.R
@@ -1,11 +1,26 @@
 #' importance 
 #' 
-#' importance of abiotic, biotic, and spatial effects
+#' Computes standardized variance components with respect to abiotic, biotic, and spatial effect groups. 
 #' 
 #' @param x object fitted by \code{\link{sjSDM}} or a list with beta, the association matrix, and the correlation matrix of the predictors, see details below
 #' @param save_memory use torch backend to calculate importance with single precision floats
 #' @param ... additional arguments
 #' 
+#' @details 
+#' 
+#' This variance partitioning approach is based on Ovaskainen et al., 2017. For an example how to interpret the outputs, see Leibold et al., 2021.
+#' 
+#' @return
+#' 
+#' An S3 class of type 'sjSDMimportance'. Implemented S3 methods include \code{\link{print.sjSDMimportance}} and \code{\link{plot.sjSDMimportance}}
+#' 
+#' @references 
+#' 
+#' Ovaskainen, O., Tikhonov, G., Norberg, A., Guillaume Blanchet, F., Duan, L., Dunson, D., ... & Abrego, N. (2017). How to make more out of community data? A conceptual framework and its implementation as models and software. Ecology letters, 20(5), 561-576.
+#' 
+#' Leibold, M. A., Rudolph, F. J., Blanchet, F. G., De Meester, L., Gravel, D., Hartig, F., ... & Chase, J. M. (2021). The internal structure of metacommunities. Oikos.
+#' 
+#' @seealso \code{\link{print.sjSDMimportance}}, \code{\link{plot.sjSDMimportance}}
 #' @example /inst/examples/importance-example.R
 #' @author Maximilian Pichler
 #' @export
@@ -40,14 +55,6 @@ importance = function(x, save_memory = TRUE, ...) {
                    total = list(env = rowSums(vp$env), biotic = vp$biotic))
         spatial=FALSE
       }
-      # sp_names = NULL
-      # beta = model[[1]]
-      # sigma = model[[2]]
-      # covX = model[[3]]
-      # vp = getImportance(beta = beta,  association = sigma, covX = covX)
-      # colnames(vp$env) = model$names
-      # res = list(split = vp, 
-      #            total = list(env = rowSums(vp$env), biotic = vp$biotic))
   } else {
     check_module()
     sp_names = colnames(model$data$Y)
@@ -55,20 +62,19 @@ importance = function(x, save_memory = TRUE, ...) {
     if(inherits(coefs, "list")) coefs = coefs[[1]]
     env = t(coefs)
     beta = env
-    #sigma = getCov(model)
     covX = stats::cov(model$data$X)
     if(!is.null(model$settings$spatial)) {
       spatial = TRUE
       sp = t(coef.sjSDM(model)[[2]][[1]])
       covSP = stats::cov(model$settings$spatial$X)
       
-      vp = fa$importance(beta = beta, betaSP = sp, sigma = model$sigma, covX = covX, covSP = covSP, ...)
+      vp = force_r( fa$importance(beta = beta, betaSP = sp, sigma = model$sigma, covX = covX, covSP = covSP, ...) )
       colnames(vp$spatial) = attributes(model$settings$spatial$X)$dimnames[[2]]
       colnames(vp$env) = model$names
       res = list(split = vp, 
                  total = list(env = rowSums(vp$env), spatial = rowSums(vp$spatial), biotic = vp$biotic))
     } else {
-      vp = fa$importance(beta = beta,  sigma = model$sigma, covX = covX, ...)
+      vp = force_r( fa$importance(beta = beta,  sigma = model$sigma, covX = covX, ...) )
       colnames(vp$env) = model$names
       res = list(split = vp, 
                  total = list(env = rowSums(vp$env), biotic = vp$biotic))
@@ -125,9 +131,6 @@ plot.sjSDMimportance= function(x, y,contour=FALSE,col.points="#24526e",cex.point
 }
 
 
-
-#model = list(t(cbind(coef(m)$Xcoef, coef(m)$Intercept)), getResidualCov(m, FALSE)$cov, cov(m$TMBfn$env$data$x))
-
 #' getImportance
 #' 
 #' variation partitioning with coefficients
@@ -191,63 +194,4 @@ getImportance = function(beta, sp=NULL, association, covX, covSP=NULL) {
                biotic=variPartRandom)
     return(res)
   }
-}
-
-
-
-#' varPartTypIII
-#' 
-#' variation partitioning Typ III
-#' @param model object fitted by \code{\link{sjSDM}}
-#' @param order which modules should be removed: E (environment), S (spatial), or B (biotic)
-#' @param ... arguments passed to \code{\link{Rsquared}}
-#' 
-#' @author Maximilian Pichler
-
-varPartTypIII = function(model, order = NULL, ...) {
-  if(!is.null(model$spatial_weights)) {
-    sp = TRUE
-    order = c("ESB", "ES", "E")
-  } else {
-    sp = FALSE
-    order = c("EB", "E")
-  }
-  res = vector("list", length(order)+1)
-  res[[1]] = Rsquared(model, ...)
-  for(i in 1:length(order))res[[i+1]] = getRsquaredWOmodule(model,modules = order[[i]],...)
-  names(res) =  c("full", order)
-  return(res)
-}
-
-
-getRsquaredWOmodule = function(model, modules = c("E"), ...) {
-  modules = strsplit(modules,split = "")[[1]]
-  for(i in modules) {
-    if(i == "E") {
-      model$model$set_env_weights(lapply(model$weights, function(w) copyRP(matrix(0.0, nrow(w), ncol(w) )) ))
-    }
-    if(i == "B") {
-      model$model$set_sigma(copyRP(diag(1.0, ncol(model$data$Y))))
-      model$model$df= as.integer(ncol(model$data$Y))
-    }
-    if(i == "S") {
-      model$model$set_spatial_weights(lapply(model$spatial_weights, function(w) copyRP(matrix(0.0, nrow(w), ncol(w)))    ))
-    }
-  }
-  R2 = Rsquared(model, ...)
-  
-  for(i in modules) {
-    if(i == "E") {
-      model$model$set_env_weights(copyRP(model$weights))
-    }
-    if(i == "B") {
-      model$model$set_sigma(copyRP(model$sigma))
-      model$model$df= as.integer(ncol(model$sigma))
-    }
-    if(i == "S") {
-      model$model$set_spatial_weights(lapply(model$spatial_weights, function(w) copyRP(matrix(0.0, nrow(w), ncol(w) ))))
-    }
-  }
-  return(R2)
-}
-
+}
\ No newline at end of file
diff --git a/sjSDM/R/install.R b/sjSDM/R/install.R
index e9253bc..67c9a45 100644
--- a/sjSDM/R/install.R
+++ b/sjSDM/R/install.R
@@ -1,131 +1,114 @@
 #' Install sjSDM and its dependencies
 #'
-#' @param method installation method, auto = automatically best (conda or virtualenv), or force conda with method = "conda" or virtualenv with method = "virtualenv"
 #' @param conda path to conda
-#' @param version version = "cpu" for CPU version, or "gpu" for gpu version. (note MacOS users have to install cuda binaries by themselves)
-#' @param envname Name of python env, "r-pytorch" is default
+#' @param version version = "cpu" for CPU version, or "gpu" for GPU version. (note MacOS users have to install 'cuda' binaries by themselves)
 #' @param restart_session Restart R session after installing (note this will
 #'   only occur within RStudio).
-#' @param cuda which cuda version, 9.2 and 10.2 are supported
 #' @param ... not supported
 #'
 #' @export
-install_sjSDM = function(method = "conda",
-                         conda = "auto",
+install_sjSDM = function(conda = "auto",
                          version = c("cpu", "gpu"),
-                         envname = "r-reticulate",
-                         restart_session = TRUE,
-                         cuda = c("10.2", "9,2"), ...) {
+                         restart_session = TRUE, ...) {
   
-  pip = FALSE
-  extra_packages = NULL
-  is_windows = function() {
-    identical(.Platform$OS.type, "windows")
-  }
-  
-  is_unix = function() {
-    identical(.Platform$OS.type, "unix")
-  }
-  
-  is_osx = function() {
-    Sys.info()["sysname"] == "Darwin"
-  }
-  
-  is_linux = function() {
-    identical(tolower(Sys.info()[["sysname"]]), "linux")
-  }
   version = match.arg(version)
-  cuda = match.arg(cuda)
   
+  method = "conda"
+  envname = "r-sjsdm"
   
+  # install conda if not installed 
   conda = tryCatch(reticulate::conda_binary(), error = function(e) e)
-  
   if(inherits(conda, "error")) {
-    reticulate::install_miniconda()
-  }
-  channel = "pytorch"
-  if(is_windows()) {
-    package = list()
-    package$conda =
-      switch(version,
-             cpu = "pytorch torchvision torchaudio cpuonly",
-             gpu = "pytorch torchvision torchaudio cudatoolkit=10.2")
-    if(cuda == 9.2 && version == "gpu") package$conda = "pytorch torchvision cudatoolkit=9.2 -c pytorch -c defaults -c numba/label/dev"
-    
-    package$pip = 
-      switch(version,
-             cpu = "torch===1.8.1 torchvision===0.9.1 torchaudio===0.8.1 -f https://download.pytorch.org/whl/torch_stable.html",
-             gpu = "torch==1.8.1+cpu torchvision==0.9.1+cpu torchaudio===0.8.1 -f https://download.pytorch.org/whl/torch_stable.html")
-    if(cuda == 9.2 && version == "gpu") package$conda = "torch==1.4.0+cu92 torchvision==0.5.0+cu92 -f https://download.pytorch.org/whl/torch_stable.html"
+    reticulate::install_miniconda(update = TRUE)
   }
   
-  if(is_linux() || is_unix()) {
-    package = list()
-    package$conda =
-      switch(version,
-             cpu = "pytorch torchvision torchaudio cpuonly",
-             gpu = "pytorch torchvision torchaudio cudatoolkit=10.2")
-    if(cuda == 9.2 && version == "gpu") package$conda = "pytorch torchvision cudatoolkit=9.2 -c pytorch"
-    
-    package$pip =
-      switch(version,
-             cpu = "torch==1.8.1+cpu torchvision==0.9.1+cpu torchaudio==0.8.1 -f https://download.pytorch.org/whl/torch_stable.html",
-             gpu = "torch torchvision")
-    if(cuda == 9.2 && version == "gpu") package$pip = "torch==1.4.0+cu92 torchvision==0.5.0+cu92 -f https://download.pytorch.org/whl/torch_stable.html"
-  } 
+  # get python dependencies
+  pkgs = get_pkgs(version = version)
+  
+  # torch will be installed via pip on macOS because of mkl dependencies
+  pip = FALSE
+  channel = "pytorch"
   if(is_osx()) {
-    package = list()
-    package$conda =
-      switch(version,
-             cpu = "pytorch torchvision torchaudio",
-             gpu = "pytorch torchvision torchaudio")
-    
-    package$pip =
-      switch(version,
-             cpu = "torch torchvision torchaudio",
-             gpu = "torch torchvision torchaudio")
-    
-    if(version == "gpu") message("PyTorch does not provide cuda binaries for macOS, installing CPU version...\n")
+    pip = TRUE
+    channel = NULL
   }
   
-  packages = strsplit(unlist(package), " ", fixed = TRUE)
-  
+  # install dependencies
   error = tryCatch({
-#     conda_path =reticulate::conda_binary()
-#     system2(conda_path, args=paste0(" create -y --force -n ", envname))
-#     system2(conda_path, args=paste0(" install -y -n ",envname ," python=", conda_python_version))
-#     system2(conda_path, args=paste0(" install -y -n ",envname, " ", paste(packages$conda, collapse = " "), " -c pytorch"))
-# 	  conda_python = reticulate::conda_python(envname=envname)
-# 	  system2(conda_python, args=" -m pip install --upgrade ssl")
-# 	  reticulate::conda_install(envname, packages = c("pyro-ppl", "torch_optimizer"), pip = TRUE)
-#     #system2(conda_python, args=paste0(" -m pip install pyro-ppl torch_optimizer"))
     
-    reticulate::conda_install(envname = envname, packages = packages$conda, channel = channel)
-    reticulate::conda_install(envname = envname, packages = c("pyro-ppl", "torch_optimizer", "madgrad"), pip = TRUE)
-  
-  }, error = function(e) e)
-  
-  error = tryCatch({
-    reticulate::conda_install(envname = envname, packages = packages$conda, channel = channel)
-    reticulate::conda_install(envname = envname, packages = c("pyro-ppl", "torch_optimizer"), pip = TRUE)
+    reticulate::py_install(
+      pkgs$conda,
+      envname = envname,
+      method = "conda",
+      conda = "auto",
+      python_version = "3.7.1",
+      channel = channel,
+      pip = pip
+    )
+    
+    reticulate::py_install(
+      c("numpy", "pyro-ppl", "torch_optimizer", "madgrad"),
+      envname = envname,
+      method = "conda",
+      conda = "auto",
+      pip = TRUE
+    )
   }, error = function(e) e)
   
-  
+  # check if instllation was successfull
   if(!inherits(error, "error")) {
-    message("\nInstallation complete.\n\n")
+    cli::cli_alert_success("\nInstallation complete.\n\n")
     
     if (restart_session && rstudioapi::hasFun("restartSession"))
       rstudioapi::restartSession()
     
     invisible(NULL)
   } else {
-    cat("\nInstallation failed... Try to install manually PyTorch (install instructions: https://github.com/TheoreticalEcology/s-jSDM\n")
-    cat("If the installation still fails, please report the following error on https://github.com/TheoreticalEcology/s-jSDM/issues\n")
-    cat(error$message)
+    cli::cli_alert_danger("\nInstallation failed... try to install manually PyTorch (install instructions: https://github.com/TheoreticalEcology/s-jSDM\n")
+    cli::cli_alert_info("If the installation still fails, please report the following error on https://github.com/TheoreticalEcology/s-jSDM/issues\n")
+    cli::cli_alert(error$message)
   }
 }
 
 
+
+is_windows = function() {
+  identical(.Platform$OS.type, "windows")
+}
+
+is_unix = function() {
+  identical(.Platform$OS.type, "unix")
+}
+
+is_osx = function() {
+  Sys.info()["sysname"] == "Darwin"
+}
+
+is_linux = function() {
+  identical(tolower(Sys.info()[["sysname"]]), "linux")
+}
+
+get_pkgs = function(version="cpu") {
+  
+  channel = "pytorch"
+  if(is_windows() || is_linux() || is_unix()) {
+    package = list()
+    package$conda =
+      switch(version,
+             cpu = "pytorch torchvision torchaudio cpuonly",
+             gpu = "pytorch torchvision torchaudio cudatoolkit=11.3")
+   }
+
+  if(is_osx()) {
+    package = list()
+    package$conda = "torch torchvision torchaudio"
+    if(version == "gpu") message("PyTorch does not provide cuda binaries for macOS, installing CPU version...\n")
+  }
+  
+  packages = strsplit(unlist(package), " ", fixed = TRUE)
+  return(packages)
+}
+
 #' @title install diagnostic
 #' 
 #' @description Print information about available conda environments, python configs, and pytorch versions. 
diff --git a/sjSDM/R/installation_help.R b/sjSDM/R/installation_help.R
index e3739ab..a0407b4 100644
--- a/sjSDM/R/installation_help.R
+++ b/sjSDM/R/installation_help.R
@@ -1,168 +1,151 @@
-#' @title installation help
-#' @name installation_help
-#' @docType package
-#' @description A scalable method to estimates joint Species Distribution Models (jSDMs).
-#' @details A scalable method to estimates joint Species Distribution Models (jSDMs) based on the multivariate probit model through Monte-Carlo approximation of the joint likelihood. The numerical approximation is based on PyTorch and reticulate, and can be calculated on CPUs and GPUs alike. 
-#' 
-#' @section PyTorch Installation - Before you start:
-#' 
-#' A few notes before you start with the installation:
-#'\itemize{
-#'  \item existing conda installations (skip this point if you do not know conda): make sure you have the latest conda3/miniconda3 installation and remove unneccessary conda installations.
-#'  \item existing conda/virtualenv (skip this point if you do not know conda): the R package reticulate has problems to find the right environment and it is better to remove unneccessary environments (see the troubleshooting section)
-#' }
-#' 
-#' 
-#' @section Windows - automatic installation:
-#' 
-#' Conda is the easiest way to install python and python packages on windows:
-#' Install the latest \href{https://www.anaconda.com/distribution/}{conda version}
-#' 
-#' Afterwards run:\cr
-#' \code{install_sjSDM(version = c("gpu")) # or "cpu" if you do not have a proper gpu device }
-#' 
-#' Reload the package and run the example , if this doesn't work:
-#' \itemize{
-#' \item Restart RStudio
-#' \item Install manually pytorch, see the following section
-#' }
-#' 
-#'  
-#' @section Windows - manual installation:
-#' 
-#' Conda is the easiest way to install python and python packages on windows:
-#' \itemize{
-#' \item Install the latest \href{https://www.anaconda.com/distribution/}{conda version}
-#' \item Open the command window (cmd.exe - hit windows key + r and write cmd)
-#' }
-#' Run in cmd.exe:\cr
-#' \preformatted{
-#' $ conda create --name sjSDM_env python=3.7\cr
-#' $ conda activate sjSDM_env\cr
-#' $ conda install pytorch torchvision cpuonly -c pytorch # cpu\cr
-#' $ conda install pytorch torchvision cudatoolkit=10.1 -c pytorch #gpu\cr
-#' }
-#' 
-#' Restart R try to run the example, if this doesn't work:
-#' \itemize{
-#' \item Restart RStudio
-#' \item See the troubleshooting section
-#' }
-#' 
-#'    
-#' @section Linux - automatic installation:
-#' 
-#' Run in R:\cr
-#' \code{install_sjSDM(version = c("gpu")) # or "cpu" if you do not have a proper gpu device }
-#' Restart R try to run the example, if this doesn't work:
-#' \itemize{
-#' \item Restart RStudio
-#' \item Install manually pytorch, see the following section
-#' }
-#'  
-#'  
-#' @section Linux - manual installation:
-#' 
-#' Via pip\cr
-#' python3 is pre-installed on most linux distributions, but you have to check that the minimal requirement of python >= 3.6 is met: 
-#'   
-#' Run in your shell:\cr
-#' \preformatted{
-#' $ python3 --version\cr
-#' $ python --version\cr
-#' }
-#' 
-#' Check if pip is installed:
-#' \preformatted{
-#' $ pip3 --version\cr
-#' $ pip --version\cr
-#' }
-#' 
-#' If not then install pip:\cr
-#' \preformatted{
-#' $ sudo apt install python3-pip # for ubuntu/deb   # e.g. for ubuntu
-#' }
-#' 
-#' It depends on your ENVIRONMENTAL variables whether pip or pip3 corresponds to python3. You can check the python version of pip via:\cr
-#' \preformatted{
-#' $ pip --version
-#' }
-#' 
-#' In my case, I have to use "pip3":\cr
-#' \preformatted{
-#' $ pip3 install torch==1.4.0+cpu torchvision==0.5.0+cpu -f https://download.pytorch.org/whl/torch_stable.html #cpu
-#' $ pip3 install torch torchvision #gpu
-#' }
-#' 
-#' Restart R try to run the example, if this doesn't work:
-#' \itemize{
-#' \item Restart RStudio
-#' \item See the troubleshooting section
-#' }
-#' 
-#' Via virtualenv\cr
-#' Create a virtualenv and install dependencies (shell):\cr
-#' \preformatted{
-#' $ python3 -m pip install --user virtualenv\cr
-#' $ python3 -m venv ~/sjSDM_env\cr
-#' $ source ~/sjSDM_env/bin/activate\cr
-#' $ pip install torch==1.4.0+cpu torchvision==0.5.0+cpu -f https://download.pytorch.org/whl/torch_stable.html #cpu\cr
-#' $ pip install torch torchvision #gpu\cr
-#' }
-#' 
-#' Restart R try to run the example, if this doesn't work:
-#' \itemize{
-#' \item Restart RStudio
-#' \item See the troubleshooting section
-#' }
-#' 
-#' Via conda\cr
-#' Install the latest \href{https://www.anaconda.com/distribution/}{conda version} and run (shell):\cr
-#' \preformatted{
-#' $ conda create --name sjSDM_env python=3.7\cr
-#' $ conda activate sjSDM_env\cr
-#' $ conda install pytorch torchvision cpuonly -c pytorch # cpu\cr
-#' $ conda install pytorch torchvision cudatoolkit=10.1 -c pytorch #gpu\cr
-#' }
-#' Restart R try to run the example from, if this doesn't work:\cr
-#' \itemize{
-#' \item Restart RStudio
-#' \item See the troubleshooting section
-#' }
-#' 
-#' @section  MacOS:
-#' 
-#' Via conda\cr
-#' Install the latest \href{https://www.anaconda.com/distribution/}{conda version} and run in your OS shell:\cr
-#' \preformatted{
-#' $ conda create --name sjSDM_env python=3.7\cr
-#' $ conda activate sjSDM_env\cr
-#' $ conda install pytorch torchvision cpuonly -c pytorch # cpu\Cr
-#' }
-#' Restart R try to run the example from, if this doesn't work:
-#' \itemize{
-#' \item Restart RStudio
-#' \item See the troubleshooting section
-#' }
-#'     
-#' For GPU support on MacOS, you have to install the cuda binaries yourself, see \href{https://pytorch.org/}{PyTorch for help}
-#'
-#'      
-#' @section Troubleshooting:
-#' 
-#' After several installation attempts you might have corrupt and unneccessary conda environments which you have to remove:
-#' Open the shell (Windows users: run cmd.exe):\cr
-#' \preformatted{
-#' $ conda env list\cr
-#' }
-#' will list the paths of all your environments, except for the "base" env, delete them via:\cr
-#' \preformatted{
-#' $ rm - r <path-to-env1>\cr
-#' $ rm - r <path-to-env2>\cr
-#' }
-#' Then continue with the manual install instructions in above sections.
-#'
-#' @section Help and bugs:
-#' 
-#' To report bugs or ask for help, post a \href{http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example}{reproducible example} via the sjSDM \href{https://github.com/TheoreticalEcology/s-jSDM/issues}{issue tracker} with a copy of the \code{\link{install_diagnostic}} output as a quote on GitHub. 
+#' @title Installation help
+#' @name installation_help
+#' @docType package
+#' @description Trouble shooting guide for the installation of the sjSDM package
+#' 
+#' We provide a function \code{\link{install_sjSDM}} to install automatically 
+#' all necessary python dependencies but it can fail sometimes because of 
+#' individual system settings or if other python/conda installations get into 
+#' the way. 
+#' 
+#' @section 'PyTorch' Installation - Before you start:
+#' 
+#' A few notes before you start with the installation (skip this point if you 
+#' do not know 'conda'):
+#'\itemize{
+#'  \item existing 'conda' installations:
+#'   make sure you have the latest conda3/miniconda3 version and 
+#'   remove unnecessary 'conda' installations.
+#'  \item existing 'conda'/'virtualenv' environments (skip this point if you do not know 'conda'): 
+#'  we currently enforce the usage of a specific environment called 'r-sjsdm', 
+#'  so if you want use a custom environment it should be named 'r-sjsdm'
+#' }
+#' 
+#' 
+#' @section Windows - automatic installation:
+#' 
+#' Sometimes the automatic 'miniconda' installation 
+#' (via \code{\link{install_sjSDM}}) doesn't work because of white
+#' spaces in the user's name. But you can easily download and install 'conda' on
+#' your own:
+#' 
+#' Download and install the latest 
+#' \href{https://www.anaconda.com/products/individual}{'conda' version}
+#' 
+#' Afterwards run:\cr
+#' \code{install_sjSDM(version = c("gpu")) # or "cpu" if you do not have a proper gpu device }
+#' 
+#' Reload the package and run the example , if this doesn't work:
+#' \itemize{
+#' \item Restart RStudio
+#' \item Install manually 'pytorch', see the following section
+#' }
+#' 
+#'  
+#' @section Windows - manual installation:
+#' 
+#' Download and install the latest 'conda' version:
+#' \itemize{
+#' \item Install the latest 
+#' \href{https://www.anaconda.com/products/individual}{'conda' version}
+#' \item Open the command window (cmd.exe - hit windows key + r and write cmd)
+#' }
+#' Run in cmd.exe:\cr
+#' \preformatted{
+#' $ conda create --name r-sjsdm python=3.7
+#' $ conda activate r-sjsdm
+#' $ conda install pytorch torchvision cpuonly -c pytorch # cpu
+#' $ conda install pytorch torchvision cudatoolkit=11.3 -c pytorch #gpu
+#' $ python -m pip install pyro-ppl torch_optimizer madgrad
+#' }
+#' 
+#' Restart R, try to run the example, and if this doesn't work:
+#' \itemize{
+#' \item Restart RStudio
+#' \item See the 'Help and bugs' section
+#' }
+#' 
+#'    
+#' @section Linux - automatic installation:
+#' 
+#' Run in R:\cr
+#' \code{install_sjSDM(version = c("gpu")) # or "cpu" if 
+#' you do not have a proper 'gpu' device }
+#' 
+#' Restart R try to run the example, if this doesn't work:
+#' \itemize{
+#' \item Restart RStudio
+#' \item Install manually 'PyTorch', see the following section
+#' }
+#'  
+#'  
+#' @section Linux - manual installation:
+#' 
+#' We strongly advise to use a 'conda' environment but a virtual env should also 
+#' work. The only requirement is that it is named 'r-sjsdm'
+#' 
+#' 
+#' Download and install the latest 'conda' version:
+#' \itemize{
+#' \item Install the latest 
+#' \href{https://www.anaconda.com/products/individual}{'conda' version}
+#' \item Open your terminal 
+#' }
+#' 
+#' Run in your terminal:\cr
+#' \preformatted{
+#' $ conda create --name r-sjsdm python=3.7
+#' $ conda activate r-sjsdm
+#' $ conda install pytorch torchvision cpuonly -c pytorch # cpu
+#' $ conda install pytorch torchvision cudatoolkit=11.3 -c pytorch #gpu
+#' $ python -m pip install pyro-ppl torch_optimizer madgrad
+#' }
+#' 
+#' Restart R try to run the example, if this doesn't work:
+#' \itemize{
+#' \item Restart RStudio
+#' \item See the 'Help and bugs' section
+#' }
+#' 
+#' 
+#' @section MacOS - automatic installation:
+#' 
+#' Run in R:\cr
+#' \code{install_sjSDM(version = c("cpu"))}
+#' 
+#' Restart R try to run the example, if this doesn't work:
+#' \itemize{
+#' \item Restart RStudio
+#' \item Install manually 'PyTorch', see the following section
+#' }
+#' 
+#' 
+#' @section MacOS - manual installation:
+#' 
+#' Download and install the latest 'conda' version:
+#' \itemize{
+#' \item Install the latest 
+#' \href{https://www.anaconda.com/products/individual}{'conda' version}
+#' \item Open your terminal 
+#' }
+#' 
+#' Run in your terminal:\cr
+#' \preformatted{
+#' $ conda create --name r-sjsdm python=3.7
+#' $ conda activate r-sjsdm
+#' $ python -m pip install torch torchvision torchaudio 
+#' $ python -m pip install pyro-ppl torch_optimizer madgrad
+#' }
+#' Restart R try to run the example from, if this doesn't work:
+#' \itemize{
+#' \item Restart RStudio
+#' \item See the 'Help and bugs' section
+#' }
+#'
+#' @section Help and bugs:
+#' 
+#' To report bugs or ask for help, post a 
+#' \href{https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example}{reproducible example} 
+#' via the sjSDM \href{https://github.com/TheoreticalEcology/s-jSDM/issues}{issue tracker} 
+#' with a copy of the \code{\link{install_diagnostic}} output as a quote. 
 NULL
\ No newline at end of file
diff --git a/sjSDM/R/methods.R b/sjSDM/R/methods.R
index 4ad68d3..7377473 100644
--- a/sjSDM/R/methods.R
+++ b/sjSDM/R/methods.R
@@ -1,7 +1,7 @@
 #' getCov
 #'
-#' get species-species assocation (covariance) matrix
-#' @param object a model fitted by \code{\link{sjSDM}}, \code{\link{sLVM}}  or \code{\link{sjSDM}} with \code{\link{DNN}} object
+#' get species-species association (covariance) matrix
+#' @param object a model fitted by \code{\link{sjSDM}}, or \code{\link{sjSDM}} with \code{\link{DNN}} object
 #' @seealso \code{\link{sjSDM}},\code{\link{DNN}}
 #' @export
 getCov = function(object) UseMethod("getCov")
@@ -11,18 +11,11 @@ getCov = function(object) UseMethod("getCov")
 #' @export
 getCov.sjSDM = function(object){
   object = checkModel(object)
-  return(object$model$covariance)
+  return(force_r(object$model$covariance))
   #return(object$sigma %*% t(object$sigma))
 }
 
 
-#' @rdname getCov
-#' @export
-getCov.sLVM= function(object){
-  return(object$covariance+diag(1.0, ncol(object$covariance)))
-}
-
-
 #' Get weights
 #' 
 #' return weights of each layer
@@ -40,7 +33,9 @@ getWeights = function(object) UseMethod("getWeights")
 #' @rdname getWeights
 #' @export
 getWeights.sjSDM= function(object) {
-  return(list(env=object$model$env_weights, spatial=object$model$spatial_weights, sigma = object$model$get_sigma))
+  return(list(env=force_r(object$model$env_weights), 
+              spatial=force_r(object$model$spatial_weights), 
+              sigma = force_r(object$model$get_sigma)))
 }
 
 
diff --git a/sjSDM/R/modules.R b/sjSDM/R/modules.R
new file mode 100644
index 0000000..19c7b98
--- /dev/null
+++ b/sjSDM/R/modules.R
@@ -0,0 +1,17 @@
+#' Torch module
+#' 
+#' Interface to 'PyTorch' module
+#' 
+#' @export
+#' @format Torch module
+#' @rdname modules
+torch = NULL
+
+#' fa module
+#' 
+#' Interface to internal 'fa' module
+#' 
+#' @export
+#' @format fa module
+#' @rdname modules
+fa = NULL
\ No newline at end of file
diff --git a/sjSDM/R/plot.R b/sjSDM/R/plot.R
index cb4b92e..591cb2d 100644
--- a/sjSDM/R/plot.R
+++ b/sjSDM/R/plot.R
@@ -1,12 +1,12 @@
-#' Coeffect plot
+#' Coefficients plot
 #' 
-#' Plotting coeffects return by sjSDM model.
+#' Plotting coefficients returned by sjSDM model.
 #' This function only for model fitted by linear, fitted by DNN is not yet supported.
 #' 
 #' @param x a model fitted by \code{\link{sjSDM}} 
 #' @param ... Additional arguments to pass to \code{\link{plotsjSDMcoef}}. 
 #' @seealso \code{\link{plotsjSDMcoef}}
-#' @example /inst/examples/plot.sjSDM-emample.R
+#' @example /inst/examples/plot.sjSDM-example.R
 #' 
 #' @import graphics
 #' @author CAI Wang
@@ -16,21 +16,18 @@ plot.sjSDM = function(x, ...) {
   plotsjSDMcoef(x, ...)
 }
 
-#' Coeffect plot
+#' Coefficients plot
 #' 
-#' Plotting coeffects return by sjSDM model.
+#' Plotting coefficients returned by sjSDM model.
 #' This function only for model fitted by linear, fitted by DNN is not yet supported.
 #' 
-#' @import tidyr
-#' @import dplyr
 #' @import ggplot2
-#' @importFrom magrittr `%>%`
 #' @param object a model fitted by \code{\link{sjSDM}} 
 #' @param wrap_col Scales argument passed to wrap_col
 #' @param group Define the taxonomic characteristics of a species, you need to provide a dataframe with column1 named “species” and column2 named “group”, default is NULL. For example, group[1,1]== "sp1", group[1,2]== "Mammal".
 #' @param col Define colors for groups, default is NULL.
 #' @param slist Select the species you want to plot, default is all, parameter is not supported yet.
-#' @example /inst/examples/plot.sjSDM-emample.R
+#' @example /inst/examples/plot.sjSDM-example.R
 #
 #' @author CAI Wang
 #' @export
@@ -42,14 +39,19 @@ plotsjSDMcoef = function(object,wrap_col=NULL,group=NULL,col=NULL,slist=NULL) {
   )
   
   if(is.null(object$se)) object=getSe(object)
-  summary.se=summary(object)
+  summary.se = summary(object)
   #create dataset for plot 
   effect = data.frame( Estimate=summary.se$coefmat[,1],Std.Err=summary.se$coefmat[,2],P=summary.se$coefmat[,4],rownames=rownames(summary.se$coefmat))
   
   coef = NULL
   rownames = NULL
-  effect= effect %>% tidyr::separate(col = rownames, into = c("species", "coef"), sep = " ") %>% dplyr::filter(coef != "(Intercept)") %>% dplyr::mutate(coef=as.factor(coef),star=NA)
-  effect$star <- stats::symnum(effect$P, corr = FALSE,
+  sep_df = do.call(rbind, strsplit(effect$rownames, split = " ", fixed = TRUE))
+  colnames(sep_df) = c("species", "coef")
+  effect = cbind(effect[,-4], sep_df)
+  effect = effect[effect$coef!= "(Intercept)",]
+  effect$coef = as.factor(effect$coef)
+  effect$star = NA
+  effect$star = stats::symnum(effect$P, corr = FALSE,
                                cutpoints = c(0, .001, .01, .05, .1, 1),
                                symbols = c("***","**","*","."," ")) 
   
@@ -58,17 +60,19 @@ plotsjSDMcoef = function(object,wrap_col=NULL,group=NULL,col=NULL,slist=NULL) {
   else if ( (colnames(data.frame(group)) != c("species","group"))[1]=="TRUE" |(colnames(data.frame(group)) != c("species","group"))[2]=="TRUE") {
     print ("group column's name should be 'species' and 'group'")
     group=NULL
-  }
-  else {
-    effect=dplyr::left_join(effect,data.frame(group),by="species")
+  } else {
+    effect = merge(effect, data.frame(group), by = "species", all.x = TRUE)
     if(anyNA(effect$group)) stop("There are no groups or with NAs")
-    group= dplyr::arrange(group,desc(group))
+    group = group[order(group$group, decreasing = TRUE), ]
     effect$species=factor(effect$species,levels= group$species)
   }
   
-  if(is.null(col))  
-    col <- RColorBrewer::brewer.pal(10, "Paired") 
-  else col=col
+  # colors
+  if(is.null(group) && is.null(col)) col = "grey"
+  if(!is.null(group) && is.null(col)) {
+    col = grDevices::palette.colors(length(unique(group$group))+1)[-1]
+    names(col) = NULL
+  }
   
   #if(!is.null(slist)) #effect = effect %>% dplyr::filter(species!=slist)
   
@@ -80,7 +84,7 @@ plotsjSDMcoef = function(object,wrap_col=NULL,group=NULL,col=NULL,slist=NULL) {
       scale_fill_manual(values=col)+
       guides(fill = guide_legend(reverse=F))+
       xlab("species") + 
-      ylab("coef") + 
+      ylab("coefficients") + 
       labs(fill="Group") + 
       coord_flip(expand=F) + 
       geom_hline(aes(yintercept = 0),linetype="dashed",size=1) +
@@ -248,7 +252,7 @@ add_species_arrows = function(radius = 5.0, label = "Species", reverse = TRUE, s
 #' @param main title
 #' @param circleBreak circle break or not
 #' @param top top negative and positive associations
-#' @param occ species occurence data
+#' @param occ species occurrence data
 #' @param cols_association col gradient for association lines
 #' @param cols_occurrence col gradient for species 
 #' @param lwd_occurrence lwd for occurrence lines
diff --git a/sjSDM/R/simulation.R b/sjSDM/R/simulation.R
index 58ada74..57ea4de 100644
--- a/sjSDM/R/simulation.R
+++ b/sjSDM/R/simulation.R
@@ -6,7 +6,7 @@
 #' @param Re random effects (intercepts)
 #' @param correlation correlated species TRUE or FALSE, can be also a function or a matrix
 #' @param weight_range sample true weights from uniform range, default -1,1
-#' @param link probit, logit or idential
+#' @param link probit, logit or identical
 #' @param response pa (presence-absence) or count
 #' @param sparse sparse rate
 #' @param tolerance tolerance for sparsity check
diff --git a/sjSDM/R/sjSDM.R b/sjSDM/R/sjSDM.R
index 7480a84..a51cdd9 100644
--- a/sjSDM/R/sjSDM.R
+++ b/sjSDM/R/sjSDM.R
@@ -1,8 +1,12 @@
-#' @title sjSDM
+#' @title Fitting scalable joint Species Distribution Models (sjSDM)
 #'
-#' @description fast and accurate joint species model
+#' @description 
 #' 
-#' @param Y matrix of species occurences/responses in range [0,1]
+#' \code{sjSDM} is used to fit joint Species Distribution models (jSDMs) using the central processing unit (CPU) or the graphical processing unit (GPU). 
+#' The default is a multivariate probit model based on a Monte-Carlo approximation of the joint likelihood. 
+#' \code{sjSDM} can be used to fit linear but also deep neural networks and supports the well known formula syntax. 
+#' 
+#' @param Y matrix of species occurences/responses in range
 #' @param env matrix of environmental predictors, object of type \code{\link{linear}} or \code{\link{DNN}}
 #' @param biotic defines biotic (species-species associations) structure, object of type \code{\link{bioticStruct}}
 #' @param spatial defines spatial structure, object of type \code{\link{linear}} or \code{\link{DNN}}
@@ -11,38 +15,113 @@
 #' @param step_size batch size for stochastic gradient descent, if \code{NULL} then step_size is set to: \code{step_size = 0.1*nrow(X)}
 #' @param learning_rate learning rate for Adamax optimizer
 #' @param se calculate standard errors for environmental coefficients
-#' @param sampling number of sampling steps for Monte Carlo integreation
+#' @param sampling number of sampling steps for Monte Carlo integration
 #' @param parallel number of cpu cores for the data loader, only necessary for large datasets
 #' @param control control parameters for optimizer, see \code{\link{sjSDMControl}}
 #' @param device which device to be used, "cpu" or "gpu"
 #' @param dtype which data type, most GPUs support only 32 bit floats.
 #' 
-#' @details The function fits a multivariate probit model via Monte-Carlo integration (see Chen et al., 2018) of the joint likelihood for all species. See Pichler and Hartig, 2020 for benchmark results.
+#' @details 
+#' \loadmathjax
+#' The function fits per default a multivariate probit model via Monte-Carlo integration (see Chen et al., 2018) of the joint likelihood for all species.
+#' 
+#' \subsection{Model description}{
+#' 
+#' The most common jSDM structure describes the site (\mjeqn{i = 1, ..., I}{})  by species (\mjeqn{j = 1, ..., J}{}) matrix \mjeqn{Y_{ij}}{} as a function of
+#' environmental covariates \mjeqn{X_{in}}{}(\mjeqn{n=1,...,N}{} covariates), and the species-species covariance matrix
+#' \mjeqn{\Sigma}{} accounts for correlations in \mjeqn{e_{ij}}{}:
+#' 
+#' \mjdeqn{g(Z_{ij}) = \beta_{j0} + \Sigma^{N}_{n=1}X_{in}\beta_{nj} + e_{ij}}{}
+#' 
+#' \mjeqn{g(.)}{} is a link function. For the multivariate probit model, the link function is:
+#' 
+#' \mjdeqn{Y_{ij}=1(Z_{ij} > 0)}{}
+#' 
+#' The probability to observe the occurrence vector \mjeqn{\bf{Y_i}}{} is:
+#' 
+#' \mjdeqn{Pr(\bf{Y}_i|\bf{X}_i\beta, \Sigma) = \int_{A_{iJ}}...\int_{A_{i1}} \phi_J(\bf{Y}_i^{\ast};\bf{X}_i\beta, \Sigma)  dY_{i1}^{\ast}... dY_{iJ}^{\ast}}{}
+#' 
+#' in the interval \mjeqn{A_{ij}}{} with \mjeqn{(-\inf, 0]}{} if \mjeqn{Y_{ij}=0}{} and \mjeqn{ [0, +\inf) }{}  if \mjeqn{Y_{ij}=1}{}.
+#' 
+#' and \mjeqn{\phi}{} being the density function of the multivariate normal distribution. 
+#' 
+#' The probability of \mjeqn{\bf{Y_i}}{} requires to integrate over \mjeqn{\bf{Y_i^{\ast}}}{} which has no closed analytical expression for more than two species
+#' which makes the evaluation of the likelihood computationally costly and needs a numerical approximation.
+#' The previous equation can be expressed more generally as:
+#' 
+#' \mjdeqn{ \mathcal{L}(\beta, \Sigma; \bf{Y}_i, \bf{X}_i) = \int_{\Omega} \prod_{j=1}^J Pr(Y_{ij}|\bf{X}_i\beta+\zeta) Pr(\zeta|\Sigma) d\zeta  }{}
+#' 
+#' \code{sjSDM} approximates this integral by \mjeqn{M}{} Monte-Carlo samples from the multivariate normal species-species covariance. 
+#' After integrating out the covariance term, the remaining part of the likelihood can be calculated as in an univariate case and the average 
+#' of the \mjeqn{M}{} samples are used to get an approximation of the integral:
+#' 
+#' \mjdeqn{ \mathcal{L}(\beta, \Sigma; \bf{Y}_i, \bf{X}_i) \approx \frac{1}{M} \Sigma_{m=1}^M \prod_{j=1}^J Pr(Y_{ij}|\bf{X}_i\beta+\zeta_m)}{}
+#' 
+#' with \mjeqn{ \zeta_m \sim MVN(0, \Sigma)}{}. 
 #' 
-#' sjSDM depends on the anaconda python distribution and pytorch, which need to be installed before being able to use the sjSDM function. 
+#' \code{sjSDM} uses 'PyTorch' to run optionally the model on the graphical processing unit (GPU). Python dependencies needs to be  
+#' installed before being able to use the \code{sjSDM} function. We provide a function which installs automatically python and the python dependencies.
 #' See \code{\link{install_sjSDM}}, \code{vignette("Dependencies", package = "sjSDM")}
 #' 
-#' @section Family:
+#' See Pichler and Hartig, 2020 for benchmark results.
+#' }
+#' 
+#' \subsection{Supported distributions}{
+#' 
 #' Currently supported distributions and link functions:
 #' \itemize{
 #' \item \code{\link{binomial}}: \code{"probit"} or \code{"logit"}
 #' \item \code{\link{poisson}}: \code{"log"} 
 #' \item \code{\link{gaussian}}: \code{"identity"} 
 #' }
+#' }
+#' 
+#' \subsection{Space}{
+#' 
+#' We can extend the model to account for spatial auto-correlation between the sites by:
+#' 
+#' \mjdeqn{g(Z_{ij}) = \beta_{j0} + \Sigma^{N}_{n=1}X_{in}\beta_{nj} + \Sigma^{M}_{m=1}S_{im}\alpha_{mj} + e_{ij}}{}
+#' 
+#' There are two ways to generate spatial predictors \mjeqn{S}{}:
+#' 
+#' \itemize{
+#' \item trend surface model - using spatial coordinates in a polynomial:
+#' 
+#'  \code{linear(data=Coords, ~0+poly(X, Y, degree = 2))} 
+#'  
+#' \item eigenvector spatial filtering - using spatial eigenvectors. 
+#'   Spatial eigenvectors can be generated by the \code{\link{generateSpatialEV}} function:
+#'   
+#'   \code{SPV = generateSpatialEV(Coords)}
+#'   
+#'   Then we use, for example, the first 20 spatial eigenvectors:
+#' 
+#'   \code{linear(data=SPV[ ,1:20], ~0+.)}
+#' }
+#' 
+#' It is important to set the intercept to 0 in the spatial term (e.g. via \code{~0+.}) because the intercept is already set in the environmental object.
+#' 
+#' }
+#' 
+#' \subsection{Installation}{
+#' 
+#' \code{\link{install_sjSDM}} should be theoretically able to install conda and 'PyTorch' automatically. If \code{\link{sjSDM}} still does not work after reloading RStudio, you can try to solve this on your following our trouble shooting guide \code{\link{installation_help}}.
+#' If the problem remains, please create an issue on \href{https://github.com/TheoreticalEcology/s-jSDM/issues}{issue tracker} with a copy of the \code{\link{install_diagnostic}} output as a quote. 
+#' }
+#' 
+#' @return 
+#' An S3 class of type 'sjSDM'. Implemented S3 methods include \code{\link{summary.sjSDM}}, \code{\link{plot.sjSDM}}, \code{\link{print.sjSDM}}, \code{\link{predict.sjSDM}}, and \code{\link{coef.sjSDM}}. For other methods, see section 'See Also'.
 #' 
-#' @section Installation:
-#' \code{\link{install_sjSDM}} should be theoretically able to install conda and pytorch automatically. If \code{\link{sjSDM}} still does not work after reloading RStudio, you can try to solve this in on your own with our trouble shooting guide \code{\link{installation_help}}.
-#' If the trouble shooting guide did not help, please create an issue on \href{https://github.com/TheoreticalEcology/s-jSDM/issues}{issue tracker} with a copy of the \code{\link{install_diagnostic}} output as a quote. 
 #' 
 #' @references 
 #' Chen, D., Xue, Y., & Gomes, C. P. (2018). End-to-end learning for the deep multivariate probit model. arXiv preprint arXiv:1803.08591.
 #' 
-#' Pichler, M., and Hartig, F. (2020). A new method for faster and more accurate inference of species associations from novel community data. arXiv preprint arXiv:2003.05331.
-#' 
+#' Pichler, M., & Hartig, F. (2021). A new joint species distribution model for faster and more accurate inference of species associations from big community data. Methods in Ecology and Evolution, 12(11), 2159-2173. 
 #' 
 #' @example /inst/examples/sjSDM-example.R
-#' @seealso \code{\link{sjSDM_cv}}, \code{\link{DNN}}, \code{\link{plot.sjSDM}}, \code{\link{print.sjSDM}}, \code{\link{predict.sjSDM}}, \code{\link{coef.sjSDM}}, \code{\link{summary.sjSDM}}, \code{\link{getCov}}, \code{\link{simulate.sjSDM}}, \code{\link{getSe}}, \code{\link{anova.sjSDM}}, \code{\link{importance}}
-#' @import checkmate
+#' @seealso \code{\link{update.sjSDM}}, \code{\link{sjSDM_cv}}, \code{\link{DNN}}, \code{\link{plot.sjSDM}}, \code{\link{print.sjSDM}}, \code{\link{predict.sjSDM}}, \code{\link{coef.sjSDM}}, \code{\link{summary.sjSDM}}, \code{\link{getCov}}, \code{\link{simulate.sjSDM}}, \code{\link{getSe}}, \code{\link{anova.sjSDM}}, \code{\link{importance}}
+#' 
+#' @import checkmate mathjaxr
 #' @author Maximilian Pichler
 #' @export
 sjSDM = function(Y = NULL, 
@@ -54,7 +133,7 @@ sjSDM = function(Y = NULL,
                  step_size = NULL,
                  learning_rate = 0.01, 
                  se = FALSE, 
-                 sampling = 1000L,
+                 sampling = 100L,
                  parallel = 0L, 
                  control = sjSDMControl(),
                  device = "cpu", 
@@ -168,16 +247,16 @@ sjSDM = function(Y = NULL,
                                   epochs = as.integer(iter), parallel = parallel, 
                                   sampling = as.integer(sampling),
                                   early_stopping_training=control$early_stopping_training)})[3]
-    out$logLik = model$logLik(env$X, Y,batch_size = step_size,parallel = parallel)
-    if(se && !inherits(env, "DNN")) try({ out$se = t(abind::abind(model$se(env$X, Y, batch_size = step_size, parallel = parallel),along=0L)) })
+    out$logLik = force_r( model$logLik(env$X, Y,batch_size = step_size,parallel = parallel) )
+    if(se && !inherits(env, "DNN")) try({ out$se = t(abind::abind(force_r(model$se(env$X, Y, batch_size = step_size, parallel = parallel)),along=0L)) })
   
   } else {
     time = system.time({model$fit(env$X, Y=Y,SP=spatial$X, batch_size = step_size, 
                                   epochs = as.integer(iter), parallel = parallel, 
                                   sampling = as.integer(sampling),
                                   early_stopping_training=control$early_stopping_training)})[3]
-    out$logLik = model$logLik(env$X, Y, SP=spatial$X, batch_size = step_size,parallel = parallel)
-    if(se && !inherits(env, "DNN")) try({ out$se = t(abind::abind(model$se(env$X, Y, SP=spatial$X,batch_size = step_size, parallel = parallel),along=0L)) })
+    out$logLik = force_r( model$logLik(env$X, Y, SP=spatial$X, batch_size = step_size,parallel = parallel) )
+    if(se && !inherits(env, "DNN")) try({ out$se = t(abind::abind(force_r(model$se(env$X, Y, SP=spatial$X,batch_size = step_size, parallel = parallel)),along=0L)) })
     
   }
 
@@ -193,18 +272,20 @@ sjSDM = function(Y = NULL,
     
   out$model = model
   out$settings = list(biotic = biotic, env = env, spatial = spatial,iter = iter, 
-                      step_size = step_size,learning_rate = learning_rate, 
-                      parallel = parallel,device = device, dtype = dtype, sampling = sampling)
+                      step_size = step_size,learning_rate = learning_rate, control = control, 
+                      parallel = parallel,device = device, dtype = dtype, sampling = sampling,
+                      se = se)
   out$family = family
   out$time = time
   out$data = list(X = env$X, Y = Y)
   out$sessionInfo = utils::sessionInfo()
-  out$weights = model$env_weights
-  out$sigma = model$get_sigma
-  out$history = model$history
-  out$spatial_weights = model$spatial_weights
+  out$weights = force_r(model$env_weights)
+  out$sigma = force_r(model$get_sigma)
+  out$history = force_r(model$history)
+  out$spatial_weights = force_r(model$spatial_weights)
   out$spatial = spatial
-  torch$cuda$empty_cache()
+  out$Null = NULL
+  .n = torch$cuda$empty_cache()
   return(out)
 }
 
@@ -247,7 +328,7 @@ predict.sjSDM = function(object, newdata = NULL, SP = NULL, type = c("link", "ra
     
     
     if(is.null(newdata)) {
-      return(object$model$predict(newdata = object$data$X, SP = object$spatial$X, link=link, dropout = dropout, ...))
+      return(force_r( object$model$predict(newdata = object$data$X, SP = object$spatial$X, link=link, dropout = dropout, ...)))
     } else {
       
       if(is.data.frame(newdata)) {
@@ -263,14 +344,14 @@ predict.sjSDM = function(object, newdata = NULL, SP = NULL, type = c("link", "ra
       }
       
     }
-    pred = object$model$predict(newdata = newdata, SP = sp, link=link, dropout = dropout, ...)
+    pred = force_r(object$model$predict(newdata = newdata, SP = sp, link=link, dropout = dropout, ...))
     return(pred)
     
     
   } else {
     
     if(is.null(newdata)) {
-      return(object$model$predict(newdata = object$data$X, link=link))
+      return(force_r(object$model$predict(newdata = object$data$X, link=link)))
     } else {
       if(is.data.frame(newdata)) {
         newdata = stats::model.matrix(object$formula, newdata)
@@ -278,7 +359,7 @@ predict.sjSDM = function(object, newdata = NULL, SP = NULL, type = c("link", "ra
         newdata = stats::model.matrix(object$formula, data.frame(newdata))
       }
     }
-    pred = object$model$predict(newdata = newdata, link=link, dropout = dropout, ...)
+    pred = force_r(object$model$predict(newdata = newdata, link=link, dropout = dropout, ...))
     return(pred)
     
   }
@@ -310,8 +391,8 @@ getSe = function(object, step_size = NULL, parallel = 0L){
   object = checkModel(object)
   if(is.null(step_size)) step_size = object$settings$step_size
   else step_size = as.integer(step_size)
-  if(!inherits(object, "spatialRE")) try({ object$se = t(abind::abind(object$model$se(object$data$X, object$data$Y, batch_size = step_size, parallel = parallel),along=0L)) })
-  else try({ object$se = t(abind::abind(object$model$se(object$data$X, object$data$Y, object$spatial$re, batch_size = step_size, parallel = parallel),along=0L)) })
+  if(!inherits(object, "spatialRE")) try({ object$se = t(abind::abind(force_r(object$model$se(object$data$X, object$data$Y, batch_size = step_size, parallel = parallel)),along=0L)) })
+  else try({ object$se = t(abind::abind(force_r(object$model$se(object$data$X, object$data$Y, object$spatial$re, batch_size = step_size, parallel = parallel)),along=0L)) })
   return(object)
 }
 
@@ -325,7 +406,6 @@ summary.sjSDM = function(object, ...) {
   out = list()
   
   cat("LogLik: ", -object$logLik[[1]], "\n")
-  cat("Deviance: ", 2*object$logLik[[1]], "\n\n")
   cat("Regularization loss: ", object$logLik[[2]], "\n\n")
   
   cov_m = getCov(object)
@@ -377,14 +457,6 @@ summary.sjSDM = function(object, ...) {
       else colnames(env) = object$species
       rownames(env) = object$names
     
-      
-      # if(inherits(object, "spatialRE")) {
-      #   cat("Spatial random effects (Intercept): \n")
-      #   cat("\tVar: ", round(stats::var(object$re), 3), "\n\tStd. Dev.: ", round(stats::sd(object$re), 3), "")
-      #   cat("\n\n\n")
-      # }
-      # 
-      
       # TO DO: p-value parsing:
       if(!is.null(object$se)) {
         out$z = env2 / object$se
@@ -458,3 +530,68 @@ simulate.sjSDM = function(object, nsim = 1, seed = NULL, ...) {
 logLik.sjSDM <- function(object, ...){
   return(object$logLik[[1]])
 }
+
+
+
+
+#' Update and re-fit a model call
+#' 
+#' @param object of class 'sjSDM'
+#' @param env_formula new environmental formula
+#' @param spatial_formula new spatial formula
+#' @param biotic new biotic config
+#' @param ... additional arguments
+#' 
+#' @return An S3 class of type 'sjSDM'.
+#' @export
+update.sjSDM = function(object, env_formula = NULL, spatial_formula = NULL, biotic = NULL, ...) {
+  
+  mf = match.call()
+  if(!is.null(env_formula)){
+    m = match("env_formula", names(mf))
+    if(class(mf[3]$env_formula) == "name") mf[3]$env_formula = eval(mf[3]$env_formula, envir = parent.env(environment()))
+    env_formula = stats::as.formula(mf[m]$env_formula)
+  } else {
+    env_formula = object$settings$env$formula
+  }
+  
+  if(!is.null(spatial_formula)){
+    m = match("spatial_formula", names(mf))
+    if(class(mf[4]$spatial_formula) == "name") mf[4]$spatial_formula = eval(mf[4]$spatial_formula, envir = parent.env(environment()))
+    spatial_formula = stats::as.formula(mf[m]$spatial_formula)
+  } else {
+    spatial_formula = object$settings$spatial$formula
+  }
+  
+  if(is.null(biotic)) {
+    biotic = object$settings$biotic
+  } 
+  
+  env = object$settings$env
+  env$formula = env_formula
+  env$X = stats::model.matrix(env_formula, env$data)
+  
+  if(inherits(object, "spatial")) {
+    spatial = object$settings$spatial
+    spatial$formula = spatial_formula
+    spatial$X = stats::model.matrix(spatial_formula, spatial$data)
+  } else {
+    spatial = NULL
+  }
+  
+  new_model = sjSDM(object$data$Y, 
+                    env = env, 
+                    spatial = spatial,
+                    biotic = biotic,
+                    family = object$family$family, 
+                    iter = object$settings$iter, 
+                    step_size = object$settings$step_size, 
+                    learning_rate = object$settings$learning_rate,
+                    sampling = object$settings$sampling,
+                    control = object$settings$control,
+                    device = object$settings$device, 
+                    dtype = object$settings$dtype,
+                    se = object$settings$se
+  )
+  return(new_model)
+}
\ No newline at end of file
diff --git a/sjSDM/R/sjSDM_configs.R b/sjSDM/R/sjSDM_configs.R
index ba8b02a..fe37ba8 100644
--- a/sjSDM/R/sjSDM_configs.R
+++ b/sjSDM/R/sjSDM_configs.R
@@ -3,7 +3,7 @@
 #' specify the model to be fitted
 #' @param data matrix of environmental predictors
 #' @param formula formula object for predictors
-#' @param lambda lambda penality, strength of regularization: \eqn{\lambda * (lasso + ridge)}
+#' @param lambda lambda penalty, strength of regularization: \eqn{\lambda * (lasso + ridge)}
 #' @param alpha weighting between lasso and ridge: \eqn{(1 - \alpha) * |coefficients| + \alpha ||coefficients||^2}
 #' 
 #' @seealso \code{\link{DNN}}, \code{\link{sjSDM}}
@@ -36,11 +36,12 @@ linear = function(data = NULL, formula = NULL, lambda = 0.0, alpha = 0.5) {
       m = match("formula", names(mf))
       if(class(mf[3]$formula) == "name") mf[3]$formula = eval(mf[3]$formula, envir = parent.env(environment()))
       formula = stats::as.formula(mf[m]$formula)
-      X = data.frame(data)
-      X = stats::model.matrix(formula, X)
+      data = data.frame(data)
+      X = stats::model.matrix(formula, data)
     } else {
       formula = stats::as.formula("~.")
-      X = stats::model.matrix(formula,data.frame(data))
+      data = data.frame(data)
+      X = stats::model.matrix(formula,data)
     }
   }
   
@@ -51,6 +52,7 @@ linear = function(data = NULL, formula = NULL, lambda = 0.0, alpha = 0.5) {
   out = list()
   out$formula = formula
   out$X = X
+  out$data = data
   out$l1_coef = (1-alpha)*lambda
   out$l2_coef = alpha*lambda
   class(out) = "linear"
@@ -67,7 +69,7 @@ print.linear = function(x, ...) {
 }
 
 
-#' Non-linear nodel (deep neural network) of environmental responses
+#' Non-linear model (deep neural network) of environmental responses
 #' 
 #' specify the model to be fitted
 #' @param data matrix of environmental predictors
@@ -114,16 +116,18 @@ DNN = function(data = NULL, formula = NULL, hidden = c(10L, 10L, 10L), activatio
       m = match("formula", names(mf))
       if(class(mf[3]$formula) == "name") mf[3]$formula = eval(mf[3]$formula, envir = parent.env(environment()))
       formula = stats::as.formula(mf[m]$formula)
-      X = data.frame(data)
-      X = stats::model.matrix(formula, X)
+      data = data.frame(data)
+      X = stats::model.matrix(formula, data)
     } else {
       formula = stats::as.formula("~.")
-      X = stats::model.matrix(formula,data.frame(data))
+      data = data.frame(data)
+      X = stats::model.matrix(formula, data)
     }
   }
   out = list()
   out$formula = formula
   out$X = X
+  out$data = data
   out$l1_coef = (1-alpha)*lambda
   out$l2_coef = alpha*lambda
   out$hidden = as.integer(hidden)
@@ -149,14 +153,14 @@ print.DNN = function(x, ...) {
 
 #' biotic structure
 #' 
-#' define biotic (species-species) assocation (interaction) structur
+#' define biotic (species-species) association (interaction) structure
 #' @param df degree of freedom for covariance parametrization, if \code{NULL} df is set to \code{ncol(Y)/2}
-#' @param lambda lambda penality, strength of regularization: \eqn{\lambda * (lasso + ridge)}
+#' @param lambda lambda penalty, strength of regularization: \eqn{\lambda * (lasso + ridge)}
 #' @param alpha weighting between lasso and ridge: \eqn{(1 - \alpha) * |covariances| + \alpha ||covariances||^2}
 #' @param on_diag regularization on diagonals 
 #' @param reg_on_Cov regularization on covariance matrix 
 #' @param inverse regularization on the inverse covariance matrix
-#' @param diag use diagonal marix with zeros (internal usage)
+#' @param diag use diagonal matrix with zeros (internal usage)
 #' 
 #' @seealso \code{\link{sjSDM}}
 #' @example /inst/examples/sjSDM-example.R
@@ -405,7 +409,7 @@ madgrad = function(momentum=0.9, weight_decay=0, eps=1e-6) {
 #' accelerated stochastic gradient, see Kidambi et al., 2018 for details
 #' @param kappa long step
 #' @param xi advantage parameter
-#' @param small_const small_const
+#' @param small_const small constant
 #' @param weight_decay l2 penalty on weights
 #' 
 #' @references 
diff --git a/sjSDM/R/tuning.R b/sjSDM/R/sjSDM_cv.R
similarity index 82%
rename from sjSDM/R/tuning.R
rename to sjSDM/R/sjSDM_cv.R
index dceb4f2..711ca8b 100644
--- a/sjSDM/R/tuning.R
+++ b/sjSDM/R/sjSDM_cv.R
@@ -15,17 +15,26 @@
 #' @param lambda_spatial overall regularization strength on spatial coefficients
 #' @param device device, default cpu
 #' @param n_cores number of cores for parallelization 
-#' @param n_gpu number of gpus
-#' @param sampling number of sampling steps for Monte Carlo integreation
-#' @param blocks blocks of parallen tuning steps
+#' @param n_gpu number of GPUs
+#' @param sampling number of sampling steps for Monte Carlo integration
+#' @param blocks blocks of parallel tuning steps
 #' @param ... arguments passed to sjSDM, see \code{\link{sjSDM}}
 #' 
+#' @return 
+#' An S3 class of type 'sjSDM_cv'. Implemented S3 methods include \code{\link{sjSDM.tune}}, \code{\link{plot.sjSDM_cv}}, \code{\link{print.sjSDM_cv}}, and \code{\link{summary.sjSDM_cv}}
+#' 
 #' @example /inst/examples/sjSDM_cv-example.R
-#' @seealso \code{\link{plot.sjSDM_cv}}, \code{\link{print.sjSDM_cv}}, \code{\link{summary.sjSDM_cv}}
+#' @seealso \code{\link{plot.sjSDM_cv}}, \code{\link{print.sjSDM_cv}}, \code{\link{summary.sjSDM_cv}}, \code{\link{sjSDM.tune}}
 #' @import checkmate
 #' @export
 
-sjSDM_cv = function(Y, env = NULL, biotic = bioticStruct(), spatial = NULL, tune = c("random", "grid"), CV = 5L, tune_steps = 20L,
+sjSDM_cv = function(Y, 
+                    env = NULL, 
+                    biotic = bioticStruct(), 
+                    spatial = NULL, 
+                    tune = c("random", "grid"), 
+                    CV = 5L, 
+                    tune_steps = 20L,
                     alpha_cov = seq(0.0, 1.0, 0.1), 
                     alpha_coef = seq(0.0, 1.0, 0.1),
                     alpha_spatial = seq(0.0, 1.0, 0.1), 
@@ -57,6 +66,7 @@ sjSDM_cv = function(Y, env = NULL, biotic = bioticStruct(), spatial = NULL, tune
   qassert(sampling, "X1[0,)")
   qassert(blocks, "X1[1,)")
   
+  ellip = list(...)
   
   tune = match.arg(tune)
   if(is.matrix(env) || is.data.frame(env)) env = linear(data = env)
@@ -66,19 +76,29 @@ sjSDM_cv = function(Y, env = NULL, biotic = bioticStruct(), spatial = NULL, tune
   test_indices = lapply(unique(set), function(s) which(set == s, arr.ind = TRUE))
   
   if(is.null(spatial)) {
-    tune_grid = expand.grid(alpha_cov, alpha_coef, lambda_cov, lambda_coef)
-    colnames(tune_grid) = c("alpha_cov", "alpha_coef", "lambda_cov", "lambda_coef")
-  } else {
-    tune_grid = expand.grid(alpha_cov, alpha_coef,alpha_spatial, lambda_cov, lambda_coef, lambda_spatial)
-    colnames(tune_grid) = c("alpha_cov", "alpha_coef", "alpha_spatial","lambda_cov", "lambda_coef", "lambda_spatial")
-  }
-  
-  if(tune == "random") {
-    tune_samples = tune_grid[sample.int(nrow(tune_grid), tune_steps),]
+    if(tune == "random") { 
+      tune_samples = data.frame(t(sapply(1:tune_steps, function(i) c(sample(alpha_cov, 1), 
+                                                                  sample(alpha_coef, 1),
+                                                                  sample(lambda_cov, 1),
+                                                                  sample(lambda_coef, 1)))))
+    } else {
+      tune_samples = expand.grid(alpha_cov, alpha_coef, lambda_cov, lambda_coef)
+    }
+    colnames(tune_samples) = c("alpha_cov", "alpha_coef", "lambda_cov", "lambda_coef")
   } else {
-    tune_samples = tune_grid
+    if(tune == "random") { 
+      tune_samples = data.frame(t(sapply(1:tune_steps, function(i) c(sample(alpha_cov, 1), 
+                                                                  sample(alpha_coef, 1),
+                                                                  sample(alpha_spatial, 1),
+                                                                  sample(lambda_cov, 1),
+                                                                  sample(lambda_coef, 1),
+                                                                  sample(lambda_spatial, 1)))))
+    } else {
+      tune_samples = expand.grid(alpha_cov, alpha_coef,alpha_spatial, lambda_cov, lambda_coef, lambda_spatial)
+    }
+    colnames(tune_samples) = c("alpha_cov", "alpha_coef", "alpha_spatial","lambda_cov", "lambda_coef", "lambda_spatial")
   }
-  
+
   
   tune_func = function(t){
 
@@ -139,7 +159,6 @@ sjSDM_cv = function(Y, env = NULL, biotic = bioticStruct(), spatial = NULL, tune
         model = sjSDM(Y = Y_train, env = new_env, biotic = biotic, spatial = new_spatial,device=device, sampling=sampling,...)
       }
       
-      #model$model$set_sigma(matrix(0.0, ncol(Y_train), model$model$df))
       mean_func = function(f) apply(abind::abind(lapply(1:50, function(i) f() ),along = -1), 2:3, mean)
       
       pred_test = mean_func(function() predict.sjSDM(model, newdata = X_test, SP = SP_test) )
@@ -158,7 +177,7 @@ sjSDM_cv = function(Y, env = NULL, biotic = bioticStruct(), spatial = NULL, tune
       ll_train = logLik.sjSDM(model)
       bs =  as.integer(model$settings$step_size)
       if(bs > nrow(X_test)) bs = 1L
-      ll_test =  mean(sapply(1:20, function(i) model$model$logLik(X_test, Y_test, SP = SP_test, batch_size =bs, sampling=sampling)[[1]] ))
+      ll_test =  mean(sapply(1:20, function(i) force_r( model$model$logLik(X_test, Y_test, SP = SP_test, batch_size =bs, sampling=sampling) )[[1]] ))
       cv_step_result[[i]] = list(indices = test_indices[[i]], 
                                  pars = tune_samples[t,],
                                  pred_test = pred_test,
@@ -190,7 +209,8 @@ sjSDM_cv = function(Y, env = NULL, biotic = bioticStruct(), spatial = NULL, tune
     nodes = unlist(parallel::clusterEvalQ(cl, paste(Sys.info()[['nodename']], Sys.getpid(), sep='-')))
     #print(nodes)
     control = parallel::clusterEvalQ(cl, {library(sjSDM)})
-    parallel::clusterExport(cl, list("tune_samples", "test_indices","biotic", "CV", "env","spatial", "Y", "nodes","n_gpu","n_cores","device","sampling","..."), envir = environment())
+    if(length(ellip) > 0 ) parallel::clusterExport(cl, list("tune_samples", "test_indices","biotic", "CV", "env","spatial", "Y", "nodes","n_gpu","n_cores","device","sampling","..."), envir = environment())
+    else parallel::clusterExport(cl, list("tune_samples", "test_indices","biotic", "CV", "env","spatial", "Y", "nodes","n_gpu","n_cores","device","sampling"), envir = environment())
     
     for(i in 1:length(unique(blocks_run))){
       ind = blocks_run == unique(blocks_run)[i]
@@ -246,12 +266,80 @@ sjSDM_cv = function(Y, env = NULL, biotic = bioticStruct(), spatial = NULL, tune
     short_summary$l1_sp = (1-short_summary$alpha_sp)*short_summary$lambda_sp
     short_summary$l2_sp = short_summary$alpha_sp*short_summary$lambda_sp
   }
-  
-  out = list(tune_results = result, short_summary = short_summary, summary = summary_results, settings = list(tune_samples = tune_samples, CV = CV, tune = tune))
+  out = list(tune_results = result, 
+             short_summary = short_summary, 
+             summary = summary_results, 
+             settings = list(tune_samples = tune_samples, CV = CV, tune = tune),
+             data = list(Y = Y, env = env, biotic = biotic, spatial = spatial),
+             config = c(list(device=device, sampling=sampling), as.list(unlist(ellip))),
+             spatial = !is.null(spatial))
   class(out) = c("sjSDM_cv")
   return(out)
 }
 
+zero_one = function(x) (x-min(x))/(max(x) - min(x))
+
+#' @rdname sjSDM
+#' @param object object of type \code{\link{sjSDM_cv}}
+#' @author Maximilian Pichler
+#' @export
+sjSDM.tune = function(object) {
+  if(!inherits(object, "sjSDM_cv")) stop("Object must be of type sjSDM_cv, see function ?sjSDM_cv")
+  x = object$short_summary
+  maxP = which.min(x[["logLik"]])
+  
+  if(object$spatial) {
+    best_values = 
+      c(lambda_cov = x[maxP,]$lambda_cov,
+        alpha_cov = x[maxP,]$alpha_cov,
+        lambda_coef =  x[maxP,]$lambda_coef,
+        alpha_coef = x[maxP,]$alpha_coef,
+        lambda_spatial =  x[maxP,]$lambda_spatial,
+        alpha_spatial = x[maxP,]$alpha_spatial)
+  } else {
+    best_values = 
+      c(lambda_cov = x[maxP,]$lambda_cov,
+        alpha_cov = x[maxP,]$alpha_cov,
+        lambda_coef =  x[maxP,]$lambda_coef,
+        alpha_coef = x[maxP,]$alpha_coef)
+  }
+  spatial = object$data$spatial
+  env = object$data$env
+  biotic = object$data$biotic
+  settings = object$config
+  
+  ## update env regularization ##
+  lambda_coef = best_values[["lambda_coef"]]
+  if(lambda_coef == 0.0) {
+    lambda_coef = -99.9
+  }
+  env$l1_coef = (1-best_values[["alpha_coef"]])*lambda_coef
+  env$l2_coef = best_values[["alpha_coef"]]*lambda_coef
+  
+  ## update biotic regularization ##
+  biotic$l1_cov = (1-best_values[["alpha_cov"]])*best_values[["lambda_cov"]]
+  biotic$l2_cov = best_values[["alpha_cov"]]*best_values[["lambda_cov"]]
+  
+  ## update space ##
+  if(object$spatial) {
+    lambda_spatial = best_values[["lambda_spatial"]]
+    if(lambda_spatial == 0.0) {
+      lambda_spatial = -99.9
+    }
+    spatial$l1_coef = (1-best_values[["alpha_spatial"]])*lambda_spatial
+    spatial$l2_coef = best_values[["alpha_spatial"]]*lambda_spatial
+  }
+  
+  settings = c(list(Y = object$data$Y,
+                    env = env,
+                    spatial = spatial,
+                    biotic = biotic),
+               settings
+               )
+  model = do.call(sjSDM, settings)
+  return(model)
+}
+
 
 #' Print a fitted sjSDM_cv model
 #' 
@@ -301,7 +389,6 @@ plot.sjSDM_cv = function(x, y, perf = c("logLik", "AUC", "AUC_macro"), resolutio
   yn1 = seq(min(x$lambda_cov), max(x$lambda_cov), length.out = resolution)
   xn2 = seq(min(x$alpha_coef), max(x$alpha_coef), length.out = resolution)
   yn2 = seq(min(x$lambda_coef), max(x$lambda_coef), length.out = resolution)
-  
   if(spatial) {
     
     xn3 = seq(min(x$alpha_spatial), max(x$alpha_spatial), length.out = resolution)
@@ -347,7 +434,7 @@ plot.sjSDM_cv = function(x, y, perf = c("logLik", "AUC", "AUC_macro"), resolutio
     res_spatial = apply(res_spatial, 2:3, mean)
     
     x_scaled = x[,1:6]
-    x_scaled = sapply(x_scaled, function(s) scales::rescale(s, c(0,1)))
+    x_scaled = sapply(x_scaled, function(s) zero_one(s))
   } else {
     
     d = data.frame(expand.grid(xn1, yn1, xn2, yn2))
@@ -373,7 +460,7 @@ plot.sjSDM_cv = function(x, y, perf = c("logLik", "AUC", "AUC_macro"), resolutio
     res_cov = apply(res_cov, 2:3, mean)
     
     x_scaled = x[,1:4]
-    x_scaled = sapply(x_scaled, function(s) scales::rescale(s, c(0,1)))
+    x_scaled = sapply(x_scaled, function(s) zero_one(s))
   
   }
   
@@ -506,8 +593,8 @@ plot.sjSDM_cv = function(x, y, perf = c("logLik", "AUC", "AUC_macro"), resolutio
 #' @param range rescale to range
 new_image = function(z, cols= (grDevices::colorRampPalette(c("white", "#24526E"), bias = 1.5))(10), range = c(0.5, 1.0)) {
   graphics::plot(NULL, NULL , axes = FALSE, xlab = "", ylab = "", xlim = c(0,1), ylim = c(0,1))
-  x = scales::rescale(z[,2], c(0,1))
-  y = scales::rescale(z[,3], c(0,1))
+  x = zero_one(z[,2])
+  y = zero_one(z[,3])
   zz =cut(z[,1], breaks = seq(range[1], range[2], length.out = length(cols) + 1))
   levels(zz) = cols
   zz = as.character(zz)
diff --git a/sjSDM/R/utils.R b/sjSDM/R/utils.R
index a423c77..53e3b53 100644
--- a/sjSDM/R/utils.R
+++ b/sjSDM/R/utils.R
@@ -14,17 +14,6 @@ is_torch_available = function() {
   }
 }
 
-#' is_sjSDM_py_available
-#' check whetcher torch is available
-is_sjSDM_py_available = function() {
-  #implementation_module <- resolve_implementation_module()
-  if (reticulate::py_module_available("sjSDM_py")) {
-    TRUE
-  } else {
-    FALSE
-  }
-}
-
 createSplit = function(n=NULL,CV=5) {
   set = cut(sample.int(n), breaks = CV, labels = FALSE)
   test_indices = lapply(unique(set), function(s) which(set == s, arr.ind = TRUE))
@@ -53,10 +42,10 @@ checkModel = function(object) {
     object$model$set_sigma(reticulate::r_to_py(object$sigma)$copy())
   }
   
-  if(inherits(object, "sLVM")) {
-    unserialize_state(object, object$state)
-    object$model$set_posterior_samples(lapply(object$posterior_samples, function(p) torch$tensor(p, dtype=object$model$dtype, device=object$model$device)))
-  }
+  # if(inherits(object, "sLVM")) {
+  #   unserialize_state(object, object$state)
+  #   object$model$set_posterior_samples(lapply(object$posterior_samples, function(p) torch$tensor(p, dtype=object$model$dtype, device=object$model$device)))
+  # }
   return(object)
 }
 
@@ -77,8 +66,9 @@ is_linux = function() {
   identical(tolower(Sys.info()[["sysname"]]), "linux")
 }
 
-#' check modul
-#' check if modul is loaded
+#' check module
+#' 
+#' check if module is loaded
 check_module = function(){
   if(!exists("fa")){
     .onLoad()
@@ -104,11 +94,11 @@ parse_nn = function(nn) {
   for(i in 1:length(layers)) {
     type = strsplit(class(slices[[i]]), ".", fixed = TRUE)[[1]]
     
-    if(layers[i] == "Linear") {
-      wM[i, 1] = slices[[i]]$in_features
-      wM[i, 2] = slices[[i]]$out_features
+    if(layers[i] %in% "Linear") {
+      wM[i, 1] = force_r( slices[[i]]$in_features )
+      wM[i, 2] = force_r( slices[[i]]$out_features )
       txt = paste0(txt, paste0("Layer_", i),":",
-                   "\t (", slices[[i]]$in_features, ", ",slices[[i]]$out_features, ")\n"
+                   "\t (", force_r( slices[[i]]$in_features ), ", ",force_r( slices[[i]]$out_features ), ")\n"
                    )
     } else {
       txt = paste0(txt, paste0("Layer_", i),":",
@@ -123,20 +113,6 @@ parse_nn = function(nn) {
 }
 
 
-serialize_state = function(model) {
-  tmp = tempfile(pattern = "svi state")
-  on.exit(unlink(tmp), add = TRUE)
-  model$pyro$get_param_store()$save(tmp)
-  return(readBin(tmp, what = "raw", n = file.size(tmp), size=1))
-}
-
-unserialize_state = function(model, state) {
-  tmp = tempfile(pattern = "svi state")
-  on.exit(unlink(tmp), add = TRUE)
-  writeBin(state, tmp)
-  model$model$pyro$get_param_store()$load(tmp)
-}
-
 
 #' Generate spatial eigenvectors
 #' 
@@ -171,4 +147,19 @@ generateSpatialEV = function(coords = NULL, threshold = 0.0) {
   SV = eigV$vectors[, values>0]
   colnames(SV) = paste0("SE_", 1:ncol(SV))
   return(SV)
-}
\ No newline at end of file
+}
+
+force_r = function(x) {
+  if(inherits(x, "python.builtin.object")) return(reticulate::py_to_r( x ))
+  else return(x)
+}
+
+check_installation = function() {
+  # check if dependencies are installed
+  torch_ = pyro_ = torch_optimizer_ = madgrad_ = c(crayon::red(cli::symbol$cross), 0)
+  if(reticulate::py_module_available("torch")) torch_ =  c(crayon::green(cli::symbol$tick), 1)
+  if(reticulate::py_module_available("pyro")) pyro_ =  c(crayon::green(cli::symbol$tick), 1)
+  if(reticulate::py_module_available("torch_optimizer")) torch_optimizer_ =  c(crayon::green(cli::symbol$tick), 1)
+  if(reticulate::py_module_available("madgrad")) madgrad_ =  c(crayon::green(cli::symbol$tick), 1)
+  return(rbind("torch" = torch_,  "torch_optimizer" = torch_optimizer_, "pyro" = pyro_, "madgrad" = madgrad_))
+}
diff --git a/sjSDM/R/zzz.R b/sjSDM/R/zzz.R
index 32ddbd2..9d846ee 100644
--- a/sjSDM/R/zzz.R
+++ b/sjSDM/R/zzz.R
@@ -1,34 +1,33 @@
-check_installation = function() {
+.onLoad = function(libname, pkgname){
+  msg( text_col( cli::rule(left = "Attaching sjSDM", right = utils::packageVersion("sjSDM")) ), startup = TRUE)
   
-  torch_ = pyro_ = torch_optimizer_ = madgrad_ = c(crayon::red(cli::symbol$cross), 0)
+  # causes problems on macOS systems
+  if( is_osx() ) Sys.setenv( KMP_DUPLICATE_LIB_OK=TRUE ) 
   
-  if(reticulate::py_module_available("torch")) torch_ =  c(crayon::green(cli::symbol$tick), 1)
-  if(reticulate::py_module_available("pyro")) pyro_ =  c(crayon::green(cli::symbol$tick), 1)
-  if(reticulate::py_module_available("torch_optimizer")) torch_optimizer_ =  c(crayon::green(cli::symbol$tick), 1)
-  if(reticulate::py_module_available("madgrad")) madgrad_ =  c(crayon::green(cli::symbol$tick), 1)
+  # load r-sjsdm environment
+  success_env = try({
+    envs = reticulate::conda_list()
+    env_path = envs[which(envs$name %in% "r-sjsdm", arr.ind = TRUE), 2]
+    reticulate::use_python(env_path, required = TRUE)
+  }, silent = TRUE)
   
-  return(rbind("torch" = torch_,  "torch_optimizer" = torch_optimizer_, "pyro" = pyro_, "madgrad" = madgrad_))
-}
-
-.onLoad = function(libname, pkgname){
-  msg( text_col( cli::rule(left = "Attaching sjSDM", right = packageVersion("sjSDM")) ), startup = TRUE)
+  # check if dependencies are installed
   check = check_installation()
   
+  # load modules only if dependencies are available
   modules_available = any(check[,2] == "0")
   if(!modules_available) {
-    torch <<- reticulate::import("torch")
+    # load torch
+    torch <<- reticulate::import("torch", delay_load = list(environment = "r-torch"), convert = FALSE )  
     
+    # 'compile' and load sjSDM python package
     path = system.file("python", package = "sjSDM")
-    
-    Sys.setenv( KMP_DUPLICATE_LIB_OK=TRUE )
-    
     try({
-      compile = reticulate::import("compileall")
+      compile = reticulate::import("compileall", delay_load = TRUE)
       tmp = compile$compile_dir(paste0(path, "/sjSDM_py"),quiet = 2L,force=TRUE)
     }, silent = TRUE)
-    fa <<- reticulate::import_from_path("sjSDM_py", path)
-    
-    check= cbind(check, crayon::black( c(torch$`__version__`, rep("", 3))) )
+    fa <<- reticulate::import_from_path("sjSDM_py", path, delay_load = list(environment = "r-fa"), convert = FALSE)
+    check= cbind(check, crayon::black( c(torch$`__version__`, rep("", 3))))
   } 
   
   check[,2] = crayon::black( rownames(check) )
diff --git a/sjSDM/README.Rmd b/sjSDM/README.Rmd
new file mode 100644
index 0000000..665c834
--- /dev/null
+++ b/sjSDM/README.Rmd
@@ -0,0 +1,85 @@
+---
+output: github_document
+---
+<!-- README.md is generated from README.Rmd. Please edit that file -->
+
+
+```{r setup, include=FALSE}
+knitr::opts_chunk$set(echo = TRUE, collapse = TRUE)
+```
+
+
+# sjSDM - Fast and accurate Joint Species Distribution Modeling
+
+[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
+![R-CMD-check](https://github.com/TheoreticalEcology/s-jSDM/workflows/R-CMD-check/badge.svg?branch=master)
+[![Publication](https://img.shields.io/badge/Publication-10.1111/2041-green.svg)](https://besjournals.onlinelibrary.wiley.com/doi/abs/10.1111/2041-210X.13687)
+
+## Overview
+
+A scalable method to estimates joint Species Distribution Models (jSDMs) based on the multivariate probit model through Monte-Carlo approximation of the joint likelihood. The numerical approximation is based on 'PyTorch' and 'reticulate', and can be calculated on CPUs and GPUs alike. 
+
+The method is described in [Pichler & Hartig (2021)](https://besjournals.onlinelibrary.wiley.com/doi/abs/10.1111/2041-210X.13687) A new joint species distribution model for faster and more accurate inference of species associations from big community data.
+
+The package includes options to fit various different (j)SDM models:
+
+* jSDMs with Binomial, Poisson and Normal distributed responses
+* jSDMs based on deep neural networks
+* Spatial auto-correlation can be accounted for by spatial eigenvectors or trend surface polynomials 
+
+To get more information, install the package and run
+
+```{r, eval=FALSE}
+library(sjSDM)
+?sjSDM
+vignette("sjSDM", package="sjSDM")
+```
+
+## Installation
+
+__sjSDM__ is based on 'PyTorch', a 'python' library, and thus requires 'python' dependencies. The 'python' dependencies can be automatically installed by running:
+
+```{r,eval=FALSE}
+library(sjSDM)
+install_sjSDM()
+```
+
+If this didn't work, please check the troubleshooting guide:
+```{r,eval=FALSE}
+library(sjSDM)
+?installation_help
+```
+
+## Usage
+
+Let's first simulate a community data set:
+
+```{r}
+library(sjSDM)
+set.seed(42)
+community <- simulate_SDM(sites = 100, species = 10, env = 3, se = TRUE)
+Env <- community$env_weights
+Occ <- community$response
+SP <- matrix(rnorm(200, 0, 0.3), 100, 2) # spatial coordinates (no effect on species occurences)
+```
+
+Estimate jSDM:
+
+```{r}
+model <- sjSDM(Y = Occ, env = linear(data = Env, formula = ~X1), spatial = linear(data = SP, formula = ~0+X1:X2), se = TRUE, family=binomial("probit"), sampling = 100L)
+summary(model)
+```
+
+Update model (change main effects to quadratic effects):
+
+```{r}
+model2 <- update(model, env_formula = ~I(X1^2))
+summary(model2)
+```
+
+Change linear part of model to a deep neural network:
+
+```{r}
+DNN <- sjSDM(Y = Occ, env = DNN(data = Env, formula = ~.), spatial = linear(data = SP, formula = ~0+X1:X2), se = TRUE, family=binomial("probit"), sampling = 100L)
+summary(DNN)
+```
diff --git a/sjSDM/README.md b/sjSDM/README.md
new file mode 100644
index 0000000..6c5fc9c
--- /dev/null
+++ b/sjSDM/README.md
@@ -0,0 +1,227 @@
+
+<!-- README.md is generated from README.Rmd. Please edit that file -->
+
+# sjSDM - Fast and accurate Joint Species Distribution Modeling
+
+[![License: GPL
+v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
+![R-CMD-check](https://github.com/TheoreticalEcology/s-jSDM/workflows/R-CMD-check/badge.svg?branch=master)
+[![Publication](https://img.shields.io/badge/Publication-10.1111/2041-green.svg)](https://besjournals.onlinelibrary.wiley.com/doi/abs/10.1111/2041-210X.13687)
+
+## Overview
+
+A scalable method to estimates joint Species Distribution Models (jSDMs)
+based on the multivariate probit model through Monte-Carlo approximation
+of the joint likelihood. The numerical approximation is based on
+‘PyTorch’ and ‘reticulate’, and can be calculated on CPUs and GPUs
+alike.
+
+The method is described in [Pichler & Hartig
+(2021)](https://besjournals.onlinelibrary.wiley.com/doi/abs/10.1111/2041-210X.13687)
+A new joint species distribution model for faster and more accurate
+inference of species associations from big community data.
+
+The package includes options to fit various different (j)SDM models:
+
+-   jSDMs with Binomial, Poisson and Normal distributed responses
+-   jSDMs based on deep neural networks
+-   Spatial auto-correlation can be accounted for by spatial
+    eigenvectors or trend surface polynomials
+
+To get more information, install the package and run
+
+``` r
+library(sjSDM)
+?sjSDM
+vignette("sjSDM", package="sjSDM")
+```
+
+## Installation
+
+**sjSDM** is based on ‘PyTorch’, a ‘python’ library, and thus requires
+‘python’ dependencies. The ‘python’ dependencies can be automatically
+installed by running:
+
+``` r
+library(sjSDM)
+install_sjSDM()
+```
+
+If this didn’t work, please check the troubleshooting guide:
+
+``` r
+library(sjSDM)
+?installation_help
+```
+
+## Usage
+
+Let’s first simulate a community data set:
+
+``` r
+library(sjSDM)
+## ── Attaching sjSDM ──────────────────────────────────────────────────── 1.0.0 ──
+## ✓ torch <environment> 
+## ✓ torch_optimizer  
+## ✓ pyro  
+## ✓ madgrad
+set.seed(42)
+community <- simulate_SDM(sites = 100, species = 10, env = 3, se = TRUE)
+Env <- community$env_weights
+Occ <- community$response
+SP <- matrix(rnorm(200, 0, 0.3), 100, 2) # spatial coordinates (no effect on species occurences)
+```
+
+Estimate jSDM:
+
+``` r
+model <- sjSDM(Y = Occ, env = linear(data = Env, formula = ~X1), spatial = linear(data = SP, formula = ~0+X1:X2), se = TRUE, family=binomial("probit"), sampling = 100L)
+summary(model)
+## LogLik:  -575.5497 
+## Regularization loss:  0 
+## 
+## Species-species correlation matrix: 
+## 
+##  sp1  1.0000                                 
+##  sp2 -0.3430  1.0000                             
+##  sp3 -0.0570 -0.3700  1.0000                         
+##  sp4  0.0770 -0.3130  0.6730  1.0000                     
+##  sp5  0.4870 -0.3630 -0.0450 -0.1260  1.0000                 
+##  sp6 -0.0970  0.3320  0.1880  0.1880 -0.0880  1.0000             
+##  sp7  0.4360 -0.2090  0.1800  0.1530  0.5090  0.2490  1.0000         
+##  sp8  0.2350  0.0560 -0.3290 -0.3380  0.3190 -0.0090  0.2010  1.0000     
+##  sp9  0.0400 -0.0330  0.0160  0.2050 -0.3410 -0.1920 -0.2980 -0.2220  1.0000 
+##  sp10     0.3090  0.3230 -0.5050 -0.3800  0.1930  0.1360  0.1890  0.3570 -0.0930  1.0000
+## 
+## 
+## 
+## Spatial: 
+##              sp1        sp2       sp3       sp4       sp5       sp6       sp7
+## X1:X2 0.08259914 -0.5019723 0.4352706 -0.169348 0.4040644 0.2000494 0.4183032
+##             sp8       sp9        sp10
+## X1:X2 0.3042413 0.2288286 -0.02296865
+## 
+## 
+## 
+##                  Estimate  Std.Err Z value Pr(>|z|)    
+## sp1 (Intercept)  -0.06842  0.20499   -0.33  0.73857    
+## sp1 X1            0.72483  0.39751    1.82  0.06824 .  
+## sp2 (Intercept)  -0.03794  0.20898   -0.18  0.85593    
+## sp2 X1            0.92104  0.40582    2.27  0.02323 *  
+## sp3 (Intercept)  -0.26596  0.21984   -1.21  0.22637    
+## sp3 X1            0.95088  0.41292    2.30  0.02129 *  
+## sp4 (Intercept)  -0.04988  0.20611   -0.24  0.80877    
+## sp4 X1           -1.15879  0.38965   -2.97  0.00294 ** 
+## sp5 (Intercept)  -0.15585  0.19463   -0.80  0.42326    
+## sp5 X1            0.50131  0.37329    1.34  0.17929    
+## sp6 (Intercept)   0.18499  0.19405    0.95  0.34043    
+## sp6 X1            1.55482  0.39826    3.90  9.5e-05 ***
+## sp7 (Intercept)   0.00426  0.17742    0.02  0.98084    
+## sp7 X1           -0.34412  0.34556   -1.00  0.31933    
+## sp8 (Intercept)   0.15873  0.13976    1.14  0.25607    
+## sp8 X1            0.14996  0.26153    0.57  0.56637    
+## sp9 (Intercept)   0.01891  0.17133    0.11  0.91211    
+## sp9 X1            1.09219  0.32656    3.34  0.00082 ***
+## sp10 (Intercept) -0.07258  0.17739   -0.41  0.68243    
+## sp10 X1          -0.49947  0.32436   -1.54  0.12359    
+## ---
+## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
+```
+
+Update model (change main effects to quadratic effects):
+
+``` r
+model2 <- update(model, env_formula = ~I(X1^2))
+summary(model2)
+## LogLik:  -608.1784 
+## Regularization loss:  0 
+## 
+## Species-species correlation matrix: 
+## 
+##  sp1  1.0000                                 
+##  sp2 -0.3030  1.0000                             
+##  sp3 -0.0130 -0.2560  1.0000                         
+##  sp4  0.0600 -0.3530  0.5650  1.0000                     
+##  sp5  0.4550 -0.3540 -0.0540 -0.0690  1.0000                 
+##  sp6 -0.0420  0.4110  0.2420  0.0420 -0.0790  1.0000             
+##  sp7  0.4220 -0.2130  0.1750  0.0780  0.5140  0.2090  1.0000         
+##  sp8  0.2440  0.0710 -0.3000 -0.3740  0.3210  0.0220  0.2360  1.0000     
+##  sp9  0.0920  0.0950  0.1040  0.1220 -0.3260  0.0200 -0.2400 -0.1540  1.0000 
+##  sp10     0.2760  0.2130 -0.5060 -0.3470  0.2340  0.0230  0.1450  0.3220 -0.1210  1.0000
+## 
+## 
+## 
+## Spatial: 
+##             sp1        sp2       sp3        sp4       sp5       sp6      sp7
+## X1:X2 0.1553214 -0.4860287 0.4846192 -0.2180294 0.4662001 0.1784182 0.378258
+##             sp8       sp9        sp10
+## X1:X2 0.2950488 0.2057981 -0.03424472
+## 
+## 
+## 
+##                  Estimate Std.Err Z value Pr(>|z|)
+## sp1 (Intercept)   -0.1303  0.2849   -0.46     0.65
+## sp1 I(X1^2)        0.4434  0.6996    0.63     0.53
+## sp2 (Intercept)   -0.2555  0.2864   -0.89     0.37
+## sp2 I(X1^2)        0.7050  0.7215    0.98     0.33
+## sp3 (Intercept)   -0.2640  0.2952   -0.89     0.37
+## sp3 I(X1^2)        0.1099  0.6970    0.16     0.87
+## sp4 (Intercept)   -0.2272  0.2737   -0.83     0.41
+## sp4 I(X1^2)        0.7222  0.6841    1.06     0.29
+## sp5 (Intercept)   -0.1383  0.2487   -0.56     0.58
+## sp5 I(X1^2)        0.2325  0.6248    0.37     0.71
+## sp6 (Intercept)    0.1669  0.2690    0.62     0.53
+## sp6 I(X1^2)       -0.0286  0.6517   -0.04     0.97
+## sp7 (Intercept)    0.0521  0.2466    0.21     0.83
+## sp7 I(X1^2)       -0.0193  0.6236   -0.03     0.98
+## sp8 (Intercept)   -0.0328  0.2086   -0.16     0.88
+## sp8 I(X1^2)        0.7716  0.5249    1.47     0.14
+## sp9 (Intercept)    0.2076  0.2478    0.84     0.40
+## sp9 I(X1^2)       -0.6296  0.5992   -1.05     0.29
+## sp10 (Intercept)  -0.1308  0.2505   -0.52     0.60
+## sp10 I(X1^2)       0.2070  0.5999    0.35     0.73
+```
+
+Change linear part of model to a deep neural network:
+
+``` r
+DNN <- sjSDM(Y = Occ, env = DNN(data = Env, formula = ~.), spatial = linear(data = SP, formula = ~0+X1:X2), se = TRUE, family=binomial("probit"), sampling = 100L)
+summary(DNN)
+## LogLik:  -564.1605 
+## Regularization loss:  0 
+## 
+## Species-species correlation matrix: 
+## 
+##  sp1  1.0000                                 
+##  sp2 -0.4150  1.0000                             
+##  sp3 -0.0480 -0.3220  1.0000                         
+##  sp4  0.0440 -0.3230  0.5590  1.0000                     
+##  sp5  0.5510 -0.2900 -0.0280 -0.0880  1.0000                 
+##  sp6 -0.1760  0.3670  0.2260  0.0560  0.0130  1.0000             
+##  sp7  0.5050 -0.1590  0.2130  0.0860  0.5020  0.3070  1.0000         
+##  sp8  0.2690  0.1100 -0.2800 -0.3930  0.2870  0.0620  0.2770  1.0000     
+##  sp9 -0.0630 -0.1070  0.0550  0.1380 -0.2600 -0.2420 -0.2260 -0.1470  1.0000 
+##  sp10     0.2720  0.2690 -0.5240 -0.3000  0.2340  0.0440  0.1590  0.2880 -0.1800  1.0000
+## 
+## 
+## 
+## Spatial: 
+##              sp1        sp2       sp3        sp4       sp5       sp6       sp7
+## X1:X2 0.09318528 -0.4935189 0.4328462 -0.1994821 0.4871828 0.1590104 0.3766337
+##             sp8       sp9         sp10
+## X1:X2 0.2689047 0.2027397 -0.002816148
+## 
+## 
+## 
+## Env architecture:
+## ===================================
+## Layer_1:  (4, 10)
+## Layer_2:  ReLU
+## Layer_3:  (10, 10)
+## Layer_4:  ReLU
+## Layer_5:  (10, 10)
+## Layer_6:  ReLU
+## Layer_7:  (10, 10)
+## ===================================
+## Weights :     340
+```
diff --git a/sjSDM/cran-comments.md b/sjSDM/cran-comments.md
new file mode 100644
index 0000000..67598d8
--- /dev/null
+++ b/sjSDM/cran-comments.md
@@ -0,0 +1,37 @@
+## Version 1.0.0
+
+### Submission 1, 01/0.5/2022
+
+This is a new submission. 
+
+Examples are locally tested (runtimes are too high for Rcmdcheck).
+
+Description:
+
+A scalable method to estimate joint Species Distribution Models (jSDMs) for big community datasets based on a Monte Carlo approximation of the joint likelihood.  The numerical approximation is based on 'PyTorch' and 'reticulate', and can be run on CPUs and GPUs alike. The method is described in Pichler & Hartig (2021) <doi:10.1111/2041-210X.13687>. The package contains various extensions, including support for different response families, ability to account for spatial autocorrelation, and deep neural networks instead of the linear predictor in jSDMs.
+
+### Successfull R CMD checks under
+
+* Locally: MacOS Monterey 12.1 (R x86_64 version)
+* Github actions: 
+  - MacOS Catalina 10.15 R-release 
+  - Ubuntu 20.04 R-release, R-oldrelease, and R-development
+  - Windows-latest R-release
+* Rhub:
+  - fedora 
+  - solairs
+* Win-builder R-release, R-development, and R-oldrelease
+
+Notes (from win-builder): 
+
+Possibly misspelled words in DESCRIPTION:
+  CPUs (21:262)
+  GPUs (21:271)
+  Hartig (21:320)
+  Pichler (21:310)
+  Scalable (3:8)
+  autocorrelation (21:488)
+  jSDMs (21:79, 21:565)
+  scalable (21:16)
+
+However, this seems fine to me. The spelling is intended. 
\ No newline at end of file
diff --git a/sjSDM/inst/examples/importance-example.R b/sjSDM/inst/examples/importance-example.R
index 2f3d39f..6800715 100644
--- a/sjSDM/inst/examples/importance-example.R
+++ b/sjSDM/inst/examples/importance-example.R
@@ -1,17 +1,17 @@
-\donttest{
-library(sjSDM)
-com = simulate_SDM(sites = 300L, species = 12L, 
-                   link = "identical", response = "identical")
-Raw = com$response
-SP = matrix(rnorm(300*2), 300, 2)
-SPweights = matrix(rnorm(12L), 1L)
-SPweights[1,1:6] = 0
-Y = Raw + (SP[,1,drop=FALSE]*SP[,2,drop=FALSE]) %*% SPweights
-Y = ifelse(Y > 0, 1, 0)
-
-model = sjSDM(Y = Y,env = linear(com$env_weights, lambda = 0.001), 
-              spatial = linear(SP,formula = ~0+X1:X2, lambda = 0.001), 
-              biotic = bioticStruct(lambda = 0.001),iter = 40L)
-imp = importance(model)
-plot(imp)
+\dontrun{
+library(sjSDM)
+com = simulate_SDM(sites = 300L, species = 12L, 
+                   link = "identical", response = "identical")
+Raw = com$response
+SP = matrix(rnorm(300*2), 300, 2)
+SPweights = matrix(rnorm(12L), 1L)
+SPweights[1,1:6] = 0
+Y = Raw + (SP[,1,drop=FALSE]*SP[,2,drop=FALSE]) %*% SPweights
+Y = ifelse(Y > 0, 1, 0)
+
+model = sjSDM(Y = Y,env = linear(com$env_weights, lambda = 0.001), 
+              spatial = linear(SP,formula = ~0+X1:X2, lambda = 0.001), 
+              biotic = bioticStruct(lambda = 0.001),iter = 40L)
+imp = importance(model)
+plot(imp)
 }
\ No newline at end of file
diff --git a/sjSDM/inst/examples/plot.sjSDM-emample.R b/sjSDM/inst/examples/plot.sjSDM-example.R
similarity index 97%
rename from sjSDM/inst/examples/plot.sjSDM-emample.R
rename to sjSDM/inst/examples/plot.sjSDM-example.R
index debf639..236088e 100644
--- a/sjSDM/inst/examples/plot.sjSDM-emample.R
+++ b/sjSDM/inst/examples/plot.sjSDM-example.R
@@ -1,4 +1,4 @@
-\donttest{
+\dontrun{
 library(sjSDM)
 # simulate community:
 com = simulate_SDM(env = 6L, species = 7L, sites = 100L)
diff --git a/sjSDM/inst/examples/sLVM-example.R b/sjSDM/inst/examples/sLVM-example.R
deleted file mode 100644
index 1e1eacd..0000000
--- a/sjSDM/inst/examples/sLVM-example.R
+++ /dev/null
@@ -1,37 +0,0 @@
-\donttest{
-  
-# Basic workflow:
-## simulate community:
-com = simulate_SDM(env = 3L, species = 5L, sites = 100L)
-
-## fit model:
-model = sLVM(Y = com$response,X = com$env_weights,
-             family = binomial("probit"))
-coef(model)
-summary(model)
-getCov(model)
-
-# get latent variables and factors
-getLF(model)
-getLV(model)
-
-# plot LV ordination
-plot(model)
-
-## fit model with interactions:
-model = sLVM(Y = com$response,
-             X = com$env_weights, formula = ~X1:X2 + X3,
-             family = binomial("probit"))
-summary(model)
-
-## without intercept:
-model = sLVM(Y = com$response,
-             X = com$env_weights, formula = ~0+X1:X2 + X3,
-             family = binomial("probit"))
-## predict with model:
-preds = predict(model, newdata = com$env_weights)
-
-## predictions over parameter distribution:
-preds = predict(model, newdata = com$env_weights, mean_field = FALSE)
-dim(preds)
-}
diff --git a/sjSDM/inst/examples/sjSDM-example.R b/sjSDM/inst/examples/sjSDM-example.R
index aefffb6..2493d51 100644
--- a/sjSDM/inst/examples/sjSDM-example.R
+++ b/sjSDM/inst/examples/sjSDM-example.R
@@ -1,11 +1,11 @@
-\donttest{
+\dontrun{
   
 # Basic workflow:
 ## simulate community:
 com = simulate_SDM(env = 3L, species = 7L, sites = 100L)
 
 ## fit model:
-model = sjSDM(Y = com$response,env = com$env_weights, iter = 2L) 
+model = sjSDM(Y = com$response,env = com$env_weights, iter = 50L) 
 # increase iter for your own data 
 
 coef(model)
@@ -36,22 +36,23 @@ model = sjSDM(Y = com$response,
 summary(model)
 
 ## without intercept:
-model = sjSDM(Y = com$response,
-              env = linear(data = com$env_weights, formula = ~0+X1:X2 + X3), 
-              se = TRUE,
-              iter = 2L) # increase iter for your own data 
+model = update(model, env_formula = ~0+X1:X2 + X3)
+
 summary(model)
 
 ## predict with model:
 preds = predict(model, newdata = com$env_weights)
 
+## calculate R-squared:
+R2 = Rsquared(model)
+print(R2)
 
 # With spatial terms:
 ## linear spatial model
 XY = matrix(rnorm(200), 100, 2)
 model = sjSDM(Y = com$response, env = linear(com$env_weights), 
               spatial = linear(XY, ~0+X1:X2),
-              iter = 2L) # increase iter for your own data 
+              iter = 50L) # increase iter for your own data 
 summary(model)
 predict(model, newdata = com$env_weights, SP = XY)
 
@@ -60,7 +61,7 @@ predict(model, newdata = com$env_weights, SP = XY)
 SPV = generateSpatialEV(XY)
 model = sjSDM(Y = com$response, env = linear(com$env_weights), 
               spatial = linear(SPV, ~0+., lambda = 0.1),
-              iter = 2L) # increase iter for your own data 
+              iter = 50L) # increase iter for your own data 
 summary(model)
 predict(model, newdata = com$env_weights, SP = SPV)
 
@@ -92,14 +93,14 @@ getCov(model)
 
 
 # Anova 
-com = simulate_SDM(env = 3L, species = 15L, sites = 200L)
+com = simulate_SDM(env = 3L, species = 15L, sites = 200L, correlation = TRUE)
 
 XY = matrix(rnorm(400), 200, 2)
 SPV = generateSpatialEV(XY)
 model = sjSDM(Y = com$response, env = linear(com$env_weights), 
               spatial = linear(SPV, ~0+.), 
-              iter = 2L) # increase iter for your own data 
-result = anova(model, cv = 2L)
+              iter = 50L) # increase iter for your own data 
+result = anova(model)
 print(result)
 plot(result)
 
diff --git a/sjSDM/inst/examples/sjSDM_cv-example.R b/sjSDM/inst/examples/sjSDM_cv-example.R
index 25f9368..2ab9735 100644
--- a/sjSDM/inst/examples/sjSDM_cv-example.R
+++ b/sjSDM/inst/examples/sjSDM_cv-example.R
@@ -1,4 +1,4 @@
-\donttest{
+\dontrun{
 # simulate sparse community:
 com = simulate_SDM(env = 5L, species = 25L, sites = 100L, sparse = 0.5)
 
@@ -26,15 +26,8 @@ summary(tune_results)
 # visualize tuning and best points:
 best = plot(tune_results, perf = "logLik")
 
-# fit model with new regularization paramter:
-model = sjSDM(Y = com$response,
-              env = linear(com$env_weights, 
-                              lambda = best[["lambda_coef"]],
-                              alpha = best[["alpha_coef"]]),
-              biotic = bioticStruct(lambda = best[["lambda_cov"]],
-                                    alpha = best[["alpha_cov"]]),
-              iter = 2L # increase it for your own data 
-              )
+# fit model with best regularization paramter:
+model = sjSDM.tune(tune_results)
 
 summary(model)
 }
diff --git a/sjSDM/inst/python/setup.py b/sjSDM/inst/python/setup.py
index 0d923d6..f32480d 100644
--- a/sjSDM/inst/python/setup.py
+++ b/sjSDM/inst/python/setup.py
@@ -5,7 +5,7 @@
 
 setuptools.setup(
     name="sjSDM_py", 
-    version="0.1.1",
+    version="0.1.2",
     author="Maximilian Pichler",
     author_email="Maximilian.Pichler@ur.de",
     description="jSDM package",
@@ -20,7 +20,6 @@
         "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
         "Operating System :: OS Independent",
         "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.6",
         "Programming Language :: Python :: 3.7",
         "Programming Language :: Python :: 3.8",
     ]
diff --git a/sjSDM/inst/python/sjSDM_py/__init__.py b/sjSDM/inst/python/sjSDM_py/__init__.py
index f5c2537..8d640e8 100644
--- a/sjSDM/inst/python/sjSDM_py/__init__.py
+++ b/sjSDM/inst/python/sjSDM_py/__init__.py
@@ -1,6 +1,4 @@
 from .model_sjSDM import Model_sjSDM
-from .model_svi import Model_SVI
-from .model_LVM import Model_LVM
 from .optimizer import *
 from .dist_mvp import MVP_logLik
 from .utils_fa import covariance, importance
\ No newline at end of file
diff --git a/sjSDM/man/AccSGD.Rd b/sjSDM/man/AccSGD.Rd
index ea9561f..e591bd6 100644
--- a/sjSDM/man/AccSGD.Rd
+++ b/sjSDM/man/AccSGD.Rd
@@ -11,7 +11,7 @@ AccSGD(kappa = 1000, xi = 10, small_const = 0.7, weight_decay = 0)
 
 \item{xi}{advantage parameter}
 
-\item{small_const}{small_const}
+\item{small_const}{small constant}
 
 \item{weight_decay}{l2 penalty on weights}
 }
diff --git a/sjSDM/man/AdaBound.Rd b/sjSDM/man/AdaBound.Rd
index 1245c34..a24d56a 100644
--- a/sjSDM/man/AdaBound.Rd
+++ b/sjSDM/man/AdaBound.Rd
@@ -4,8 +4,14 @@
 \alias{AdaBound}
 \title{AdaBound}
 \usage{
-AdaBound(betas = c(0.9, 0.999), final_lr = 0.1, gamma = 0.001,
-  eps = 1e-08, weight_decay = 0, amsbound = TRUE)
+AdaBound(
+  betas = c(0.9, 0.999),
+  final_lr = 0.1,
+  gamma = 0.001,
+  eps = 1e-08,
+  weight_decay = 0,
+  amsbound = TRUE
+)
 }
 \arguments{
 \item{betas}{betas}
diff --git a/sjSDM/man/DNN.Rd b/sjSDM/man/DNN.Rd
index 35a8544..34fbdd7 100644
--- a/sjSDM/man/DNN.Rd
+++ b/sjSDM/man/DNN.Rd
@@ -2,11 +2,18 @@
 % Please edit documentation in R/sjSDM_configs.R
 \name{DNN}
 \alias{DNN}
-\title{Non-linear nodel (deep neural network) of environmental responses}
+\title{Non-linear model (deep neural network) of environmental responses}
 \usage{
-DNN(data = NULL, formula = NULL, hidden = c(10L, 10L, 10L),
-  activation = "relu", bias = TRUE, lambda = 0, alpha = 0.5,
-  dropout = 0)
+DNN(
+  data = NULL,
+  formula = NULL,
+  hidden = c(10L, 10L, 10L),
+  activation = "relu",
+  bias = TRUE,
+  lambda = 0,
+  alpha = 0.5,
+  dropout = 0
+)
 }
 \arguments{
 \item{data}{matrix of environmental predictors}
@@ -29,14 +36,14 @@ DNN(data = NULL, formula = NULL, hidden = c(10L, 10L, 10L),
 specify the model to be fitted
 }
 \examples{
-\donttest{
+\dontrun{
   
 # Basic workflow:
 ## simulate community:
 com = simulate_SDM(env = 3L, species = 7L, sites = 100L)
 
 ## fit model:
-model = sjSDM(Y = com$response,env = com$env_weights, iter = 2L) 
+model = sjSDM(Y = com$response,env = com$env_weights, iter = 50L) 
 # increase iter for your own data 
 
 coef(model)
@@ -67,22 +74,23 @@ model = sjSDM(Y = com$response,
 summary(model)
 
 ## without intercept:
-model = sjSDM(Y = com$response,
-              env = linear(data = com$env_weights, formula = ~0+X1:X2 + X3), 
-              se = TRUE,
-              iter = 2L) # increase iter for your own data 
+model = update(model, env_formula = ~0+X1:X2 + X3)
+
 summary(model)
 
 ## predict with model:
 preds = predict(model, newdata = com$env_weights)
 
+## calculate R-squared:
+R2 = Rsquared(model)
+print(R2)
 
 # With spatial terms:
 ## linear spatial model
 XY = matrix(rnorm(200), 100, 2)
 model = sjSDM(Y = com$response, env = linear(com$env_weights), 
               spatial = linear(XY, ~0+X1:X2),
-              iter = 2L) # increase iter for your own data 
+              iter = 50L) # increase iter for your own data 
 summary(model)
 predict(model, newdata = com$env_weights, SP = XY)
 
@@ -91,7 +99,7 @@ predict(model, newdata = com$env_weights, SP = XY)
 SPV = generateSpatialEV(XY)
 model = sjSDM(Y = com$response, env = linear(com$env_weights), 
               spatial = linear(SPV, ~0+., lambda = 0.1),
-              iter = 2L) # increase iter for your own data 
+              iter = 50L) # increase iter for your own data 
 summary(model)
 predict(model, newdata = com$env_weights, SP = SPV)
 
@@ -123,14 +131,14 @@ getCov(model)
 
 
 # Anova 
-com = simulate_SDM(env = 3L, species = 15L, sites = 200L)
+com = simulate_SDM(env = 3L, species = 15L, sites = 200L, correlation = TRUE)
 
 XY = matrix(rnorm(400), 200, 2)
 SPV = generateSpatialEV(XY)
 model = sjSDM(Y = com$response, env = linear(com$env_weights), 
               spatial = linear(SPV, ~0+.), 
-              iter = 2L) # increase iter for your own data 
-result = anova(model, cv = 2L)
+              iter = 50L) # increase iter for your own data 
+result = anova(model)
 print(result)
 plot(result)
 
diff --git a/sjSDM/man/RMSprop.Rd b/sjSDM/man/RMSprop.Rd
index 143d6d9..d387844 100644
--- a/sjSDM/man/RMSprop.Rd
+++ b/sjSDM/man/RMSprop.Rd
@@ -4,8 +4,13 @@
 \alias{RMSprop}
 \title{RMSprop}
 \usage{
-RMSprop(alpha = 0.99, eps = 1e-08, weight_decay = 0.01, momentum = 0.1,
-  centered = FALSE)
+RMSprop(
+  alpha = 0.99,
+  eps = 1e-08,
+  weight_decay = 0.01,
+  momentum = 0.1,
+  centered = FALSE
+)
 }
 \arguments{
 \item{alpha}{decay factor}
diff --git a/sjSDM/man/Rsquared.Rd b/sjSDM/man/Rsquared.Rd
index 7e2ae99..04c5f1a 100644
--- a/sjSDM/man/Rsquared.Rd
+++ b/sjSDM/man/Rsquared.Rd
@@ -2,28 +2,30 @@
 % Please edit documentation in R/Rsquared.R
 \name{Rsquared}
 \alias{Rsquared}
-\title{Rsquared}
+\title{R-squared}
 \usage{
-Rsquared(model, X = NULL, Y = NULL, SP = NULL, adjust = FALSE,
-  averageSP = TRUE, averageSite = TRUE)
+Rsquared(model, method = c("Nagelkerke", "McFadden"))
 }
 \arguments{
 \item{model}{model}
 
-\item{X}{new environmental covariates}
-
-\item{Y}{new species occurences}
-
-\item{SP}{new spatial covariates}
-
-\item{adjust}{adjust R squared or not}
+\item{method}{Nagelkerke or McFadden}
+}
+\value{
+R-squared as numeric value
+}
+\description{
+calculate R-squared following Nagelkerke or McFadden
+}
+\details{
+\loadmathjax 
 
-\item{averageSP}{average R squared over species}
+Calculate R-squared following Nagelkerke or McFadden:
 
-\item{averageSite}{average R squared over sites}
+\itemize{
+\item Nagelkerke: \mjeqn{R^2 = 1 - \exp(2/N \cdot (log\mathcal{L}_0 - log\mathcal{L}_1 ) )}{}
+\item McFadden: \mjeqn{R^2 = 1 - log\mathcal{L}_1 / log\mathcal{L}_0  }{}
 }
-\description{
-claculate Rsquared following Nakagawa
 }
 \author{
 Maximilian Pichler
diff --git a/sjSDM/man/Rsquared2.Rd b/sjSDM/man/Rsquared2.Rd
deleted file mode 100644
index 5f3bd9b..0000000
--- a/sjSDM/man/Rsquared2.Rd
+++ /dev/null
@@ -1,27 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/Rsquared.R
-\name{Rsquared2}
-\alias{Rsquared2}
-\title{Rsquared2}
-\usage{
-Rsquared2(model, X = NULL, Y = NULL, SP = NULL, individual = TRUE, ...)
-}
-\arguments{
-\item{model}{model}
-
-\item{X}{new environmental covariates}
-
-\item{Y}{new species occurences}
-
-\item{SP}{new spatial covariates}
-
-\item{individual}{R squared for each site}
-
-\item{...}{additional parameters}
-}
-\description{
-claculate Rsquared following Nakagawa
-}
-\author{
-Maximilian Pichler
-}
diff --git a/sjSDM/man/add_curve.Rd b/sjSDM/man/add_curve.Rd
index e0e1b7c..449a8ab 100644
--- a/sjSDM/man/add_curve.Rd
+++ b/sjSDM/man/add_curve.Rd
@@ -5,8 +5,16 @@
 \title{add_curve
 curve plotting 'engine'}
 \usage{
-add_curve(p1 = NULL, p2 = NULL, n = 10, spar = 0.7, col = "black",
-  species = TRUE, radius = 5, lwd = 1)
+add_curve(
+  p1 = NULL,
+  p2 = NULL,
+  n = 10,
+  spar = 0.7,
+  col = "black",
+  species = TRUE,
+  radius = 5,
+  lwd = 1
+)
 }
 \arguments{
 \item{p1}{first point}
diff --git a/sjSDM/man/add_species_arrows.Rd b/sjSDM/man/add_species_arrows.Rd
index 25891d5..11ae8c7 100644
--- a/sjSDM/man/add_species_arrows.Rd
+++ b/sjSDM/man/add_species_arrows.Rd
@@ -5,8 +5,13 @@
 \title{add_species_arrows
 add species arrows to circle}
 \usage{
-add_species_arrows(radius = 5, label = "Species", reverse = TRUE,
-  start = 150, end = 270)
+add_species_arrows(
+  radius = 5,
+  label = "Species",
+  reverse = TRUE,
+  start = 150,
+  end = 270
+)
 }
 \arguments{
 \item{radius}{radius}
diff --git a/sjSDM/man/anova.sjSDM.Rd b/sjSDM/man/anova.sjSDM.Rd
index 94136ab..6c111c0 100644
--- a/sjSDM/man/anova.sjSDM.Rd
+++ b/sjSDM/man/anova.sjSDM.Rd
@@ -4,21 +4,25 @@
 \alias{anova.sjSDM}
 \title{Anova}
 \usage{
-\method{anova}{sjSDM}(object, cv = 5L, individual = FALSE, sampling = 5000L, ...)
+\method{anova}{sjSDM}(object, ...)
 }
 \arguments{
 \item{object}{model of object \code{\link{sjSDM}}}
 
-\item{cv}{number of cross-validation splits}
-
-\item{individual}{compute analysis of variance on species and site level}
-
-\item{sampling}{number of sampling steps for Monte Carlo integreation}
-
 \item{...}{optional arguments for compatibility with the generic function, no function implemented}
 }
+\value{
+An S3 class of type 'sjSDManova'. Implemented S3 methods are \code{\link{print.sjSDManova}} and \code{\link{plot.sjSDManova}}
+}
 \description{
-Compute analysis of variance via cross-validation for environmental, associations, and spatial effects
+Calculate type I anova in the following order:
+
+Null, biotic, abiotic (environment), and spatial (if present).
+
+Deviance for interactions (e.g. between space and environment) are also calculated and can be visualized via \code{\link{plot.sjSDManova}}.
+}
+\details{
+Compute analysis of variance
 }
 \seealso{
 \code{\link{plot.sjSDManova}}, \code{\link{print.sjSDManova}}
diff --git a/sjSDM/man/bioticStruct.Rd b/sjSDM/man/bioticStruct.Rd
index ff82ce6..bd743a2 100644
--- a/sjSDM/man/bioticStruct.Rd
+++ b/sjSDM/man/bioticStruct.Rd
@@ -4,13 +4,20 @@
 \alias{bioticStruct}
 \title{biotic structure}
 \usage{
-bioticStruct(df = NULL, lambda = 0, alpha = 0.5, on_diag = FALSE,
-  reg_on_Cov = TRUE, inverse = FALSE, diag = FALSE)
+bioticStruct(
+  df = NULL,
+  lambda = 0,
+  alpha = 0.5,
+  on_diag = FALSE,
+  reg_on_Cov = TRUE,
+  inverse = FALSE,
+  diag = FALSE
+)
 }
 \arguments{
 \item{df}{degree of freedom for covariance parametrization, if \code{NULL} df is set to \code{ncol(Y)/2}}
 
-\item{lambda}{lambda penality, strength of regularization: \eqn{\lambda * (lasso + ridge)}}
+\item{lambda}{lambda penalty, strength of regularization: \eqn{\lambda * (lasso + ridge)}}
 
 \item{alpha}{weighting between lasso and ridge: \eqn{(1 - \alpha) * |covariances| + \alpha ||covariances||^2}}
 
@@ -20,20 +27,20 @@ bioticStruct(df = NULL, lambda = 0, alpha = 0.5, on_diag = FALSE,
 
 \item{inverse}{regularization on the inverse covariance matrix}
 
-\item{diag}{use diagonal marix with zeros (internal usage)}
+\item{diag}{use diagonal matrix with zeros (internal usage)}
 }
 \description{
-define biotic (species-species) assocation (interaction) structur
+define biotic (species-species) association (interaction) structure
 }
 \examples{
-\donttest{
+\dontrun{
   
 # Basic workflow:
 ## simulate community:
 com = simulate_SDM(env = 3L, species = 7L, sites = 100L)
 
 ## fit model:
-model = sjSDM(Y = com$response,env = com$env_weights, iter = 2L) 
+model = sjSDM(Y = com$response,env = com$env_weights, iter = 50L) 
 # increase iter for your own data 
 
 coef(model)
@@ -64,22 +71,23 @@ model = sjSDM(Y = com$response,
 summary(model)
 
 ## without intercept:
-model = sjSDM(Y = com$response,
-              env = linear(data = com$env_weights, formula = ~0+X1:X2 + X3), 
-              se = TRUE,
-              iter = 2L) # increase iter for your own data 
+model = update(model, env_formula = ~0+X1:X2 + X3)
+
 summary(model)
 
 ## predict with model:
 preds = predict(model, newdata = com$env_weights)
 
+## calculate R-squared:
+R2 = Rsquared(model)
+print(R2)
 
 # With spatial terms:
 ## linear spatial model
 XY = matrix(rnorm(200), 100, 2)
 model = sjSDM(Y = com$response, env = linear(com$env_weights), 
               spatial = linear(XY, ~0+X1:X2),
-              iter = 2L) # increase iter for your own data 
+              iter = 50L) # increase iter for your own data 
 summary(model)
 predict(model, newdata = com$env_weights, SP = XY)
 
@@ -88,7 +96,7 @@ predict(model, newdata = com$env_weights, SP = XY)
 SPV = generateSpatialEV(XY)
 model = sjSDM(Y = com$response, env = linear(com$env_weights), 
               spatial = linear(SPV, ~0+., lambda = 0.1),
-              iter = 2L) # increase iter for your own data 
+              iter = 50L) # increase iter for your own data 
 summary(model)
 predict(model, newdata = com$env_weights, SP = SPV)
 
@@ -120,14 +128,14 @@ getCov(model)
 
 
 # Anova 
-com = simulate_SDM(env = 3L, species = 15L, sites = 200L)
+com = simulate_SDM(env = 3L, species = 15L, sites = 200L, correlation = TRUE)
 
 XY = matrix(rnorm(400), 200, 2)
 SPV = generateSpatialEV(XY)
 model = sjSDM(Y = com$response, env = linear(com$env_weights), 
               spatial = linear(SPV, ~0+.), 
-              iter = 2L) # increase iter for your own data 
-result = anova(model, cv = 2L)
+              iter = 50L) # increase iter for your own data 
+result = anova(model)
 print(result)
 plot(result)
 
diff --git a/sjSDM/man/check_module.Rd b/sjSDM/man/check_module.Rd
index 1d351b2..94e52d0 100644
--- a/sjSDM/man/check_module.Rd
+++ b/sjSDM/man/check_module.Rd
@@ -2,12 +2,10 @@
 % Please edit documentation in R/utils.R
 \name{check_module}
 \alias{check_module}
-\title{check modul
-check if modul is loaded}
+\title{check module}
 \usage{
 check_module()
 }
 \description{
-check modul
-check if modul is loaded
+check if module is loaded
 }
diff --git a/sjSDM/man/coef.sLVM.Rd b/sjSDM/man/coef.sLVM.Rd
deleted file mode 100644
index 8acef42..0000000
--- a/sjSDM/man/coef.sLVM.Rd
+++ /dev/null
@@ -1,16 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/sLVM.R
-\name{coef.sLVM}
-\alias{coef.sLVM}
-\title{Return coefficients from a fitted sLVM model}
-\usage{
-\method{coef}{sLVM}(object, ...)
-}
-\arguments{
-\item{object}{a model fitted by \code{\link{sLVM}}}
-
-\item{...}{optional arguments for compatibility with the generic function, no function implemented}
-}
-\description{
-Return coefficients from a fitted sLVM model
-}
diff --git a/sjSDM/man/curve_text.Rd b/sjSDM/man/curve_text.Rd
index 16d450a..53221c0 100644
--- a/sjSDM/man/curve_text.Rd
+++ b/sjSDM/man/curve_text.Rd
@@ -5,8 +5,15 @@
 \title{curve_text
 plot curved text}
 \usage{
-curve_text(pos = 0, label = "", radius = 5, reverse = FALSE,
-  middle = FALSE, extend = 1.1, ...)
+curve_text(
+  pos = 0,
+  label = "",
+  radius = 5,
+  reverse = FALSE,
+  middle = FALSE,
+  extend = 1.1,
+  ...
+)
 }
 \arguments{
 \item{pos}{position in degree}
diff --git a/sjSDM/man/getCI.Rd b/sjSDM/man/getCI.Rd
deleted file mode 100644
index 2f66f82..0000000
--- a/sjSDM/man/getCI.Rd
+++ /dev/null
@@ -1,18 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/sLVM.R
-\name{getCI}
-\alias{getCI}
-\title{Get Credible Intervals}
-\usage{
-getCI(object, lower = 0.025, upper = 0.975)
-}
-\arguments{
-\item{object}{a model fitted by \code{\link{sLVM}}}
-
-\item{lower}{lower quantile}
-
-\item{upper}{upper quantile}
-}
-\description{
-Get Credible Intervals
-}
diff --git a/sjSDM/man/getCov.Rd b/sjSDM/man/getCov.Rd
index 1257a41..cc9a0db 100644
--- a/sjSDM/man/getCov.Rd
+++ b/sjSDM/man/getCov.Rd
@@ -3,20 +3,17 @@
 \name{getCov}
 \alias{getCov}
 \alias{getCov.sjSDM}
-\alias{getCov.sLVM}
 \title{getCov}
 \usage{
 getCov(object)
 
 \method{getCov}{sjSDM}(object)
-
-\method{getCov}{sLVM}(object)
 }
 \arguments{
-\item{object}{a model fitted by \code{\link{sjSDM}}, \code{\link{sLVM}}  or \code{\link{sjSDM}} with \code{\link{DNN}} object}
+\item{object}{a model fitted by \code{\link{sjSDM}}, or \code{\link{sjSDM}} with \code{\link{DNN}} object}
 }
 \description{
-get species-species assocation (covariance) matrix
+get species-species association (covariance) matrix
 }
 \seealso{
 \code{\link{sjSDM}},\code{\link{DNN}}
diff --git a/sjSDM/man/getLF.Rd b/sjSDM/man/getLF.Rd
deleted file mode 100644
index 8b2a656..0000000
--- a/sjSDM/man/getLF.Rd
+++ /dev/null
@@ -1,14 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/sLVM.R
-\name{getLF}
-\alias{getLF}
-\title{Get latent factors}
-\usage{
-getLF(object)
-}
-\arguments{
-\item{object}{a model fitted by \code{\link{sLVM}}}
-}
-\description{
-Get latent factors
-}
diff --git a/sjSDM/man/getLV.Rd b/sjSDM/man/getLV.Rd
deleted file mode 100644
index e05d4ce..0000000
--- a/sjSDM/man/getLV.Rd
+++ /dev/null
@@ -1,14 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/sLVM.R
-\name{getLV}
-\alias{getLV}
-\title{Get latent variables}
-\usage{
-getLV(object)
-}
-\arguments{
-\item{object}{a model fitted by \code{\link{sLVM}}}
-}
-\description{
-Get latent variables
-}
diff --git a/sjSDM/man/importance.Rd b/sjSDM/man/importance.Rd
index 7ee86ad..821cbe0 100644
--- a/sjSDM/man/importance.Rd
+++ b/sjSDM/man/importance.Rd
@@ -13,11 +13,17 @@ importance(x, save_memory = TRUE, ...)
 
 \item{...}{additional arguments}
 }
+\value{
+An S3 class of type 'sjSDMimportance'. Implemented S3 methods include \code{\link{print.sjSDMimportance}} and \code{\link{plot.sjSDMimportance}}
+}
 \description{
-importance of abiotic, biotic, and spatial effects
+Computes standardized variance components with respect to abiotic, biotic, and spatial effect groups.
+}
+\details{
+This variance partitioning approach is based on Ovaskainen et al., 2017. For an example how to interpret the outputs, see Leibold et al., 2021.
 }
 \examples{
-\donttest{
+\dontrun{
 library(sjSDM)
 com = simulate_SDM(sites = 300L, species = 12L, 
                    link = "identical", response = "identical")
@@ -35,6 +41,14 @@ imp = importance(model)
 plot(imp)
 }
 }
+\references{
+Ovaskainen, O., Tikhonov, G., Norberg, A., Guillaume Blanchet, F., Duan, L., Dunson, D., ... & Abrego, N. (2017). How to make more out of community data? A conceptual framework and its implementation as models and software. Ecology letters, 20(5), 561-576.
+
+Leibold, M. A., Rudolph, F. J., Blanchet, F. G., De Meester, L., Gravel, D., Hartig, F., ... & Chase, J. M. (2021). The internal structure of metacommunities. Oikos.
+}
+\seealso{
+\code{\link{print.sjSDMimportance}}, \code{\link{plot.sjSDMimportance}}
+}
 \author{
 Maximilian Pichler
 }
diff --git a/sjSDM/man/install_sjSDM.Rd b/sjSDM/man/install_sjSDM.Rd
index 9466ab6..7f5b823 100644
--- a/sjSDM/man/install_sjSDM.Rd
+++ b/sjSDM/man/install_sjSDM.Rd
@@ -4,24 +4,21 @@
 \alias{install_sjSDM}
 \title{Install sjSDM and its dependencies}
 \usage{
-install_sjSDM(method = "conda", conda = "auto", version = c("cpu",
-  "gpu"), envname = "r-reticulate", restart_session = TRUE,
-  cuda = c("10.2", "9,2"), ...)
+install_sjSDM(
+  conda = "auto",
+  version = c("cpu", "gpu"),
+  restart_session = TRUE,
+  ...
+)
 }
 \arguments{
-\item{method}{installation method, auto = automatically best (conda or virtualenv), or force conda with method = "conda" or virtualenv with method = "virtualenv"}
-
 \item{conda}{path to conda}
 
-\item{version}{version = "cpu" for CPU version, or "gpu" for gpu version. (note MacOS users have to install cuda binaries by themselves)}
-
-\item{envname}{Name of python env, "r-pytorch" is default}
+\item{version}{version = "cpu" for CPU version, or "gpu" for GPU version. (note MacOS users have to install 'cuda' binaries by themselves)}
 
 \item{restart_session}{Restart R session after installing (note this will
 only occur within RStudio).}
 
-\item{cuda}{which cuda version, 9.2 and 10.2 are supported}
-
 \item{...}{not supported}
 }
 \description{
diff --git a/sjSDM/man/installation_help.Rd b/sjSDM/man/installation_help.Rd
index 45a860a..6b53c78 100644
--- a/sjSDM/man/installation_help.Rd
+++ b/sjSDM/man/installation_help.Rd
@@ -3,28 +3,40 @@
 \docType{package}
 \name{installation_help}
 \alias{installation_help}
-\title{installation help}
+\title{Installation help}
 \description{
-A scalable method to estimates joint Species Distribution Models (jSDMs).
-}
-\details{
-A scalable method to estimates joint Species Distribution Models (jSDMs) based on the multivariate probit model through Monte-Carlo approximation of the joint likelihood. The numerical approximation is based on PyTorch and reticulate, and can be calculated on CPUs and GPUs alike.
+Trouble shooting guide for the installation of the sjSDM package
+
+We provide a function \code{\link{install_sjSDM}} to install automatically 
+all necessary python dependencies but it can fail sometimes because of 
+individual system settings or if other python/conda installations get into 
+the way.
 }
-\section{PyTorch Installation - Before you start}{
+\section{'PyTorch' Installation - Before you start}{
 
 
-A few notes before you start with the installation:
+A few notes before you start with the installation (skip this point if you 
+do not know 'conda'):
 \itemize{
- \item existing conda installations (skip this point if you do not know conda): make sure you have the latest conda3/miniconda3 installation and remove unneccessary conda installations.
- \item existing conda/virtualenv (skip this point if you do not know conda): the R package reticulate has problems to find the right environment and it is better to remove unneccessary environments (see the troubleshooting section)
+ \item existing 'conda' installations:
+  make sure you have the latest conda3/miniconda3 version and 
+  remove unnecessary 'conda' installations.
+ \item existing 'conda'/'virtualenv' environments (skip this point if you do not know 'conda'): 
+ we currently enforce the usage of a specific environment called 'r-sjsdm', 
+ so if you want use a custom environment it should be named 'r-sjsdm'
 }
 }
 
 \section{Windows - automatic installation}{
 
 
-Conda is the easiest way to install python and python packages on windows:
-Install the latest \href{https://www.anaconda.com/distribution/}{conda version}
+Sometimes the automatic 'miniconda' installation 
+(via \code{\link{install_sjSDM}}) doesn't work because of white
+spaces in the user's name. But you can easily download and install 'conda' on
+your own:
+
+Download and install the latest 
+\href{https://www.anaconda.com/products/individual}{'conda' version}
 
 Afterwards run:\cr
 \code{install_sjSDM(version = c("gpu")) # or "cpu" if you do not have a proper gpu device }
@@ -32,30 +44,32 @@ Afterwards run:\cr
 Reload the package and run the example , if this doesn't work:
 \itemize{
 \item Restart RStudio
-\item Install manually pytorch, see the following section
+\item Install manually 'pytorch', see the following section
 }
 }
 
 \section{Windows - manual installation}{
 
 
-Conda is the easiest way to install python and python packages on windows:
+Download and install the latest 'conda' version:
 \itemize{
-\item Install the latest \href{https://www.anaconda.com/distribution/}{conda version}
+\item Install the latest 
+\href{https://www.anaconda.com/products/individual}{'conda' version}
 \item Open the command window (cmd.exe - hit windows key + r and write cmd)
 }
 Run in cmd.exe:\cr
 \preformatted{
-$ conda create --name sjSDM_env python=3.7\cr
-$ conda activate sjSDM_env\cr
-$ conda install pytorch torchvision cpuonly -c pytorch # cpu\cr
-$ conda install pytorch torchvision cudatoolkit=10.1 -c pytorch #gpu\cr
+$ conda create --name r-sjsdm python=3.7
+$ conda activate r-sjsdm
+$ conda install pytorch torchvision cpuonly -c pytorch # cpu
+$ conda install pytorch torchvision cudatoolkit=11.3 -c pytorch #gpu
+$ python -m pip install pyro-ppl torch_optimizer madgrad
 }
 
-Restart R try to run the example, if this doesn't work:
+Restart R, try to run the example, and if this doesn't work:
 \itemize{
 \item Restart RStudio
-\item See the troubleshooting section
+\item See the 'Help and bugs' section
 }
 }
 
@@ -63,123 +77,89 @@ Restart R try to run the example, if this doesn't work:
 
 
 Run in R:\cr
-\code{install_sjSDM(version = c("gpu")) # or "cpu" if you do not have a proper gpu device }
+\code{install_sjSDM(version = c("gpu")) # or "cpu" if 
+you do not have a proper 'gpu' device }
+
 Restart R try to run the example, if this doesn't work:
 \itemize{
 \item Restart RStudio
-\item Install manually pytorch, see the following section
+\item Install manually 'PyTorch', see the following section
 }
 }
 
 \section{Linux - manual installation}{
 
 
-Via pip\cr
-python3 is pre-installed on most linux distributions, but you have to check that the minimal requirement of python >= 3.6 is met: 
-  
-Run in your shell:\cr
-\preformatted{
-$ python3 --version\cr
-$ python --version\cr
-}
+We strongly advise to use a 'conda' environment but a virtual env should also 
+work. The only requirement is that it is named 'r-sjsdm'
 
-Check if pip is installed:
-\preformatted{
-$ pip3 --version\cr
-$ pip --version\cr
-}
 
-If not then install pip:\cr
-\preformatted{
-$ sudo apt install python3-pip # for ubuntu/deb   # e.g. for ubuntu
-}
-
-It depends on your ENVIRONMENTAL variables whether pip or pip3 corresponds to python3. You can check the python version of pip via:\cr
-\preformatted{
-$ pip --version
+Download and install the latest 'conda' version:
+\itemize{
+\item Install the latest 
+\href{https://www.anaconda.com/products/individual}{'conda' version}
+\item Open your terminal 
 }
 
-In my case, I have to use "pip3":\cr
+Run in your terminal:\cr
 \preformatted{
-$ pip3 install torch==1.4.0+cpu torchvision==0.5.0+cpu -f https://download.pytorch.org/whl/torch_stable.html #cpu
-$ pip3 install torch torchvision #gpu
+$ conda create --name r-sjsdm python=3.7
+$ conda activate r-sjsdm
+$ conda install pytorch torchvision cpuonly -c pytorch # cpu
+$ conda install pytorch torchvision cudatoolkit=11.3 -c pytorch #gpu
+$ python -m pip install pyro-ppl torch_optimizer madgrad
 }
 
 Restart R try to run the example, if this doesn't work:
 \itemize{
 \item Restart RStudio
-\item See the troubleshooting section
+\item See the 'Help and bugs' section
 }
-
-Via virtualenv\cr
-Create a virtualenv and install dependencies (shell):\cr
-\preformatted{
-$ python3 -m pip install --user virtualenv\cr
-$ python3 -m venv ~/sjSDM_env\cr
-$ source ~/sjSDM_env/bin/activate\cr
-$ pip install torch==1.4.0+cpu torchvision==0.5.0+cpu -f https://download.pytorch.org/whl/torch_stable.html #cpu\cr
-$ pip install torch torchvision #gpu\cr
 }
 
-Restart R try to run the example, if this doesn't work:
-\itemize{
-\item Restart RStudio
-\item See the troubleshooting section
-}
+\section{MacOS - automatic installation}{
 
-Via conda\cr
-Install the latest \href{https://www.anaconda.com/distribution/}{conda version} and run (shell):\cr
-\preformatted{
-$ conda create --name sjSDM_env python=3.7\cr
-$ conda activate sjSDM_env\cr
-$ conda install pytorch torchvision cpuonly -c pytorch # cpu\cr
-$ conda install pytorch torchvision cudatoolkit=10.1 -c pytorch #gpu\cr
-}
-Restart R try to run the example from, if this doesn't work:\cr
+
+Run in R:\cr
+\code{install_sjSDM(version = c("cpu"))}
+
+Restart R try to run the example, if this doesn't work:
 \itemize{
 \item Restart RStudio
-\item See the troubleshooting section
+\item Install manually 'PyTorch', see the following section
 }
 }
 
-\section{MacOS}{
+\section{MacOS - manual installation}{
 
 
-Via conda\cr
-Install the latest \href{https://www.anaconda.com/distribution/}{conda version} and run in your OS shell:\cr
-\preformatted{
-$ conda create --name sjSDM_env python=3.7\cr
-$ conda activate sjSDM_env\cr
-$ conda install pytorch torchvision cpuonly -c pytorch # cpu\Cr
-}
-Restart R try to run the example from, if this doesn't work:
+Download and install the latest 'conda' version:
 \itemize{
-\item Restart RStudio
-\item See the troubleshooting section
-}
-    
-For GPU support on MacOS, you have to install the cuda binaries yourself, see \href{https://pytorch.org/}{PyTorch for help}
+\item Install the latest 
+\href{https://www.anaconda.com/products/individual}{'conda' version}
+\item Open your terminal 
 }
 
-\section{Troubleshooting}{
-
-
-After several installation attempts you might have corrupt and unneccessary conda environments which you have to remove:
-Open the shell (Windows users: run cmd.exe):\cr
+Run in your terminal:\cr
 \preformatted{
-$ conda env list\cr
+$ conda create --name r-sjsdm python=3.7
+$ conda activate r-sjsdm
+$ python -m pip install torch torchvision torchaudio 
+$ python -m pip install pyro-ppl torch_optimizer madgrad
 }
-will list the paths of all your environments, except for the "base" env, delete them via:\cr
-\preformatted{
-$ rm - r <path-to-env1>\cr
-$ rm - r <path-to-env2>\cr
+Restart R try to run the example from, if this doesn't work:
+\itemize{
+\item Restart RStudio
+\item See the 'Help and bugs' section
 }
-Then continue with the manual install instructions in above sections.
 }
 
 \section{Help and bugs}{
 
 
-To report bugs or ask for help, post a \href{http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example}{reproducible example} via the sjSDM \href{https://github.com/TheoreticalEcology/s-jSDM/issues}{issue tracker} with a copy of the \code{\link{install_diagnostic}} output as a quote on GitHub.
+To report bugs or ask for help, post a 
+\href{https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example}{reproducible example} 
+via the sjSDM \href{https://github.com/TheoreticalEcology/s-jSDM/issues}{issue tracker} 
+with a copy of the \code{\link{install_diagnostic}} output as a quote.
 }
 
diff --git a/sjSDM/man/is_sjSDM_py_available.Rd b/sjSDM/man/is_sjSDM_py_available.Rd
deleted file mode 100644
index dc7ed87..0000000
--- a/sjSDM/man/is_sjSDM_py_available.Rd
+++ /dev/null
@@ -1,13 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/utils.R
-\name{is_sjSDM_py_available}
-\alias{is_sjSDM_py_available}
-\title{is_sjSDM_py_available
-check whetcher torch is available}
-\usage{
-is_sjSDM_py_available()
-}
-\description{
-is_sjSDM_py_available
-check whetcher torch is available
-}
diff --git a/sjSDM/man/linear.Rd b/sjSDM/man/linear.Rd
index a03b5ca..534765a 100644
--- a/sjSDM/man/linear.Rd
+++ b/sjSDM/man/linear.Rd
@@ -11,7 +11,7 @@ linear(data = NULL, formula = NULL, lambda = 0, alpha = 0.5)
 
 \item{formula}{formula object for predictors}
 
-\item{lambda}{lambda penality, strength of regularization: \eqn{\lambda * (lasso + ridge)}}
+\item{lambda}{lambda penalty, strength of regularization: \eqn{\lambda * (lasso + ridge)}}
 
 \item{alpha}{weighting between lasso and ridge: \eqn{(1 - \alpha) * |coefficients| + \alpha ||coefficients||^2}}
 }
@@ -19,14 +19,14 @@ linear(data = NULL, formula = NULL, lambda = 0, alpha = 0.5)
 specify the model to be fitted
 }
 \examples{
-\donttest{
+\dontrun{
   
 # Basic workflow:
 ## simulate community:
 com = simulate_SDM(env = 3L, species = 7L, sites = 100L)
 
 ## fit model:
-model = sjSDM(Y = com$response,env = com$env_weights, iter = 2L) 
+model = sjSDM(Y = com$response,env = com$env_weights, iter = 50L) 
 # increase iter for your own data 
 
 coef(model)
@@ -57,22 +57,23 @@ model = sjSDM(Y = com$response,
 summary(model)
 
 ## without intercept:
-model = sjSDM(Y = com$response,
-              env = linear(data = com$env_weights, formula = ~0+X1:X2 + X3), 
-              se = TRUE,
-              iter = 2L) # increase iter for your own data 
+model = update(model, env_formula = ~0+X1:X2 + X3)
+
 summary(model)
 
 ## predict with model:
 preds = predict(model, newdata = com$env_weights)
 
+## calculate R-squared:
+R2 = Rsquared(model)
+print(R2)
 
 # With spatial terms:
 ## linear spatial model
 XY = matrix(rnorm(200), 100, 2)
 model = sjSDM(Y = com$response, env = linear(com$env_weights), 
               spatial = linear(XY, ~0+X1:X2),
-              iter = 2L) # increase iter for your own data 
+              iter = 50L) # increase iter for your own data 
 summary(model)
 predict(model, newdata = com$env_weights, SP = XY)
 
@@ -81,7 +82,7 @@ predict(model, newdata = com$env_weights, SP = XY)
 SPV = generateSpatialEV(XY)
 model = sjSDM(Y = com$response, env = linear(com$env_weights), 
               spatial = linear(SPV, ~0+., lambda = 0.1),
-              iter = 2L) # increase iter for your own data 
+              iter = 50L) # increase iter for your own data 
 summary(model)
 predict(model, newdata = com$env_weights, SP = SPV)
 
@@ -113,14 +114,14 @@ getCov(model)
 
 
 # Anova 
-com = simulate_SDM(env = 3L, species = 15L, sites = 200L)
+com = simulate_SDM(env = 3L, species = 15L, sites = 200L, correlation = TRUE)
 
 XY = matrix(rnorm(400), 200, 2)
 SPV = generateSpatialEV(XY)
 model = sjSDM(Y = com$response, env = linear(com$env_weights), 
               spatial = linear(SPV, ~0+.), 
-              iter = 2L) # increase iter for your own data 
-result = anova(model, cv = 2L)
+              iter = 50L) # increase iter for your own data 
+result = anova(model)
 print(result)
 plot(result)
 
diff --git a/sjSDM/man/logLik.sLVM.Rd b/sjSDM/man/logLik.sLVM.Rd
deleted file mode 100644
index 289eba4..0000000
--- a/sjSDM/man/logLik.sLVM.Rd
+++ /dev/null
@@ -1,16 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/sLVM.R
-\name{logLik.sLVM}
-\alias{logLik.sLVM}
-\title{Extract Log-Likelihood from a fitted sLVM model}
-\usage{
-\method{logLik}{sLVM}(object, ...)
-}
-\arguments{
-\item{object}{a model fitted by \code{\link{sLVM}}}
-
-\item{...}{optional arguments for compatibility with the generic function, no functionality implemented}
-}
-\description{
-Extract Log-Likelihood from a fitted sLVM model
-}
diff --git a/sjSDM/man/modules.Rd b/sjSDM/man/modules.Rd
new file mode 100644
index 0000000..c4930b9
--- /dev/null
+++ b/sjSDM/man/modules.Rd
@@ -0,0 +1,23 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/modules.R
+\docType{data}
+\name{torch}
+\alias{torch}
+\alias{fa}
+\title{Torch module}
+\format{
+Torch module
+
+fa module
+}
+\usage{
+torch
+
+fa
+}
+\description{
+Interface to 'PyTorch' module
+
+Interface to internal 'fa' module
+}
+\keyword{datasets}
diff --git a/sjSDM/man/new_image.Rd b/sjSDM/man/new_image.Rd
index c4cdf50..45f8b42 100644
--- a/sjSDM/man/new_image.Rd
+++ b/sjSDM/man/new_image.Rd
@@ -1,11 +1,14 @@
 % Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/tuning.R
+% Please edit documentation in R/sjSDM_cv.R
 \name{new_image}
 \alias{new_image}
 \title{new_image function}
 \usage{
-new_image(z, cols = (grDevices::colorRampPalette(c("white", "#24526E"), bias
-  = 1.5))(10), range = c(0.5, 1))
+new_image(
+  z,
+  cols = (grDevices::colorRampPalette(c("white", "#24526E"), bias = 1.5))(10),
+  range = c(0.5, 1)
+)
 }
 \arguments{
 \item{z}{z matrix}
diff --git a/sjSDM/man/plot.sLVM.Rd b/sjSDM/man/plot.sLVM.Rd
deleted file mode 100644
index da6def2..0000000
--- a/sjSDM/man/plot.sLVM.Rd
+++ /dev/null
@@ -1,16 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/sLVM.R
-\name{plot.sLVM}
-\alias{plot.sLVM}
-\title{sLVM ordinations plot}
-\usage{
-\method{plot}{sLVM}(x, ...)
-}
-\arguments{
-\item{x}{an object of class \code{\link{sLVM}}}
-
-\item{...}{optional arguments for compatibility with the generic function, passed to the plot function}
-}
-\description{
-This S3 function creates the ordination plot for the LVM model
-}
diff --git a/sjSDM/man/plot.sjSDM.Rd b/sjSDM/man/plot.sjSDM.Rd
index 65f3064..7ec0329 100644
--- a/sjSDM/man/plot.sjSDM.Rd
+++ b/sjSDM/man/plot.sjSDM.Rd
@@ -2,7 +2,7 @@
 % Please edit documentation in R/plot.R
 \name{plot.sjSDM}
 \alias{plot.sjSDM}
-\title{Coeffect plot}
+\title{Coefficients plot}
 \usage{
 \method{plot}{sjSDM}(x, ...)
 }
@@ -12,11 +12,11 @@
 \item{...}{Additional arguments to pass to \code{\link{plotsjSDMcoef}}.}
 }
 \description{
-Plotting coeffects return by sjSDM model.
+Plotting coefficients returned by sjSDM model.
 This function only for model fitted by linear, fitted by DNN is not yet supported.
 }
 \examples{
-\donttest{
+\dontrun{
 library(sjSDM)
 # simulate community:
 com = simulate_SDM(env = 6L, species = 7L, sites = 100L)
diff --git a/sjSDM/man/plot.sjSDM_cv.Rd b/sjSDM/man/plot.sjSDM_cv.Rd
index f7455dc..15fc7bd 100644
--- a/sjSDM/man/plot.sjSDM_cv.Rd
+++ b/sjSDM/man/plot.sjSDM_cv.Rd
@@ -1,5 +1,5 @@
 % Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/tuning.R
+% Please edit documentation in R/sjSDM_cv.R
 \name{plot.sjSDM_cv}
 \alias{plot.sjSDM_cv}
 \title{Plot elastic net tuning}
diff --git a/sjSDM/man/plot.sjSDManova.Rd b/sjSDM/man/plot.sjSDManova.Rd
index e717bb8..84c11cf 100644
--- a/sjSDM/man/plot.sjSDManova.Rd
+++ b/sjSDM/man/plot.sjSDManova.Rd
@@ -2,27 +2,33 @@
 % Please edit documentation in R/anova.R
 \name{plot.sjSDManova}
 \alias{plot.sjSDManova}
-\title{Plot anova}
+\title{Plot anova results}
 \usage{
-\method{plot}{sjSDManova}(x, y, perf = c("LogLik", "R2"),
-  cols = c("#7FC97F", "#BEAED4", "#FDC086"), alpha = 0.15,
-  percent = TRUE, ...)
+\method{plot}{sjSDManova}(
+  x,
+  y,
+  type = c("Deviance", "Nagelkerke", "McFadden"),
+  cols = c("#7FC97F", "#BEAED4", "#FDC086"),
+  alpha = 0.15,
+  ...
+)
 }
 \arguments{
 \item{x}{anova object from \code{\link{anova.sjSDM}}}
 
 \item{y}{unused argument}
 
-\item{perf}{performance measurement to plot}
+\item{type}{use of deviance or of Nagelkerke or McFadden R-squareds}
 
 \item{cols}{colors for the groups}
 
 \item{alpha}{alpha for colors}
 
-\item{percent}{use relative instead of absolute values (currently not supported)}
-
 \item{...}{Additional arguments to pass to \code{plot()}}
 }
+\value{
+Matrix of results
+}
 \description{
-Plot anova
+Plot anova results
 }
diff --git a/sjSDM/man/plot.sjSDManovaIndividual.Rd b/sjSDM/man/plot.sjSDManovaIndividual.Rd
deleted file mode 100644
index 6ed1aac..0000000
--- a/sjSDM/man/plot.sjSDManovaIndividual.Rd
+++ /dev/null
@@ -1,27 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/anova.R
-\name{plot.sjSDManovaIndividual}
-\alias{plot.sjSDManovaIndividual}
-\title{Plot anova}
-\usage{
-\method{plot}{sjSDManovaIndividual}(x, y, contour = FALSE,
-  col.points = "#24526e", cex.points = 1.2, pch = 19, ...)
-}
-\arguments{
-\item{x}{anova object from \code{\link{anova.sjSDM}}}
-
-\item{y}{unused argument}
-
-\item{contour}{plot contour or not}
-
-\item{col.points}{point color}
-
-\item{cex.points}{point size}
-
-\item{pch}{point symbol}
-
-\item{...}{Additional arguments to pass to \code{plot()}}
-}
-\description{
-Plot anova
-}
diff --git a/sjSDM/man/plot.sjSDMimportance.Rd b/sjSDM/man/plot.sjSDMimportance.Rd
index 148cf53..1049510 100644
--- a/sjSDM/man/plot.sjSDMimportance.Rd
+++ b/sjSDM/man/plot.sjSDMimportance.Rd
@@ -4,9 +4,16 @@
 \alias{plot.sjSDMimportance}
 \title{Plot importance}
 \usage{
-\method{plot}{sjSDMimportance}(x, y, contour = FALSE,
-  col.points = "#24526e", cex.points = 1.2, pch = 19,
-  col.contour = "#ffbf02", ...)
+\method{plot}{sjSDMimportance}(
+  x,
+  y,
+  contour = FALSE,
+  col.points = "#24526e",
+  cex.points = 1.2,
+  pch = 19,
+  col.contour = "#ffbf02",
+  ...
+)
 }
 \arguments{
 \item{x}{a model fitted by \code{\link{importance}}}
diff --git a/sjSDM/man/plotAssociations.Rd b/sjSDM/man/plotAssociations.Rd
index 1375bca..4029a77 100644
--- a/sjSDM/man/plotAssociations.Rd
+++ b/sjSDM/man/plotAssociations.Rd
@@ -5,11 +5,18 @@
 \title{plotAssociations
 plot species-species associations}
 \usage{
-plotAssociations(sigma, radius = 5, main = NULL, circleBreak = FALSE,
-  top = 10L, occ = NULL, cols_association = c("#FF0000", "#BF003F",
-  "#7F007F", "#3F00BF", "#0000FF"), cols_occurrence = c("#BEBEBE", "#8E8E8E",
-  "#5F5F5F", "#2F2F2F", "#000000"), lwd_occurrence = 1,
-  species_indices = NULL)
+plotAssociations(
+  sigma,
+  radius = 5,
+  main = NULL,
+  circleBreak = FALSE,
+  top = 10L,
+  occ = NULL,
+  cols_association = c("#FF0000", "#BF003F", "#7F007F", "#3F00BF", "#0000FF"),
+  cols_occurrence = c("#BEBEBE", "#8E8E8E", "#5F5F5F", "#2F2F2F", "#000000"),
+  lwd_occurrence = 1,
+  species_indices = NULL
+)
 }
 \arguments{
 \item{sigma}{species-species covariance matrix}
@@ -22,7 +29,7 @@ plotAssociations(sigma, radius = 5, main = NULL, circleBreak = FALSE,
 
 \item{top}{top negative and positive associations}
 
-\item{occ}{species occurence data}
+\item{occ}{species occurrence data}
 
 \item{cols_association}{col gradient for association lines}
 
diff --git a/sjSDM/man/plotsjSDMcoef.Rd b/sjSDM/man/plotsjSDMcoef.Rd
index abd5be2..48255b5 100644
--- a/sjSDM/man/plotsjSDMcoef.Rd
+++ b/sjSDM/man/plotsjSDMcoef.Rd
@@ -2,7 +2,7 @@
 % Please edit documentation in R/plot.R
 \name{plotsjSDMcoef}
 \alias{plotsjSDMcoef}
-\title{Coeffect plot}
+\title{Coefficients plot}
 \usage{
 plotsjSDMcoef(object, wrap_col = NULL, group = NULL, col = NULL, slist = NULL)
 }
@@ -18,11 +18,11 @@ plotsjSDMcoef(object, wrap_col = NULL, group = NULL, col = NULL, slist = NULL)
 \item{slist}{Select the species you want to plot, default is all, parameter is not supported yet.}
 }
 \description{
-Plotting coeffects return by sjSDM model.
+Plotting coefficients returned by sjSDM model.
 This function only for model fitted by linear, fitted by DNN is not yet supported.
 }
 \examples{
-\donttest{
+\dontrun{
 library(sjSDM)
 # simulate community:
 com = simulate_SDM(env = 6L, species = 7L, sites = 100L)
diff --git a/sjSDM/man/predict.sLVM.Rd b/sjSDM/man/predict.sLVM.Rd
deleted file mode 100644
index 76e105a..0000000
--- a/sjSDM/man/predict.sLVM.Rd
+++ /dev/null
@@ -1,20 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/sLVM.R
-\name{predict.sLVM}
-\alias{predict.sLVM}
-\title{Predict from a fitted sLVM model}
-\usage{
-\method{predict}{sLVM}(object, newdata = NULL, mean_field = FALSE, ...)
-}
-\arguments{
-\item{object}{a model fitted by \code{\link{sLVM}}}
-
-\item{newdata}{newdata for predictions}
-
-\item{mean_field}{use means of parameter estimates or samples from their distribution}
-
-\item{...}{optional arguments for compatibility with the generic function, no function implemented}
-}
-\description{
-Predict from a fitted sLVM model
-}
diff --git a/sjSDM/man/predict.sjSDM.Rd b/sjSDM/man/predict.sjSDM.Rd
index 6f83291..a215c3c 100644
--- a/sjSDM/man/predict.sjSDM.Rd
+++ b/sjSDM/man/predict.sjSDM.Rd
@@ -4,8 +4,14 @@
 \alias{predict.sjSDM}
 \title{Predict from a fitted sjSDM model}
 \usage{
-\method{predict}{sjSDM}(object, newdata = NULL, SP = NULL,
-  type = c("link", "raw"), dropout = FALSE, ...)
+\method{predict}{sjSDM}(
+  object,
+  newdata = NULL,
+  SP = NULL,
+  type = c("link", "raw"),
+  dropout = FALSE,
+  ...
+)
 }
 \arguments{
 \item{object}{a model fitted by \code{\link{sjSDM}}}
diff --git a/sjSDM/man/print.sLVM.Rd b/sjSDM/man/print.sLVM.Rd
deleted file mode 100644
index d45393d..0000000
--- a/sjSDM/man/print.sLVM.Rd
+++ /dev/null
@@ -1,16 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/sLVM.R
-\name{print.sLVM}
-\alias{print.sLVM}
-\title{Print a fitted sLVM model}
-\usage{
-\method{print}{sLVM}(x, ...)
-}
-\arguments{
-\item{x}{a model fitted by \code{\link{sLVM}}}
-
-\item{...}{optional arguments for compatibility with the generic function, no function implemented}
-}
-\description{
-Print a fitted sLVM model
-}
diff --git a/sjSDM/man/print.sjSDM_cv.Rd b/sjSDM/man/print.sjSDM_cv.Rd
index 55d2098..35f1262 100644
--- a/sjSDM/man/print.sjSDM_cv.Rd
+++ b/sjSDM/man/print.sjSDM_cv.Rd
@@ -1,5 +1,5 @@
 % Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/tuning.R
+% Please edit documentation in R/sjSDM_cv.R
 \name{print.sjSDM_cv}
 \alias{print.sjSDM_cv}
 \title{Print a fitted sjSDM_cv model}
diff --git a/sjSDM/man/print.sjSDManovaIndividual.Rd b/sjSDM/man/print.sjSDManovaIndividual.Rd
deleted file mode 100644
index b21e766..0000000
--- a/sjSDM/man/print.sjSDManovaIndividual.Rd
+++ /dev/null
@@ -1,16 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/anova.R
-\name{print.sjSDManovaIndividual}
-\alias{print.sjSDManovaIndividual}
-\title{Print sjSDM anova}
-\usage{
-\method{print}{sjSDManovaIndividual}(x, ...)
-}
-\arguments{
-\item{x}{an object of \code{\link{anova.sjSDM}}}
-
-\item{...}{optional arguments for compatibility with the generic function, no function implemented}
-}
-\description{
-Print sjSDM anova
-}
diff --git a/sjSDM/man/sLVM.Rd b/sjSDM/man/sLVM.Rd
deleted file mode 100644
index 65109e9..0000000
--- a/sjSDM/man/sLVM.Rd
+++ /dev/null
@@ -1,99 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/sLVM.R
-\name{sLVM}
-\alias{sLVM}
-\title{sLVM}
-\usage{
-sLVM(Y = NULL, X = NULL, formula = NULL, lv = 2L, family,
-  priors = list(1, 1, 1), posterior = c("DiagonalNormal",
-  "LaplaceApproximation", "LowRankMultivariateNormal", "Delta"), iter = 100L,
-  step_size = 10L, lr = list(0.1), device = "cpu", dtype = "float32")
-}
-\arguments{
-\item{Y}{species occurrences}
-
-\item{X}{environmental (abiotic) covariates (matrix or data.frame)}
-
-\item{formula}{formula for environment}
-
-\item{lv}{number of latent variables}
-
-\item{family}{supported distributions: \code{binomial(link=c("logit", "probit"))}, \code{poisson(link=c("log", "identity"))}}
-
-\item{priors}{list of scale priors for beta, lv, and lf}
-
-\item{posterior}{type of posterior distribution}
-
-\item{iter}{number of optimization steps}
-
-\item{step_size}{batch_size}
-
-\item{lr}{learning_rate, can be also a list (for each parameter type)}
-
-\item{device}{which device to be used, "cpu" or "gpu"}
-
-\item{dtype}{which data type, most GPUs support only 32 bit floats.}
-}
-\description{
-Latent-variable model
-}
-\details{
-The function fits the LVM (see Warton et al., 2015) with stochastic variational inference
-
-
-sLVM depends on the anaconda python distribution and pytorch, which need to be installed before being able to use the sjSDM function. 
-See \code{\link{install_sjSDM}}, \code{vignette("Dependencies", package = "sjSDM")}
-}
-\section{Guide}{
-
-Guide is the distribution that is assumed for the posterior distribution
-}
-
-\examples{
-\donttest{
-  
-# Basic workflow:
-## simulate community:
-com = simulate_SDM(env = 3L, species = 5L, sites = 100L)
-
-## fit model:
-model = sLVM(Y = com$response,X = com$env_weights,
-             family = binomial("probit"))
-coef(model)
-summary(model)
-getCov(model)
-
-# get latent variables and factors
-getLF(model)
-getLV(model)
-
-# plot LV ordination
-plot(model)
-
-## fit model with interactions:
-model = sLVM(Y = com$response,
-             X = com$env_weights, formula = ~X1:X2 + X3,
-             family = binomial("probit"))
-summary(model)
-
-## without intercept:
-model = sLVM(Y = com$response,
-             X = com$env_weights, formula = ~0+X1:X2 + X3,
-             family = binomial("probit"))
-## predict with model:
-preds = predict(model, newdata = com$env_weights)
-
-## predictions over parameter distribution:
-preds = predict(model, newdata = com$env_weights, mean_field = FALSE)
-dim(preds)
-}
-}
-\references{
-Warton, D. I., Blanchet, F. G., O’Hara, R. B., Ovaskainen, O., Taskinen, S., Walker, S. C., & Hui, F. K. (2015). So many variables: joint modeling in community ecology. Trends in Ecology & Evolution, 30(12), 766-779.
-}
-\seealso{
-\code{\link{print.sLVM}}, \code{\link{predict.sLVM}}, \code{\link{coef.sLVM}}, \code{\link{summary.sLVM}}, \code{\link{getCov}}, \code{\link{getLF}}, \code{\link{getCI}}, \code{\link{getLF}}
-}
-\author{
-Maximilian Pichler
-}
diff --git a/sjSDM/man/simulate_SDM.Rd b/sjSDM/man/simulate_SDM.Rd
index a28cf27..dea6d79 100644
--- a/sjSDM/man/simulate_SDM.Rd
+++ b/sjSDM/man/simulate_SDM.Rd
@@ -4,10 +4,20 @@
 \alias{simulate_SDM}
 \title{Simulate joint Species Distribution Models}
 \usage{
-simulate_SDM(env = 5L, sites = 100L, species = 5L, Re = NULL,
-  correlation = TRUE, weight_range = c(-1, 1), link = "probit",
-  response = "pa", sparse = NULL, tolerance = 0.05, iter = 20L,
-  seed = NULL)
+simulate_SDM(
+  env = 5L,
+  sites = 100L,
+  species = 5L,
+  Re = NULL,
+  correlation = TRUE,
+  weight_range = c(-1, 1),
+  link = "probit",
+  response = "pa",
+  sparse = NULL,
+  tolerance = 0.05,
+  iter = 20L,
+  seed = NULL
+)
 }
 \arguments{
 \item{env}{number of environment variables}
@@ -22,7 +32,7 @@ simulate_SDM(env = 5L, sites = 100L, species = 5L, Re = NULL,
 
 \item{weight_range}{sample true weights from uniform range, default -1,1}
 
-\item{link}{probit, logit or idential}
+\item{link}{probit, logit or identical}
 
 \item{response}{pa (presence-absence) or count}
 
diff --git a/sjSDM/man/sjSDM.Rd b/sjSDM/man/sjSDM.Rd
index 74da1f3..9c4473b 100644
--- a/sjSDM/man/sjSDM.Rd
+++ b/sjSDM/man/sjSDM.Rd
@@ -1,16 +1,31 @@
 % Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/sjSDM.R
+% Please edit documentation in R/sjSDM.R, R/sjSDM_cv.R
 \name{sjSDM}
 \alias{sjSDM}
-\title{sjSDM}
+\alias{sjSDM.tune}
+\title{Fitting scalable joint Species Distribution Models (sjSDM)}
 \usage{
-sjSDM(Y = NULL, env = NULL, biotic = bioticStruct(), spatial = NULL,
-  family = stats::binomial("probit"), iter = 100L, step_size = NULL,
-  learning_rate = 0.01, se = FALSE, sampling = 1000L, parallel = 0L,
-  control = sjSDMControl(), device = "cpu", dtype = "float32")
+sjSDM(
+  Y = NULL,
+  env = NULL,
+  biotic = bioticStruct(),
+  spatial = NULL,
+  family = stats::binomial("probit"),
+  iter = 100L,
+  step_size = NULL,
+  learning_rate = 0.01,
+  se = FALSE,
+  sampling = 100L,
+  parallel = 0L,
+  control = sjSDMControl(),
+  device = "cpu",
+  dtype = "float32"
+)
+
+sjSDM.tune(object)
 }
 \arguments{
-\item{Y}{matrix of species occurences/responses in range [0,1]}
+\item{Y}{matrix of species occurences/responses in range}
 
 \item{env}{matrix of environmental predictors, object of type \code{\link{linear}} or \code{\link{DNN}}}
 
@@ -28,7 +43,7 @@ sjSDM(Y = NULL, env = NULL, biotic = bioticStruct(), spatial = NULL,
 
 \item{se}{calculate standard errors for environmental coefficients}
 
-\item{sampling}{number of sampling steps for Monte Carlo integreation}
+\item{sampling}{number of sampling steps for Monte Carlo integration}
 
 \item{parallel}{number of cpu cores for the data loader, only necessary for large datasets}
 
@@ -37,17 +52,63 @@ sjSDM(Y = NULL, env = NULL, biotic = bioticStruct(), spatial = NULL,
 \item{device}{which device to be used, "cpu" or "gpu"}
 
 \item{dtype}{which data type, most GPUs support only 32 bit floats.}
+
+\item{object}{object of type \code{\link{sjSDM_cv}}}
+}
+\value{
+An S3 class of type 'sjSDM'. Implemented S3 methods include \code{\link{summary.sjSDM}}, \code{\link{plot.sjSDM}}, \code{\link{print.sjSDM}}, \code{\link{predict.sjSDM}}, and \code{\link{coef.sjSDM}}. For other methods, see section 'See Also'.
 }
 \description{
-fast and accurate joint species model
+\code{sjSDM} is used to fit joint Species Distribution models (jSDMs) using the central processing unit (CPU) or the graphical processing unit (GPU). 
+The default is a multivariate probit model based on a Monte-Carlo approximation of the joint likelihood. 
+\code{sjSDM} can be used to fit linear but also deep neural networks and supports the well known formula syntax.
 }
 \details{
-The function fits a multivariate probit model via Monte-Carlo integration (see Chen et al., 2018) of the joint likelihood for all species. See Pichler and Hartig, 2020 for benchmark results.
+\loadmathjax
+The function fits per default a multivariate probit model via Monte-Carlo integration (see Chen et al., 2018) of the joint likelihood for all species.
+
+\subsection{Model description}{
+
+The most common jSDM structure describes the site (\mjeqn{i = 1, ..., I}{})  by species (\mjeqn{j = 1, ..., J}{}) matrix \mjeqn{Y_{ij}}{} as a function of
+environmental covariates \mjeqn{X_{in}}{}(\mjeqn{n=1,...,N}{} covariates), and the species-species covariance matrix
+\mjeqn{\Sigma}{} accounts for correlations in \mjeqn{e_{ij}}{}:
+
+\mjdeqn{g(Z_{ij}) = \beta_{j0} + \Sigma^{N}_{n=1}X_{in}\beta_{nj} + e_{ij}}{}
+
+\mjeqn{g(.)}{} is a link function. For the multivariate probit model, the link function is:
+
+\mjdeqn{Y_{ij}=1(Z_{ij} > 0)}{}
+
+The probability to observe the occurrence vector \mjeqn{\bf{Y_i}}{} is:
+
+\mjdeqn{Pr(\bf{Y}_i|\bf{X}_i\beta, \Sigma) = \int_{A_{iJ}}...\int_{A_{i1}} \phi_J(\bf{Y}_i^{\ast};\bf{X}_i\beta, \Sigma)  dY_{i1}^{\ast}... dY_{iJ}^{\ast}}{}
+
+in the interval \mjeqn{A_{ij}}{} with \mjeqn{(-\inf, 0]}{} if \mjeqn{Y_{ij}=0}{} and \mjeqn{ [0, +\inf) }{}  if \mjeqn{Y_{ij}=1}{}.
+
+and \mjeqn{\phi}{} being the density function of the multivariate normal distribution. 
 
-sjSDM depends on the anaconda python distribution and pytorch, which need to be installed before being able to use the sjSDM function. 
+The probability of \mjeqn{\bf{Y_i}}{} requires to integrate over \mjeqn{\bf{Y_i^{\ast}}}{} which has no closed analytical expression for more than two species
+which makes the evaluation of the likelihood computationally costly and needs a numerical approximation.
+The previous equation can be expressed more generally as:
+
+\mjdeqn{ \mathcal{L}(\beta, \Sigma; \bf{Y}_i, \bf{X}_i) = \int_{\Omega} \prod_{j=1}^J Pr(Y_{ij}|\bf{X}_i\beta+\zeta) Pr(\zeta|\Sigma) d\zeta  }{}
+
+\code{sjSDM} approximates this integral by \mjeqn{M}{} Monte-Carlo samples from the multivariate normal species-species covariance. 
+After integrating out the covariance term, the remaining part of the likelihood can be calculated as in an univariate case and the average 
+of the \mjeqn{M}{} samples are used to get an approximation of the integral:
+
+\mjdeqn{ \mathcal{L}(\beta, \Sigma; \bf{Y}_i, \bf{X}_i) \approx \frac{1}{M} \Sigma_{m=1}^M \prod_{j=1}^J Pr(Y_{ij}|\bf{X}_i\beta+\zeta_m)}{}
+
+with \mjeqn{ \zeta_m \sim MVN(0, \Sigma)}{}. 
+
+\code{sjSDM} uses 'PyTorch' to run optionally the model on the graphical processing unit (GPU). Python dependencies needs to be  
+installed before being able to use the \code{sjSDM} function. We provide a function which installs automatically python and the python dependencies.
 See \code{\link{install_sjSDM}}, \code{vignette("Dependencies", package = "sjSDM")}
+
+See Pichler and Hartig, 2020 for benchmark results.
 }
-\section{Family}{
+
+\subsection{Supported distributions}{
 
 Currently supported distributions and link functions:
 \itemize{
@@ -57,21 +118,48 @@ Currently supported distributions and link functions:
 }
 }
 
-\section{Installation}{
+\subsection{Space}{
+
+We can extend the model to account for spatial auto-correlation between the sites by:
+
+\mjdeqn{g(Z_{ij}) = \beta_{j0} + \Sigma^{N}_{n=1}X_{in}\beta_{nj} + \Sigma^{M}_{m=1}S_{im}\alpha_{mj} + e_{ij}}{}
+
+There are two ways to generate spatial predictors \mjeqn{S}{}:
 
-\code{\link{install_sjSDM}} should be theoretically able to install conda and pytorch automatically. If \code{\link{sjSDM}} still does not work after reloading RStudio, you can try to solve this in on your own with our trouble shooting guide \code{\link{installation_help}}.
-If the trouble shooting guide did not help, please create an issue on \href{https://github.com/TheoreticalEcology/s-jSDM/issues}{issue tracker} with a copy of the \code{\link{install_diagnostic}} output as a quote.
+\itemize{
+\item trend surface model - using spatial coordinates in a polynomial:
+
+ \code{linear(data=Coords, ~0+poly(X, Y, degree = 2))} 
+ 
+\item eigenvector spatial filtering - using spatial eigenvectors. 
+  Spatial eigenvectors can be generated by the \code{\link{generateSpatialEV}} function:
+  
+  \code{SPV = generateSpatialEV(Coords)}
+  
+  Then we use, for example, the first 20 spatial eigenvectors:
+
+  \code{linear(data=SPV[ ,1:20], ~0+.)}
 }
 
+It is important to set the intercept to 0 in the spatial term (e.g. via \code{~0+.}) because the intercept is already set in the environmental object.
+
+}
+
+\subsection{Installation}{
+
+\code{\link{install_sjSDM}} should be theoretically able to install conda and 'PyTorch' automatically. If \code{\link{sjSDM}} still does not work after reloading RStudio, you can try to solve this on your following our trouble shooting guide \code{\link{installation_help}}.
+If the problem remains, please create an issue on \href{https://github.com/TheoreticalEcology/s-jSDM/issues}{issue tracker} with a copy of the \code{\link{install_diagnostic}} output as a quote. 
+}
+}
 \examples{
-\donttest{
+\dontrun{
   
 # Basic workflow:
 ## simulate community:
 com = simulate_SDM(env = 3L, species = 7L, sites = 100L)
 
 ## fit model:
-model = sjSDM(Y = com$response,env = com$env_weights, iter = 2L) 
+model = sjSDM(Y = com$response,env = com$env_weights, iter = 50L) 
 # increase iter for your own data 
 
 coef(model)
@@ -102,22 +190,23 @@ model = sjSDM(Y = com$response,
 summary(model)
 
 ## without intercept:
-model = sjSDM(Y = com$response,
-              env = linear(data = com$env_weights, formula = ~0+X1:X2 + X3), 
-              se = TRUE,
-              iter = 2L) # increase iter for your own data 
+model = update(model, env_formula = ~0+X1:X2 + X3)
+
 summary(model)
 
 ## predict with model:
 preds = predict(model, newdata = com$env_weights)
 
+## calculate R-squared:
+R2 = Rsquared(model)
+print(R2)
 
 # With spatial terms:
 ## linear spatial model
 XY = matrix(rnorm(200), 100, 2)
 model = sjSDM(Y = com$response, env = linear(com$env_weights), 
               spatial = linear(XY, ~0+X1:X2),
-              iter = 2L) # increase iter for your own data 
+              iter = 50L) # increase iter for your own data 
 summary(model)
 predict(model, newdata = com$env_weights, SP = XY)
 
@@ -126,7 +215,7 @@ predict(model, newdata = com$env_weights, SP = XY)
 SPV = generateSpatialEV(XY)
 model = sjSDM(Y = com$response, env = linear(com$env_weights), 
               spatial = linear(SPV, ~0+., lambda = 0.1),
-              iter = 2L) # increase iter for your own data 
+              iter = 50L) # increase iter for your own data 
 summary(model)
 predict(model, newdata = com$env_weights, SP = SPV)
 
@@ -158,14 +247,14 @@ getCov(model)
 
 
 # Anova 
-com = simulate_SDM(env = 3L, species = 15L, sites = 200L)
+com = simulate_SDM(env = 3L, species = 15L, sites = 200L, correlation = TRUE)
 
 XY = matrix(rnorm(400), 200, 2)
 SPV = generateSpatialEV(XY)
 model = sjSDM(Y = com$response, env = linear(com$env_weights), 
               spatial = linear(SPV, ~0+.), 
-              iter = 2L) # increase iter for your own data 
-result = anova(model, cv = 2L)
+              iter = 50L) # increase iter for your own data 
+result = anova(model)
 print(result)
 plot(result)
 
@@ -199,11 +288,13 @@ getWeights(model)
 \references{
 Chen, D., Xue, Y., & Gomes, C. P. (2018). End-to-end learning for the deep multivariate probit model. arXiv preprint arXiv:1803.08591.
 
-Pichler, M., and Hartig, F. (2020). A new method for faster and more accurate inference of species associations from novel community data. arXiv preprint arXiv:2003.05331.
+Pichler, M., & Hartig, F. (2021). A new joint species distribution model for faster and more accurate inference of species associations from big community data. Methods in Ecology and Evolution, 12(11), 2159-2173.
 }
 \seealso{
-\code{\link{sjSDM_cv}}, \code{\link{DNN}}, \code{\link{plot.sjSDM}}, \code{\link{print.sjSDM}}, \code{\link{predict.sjSDM}}, \code{\link{coef.sjSDM}}, \code{\link{summary.sjSDM}}, \code{\link{getCov}}, \code{\link{simulate.sjSDM}}, \code{\link{getSe}}, \code{\link{anova.sjSDM}}, \code{\link{importance}}
+\code{\link{update.sjSDM}}, \code{\link{sjSDM_cv}}, \code{\link{DNN}}, \code{\link{plot.sjSDM}}, \code{\link{print.sjSDM}}, \code{\link{predict.sjSDM}}, \code{\link{coef.sjSDM}}, \code{\link{summary.sjSDM}}, \code{\link{getCov}}, \code{\link{simulate.sjSDM}}, \code{\link{getSe}}, \code{\link{anova.sjSDM}}, \code{\link{importance}}
 }
 \author{
+Maximilian Pichler
+
 Maximilian Pichler
 }
diff --git a/sjSDM/man/sjSDMControl.Rd b/sjSDM/man/sjSDMControl.Rd
index 791623a..36fed1f 100644
--- a/sjSDM/man/sjSDMControl.Rd
+++ b/sjSDM/man/sjSDMControl.Rd
@@ -4,8 +4,13 @@
 \alias{sjSDMControl}
 \title{sjSDM control object}
 \usage{
-sjSDMControl(optimizer = RMSprop(), scheduler = 0,
-  lr_reduce_factor = 0.99, early_stopping_training = 0, mixed = FALSE)
+sjSDMControl(
+  optimizer = RMSprop(),
+  scheduler = 0,
+  lr_reduce_factor = 0.99,
+  early_stopping_training = 0,
+  mixed = FALSE
+)
 }
 \arguments{
 \item{optimizer}{object of type \code{\link{RMSprop}}, \code{\link{Adamax}}, \code{\link{SGD}}, \code{\link{AccSGD}}, \code{\link{madgrad}}, or \code{\link{AdaBound}}}
diff --git a/sjSDM/man/sjSDM_cv.Rd b/sjSDM/man/sjSDM_cv.Rd
index 2fd59af..d29dd3b 100644
--- a/sjSDM/man/sjSDM_cv.Rd
+++ b/sjSDM/man/sjSDM_cv.Rd
@@ -1,16 +1,30 @@
 % Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/tuning.R
+% Please edit documentation in R/sjSDM_cv.R
 \name{sjSDM_cv}
 \alias{sjSDM_cv}
 \title{Cross validation of elastic net tuning}
 \usage{
-sjSDM_cv(Y, env = NULL, biotic = bioticStruct(), spatial = NULL,
-  tune = c("random", "grid"), CV = 5L, tune_steps = 20L,
-  alpha_cov = seq(0, 1, 0.1), alpha_coef = seq(0, 1, 0.1),
-  alpha_spatial = seq(0, 1, 0.1), lambda_cov = 2^seq(-10, -1, length.out =
-  20), lambda_coef = 2^seq(-10, -0.5, length.out = 20),
-  lambda_spatial = 2^seq(-10, -0.5, length.out = 20), device = "cpu",
-  n_cores = NULL, n_gpu = NULL, sampling = 5000L, blocks = 1L, ...)
+sjSDM_cv(
+  Y,
+  env = NULL,
+  biotic = bioticStruct(),
+  spatial = NULL,
+  tune = c("random", "grid"),
+  CV = 5L,
+  tune_steps = 20L,
+  alpha_cov = seq(0, 1, 0.1),
+  alpha_coef = seq(0, 1, 0.1),
+  alpha_spatial = seq(0, 1, 0.1),
+  lambda_cov = 2^seq(-10, -1, length.out = 20),
+  lambda_coef = 2^seq(-10, -0.5, length.out = 20),
+  lambda_spatial = 2^seq(-10, -0.5, length.out = 20),
+  device = "cpu",
+  n_cores = NULL,
+  n_gpu = NULL,
+  sampling = 5000L,
+  blocks = 1L,
+  ...
+)
 }
 \arguments{
 \item{Y}{species occurrence matrix}
@@ -43,19 +57,22 @@ sjSDM_cv(Y, env = NULL, biotic = bioticStruct(), spatial = NULL,
 
 \item{n_cores}{number of cores for parallelization}
 
-\item{n_gpu}{number of gpus}
+\item{n_gpu}{number of GPUs}
 
-\item{sampling}{number of sampling steps for Monte Carlo integreation}
+\item{sampling}{number of sampling steps for Monte Carlo integration}
 
-\item{blocks}{blocks of parallen tuning steps}
+\item{blocks}{blocks of parallel tuning steps}
 
 \item{...}{arguments passed to sjSDM, see \code{\link{sjSDM}}}
 }
+\value{
+An S3 class of type 'sjSDM_cv'. Implemented S3 methods include \code{\link{sjSDM.tune}}, \code{\link{plot.sjSDM_cv}}, \code{\link{print.sjSDM_cv}}, and \code{\link{summary.sjSDM_cv}}
+}
 \description{
 Cross validation of elastic net tuning
 }
 \examples{
-\donttest{
+\dontrun{
 # simulate sparse community:
 com = simulate_SDM(env = 5L, species = 25L, sites = 100L, sparse = 0.5)
 
@@ -83,19 +100,12 @@ summary(tune_results)
 # visualize tuning and best points:
 best = plot(tune_results, perf = "logLik")
 
-# fit model with new regularization paramter:
-model = sjSDM(Y = com$response,
-              env = linear(com$env_weights, 
-                              lambda = best[["lambda_coef"]],
-                              alpha = best[["alpha_coef"]]),
-              biotic = bioticStruct(lambda = best[["lambda_cov"]],
-                                    alpha = best[["alpha_cov"]]),
-              iter = 2L # increase it for your own data 
-              )
+# fit model with best regularization paramter:
+model = sjSDM.tune(tune_results)
 
 summary(model)
 }
 }
 \seealso{
-\code{\link{plot.sjSDM_cv}}, \code{\link{print.sjSDM_cv}}, \code{\link{summary.sjSDM_cv}}
+\code{\link{plot.sjSDM_cv}}, \code{\link{print.sjSDM_cv}}, \code{\link{summary.sjSDM_cv}}, \code{\link{sjSDM.tune}}
 }
diff --git a/sjSDM/man/spatialRE.Rd b/sjSDM/man/spatialRE.Rd
index 5c551f7..f83d4f5 100644
--- a/sjSDM/man/spatialRE.Rd
+++ b/sjSDM/man/spatialRE.Rd
@@ -13,14 +13,14 @@ spatialRE(re = NULL)
 define spatial random effects (random intercepts for sites)
 }
 \examples{
-\donttest{
+\dontrun{
   
 # Basic workflow:
 ## simulate community:
 com = simulate_SDM(env = 3L, species = 7L, sites = 100L)
 
 ## fit model:
-model = sjSDM(Y = com$response,env = com$env_weights, iter = 2L) 
+model = sjSDM(Y = com$response,env = com$env_weights, iter = 50L) 
 # increase iter for your own data 
 
 coef(model)
@@ -51,22 +51,23 @@ model = sjSDM(Y = com$response,
 summary(model)
 
 ## without intercept:
-model = sjSDM(Y = com$response,
-              env = linear(data = com$env_weights, formula = ~0+X1:X2 + X3), 
-              se = TRUE,
-              iter = 2L) # increase iter for your own data 
+model = update(model, env_formula = ~0+X1:X2 + X3)
+
 summary(model)
 
 ## predict with model:
 preds = predict(model, newdata = com$env_weights)
 
+## calculate R-squared:
+R2 = Rsquared(model)
+print(R2)
 
 # With spatial terms:
 ## linear spatial model
 XY = matrix(rnorm(200), 100, 2)
 model = sjSDM(Y = com$response, env = linear(com$env_weights), 
               spatial = linear(XY, ~0+X1:X2),
-              iter = 2L) # increase iter for your own data 
+              iter = 50L) # increase iter for your own data 
 summary(model)
 predict(model, newdata = com$env_weights, SP = XY)
 
@@ -75,7 +76,7 @@ predict(model, newdata = com$env_weights, SP = XY)
 SPV = generateSpatialEV(XY)
 model = sjSDM(Y = com$response, env = linear(com$env_weights), 
               spatial = linear(SPV, ~0+., lambda = 0.1),
-              iter = 2L) # increase iter for your own data 
+              iter = 50L) # increase iter for your own data 
 summary(model)
 predict(model, newdata = com$env_weights, SP = SPV)
 
@@ -107,14 +108,14 @@ getCov(model)
 
 
 # Anova 
-com = simulate_SDM(env = 3L, species = 15L, sites = 200L)
+com = simulate_SDM(env = 3L, species = 15L, sites = 200L, correlation = TRUE)
 
 XY = matrix(rnorm(400), 200, 2)
 SPV = generateSpatialEV(XY)
 model = sjSDM(Y = com$response, env = linear(com$env_weights), 
               spatial = linear(SPV, ~0+.), 
-              iter = 2L) # increase iter for your own data 
-result = anova(model, cv = 2L)
+              iter = 50L) # increase iter for your own data 
+result = anova(model)
 print(result)
 plot(result)
 
diff --git a/sjSDM/man/summary.sLVM.Rd b/sjSDM/man/summary.sLVM.Rd
deleted file mode 100644
index 1ce7116..0000000
--- a/sjSDM/man/summary.sLVM.Rd
+++ /dev/null
@@ -1,16 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/sLVM.R
-\name{summary.sLVM}
-\alias{summary.sLVM}
-\title{Return summary of a fitted sLVM model}
-\usage{
-\method{summary}{sLVM}(object, ...)
-}
-\arguments{
-\item{object}{a model fitted by \code{\link{sLVM}}}
-
-\item{...}{optional arguments for compatibility with the generic function, no functionality implemented}
-}
-\description{
-Return summary of a fitted sLVM model
-}
diff --git a/sjSDM/man/summary.sjSDM_cv.Rd b/sjSDM/man/summary.sjSDM_cv.Rd
index 31e0a07..b823393 100644
--- a/sjSDM/man/summary.sjSDM_cv.Rd
+++ b/sjSDM/man/summary.sjSDM_cv.Rd
@@ -1,5 +1,5 @@
 % Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/tuning.R
+% Please edit documentation in R/sjSDM_cv.R
 \name{summary.sjSDM_cv}
 \alias{summary.sjSDM_cv}
 \title{Return summary of a fitted sjSDM_cv model}
diff --git a/sjSDM/man/update.sjSDM.Rd b/sjSDM/man/update.sjSDM.Rd
new file mode 100644
index 0000000..738187d
--- /dev/null
+++ b/sjSDM/man/update.sjSDM.Rd
@@ -0,0 +1,25 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/sjSDM.R
+\name{update.sjSDM}
+\alias{update.sjSDM}
+\title{Update and re-fit a model call}
+\usage{
+\method{update}{sjSDM}(object, env_formula = NULL, spatial_formula = NULL, biotic = NULL, ...)
+}
+\arguments{
+\item{object}{of class 'sjSDM'}
+
+\item{env_formula}{new environmental formula}
+
+\item{spatial_formula}{new spatial formula}
+
+\item{biotic}{new biotic config}
+
+\item{...}{additional arguments}
+}
+\value{
+An S3 class of type 'sjSDM'.
+}
+\description{
+Update and re-fit a model call
+}
diff --git a/sjSDM/man/varPartTypIII.Rd b/sjSDM/man/varPartTypIII.Rd
deleted file mode 100644
index e74b793..0000000
--- a/sjSDM/man/varPartTypIII.Rd
+++ /dev/null
@@ -1,21 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/importance.R
-\name{varPartTypIII}
-\alias{varPartTypIII}
-\title{varPartTypIII}
-\usage{
-varPartTypIII(model, order = NULL, ...)
-}
-\arguments{
-\item{model}{object fitted by \code{\link{sjSDM}}}
-
-\item{order}{which modules should be removed: E (environment), S (spatial), or B (biotic)}
-
-\item{...}{arguments passed to \code{\link{Rsquared}}}
-}
-\description{
-variation partitioning Typ III
-}
-\author{
-Maximilian Pichler
-}
diff --git a/sjSDM/vignettes/Dependencies.Rmd b/sjSDM/vignettes/Dependencies.Rmd
index 35474e8..d954cd7 100644
--- a/sjSDM/vignettes/Dependencies.Rmd
+++ b/sjSDM/vignettes/Dependencies.Rmd
@@ -1,5 +1,5 @@
 ---
-title: "sjSDM: help on installing dependencies"
+title: "sjSDM: Help with the installation of dependencies"
 author: "Maximilian Pichler & Florian Hartig, Theoretical Ecology, University of Regensburg"
 date: "`r Sys.Date()`"
 output: 
@@ -7,7 +7,7 @@ output:
     toc: true
     toc_depth: 3
 vignette: >
-  %\VignetteIndexEntry{Dependencies}
+  %\VignetteIndexEntry{sjSDM: Help with the installation of dependencies}
   \usepackage[utf8]{inputenc}
   %\VignetteEngine{knitr::rmarkdown}
 abstract: "This document explains how to install dependencies for the sjSDM package. \n \n \n"
@@ -22,211 +22,141 @@ set.seed(123)
 
 
 ```{r global_options, include=FALSE}
-knitr::opts_chunk$set(fig.width=7, fig.height=4.5, fig.align='center', warning=FALSE, message=FALSE, cache = F)
+knitr::opts_chunk$set(fig.width=7, fig.height=4.5, fig.align='center', warning=FALSE, message=FALSE, cache = FALSE, eval = FALSE)
 ```
 
+The `r knitr::inline_expr('sjSDM::install_sjSDM()')` function can install automatically all necessary 'python' dependencies but it can fail sometimes because of individual system settings or if other 'python'/'conda' installations get into the way. 
 
+## PyTorch Installation - Before you start:
 
+A few notes before you start with the installation (skip this point if you 
+do not know conda):
 
-# Before you start
-A few notes before you start with the installation:
-
-- existing conda installations (skip this point if you do not know conda): make sure you have the latest conda3/miniconda3 installation and remove unneccessary conda installations.
-- existing conda/virtualenv (skip this point if you do not know conda): the R package reticulate has problems to find the right environment and it is better to remove unneccessary environments (see the [troubleshooting](#troubleshooting) section
-
-
-
+* existing 'conda' installations: make sure you have the latest 'conda' or 'miniconda' version and remove unnecessary 'conda' installations.
+* existing 'conda' or 'virtualenv' environments (skip this point if you do not know 'conda'): we currently enforce the usage of a specific environment called 'r-sjsdm',so if you want use a custom environment it should be named 'r-sjsdm'
+ 
+ 
+## Windows - automatic installation:
+ 
+Sometimes the automatic 'miniconda' installation (via 
+`r knitr::inline_expr('sjSDM::install_sjSDM()')` ).doesn't work because of white spaces in the user's name. But you can easily download and install 'conda' on your own:
 
-# Windows - automatic installation 
-Conda is the easiest way to install python and python packages on windows:
-Install the latest [conda version](https://www.anaconda.com/distribution/)
+Download and install the latest ['conda' version](https://www.anaconda.com/products/individual)
 
-Afterwards, run in R:
+Afterwards run:
 ```{r,eval=FALSE}
-devtools::install_github("https://github.com/TheoreticalEcology/s-jSDM", subdir = "sjSDM")
-library(sjSDM)
 install_sjSDM(version = c("gpu")) # or "cpu" if you do not have a proper gpu device
 ```
-Try to load the package and run the example from ?sjSDM, if this doesn't work:
-
-- Restart RStudio
-- Install manually pytorch, see the following section
-
 
  
-# Windows - manual installation {#ww}
-Conda is the easiest way to install python and python packages on windows:
+Reload the package and run the example, if this doesn't work:
 
-* Install the latest [conda version](https://www.anaconda.com/distribution/)
-* Open the command window (cmd.exe - hit windows key + r and write cmd)
+* Restart RStudio
+* Install manually pytorch, see the following section
+ 
+  
+## Windows - manual installation:
+ 
+Download and install the latest ['conda' version](https://www.anaconda.com/products/individual)
 
-Run:
-```
-$ conda create --name sjSDM_env python=3.7
-$ conda activate sjSDM_env
-$ conda install pytorch torchvision cpuonly -c pytorch # cpu
-$ conda install pytorch torchvision cudatoolkit=10.1 -c pytorch #gpu
-```
+Open the command window (cmd.exe - hit windows key + r and write cmd)
 
-Start R and run:
-Download, install, and test the package:
-```{r,eval=FALSE}
-devtools::install_github("https://github.com/TheoreticalEcology/s-jSDM", subdir = "sjSDM")
-library(sjSDM)
-community <- simulate_SDM(sites = 100, species = 10, env = 5)
-Env <- community$env_weights
-Occ <- community$response
+Run in cmd.exe:
 
-model <- sjSDM(X = Env, Y = Occ, formula = ~0+X1*X2 + X3 + X4)
-summary(model)
+```{bash, eval=FALSE}
+conda create --name r-sjsdm python=3.7
+conda activate r-sjsdm
+conda install pytorch torchvision cpuonly -c pytorch # cpu
+conda install pytorch torchvision cudatoolkit=11.3 -c pytorch #gpu
+python -m pip install pyro-ppl torch_optimizer madgrad
 ```
-Try to load the package and run the [example](#example), if this doesn't work:
+ 
+ 
+Restart R, try to run the example, and if this doesn't work:
 
 * Restart RStudio
-* See the [troubleshooting](#troubleshooting) section
-
-
-
-
-# Linux - automatic installation
-Run in R:
+* See the 'Help and bugs' section
+ 
+    
+## Linux - automatic installation:
+ 
+Run in R: 
 ```{r,eval=FALSE}
-devtools::install_github("https://github.com/TheoreticalEcology/s-jSDM", subdir = "sjSDM")
-library(sjSDM)
 install_sjSDM(version = c("gpu")) # or "cpu" if you do not have a proper gpu device
 ```
-Try to load the package and run the [example](#example), if this doesn't work:
-
-* Restart RStudio
-* Install manually pytorch, see the following section
 
+Restart R try to run the example, if this doesn't work:
 
+* Restart RStudio
+* Install manually 'PyTorch', see the following section
 
+  
+  
+## Linux - manual installation:
+ 
+We strongly advise to use a 'conda' environment but a virtual environment should also work. The only requirement is that it is named 'r-sjsdm'
 
+Download and install the latest ['conda' version](https://www.anaconda.com/products/individual)
 
-# Linux - manual installation {#lm}
-## Via pip
-python3 is pre-installed on most linux distributions, but you have to check that the minimal requirement of python >= 3.6 is met: 
-
-```
-$ python3 --version 
-$ python --version
-```
-
-Check if pip is installed:
-```
-$ pip3 --version 
-$ pip --version
-```
-If not then install pip:
-```
-$ sudo apt install python3-pip # for ubuntu/deb   # e.g. for ubuntu
-```
-
-It depends on your ENVIRONMENTAL variables whether pip or pip3 corresponds to python3. You can check the python version of pip via:
-```
-$ pip --version
-```
-
-In my case, I have to use "pip3":
-
-```
-$ pip3 install torch==1.4.0+cpu torchvision==0.5.0+cpu -f https://download.pytorch.org/whl/torch_stable.html #cpu
-$ pip3 install torch torchvision #gpu
-```
-
-Run in R:
-```{r,eval=FALSE}
-devtools::install_github("https://github.com/TheoreticalEcology/s-jSDM", subdir = "sjSDM")
-library(sjSDM)
+Open your terminal and run:
+```{bash, eval=FALSE}
+conda create --name r-sjsdm python=3.7
+conda activate r-sjsdm
+conda install pytorch torchvision cpuonly -c pytorch # cpu
+conda install pytorch torchvision cudatoolkit=11.3 -c pytorch #gpu
+python -m pip install pyro-ppl torch_optimizer madgrad
 ```
-Try to load the package and run the [example](#example), if this doesn't work:
+ 
+ 
+Restart R try to run the example, if this doesn't work:
 
 * Restart RStudio
-* See the [troubleshooting](#troubleshooting) section
-
-
-## Via virtualenv
-Create a virtualenv and install dependencies:
-```
-$ python3 -m pip install --user virtualenv
-$ python3 -m venv ~/sjSDM_env
-$ source ~/sjSDM_env/bin/activate
-$ pip install torch==1.4.0+cpu torchvision==0.5.0+cpu -f https://download.pytorch.org/whl/torch_stable.html #cpu
-$ pip install torch torchvision #gpu
-```
-
-start R from within the environment and run:
+* See the 'Help and bugs' section
+ 
+ 
+## MacOS - automatic installation:
+ 
+Run in R: 
 ```{r,eval=FALSE}
-devtools::install_github("https://github.com/TheoreticalEcology/s-jSDM", subdir = "sjSDM")
-library(sjSDM)
-```
-Try to load the package and run the [example](#example), if this doesn't work:
-
-* Restart R/RStudio
-* See the [troubleshooting](#troubleshooting) section
-
-
-## Via conda
-Install the latest [conda version](https://www.anaconda.com/distribution/) and run:
+install_sjSDM()
 ```
-$ conda create --name sjSDM_env python=3.7
-$ conda activate sjSDM_env
-$ conda install pytorch torchvision cpuonly -c pytorch # cpu
-$ conda install pytorch torchvision cudatoolkit=10.1 -c pytorch #gpu
-```
-start RStudio from  within the conda env and run:
-Try to load the package and run the [example](#example), if this doesn't work:
-
-* Restart R/RStudio
-* See the [troubleshooting](#troubleshooting) section
-
 
+Restart R try to run the example, if this doesn't work:
 
+* Restart RStudio
+* Install manually 'PyTorch', see the following section
 
-# MacOS
-## Conda
-Install the latest [conda version](https://www.anaconda.com/distribution/) and run:
-```
-$ conda create --name sjSDM_env python=3.7
-$ conda activate sjSDM_env
-$ conda install pytorch torchvision cpuonly -c pytorch # cpu
-```
-start R and run:
-```{r,eval=FALSE}
-devtools::install_github("https://github.com/TheoreticalEcology/s-jSDM", subdir = "sjSDM")
-library(sjSDM)
-```
-Try to load the package and run the [example](#example), if this doesn't work:
-
-* Restart R/RStudio
-* See the [troubleshooting](#troubleshooting) section
-
-For GPU support on MacOS, you have to install the cuda binaries yourself, see [PyTorch for help](https://pytorch.org/)
+ 
+ 
+## MacOS - manual installation:
+ 
+We strongly advise to use a 'conda' environment but a virtual environment should also work. The only requirement is that it is named 'r-sjsdm'
 
+Download and install the latest conda [conda version](https://www.anaconda.com/products/individual)
 
-# Troubleshooting
-After several installation attempts you might have corrupt and unneccessary conda environments which we have to remove:
-Open the shell (Windows users: run cmd.exe):
-```
-$ conda env list
+Open your terminal and run:
+```{bash, eval=FALSE}
+conda create --name r-sjsdm python=3.7
+conda activate r-sjsdm
+python -m pip install torch torchvision torchaudio 
+python -m pip install pyro-ppl torch_optimizer madgrad
 ```
-will list the paths to all your environments, except for the "base" env, delete them via:
-```
-$ rm - r <path-to-env1>
-$ rm - r <path-to-env2>
-```
-Then continue with the manual install instructions:
+ 
+ 
+Restart R try to run the example, if this doesn't work:
 
-1. [Windows](#ww)
-2. [Linux](#lw)
-3. [MacOS](#macos)
+* Restart RStudio
+* See the 'Help and bugs' section
 
+## Help and bugs
 
+* ask for help via the [issue tracker](https://github.com/TheoreticalEcology/s-jSDM/issues). Please post the output of  `r knitr::inline_expr('sjSDM::install_diagnostic()')`as a quote. 
+* report bugs with a [reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-emple)
+ via the [issue tracker](https://github.com/TheoreticalEcology/s-jSDM/issues)
 
 
 
-# Example
+## Example
 ```{r,eval=FALSE}
 library(sjSDM)
 community <- simulate_SDM(sites = 100, species = 10, env = 5)
diff --git a/sjSDM/vignettes/sjSDM.R b/sjSDM/vignettes/sjSDM.R
index 7d0ea42..45e807c 100644
--- a/sjSDM/vignettes/sjSDM.R
+++ b/sjSDM/vignettes/sjSDM.R
@@ -65,7 +65,7 @@ knitr::opts_chunk$set(fig.width=7, fig.height=4.5, fig.align='center', warning=F
 #  summary(model)
 
 ## ----eval=FALSE---------------------------------------------------------------
-#  an = anova(model, cv = FALSE)
+#  an = anova(model)
 #  plot(an)
 
 ## ----eval=FALSE---------------------------------------------------------------
@@ -135,48 +135,11 @@ knitr::opts_chunk$set(fig.width=7, fig.height=4.5, fig.align='center', warning=F
 #  summary(model)
 
 ## ----eval=FALSE---------------------------------------------------------------
-#  Y_pa = scales::rescale(log(Y+0.001))
+#  zero_one = function(x) function(x) (x-min(x))/(max(x) -min(x))
+#  Y_pa = zero_one(log(Y+0.001))
 
 ## ----eval=FALSE---------------------------------------------------------------
 #  
 #  model = sjSDM(Y_pa, env = linear(X, ~.), se = TRUE, iter = 50L, family = binomial("logit"))
 #  summary(model)
 
-## ----eval=FALSE---------------------------------------------------------------
-#  com = simulate_SDM(env = 2L, species = 10L, sites = 100L)
-#  Y = com$response
-#  X = com$env_weights
-#  
-#  lvm = sLVM(Y, X, family = binomial("probit"))
-#  summary(lvm)
-
-## ----eval=FALSE---------------------------------------------------------------
-#  lvm = sLVM(Y, X, family = binomial("probit"), device = "cpu")
-#  summary(lvm)
-
-## ----eval=FALSE---------------------------------------------------------------
-#  lvm = sLVM(Y, X, formula = ~ 0+X1:X2,family = binomial("probit"), device = "cpu")
-#  summary(lvm)
-#  
-#  coef(lvm)
-#  
-#  print(lvm)
-
-## ----eval=FALSE---------------------------------------------------------------
-#  lvm = sLVM(Y, X, family = binomial("probit"), device = "cpu")
-#  pred = predict(lvm)
-#  dim(pred)
-#  hist(pred[,1,1])
-
-## ----eval=FALSE---------------------------------------------------------------
-#  lvm = sLVM(Y, X, family = binomial("probit"), device = "cpu")
-#  pred = predict(lvm,newdata = X, mean_field = TRUE)
-#  dim(pred)
-
-## ----eval=FALSE---------------------------------------------------------------
-#  pred = predict(lvm,newdata = X, mean_field = FALSE)
-#  dim(pred)
-
-## ----eval=FALSE---------------------------------------------------------------
-#  plot(lvm)
-
diff --git a/sjSDM/vignettes/sjSDM.Rmd b/sjSDM/vignettes/sjSDM.Rmd
index 68db503..599a2be 100644
--- a/sjSDM/vignettes/sjSDM.Rmd
+++ b/sjSDM/vignettes/sjSDM.Rmd
@@ -6,7 +6,7 @@ output:
   rmarkdown::html_vignette:
     toc: true
 vignette: >
-  %\VignetteIndexEntry{Vignette for the sjSDM package}
+  %\VignetteIndexEntry{sjSDM: a scalable joint Species Distribution Model}
   \usepackage[utf8]{inputenc}
   %\VignetteEngine{knitr::rmarkdown}
 abstract: "sjSDM is a scalable joint species distribution model based on Monte-Carlo intergration of the joint likelihood. \n \n \n"
@@ -48,7 +48,7 @@ install_sjSDM(method = "gpu")
 ```
 
 
-More details on and trouble-shooting for installing the neccessary dependencies is explained in the vignette dependencies, call 
+More details on and trouble-shooting for installing the necessary dependencies is explained in the vignette dependencies, call 
 
 ```{r,eval = F}
 vignette("Dependencies", package = "sjSDM")
@@ -74,7 +74,7 @@ com = simulate_SDM(env = 3L, species = 5L, sites = 100L)
 
 # Fitting a model
 
-The model is then fit with the function sjSDM(). You have to provide predcitors (can be also a data.frame) and response as matrices. 
+The model is then fit with the function sjSDM(). You have to provide predictors (can be also a data.frame) and response as matrices. 
 
 ```{r,eval=FALSE}
 model = sjSDM(Y = com$response, env = com$env_weights, iter = 100L, se=TRUE)
@@ -113,7 +113,7 @@ summary(model)
 
 # Handling spatial autocorrelation
 ## Simulating spatial data
-JSDM account for correlation between species within communities (sites), in real datasets, however, communities (sites) are additionally correlated (== spatial autocorrelation).
+sSDM account for correlation between species within communities (sites), in real datasets, however, communities (sites) are often additionally correlated (== spatial autocorrelation).
 
 Let's first simulate test data:
 1) Simulate JSDM without a link (normal response)
@@ -153,9 +153,9 @@ summary(model)
 
 # Further analyses
 ## Anova
-Analysis of variance for the two/three different compenents (environment, biotic associations, and space (optional)). sjSDM supports cross-validation in the anova to correct for the complexity of the model, which is somehow difficult to estimate:
+Type I analysis of variance for the two/three different components (environment, biotic associations, and space (optional)).
 ```{r,eval=FALSE}
-an = anova(model, cv = FALSE)
+an = anova(model)
 plot(an)
 ```
 
@@ -254,7 +254,7 @@ summary(model)
 
 # Fitting other distributions (e.g. species frequencies)
 sjSDM supports other responses than presence-absence data:
-Simulate non-prescence-absence data:
+Simulate non-presence-absence data:
 ```{r,eval=FALSE}
 com = simulate_SDM(env = 3L, species = 5L, sites = 100L,link = "identical", response = "count") # samples from a Poisson distribution
 X = com$env_weights
@@ -277,7 +277,8 @@ summary(model)
 ## Workaround to use the default binomial with probit or logit link:
 The log-normalization is one way to transform species counts into quasi-probabilities in the range of [0,1]:
 ```{r,eval=FALSE}
-Y_pa = scales::rescale(log(Y+0.001))
+zero_one = function(x) function(x) (x-min(x))/(max(x) -min(x))
+Y_pa = zero_one(log(Y+0.001))
 ```
 
 We can use the quasi probabilities the same way as presence-absence data:
@@ -285,62 +286,4 @@ We can use the quasi probabilities the same way as presence-absence data:
 
 model = sjSDM(Y_pa, env = linear(X, ~.), se = TRUE, iter = 50L, family = binomial("logit"))
 summary(model)
-```
-
-
-# Fitting the latent variable model (still in development)
-We also support fitting JSDM by the LVM via variational inference:
-
-```{r,eval=FALSE}
-com = simulate_SDM(env = 2L, species = 10L, sites = 100L)
-Y = com$response
-X = com$env_weights
-
-lvm = sLVM(Y, X, family = binomial("probit"))
-summary(lvm)
-```
-
-The model can be run either on the CPU or the GPU:
-```{r,eval=FALSE}
-lvm = sLVM(Y, X, family = binomial("probit"), device = "cpu")
-summary(lvm)
-```
-
-Same functionalities as for sjSDM:
-```{r,eval=FALSE}
-lvm = sLVM(Y, X, formula = ~ 0+X1:X2,family = binomial("probit"), device = "cpu")
-summary(lvm)
-
-coef(lvm)
-
-print(lvm)
-```
-
-## Predictions with sLVM
-Get posterior distribution of predictions:
-```{r,eval=FALSE}
-lvm = sLVM(Y, X, family = binomial("probit"), device = "cpu")
-pred = predict(lvm)
-dim(pred)
-hist(pred[,1,1])
-```
-
-Newdata, get mean prediction:
-```{r,eval=FALSE}
-lvm = sLVM(Y, X, family = binomial("probit"), device = "cpu")
-pred = predict(lvm,newdata = X, mean_field = TRUE)
-dim(pred)
-```
-
-Newdata, get posterior distribution of predictions:
-```{r,eval=FALSE}
-pred = predict(lvm,newdata = X, mean_field = FALSE)
-dim(pred)
-```
-
-## Ordiation
-model-based ordination based on the LVM:
-```{r,eval=FALSE}
-plot(lvm)
-```
-
+```
\ No newline at end of file
diff --git a/trace.json b/trace.json
deleted file mode 100644
index 708324c..0000000
--- a/trace.json
+++ /dev/null
@@ -1,1 +0,0 @@
-[{"name": "aten::zeros", "ph": "X", "ts": 1281.625, "dur": 36.70900000000006, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 1291.292, "dur": 15.792000000000144, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::zero_", "ph": "X", "ts": 1313.959, "dur": 3.125, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "importance", "ph": "X", "ts": 2000.167, "dur": 376385.16699999996, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 2006.25, "dur": 3.9169999999999163, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 3456.375, "dur": 2.2919999999999163, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::set_", "ph": "X", "ts": 3466.709, "dur": 5.625, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::to", "ph": "X", "ts": 3479.959, "dur": 50.875, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty_strided", "ph": "X", "ts": 3486.125, "dur": 3.4589999999998327, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::copy_", "ph": "X", "ts": 3494.75, "dur": 35.20899999999983, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::detach_", "ph": "X", "ts": 3537.334, "dur": 7.75, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "detach_", "ph": "X", "ts": 3539.5, "dur": 4.791999999999916, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 6455.209, "dur": 5.125, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::set_", "ph": "X", "ts": 6468.292, "dur": 4.75, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::to", "ph": "X", "ts": 6480.042, "dur": 1755.9170000000004, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty_strided", "ph": "X", "ts": 6485.375, "dur": 3.917000000000371, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::copy_", "ph": "X", "ts": 6494.084, "dur": 1739.7910000000002, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::detach_", "ph": "X", "ts": 8254.459, "dur": 6.540999999999258, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "detach_", "ph": "X", "ts": 8257.167, "dur": 3.25, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 8349.25, "dur": 5.166999999999462, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::set_", "ph": "X", "ts": 8361.625, "dur": 5.5, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::to", "ph": "X", "ts": 8373.0, "dur": 40.16699999999946, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty_strided", "ph": "X", "ts": 8378.0, "dur": 4.75, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::copy_", "ph": "X", "ts": 8387.709, "dur": 24.70799999999872, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::detach_", "ph": "X", "ts": 8416.459, "dur": 3.375, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "detach_", "ph": "X", "ts": 8418.084, "dur": 1.0829999999987194, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::t", "ph": "X", "ts": 8428.917, "dur": 26.75, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::transpose", "ph": "X", "ts": 8437.125, "dur": 13.291999999999462, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::as_strided", "ph": "X", "ts": 8444.25, "dur": 4.375, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::matmul", "ph": "X", "ts": 8462.125, "dur": 362747.834, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::mm", "ph": "X", "ts": 8467.209, "dur": 362740.041, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 8476.167, "dur": 3.625, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::ones", "ph": "X", "ts": 371292.375, "dur": 31.708999999973457, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 371297.5, "dur": 9.875, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::fill_", "ph": "X", "ts": 371311.625, "dur": 12.0, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::diag", "ph": "X", "ts": 371330.75, "dur": 1099.25, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 371335.542, "dur": 0.5419999999576248, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::diag", "ph": "X", "ts": 371338.584, "dur": 1086.8330000000424, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::resize_", "ph": "X", "ts": 371342.459, "dur": 4.083000000042375, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::zero_", "ph": "X", "ts": 371348.625, "dur": 1034.7089999999735, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::fill_", "ph": "X", "ts": 371350.334, "dur": 1025.5830000000424, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::add", "ph": "X", "ts": 372466.625, "dur": 2626.5, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::t", "ph": "X", "ts": 375144.709, "dur": 29.916000000026543, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::transpose", "ph": "X", "ts": 375155.834, "dur": 14.375, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::as_strided", "ph": "X", "ts": 375163.0, "dur": 5.583999999973457, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::matmul", "ph": "X", "ts": 375180.292, "dur": 45.625, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::mm", "ph": "X", "ts": 375184.292, "dur": 40.75, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 375192.917, "dur": 8.375, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::einsum", "ph": "X", "ts": 375272.709, "dur": 152.375, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::permute", "ph": "X", "ts": 375281.125, "dur": 9.625, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::as_strided", "ph": "X", "ts": 375287.0, "dur": 1.0839999999734573, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::permute", "ph": "X", "ts": 375292.834, "dur": 5.916000000026543, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::as_strided", "ph": "X", "ts": 375296.334, "dur": 0.7080000000423752, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::permute", "ph": "X", "ts": 375304.667, "dur": 6.2079999999841675, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::as_strided", "ph": "X", "ts": 375307.917, "dur": 0.7079999999841675, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::reshape", "ph": "X", "ts": 375312.75, "dur": 10.042000000015832, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::view", "ph": "X", "ts": 375315.959, "dur": 6.166000000026543, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::permute", "ph": "X", "ts": 375324.459, "dur": 5.583000000042375, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::as_strided", "ph": "X", "ts": 375327.834, "dur": 0.6660000000265427, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::reshape", "ph": "X", "ts": 375331.417, "dur": 5.4579999999841675, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::view", "ph": "X", "ts": 375332.792, "dur": 3.5, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::bmm", "ph": "X", "ts": 375338.959, "dur": 56.708000000042375, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 375342.584, "dur": 0.7080000000423752, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::resize_", "ph": "X", "ts": 375346.875, "dur": 5.4170000000158325, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::view", "ph": "X", "ts": 375400.167, "dur": 6.166999999957625, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::permute", "ph": "X", "ts": 375407.834, "dur": 7.791000000026543, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::as_strided", "ph": "X", "ts": 375412.375, "dur": 0.9170000000158325, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::view", "ph": "X", "ts": 375417.917, "dur": 3.416999999957625, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::einsum", "ph": "X", "ts": 375438.584, "dur": 39.75, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::permute", "ph": "X", "ts": 375442.167, "dur": 7.166999999957625, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::as_strided", "ph": "X", "ts": 375446.375, "dur": 1.125, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::permute", "ph": "X", "ts": 375451.125, "dur": 4.9170000000158325, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::as_strided", "ph": "X", "ts": 375454.0, "dur": 0.625, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::mul", "ph": "X", "ts": 375458.167, "dur": 18.625, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty_strided", "ph": "X", "ts": 375466.5, "dur": 1.875, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::sum", "ph": "X", "ts": 375486.875, "dur": 1209.75, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 375492.334, "dur": 1.25, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::as_strided", "ph": "X", "ts": 375496.167, "dur": 0.5829999999841675, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::fill_", "ph": "X", "ts": 375503.667, "dur": 4.291999999957625, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::diag", "ph": "X", "ts": 376727.0, "dur": 39.20899999997346, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 376738.0, "dur": 3.7920000000158325, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::diag", "ph": "X", "ts": 376743.917, "dur": 21.166999999957625, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::resize_", "ph": "X", "ts": 376748.709, "dur": 5.666000000026543, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::zero_", "ph": "X", "ts": 376756.417, "dur": 2.125, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::sub", "ph": "X", "ts": 376774.292, "dur": 20.791999999957625, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 376782.375, "dur": 1.7920000000158325, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::abs", "ph": "X", "ts": 376804.542, "dur": 17.457999999984168, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 376810.25, "dur": 0.5839999999734573, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::abs", "ph": "X", "ts": 376812.917, "dur": 7.791999999957625, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::resize_", "ph": "X", "ts": 376816.542, "dur": 0.875, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::div", "ph": "X", "ts": 376836.875, "dur": 28.042000000015832, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::to", "ph": "X", "ts": 376843.25, "dur": 13.75, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty_strided", "ph": "X", "ts": 376846.667, "dur": 1.625, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::copy_", "ph": "X", "ts": 376850.709, "dur": 5.916000000026543, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 376859.584, "dur": 1.0, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::add", "ph": "X", "ts": 376875.5, "dur": 11.375, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::div", "ph": "X", "ts": 376888.875, "dur": 6.0420000000158325, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 376891.917, "dur": 1.0419999999576248, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::div", "ph": "X", "ts": 376896.584, "dur": 8.25, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 376899.25, "dur": 3.7920000000158325, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::sum", "ph": "X", "ts": 376910.75, "dur": 27.75, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 376916.084, "dur": 1.0410000000265427, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::as_strided", "ph": "X", "ts": 376920.375, "dur": 2.25, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::fill_", "ph": "X", "ts": 376927.542, "dur": 3.875, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::repeat_interleave", "ph": "X", "ts": 376943.709, "dur": 167.58300000004238, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 376945.709, "dur": 1.2910000000265427, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::flatten", "ph": "X", "ts": 376949.834, "dur": 1.2080000000423752, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::reshape", "ph": "X", "ts": 376952.959, "dur": 11.916000000026543, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::view", "ph": "X", "ts": 376955.875, "dur": 8.333999999973457, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::expand", "ph": "X", "ts": 376966.875, "dur": 7.5, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::as_strided", "ph": "X", "ts": 376971.167, "dur": 0.9169999999576248, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::repeat_interleave", "ph": "X", "ts": 376976.959, "dur": 111.45800000004238, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::ge", "ph": "X", "ts": 376980.875, "dur": 14.708999999973457, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 376984.792, "dur": 0.5, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::ge", "ph": "X", "ts": 376987.542, "dur": 6.8329999999841675, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::resize_", "ph": "X", "ts": 376990.417, "dur": 1.1669999999576248, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::all", "ph": "X", "ts": 376997.084, "dur": 11.583000000042375, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 376998.917, "dur": 0.5, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::resize_", "ph": "X", "ts": 377001.125, "dur": 0.7920000000158325, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::as_strided", "ph": "X", "ts": 377003.417, "dur": 0.4579999999841675, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::fill_", "ph": "X", "ts": 377006.417, "dur": 0.5419999999576248, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::item", "ph": "X", "ts": 377010.459, "dur": 3.583000000042375, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::_local_scalar_dense", "ph": "X", "ts": 377012.417, "dur": 1.125, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::contiguous", "ph": "X", "ts": 377016.834, "dur": 11.041000000026543, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty_like", "ph": "X", "ts": 377018.959, "dur": 4.041000000026543, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 377020.917, "dur": 1.0419999999576248, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::copy_", "ph": "X", "ts": 377024.125, "dur": 3.375, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::cumsum", "ph": "X", "ts": 377029.584, "dur": 16.541000000026543, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::to", "ph": "X", "ts": 377033.959, "dur": 0.9580000000423752, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::_cumsum", "ph": "X", "ts": 377036.667, "dur": 9.0, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty_like", "ph": "X", "ts": 377038.125, "dur": 2.9589999999734573, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 377039.584, "dur": 0.9580000000423752, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::select", "ph": "X", "ts": 377047.459, "dur": 3.375, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::as_strided", "ph": "X", "ts": 377049.625, "dur": 0.5420000000158325, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::item", "ph": "X", "ts": 377051.625, "dur": 1.4589999999734573, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::_local_scalar_dense", "ph": "X", "ts": 377052.459, "dur": 0.2910000000265427, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 377054.584, "dur": 1.4580000000423752, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::index_select", "ph": "X", "ts": 377092.709, "dur": 16.041000000026543, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 377097.0, "dur": 0.5839999999734573, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::resize_", "ph": "X", "ts": 377100.167, "dur": 1.875, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::reshape", "ph": "X", "ts": 377117.75, "dur": 6.208999999973457, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::view", "ph": "X", "ts": 377119.542, "dur": 3.791999999957625, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::div", "ph": "X", "ts": 377126.375, "dur": 12.333999999973457, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty_strided", "ph": "X", "ts": 377130.5, "dur": 1.9170000000158325, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::repeat_interleave", "ph": "X", "ts": 377142.917, "dur": 105.16699999995762, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 377144.375, "dur": 1.0839999999734573, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::flatten", "ph": "X", "ts": 377146.834, "dur": 0.3330000000423752, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::reshape", "ph": "X", "ts": 377148.375, "dur": 5.625, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::view", "ph": "X", "ts": 377150.084, "dur": 3.4160000000265427, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::expand", "ph": "X", "ts": 377155.334, "dur": 5.25, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::as_strided", "ph": "X", "ts": 377158.292, "dur": 0.5829999999841675, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::repeat_interleave", "ph": "X", "ts": 377162.125, "dur": 70.54200000001583, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::ge", "ph": "X", "ts": 377164.209, "dur": 10.083000000042375, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 377166.667, "dur": 0.4579999999841675, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::ge", "ph": "X", "ts": 377168.625, "dur": 4.625, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::resize_", "ph": "X", "ts": 377170.792, "dur": 0.8329999999841675, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::all", "ph": "X", "ts": 377175.209, "dur": 9.583000000042375, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 377176.792, "dur": 0.4579999999841675, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::resize_", "ph": "X", "ts": 377178.709, "dur": 0.8330000000423752, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::as_strided", "ph": "X", "ts": 377181.042, "dur": 0.5, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::fill_", "ph": "X", "ts": 377183.542, "dur": 0.375, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::item", "ph": "X", "ts": 377185.667, "dur": 1.5419999999576248, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::_local_scalar_dense", "ph": "X", "ts": 377186.542, "dur": 0.25, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::contiguous", "ph": "X", "ts": 377189.292, "dur": 7.875, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty_like", "ph": "X", "ts": 377190.292, "dur": 3.166999999957625, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 377191.917, "dur": 0.9169999999576248, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::copy_", "ph": "X", "ts": 377194.5, "dur": 2.3339999999734573, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::cumsum", "ph": "X", "ts": 377198.125, "dur": 9.417000000015832, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::to", "ph": "X", "ts": 377199.709, "dur": 0.375, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::_cumsum", "ph": "X", "ts": 377201.209, "dur": 5.958000000042375, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty_like", "ph": "X", "ts": 377202.417, "dur": 2.7079999999841675, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 377203.709, "dur": 0.8330000000423752, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::select", "ph": "X", "ts": 377208.542, "dur": 2.666999999957625, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::as_strided", "ph": "X", "ts": 377210.0, "dur": 0.5420000000158325, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::item", "ph": "X", "ts": 377211.959, "dur": 1.4580000000423752, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::_local_scalar_dense", "ph": "X", "ts": 377212.834, "dur": 0.25, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 377214.834, "dur": 0.8330000000423752, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::index_select", "ph": "X", "ts": 377234.167, "dur": 12.0, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 377236.75, "dur": 0.5839999999734573, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::resize_", "ph": "X", "ts": 377239.334, "dur": 0.9580000000423752, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::reshape", "ph": "X", "ts": 377252.25, "dur": 6.0, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::view", "ph": "X", "ts": 377253.875, "dur": 3.75, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::mul", "ph": "X", "ts": 377262.75, "dur": 24.833999999973457, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::empty", "ph": "X", "ts": 377267.584, "dur": 1.0410000000265427, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::to", "ph": "X", "ts": 377294.75, "dur": 0.4170000000158325, "tid": 1, "pid": "CPU functions", "args": {}}, {"name": "aten::to", "ph": "X", "ts": 377304.084, "dur": 0.3330000000423752, "tid": 1, "pid": "CPU functions", "args": {}}]
\ No newline at end of file


Test patch:
diff --git a/sjSDM/tests/testthat/test-sLVM.R b/Code/sLVM/test-sLVM.R
similarity index 100%
rename from sjSDM/tests/testthat/test-sLVM.R
rename to Code/sLVM/test-sLVM.R
diff --git a/sjSDM/inst/python/tests/test_model_LVM.py b/Code/sLVM/test_model_LVM.py
similarity index 100%
rename from sjSDM/inst/python/tests/test_model_LVM.py
rename to Code/sLVM/test_model_LVM.py
diff --git a/sjSDM/tests/testthat/test-anova.R b/sjSDM/tests/testthat/test-1-anova.R
similarity index 95%
rename from sjSDM/tests/testthat/test-anova.R
rename to sjSDM/tests/testthat/test-1-anova.R
index b92ecfd..02a5df8 100644
--- a/sjSDM/tests/testthat/test-anova.R
+++ b/sjSDM/tests/testthat/test-1-anova.R
@@ -1,13 +1,10 @@
-context("sjSDM anova")
-
 source("utils.R")
 
 test_model = function(occ = NULL, env, spatial=NULL, biotic = bioticStruct(), 
                       iter = 1L, step_size = 10L, se=FALSE, family = stats::binomial(), context = "") {
     
     sjSDM:::check_module()
-    if(torch$cuda$is_available()) device = "gpu"
-    else device = "cpu"
+    device = is_gpu_available()
     testthat::expect_error({model = sjSDM(!!occ, env=!!env, 
                                           spatial = !!spatial, 
                                           biotic = !!biotic,
@@ -18,7 +15,7 @@ test_model = function(occ = NULL, env, spatial=NULL, biotic = bioticStruct(),
                                           device = device,
                                           sampling = 10L)}, NA)
     testthat::expect_false(any(is.na(model$history)))
-    testthat::expect_error({res = anova(model, cv = 2L)}, NA)
+    testthat::expect_error({res = anova(model)}, NA)
     testthat::expect_error({plot(res)}, NA)
 }
 
diff --git a/sjSDM/tests/testthat/test-sjSDM_cv.R b/sjSDM/tests/testthat/test-2-sjSDM_cv.R
similarity index 97%
rename from sjSDM/tests/testthat/test-sjSDM_cv.R
rename to sjSDM/tests/testthat/test-2-sjSDM_cv.R
index 33d04e5..2a675ed 100644
--- a/sjSDM/tests/testthat/test-sjSDM_cv.R
+++ b/sjSDM/tests/testthat/test-2-sjSDM_cv.R
@@ -1,5 +1,3 @@
-context("sjSDM_cv")
-
 source("utils.R")
 
 testthat::test_that("sjSDM_cv", {
@@ -14,8 +12,7 @@ testthat::test_that("sjSDM_cv", {
   Y1 = sim$response
   
   sjSDM:::check_module()
-  if(torch$cuda$is_available()) device = "gpu"
-  else device = "cpu"
+  device = is_gpu_available()
   
   testthat::expect_error(sjSDM_cv(Y1, X1, iter = 1L, CV = 2L, tune_steps = 3L, device=device, sampling=10L), NA)
   testthat::expect_error(sjSDM_cv(Y1, X1, iter = 1L, CV = 2L, tune_steps = 3L, lambda_coef = 0.0, device=device, sampling=10L), NA)
@@ -52,4 +49,4 @@ testthat::test_that("sjSDM_cv", {
   #testthat::expect_error(suppressWarnings(plot(model)), NA)
   testthat::expect_error(summary(model), NA)  
   
-})
\ No newline at end of file
+})
diff --git a/sjSDM/tests/testthat/test-python_core.R b/sjSDM/tests/testthat/test-3-python_core.R
similarity index 94%
rename from sjSDM/tests/testthat/test-python_core.R
rename to sjSDM/tests/testthat/test-3-python_core.R
index fcb4f60..1e03982 100644
--- a/sjSDM/tests/testthat/test-python_core.R
+++ b/sjSDM/tests/testthat/test-3-python_core.R
@@ -1,5 +1,3 @@
-context("python core")
-
 source("utils.R")
 
 testthat::test_that("sjSDM python core", {
diff --git a/sjSDM/tests/testthat/test-sjSDM.R b/sjSDM/tests/testthat/test-4-sjSDM.R
similarity index 97%
rename from sjSDM/tests/testthat/test-sjSDM.R
rename to sjSDM/tests/testthat/test-4-sjSDM.R
index ccc55a4..7c06c0d 100644
--- a/sjSDM/tests/testthat/test-sjSDM.R
+++ b/sjSDM/tests/testthat/test-4-sjSDM.R
@@ -1,5 +1,3 @@
-context("sjSDM")
-
 source("utils.R")
 
 test_model = function(occ = NULL, env, spatial=NULL, biotic = bioticStruct(), 
@@ -8,8 +6,7 @@ test_model = function(occ = NULL, env, spatial=NULL, biotic = bioticStruct(),
                       control = sjSDMControl(),
                       context = "") {
     sjSDM:::check_module()
-    if(torch$cuda$is_available()) device = "gpu"
-    else device = "cpu"
+    device = is_gpu_available()
     testthat::expect_error({model = sjSDM(!!occ, env=!!env, 
                                           spatial = !!spatial, 
                                           biotic = !!biotic,
@@ -213,8 +210,7 @@ testthat::test_that("sjSDM reload model", {
   testthat::skip_on_ci()
   skip_if_no_torch()
   sjSDM:::check_module()
-  if(torch$cuda$is_available()) device = "gpu"
-  else device = "cpu"
+  device = is_gpu_available()
   
   com = simulate_SDM(env = 3L, species = 5L, sites = 100L)
   model = sjSDM(Y = com$response,env = com$env_weights, iter = 2L, device=device)
@@ -253,8 +249,8 @@ testthat::test_that("sjSDM reload model", {
   testthat::expect_error(predict(model2), NA)
   testthat::expect_error(predict(model2, newdata = com$env_weights, SP = SP), NA)
   model2 = sjSDM:::checkModel(model2)
-  dims1 = lapply(model2$model$env_weights, dim)
-  dims2 = lapply(model$model$env_weights, dim)
+  dims1 = lapply(sjSDM:::force_r(model2$model$env_weights), dim)
+  dims2 = lapply(sjSDM:::force_r(model$model$env_weights ), dim)
   testthat::expect_equal(dims1, dims2, info = "dimensions of saved model does not match")
   file.remove("test_model.RDS")
 })
diff --git a/sjSDM/tests/testthat/test-importance.R b/sjSDM/tests/testthat/test-5-importance.R
similarity index 96%
rename from sjSDM/tests/testthat/test-importance.R
rename to sjSDM/tests/testthat/test-5-importance.R
index d4d26c8..20663bc 100644
--- a/sjSDM/tests/testthat/test-importance.R
+++ b/sjSDM/tests/testthat/test-5-importance.R
@@ -1,12 +1,9 @@
-context("sjSDM")
-
 source("utils.R")
 
 test_model = function(occ = NULL, env, spatial=NULL, biotic = bioticStruct(), 
                       iter = 1L, step_size = 10L, se=FALSE, family = stats::binomial(), context = "") {
     sjSDM:::check_module()
-    if(torch$cuda$is_available()) device = "gpu"
-    else device = "cpu"
+    device = is_gpu_available()
     testthat::expect_error({model = sjSDM(!!occ, env=!!env, 
                                           spatial = !!spatial, 
                                           biotic = !!biotic,
diff --git a/sjSDM/tests/testthat/test-examples.R b/sjSDM/tests/testthat/test-6-examples.R
similarity index 92%
rename from sjSDM/tests/testthat/test-examples.R
rename to sjSDM/tests/testthat/test-6-examples.R
index baebae8..dc1518b 100644
--- a/sjSDM/tests/testthat/test-examples.R
+++ b/sjSDM/tests/testthat/test-6-examples.R
@@ -1,5 +1,3 @@
-context("examples")
-
 source("utils.R")
 
 testthat::test_that("sjSDM examples", {
@@ -11,7 +9,7 @@ testthat::test_that("sjSDM examples", {
   path = system.file("examples", package = "sjSDM")
   to_do = list.files(path, full.names = TRUE)
   run_raw = function(rr) suppressWarnings(eval(str2expression(rr[c(-1, -length(rr))])))
-  for(i in 1:5) {
+  for(i in 1:length(to_do)) {
     raw = readLines(to_do[i])
     testthat::expect_error(run_raw(raw), NA, info = paste0(raw, collapse = "\n"))
   }
diff --git a/sjSDM/tests/testthat/test-plotsjSDM.R b/sjSDM/tests/testthat/test-7-plotsjSDM.R
similarity index 92%
rename from sjSDM/tests/testthat/test-plotsjSDM.R
rename to sjSDM/tests/testthat/test-7-plotsjSDM.R
index 1901551..19df74f 100644
--- a/sjSDM/tests/testthat/test-plotsjSDM.R
+++ b/sjSDM/tests/testthat/test-7-plotsjSDM.R
@@ -1,12 +1,9 @@
-context("plot sjSDM")
-
 source("utils.R")
 
 test_model = function(occ = NULL, env, spatial=NULL, biotic = bioticStruct(), 
                       iter = 1L, step_size = 10L, se=FALSE, family = stats::binomial(), context = "") {
   sjSDM:::check_module()
-  if(torch$cuda$is_available()) device = "gpu"
-  else device = "cpu"
+  device = is_gpu_available()
   testthat::expect_error({model = sjSDM(!!occ, env=!!env, 
                                         spatial = !!spatial, 
                                         biotic = !!biotic,
@@ -19,9 +16,6 @@ test_model = function(occ = NULL, env, spatial=NULL, biotic = bioticStruct(),
   testthat::expect_error(plot(model), NA)
 }
 
-# 
-# testthat::test_that("sjSDM functionality", {
-#   skip_if_no_torch()
 
 library(sjSDM)
 
@@ -30,8 +24,6 @@ X1 = sim$env_weights
 Y1 = sim$response
 
 
-# iter, batch_size, se, link
-# iter, batch_size, se, link
 Funcs = list(
   list(5, 2, FALSE, binomial("logit")),
   list(5, 23, FALSE, poisson()),
diff --git a/sjSDM/tests/testthat/utils.R b/sjSDM/tests/testthat/utils.R
index d3a80da..f2ef494 100644
--- a/sjSDM/tests/testthat/utils.R
+++ b/sjSDM/tests/testthat/utils.R
@@ -1,4 +1,14 @@
-skip_if_no_torch = function(required_version = NULL) {
-  if (!is_torch_available())
-    skip("required torch version not available for testing")
-}
+skip_if_no_torch = function(required_version = NULL) {
+  if (!is_torch_available())
+    skip("required torch version not available for testing")
+}
+
+force_r = function(x) {
+  if(inherits(x, "python.builtin.object")) return(reticulate::py_to_r( x ))
+  else return(x)
+}
+
+is_gpu_available = function() {
+  if( force_r(torch$cuda$is_available()) ) return("gpu")
+  else return("cpu")
+}
\ No newline at end of file