diff --git a/assets/report/renv.lock b/assets/report/renv.lock index a84cbbbb..02b44237 100644 --- a/assets/report/renv.lock +++ b/assets/report/renv.lock @@ -190,6 +190,13 @@ ], "Hash": "f20c47fd52fae58b4e377c37bb8c335b" }, + "commonmark": { + "Package": "commonmark", + "Version": "1.9.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "5d8225445acb167abf7797de48b2ee3c" + }, "cpp11": { "Package": "cpp11", "Version": "0.4.7", @@ -854,6 +861,50 @@ ], "Hash": "c19df082ba346b0ffa6f833e92de34d1" }, + "shiny": { + "Package": "shiny", + "Version": "1.8.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "R6", + "bslib", + "cachem", + "commonmark", + "crayon", + "ellipsis", + "fastmap", + "fontawesome", + "glue", + "grDevices", + "htmltools", + "httpuv", + "jsonlite", + "later", + "lifecycle", + "methods", + "mime", + "promises", + "rlang", + "sourcetools", + "tools", + "utils", + "withr", + "xtable" + ], + "Hash": "3a1f41807d648a908e3c7f0334bf85e6" + }, + "sourcetools": { + "Package": "sourcetools", + "Version": "0.1.7-1", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "5f5a7629f956619d519205ec475fe647" + }, "stringi": { "Package": "stringi", "Version": "1.8.3", @@ -1047,6 +1098,18 @@ ], "Hash": "fd1349170df31f7a10bd98b0189e85af" }, + "xtable": { + "Package": "xtable", + "Version": "1.8-4", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "stats", + "utils" + ], + "Hash": "b8acdf8af494d9ec19ccb2481a9b11c2" + }, "yaml": { "Package": "yaml", "Version": "2.3.8", diff --git a/conf/base.config b/conf/base.config index 954ff49f..ae2ce810 100644 --- a/conf/base.config +++ b/conf/base.config @@ -1,6 +1,6 @@ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - pgscatalog/pgsccalc Nextflow base config file + pgscatalog/pgsc_calc Nextflow base config file ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A 'blank slate' config file, appropriate for general use on most high performance compute environments. Assumes that all software is installed and available on @@ -9,8 +9,6 @@ */ process { - // defaults for unlabelled processes - // however all processes are labelled cpus = { check_max( 1 * task.attempt, 'cpus' ) } memory = { check_max( 6.GB * task.attempt, 'memory' ) } time = { check_max( 4.h * task.attempt, 'time' ) } @@ -19,15 +17,19 @@ process { maxRetries = 1 maxErrors = '-1' - // reasonable resource limits for medium sized datasets + withLabel:process_single { + cpus = { check_max( 1 , 'cpus' ) } + memory = { check_max( 4.GB * task.attempt, 'memory' ) } + time = { check_max( 2.h * task.attempt, 'time' ) } + } withLabel:process_low { cpus = { check_max( 2 * task.attempt, 'cpus' ) } memory = { check_max( 8.GB * task.attempt, 'memory' ) } - time = { check_max( 8.h * task.attempt, 'time' ) } + time = { check_max( 4.h * task.attempt, 'time' ) } } withLabel:process_medium { cpus = { check_max( 4 * task.attempt, 'cpus' ) } - memory = { check_max( 16.GB * task.attempt, 'memory' ) } + memory = { check_max( 16.GB * task.attempt, 'memory' ) } time = { check_max( 8.h * task.attempt, 'time' ) } } withLabel:process_high { @@ -51,7 +53,4 @@ process { withName:DUMPSOFTWAREVERSIONS { cache = false } - withLabel:plink2{ - memory = { check_max( 16.GB * task.attempt, 'memory' ) } - } } diff --git a/conf/modules.config b/conf/modules.config index d3f4bea4..7ee2a45a 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -63,7 +63,7 @@ process { ext.singularity = 'oras://dockerhub.ebi.ac.uk/gdp-public/pgsc_calc/singularity/report' ext.singularity_version = ':2.0' ext.docker = 'dockerhub.ebi.ac.uk/gdp-public/pgsc_calc/report' - ext.docker_version = ':2.0' + ext.docker_version = ':dev' } withLabel: pyyaml { diff --git a/conf/sequential.config b/conf/sequential.config deleted file mode 100644 index 0679d36c..00000000 --- a/conf/sequential.config +++ /dev/null @@ -1,16 +0,0 @@ -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Config file for sequential score calculation - - - This is the default to prevent laptops from exploding (bad UX) - - Scoring genomes in parallel is I/O intensive and eats RAM - - Set the parameter --parallel to disable this behaviour -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ - -process { - withName: PLINK2_SCORE { - ext.args2 = "" - maxForks = 1 - } -} diff --git a/docs/how-to/bigjob.rst b/docs/how-to/bigjob.rst index 978bc419..faf6e016 100644 --- a/docs/how-to/bigjob.rst +++ b/docs/how-to/bigjob.rst @@ -57,12 +57,8 @@ pgsc_calc: -profile \ --input samplesheet.csv \ --pgs_id PGS001229 \ - --parallel \ -c my_custom.config -.. note:: Using the ``parallel`` parameter enables parallel score calculation, - which is a RAM and I/O intensive process. It's disabled by default to - prevent laptops with 16GB RAM crashing on smaller datasets. High performance computing cluster ---------------------------------- @@ -125,7 +121,6 @@ instead: -profile singularity \ --input samplesheet.csv \ --pgs_id PGS001229 \ - --parallel \ -c my_custom.config .. note:: The name of the nextflow and singularity modules will be different in diff --git a/environments/report/Dockerfile b/environments/report/Dockerfile index 8d841a6d..d3523fc3 100644 --- a/environments/report/Dockerfile +++ b/environments/report/Dockerfile @@ -1,13 +1,11 @@ -ARG QUARTO_VERSION=1.3.433 - FROM continuumio/miniconda3 AS build -ARG QUARTO_VERSION +ARG QUARTO_VERSION=1.4.550 ARG TARGETARCH -RUN wget https://github.com/quarto-dev/quarto-cli/releases/download/v${QUARTO_VERSION}/quarto-${QUARTO_VERSION}-linux-${TARGETARCH}.deb && \ - dpkg -i quarto-${QUARTO_VERSION}-linux-${TARGETARCH}.deb && \ - rm quarto-${QUARTO_VERSION}-linux-${TARGETARCH}.deb +RUN apt-get update \ + && apt-get install -y procps zlib1g-dev \ + && rm -rf /var/lib/apt/lists/* RUN conda install -c conda-forge r-renv @@ -19,7 +17,6 @@ RUN R -e "renv::restore(clean=TRUE, prompt=FALSE)" # RUN conda env export > environment.yml -RUN apt-get update \ - && apt-get install -y procps \ - && rm -rf /var/lib/apt/lists/* - +RUN wget https://github.com/quarto-dev/quarto-cli/releases/download/v${QUARTO_VERSION}/quarto-${QUARTO_VERSION}-linux-${TARGETARCH}.deb && \ + dpkg -i quarto-${QUARTO_VERSION}-linux-${TARGETARCH}.deb && \ + rm quarto-${QUARTO_VERSION}-linux-${TARGETARCH}.deb diff --git a/environments/report/environment.yml b/environments/report/environment.yml index 2701d175..381836f1 100644 --- a/environments/report/environment.yml +++ b/environments/report/environment.yml @@ -1,17 +1,146 @@ +# generated from docker image name: report channels: - conda-forge - defaults dependencies: - - r-dplyr - - r-dt - - r-tidyr - - r-ggplot2 - - r-forcats - - r-readr - - r-purrr - - r-jsonlite - - r-data.table - - quarto=1.3.433 - - r-rmarkdown - - r-r.utils + - _libgcc_mutex=0.1=main + - _openmp_mutex=5.1=51_gnu + - _r-mutex=1.0.1=anacondar_1 + - _sysroot_linux-aarch64_curr_repodata_hack=4=h57d6b7b_14 + - archspec=0.2.1=pyhd3eb1b0_0 + - binutils_impl_linux-aarch64=2.38=h0c9fd12_1 + - boltons=23.0.0=py311hd43f75c_0 + - brotli-python=1.0.9=py311h419075a_7 + - bwidget=1.9.14=h8af1aa0_1 + - bzip2=1.0.8=hfd63f10_2 + - c-ares=1.19.1=h998d150_0 + - ca-certificates=2024.2.2=hcefe29a_0 + - cairo=1.18.0=ha13f110_0 + - certifi=2024.2.2=pyhd8ed1ab_0 + - cffi=1.15.1=py311h998d150_3 + - charset-normalizer=2.0.4=pyhd3eb1b0_0 + - conda=24.1.1=py311hec3470c_0 + - conda-content-trust=0.2.0=py311hd43f75c_0 + - conda-libmamba-solver=23.11.1=py311hd43f75c_0 + - conda-package-handling=2.2.0=py311hd43f75c_0 + - conda-package-streaming=0.9.0=py311hd43f75c_0 + - cryptography=41.0.3=py311h5077475_0 + - curl=8.4.0=h6ac735f_0 + - distro=1.9.0=pyhd8ed1ab_0 + - expat=2.5.0=hd600fc2_1 + - fmt=9.1.0=hb8fdbf2_0 + - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 + - font-ttf-inconsolata=3.000=h77eed37_0 + - font-ttf-source-code-pro=2.038=h77eed37_0 + - font-ttf-ubuntu=0.83=h77eed37_1 + - fontconfig=2.14.2=ha9a116f_0 + - fonts-conda-ecosystem=1=0 + - fonts-conda-forge=1=0 + - freetype=2.12.1=hf0a5ef3_2 + - fribidi=1.0.10=hb9de7d4_0 + - gcc_impl_linux-aarch64=12.1.0=h9c21524_17 + - gettext=0.21.1=ha18d298_0 + - gfortran_impl_linux-aarch64=12.1.0=hd36f8f4_17 + - graphite2=1.3.13=h7fd3ca4_1001 + - gxx_impl_linux-aarch64=12.1.0=h9c21524_17 + - harfbuzz=8.3.0=hebeb849_0 + - icu=73.2=h787c7f5_0 + - idna=3.4=py311hd43f75c_0 + - jsonpatch=1.32=pyhd3eb1b0_0 + - jsonpointer=2.1=pyhd3eb1b0_0 + - kernel-headers_linux-aarch64=4.18.0=h5b4a56d_14 + - krb5=1.20.1=h2e2fba8_1 + - ld_impl_linux-aarch64=2.38=h8131f2d_1 + - lerc=4.0.0=h4de3ea5_0 + - libarchive=3.6.2=h654c02d_2 + - libblas=3.9.0=21_linuxaarch64_openblas + - libcurl=8.4.0=hfa2bbb0_0 + - libdeflate=1.19=h31becfc_0 + - libedit=3.1.20221030=h998d150_0 + - libev=4.33=hfd63f10_1 + - libexpat=2.5.0=hd600fc2_1 + - libffi=3.4.4=h419075a_0 + - libgcc-devel_linux-aarch64=12.1.0=hf2ffb8d_17 + - libgcc-ng=13.2.0=hf8544c7_5 + - libgfortran-ng=13.2.0=he9431aa_5 + - libgfortran5=13.2.0=h582850c_5 + - libglib=2.78.4=h311d5f7_0 + - libgomp=13.2.0=hf8544c7_5 + - libiconv=1.17=h31becfc_2 + - libjpeg-turbo=3.0.0=h31becfc_1 + - liblapack=3.9.0=21_linuxaarch64_openblas + - libmamba=1.5.3=h78dbd8a_0 + - libmambapy=1.5.3=py311hd82f176_0 + - libnghttp2=1.57.0=hb788212_0 + - libnsl=2.0.1=h31becfc_0 + - libopenblas=0.3.26=pthreads_h5a5ec62_0 + - libpng=1.6.42=h194ca79_0 + - libsanitizer=12.1.0=hd01590b_17 + - libsolv=0.7.24=h94b7715_0 + - libsqlite=3.45.1=h194ca79_0 + - libssh2=1.10.0=h6ac735f_2 + - libstdcxx-devel_linux-aarch64=12.1.0=hf2ffb8d_17 + - libstdcxx-ng=13.2.0=h9a76618_5 + - libtiff=4.6.0=h1708d11_2 + - libuuid=2.38.1=hb4cce97_0 + - libwebp-base=1.3.2=h31becfc_0 + - libxcb=1.15=h2a766a3_0 + - libxcrypt=4.4.36=h31becfc_1 + - libxml2=2.10.4=h045d036_1 + - libzlib=1.2.13=h31becfc_5 + - lz4-c=1.9.4=h419075a_0 + - make=4.3=h309ac5b_1 + - menuinst=2.0.2=py311hec3470c_0 + - ncurses=6.4=h419075a_0 + - openssl=3.2.1=h31becfc_0 + - packaging=23.1=py311hd43f75c_0 + - pango=1.50.14=h11ef544_2 + - pcre2=10.42=hcfaa891_0 + - pip=23.3=py311hd43f75c_0 + - pixman=0.43.2=h2f0025b_0 + - platformdirs=4.2.0=pyhd8ed1ab_0 + - pluggy=1.0.0=py311hd43f75c_1 + - pthread-stubs=0.4=hb9de7d4_1001 + - pybind11-abi=4=hd3eb1b0_1 + - pycosat=0.6.6=py311h998d150_0 + - pycparser=2.21=pyhd3eb1b0_0 + - pyopenssl=23.2.0=py311hd43f75c_0 + - pysocks=1.7.1=py311hd43f75c_0 + - python=3.11.8=h43d1f9e_0_cpython + - python_abi=3.11=4_cp311 + - r-base=4.3.2=h7dc8e12_1 + - r-renv=1.0.4=r43hc72bb7e_0 + - readline=8.2=h998d150_0 + - reproc=14.2.4=h22f4aa5_1 + - reproc-cpp=14.2.4=h22f4aa5_1 + - requests=2.31.0=py311hd43f75c_0 + - ruamel.yaml=0.17.21=py311h998d150_0 + - sed=4.8=ha0d5d3d_0 + - setuptools=68.0.0=py311hd43f75c_0 + - sqlite=3.41.2=h998d150_0 + - sysroot_linux-aarch64=2.17=h5b4a56d_14 + - tk=8.6.13=h194ca79_0 + - tktable=2.10=h4f9ca69_5 + - tqdm=4.65.0=py311h2163289_0 + - truststore=0.8.0=py311hd43f75c_0 + - tzdata=2023c=h04d1e81_0 + - urllib3=1.26.18=py311hd43f75c_0 + - wheel=0.41.2=py311hd43f75c_0 + - xorg-kbproto=1.0.7=h3557bc0_1002 + - xorg-libice=1.1.1=h7935292_0 + - xorg-libsm=1.2.4=h5a01bc2_0 + - xorg-libx11=1.8.7=h055a233_0 + - xorg-libxau=1.0.11=h31becfc_0 + - xorg-libxdmcp=1.1.3=h3557bc0_0 + - xorg-libxext=1.3.4=h2a766a3_2 + - xorg-libxrender=0.9.11=h7935292_0 + - xorg-libxt=1.3.0=h7935292_1 + - xorg-renderproto=0.11.1=h3557bc0_1002 + - xorg-xextproto=7.3.0=h2a766a3_1003 + - xorg-xproto=7.0.31=h3557bc0_1007 + - xz=5.4.2=h998d150_0 + - yaml-cpp=0.8.0=h419075a_0 + - zlib=1.2.13=h31becfc_5 + - zstandard=0.19.0=py311h998d150_0 + - zstd=1.5.5=h6a09583_0 \ No newline at end of file diff --git a/environments/report/renv.lock b/environments/report/renv.lock new file mode 100644 index 00000000..02b44237 --- /dev/null +++ b/environments/report/renv.lock @@ -0,0 +1,1121 @@ +{ + "R": { + "Version": "4.3.2", + "Repositories": [ + { + "Name": "CRAN", + "URL": "https://cloud.r-project.org" + } + ] + }, + "Packages": { + "DT": { + "Package": "DT", + "Version": "0.32", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "crosstalk", + "htmltools", + "htmlwidgets", + "httpuv", + "jquerylib", + "jsonlite", + "magrittr", + "promises" + ], + "Hash": "0d3ab8abbb0c3e3daa47d4dc8e17bbae" + }, + "MASS": { + "Package": "MASS", + "Version": "7.3-60", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "grDevices", + "graphics", + "methods", + "stats", + "utils" + ], + "Hash": "a56a6365b3fa73293ea8d084be0d9bb0" + }, + "Matrix": { + "Package": "Matrix", + "Version": "1.6-1.1", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "grDevices", + "graphics", + "grid", + "lattice", + "methods", + "stats", + "utils" + ], + "Hash": "1a00d4828f33a9d690806e98bd17150c" + }, + "R6": { + "Package": "R6", + "Version": "2.5.1", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "470851b6d5d0ac559e9d01bb352b4021" + }, + "RColorBrewer": { + "Package": "RColorBrewer", + "Version": "1.1-3", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "45f0398006e83a5b10b72a90663d8d8c" + }, + "Rcpp": { + "Package": "Rcpp", + "Version": "1.0.12", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "methods", + "utils" + ], + "Hash": "5ea2700d21e038ace58269ecdbeb9ec0" + }, + "base64enc": { + "Package": "base64enc", + "Version": "0.1-3", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "543776ae6848fde2f48ff3816d0628bc" + }, + "bit": { + "Package": "bit", + "Version": "4.0.5", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "d242abec29412ce988848d0294b208fd" + }, + "bit64": { + "Package": "bit64", + "Version": "4.0.5", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "bit", + "methods", + "stats", + "utils" + ], + "Hash": "9fe98599ca456d6552421db0d6772d8f" + }, + "bslib": { + "Package": "bslib", + "Version": "0.6.1", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "base64enc", + "cachem", + "grDevices", + "htmltools", + "jquerylib", + "jsonlite", + "lifecycle", + "memoise", + "mime", + "rlang", + "sass" + ], + "Hash": "c0d8599494bc7fb408cd206bbdd9cab0" + }, + "cachem": { + "Package": "cachem", + "Version": "1.0.8", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "fastmap", + "rlang" + ], + "Hash": "c35768291560ce302c0a6589f92e837d" + }, + "cli": { + "Package": "cli", + "Version": "3.6.2", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "utils" + ], + "Hash": "1216ac65ac55ec0058a6f75d7ca0fd52" + }, + "clipr": { + "Package": "clipr", + "Version": "0.8.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "utils" + ], + "Hash": "3f038e5ac7f41d4ac41ce658c85e3042" + }, + "colorspace": { + "Package": "colorspace", + "Version": "2.1-0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "grDevices", + "graphics", + "methods", + "stats" + ], + "Hash": "f20c47fd52fae58b4e377c37bb8c335b" + }, + "commonmark": { + "Package": "commonmark", + "Version": "1.9.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "5d8225445acb167abf7797de48b2ee3c" + }, + "cpp11": { + "Package": "cpp11", + "Version": "0.4.7", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "5a295d7d963cc5035284dcdbaf334f4e" + }, + "crayon": { + "Package": "crayon", + "Version": "1.5.2", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "grDevices", + "methods", + "utils" + ], + "Hash": "e8a1e41acf02548751f45c718d55aa6a" + }, + "crosstalk": { + "Package": "crosstalk", + "Version": "1.2.1", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R6", + "htmltools", + "jsonlite", + "lazyeval" + ], + "Hash": "ab12c7b080a57475248a30f4db6298c0" + }, + "digest": { + "Package": "digest", + "Version": "0.6.34", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "utils" + ], + "Hash": "7ede2ee9ea8d3edbf1ca84c1e333ad1a" + }, + "dplyr": { + "Package": "dplyr", + "Version": "1.1.4", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "R6", + "cli", + "generics", + "glue", + "lifecycle", + "magrittr", + "methods", + "pillar", + "rlang", + "tibble", + "tidyselect", + "utils", + "vctrs" + ], + "Hash": "fedd9d00c2944ff00a0e2696ccf048ec" + }, + "ellipsis": { + "Package": "ellipsis", + "Version": "0.3.2", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "rlang" + ], + "Hash": "bb0eec2fe32e88d9e2836c2f73ea2077" + }, + "evaluate": { + "Package": "evaluate", + "Version": "0.23", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "methods" + ], + "Hash": "daf4a1246be12c1fa8c7705a0935c1a0" + }, + "fansi": { + "Package": "fansi", + "Version": "1.0.6", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "grDevices", + "utils" + ], + "Hash": "962174cf2aeb5b9eea581522286a911f" + }, + "farver": { + "Package": "farver", + "Version": "2.1.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "8106d78941f34855c440ddb946b8f7a5" + }, + "fastmap": { + "Package": "fastmap", + "Version": "1.1.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "f7736a18de97dea803bde0a2daaafb27" + }, + "fontawesome": { + "Package": "fontawesome", + "Version": "0.5.2", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "htmltools", + "rlang" + ], + "Hash": "c2efdd5f0bcd1ea861c2d4e2a883a67d" + }, + "forcats": { + "Package": "forcats", + "Version": "1.0.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "cli", + "glue", + "lifecycle", + "magrittr", + "rlang", + "tibble" + ], + "Hash": "1a0a9a3d5083d0d573c4214576f1e690" + }, + "fs": { + "Package": "fs", + "Version": "1.6.3", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "methods" + ], + "Hash": "47b5f30c720c23999b913a1a635cf0bb" + }, + "generics": { + "Package": "generics", + "Version": "0.1.3", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "methods" + ], + "Hash": "15e9634c0fcd294799e9b2e929ed1b86" + }, + "ggplot2": { + "Package": "ggplot2", + "Version": "3.4.4", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "MASS", + "R", + "cli", + "glue", + "grDevices", + "grid", + "gtable", + "isoband", + "lifecycle", + "mgcv", + "rlang", + "scales", + "stats", + "tibble", + "vctrs", + "withr" + ], + "Hash": "313d31eff2274ecf4c1d3581db7241f9" + }, + "glue": { + "Package": "glue", + "Version": "1.7.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "methods" + ], + "Hash": "e0b3a53876554bd45879e596cdb10a52" + }, + "gtable": { + "Package": "gtable", + "Version": "0.3.4", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "cli", + "glue", + "grid", + "lifecycle", + "rlang" + ], + "Hash": "b29cf3031f49b04ab9c852c912547eef" + }, + "highr": { + "Package": "highr", + "Version": "0.10", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "xfun" + ], + "Hash": "06230136b2d2b9ba5805e1963fa6e890" + }, + "hms": { + "Package": "hms", + "Version": "1.1.3", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "lifecycle", + "methods", + "pkgconfig", + "rlang", + "vctrs" + ], + "Hash": "b59377caa7ed00fa41808342002138f9" + }, + "htmltools": { + "Package": "htmltools", + "Version": "0.5.7", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "base64enc", + "digest", + "ellipsis", + "fastmap", + "grDevices", + "rlang", + "utils" + ], + "Hash": "2d7b3857980e0e0d0a1fd6f11928ab0f" + }, + "htmlwidgets": { + "Package": "htmlwidgets", + "Version": "1.6.4", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "grDevices", + "htmltools", + "jsonlite", + "knitr", + "rmarkdown", + "yaml" + ], + "Hash": "04291cc45198225444a397606810ac37" + }, + "httpuv": { + "Package": "httpuv", + "Version": "1.6.14", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "R6", + "Rcpp", + "later", + "promises", + "utils" + ], + "Hash": "16abeb167dbf511f8cc0552efaf05bab" + }, + "isoband": { + "Package": "isoband", + "Version": "0.2.7", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "grid", + "utils" + ], + "Hash": "0080607b4a1a7b28979aecef976d8bc2" + }, + "jquerylib": { + "Package": "jquerylib", + "Version": "0.1.4", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "htmltools" + ], + "Hash": "5aab57a3bd297eee1c1d862735972182" + }, + "jsonlite": { + "Package": "jsonlite", + "Version": "1.8.8", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "methods" + ], + "Hash": "e1b9c55281c5adc4dd113652d9e26768" + }, + "knitr": { + "Package": "knitr", + "Version": "1.45", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "evaluate", + "highr", + "methods", + "tools", + "xfun", + "yaml" + ], + "Hash": "1ec462871063897135c1bcbe0fc8f07d" + }, + "labeling": { + "Package": "labeling", + "Version": "0.4.3", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "graphics", + "stats" + ], + "Hash": "b64ec208ac5bc1852b285f665d6368b3" + }, + "later": { + "Package": "later", + "Version": "1.3.2", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "Rcpp", + "rlang" + ], + "Hash": "a3e051d405326b8b0012377434c62b37" + }, + "lattice": { + "Package": "lattice", + "Version": "0.21-9", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "grDevices", + "graphics", + "grid", + "stats", + "utils" + ], + "Hash": "5558c61e0136e247252f5f952cdaad6a" + }, + "lazyeval": { + "Package": "lazyeval", + "Version": "0.2.2", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "d908914ae53b04d4c0c0fd72ecc35370" + }, + "lifecycle": { + "Package": "lifecycle", + "Version": "1.0.4", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "cli", + "glue", + "rlang" + ], + "Hash": "b8552d117e1b808b09a832f589b79035" + }, + "magrittr": { + "Package": "magrittr", + "Version": "2.0.3", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "7ce2733a9826b3aeb1775d56fd305472" + }, + "memoise": { + "Package": "memoise", + "Version": "2.0.1", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "cachem", + "rlang" + ], + "Hash": "e2817ccf4a065c5d9d7f2cfbe7c1d78c" + }, + "mgcv": { + "Package": "mgcv", + "Version": "1.9-0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "Matrix", + "R", + "graphics", + "methods", + "nlme", + "splines", + "stats", + "utils" + ], + "Hash": "086028ca0460d0c368028d3bda58f31b" + }, + "mime": { + "Package": "mime", + "Version": "0.12", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "tools" + ], + "Hash": "18e9c28c1d3ca1560ce30658b22ce104" + }, + "munsell": { + "Package": "munsell", + "Version": "0.5.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "colorspace", + "methods" + ], + "Hash": "6dfe8bf774944bd5595785e3229d8771" + }, + "nlme": { + "Package": "nlme", + "Version": "3.1-163", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "graphics", + "lattice", + "stats", + "utils" + ], + "Hash": "8d1938040a05566f4f7a14af4feadd6b" + }, + "pillar": { + "Package": "pillar", + "Version": "1.9.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "cli", + "fansi", + "glue", + "lifecycle", + "rlang", + "utf8", + "utils", + "vctrs" + ], + "Hash": "15da5a8412f317beeee6175fbc76f4bb" + }, + "pkgconfig": { + "Package": "pkgconfig", + "Version": "2.0.3", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "utils" + ], + "Hash": "01f28d4278f15c76cddbea05899c5d6f" + }, + "prettyunits": { + "Package": "prettyunits", + "Version": "1.2.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "6b01fc98b1e86c4f705ce9dcfd2f57c7" + }, + "progress": { + "Package": "progress", + "Version": "1.2.3", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "R6", + "crayon", + "hms", + "prettyunits" + ], + "Hash": "f4625e061cb2865f111b47ff163a5ca6" + }, + "promises": { + "Package": "promises", + "Version": "1.2.1", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R6", + "Rcpp", + "fastmap", + "later", + "magrittr", + "rlang", + "stats" + ], + "Hash": "0d8a15c9d000970ada1ab21405387dee" + }, + "purrr": { + "Package": "purrr", + "Version": "1.0.2", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "cli", + "lifecycle", + "magrittr", + "rlang", + "vctrs" + ], + "Hash": "1cba04a4e9414bdefc9dcaa99649a8dc" + }, + "rappdirs": { + "Package": "rappdirs", + "Version": "0.3.3", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "5e3c5dc0b071b21fa128676560dbe94d" + }, + "readr": { + "Package": "readr", + "Version": "2.1.5", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "R6", + "cli", + "clipr", + "cpp11", + "crayon", + "hms", + "lifecycle", + "methods", + "rlang", + "tibble", + "tzdb", + "utils", + "vroom" + ], + "Hash": "9de96463d2117f6ac49980577939dfb3" + }, + "renv": { + "Package": "renv", + "Version": "1.0.3", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "utils" + ], + "Hash": "41b847654f567341725473431dd0d5ab" + }, + "rlang": { + "Package": "rlang", + "Version": "1.1.3", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "utils" + ], + "Hash": "42548638fae05fd9a9b5f3f437fbbbe2" + }, + "rmarkdown": { + "Package": "rmarkdown", + "Version": "2.25", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "bslib", + "evaluate", + "fontawesome", + "htmltools", + "jquerylib", + "jsonlite", + "knitr", + "methods", + "stringr", + "tinytex", + "tools", + "utils", + "xfun", + "yaml" + ], + "Hash": "d65e35823c817f09f4de424fcdfa812a" + }, + "sass": { + "Package": "sass", + "Version": "0.4.8", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R6", + "fs", + "htmltools", + "rappdirs", + "rlang" + ], + "Hash": "168f9353c76d4c4b0a0bbf72e2c2d035" + }, + "scales": { + "Package": "scales", + "Version": "1.3.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "R6", + "RColorBrewer", + "cli", + "farver", + "glue", + "labeling", + "lifecycle", + "munsell", + "rlang", + "viridisLite" + ], + "Hash": "c19df082ba346b0ffa6f833e92de34d1" + }, + "shiny": { + "Package": "shiny", + "Version": "1.8.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "R6", + "bslib", + "cachem", + "commonmark", + "crayon", + "ellipsis", + "fastmap", + "fontawesome", + "glue", + "grDevices", + "htmltools", + "httpuv", + "jsonlite", + "later", + "lifecycle", + "methods", + "mime", + "promises", + "rlang", + "sourcetools", + "tools", + "utils", + "withr", + "xtable" + ], + "Hash": "3a1f41807d648a908e3c7f0334bf85e6" + }, + "sourcetools": { + "Package": "sourcetools", + "Version": "0.1.7-1", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "5f5a7629f956619d519205ec475fe647" + }, + "stringi": { + "Package": "stringi", + "Version": "1.8.3", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "stats", + "tools", + "utils" + ], + "Hash": "058aebddea264f4c99401515182e656a" + }, + "stringr": { + "Package": "stringr", + "Version": "1.5.1", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "cli", + "glue", + "lifecycle", + "magrittr", + "rlang", + "stringi", + "vctrs" + ], + "Hash": "960e2ae9e09656611e0b8214ad543207" + }, + "tibble": { + "Package": "tibble", + "Version": "3.2.1", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "fansi", + "lifecycle", + "magrittr", + "methods", + "pillar", + "pkgconfig", + "rlang", + "utils", + "vctrs" + ], + "Hash": "a84e2cc86d07289b3b6f5069df7a004c" + }, + "tidyr": { + "Package": "tidyr", + "Version": "1.3.1", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "cli", + "cpp11", + "dplyr", + "glue", + "lifecycle", + "magrittr", + "purrr", + "rlang", + "stringr", + "tibble", + "tidyselect", + "utils", + "vctrs" + ], + "Hash": "915fb7ce036c22a6a33b5a8adb712eb1" + }, + "tidyselect": { + "Package": "tidyselect", + "Version": "1.2.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "cli", + "glue", + "lifecycle", + "rlang", + "vctrs", + "withr" + ], + "Hash": "79540e5fcd9e0435af547d885f184fd5" + }, + "tinytex": { + "Package": "tinytex", + "Version": "0.49", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "xfun" + ], + "Hash": "5ac22900ae0f386e54f1c307eca7d843" + }, + "tzdb": { + "Package": "tzdb", + "Version": "0.4.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "cpp11" + ], + "Hash": "f561504ec2897f4d46f0c7657e488ae1" + }, + "utf8": { + "Package": "utf8", + "Version": "1.2.4", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "62b65c52671e6665f803ff02954446e9" + }, + "vctrs": { + "Package": "vctrs", + "Version": "0.6.5", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "cli", + "glue", + "lifecycle", + "rlang" + ], + "Hash": "c03fa420630029418f7e6da3667aac4a" + }, + "viridisLite": { + "Package": "viridisLite", + "Version": "0.4.2", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "c826c7c4241b6fc89ff55aaea3fa7491" + }, + "vroom": { + "Package": "vroom", + "Version": "1.6.5", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "bit64", + "cli", + "cpp11", + "crayon", + "glue", + "hms", + "lifecycle", + "methods", + "progress", + "rlang", + "stats", + "tibble", + "tidyselect", + "tzdb", + "vctrs", + "withr" + ], + "Hash": "390f9315bc0025be03012054103d227c" + }, + "withr": { + "Package": "withr", + "Version": "3.0.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "grDevices", + "graphics" + ], + "Hash": "d31b6c62c10dcf11ec530ca6b0dd5d35" + }, + "xfun": { + "Package": "xfun", + "Version": "0.42", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "grDevices", + "stats", + "tools" + ], + "Hash": "fd1349170df31f7a10bd98b0189e85af" + }, + "xtable": { + "Package": "xtable", + "Version": "1.8-4", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "stats", + "utils" + ], + "Hash": "b8acdf8af494d9ec19ccb2481a9b11c2" + }, + "yaml": { + "Package": "yaml", + "Version": "2.3.8", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "29240487a071f535f5e5d5a323b7afbd" + } + } +} diff --git a/lib/NfcoreSchema.groovy b/lib/NfcoreSchema.groovy deleted file mode 100755 index b3d092f8..00000000 --- a/lib/NfcoreSchema.groovy +++ /dev/null @@ -1,529 +0,0 @@ -// -// This file holds several functions used to perform JSON parameter validation, help and summary rendering for the nf-core pipeline template. -// - -import org.everit.json.schema.Schema -import org.everit.json.schema.loader.SchemaLoader -import org.everit.json.schema.ValidationException -import org.json.JSONObject -import org.json.JSONTokener -import org.json.JSONArray -import groovy.json.JsonSlurper -import groovy.json.JsonBuilder - -class NfcoreSchema { - - // - // Resolve Schema path relative to main workflow directory - // - public static String getSchemaPath(workflow, schema_filename='nextflow_schema.json') { - return "${workflow.projectDir}/${schema_filename}" - } - - // - // Function to loop over all parameters defined in schema and check - // whether the given parameters adhere to the specifications - // - /* groovylint-disable-next-line UnusedPrivateMethodParameter */ - public static void validateParameters(workflow, params, log, schema_filename='nextflow_schema.json') { - def has_error = false - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Check for nextflow core params and unexpected params - def json = new File(getSchemaPath(workflow, schema_filename=schema_filename)).text - def Map schemaParams = (Map) new JsonSlurper().parseText(json).get('definitions') - def nf_params = [ - // Options for base `nextflow` command - 'bg', - 'c', - 'C', - 'config', - 'd', - 'D', - 'dockerize', - 'h', - 'log', - 'q', - 'quiet', - 'syslog', - 'v', - 'version', - - // Options for `nextflow run` command - 'ansi', - 'ansi-log', - 'bg', - 'bucket-dir', - 'c', - 'cache', - 'config', - 'dsl2', - 'dump-channels', - 'dump-hashes', - 'E', - 'entry', - 'latest', - 'lib', - 'main-script', - 'N', - 'name', - 'offline', - 'params-file', - 'pi', - 'plugins', - 'poll-interval', - 'pool-size', - 'profile', - 'ps', - 'qs', - 'queue-size', - 'r', - 'resume', - 'revision', - 'stdin', - 'stub', - 'stub-run', - 'test', - 'w', - 'with-charliecloud', - 'with-conda', - 'with-dag', - 'with-docker', - 'with-mpi', - 'with-notification', - 'with-podman', - 'with-report', - 'with-singularity', - 'with-timeline', - 'with-tower', - 'with-trace', - 'with-weblog', - 'without-docker', - 'without-podman', - 'work-dir' - ] - def unexpectedParams = [] - - // Collect expected parameters from the schema - def expectedParams = [] - def enums = [:] - for (group in schemaParams) { - for (p in group.value['properties']) { - expectedParams.push(p.key) - if (group.value['properties'][p.key].containsKey('enum')) { - enums[p.key] = group.value['properties'][p.key]['enum'] - } - } - } - - for (specifiedParam in params.keySet()) { - // nextflow params - if (nf_params.contains(specifiedParam)) { - log.error "ERROR: You used a core Nextflow option with two hyphens: '--${specifiedParam}'. Please resubmit with '-${specifiedParam}'" - has_error = true - } - // unexpected params - def params_ignore = params.schema_ignore_params.split(',') + 'schema_ignore_params' - def expectedParamsLowerCase = expectedParams.collect{ it.replace("-", "").toLowerCase() } - def specifiedParamLowerCase = specifiedParam.replace("-", "").toLowerCase() - def isCamelCaseBug = (specifiedParam.contains("-") && !expectedParams.contains(specifiedParam) && expectedParamsLowerCase.contains(specifiedParamLowerCase)) - if (!expectedParams.contains(specifiedParam) && !params_ignore.contains(specifiedParam) && !isCamelCaseBug) { - // Temporarily remove camelCase/camel-case params #1035 - def unexpectedParamsLowerCase = unexpectedParams.collect{ it.replace("-", "").toLowerCase()} - if (!unexpectedParamsLowerCase.contains(specifiedParamLowerCase)){ - unexpectedParams.push(specifiedParam) - } - } - } - - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Validate parameters against the schema - InputStream input_stream = new File(getSchemaPath(workflow, schema_filename=schema_filename)).newInputStream() - JSONObject raw_schema = new JSONObject(new JSONTokener(input_stream)) - - // Remove anything that's in params.schema_ignore_params - raw_schema = removeIgnoredParams(raw_schema, params) - - Schema schema = SchemaLoader.load(raw_schema) - - // Clean the parameters - def cleanedParams = cleanParameters(params) - - // Convert to JSONObject - def jsonParams = new JsonBuilder(cleanedParams) - JSONObject params_json = new JSONObject(jsonParams.toString()) - - // Validate - try { - schema.validate(params_json) - } catch (ValidationException e) { - println '' - log.error 'ERROR: Validation of pipeline parameters failed!' - JSONObject exceptionJSON = e.toJSON() - printExceptions(exceptionJSON, params_json, log, enums) - println '' - has_error = true - } - - // Check for unexpected parameters - if (unexpectedParams.size() > 0) { - Map colors = NfcoreTemplate.logColours(params.monochrome_logs) - println '' - def warn_msg = 'Found unexpected parameters:' - for (unexpectedParam in unexpectedParams) { - warn_msg = warn_msg + "\n* --${unexpectedParam}: ${params[unexpectedParam].toString()}" - } - log.warn warn_msg - log.info "- ${colors.dim}Ignore this warning: params.schema_ignore_params = \"${unexpectedParams.join(',')}\" ${colors.reset}" - println '' - } - - if (has_error) { - System.exit(1) - } - } - - // - // Beautify parameters for --help - // - public static String paramsHelp(workflow, params, command, schema_filename='nextflow_schema.json') { - Map colors = NfcoreTemplate.logColours(params.monochrome_logs) - Integer num_hidden = 0 - String output = '' - output += 'Typical pipeline command:\n\n' - output += " ${colors.cyan}${command}${colors.reset}\n\n" - Map params_map = paramsLoad(getSchemaPath(workflow, schema_filename=schema_filename)) - Integer max_chars = paramsMaxChars(params_map) + 1 - Integer desc_indent = max_chars + 14 - Integer dec_linewidth = 160 - desc_indent - for (group in params_map.keySet()) { - Integer num_params = 0 - String group_output = colors.underlined + colors.bold + group + colors.reset + '\n' - def group_params = params_map.get(group) // This gets the parameters of that particular group - for (param in group_params.keySet()) { - if (group_params.get(param).hidden && !params.show_hidden_params) { - num_hidden += 1 - continue; - } - def type = '[' + group_params.get(param).type + ']' - def description = group_params.get(param).description - def defaultValue = group_params.get(param).default != null ? " [default: " + group_params.get(param).default.toString() + "]" : '' - def description_default = description + colors.dim + defaultValue + colors.reset - // Wrap long description texts - // Loosely based on https://dzone.com/articles/groovy-plain-text-word-wrap - if (description_default.length() > dec_linewidth){ - List olines = [] - String oline = "" // " " * indent - description_default.split(" ").each() { wrd -> - if ((oline.size() + wrd.size()) <= dec_linewidth) { - oline += wrd + " " - } else { - olines += oline - oline = wrd + " " - } - } - olines += oline - description_default = olines.join("\n" + " " * desc_indent) - } - group_output += " --" + param.padRight(max_chars) + colors.dim + type.padRight(10) + colors.reset + description_default + '\n' - num_params += 1 - } - group_output += '\n' - if (num_params > 0){ - output += group_output - } - } - if (num_hidden > 0){ - output += colors.dim + "!! Hiding $num_hidden params, use --show_hidden_params to show them !!\n" + colors.reset - } - output += NfcoreTemplate.dashedLine(params.monochrome_logs) - return output - } - - // - // Groovy Map summarising parameters/workflow options used by the pipeline - // - public static LinkedHashMap paramsSummaryMap(workflow, params, schema_filename='nextflow_schema.json') { - // Get a selection of core Nextflow workflow options - def Map workflow_summary = [:] - if (workflow.revision) { - workflow_summary['revision'] = workflow.revision - } - workflow_summary['runName'] = workflow.runName - if (workflow.containerEngine) { - workflow_summary['containerEngine'] = workflow.containerEngine - } - if (workflow.container) { - workflow_summary['container'] = workflow.container - } - workflow_summary['launchDir'] = workflow.launchDir - workflow_summary['workDir'] = workflow.workDir - workflow_summary['projectDir'] = workflow.projectDir - workflow_summary['userName'] = workflow.userName - workflow_summary['profile'] = workflow.profile - workflow_summary['configFiles'] = workflow.configFiles.join(', ') - - // Get pipeline parameters defined in JSON Schema - def Map params_summary = [:] - def params_map = paramsLoad(getSchemaPath(workflow, schema_filename=schema_filename)) - for (group in params_map.keySet()) { - def sub_params = new LinkedHashMap() - def group_params = params_map.get(group) // This gets the parameters of that particular group - for (param in group_params.keySet()) { - if (params.containsKey(param)) { - def params_value = params.get(param) - def schema_value = group_params.get(param).default - def param_type = group_params.get(param).type - if (schema_value != null) { - if (param_type == 'string') { - if (schema_value.contains('$projectDir') || schema_value.contains('${projectDir}')) { - def sub_string = schema_value.replace('\$projectDir', '') - sub_string = sub_string.replace('\${projectDir}', '') - if (params_value.contains(sub_string)) { - schema_value = params_value - } - } - if (schema_value.contains('$params.outdir') || schema_value.contains('${params.outdir}')) { - def sub_string = schema_value.replace('\$params.outdir', '') - sub_string = sub_string.replace('\${params.outdir}', '') - if ("${params.outdir}${sub_string}" == params_value) { - schema_value = params_value - } - } - } - } - - // We have a default in the schema, and this isn't it - if (schema_value != null && params_value != schema_value) { - sub_params.put(param, params_value) - } - // No default in the schema, and this isn't empty - else if (schema_value == null && params_value != "" && params_value != null && params_value != false) { - sub_params.put(param, params_value) - } - } - } - params_summary.put(group, sub_params) - } - return [ 'Core Nextflow options' : workflow_summary ] << params_summary - } - - // - // Beautify parameters for summary and return as string - // - public static String paramsSummaryLog(workflow, params) { - Map colors = NfcoreTemplate.logColours(params.monochrome_logs) - String output = '' - def params_map = paramsSummaryMap(workflow, params) - def max_chars = paramsMaxChars(params_map) - for (group in params_map.keySet()) { - def group_params = params_map.get(group) // This gets the parameters of that particular group - if (group_params) { - output += colors.bold + group + colors.reset + '\n' - for (param in group_params.keySet()) { - output += " " + colors.blue + param.padRight(max_chars) + ": " + colors.green + group_params.get(param) + colors.reset + '\n' - } - output += '\n' - } - } - output += "!! Only displaying parameters that differ from the pipeline defaults !!\n" - output += NfcoreTemplate.dashedLine(params.monochrome_logs) - return output - } - - // - // Loop over nested exceptions and print the causingException - // - private static void printExceptions(ex_json, params_json, log, enums, limit=5) { - def causingExceptions = ex_json['causingExceptions'] - if (causingExceptions.length() == 0) { - def m = ex_json['message'] =~ /required key \[([^\]]+)\] not found/ - // Missing required param - if (m.matches()) { - log.error "* Missing required parameter: --${m[0][1]}" - } - // Other base-level error - else if (ex_json['pointerToViolation'] == '#') { - log.error "* ${ex_json['message']}" - } - // Error with specific param - else { - def param = ex_json['pointerToViolation'] - ~/^#\// - def param_val = params_json[param].toString() - if (enums.containsKey(param)) { - def error_msg = "* --${param}: '${param_val}' is not a valid choice (Available choices" - if (enums[param].size() > limit) { - log.error "${error_msg} (${limit} of ${enums[param].size()}): ${enums[param][0..limit-1].join(', ')}, ... )" - } else { - log.error "${error_msg}: ${enums[param].join(', ')})" - } - } else { - log.error "* --${param}: ${ex_json['message']} (${param_val})" - } - } - } - for (ex in causingExceptions) { - printExceptions(ex, params_json, log, enums) - } - } - - // - // Remove an element from a JSONArray - // - private static JSONArray removeElement(json_array, element) { - def list = [] - int len = json_array.length() - for (int i=0;i - if(raw_schema.keySet().contains('definitions')){ - raw_schema.definitions.each { definition -> - for (key in definition.keySet()){ - if (definition[key].get("properties").keySet().contains(ignore_param)){ - // Remove the param to ignore - definition[key].get("properties").remove(ignore_param) - // If the param was required, change this - if (definition[key].has("required")) { - def cleaned_required = removeElement(definition[key].required, ignore_param) - definition[key].put("required", cleaned_required) - } - } - } - } - } - if(raw_schema.keySet().contains('properties') && raw_schema.get('properties').keySet().contains(ignore_param)) { - raw_schema.get("properties").remove(ignore_param) - } - if(raw_schema.keySet().contains('required') && raw_schema.required.contains(ignore_param)) { - def cleaned_required = removeElement(raw_schema.required, ignore_param) - raw_schema.put("required", cleaned_required) - } - } - return raw_schema - } - - // - // Clean and check parameters relative to Nextflow native classes - // - private static Map cleanParameters(params) { - def new_params = params.getClass().newInstance(params) - for (p in params) { - // remove anything evaluating to false - if (!p['value']) { - new_params.remove(p.key) - } - // Cast MemoryUnit to String - if (p['value'].getClass() == nextflow.util.MemoryUnit) { - new_params.replace(p.key, p['value'].toString()) - } - // Cast Duration to String - if (p['value'].getClass() == nextflow.util.Duration) { - new_params.replace(p.key, p['value'].toString().replaceFirst(/d(?!\S)/, "day")) - } - // Cast LinkedHashMap to String - if (p['value'].getClass() == LinkedHashMap) { - new_params.replace(p.key, p['value'].toString()) - } - } - return new_params - } - - // - // This function tries to read a JSON params file - // - private static LinkedHashMap paramsLoad(String json_schema) { - def params_map = new LinkedHashMap() - try { - params_map = paramsRead(json_schema) - } catch (Exception e) { - println "Could not read parameters settings from JSON. $e" - params_map = new LinkedHashMap() - } - return params_map - } - - // - // Method to actually read in JSON file using Groovy. - // Group (as Key), values are all parameters - // - Parameter1 as Key, Description as Value - // - Parameter2 as Key, Description as Value - // .... - // Group - // - - private static LinkedHashMap paramsRead(String json_schema) throws Exception { - def json = new File(json_schema).text - def Map schema_definitions = (Map) new JsonSlurper().parseText(json).get('definitions') - def Map schema_properties = (Map) new JsonSlurper().parseText(json).get('properties') - /* Tree looks like this in nf-core schema - * definitions <- this is what the first get('definitions') gets us - group 1 - title - description - properties - parameter 1 - type - description - parameter 2 - type - description - group 2 - title - description - properties - parameter 1 - type - description - * properties <- parameters can also be ungrouped, outside of definitions - parameter 1 - type - description - */ - - // Grouped params - def params_map = new LinkedHashMap() - schema_definitions.each { key, val -> - def Map group = schema_definitions."$key".properties // Gets the property object of the group - def title = schema_definitions."$key".title - def sub_params = new LinkedHashMap() - group.each { innerkey, value -> - sub_params.put(innerkey, value) - } - params_map.put(title, sub_params) - } - - // Ungrouped params - def ungrouped_params = new LinkedHashMap() - schema_properties.each { innerkey, value -> - ungrouped_params.put(innerkey, value) - } - params_map.put("Other parameters", ungrouped_params) - - return params_map - } - - // - // Get maximum number of characters across all parameter names - // - private static Integer paramsMaxChars(params_map) { - Integer max_chars = 0 - for (group in params_map.keySet()) { - def group_params = params_map.get(group) // This gets the parameters of that particular group - for (param in group_params.keySet()) { - if (param.size() > max_chars) { - max_chars = param.size() - } - } - } - return max_chars - } -} diff --git a/lib/NfcoreTemplate.groovy b/lib/NfcoreTemplate.groovy index 8f857360..4ce590c0 100755 --- a/lib/NfcoreTemplate.groovy +++ b/lib/NfcoreTemplate.groovy @@ -3,6 +3,8 @@ // import org.yaml.snakeyaml.Yaml +import groovy.json.JsonOutput +import nextflow.extension.FilesEx class NfcoreTemplate { @@ -32,6 +34,25 @@ class NfcoreTemplate { } } + // + // Generate version string + // + public static String version(workflow) { + String version_string = "" + + if (workflow.manifest.version) { + def prefix_v = workflow.manifest.version[0] != 'v' ? 'v' : '' + version_string += "${prefix_v}${workflow.manifest.version}" + } + + if (workflow.commitId) { + def git_shortsha = workflow.commitId.substring(0, 7) + version_string += "-g${git_shortsha}" + } + + return version_string + } + // // Construct and send completion email // @@ -61,7 +82,7 @@ class NfcoreTemplate { misc_fields['Nextflow Compile Timestamp'] = workflow.nextflow.timestamp def email_fields = [:] - email_fields['version'] = workflow.manifest.version + email_fields['version'] = NfcoreTemplate.version(workflow) email_fields['runName'] = workflow.runName email_fields['success'] = workflow.success email_fields['dateComplete'] = workflow.complete @@ -109,7 +130,7 @@ class NfcoreTemplate { def email_html = html_template.toString() // Render the sendmail template - def max_multiqc_email_size = params.max_multiqc_email_size as nextflow.util.MemoryUnit + def max_multiqc_email_size = (params.containsKey('max_multiqc_email_size') ? params.max_multiqc_email_size : 0) as nextflow.util.MemoryUnit def smail_fields = [ email: email_address, subject: subject, email_txt: email_txt, email_html: email_html, projectDir: "$projectDir", mqcFile: mqc_report, mqcMaxSize: max_multiqc_email_size.toBytes() ] def sf = new File("$projectDir/assets/sendmail_template.txt") def sendmail_template = engine.createTemplate(sf).make(smail_fields) @@ -121,12 +142,14 @@ class NfcoreTemplate { try { if (params.plaintext_email) { throw GroovyException('Send plaintext e-mail, not HTML') } // Try to send HTML e-mail using sendmail + def sendmail_tf = new File(workflow.launchDir.toString(), ".sendmail_tmp.html") + sendmail_tf.withWriter { w -> w << sendmail_html } [ 'sendmail', '-t' ].execute() << sendmail_html log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Sent summary e-mail to $email_address (sendmail)-" } catch (all) { // Catch failures and try with plaintext def mail_cmd = [ 'mail', '-s', subject, '--content-type=text/html', email_address ] - if ( mqc_report.size() <= max_multiqc_email_size.toBytes() ) { + if ( mqc_report != null && mqc_report.size() <= max_multiqc_email_size.toBytes() ) { mail_cmd += [ '-A', mqc_report ] } mail_cmd.execute() << email_html @@ -135,14 +158,88 @@ class NfcoreTemplate { } // Write summary e-mail HTML to a file - def output_d = new File("${params.outdir}/pipeline_info/") - if (!output_d.exists()) { - output_d.mkdirs() - } - def output_hf = new File(output_d, "pipeline_report.html") + def output_hf = new File(workflow.launchDir.toString(), ".pipeline_report.html") output_hf.withWriter { w -> w << email_html } - def output_tf = new File(output_d, "pipeline_report.txt") + FilesEx.copyTo(output_hf.toPath(), "${params.outdir}/pipeline_info/pipeline_report.html"); + output_hf.delete() + + // Write summary e-mail TXT to a file + def output_tf = new File(workflow.launchDir.toString(), ".pipeline_report.txt") output_tf.withWriter { w -> w << email_txt } + FilesEx.copyTo(output_tf.toPath(), "${params.outdir}/pipeline_info/pipeline_report.txt"); + output_tf.delete() + } + + // + // Construct and send a notification to a web server as JSON + // e.g. Microsoft Teams and Slack + // + public static void IM_notification(workflow, params, summary_params, projectDir, log) { + def hook_url = params.hook_url + + def summary = [:] + for (group in summary_params.keySet()) { + summary << summary_params[group] + } + + def misc_fields = [:] + misc_fields['start'] = workflow.start + misc_fields['complete'] = workflow.complete + misc_fields['scriptfile'] = workflow.scriptFile + misc_fields['scriptid'] = workflow.scriptId + if (workflow.repository) misc_fields['repository'] = workflow.repository + if (workflow.commitId) misc_fields['commitid'] = workflow.commitId + if (workflow.revision) misc_fields['revision'] = workflow.revision + misc_fields['nxf_version'] = workflow.nextflow.version + misc_fields['nxf_build'] = workflow.nextflow.build + misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp + + def msg_fields = [:] + msg_fields['version'] = NfcoreTemplate.version(workflow) + msg_fields['runName'] = workflow.runName + msg_fields['success'] = workflow.success + msg_fields['dateComplete'] = workflow.complete + msg_fields['duration'] = workflow.duration + msg_fields['exitStatus'] = workflow.exitStatus + msg_fields['errorMessage'] = (workflow.errorMessage ?: 'None') + msg_fields['errorReport'] = (workflow.errorReport ?: 'None') + msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "") + msg_fields['projectDir'] = workflow.projectDir + msg_fields['summary'] = summary << misc_fields + + // Render the JSON template + def engine = new groovy.text.GStringTemplateEngine() + // Different JSON depending on the service provider + // Defaults to "Adaptive Cards" (https://adaptivecards.io), except Slack which has its own format + def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json" + def hf = new File("$projectDir/assets/${json_path}") + def json_template = engine.createTemplate(hf).make(msg_fields) + def json_message = json_template.toString() + + // POST + def post = new URL(hook_url).openConnection(); + post.setRequestMethod("POST") + post.setDoOutput(true) + post.setRequestProperty("Content-Type", "application/json") + post.getOutputStream().write(json_message.getBytes("UTF-8")); + def postRC = post.getResponseCode(); + if (! postRC.equals(200)) { + log.warn(post.getErrorStream().getText()); + } + } + + // + // Dump pipeline parameters in a json file + // + public static void dump_parameters(workflow, params) { + def timestamp = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss') + def filename = "params_${timestamp}.json" + def temp_pf = new File(workflow.launchDir.toString(), ".${filename}") + def jsonStr = JsonOutput.toJson(params) + temp_pf.text = JsonOutput.prettyPrint(jsonStr) + + FilesEx.copyTo(temp_pf.toPath(), "${params.outdir}/pipeline_info/params_${timestamp}.json") + temp_pf.delete() } // @@ -154,7 +251,7 @@ class NfcoreTemplate { if (workflow.stats.ignoredCount == 0) { log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Pipeline completed successfully${colors.reset}-" } else { - log.info "-${colors.purple}[$workflow.manifest.name]${colors.red} Pipeline completed successfully, but with errored process(es) ${colors.reset}-" + log.info "-${colors.purple}[$workflow.manifest.name]${colors.yellow} Pipeline completed successfully, but with errored process(es) ${colors.reset}-" } } else { log.info "-${colors.purple}[$workflow.manifest.name]${colors.red} Pipeline completed with errors${colors.reset}-" @@ -242,10 +339,11 @@ class NfcoreTemplate { // public static String logo(workflow, monochrome_logs) { Map colors = logColours(monochrome_logs) + String workflow_version = NfcoreTemplate.version(workflow) String.format( """\n ${dashedLine(monochrome_logs)} - ${colors.purple} ${workflow.manifest.name} v${workflow.manifest.version}${colors.reset} + ${colors.purple} ${workflow.manifest.name} ${workflow_version}${colors.reset} ${dashedLine(monochrome_logs)} """.stripIndent() ) diff --git a/lib/Utils.groovy b/lib/Utils.groovy old mode 100755 new mode 100644 diff --git a/lib/WorkflowMain.groovy b/lib/WorkflowMain.groovy index 9e197906..238741a6 100755 --- a/lib/WorkflowMain.groovy +++ b/lib/WorkflowMain.groovy @@ -1,7 +1,9 @@ // -// This file holds several functions specific to the main.nf workflow in the pgscatalog/pgsc_calc pipeline +// This file holds several functions specific to the main.nf workflow in the pgscatalog/pgsccalc pipeline // +import nextflow.Nextflow + class WorkflowMain { // @@ -17,51 +19,23 @@ class WorkflowMain { " https://github.com/${workflow.manifest.name}/blob/master/CITATIONS.md" } - // - // Print help to screen if required - // - public static String help(workflow, params, log) { - def command = "nextflow run ${workflow.manifest.name} --input assets/samplesheet.csv --scorefile assets/PGS001229_22.txt -profile docker" - def help_string = '' - help_string += NfcoreTemplate.logo(workflow, params.monochrome_logs) - help_string += NfcoreSchema.paramsHelp(workflow, params, command) - help_string += '\n' + citation(workflow) + '\n' - help_string += NfcoreTemplate.dashedLine(params.monochrome_logs) - return help_string - } - - // - // Print parameter summary log to screen - // - public static String paramsSummaryLog(workflow, params, log) { - def summary_log = '' - summary_log += NfcoreTemplate.logo(workflow, params.monochrome_logs) - summary_log += NfcoreSchema.paramsSummaryLog(workflow, params) - summary_log += '\n' + citation(workflow) + '\n' - summary_log += NfcoreTemplate.dashedLine(params.monochrome_logs) - return summary_log - } // // Validate parameters and print summary to screen // - public static void initialise(workflow, params, log) { - // Print help to screen if required - if (params.help) { - log.info help(workflow, params, log) - System.exit(0) - } + public static void initialise(workflow, params, log, args) { - // Validate workflow parameters via the JSON schema - if (params.validate_params) { - NfcoreSchema.validateParameters(workflow, params, log) + // Print workflow version and exit on --version + if (params.version) { + String workflow_version = NfcoreTemplate.version(workflow) + log.info "${workflow.manifest.name} ${workflow_version}" + System.exit(0) } - // Print parameter summary log to screen - log.info paramsSummaryLog(workflow, params, log) - // Check that a -profile or Nextflow config has been provided to run the pipeline NfcoreTemplate.checkConfigProvided(workflow, log) + // Check that the profile doesn't contain spaces and doesn't end with a trailing comma + checkProfile(workflow.profile, args, log) // Check that conda channels are set-up correctly if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { @@ -72,9 +46,8 @@ class WorkflowMain { NfcoreTemplate.awsBatch(workflow, params) // Check input has been provided - if (!params.input && !params.json) { - log.error "Please provide an input samplesheet to the pipeline e.g. '--input samplesheet.csv'" - System.exit(1) + if (!params.input) { + Nextflow.error("Please provide an input samplesheet to the pipeline e.g. '--input samplesheet.csv'") } } // @@ -88,4 +61,16 @@ class WorkflowMain { } return null } + + // + // Exit pipeline if --profile contains spaces + // + private static void checkProfile(profile, args, log) { + if (profile.endsWith(',')) { + Nextflow.error "Profile cannot end with a trailing comma. Please remove the comma from the end of the profile string.\nHint: A common mistake is to provide multiple values to `-profile` separated by spaces. Please use commas to separate profiles instead,e.g., `-profile docker,test`." + } + if (args[0]) { + log.warn "nf-core pipelines do not accept positional arguments. The positional argument `${args[0]}` has been detected.\n Hint: A common mistake is to provide multiple values to `-profile` separated by spaces. Please use commas to separate profiles instead,e.g., `-profile docker,test`." + } + } } diff --git a/lib/WorkflowPgscCalc.groovy b/lib/WorkflowPgscCalc.groovy new file mode 100755 index 00000000..60c4e9fe --- /dev/null +++ b/lib/WorkflowPgscCalc.groovy @@ -0,0 +1,149 @@ +// +// This file holds several functions specific to the workflow/pgsccalc.nf in the pgscatalog/pgsccalc pipeline +// + +import nextflow.Nextflow +import groovy.text.SimpleTemplateEngine + +class WorkflowPgscCalc { + + // + // Check and validate parameters + // + public static void initialise(params, log) { + if (![params.scorefile, params.pgs_id, params.trait_efo, params.pgp_id].any()) { + Nextflow.error " ERROR: You didn't set any scores to use! Please set --scorefile, --pgs_id, --trait_efo, or --pgp_id" + } + + if (!params.target_build) { + Nextflow.error "ERROR: You didn't set the target build of your target genomes. Please set --target_build GRCh37 or --target_build GRCh38" + } + + if (params.liftover && !params.hg19_chain || params.liftover && !params.hg38_chain) { + Nextflow.error "ERROR: Missing --hg19_chain or --hg38_chain with --liftover. Please download UCSC chain files and set chain file paths" + } + } + + public static LinkedHashMap prepareAccessions(String accession, String key) { + // do a simple check that accessions look reasonable + // PGS000000 / PGP000000 / EFO_000... + if (!accession) { + return [(key): ""] + } + + def unique_accession = accession.replaceAll('\\s','').tokenize(',').unique() + def good_accessions = [] + unique_accession.each { it -> + if (!(it ==~ "(?:PGP|PGS)[0-9]{6}|(?:[A-Za-z]+)_[0-9]+")) { + System.err.println "WARNING: ${it} doesn't seem like a valid PGS Catalog accession, ignoring" + } else { + good_accessions.add(it) + } + } + if (good_accessions) { + return [(key): good_accessions.join(" ")] + } else { + return [(key): ""] + } + } + + // + // Get workflow summary for MultiQC + // + public static String paramsSummaryMultiqc(workflow, summary) { + String summary_section = '' + for (group in summary.keySet()) { + def group_params = summary.get(group) // This gets the parameters of that particular group + if (group_params) { + summary_section += "

$group

\n" + summary_section += "
\n" + for (param in group_params.keySet()) { + summary_section += "
$param
${group_params.get(param) ?: 'N/A'}
\n" + } + summary_section += "
\n" + } + } + + String yaml_file_text = "id: '${workflow.manifest.name.replace('/','-')}-summary'\n" + yaml_file_text += "description: ' - this information is collected when the pipeline is started.'\n" + yaml_file_text += "section_name: '${workflow.manifest.name} Workflow Summary'\n" + yaml_file_text += "section_href: 'https://github.com/${workflow.manifest.name}'\n" + yaml_file_text += "plot_type: 'html'\n" + yaml_file_text += "data: |\n" + yaml_file_text += "${summary_section}" + return yaml_file_text + } + + // + // Generate methods description for MultiQC + // + + public static String toolCitationText(params) { + + // TODO nf-core: Optionally add in-text citation tools to this list. + // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "Tool (Foo et al. 2023)" : "", + // Uncomment function in methodsDescriptionText to render in MultiQC report + def citation_text = [ + "Tools used in the workflow included:", + "FastQC (Andrews 2010),", + "MultiQC (Ewels et al. 2016)", + "." + ].join(' ').trim() + + return citation_text + } + + public static String toolBibliographyText(params) { + + // TODO Optionally add bibliographic entries to this list. + // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "
  • Author (2023) Pub name, Journal, DOI
  • " : "", + // Uncomment function in methodsDescriptionText to render in MultiQC report + def reference_text = [ + "
  • Andrews S, (2010) FastQC, URL: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/).
  • ", + "
  • Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
  • " + ].join(' ').trim() + + return reference_text + } + + public static String methodsDescriptionText(run_workflow, mqc_methods_yaml, params) { + // Convert to a named map so can be used as with familar NXF ${workflow} variable syntax in the MultiQC YML file + def meta = [:] + meta.workflow = run_workflow.toMap() + meta["manifest_map"] = run_workflow.manifest.toMap() + + // Pipeline DOI + meta["doi_text"] = meta.manifest_map.doi ? "(doi: ${meta.manifest_map.doi})" : "" + meta["nodoi_text"] = meta.manifest_map.doi ? "": "
  • If available, make sure to update the text to include the Zenodo DOI of version of the pipeline used.
  • " + + // Tool references + meta["tool_citations"] = "" + meta["tool_bibliography"] = "" + + // TODO Only uncomment below if logic in toolCitationText/toolBibliographyText has been filled! + //meta["tool_citations"] = toolCitationText(params).replaceAll(", \\.", ".").replaceAll("\\. \\.", ".").replaceAll(", \\.", ".") + //meta["tool_bibliography"] = toolBibliographyText(params) + + + def methods_text = mqc_methods_yaml.text + + def engine = new SimpleTemplateEngine() + def description_html = engine.createTemplate(methods_text).make(meta) + + return description_html + } + + // + // Exit pipeline if incorrect --genome key provided + // + private static void genomeExistsError(params, log) { + if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { + def error_string = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + + " Genome '${params.genome}' not found in any config files provided to the pipeline.\n" + + " Currently, the available genome keys are:\n" + + " ${params.genomes.keySet().join(", ")}\n" + + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + Nextflow.error(error_string) + } + } +} diff --git a/lib/WorkflowPgscalc.groovy b/lib/WorkflowPgscalc.groovy deleted file mode 100755 index e0359254..00000000 --- a/lib/WorkflowPgscalc.groovy +++ /dev/null @@ -1,15 +0,0 @@ -// -// This file holds several functions specific to the workflow/pgscalc.nf in the nf-core/pgscalc pipeline -// - -class WorkflowPgscalc { - // - // Check and validate parameters - // - public static void initialise(params, log) { - if (!params.input && !params.json) { - log.error "Sample sheet input file not specified with e.g. '--input input.csv' or via a detectable config file." - System.exit(1) - } - } -} diff --git a/lib/WorkflowTest.groovy b/lib/WorkflowTest.groovy deleted file mode 100755 index b56b2b2a..00000000 --- a/lib/WorkflowTest.groovy +++ /dev/null @@ -1,59 +0,0 @@ -// -// This file holds several functions specific to the workflow/test.nf in the nf-core/test pipeline -// - -class WorkflowTest { - - // - // Check and validate parameters - // - public static void initialise(params, log) { - genomeExistsError(params, log) - - if (!params.fasta) { - log.error "Genome fasta file not specified with e.g. '--fasta genome.fa' or via a detectable config file." - System.exit(1) - } - } - - // - // Get workflow summary for MultiQC - // - public static String paramsSummaryMultiqc(workflow, summary) { - String summary_section = '' - for (group in summary.keySet()) { - def group_params = summary.get(group) // This gets the parameters of that particular group - if (group_params) { - summary_section += "

    $group

    \n" - summary_section += "
    \n" - for (param in group_params.keySet()) { - summary_section += "
    $param
    ${group_params.get(param) ?: 'N/A'}
    \n" - } - summary_section += "
    \n" - } - } - - String yaml_file_text = "id: '${workflow.manifest.name.replace('/','-')}-summary'\n" - yaml_file_text += "description: ' - this information is collected when the pipeline is started.'\n" - yaml_file_text += "section_name: '${workflow.manifest.name} Workflow Summary'\n" - yaml_file_text += "section_href: 'https://github.com/${workflow.manifest.name}'\n" - yaml_file_text += "plot_type: 'html'\n" - yaml_file_text += "data: |\n" - yaml_file_text += "${summary_section}" - return yaml_file_text - } - - // - // Exit pipeline if incorrect --genome key provided - // - private static void genomeExistsError(params, log) { - if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { - log.error "=============================================================================\n" + - " Genome '${params.genome}' not found in any config files provided to the pipeline.\n" + - " Currently, the available genome keys are:\n" + - " ${params.genomes.keySet().join(", ")}\n" + - "===================================================================================" - System.exit(1) - } - } -} diff --git a/lib/nfcore_external_java_deps.jar b/lib/nfcore_external_java_deps.jar deleted file mode 100644 index 805c8bb5..00000000 Binary files a/lib/nfcore_external_java_deps.jar and /dev/null differ diff --git a/main.nf b/main.nf index 7b544164..efea0127 100644 --- a/main.nf +++ b/main.nf @@ -15,7 +15,16 @@ nextflow.enable.dsl = 2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -WorkflowMain.initialise(workflow, params, log) +// Print help message if needed +if (params.help) { + def logo = NfcoreTemplate.logo(workflow, params.monochrome_logs) + def citation = '\n' + WorkflowMain.citation(workflow) + '\n' + def String command = '\n' + "\$ nextflow run ${workflow.manifest.name} -profile test,docker" + '\n' + log.info logo + command + citation + NfcoreTemplate.dashedLine(params.monochrome_logs) + System.exit(0) +} + +WorkflowMain.initialise(workflow, params, log, args) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -23,13 +32,13 @@ WorkflowMain.initialise(workflow, params, log) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -include { PGSCALC } from './workflows/pgscalc' +include { PGSCCALC } from './workflows/pgsc_calc' // -// WORKFLOW: Run main pgscatalog/pgsc_calc analysis pipeline +// WORKFLOW: Run main pgscatalog/pgsccalc analysis pipeline // -workflow PGSCATALOG_PGSCALC { - PGSCALC () +workflow PGSCATALOG_PGSCCALC { + PGSCCALC () } /* @@ -43,7 +52,7 @@ workflow PGSCATALOG_PGSCALC { // See: https://github.com/nf-core/rnaseq/issues/619 // workflow { - PGSCATALOG_PGSCALC () + PGSCATALOG_PGSCCALC () } /* diff --git a/modules/local/ancestry/bootstrap/make_database.nf b/modules/local/ancestry/bootstrap/make_database.nf index e6d2aa16..fdc1e7f9 100644 --- a/modules/local/ancestry/bootstrap/make_database.nf +++ b/modules/local/ancestry/bootstrap/make_database.nf @@ -3,7 +3,7 @@ process MAKE_DATABASE { label 'process_low' label 'zstd' // controls conda, docker, + singularity options - storeDir "$workDir/reference" + storeDir "${workDir.resolve()}/reference" conda "${task.ext.conda}" diff --git a/modules/local/ancestry/extract_database.nf b/modules/local/ancestry/extract_database.nf index b7c2fc1b..5ae7184b 100644 --- a/modules/local/ancestry/extract_database.nf +++ b/modules/local/ancestry/extract_database.nf @@ -3,7 +3,7 @@ process EXTRACT_DATABASE { label 'process_low' label 'zstd' // controls conda, docker, + singularity options - storeDir "$workDir/ref_extracted/" + storeDir "${workDir.resolve()}/ref_extracted/" conda "${task.ext.conda}" diff --git a/modules/local/ancestry/intersect_variants.nf b/modules/local/ancestry/intersect_variants.nf index ec505627..6f01e427 100644 --- a/modules/local/ancestry/intersect_variants.nf +++ b/modules/local/ancestry/intersect_variants.nf @@ -4,7 +4,7 @@ process INTERSECT_VARIANTS { label 'zstd' // controls conda, docker, + singularity options tag "$meta.id chromosome $meta.chrom" - storeDir "$workDir/intersected/$meta.id/$meta.chrom" + storeDir "${workDir.resolve()}/intersected/$meta.id/$meta.chrom" conda "${task.ext.conda}" diff --git a/modules/local/ancestry/oadp/fraposa_pca.nf b/modules/local/ancestry/oadp/fraposa_pca.nf index ec317190..1cccbf07 100644 --- a/modules/local/ancestry/oadp/fraposa_pca.nf +++ b/modules/local/ancestry/oadp/fraposa_pca.nf @@ -4,7 +4,7 @@ process FRAPOSA_PCA { label 'fraposa' // controls conda, docker, + singularity options tag "reference" - cache "deep" + storeDir "${workDir.resolve()}/fraposa/reference/${target_geno.baseName}/" conda "${task.ext.conda}" diff --git a/modules/local/ancestry/oadp/fraposa_project.nf b/modules/local/ancestry/oadp/fraposa_project.nf index 79270ecd..d792be92 100644 --- a/modules/local/ancestry/oadp/fraposa_project.nf +++ b/modules/local/ancestry/oadp/fraposa_project.nf @@ -4,7 +4,7 @@ process FRAPOSA_PROJECT { label 'fraposa' // controls conda, docker, + singularity options tag "${target_geno.baseName.tokenize('_')[1]}" - storeDir "$workDir/fraposa/${params.target_build}/${target_geno.baseName}/${split_fam}" + storeDir "${workDir.resolve()}/fraposa/${params.target_build}/${target_geno.baseName}/${split_fam}" conda "${task.ext.conda}" diff --git a/modules/local/ancestry/oadp/intersect_thinned.nf b/modules/local/ancestry/oadp/intersect_thinned.nf index bb0b5db8..9e300f90 100644 --- a/modules/local/ancestry/oadp/intersect_thinned.nf +++ b/modules/local/ancestry/oadp/intersect_thinned.nf @@ -11,7 +11,7 @@ process INTERSECT_THINNED { label 'plink2' // controls conda, docker, + singularity options tag "$meta.id" - storeDir "$workDir/thinned_intersection/${params.target_build}/${meta.id}" + storeDir "${workDir.resolve()}/thinned_intersection/${params.target_build}/${meta.id}" conda "${task.ext.conda}" diff --git a/modules/local/match_combine.nf b/modules/local/match_combine.nf index 1b84709f..4aa1871a 100644 --- a/modules/local/match_combine.nf +++ b/modules/local/match_combine.nf @@ -6,7 +6,7 @@ process MATCH_COMBINE { // first element of tag must be sampleset tag "$meta.id" - scratch (workflow.containerEngine == 'singularity' || params.parallel ? true : false) + scratch (workflow.containerEngine == 'singularity') conda "${task.ext.conda}" diff --git a/modules/local/match_variants.nf b/modules/local/match_variants.nf index b2a4dbc8..4c43523a 100644 --- a/modules/local/match_variants.nf +++ b/modules/local/match_variants.nf @@ -5,7 +5,7 @@ process MATCH_VARIANTS { // first element of tag must be sampleset tag "$meta.id chromosome $meta.chrom" - scratch (workflow.containerEngine == 'singularity' || params.parallel ? true : false) + scratch (workflow.containerEngine == 'singularity') errorStrategy 'finish' conda "${task.ext.conda}" diff --git a/modules/local/plink2_relabelbim.nf b/modules/local/plink2_relabelbim.nf index beb487da..5c9fc4bf 100644 --- a/modules/local/plink2_relabelbim.nf +++ b/modules/local/plink2_relabelbim.nf @@ -6,8 +6,7 @@ process PLINK2_RELABELBIM { tag "$meta.id chromosome $meta.chrom" storeDir ( params.genotypes_cache ? "$params.genotypes_cache/${meta.id}/${meta.build}/${meta.chrom}" : - "$workDir/genomes/${meta.id}/${meta.build}/${meta.chrom}/") - + "${workDir.resolve()}/genomes/${meta.id}/${meta.build}/${meta.chrom}") conda "${task.ext.conda}" container "${ workflow.containerEngine == 'singularity' && diff --git a/modules/local/plink2_relabelpvar.nf b/modules/local/plink2_relabelpvar.nf index 6de23ec3..7aac2135 100644 --- a/modules/local/plink2_relabelpvar.nf +++ b/modules/local/plink2_relabelpvar.nf @@ -7,7 +7,7 @@ process PLINK2_RELABELPVAR { tag "$meta.id chromosome $meta.chrom" storeDir ( params.genotypes_cache ? "$params.genotypes_cache/${meta.id}/${meta.build}/${meta.chrom}" : - "$workDir/genomes/${meta.id}/${meta.build}/${meta.chrom}/") + "${workDir.resolve()}/genomes/${meta.id}/${meta.build}/${meta.chrom}") conda "${task.ext.conda}" diff --git a/modules/local/plink2_vcf.nf b/modules/local/plink2_vcf.nf index d13201d4..f2986b3b 100644 --- a/modules/local/plink2_vcf.nf +++ b/modules/local/plink2_vcf.nf @@ -7,7 +7,7 @@ process PLINK2_VCF { tag "$meta.id chromosome $meta.chrom" storeDir ( params.genotypes_cache ? "$params.genotypes_cache/${meta.id}/${meta.build}/${meta.chrom}" : - "$workDir/genomes/${meta.id}/${meta.build}/${meta.chrom}/") + "${workDir.resolve()}/genomes/${meta.id}/${meta.build}/${meta.chrom}") conda "${task.ext.conda}" diff --git a/modules/local/score_report.nf b/modules/local/score_report.nf index 32e25c29..8471ab30 100644 --- a/modules/local/score_report.nf +++ b/modules/local/score_report.nf @@ -32,15 +32,15 @@ process SCORE_REPORT { def args = task.ext.args ?: '' run_ancestry = params.run_ancestry ? true : false """ + cp $projectDir/assets/report/report.qmd . + export DENO_DIR=\$(mktemp -d) + export XDG_CACHE_HOME=\$(mktemp -d) + echo $workflow.commandLine > command.txt echo "keep_multiallelic: $params.keep_multiallelic" > params.txt echo "keep_ambiguous : $params.keep_ambiguous" >> params.txt echo "min_overlap : $params.min_overlap" >> params.txt - - cp -r $projectDir/assets/report/* . - # workaround for unhelpful filenotfound quarto errors in some HPCs - mkdir temp && TMPDIR=temp - + quarto render report.qmd -M "self-contained:true" \ -P score_path:$scorefile \ -P sampleset:$meta.id \ @@ -53,3 +53,4 @@ process SCORE_REPORT { END_VERSIONS """ } + diff --git a/nextflow.config b/nextflow.config index 4adc2fc7..c81da04c 100644 --- a/nextflow.config +++ b/nextflow.config @@ -1,6 +1,6 @@ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - pgscatalog/pgsc_calc Nextflow config file + pgscatalog/pgsccalc Nextflow config file ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Default config options for all compute environments ---------------------------------------------------------------------------------------- @@ -8,10 +8,6 @@ // Global default params, used in configs params { - // runtime params - platform = "amd64" - parallel = false - // Input params input = null format = "csv" @@ -21,9 +17,11 @@ params { pgp_id = null efo_direct = false + // reference params - run_ancestry = null // path to reference database TODO: replace with NO_FILE + run_ancestry = null ancestry_checksums = "$projectDir/assets/ancestry/checksums.txt" + // if you want to liftover --scorefiles, set the chain files hg19_chain = null // "https://hgdownload.cse.ucsc.edu/goldenpath/hg19/liftOver/hg19ToHg38.over.chain.gz" hg38_chain = null // "https://hgdownload.soe.ucsc.edu/goldenPath/hg38/liftOver/hg38ToHg19.over.chain.gz" @@ -46,6 +44,7 @@ params { normalization_method = "empirical mean mean+var" n_normalization = 4 + // compatibility params liftover = false target_build = null @@ -59,6 +58,7 @@ params { copy_genomes = false genotypes_cache = null + // Debug params only_bootstrap = false only_input = false @@ -68,35 +68,67 @@ params { only_score = false skip_ancestry = true + // deprecated params + platform = null + // Boilerplate options - outdir = "./results" - tracedir = "${params.outdir}/pipeline_info" + outdir = 'results' publish_dir_mode = 'copy' email = null email_on_fail = null plaintext_email = false monochrome_logs = false + hook_url = null help = false - validate_params = true - show_hidden_params = false - schema_ignore_params = 'only_bootstrap,only_input,only_compatible,only_match,only_projection,only_score,skip_ancestry' + version = false + + // Config options + config_profile_name = null + config_profile_description = null + custom_config_version = 'master' + custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" + config_profile_contact = null + config_profile_url = null + // Max resource options // Defaults only, expecting to be overwritten - max_memory = '16.GB' - max_cpus = 2 + max_memory = '128.GB' + max_cpus = 16 max_time = '240.h' + // Schema validation default options + validationFailUnrecognisedParams = false + validationLenientMode = false + validationSchemaIgnoreParams = 'genomes,igenomes_base,platform,only_bootstrap,only_input,only_compatible,only_match,only_score' + validationShowHiddenParams = false + validate_params = true + } // Load base.config by default for all pipelines includeConfig 'conf/base.config' +// Load nf-core custom profiles from different Institutions +try { + includeConfig "${params.custom_config_base}/nfcore_custom.config" +} catch (Exception e) { + System.err.println("WARNING: Could not load nf-core/config profiles: ${params.custom_config_base}/nfcore_custom.config") +} + +// Load pgscatalog/pgsccalc custom profiles from different institutions. +// Warning: Uncomment only if a pipeline-specific institutional config already exists on nf-core/configs! +// try { +// includeConfig "${params.custom_config_base}/pipeline/pgsccalc.config" +// } catch (Exception e) { +// System.err.println("WARNING: Could not load nf-core/config/pgsccalc profiles: ${params.custom_config_base}/pipeline/pgsccalc.config") +// } profiles { debug { dumpHashes = true process.beforeScript = 'echo $HOSTNAME' cleanup = false + nextflow.enable.configProcessNamesValidation = true } conda { conda.enabled = true @@ -105,6 +137,8 @@ profiles { podman.enabled = false shifter.enabled = false charliecloud.enabled = false + channels = ['conda-forge', 'bioconda', 'defaults'] + apptainer.enabled = false } mamba { conda.enabled = true @@ -114,59 +148,84 @@ profiles { podman.enabled = false shifter.enabled = false charliecloud.enabled = false + apptainer.enabled = false } docker { - def platform = params.platform == 'arm64' ? '--platform linux/arm64' : '--platform linux/amd64' - docker.runOptions = ['-u $(id -u):$(id -g) ', platform].join(' ') docker.enabled = true - docker.userEmulation = true + conda.enabled = false singularity.enabled = false podman.enabled = false shifter.enabled = false charliecloud.enabled = false + apptainer.enabled = false + docker.runOptions = '-u $(id -u):$(id -g)' + } + arm { + docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/arm64' } singularity { singularity.enabled = true singularity.autoMounts = true + conda.enabled = false docker.enabled = false podman.enabled = false shifter.enabled = false charliecloud.enabled = false + apptainer.enabled = false } podman { podman.enabled = true + conda.enabled = false docker.enabled = false singularity.enabled = false shifter.enabled = false charliecloud.enabled = false + apptainer.enabled = false } shifter { shifter.enabled = true + conda.enabled = false docker.enabled = false singularity.enabled = false podman.enabled = false charliecloud.enabled = false + apptainer.enabled = false } charliecloud { charliecloud.enabled = true + conda.enabled = false docker.enabled = false singularity.enabled = false podman.enabled = false shifter.enabled = false + apptainer.enabled = false + } + apptainer { + apptainer.enabled = true + apptainer.autoMounts = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false } gitpod { executor.name = 'local' - executor.cpus = 16 - executor.memory = 60.GB + executor.cpus = 4 + executor.memory = 8.GB } test { includeConfig 'conf/test.config' } - test_json { includeConfig 'conf/test_json.config' } test_full { includeConfig 'conf/test_full.config' } } -if (!params.parallel) { - includeConfig 'conf/sequential.config' -} +// Set default registry for Apptainer, Docker, Podman and Singularity independent of -profile +// Will not be used unless Apptainer / Docker / Podman / Singularity are enabled +// Set to your registry if you have a mirror of containers +apptainer.registry = 'quay.io' +docker.registry = 'quay.io' +podman.registry = 'quay.io' +singularity.registry = 'quay.io' // Export these variables to prevent local Python/R libraries from conflicting with those in the container // The JULIA depot path has been adjusted to a fixed path `/usr/local/share/julia` that needs to be used for packages in the container. @@ -182,22 +241,25 @@ env { // Capture exit codes from upstream processes when piping process.shell = ['/bin/bash', '-euo', 'pipefail'] +// Disable process selector warnings by default. Use debug profile to enable warnings. +nextflow.enable.configProcessNamesValidation = false + def trace_timestamp = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss') timeline { enabled = true - file = "${params.tracedir}/execution_timeline_${trace_timestamp}.html" + file = "${params.outdir}/pipeline_info/execution_timeline_${trace_timestamp}.html" } report { enabled = true - file = "${params.tracedir}/execution_report_${trace_timestamp}.html" + file = "${params.outdir}/pipeline_info/execution_report_${trace_timestamp}.html" } trace { enabled = true - file = "${params.tracedir}/execution_trace_${trace_timestamp}.txt" + file = "${params.outdir}/pipeline_info/execution_trace_${trace_timestamp}.txt" } dag { enabled = true - file = "${params.tracedir}/pipeline_dag_${trace_timestamp}.html" + file = "${params.outdir}/pipeline_info/pipeline_dag_${trace_timestamp}.html" } manifest { @@ -208,7 +270,7 @@ manifest { description = 'The Polygenic Score Catalog Calculator is a nextflow pipeline for polygenic score calculation' mainScript = 'main.nf' nextflowVersion = '>=22.10.0' - version = '2.0.0-alpha.4' + version = '2.0.0-alpha.5' } // Load modules.config for DSL2 module specific options diff --git a/nextflow_schema.json b/nextflow_schema.json index 975dd273..9cd5993a 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -1,455 +1,456 @@ { - "$schema": "http://json-schema.org/draft-07/schema", - "$id": "https://raw.githubusercontent.com/pgscatalog/pgsc_calc/master/nextflow_schema.json", - "title": "pgscatalog/pgsc_calc pipeline parameters", - "description": "This pipeline applies scoring files from the PGS Catalog to target set(s) of genotyped samples", - "type": "object", - "definitions": { - "input_output_options": { - "title": "Input/output options", - "type": "object", - "fa_icon": "fas fa-terminal", - "description": "Define where the pipeline should find input data and save output data.", - "properties": { - "input": { - "type": "string", - "description": "Path to input samplesheet", - "format": "file-path" - }, - "format": { - "type": "string", - "default": "csv", - "fa_icon": "fas fa-cog", - "description": "Format of input samplesheet", - "enum": [ - "csv", - "json" - ] - }, - "scorefile": { - "type": "string", - "description": "Path to a scoring file in PGS Catalog format. Multiple scorefiles can be specified using wildcards (e.g., ``--scorefile \"path/to/scores/*.txt\"``)", - "fa_icon": "fas fa-file-alt", - "format": "file-path" - }, - "pgs_id": { - "type": "string", - "description": "A comma separated list of PGS score IDs, e.g. PGS000802" - }, - "pgp_id": { - "type": "string", - "description": "A comma separated list of PGS Catalog publications, e.g. PGP000001" - }, - "trait_efo": { - "type": "string", - "description": "A comma separated list of PGS Catalog EFO traits, e.g. EFO_0004214" - }, - "efo_direct": { - "type": "boolean", - "description": "Return only PGS tagged with exact EFO term (e.g. no PGS for child/descendant terms in the ontology)" - }, - "copy_genomes": { - "type": "boolean", - "description": "Copy harmonised genomes (plink2 pgen/pvar/psam files) to outdir" - }, - "genotypes_cache": { - "type": "string", - "default": "None", - "description": "A path to a directory that should contain relabelled genotypes", - "format": "directory-path" - }, - "outdir": { - "type": "string", - "description": "Path to the output directory where the results will be saved.", - "default": "./results", - "fa_icon": "fas fa-folder-open", - "format": "directory-path" - }, - "email": { - "type": "string", - "description": "Email address for completion summary.", - "fa_icon": "fas fa-envelope", - "help_text": "Set this parameter to your e-mail address to get a summary e-mail with details of the run sent to you when the workflow exits. If set in your user config file (`~/.nextflow/config`) then you don't need to specify this on the command line for every run.", - "pattern": "^([a-zA-Z0-9_\\-\\.]+)@([a-zA-Z0-9_\\-\\.]+)\\.([a-zA-Z]{2,5})$" - } - }, - "required": [ - "input", - "format" - ] - }, - "ancestry_options": { - "title": "Ancestry options", - "type": "object", - "description": "", - "default": "", - "properties": { - "ancestry_params_file": { - "type": "string", - "default": "None", - "description": "A YAML or JSON file that contains parameters for handling ancestry options" - }, - "projection_method": { - "type": "string", - "default": "oadp", - "enum": [ - "oadp", - "sp", - "adp" - ], - "description": "The method for PCA prediction. oadp: most accurate. adp: accurate but slow. sp: fast but inaccurate." - }, - "ancestry_method": { - "type": "string", - "default": "RandomForest", - "description": "Method used for population/ancestry assignment", - "enum": [ - "Mahalanobis", - "RandomForest" - ] - }, - "ref_label": { - "type": "string", - "default": "SuperPop", - "description": "Population labels in reference psam to use for assignment" - }, - "n_popcomp": { - "type": "integer", - "default": 5, - "description": "Number of PCs used for population assignment" - }, - "normalization_method": { - "type": "string", - "default": "empirical mean mean+var", - "description": "Method used for normalisation of genetic ancestry", - "enum": [ - "empirical", - "mean", - "mean+var", - "empirical mean mean+var" - ] - }, - "n_normalization": { - "type": "integer", - "default": 4, - "description": "Number of PCs used for population normalisation" - }, - "load_afreq": { - "type": "boolean", - "default": true, - "description": "Load allelic frequencies from reference panel when scoring target genomes" - } - }, - "required": [ - "projection_method", - "ancestry_method", - "ref_label", - "n_popcomp", - "normalization_method", - "n_normalization", - "load_afreq" - ] - }, - "reference_options": { - "title": "Reference options", - "type": "object", - "description": "Define how reference genomes are defined and processed", - "default": "", - "properties": { - "run_ancestry": { - "type": "string", - "default": "None", - "format": "file-path", - "description": "Path to reference database. Must be set if --ref_samplesheet is not set." - }, - "ref_samplesheet": { - "type": "string", - "description": "Path to a samplesheet that describes the structure of reference data. Must be set if --ref isn't set." - }, - "hg19_chain": { - "type": "string", - "description": "Path to a UCSC chain file for converting from hg19 to hg38. Needed if lifting over a custom scoring file.", - "pattern": ".*chain.gz$", - "format": "file-path", - "mimetype": "application/gzip" - }, - "hg38_chain": { - "type": "string", - "description": "Path to a UCSC chain file for converting from hg38 to hg19. Needed if lifting over a custom scoring file.", - "format": "file-path", - "mimetype": "application/gzip" - }, - "geno_ref": { - "type": "number", - "default": 0.1, - "description": "Exclude variants with missing call frequencies greater than a threshold (in reference genomes)", - "minimum": 0, - "maximum": 1 - }, - "mind_ref": { - "type": "number", - "default": 0.1, - "description": "Exclude samples with missing call frequencies greater than a threshold (in reference genomes)", - "minimum": 0, - "maximum": 1 - }, - "maf_ref": { - "type": "number", - "default": 0.05, - "description": "Exclude variants with allele frequency lower than a threshold (in reference genomes)", - "minimum": 0, - "maximum": 1 - }, - "hwe_ref": { - "type": "number", - "default": 1e-04, - "description": "Exclude variants with Hardy-Weinberg equilibrium exact test p-values below a threshold (in reference genomes)", - "minimum": 0, - "maximum": 1 - }, - "indep_pairwise_ref": { - "type": "string", - "default": "1000 50 0.05", - "description": "Used to generate a list of variants in approximate linkage equilibrium in reference genomes. Window size - step size - unphased hardcall r^2 threshold." - }, - "ld_grch37": { - "type": "string", - "description": "Path to a file that contains areas of high linkage disequilibrium in the reference data (build GRCh37).", - "format": "file-path", - "mimetype": "text/plain" - }, - "ld_grch38": { - "type": "string", - "description": "Path to a file that contains areas of high linkage disequilibrium in the reference data (build GRCh38).", - "format": "file-path", - "mimetype": "text/plain" - } - }, - "required": [ - "geno_ref", - "mind_ref", - "maf_ref", - "hwe_ref", - "indep_pairwise_ref", - "ld_grch37", - "ld_grch38" - ] - }, - "compatibility_options": { - "title": "Compatibility options", - "type": "object", - "description": "Define parameters that control how scoring files and target genomes are made compatible with each other", - "default": "", - "properties": { - "compat_params_file": { - "type": "string", - "default": "None", - "description": "A YAML or JSON file that contains parameters for handling compatibility options" - }, - "target_build": { - "type": "string", - "enum": [ - "GRCh37", - "GRCh38" - ], - "description": "Genome build of target genomes" - }, - "liftover": { - "type": "boolean", - "description": "Lift scoring files to match your target genomes. Requires build information in the header of the scoring files." - }, - "min_lift": { - "type": "number", - "default": 0.95, - "description": "Minimum proportion of variants required to successfully remap a scoring file to a different genome build", - "minimum": 0, - "maximum": 1 - } - }, - "required": [ - "target_build" - ] - }, - "matching_options": { - "title": "Matching options", - "type": "object", - "description": "Define how variants are matched across scoring files and target genomes", - "default": "", - "properties": { - "keep_multiallelic": { - "type": "boolean", - "description": "Allow matches of scoring file variants to multiallelic variants in the target dataset" - }, - "keep_ambiguous": { - "type": "boolean", - "description": "Keep matches of scoring file variants to strand ambiguous variants (e.g. A/T and C/G SNPs) in the target dataset. This assumes the scoring file and target dataset report variants on the same strand." - }, - "fast_match": { - "type": "boolean", - "description": "Enable fast matching, which significantly increases RAM usage (32GB minimum recommended)" - }, - "min_overlap": { - "type": "number", - "default": 0.75, - "description": "Minimum proportion of variants present in both the score file and input target genomic data", - "fa_icon": "fas fa-cog", - "minimum": 0, - "maximum": 1 - } - }, - "fa_icon": "fas fa-user-cog" - }, - "max_job_request_options": { - "title": "Max job request options", - "type": "object", - "fa_icon": "fab fa-acquisitions-incorporated", - "description": "Set the top limit for requested resources for any single job.", - "help_text": "If you are running on a smaller system, a pipeline step requesting more resources than are available may cause the Nextflow to stop the run with an error. These options allow you to cap the maximum resources requested by any single job so that the pipeline will run on your system.\n\nNote that you can not _increase_ the resources requested by any job using these options. For that you will need your own configuration file. See [the nf-core website](https://nf-co.re/usage/configuration) for details.", - "properties": { - "max_cpus": { - "type": "integer", - "description": "Maximum number of CPUs that can be requested for any single job.", - "default": 16, - "fa_icon": "fas fa-microchip", - "hidden": true, - "help_text": "Use to set an upper-limit for the CPU requirement for each process. Should be an integer e.g. `--max_cpus 1`" - }, - "max_memory": { - "type": "string", - "description": "Maximum amount of memory that can be requested for any single job.", - "default": "128.GB", - "fa_icon": "fas fa-memory", - "pattern": "^\\d+(\\.\\d+)?\\.?\\s*(K|M|G|T)?B$", - "hidden": true, - "help_text": "Use to set an upper-limit for the memory requirement for each process. Should be a string in the format integer-unit e.g. `--max_memory '8.GB'`" - }, - "max_time": { - "type": "string", - "description": "Maximum amount of time that can be requested for any single job.", - "default": "240.h", - "fa_icon": "far fa-clock", - "pattern": "^(\\d+\\.?\\s*(s|m|h|day)\\s*)+$", - "hidden": true, - "help_text": "Use to set an upper-limit for the time requirement for each process. Should be a string in the format integer-unit e.g. `--max_time '2.h'`" - } - } - }, - "generic_options": { - "title": "Generic options", - "type": "object", - "fa_icon": "fas fa-file-import", - "description": "Less common options for the pipeline, typically set in a config file.", - "help_text": "These options are common to all nf-core pipelines and allow you to customise some of the core preferences for how the pipeline runs.\n\nTypically these options would be set in a Nextflow config file loaded for all pipeline runs, such as `~/.nextflow/config`.", - "properties": { - "help": { - "type": "boolean", - "description": "Display help text.", - "fa_icon": "fas fa-question-circle", - "hidden": true - }, - "publish_dir_mode": { - "type": "string", - "default": "copy", - "description": "Method used to save pipeline results to output directory.", - "help_text": "The Nextflow `publishDir` option specifies which intermediate files should be saved to the output directory. This option tells the pipeline what method should be used to move these files. See [Nextflow docs](https://www.nextflow.io/docs/latest/process.html#publishdir) for details.", - "fa_icon": "fas fa-copy", - "enum": [ - "symlink", - "rellink", - "link", - "copy", - "copyNoFollow", - "move" - ], - "hidden": true - }, - "email_on_fail": { - "type": "string", - "description": "Email address for completion summary, only when pipeline fails.", - "fa_icon": "fas fa-exclamation-triangle", - "pattern": "^([a-zA-Z0-9_\\-\\.]+)@([a-zA-Z0-9_\\-\\.]+)\\.([a-zA-Z]{2,5})$", - "help_text": "An email address to send a summary email to when the pipeline is completed - ONLY sent if the pipeline does not exit successfully.", - "hidden": true - }, - "plaintext_email": { - "type": "boolean", - "description": "Send plain-text email instead of HTML.", - "fa_icon": "fas fa-remove-format", - "hidden": true - }, - "monochrome_logs": { - "type": "boolean", - "description": "Do not use coloured log outputs.", - "fa_icon": "fas fa-palette", - "hidden": true - }, - "tracedir": { - "type": "string", - "description": "Directory to keep pipeline Nextflow logs and reports.", - "default": "${params.outdir}/pipeline_info", - "fa_icon": "fas fa-cogs", - "hidden": true - }, - "validate_params": { - "type": "boolean", - "description": "Boolean whether to validate parameters against the schema at runtime", - "default": true, - "fa_icon": "fas fa-check-square", - "hidden": true - }, - "show_hidden_params": { - "type": "boolean", - "fa_icon": "far fa-eye-slash", - "description": "Show all params when using `--help`", - "hidden": true, - "help_text": "By default, parameters set as _hidden_ in the schema are not shown on the command line when a user runs with `--help`. Specifying this option will tell the pipeline to show all parameters." - }, - "platform": { - "type": "string", - "default": "amd64", - "enum": [ - "amd64", - "arm64" - ], - "description": "What platform is the pipeline executing on?" - }, - "parallel": { - "type": "boolean", - "description": "Enable parallel calculation of scores. This is I/O and RAM intensive." - } - }, - "required": [ - "platform" - ] + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "https://raw.githubusercontent.com/pgscatalog/pgsc_calc/master/nextflow_schema.json", + "title": "pgscatalog/pgsc_calc pipeline parameters", + "description": "This pipeline applies scoring files from the PGS Catalog to target set(s) of genotyped samples", + "type": "object", + "definitions": { + "input_output_options": { + "title": "Input/output options", + "type": "object", + "fa_icon": "fas fa-terminal", + "description": "Define where the pipeline should find input data and save output data.", + "properties": { + "input": { + "type": "string", + "description": "Path to input samplesheet", + "format": "file-path" + }, + "format": { + "type": "string", + "default": "csv", + "fa_icon": "fas fa-cog", + "description": "Format of input samplesheet", + "enum": ["csv", "json"] + }, + "scorefile": { + "type": "string", + "description": "Path to a scoring file in PGS Catalog format. Multiple scorefiles can be specified using wildcards (e.g., ``--scorefile \"path/to/scores/*.txt\"``)", + "fa_icon": "fas fa-file-alt", + "format": "file-path" + }, + "pgs_id": { + "type": "string", + "description": "A comma separated list of PGS score IDs, e.g. PGS000802" + }, + "pgp_id": { + "type": "string", + "description": "A comma separated list of PGS Catalog publications, e.g. PGP000001" + }, + "trait_efo": { + "type": "string", + "description": "A comma separated list of PGS Catalog EFO traits, e.g. EFO_0004214" + }, + "efo_direct": { + "type": "boolean", + "description": "Return only PGS tagged with exact EFO term (e.g. no PGS for child/descendant terms in the ontology)" + }, + "copy_genomes": { + "type": "boolean", + "description": "Copy harmonised genomes (plink2 pgen/pvar/psam files) to outdir" + }, + "genotypes_cache": { + "type": "string", + "description": "A path to a directory that should contain relabelled genotypes", + "format": "directory-path" + }, + "outdir": { + "type": "string", + "description": "Path to the output directory where the results will be saved.", + "fa_icon": "fas fa-folder-open", + "format": "directory-path" + }, + "email": { + "type": "string", + "description": "Email address for completion summary.", + "fa_icon": "fas fa-envelope", + "help_text": "Set this parameter to your e-mail address to get a summary e-mail with details of the run sent to you when the workflow exits. If set in your user config file (`~/.nextflow/config`) then you don't need to specify this on the command line for every run.", + "pattern": "^([a-zA-Z0-9_\\-\\.]+)@([a-zA-Z0-9_\\-\\.]+)\\.([a-zA-Z]{2,5})$" } + }, + "required": ["input", "format"] }, - "allOf": [ - { - "$ref": "#/definitions/input_output_options" + "ancestry_options": { + "title": "Ancestry options", + "type": "object", + "description": "", + "default": "", + "properties": { + "projection_method": { + "type": "string", + "default": "oadp", + "enum": ["oadp", "sp", "adp"], + "description": "The method for PCA prediction. oadp: most accurate. adp: accurate but slow. sp: fast but inaccurate." }, - { - "$ref": "#/definitions/ancestry_options" + "ancestry_method": { + "type": "string", + "default": "RandomForest", + "description": "Method used for population/ancestry assignment", + "enum": ["Mahalanobis", "RandomForest"] }, - { - "$ref": "#/definitions/reference_options" + "ref_label": { + "type": "string", + "default": "SuperPop", + "description": "Population labels in reference psam to use for assignment" }, - { - "$ref": "#/definitions/compatibility_options" + "n_popcomp": { + "type": "integer", + "default": 5, + "description": "Number of PCs used for population assignment" }, - { - "$ref": "#/definitions/matching_options" + "normalization_method": { + "type": "string", + "default": "empirical mean mean+var", + "description": "Method used for normalisation of genetic ancestry", + "enum": ["empirical", "mean", "mean+var", "empirical mean mean+var"] }, - { - "$ref": "#/definitions/max_job_request_options" + "n_normalization": { + "type": "integer", + "default": 4, + "description": "Number of PCs used for population normalisation" }, - { - "$ref": "#/definitions/generic_options" + "load_afreq": { + "type": "boolean", + "default": true, + "description": "Load allelic frequencies from reference panel when scoring target genomes" } - ], - "properties": { + }, + "required": [ + "projection_method", + "ancestry_method", + "ref_label", + "n_popcomp", + "normalization_method", + "n_normalization", + "load_afreq" + ] + }, + "reference_options": { + "title": "Reference options", + "type": "object", + "description": "Define how reference genomes are defined and processed", + "default": "", + "properties": { + "run_ancestry": { + "type": "string", + "format": "file-path", + "description": "Path to reference database. Must be set if --ref_samplesheet is not set." + }, + "ref_samplesheet": { + "type": "string", + "description": "Path to a samplesheet that describes the structure of reference data. Must be set if --ref isn't set." + }, + "hg19_chain": { + "type": "string", + "description": "Path to a UCSC chain file for converting from hg19 to hg38. Needed if lifting over a custom scoring file.", + "pattern": ".*chain.gz$", + "format": "file-path", + "mimetype": "application/gzip" + }, + "hg38_chain": { + "type": "string", + "description": "Path to a UCSC chain file for converting from hg38 to hg19. Needed if lifting over a custom scoring file.", + "format": "file-path", + "mimetype": "application/gzip" + }, + "geno_ref": { + "type": "number", + "default": 0.1, + "description": "Exclude variants with missing call frequencies greater than a threshold (in reference genomes)", + "minimum": 0, + "maximum": 1 + }, + "mind_ref": { + "type": "number", + "default": 0.1, + "description": "Exclude samples with missing call frequencies greater than a threshold (in reference genomes)", + "minimum": 0, + "maximum": 1 + }, + "maf_ref": { + "type": "number", + "default": 0.05, + "description": "Exclude variants with allele frequency lower than a threshold (in reference genomes)", + "minimum": 0, + "maximum": 1 + }, + "hwe_ref": { + "type": "number", + "default": 0.0001, + "description": "Exclude variants with Hardy-Weinberg equilibrium exact test p-values below a threshold (in reference genomes)", + "minimum": 0, + "maximum": 1 + }, + "indep_pairwise_ref": { + "type": "string", + "default": "1000 50 0.05", + "description": "Used to generate a list of variants in approximate linkage equilibrium in reference genomes. Window size - step size - unphased hardcall r^2 threshold." + }, + "ld_grch37": { + "type": "string", + "description": "Path to a file that contains areas of high linkage disequilibrium in the reference data (build GRCh37).", + "format": "file-path", + "mimetype": "text/plain" + }, + "ld_grch38": { + "type": "string", + "description": "Path to a file that contains areas of high linkage disequilibrium in the reference data (build GRCh38).", + "format": "file-path", + "mimetype": "text/plain" + }, + "ref_format_version": { + "type": "string", + "default": "v0.1" + }, "ancestry_checksums": { - "type": "string", - "default": "/Users/bwingfield/Documents/projects/pgsc_calc/assets/ancestry/checksums.txt" + "type": "string" + } + }, + "required": [ + "geno_ref", + "mind_ref", + "maf_ref", + "hwe_ref", + "indep_pairwise_ref", + "ld_grch37", + "ld_grch38" + ] + }, + "compatibility_options": { + "title": "Compatibility options", + "type": "object", + "description": "Define parameters that control how scoring files and target genomes are made compatible with each other", + "default": "", + "properties": { + "target_build": { + "type": "string", + "enum": ["GRCh37", "GRCh38"], + "description": "Genome build of target genomes" + }, + "liftover": { + "type": "boolean", + "description": "Lift scoring files to match your target genomes. Requires build information in the header of the scoring files." + }, + "min_lift": { + "type": "number", + "default": 0.95, + "description": "Minimum proportion of variants required to successfully remap a scoring file to a different genome build", + "minimum": 0, + "maximum": 1 + } + }, + "required": ["target_build"] + }, + "matching_options": { + "title": "Matching options", + "type": "object", + "description": "Define how variants are matched across scoring files and target genomes", + "default": "", + "properties": { + "keep_multiallelic": { + "type": "boolean", + "description": "Allow matches of scoring file variants to multiallelic variants in the target dataset" + }, + "keep_ambiguous": { + "type": "boolean", + "description": "Keep matches of scoring file variants to strand ambiguous variants (e.g. A/T and C/G SNPs) in the target dataset. This assumes the scoring file and target dataset report variants on the same strand." + }, + "fast_match": { + "type": "boolean", + "description": "Enable fast matching, which significantly increases RAM usage (32GB minimum recommended)" + }, + "min_overlap": { + "type": "number", + "default": 0.75, + "description": "Minimum proportion of variants present in both the score file and input target genomic data", + "fa_icon": "fas fa-cog", + "minimum": 0, + "maximum": 1 + } + }, + "fa_icon": "fas fa-user-cog" + }, + "max_job_request_options": { + "title": "Max job request options", + "type": "object", + "fa_icon": "fab fa-acquisitions-incorporated", + "description": "Set the top limit for requested resources for any single job.", + "help_text": "If you are running on a smaller system, a pipeline step requesting more resources than are available may cause the Nextflow to stop the run with an error. These options allow you to cap the maximum resources requested by any single job so that the pipeline will run on your system.\n\nNote that you can not _increase_ the resources requested by any job using these options. For that you will need your own configuration file. See [the nf-core website](https://nf-co.re/usage/configuration) for details.", + "properties": { + "max_cpus": { + "type": "integer", + "description": "Maximum number of CPUs that can be requested for any single job.", + "default": 16, + "fa_icon": "fas fa-microchip", + "hidden": true, + "help_text": "Use to set an upper-limit for the CPU requirement for each process. Should be an integer e.g. `--max_cpus 1`" + }, + "max_memory": { + "type": "string", + "description": "Maximum amount of memory that can be requested for any single job.", + "default": "128.GB", + "fa_icon": "fas fa-memory", + "pattern": "^\\d+(\\.\\d+)?\\.?\\s*(K|M|G|T)?B$", + "hidden": true, + "help_text": "Use to set an upper-limit for the memory requirement for each process. Should be a string in the format integer-unit e.g. `--max_memory '8.GB'`" + }, + "max_time": { + "type": "string", + "description": "Maximum amount of time that can be requested for any single job.", + "default": "240.h", + "fa_icon": "far fa-clock", + "pattern": "^(\\d+\\.?\\s*(s|m|h|day)\\s*)+$", + "hidden": true, + "help_text": "Use to set an upper-limit for the time requirement for each process. Should be a string in the format integer-unit e.g. `--max_time '2.h'`" + } + } + }, + "generic_options": { + "title": "Generic options", + "type": "object", + "fa_icon": "fas fa-file-import", + "description": "Less common options for the pipeline, typically set in a config file.", + "help_text": "These options are common to all nf-core pipelines and allow you to customise some of the core preferences for how the pipeline runs.\n\nTypically these options would be set in a Nextflow config file loaded for all pipeline runs, such as `~/.nextflow/config`.", + "properties": { + "help": { + "type": "boolean", + "description": "Display help text.", + "fa_icon": "fas fa-question-circle", + "hidden": true + }, + "publish_dir_mode": { + "type": "string", + "default": "copy", + "description": "Method used to save pipeline results to output directory.", + "help_text": "The Nextflow `publishDir` option specifies which intermediate files should be saved to the output directory. This option tells the pipeline what method should be used to move these files. See [Nextflow docs](https://www.nextflow.io/docs/latest/process.html#publishdir) for details.", + "fa_icon": "fas fa-copy", + "enum": [ + "symlink", + "rellink", + "link", + "copy", + "copyNoFollow", + "move" + ], + "hidden": true + }, + "email_on_fail": { + "type": "string", + "description": "Email address for completion summary, only when pipeline fails.", + "fa_icon": "fas fa-exclamation-triangle", + "pattern": "^([a-zA-Z0-9_\\-\\.]+)@([a-zA-Z0-9_\\-\\.]+)\\.([a-zA-Z]{2,5})$", + "help_text": "An email address to send a summary email to when the pipeline is completed - ONLY sent if the pipeline does not exit successfully.", + "hidden": true + }, + "plaintext_email": { + "type": "boolean", + "description": "Send plain-text email instead of HTML.", + "fa_icon": "fas fa-remove-format", + "hidden": true + }, + "monochrome_logs": { + "type": "boolean", + "description": "Do not use coloured log outputs.", + "fa_icon": "fas fa-palette", + "hidden": true + }, + "validate_params": { + "type": "boolean", + "description": "Boolean whether to validate parameters against the schema at runtime", + "default": true, + "fa_icon": "fas fa-check-square", + "hidden": true } + } + } + }, + "allOf": [ + { + "$ref": "#/definitions/input_output_options" + }, + { + "$ref": "#/definitions/ancestry_options" + }, + { + "$ref": "#/definitions/reference_options" + }, + { + "$ref": "#/definitions/compatibility_options" + }, + { + "$ref": "#/definitions/matching_options" + }, + { + "$ref": "#/definitions/max_job_request_options" + }, + { + "$ref": "#/definitions/generic_options" + } + ], + "properties": { + "only_bootstrap": { + "type": "boolean", + "hidden": true + }, + "only_input": { + "type": "boolean", + "hidden": true + }, + "only_compatible": { + "type": "boolean", + "hidden": true + }, + "only_match": { + "type": "boolean", + "hidden": true + }, + "only_projection": { + "type": "boolean", + "hidden": true + }, + "only_score": { + "type": "boolean", + "hidden": true + }, + "skip_ancestry": { + "type": "boolean", + "default": true, + "hidden": true + }, + "hook_url": { + "type": "string" + }, + "version": { + "type": "boolean" + }, + "config_profile_name": { + "type": "string" + }, + "config_profile_description": { + "type": "string" + }, + "custom_config_version": { + "type": "string", + "default": "master" + }, + "custom_config_base": { + "type": "string", + "default": "https://raw.githubusercontent.com/nf-core/configs/master" + }, + "config_profile_contact": { + "type": "string" + }, + "config_profile_url": { + "type": "string" + }, + "validationFailUnrecognisedParams": { + "type": "boolean" + }, + "validationLenientMode": { + "type": "boolean" + }, + "validationShowHiddenParams": { + "type": "boolean" } + } } diff --git a/workflows/pgscalc.nf b/workflows/pgsc_calc.nf similarity index 77% rename from workflows/pgscalc.nf rename to workflows/pgsc_calc.nf index 84fec661..d2d5ca92 100644 --- a/workflows/pgscalc.nf +++ b/workflows/pgsc_calc.nf @@ -1,75 +1,25 @@ /* -======================================================================================== - VALIDATE INPUTS (SAMPLESHEET) -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + PRINT PARAMS SUMMARY +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -def summary_params = NfcoreSchema.paramsSummaryMap(workflow, params) - -// Validate input parameters -WorkflowPgscalc.initialise(params, log) - -// Check input path parameters to see if they exist -def checkPathParamList = [params.input] - -for (param in checkPathParamList) { - file(param, checkIfExists: true) -} +include { paramsSummaryLog; paramsSummaryMap } from 'plugin/nf-validation' +def logo = NfcoreTemplate.logo(workflow, params.monochrome_logs) +def citation = '\n' + WorkflowMain.citation(workflow) + '\n' +def summary_params = paramsSummaryMap(workflow) -if (params.platform == 'arm64') { - profiles = summary_params['Core Nextflow options'].profile.tokenize(',') - if (profiles.contains('singularity') | profiles.contains('conda')) { - println "ERROR: arm64 platform only supports -profile docker" - System.exit(1) - } -} +// Print parameter summary log to screen +log.info logo + paramsSummaryLog(workflow) + citation -// Set up scorefile channels --------------------------------------------------- - -if (![params.scorefile, params.pgs_id, params.trait_efo, params.pgp_id].any()) { - println " ERROR: You didn't set any scores to use! \ - Please set --scorefile, --pgs_id, --trait_efo, or --pgp_id" - System.exit(1) -} - -if (!params.target_build) { - println "ERROR: You didn't set the target build of your target genomes" - println "Please set --target_build GRCh37 or --target_build GRCh38" - System.exit(1) -} - -if (params.liftover && !params.hg19_chain || params.liftover && !params.hg38_chain) { - println "ERROR: Missing --hg19_chain or --hg38_chain with --liftover set" - println "Please download UCSC chain files and set chain file paths" - println "See https://pgsc-calc.readthedocs.io/en/latest/how-to/liftover.html" - System.exit(1) -} - -unique_scorefiles = Channel.empty() - -if (params.scorefile) { - Channel.fromPath(params.scorefile, checkIfExists: true) - .set { scorefiles } - - scorefiles - .unique() - .join(scorefiles) - .set { unique_scorefiles } -} - -def process_accessions(String accession) { - if (accession) { - return accession.replaceAll('\\s','').tokenize(',').unique().join(' ') - } else { - return '' - } -} - -def String unique_trait_efo = process_accessions(params.trait_efo) -def String unique_pgp_id = process_accessions(params.pgp_id) -def String unique_pgs_id = process_accessions(params.pgs_id) +WorkflowPgscCalc.initialise(params, log) +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + DEBUG OPTIONS TO HALT WORKFLOW EXECUTION +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ def run_ancestry_bootstrap = true def run_input_check = true @@ -101,27 +51,27 @@ if (params.only_input) { run_report = false } -if (params.only_compatible) { +if (params.only_projection) { run_ancestry_bootstrap = true run_input_check = true run_make_compatible = true - run_match = false + run_match = true run_ancestry_assign = true run_apply_score = false run_report = false } -if (params.only_match) { +if (params.only_compatible) { run_ancestry_bootstrap = true run_input_check = true run_make_compatible = true - run_match = true + run_match = false run_ancestry_assign = true run_apply_score = false run_report = false } -if (params.only_projection) { +if (params.only_match) { run_ancestry_bootstrap = true run_input_check = true run_make_compatible = true @@ -151,6 +101,7 @@ if (params.run_ancestry) { run_ancestry_adjust = false } +// don't try to bootstrap if we're not estimating or adjusting if (!run_ancestry_assign && !run_ancestry_adjust) { run_ancestry_bootstrap = false } @@ -172,13 +123,26 @@ include { APPLY_SCORE } from '../subworkflows/local/apply_score' include { REPORT } from '../subworkflows/local/report' include { DUMPSOFTWAREVERSIONS } from '../modules/local/dumpsoftwareversions' + +/* +======================================================================================== + DEPRECATION WARNINGS +======================================================================================== +*/ + +if (params.platform) { + System.err.println "--platform has been deprecated to match nf-core framework" + System.err.println "Please use -profile docker,arm instead" + System.exit(1) +} + /* ======================================================================================== RUN MAIN WORKFLOW ======================================================================================== */ -workflow PGSCALC { +workflow PGSCCALC { ch_versions = Channel.empty() // @@ -200,25 +164,36 @@ workflow PGSCALC { // // SUBWORKFLOW: Get scoring file from PGS Catalog accession // - def accessions = [pgs_id: unique_pgs_id, pgp_id: unique_pgp_id, - trait_efo: unique_trait_efo] - - if (!accessions.every( { it.value == '' })) { - DOWNLOAD_SCOREFILES ( accessions, params.target_build ) - scorefiles = DOWNLOAD_SCOREFILES.out.scorefiles.mix(unique_scorefiles) - } else { - scorefiles = unique_scorefiles + ch_scores = Channel.empty() + if (params.scorefile) { + ch_scores = ch_scores.mix(Channel.fromPath(params.scorefile, checkIfExists: true)) + } + + // make sure accessions look sensible before querying PGS Catalog + def pgs_id = WorkflowPgscCalc.prepareAccessions(params.pgs_id, "pgs_id") + def pgp_id = WorkflowPgscCalc.prepareAccessions(params.pgp_id, "pgp_id") + def trait_efo = WorkflowPgscCalc.prepareAccessions(params.trait_efo, "trait_efo") + def accessions = pgs_id + pgp_id + trait_efo + + if (!accessions.every { it.value == "" }) { + DOWNLOAD_SCOREFILES(accessions, params.target_build) + ch_versions = ch_versions.mix(DOWNLOAD_SCOREFILES.out.versions) + ch_scores = ch_scores.mix(DOWNLOAD_SCOREFILES.out.scorefiles) + } + + if (!params.scorefile && accessions.every { it.value == "" }) { + Nextflow.error("No valid accessions or scoring files provided. Please double check --pgs_id, --pgp_id, --trait_efo, or --scorefile parameters") } // // SUBWORKFLOW: Validate and stage input files // - scorefiles.collect().set{ ch_scorefiles } - if (run_input_check) { + // flatten the score channel + ch_scorefiles = ch_scores.collect() // chain files are optional input - Channel.fromPath('NO_FILE', checkIfExists: false).set { chain_files } + Channel.fromPath("$projectDir/assets/NO_FILE", checkIfExists: false).set { chain_files } if (params.hg19_chain && params.hg38_chain) { Channel.fromPath(params.hg19_chain, checkIfExists: true) .mix(Channel.fromPath(params.hg38_chain, checkIfExists: true)) @@ -384,18 +359,27 @@ workflow PGSCALC { } /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ COMPLETION EMAIL AND SUMMARY -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ workflow.onComplete { if (params.email || params.email_on_fail) { - NfcoreTemplate.email(workflow, params, summary_params, projectDir, log, multiqc_report) + NfcoreTemplate.email(workflow, params, summary_params, projectDir, log) } + NfcoreTemplate.dump_parameters(workflow, params) NfcoreTemplate.summary(workflow, params, log) - println "Please remember to cite polygenic score authors if you publish with them!" - println "Check the output report for citation details" + if (params.hook_url) { + NfcoreTemplate.IM_notification(workflow, params, summary_params, projectDir, log) + } +} + +workflow.onError { + if (workflow.errorReport.contains("Process requirement exceeds available memory")) { + println("🛑 Default resources exceed availability 🛑 ") + println("💡 See here on how to configure pipeline: https://nf-co.re/docs/usage/configuration#tuning-workflow-resources 💡") + } } /*