From 7a93b668665336cfd7cd80fbf17a93314e9fa090 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 30 Apr 2019 17:32:47 +0200 Subject: [PATCH 001/854] Initial template commit --- .gitattributes | 1 + .github/CONTRIBUTING.md | 47 +++ .github/ISSUE_TEMPLATE/bug_report.md | 31 ++ .github/ISSUE_TEMPLATE/feature_request.md | 16 + .github/PULL_REQUEST_TEMPLATE.md | 15 + .github/markdownlint.yml | 9 + .gitignore | 7 + .travis.yml | 42 +++ CHANGELOG.md | 4 + CODE_OF_CONDUCT.md | 46 +++ Dockerfile | 7 + LICENSE | 21 ++ README.md | 30 ++ assets/email_template.html | 52 +++ assets/email_template.txt | 34 ++ assets/multiqc_config.yaml | 9 + assets/sendmail_template.txt | 36 ++ bin/markdown_to_html.r | 51 +++ bin/scrape_software_versions.py | 49 +++ conf/awsbatch.config | 18 + conf/base.config | 34 ++ conf/igenomes.config | 147 ++++++++ conf/test.config | 25 ++ docs/README.md | 12 + docs/output.md | 41 +++ docs/usage.md | 282 ++++++++++++++ environment.yml | 11 + main.nf | 428 ++++++++++++++++++++++ nextflow.config | 127 +++++++ 29 files changed, 1632 insertions(+) create mode 100644 .gitattributes create mode 100644 .github/CONTRIBUTING.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/markdownlint.yml create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 CHANGELOG.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 README.md create mode 100644 assets/email_template.html create mode 100644 assets/email_template.txt create mode 100644 assets/multiqc_config.yaml create mode 100644 assets/sendmail_template.txt create mode 100755 bin/markdown_to_html.r create mode 100755 bin/scrape_software_versions.py create mode 100644 conf/awsbatch.config create mode 100644 conf/base.config create mode 100644 conf/igenomes.config create mode 100644 conf/test.config create mode 100644 docs/README.md create mode 100644 docs/output.md create mode 100644 docs/usage.md create mode 100644 environment.yml create mode 100644 main.nf create mode 100644 nextflow.config diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..7fe55006f8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.config linguist-language=nextflow diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000000..aa11820ab2 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,47 @@ +# nf-core/sarek: Contributing Guidelines + +Hi there! Many thanks for taking an interest in improving nf-core/sarek. + +We try to manage the required tasks for nf-core/sarek using GitHub issues, you probably came to this page when creating one. Please use the pre-filled template to save time. + +However, don't be put off by this template - other more general issues and suggestions are welcome! Contributions to the code are even more welcome ;) + +> If you need help using or modifying nf-core/sarek then the best place to ask is on the pipeline channel on [Slack](https://nf-core-invite.herokuapp.com/). + + + +## Contribution workflow +If you'd like to write some code for nf-core/sarek, the standard workflow +is as follows: + +1. Check that there isn't already an issue about your idea in the + [nf-core/sarek issues](https://github.com/nf-core/sarek/issues) to avoid + duplicating work. + * If there isn't one already, please create one so that others know you're working on this +2. Fork the [nf-core/sarek repository](https://github.com/nf-core/sarek) to your GitHub account +3. Make the necessary changes / additions within your forked repository +4. Submit a Pull Request against the `dev` branch and wait for the code to be reviewed and merged. + +If you're not used to this workflow with git, you can start with some [basic docs from GitHub](https://help.github.com/articles/fork-a-repo/) or even their [excellent interactive tutorial](https://try.github.io/). + + +## Tests +When you create a pull request with changes, [Travis CI](https://travis-ci.org/) will run automatic tests. +Typically, pull-requests are only fully reviewed when these tests are passing, though of course we can help out before then. + +There are typically two types of tests that run: + +### Lint Tests +The nf-core has a [set of guidelines](http://nf-co.re/guidelines) which all pipelines must adhere to. +To enforce these and ensure that all pipelines stay in sync, we have developed a helper tool which runs checks on the pipeline code. This is in the [nf-core/tools repository](https://github.com/nf-core/tools) and once installed can be run locally with the `nf-core lint ` command. + +If any failures or warnings are encountered, please follow the listed URL for more documentation. + +### Pipeline Tests +Each nf-core pipeline should be set up with a minimal set of test-data. +Travis CI then runs the pipeline on this data to ensure that it exists successfully. +If there are any failures then the automated tests fail. +These tests are run both with the latest available version of Nextflow and also the minimum required version that is stated in the pipeline code. + +## Getting help +For further information/help, please consult the [nf-core/sarek documentation](https://github.com/nf-core/sarek#documentation) and don't hesitate to get in touch on the pipeline channel on [Slack](https://nf-core-invite.herokuapp.com/). diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000..6df6c5052c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,31 @@ +Hi there! + +Thanks for telling us about a problem with the pipeline. Please delete this text and anything that's not relevant from the template below: + +#### Describe the bug +A clear and concise description of what the bug is. + +#### Steps to reproduce +Steps to reproduce the behaviour: +1. Command line: `nextflow run ...` +2. See error: _Please provide your error message_ + +#### Expected behaviour +A clear and concise description of what you expected to happen. + +#### System: + - Hardware: [e.g. HPC, Desktop, Cloud...] + - Executor: [e.g. slurm, local, awsbatch...] + - OS: [e.g. CentOS Linux, macOS, Linux Mint...] + - Version [e.g. 7, 10.13.6, 18.3...] + +#### Nextflow Installation: + - Version: [e.g. 0.31.0] + +#### Container engine: + - Engine: [e.g. Conda, Docker or Singularity] + - version: [e.g. 1.0.0] + - Image tag: [e.g. nfcore/sarek:1.0.0] + +#### Additional context +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000..1f025b779c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,16 @@ +Hi there! + +Thanks for suggesting a new feature for the pipeline! Please delete this text and anything that's not relevant from the template below: + +#### Is your feature request related to a problem? Please describe. +A clear and concise description of what the problem is. +Ex. I'm always frustrated when [...] + +#### Describe the solution you'd like +A clear and concise description of what you want to happen. + +#### Describe alternatives you've considered +A clear and concise description of any alternative solutions or features you've considered. + +#### Additional context +Add any other context about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..f9fe1f9ffa --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,15 @@ +Many thanks to contributing to nf-core/sarek! + +Please fill in the appropriate checklist below (delete whatever is not relevant). These are the most common things requested on pull requests (PRs). + +## PR checklist + - [ ] This comment contains a description of changes (with reason) + - [ ] If you've fixed a bug or added code that should be tested, add tests! + - [ ] If necessary, also make a PR on the [nf-core/sarek branch on the nf-core/test-datasets repo]( https://github.com/nf-core/test-datasets/pull/new/nf-core/sarek) + - [ ] Ensure the test suite passes (`nextflow run . -profile test,docker`). + - [ ] Make sure your code lints (`nf-core lint .`). + - [ ] Documentation in `docs` is updated + - [ ] `CHANGELOG.md` is updated + - [ ] `README.md` is updated + +**Learn more about contributing:** https://github.com/nf-core/sarek/tree/master/.github/CONTRIBUTING.md diff --git a/.github/markdownlint.yml b/.github/markdownlint.yml new file mode 100644 index 0000000000..e052a635aa --- /dev/null +++ b/.github/markdownlint.yml @@ -0,0 +1,9 @@ +# Markdownlint configuration file +default: true, +line-length: false +no-multiple-blanks: 0 +blanks-around-headers: false +blanks-around-lists: false +header-increment: false +no-duplicate-header: + siblings_only: true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..5b54e3e6c2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.nextflow* +work/ +data/ +results/ +.DS_Store +tests/test_data +*.pyc diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..5477cf5611 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,42 @@ +sudo: required +language: python +jdk: openjdk8 +services: docker +python: '3.6' +cache: pip +matrix: + fast_finish: true + +before_install: + # PRs to master are only ok if coming from dev branch + - '[ $TRAVIS_PULL_REQUEST = "false" ] || [ $TRAVIS_BRANCH != "master" ] || ([ $TRAVIS_PULL_REQUEST_SLUG = $TRAVIS_REPO_SLUG ] && [ $TRAVIS_PULL_REQUEST_BRANCH = "dev" ])' + # Pull the docker image first so the test doesn't wait for this + - docker pull nfcore/sarek:dev + # Fake the tag locally so that the pipeline runs properly + # Looks weird when this is :dev to :dev, but makes sense when testing code for a release (:dev to :1.0.1) + - docker tag nfcore/sarek:dev nfcore/sarek:dev + +install: + # Install Nextflow + - mkdir /tmp/nextflow && cd /tmp/nextflow + - wget -qO- get.nextflow.io | bash + - sudo ln -s /tmp/nextflow/nextflow /usr/local/bin/nextflow + # Install nf-core/tools + - pip install --upgrade pip + - pip install nf-core + # Reset + - mkdir ${TRAVIS_BUILD_DIR}/tests && cd ${TRAVIS_BUILD_DIR}/tests + # Install markdownlint-cli + - sudo apt-get install npm && npm install -g markdownlint-cli + +env: + - NXF_VER='0.32.0' # Specify a minimum NF version that should be tested and work + - NXF_VER='' # Plus: get the latest NF version and check that it works + +script: + # Lint the pipeline code + - nf-core lint ${TRAVIS_BUILD_DIR} + # Lint the documentation + - markdownlint ${TRAVIS_BUILD_DIR} -c ${TRAVIS_BUILD_DIR}/.github/markdownlint.yml + # Run the pipeline with the test profile + - nextflow run ${TRAVIS_BUILD_DIR} -profile test,docker diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000..3a0c68eccd --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,4 @@ +# nf-core/sarek: Changelog + +## v2.5dev - [date] +Initial release of nf-core/sarek, created with the [nf-core](http://nf-co.re/) template. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..09226d0d8d --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team on [Slack](https://nf-core-invite.herokuapp.com/). The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..8cb51fe468 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,7 @@ +FROM nfcore/base +LABEL authors="Maxime Garcia" \ + description="Docker image containing all requirements for nf-core/sarek pipeline" + +COPY environment.yml / +RUN conda env create -f /environment.yml && conda clean -a +ENV PATH /opt/conda/envs/nf-core-sarek-2.5dev/bin:$PATH diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..bceca733b3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Maxime Garcia + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000000..f8efe7afa3 --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +# nf-core/sarek + +**An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing**. + +[![Build Status](https://travis-ci.com/nf-core/sarek.svg?branch=master)](https://travis-ci.com/nf-core/sarek) +[![Nextflow](https://img.shields.io/badge/nextflow-%E2%89%A50.32.0-brightgreen.svg)](https://www.nextflow.io/) + +[![install with bioconda](https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg)](http://bioconda.github.io/) +[![Docker](https://img.shields.io/docker/automated/nfcore/sarek.svg)](https://hub.docker.com/r/nfcore/sarek) + +## Introduction +The pipeline is built using [Nextflow](https://www.nextflow.io), a workflow tool to run tasks across multiple compute infrastructures in a very portable manner. It comes with docker containers making installation trivial and results highly reproducible. + + +## Documentation +The nf-core/sarek pipeline comes with documentation about the pipeline, found in the `docs/` directory: + +1. [Installation](https://nf-co.re/usage/installation) +2. Pipeline configuration + * [Local installation](https://nf-co.re/usage/local_installation) + * [Adding your own system config](https://nf-co.re/usage/adding_own_config) + * [Reference genomes](https://nf-co.re/usage/reference_genomes) +3. [Running the pipeline](docs/usage.md) +4. [Output and how to interpret the results](docs/output.md) +5. [Troubleshooting](https://nf-co.re/usage/troubleshooting) + + + +## Credits +nf-core/sarek was originally written by Maxime Garcia. diff --git a/assets/email_template.html b/assets/email_template.html new file mode 100644 index 0000000000..20a5dd5da4 --- /dev/null +++ b/assets/email_template.html @@ -0,0 +1,52 @@ + + + + + + + + + nf-core/sarek Pipeline Report + + +
+ +

nf-core/sarek v${version}

+

Run Name: $runName

+ +<% if (!success){ + out << """ +
+

nf-core/sarek execution completed unsuccessfully!

+

The exit status of the task that caused the workflow execution to fail was: $exitStatus.

+

The full error message was:

+
${errorReport}
+
+ """ +} else { + out << """ +
+ nf-core/sarek execution completed successfully! +
+ """ +} +%> + +

The workflow was completed at $dateComplete (duration: $duration)

+

The command used to launch the workflow was as follows:

+
$commandLine
+ +

Pipeline Configuration:

+ + + <% out << summary.collect{ k,v -> "" }.join("\n") %> + +
$k
$v
+ +

nf-core/sarek

+

https://github.com/nf-core/sarek

+ +
+ + + diff --git a/assets/email_template.txt b/assets/email_template.txt new file mode 100644 index 0000000000..76e9ae7e57 --- /dev/null +++ b/assets/email_template.txt @@ -0,0 +1,34 @@ +======================================== + nf-core/sarek v${version} +======================================== +Run Name: $runName + +<% if (success){ + out << "## nf-core/sarek execution completed successfully! ##" +} else { + out << """#################################################### +## nf-core/sarek execution completed unsuccessfully! ## +#################################################### +The exit status of the task that caused the workflow execution to fail was: $exitStatus. +The full error message was: + +${errorReport} +""" +} %> + + +The workflow was completed at $dateComplete (duration: $duration) + +The command used to launch the workflow was as follows: + + $commandLine + + + +Pipeline Configuration: +----------------------- +<% out << summary.collect{ k,v -> " - $k: $v" }.join("\n") %> + +-- +nf-core/sarek +https://github.com/nf-core/sarek diff --git a/assets/multiqc_config.yaml b/assets/multiqc_config.yaml new file mode 100644 index 0000000000..fe8d008cb4 --- /dev/null +++ b/assets/multiqc_config.yaml @@ -0,0 +1,9 @@ +report_comment: > + This report has been generated by the nf-core/sarek + analysis pipeline. For information about how to interpret these results, please see the + documentation. +report_section_order: + nf-core/sarek-software-versions: + order: -1000 + +export_plots: true diff --git a/assets/sendmail_template.txt b/assets/sendmail_template.txt new file mode 100644 index 0000000000..2d67122006 --- /dev/null +++ b/assets/sendmail_template.txt @@ -0,0 +1,36 @@ +To: $email +Subject: $subject +Mime-Version: 1.0 +Content-Type: multipart/related;boundary="nfcoremimeboundary" + +--nfcoremimeboundary +Content-Type: text/html; charset=utf-8 + +$email_html + +<% +if (mqcFile){ +def mqcFileObj = new File("$mqcFile") +if (mqcFileObj.length() < mqcMaxSize){ +out << """ +--nfcoremimeboundary +Content-Type: text/html; name=\"multiqc_report\" +Content-Transfer-Encoding: base64 +Content-ID: +Content-Disposition: attachment; filename=\"${mqcFileObj.getName()}\" + +${mqcFileObj. + bytes. + encodeBase64(). + toString(). + tokenize( '\n' )*. + toList()*. + collate( 76 )*. + collect { it.join() }. + flatten(). + join( '\n' )} +""" +}} +%> + +--nfcoremimeboundary-- diff --git a/bin/markdown_to_html.r b/bin/markdown_to_html.r new file mode 100755 index 0000000000..abe1335070 --- /dev/null +++ b/bin/markdown_to_html.r @@ -0,0 +1,51 @@ +#!/usr/bin/env Rscript + +# Command line argument processing +args = commandArgs(trailingOnly=TRUE) +if (length(args) < 2) { + stop("Usage: markdown_to_html.r ", call.=FALSE) +} +markdown_fn <- args[1] +output_fn <- args[2] + +# Load / install packages +if (!require("markdown")) { + install.packages("markdown", dependencies=TRUE, repos='http://cloud.r-project.org/') + library("markdown") +} + +base_css_fn <- getOption("markdown.HTML.stylesheet") +base_css <- readChar(base_css_fn, file.info(base_css_fn)$size) +custom_css <- paste(base_css, " +body { + padding: 3em; + margin-right: 350px; + max-width: 100%; +} +#toc { + position: fixed; + right: 20px; + width: 300px; + padding-top: 20px; + overflow: scroll; + height: calc(100% - 3em - 20px); +} +#toc_header { + font-size: 1.8em; + font-weight: bold; +} +#toc > ul { + padding-left: 0; + list-style-type: none; +} +#toc > ul ul { padding-left: 20px; } +#toc > ul > li > a { display: none; } +img { max-width: 800px; } +") + +markdownToHTML( + file = markdown_fn, + output = output_fn, + stylesheet = custom_css, + options = c('toc', 'base64_images', 'highlight_code') +) diff --git a/bin/scrape_software_versions.py b/bin/scrape_software_versions.py new file mode 100755 index 0000000000..0cb269ad8c --- /dev/null +++ b/bin/scrape_software_versions.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +from __future__ import print_function +from collections import OrderedDict +import re + +# TODO nf-core: Add additional regexes for new tools in process get_software_versions +regexes = { + 'nf-core/sarek': ['v_pipeline.txt', r"(\S+)"], + 'Nextflow': ['v_nextflow.txt', r"(\S+)"], + 'FastQC': ['v_fastqc.txt', r"FastQC v(\S+)"], + 'MultiQC': ['v_multiqc.txt', r"multiqc, version (\S+)"], +} +results = OrderedDict() +results['nf-core/sarek'] = 'N/A' +results['Nextflow'] = 'N/A' +results['FastQC'] = 'N/A' +results['MultiQC'] = 'N/A' + +# Search each file using its regex +for k, v in regexes.items(): + with open(v[0]) as x: + versions = x.read() + match = re.search(v[1], versions) + if match: + results[k] = "v{}".format(match.group(1)) + +# Remove software set to false in results +for k in results: + if not results[k]: + del(results[k]) + +# Dump to YAML +print (''' +id: 'software_versions' +section_name: 'nf-core/sarek Software Versions' +section_href: 'https://github.com/nf-core/sarek' +plot_type: 'html' +description: 'are collected at run time from the software output.' +data: | +
+''') +for k,v in results.items(): + print("
{}
{}
".format(k,v)) +print ("
") + +# Write out regexes as csv file: +with open('software_versions.csv', 'w') as f: + for k,v in results.items(): + f.write("{}\t{}\n".format(k,v)) diff --git a/conf/awsbatch.config b/conf/awsbatch.config new file mode 100644 index 0000000000..14af5866f5 --- /dev/null +++ b/conf/awsbatch.config @@ -0,0 +1,18 @@ +/* + * ------------------------------------------------- + * Nextflow config file for running on AWS batch + * ------------------------------------------------- + * Base config needed for running with -profile awsbatch + */ +params { + config_profile_name = 'AWSBATCH' + config_profile_description = 'AWSBATCH Cloud Profile' + config_profile_contact = 'Alexander Peltzer (@apeltzer)' + config_profile_url = 'https://aws.amazon.com/de/batch/' +} + +aws.region = params.awsregion +process.executor = 'awsbatch' +process.queue = params.awsqueue +executor.awscli = '/home/ec2-user/miniconda/bin/aws' +params.tracedir = './' diff --git a/conf/base.config b/conf/base.config new file mode 100644 index 0000000000..bb54f1e010 --- /dev/null +++ b/conf/base.config @@ -0,0 +1,34 @@ +/* + * ------------------------------------------------- + * nf-core/sarek Nextflow base config file + * ------------------------------------------------- + * A 'blank slate' config file, appropriate for general + * use on most high performace compute environments. + * Assumes that all software is installed and available + * on the PATH. Runs in `local` mode - all jobs will be + * run on the logged in environment. + */ + +process { + + // TODO nf-core: Check the defaults for all processes + cpus = { check_max( 1 * task.attempt, 'cpus' ) } + memory = { check_max( 8.GB * task.attempt, 'memory' ) } + time = { check_max( 2.h * task.attempt, 'time' ) } + + errorStrategy = { task.exitStatus in [143,137,104,134,139] ? 'retry' : 'finish' } + maxRetries = 1 + maxErrors = '-1' + + // Process-specific resource requirements + // TODO nf-core: Customise requirements for specific processes. + // See https://www.nextflow.io/docs/latest/config.html#config-process-selectors +} + +params { + // Defaults only, expecting to be overwritten + max_memory = 128.GB + max_cpus = 16 + max_time = 240.h + igenomes_base = 's3://ngi-igenomes/igenomes/' +} diff --git a/conf/igenomes.config b/conf/igenomes.config new file mode 100644 index 0000000000..d19e61f4b1 --- /dev/null +++ b/conf/igenomes.config @@ -0,0 +1,147 @@ +/* + * ------------------------------------------------- + * Nextflow config file for iGenomes paths + * ------------------------------------------------- + * Defines reference genomes, using iGenome paths + * Can be used by any config that customises the base + * path using $params.igenomes_base / --igenomes_base + */ + +params { + // illumina iGenomes reference file paths + // TODO nf-core: Add new reference types and strip out those that are not needed + genomes { + 'GRCh37' { + bed12 = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/STARIndex/" + } + 'GRCm38' { + bed12 = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/STARIndex/" + } + 'TAIR10' { + bed12 = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/STARIndex/" + } + 'EB2' { + bed12 = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/STARIndex/" + } + 'UMD3.1' { + bed12 = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/STARIndex/" + } + 'WBcel235' { + bed12 = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/STARIndex/" + } + 'CanFam3.1' { + bed12 = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/STARIndex/" + } + 'GRCz10' { + bed12 = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/STARIndex/" + } + 'BDGP6' { + bed12 = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/STARIndex/" + } + 'EquCab2' { + bed12 = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/STARIndex/" + } + 'EB1' { + bed12 = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/STARIndex/" + } + 'Galgal4' { + bed12 = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/STARIndex/" + } + 'Gm01' { + bed12 = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/STARIndex/" + } + 'Mmul_1' { + bed12 = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/STARIndex/" + } + 'IRGSP-1.0' { + bed12 = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/STARIndex/" + } + 'CHIMP2.1.4' { + bed12 = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/STARIndex/" + } + 'Rnor_6.0' { + bed12 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/STARIndex/" + } + 'R64-1-1' { + bed12 = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/STARIndex/" + } + 'EF2' { + bed12 = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/STARIndex/" + } + 'Sbi1' { + bed12 = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/STARIndex/" + } + 'Sscrofa10.2' { + bed12 = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/STARIndex/" + } + 'AGPv3' { + bed12 = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Annotation/Genes/genes.bed" + fasta = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/WholeGenomeFasta/genome.fa" + gtf = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Annotation/Genes/genes.gtf" + star = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/STARIndex/" + } + } +} diff --git a/conf/test.config b/conf/test.config new file mode 100644 index 0000000000..84e483eb2a --- /dev/null +++ b/conf/test.config @@ -0,0 +1,25 @@ +/* + * ------------------------------------------------- + * Nextflow config file for running tests + * ------------------------------------------------- + * Defines bundled input files and everything required + * to run a fast and simple test. Use as follows: + * nextflow run nf-core/sarek -profile test + */ + +params { + config_profile_name = 'Test profile' + config_profile_description = 'Minimal test dataset to check pipeline function' + // Limit resources so that this can run on Travis + max_cpus = 2 + max_memory = 6.GB + max_time = 48.h + // Input data + // TODO nf-core: Specify the paths to your test data on nf-core/test-datasets + // TODO nf-core: Give any required params for the test so that command line flags are not needed + singleEnd = false + readPaths = [ + ['Testdata', ['https://github.com/nf-core/test-datasets/raw/exoseq/testdata/Testdata_R1.tiny.fastq.gz', 'https://github.com/nf-core/test-datasets/raw/exoseq/testdata/Testdata_R2.tiny.fastq.gz']], + ['SRR389222', ['https://github.com/nf-core/test-datasets/raw/methylseq/testdata/SRR389222_sub1.fastq.gz', 'https://github.com/nf-core/test-datasets/raw/methylseq/testdata/SRR389222_sub2.fastq.gz']] + ] +} diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..ca3fe27a91 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,12 @@ +# nf-core/sarek: Documentation + +The nf-core/sarek documentation is split into the following files: + +1. [Installation](https://nf-co.re/usage/installation) +2. Pipeline configuration + * [Local installation](https://nf-co.re/usage/local_installation) + * [Adding your own system config](https://nf-co.re/usage/adding_own_config) + * [Reference genomes](https://nf-co.re/usage/reference_genomes) +3. [Running the pipeline](usage.md) +4. [Output and how to interpret the results](output.md) +5. [Troubleshooting](https://nf-co.re/usage/troubleshooting) diff --git a/docs/output.md b/docs/output.md new file mode 100644 index 0000000000..65b4509093 --- /dev/null +++ b/docs/output.md @@ -0,0 +1,41 @@ +# nf-core/sarek: Output + +This document describes the output produced by the pipeline. Most of the plots are taken from the MultiQC report, which summarises results at the end of the pipeline. + + + +## Pipeline overview +The pipeline is built using [Nextflow](https://www.nextflow.io/) +and processes data using the following steps: + +* [FastQC](#fastqc) - read quality control +* [MultiQC](#multiqc) - aggregate report, describing results of the whole pipeline + +## FastQC +[FastQC](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/) gives general quality metrics about your reads. It provides information about the quality score distribution across your reads, the per base sequence content (%T/A/G/C). You get information about adapter contamination and other overrepresented sequences. + +For further reading and documentation see the [FastQC help](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/). + +> **NB:** The FastQC plots displayed in the MultiQC report shows _untrimmed_ reads. They may contain adapter sequence and potentially regions with low quality. To see how your reads look after trimming, look at the FastQC reports in the `trim_galore` directory. + +**Output directory: `results/fastqc`** + +* `sample_fastqc.html` + * FastQC report, containing quality metrics for your untrimmed raw fastq files +* `zips/sample_fastqc.zip` + * zip file containing the FastQC report, tab-delimited data file and plot images + + +## MultiQC +[MultiQC](http://multiqc.info) is a visualisation tool that generates a single HTML report summarising all samples in your project. Most of the pipeline QC results are visualised in the report and further statistics are available in within the report data directory. + +The pipeline has special steps which allow the software versions used to be reported in the MultiQC output for future traceability. + +**Output directory: `results/multiqc`** + +* `Project_multiqc_report.html` + * MultiQC report - a standalone HTML file that can be viewed in your web browser +* `Project_multiqc_data/` + * Directory containing parsed statistics from the different tools used in the pipeline + +For more information about how to use MultiQC reports, see [http://multiqc.info](http://multiqc.info) diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 0000000000..ee1162992a --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,282 @@ +# nf-core/sarek: Usage + +## Table of contents + + + +* [Table of contents](#table-of-contents) +* [Introduction](#introduction) +* [Running the pipeline](#running-the-pipeline) + * [Updating the pipeline](#updating-the-pipeline) + * [Reproducibility](#reproducibility) +* [Main arguments](#main-arguments) + * [`-profile`](#-profile) + * [`--reads`](#--reads) + * [`--singleEnd`](#--singleend) +* [Reference genomes](#reference-genomes) + * [`--genome` (using iGenomes)](#--genome-using-igenomes) + * [`--fasta`](#--fasta) + * [`--igenomesIgnore`](#--igenomesignore) +* [Job resources](#job-resources) + * [Automatic resubmission](#automatic-resubmission) + * [Custom resource requests](#custom-resource-requests) +* [AWS Batch specific parameters](#aws-batch-specific-parameters) + * [`--awsqueue`](#--awsqueue) + * [`--awsregion`](#--awsregion) +* [Other command line parameters](#other-command-line-parameters) + * [`--outdir`](#--outdir) + * [`--email`](#--email) + * [`-name`](#-name) + * [`-resume`](#-resume) + * [`-c`](#-c) + * [`--custom_config_version`](#--custom_config_version) + * [`--custom_config_base`](#--custom_config_base) + * [`--max_memory`](#--max_memory) + * [`--max_time`](#--max_time) + * [`--max_cpus`](#--max_cpus) + * [`--plaintext_email`](#--plaintext_email) + * [`--monochrome_logs`](#--monochrome_logs) + * [`--multiqc_config`](#--multiqc_config) + + + +## Introduction +Nextflow handles job submissions on SLURM or other environments, and supervises running the jobs. Thus the Nextflow process must run until the pipeline is finished. We recommend that you put the process running in the background through `screen` / `tmux` or similar tool. Alternatively you can run nextflow within a cluster job submitted your job scheduler. + +It is recommended to limit the Nextflow Java virtual machines memory. We recommend adding the following line to your environment (typically in `~/.bashrc` or `~./bash_profile`): + +```bash +NXF_OPTS='-Xms1g -Xmx4g' +``` + + + +## Running the pipeline +The typical command for running the pipeline is as follows: + +```bash +nextflow run nf-core/sarek --reads '*_R{1,2}.fastq.gz' -profile docker +``` + +This will launch the pipeline with the `docker` configuration profile. See below for more information about profiles. + +Note that the pipeline will create the following files in your working directory: + +```bash +work # Directory containing the nextflow working files +results # Finished results (configurable, see below) +.nextflow_log # Log file from Nextflow +# Other nextflow hidden files, eg. history of pipeline runs and old logs. +``` + +### Updating the pipeline +When you run the above command, Nextflow automatically pulls the pipeline code from GitHub and stores it as a cached version. When running the pipeline after this, it will always use the cached version if available - even if the pipeline has been updated since. To make sure that you're running the latest version of the pipeline, make sure that you regularly update the cached version of the pipeline: + +```bash +nextflow pull nf-core/sarek +``` + +### Reproducibility +It's a good idea to specify a pipeline version when running the pipeline on your data. This ensures that a specific version of the pipeline code and software are used when you run your pipeline. If you keep using the same tag, you'll be running the same version of the pipeline, even if there have been changes to the code since. + +First, go to the [nf-core/sarek releases page](https://github.com/nf-core/sarek/releases) and find the latest version number - numeric only (eg. `1.3.1`). Then specify this when running the pipeline with `-r` (one hyphen) - eg. `-r 1.3.1`. + +This version number will be logged in reports when you run the pipeline, so that you'll know what you used when you look back in the future. + + +## Main arguments + +### `-profile` +Use this parameter to choose a configuration profile. Profiles can give configuration presets for different compute environments. Note that multiple profiles can be loaded, for example: `-profile docker` - the order of arguments is important! + +If `-profile` is not specified at all the pipeline will be run locally and expects all software to be installed and available on the `PATH`. + +* `awsbatch` + * A generic configuration profile to be used with AWS Batch. +* `conda` + * A generic configuration profile to be used with [conda](https://conda.io/docs/) + * Pulls most software from [Bioconda](https://bioconda.github.io/) +* `docker` + * A generic configuration profile to be used with [Docker](http://docker.com/) + * Pulls software from dockerhub: [`nfcore/sarek`](http://hub.docker.com/r/nfcore/sarek/) +* `singularity` + * A generic configuration profile to be used with [Singularity](http://singularity.lbl.gov/) + * Pulls software from DockerHub: [`nfcore/sarek`](http://hub.docker.com/r/nfcore/sarek/) +* `test` + * A profile with a complete configuration for automated testing + * Includes links to test data so needs no other parameters + + + +### `--reads` +Use this to specify the location of your input FastQ files. For example: + +```bash +--reads 'path/to/data/sample_*_{1,2}.fastq' +``` + +Please note the following requirements: + +1. The path must be enclosed in quotes +2. The path must have at least one `*` wildcard character +3. When using the pipeline with paired end data, the path must use `{1,2}` notation to specify read pairs. + +If left unspecified, a default pattern is used: `data/*{1,2}.fastq.gz` + +### `--singleEnd` +By default, the pipeline expects paired-end data. If you have single-end data, you need to specify `--singleEnd` on the command line when you launch the pipeline. A normal glob pattern, enclosed in quotation marks, can then be used for `--reads`. For example: + +```bash +--singleEnd --reads '*.fastq' +``` + +It is not possible to run a mixture of single-end and paired-end files in one run. + + +## Reference genomes + +The pipeline config files come bundled with paths to the illumina iGenomes reference index files. If running with docker or AWS, the configuration is set up to use the [AWS-iGenomes](https://ewels.github.io/AWS-iGenomes/) resource. + +### `--genome` (using iGenomes) +There are 31 different species supported in the iGenomes references. To run the pipeline, you must specify which to use with the `--genome` flag. + +You can find the keys to specify the genomes in the [iGenomes config file](../conf/igenomes.config). Common genomes that are supported are: + +* Human + * `--genome GRCh37` +* Mouse + * `--genome GRCm38` +* _Drosophila_ + * `--genome BDGP6` +* _S. cerevisiae_ + * `--genome 'R64-1-1'` + +> There are numerous others - check the config file for more. + +Note that you can use the same configuration setup to save sets of reference files for your own use, even if they are not part of the iGenomes resource. See the [Nextflow documentation](https://www.nextflow.io/docs/latest/config.html) for instructions on where to save such a file. + +The syntax for this reference configuration is as follows: + + + +```nextflow +params { + genomes { + 'GRCh37' { + fasta = '' // Used if no star index given + } + // Any number of additional genomes, key is used with --genome + } +} +``` + + +### `--fasta` +If you prefer, you can specify the full path to your reference genome when you run the pipeline: + +```bash +--fasta '[path to Fasta reference]' +``` + +### `--igenomesIgnore` +Do not load `igenomes.config` when running the pipeline. You may choose this option if you observe clashes between custom parameters and those supplied in `igenomes.config`. + +## Job resources +### Automatic resubmission +Each step in the pipeline has a default set of requirements for number of CPUs, memory and time. For most of the steps in the pipeline, if the job exits with an error code of `143` (exceeded requested resources) it will automatically resubmit with higher requests (2 x original, then 3 x original). If it still fails after three times then the pipeline is stopped. + +### Custom resource requests +Wherever process-specific requirements are set in the pipeline, the default value can be changed by creating a custom config file. See the files hosted at [`nf-core/configs`](https://github.com/nf-core/configs/tree/master/conf) for examples. + +If you are likely to be running `nf-core` pipelines regularly it may be a good idea to request that your custom config file is uploaded to the `nf-core/configs` git repository. Before you do this please can you test that the config file works with your pipeline of choice using the `-c` parameter (see definition below). You can then create a pull request to the `nf-core/configs` repository with the addition of your config file, associated documentation file (see examples in [`nf-core/configs/docs`](https://github.com/nf-core/configs/tree/master/docs)), and amending [`nfcore_custom.config`](https://github.com/nf-core/configs/blob/master/nfcore_custom.config) to include your custom profile. + +If you have any questions or issues please send us a message on [Slack](https://nf-core-invite.herokuapp.com/). + +## AWS Batch specific parameters +Running the pipeline on AWS Batch requires a couple of specific parameters to be set according to your AWS Batch configuration. Please use the `-awsbatch` profile and then specify all of the following parameters. +### `--awsqueue` +The JobQueue that you intend to use on AWS Batch. +### `--awsregion` +The AWS region to run your job in. Default is set to `eu-west-1` but can be adjusted to your needs. + +Please make sure to also set the `-w/--work-dir` and `--outdir` parameters to a S3 storage bucket of your choice - you'll get an error message notifying you if you didn't. + +## Other command line parameters + + + +### `--outdir` +The output directory where the results will be saved. + +### `--email` +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. + +### `-name` +Name for the pipeline run. If not specified, Nextflow will automatically generate a random mnemonic. + +This is used in the MultiQC report (if not default) and in the summary HTML / e-mail (always). + +**NB:** Single hyphen (core Nextflow option) + +### `-resume` +Specify this when restarting a pipeline. Nextflow will used cached results from any pipeline steps where the inputs are the same, continuing from where it got to previously. + +You can also supply a run name to resume a specific run: `-resume [run-name]`. Use the `nextflow log` command to show previous run names. + +**NB:** Single hyphen (core Nextflow option) + +### `-c` +Specify the path to a specific config file (this is a core NextFlow command). + +**NB:** Single hyphen (core Nextflow option) + +Note - you can use this to override pipeline defaults. + +### `--custom_config_version` +Provide git commit id for custom Institutional configs hosted at `nf-core/configs`. This was implemented for reproducibility purposes. Default is set to `master`. + +```bash +## Download and use config file with following git commid id +--custom_config_version d52db660777c4bf36546ddb188ec530c3ada1b96 +``` + +### `--custom_config_base` +If you're running offline, nextflow will not be able to fetch the institutional config files +from the internet. If you don't need them, then this is not a problem. If you do need them, +you should download the files from the repo and tell nextflow where to find them with the +`custom_config_base` option. For example: + +```bash +## Download and unzip the config files +cd /path/to/my/configs +wget https://github.com/nf-core/configs/archive/master.zip +unzip master.zip + +## Run the pipeline +cd /path/to/my/data +nextflow run /path/to/pipeline/ --custom_config_base /path/to/my/configs/configs-master/ +``` + +> Note that the nf-core/tools helper package has a `download` command to download all required pipeline +> files + singularity containers + institutional configs in one go for you, to make this process easier. + +### `--max_memory` +Use to set a top-limit for the default memory requirement for each process. +Should be a string in the format integer-unit. eg. `--max_memory '8.GB'` + +### `--max_time` +Use to set a top-limit for the default time requirement for each process. +Should be a string in the format integer-unit. eg. `--max_time '2.h'` + +### `--max_cpus` +Use to set a top-limit for the default CPU requirement for each process. +Should be a string in the format integer-unit. eg. `--max_cpus 1` + +### `--plaintext_email` +Set to receive plain-text e-mails instead of HTML formatted. + +### `--monochrome_logs` +Set to disable colourful command line output and live life in monochrome. + +### `--multiqc_config` +Specify a path to a custom MultiQC configuration file. diff --git a/environment.yml b/environment.yml new file mode 100644 index 0000000000..4e6811ec55 --- /dev/null +++ b/environment.yml @@ -0,0 +1,11 @@ +# You can use this file to create a conda environment for this pipeline: +# conda env create -f environment.yml +name: nf-core-sarek-2.5dev +channels: + - conda-forge + - bioconda + - defaults +dependencies: + # TODO nf-core: Add required software dependencies here + - fastqc=0.11.8 + - multiqc=1.7 diff --git a/main.nf b/main.nf new file mode 100644 index 0000000000..42567aca5c --- /dev/null +++ b/main.nf @@ -0,0 +1,428 @@ +#!/usr/bin/env nextflow +/* +======================================================================================== + nf-core/sarek +======================================================================================== + nf-core/sarek Analysis Pipeline. + #### Homepage / Documentation + https://github.com/nf-core/sarek +---------------------------------------------------------------------------------------- +*/ + + +def helpMessage() { + // TODO nf-core: Add to this help message with new command line parameters + log.info nfcoreHeader() + log.info""" + + Usage: + + The typical command for running the pipeline is as follows: + + nextflow run nf-core/sarek --reads '*_R{1,2}.fastq.gz' -profile docker + + Mandatory arguments: + --reads Path to input data (must be surrounded with quotes) + -profile Configuration profile to use. Can use multiple (comma separated) + Available: conda, docker, singularity, awsbatch, test and more. + + Options: + --genome Name of iGenomes reference + --singleEnd Specifies that the input is single end reads + + References If not specified in the configuration file or you wish to overwrite any of the references. + --fasta Path to Fasta reference + + Other options: + --outdir The output directory where the results will be saved + --email 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 + --maxMultiqcEmailFileSize Theshold size for MultiQC report to be attached in notification email. If file generated by pipeline exceeds the threshold, it will not be attached (Default: 25MB) + -name Name for the pipeline run. If not specified, Nextflow will automatically generate a random mnemonic. + + AWSBatch options: + --awsqueue The AWSBatch JobQueue that needs to be set when running on AWSBatch + --awsregion The AWS Region for your AWS Batch job to run on + """.stripIndent() +} + +/* + * SET UP CONFIGURATION VARIABLES + */ + +// Show help emssage +if (params.help){ + helpMessage() + exit 0 +} + +// Check if genome exists in the config file +if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { + exit 1, "The provided genome '${params.genome}' is not available in the iGenomes file. Currently the available genomes are ${params.genomes.keySet().join(", ")}" +} + +// TODO nf-core: Add any reference files that are needed +// Configurable reference genomes +fasta = params.genome ? params.genomes[ params.genome ].fasta ?: false : false +if ( params.fasta ){ + fasta = file(params.fasta) + if( !fasta.exists() ) exit 1, "Fasta file not found: ${params.fasta}" +} +// +// NOTE - THIS IS NOT USED IN THIS PIPELINE, EXAMPLE ONLY +// If you want to use the above in a process, define the following: +// input: +// file fasta from fasta +// + + +// Has the run name been specified by the user? +// this has the bonus effect of catching both -name and --name +custom_runName = params.name +if( !(workflow.runName ==~ /[a-z]+_[a-z]+/) ){ + custom_runName = workflow.runName +} + + +if( workflow.profile == 'awsbatch') { + // AWSBatch sanity checking + if (!params.awsqueue || !params.awsregion) exit 1, "Specify correct --awsqueue and --awsregion parameters on AWSBatch!" + // Check outdir paths to be S3 buckets if running on AWSBatch + // related: https://github.com/nextflow-io/nextflow/issues/813 + if (!params.outdir.startsWith('s3:')) exit 1, "Outdir not on S3 - specify S3 Bucket to run on AWSBatch!" + // Prevent trace files to be stored on S3 since S3 does not support rolling files. + if (workflow.tracedir.startsWith('s3:')) exit 1, "Specify a local tracedir or run without trace! S3 cannot be used for tracefiles." +} + +// Stage config files +ch_multiqc_config = Channel.fromPath(params.multiqc_config) +ch_output_docs = Channel.fromPath("$baseDir/docs/output.md") + +/* + * Create a channel for input read files + */ +if(params.readPaths){ + if(params.singleEnd){ + Channel + .from(params.readPaths) + .map { row -> [ row[0], [file(row[1][0])]] } + .ifEmpty { exit 1, "params.readPaths was empty - no input files supplied" } + .into { read_files_fastqc; read_files_trimming } + } else { + Channel + .from(params.readPaths) + .map { row -> [ row[0], [file(row[1][0]), file(row[1][1])]] } + .ifEmpty { exit 1, "params.readPaths was empty - no input files supplied" } + .into { read_files_fastqc; read_files_trimming } + } +} else { + Channel + .fromFilePairs( params.reads, size: params.singleEnd ? 1 : 2 ) + .ifEmpty { exit 1, "Cannot find any reads matching: ${params.reads}\nNB: Path needs to be enclosed in quotes!\nIf this is single-end data, please specify --singleEnd on the command line." } + .into { read_files_fastqc; read_files_trimming } +} + + +// Header log info +log.info nfcoreHeader() +def summary = [:] +if(workflow.revision) summary['Pipeline Release'] = workflow.revision +summary['Run Name'] = custom_runName ?: workflow.runName +// TODO nf-core: Report custom parameters here +summary['Reads'] = params.reads +summary['Fasta Ref'] = params.fasta +summary['Data Type'] = params.singleEnd ? 'Single-End' : 'Paired-End' +summary['Max Resources'] = "$params.max_memory memory, $params.max_cpus cpus, $params.max_time time per job" +if(workflow.containerEngine) summary['Container'] = "$workflow.containerEngine - $workflow.container" +summary['Output dir'] = params.outdir +summary['Launch dir'] = workflow.launchDir +summary['Working dir'] = workflow.workDir +summary['Script dir'] = workflow.projectDir +summary['User'] = workflow.userName +if(workflow.profile == 'awsbatch'){ + summary['AWS Region'] = params.awsregion + summary['AWS Queue'] = params.awsqueue +} +summary['Config Profile'] = workflow.profile +if(params.config_profile_description) summary['Config Description'] = params.config_profile_description +if(params.config_profile_contact) summary['Config Contact'] = params.config_profile_contact +if(params.config_profile_url) summary['Config URL'] = params.config_profile_url +if(params.email) { + summary['E-mail Address'] = params.email + summary['MultiQC maxsize'] = params.maxMultiqcEmailFileSize +} +log.info summary.collect { k,v -> "${k.padRight(18)}: $v" }.join("\n") +log.info "\033[2m----------------------------------------------------\033[0m" + +// Check the hostnames against configured profiles +checkHostname() + +def create_workflow_summary(summary) { + def yaml_file = workDir.resolve('workflow_summary_mqc.yaml') + yaml_file.text = """ + id: 'nf-core-sarek-summary' + description: " - this information is collected when the pipeline is started." + section_name: 'nf-core/sarek Workflow Summary' + section_href: 'https://github.com/nf-core/sarek' + plot_type: 'html' + data: | +
+${summary.collect { k,v -> "
$k
${v ?: 'N/A'}
" }.join("\n")} +
+ """.stripIndent() + + return yaml_file +} + + +/* + * Parse software version numbers + */ +process get_software_versions { + publishDir "${params.outdir}/pipeline_info", mode: 'copy', + saveAs: {filename -> + if (filename.indexOf(".csv") > 0) filename + else null + } + + output: + file 'software_versions_mqc.yaml' into software_versions_yaml + file "software_versions.csv" + + script: + // TODO nf-core: Get all tools to print their version number here + """ + echo $workflow.manifest.version > v_pipeline.txt + echo $workflow.nextflow.version > v_nextflow.txt + fastqc --version > v_fastqc.txt + multiqc --version > v_multiqc.txt + scrape_software_versions.py &> software_versions_mqc.yaml + """ +} + + + +/* + * STEP 1 - FastQC + */ +process fastqc { + tag "$name" + publishDir "${params.outdir}/fastqc", mode: 'copy', + saveAs: {filename -> filename.indexOf(".zip") > 0 ? "zips/$filename" : "$filename"} + + input: + set val(name), file(reads) from read_files_fastqc + + output: + file "*_fastqc.{zip,html}" into fastqc_results + + script: + """ + fastqc -q $reads + """ +} + + + +/* + * STEP 2 - MultiQC + */ +process multiqc { + publishDir "${params.outdir}/MultiQC", mode: 'copy' + + input: + file multiqc_config from ch_multiqc_config + // TODO nf-core: Add in log files from your new processes for MultiQC to find! + file ('fastqc/*') from fastqc_results.collect().ifEmpty([]) + file ('software_versions/*') from software_versions_yaml.collect() + file workflow_summary from create_workflow_summary(summary) + + output: + file "*multiqc_report.html" into multiqc_report + file "*_data" + file "multiqc_plots" + + script: + rtitle = custom_runName ? "--title \"$custom_runName\"" : '' + rfilename = custom_runName ? "--filename " + custom_runName.replaceAll('\\W','_').replaceAll('_+','_') + "_multiqc_report" : '' + // TODO nf-core: Specify which MultiQC modules to use with -m for a faster run time + """ + multiqc -f $rtitle $rfilename --config $multiqc_config . + """ +} + + + +/* + * STEP 3 - Output Description HTML + */ +process output_documentation { + publishDir "${params.outdir}/pipeline_info", mode: 'copy' + + input: + file output_docs from ch_output_docs + + output: + file "results_description.html" + + script: + """ + markdown_to_html.r $output_docs results_description.html + """ +} + + + +/* + * Completion e-mail notification + */ +workflow.onComplete { + + // Set up the e-mail variables + def subject = "[nf-core/sarek] Successful: $workflow.runName" + if(!workflow.success){ + subject = "[nf-core/sarek] FAILED: $workflow.runName" + } + def email_fields = [:] + email_fields['version'] = workflow.manifest.version + email_fields['runName'] = custom_runName ?: workflow.runName + email_fields['success'] = workflow.success + email_fields['dateComplete'] = workflow.complete + email_fields['duration'] = workflow.duration + email_fields['exitStatus'] = workflow.exitStatus + email_fields['errorMessage'] = (workflow.errorMessage ?: 'None') + email_fields['errorReport'] = (workflow.errorReport ?: 'None') + email_fields['commandLine'] = workflow.commandLine + email_fields['projectDir'] = workflow.projectDir + email_fields['summary'] = summary + email_fields['summary']['Date Started'] = workflow.start + email_fields['summary']['Date Completed'] = workflow.complete + email_fields['summary']['Pipeline script file path'] = workflow.scriptFile + email_fields['summary']['Pipeline script hash ID'] = workflow.scriptId + if(workflow.repository) email_fields['summary']['Pipeline repository Git URL'] = workflow.repository + if(workflow.commitId) email_fields['summary']['Pipeline repository Git Commit'] = workflow.commitId + if(workflow.revision) email_fields['summary']['Pipeline Git branch/tag'] = workflow.revision + if(workflow.container) email_fields['summary']['Docker image'] = workflow.container + email_fields['summary']['Nextflow Version'] = workflow.nextflow.version + email_fields['summary']['Nextflow Build'] = workflow.nextflow.build + email_fields['summary']['Nextflow Compile Timestamp'] = workflow.nextflow.timestamp + + // TODO nf-core: If not using MultiQC, strip out this code (including params.maxMultiqcEmailFileSize) + // On success try attach the multiqc report + def mqc_report = null + try { + if (workflow.success) { + mqc_report = multiqc_report.getVal() + if (mqc_report.getClass() == ArrayList){ + log.warn "[nf-core/sarek] Found multiple reports from process 'multiqc', will use only one" + mqc_report = mqc_report[0] + } + } + } catch (all) { + log.warn "[nf-core/sarek] Could not attach MultiQC report to summary email" + } + + // Render the TXT template + def engine = new groovy.text.GStringTemplateEngine() + def tf = new File("$baseDir/assets/email_template.txt") + def txt_template = engine.createTemplate(tf).make(email_fields) + def email_txt = txt_template.toString() + + // Render the HTML template + def hf = new File("$baseDir/assets/email_template.html") + def html_template = engine.createTemplate(hf).make(email_fields) + def email_html = html_template.toString() + + // Render the sendmail template + def smail_fields = [ email: params.email, subject: subject, email_txt: email_txt, email_html: email_html, baseDir: "$baseDir", mqcFile: mqc_report, mqcMaxSize: params.maxMultiqcEmailFileSize.toBytes() ] + def sf = new File("$baseDir/assets/sendmail_template.txt") + def sendmail_template = engine.createTemplate(sf).make(smail_fields) + def sendmail_html = sendmail_template.toString() + + // Send the HTML e-mail + if (params.email) { + try { + if( params.plaintext_email ){ throw GroovyException('Send plaintext e-mail, not HTML') } + // Try to send HTML e-mail using sendmail + [ 'sendmail', '-t' ].execute() << sendmail_html + log.info "[nf-core/sarek] Sent summary e-mail to $params.email (sendmail)" + } catch (all) { + // Catch failures and try with plaintext + [ 'mail', '-s', subject, params.email ].execute() << email_txt + log.info "[nf-core/sarek] Sent summary e-mail to $params.email (mail)" + } + } + + // 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" ) + output_hf.withWriter { w -> w << email_html } + def output_tf = new File( output_d, "pipeline_report.txt" ) + output_tf.withWriter { w -> w << email_txt } + + c_reset = params.monochrome_logs ? '' : "\033[0m"; + c_purple = params.monochrome_logs ? '' : "\033[0;35m"; + c_green = params.monochrome_logs ? '' : "\033[0;32m"; + c_red = params.monochrome_logs ? '' : "\033[0;31m"; + + if (workflow.stats.ignoredCountFmt > 0 && workflow.success) { + log.info "${c_purple}Warning, pipeline completed, but with errored process(es) ${c_reset}" + log.info "${c_red}Number of ignored errored process(es) : ${workflow.stats.ignoredCountFmt} ${c_reset}" + log.info "${c_green}Number of successfully ran process(es) : ${workflow.stats.succeedCountFmt} ${c_reset}" + } + + if(workflow.success){ + log.info "${c_purple}[nf-core/sarek]${c_green} Pipeline completed successfully${c_reset}" + } else { + checkHostname() + log.info "${c_purple}[nf-core/sarek]${c_red} Pipeline completed with errors${c_reset}" + } + +} + + +def nfcoreHeader(){ + // Log colors ANSI codes + c_reset = params.monochrome_logs ? '' : "\033[0m"; + c_dim = params.monochrome_logs ? '' : "\033[2m"; + c_black = params.monochrome_logs ? '' : "\033[0;30m"; + c_green = params.monochrome_logs ? '' : "\033[0;32m"; + c_yellow = params.monochrome_logs ? '' : "\033[0;33m"; + c_blue = params.monochrome_logs ? '' : "\033[0;34m"; + c_purple = params.monochrome_logs ? '' : "\033[0;35m"; + c_cyan = params.monochrome_logs ? '' : "\033[0;36m"; + c_white = params.monochrome_logs ? '' : "\033[0;37m"; + + return """ ${c_dim}----------------------------------------------------${c_reset} + ${c_green},--.${c_black}/${c_green},-.${c_reset} + ${c_blue} ___ __ __ __ ___ ${c_green}/,-._.--~\'${c_reset} + ${c_blue} |\\ | |__ __ / ` / \\ |__) |__ ${c_yellow}} {${c_reset} + ${c_blue} | \\| | \\__, \\__/ | \\ |___ ${c_green}\\`-._,-`-,${c_reset} + ${c_green}`._,._,\'${c_reset} + ${c_purple} nf-core/sarek v${workflow.manifest.version}${c_reset} + ${c_dim}----------------------------------------------------${c_reset} + """.stripIndent() +} + +def checkHostname(){ + def c_reset = params.monochrome_logs ? '' : "\033[0m" + def c_white = params.monochrome_logs ? '' : "\033[0;37m" + def c_red = params.monochrome_logs ? '' : "\033[1;91m" + def c_yellow_bold = params.monochrome_logs ? '' : "\033[1;93m" + if(params.hostnames){ + def hostname = "hostname".execute().text.trim() + params.hostnames.each { prof, hnames -> + hnames.each { hname -> + if(hostname.contains(hname) && !workflow.profile.contains(prof)){ + log.error "====================================================\n" + + " ${c_red}WARNING!${c_reset} You are running with `-profile $workflow.profile`\n" + + " but your machine hostname is ${c_white}'$hostname'${c_reset}\n" + + " ${c_yellow_bold}It's highly recommended that you use `-profile $prof${c_reset}`\n" + + "============================================================" + } + } + } + } +} diff --git a/nextflow.config b/nextflow.config new file mode 100644 index 0000000000..283569be80 --- /dev/null +++ b/nextflow.config @@ -0,0 +1,127 @@ +/* + * ------------------------------------------------- + * nf-core/sarek Nextflow config file + * ------------------------------------------------- + * Default config options for all environments. + */ + +// Global default params, used in configs +params { + + // Workflow flags + // TODO nf-core: Specify your pipeline's command line flags + reads = "data/*{1,2}.fastq.gz" + singleEnd = false + outdir = './results' + + // Boilerplate options + name = false + multiqc_config = "$baseDir/assets/multiqc_config.yaml" + email = false + maxMultiqcEmailFileSize = 25.MB + plaintext_email = false + monochrome_logs = false + help = false + igenomes_base = "./iGenomes" + tracedir = "${params.outdir}/pipeline_info" + awsqueue = false + awsregion = 'eu-west-1' + igenomesIgnore = false + custom_config_version = 'master' + custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" + hostnames = false + config_profile_description = false + config_profile_contact = false + config_profile_url = false +} + +// Container slug. Stable releases should specify release tag! +// Developmental code should specify :dev +process.container = 'nfcore/sarek:dev' + +// 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") +} + +profiles { + awsbatch { includeConfig 'conf/awsbatch.config' } + conda { process.conda = "$baseDir/environment.yml" } + debug { process.beforeScript = 'echo $HOSTNAME' } + docker { docker.enabled = true } + singularity { singularity.enabled = true } + test { includeConfig 'conf/test.config' } +} + +// Load igenomes.config if required +if(!params.igenomesIgnore){ + includeConfig 'conf/igenomes.config' +} + +// Capture exit codes from upstream processes when piping +process.shell = ['/bin/bash', '-euo', 'pipefail'] + +timeline { + enabled = true + file = "${params.tracedir}/execution_timeline.html" +} +report { + enabled = true + file = "${params.tracedir}/execution_report.html" +} +trace { + enabled = true + file = "${params.tracedir}/execution_trace.txt" +} +dag { + enabled = true + file = "${params.tracedir}/pipeline_dag.svg" +} + +manifest { + name = 'nf-core/sarek' + author = 'Maxime Garcia' + homePage = 'https://github.com/nf-core/sarek' + description = 'An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing' + mainScript = 'main.nf' + nextflowVersion = '>=0.32.0' + version = '2.5dev' +} + +// Function to ensure that resource requirements don't go beyond +// a maximum limit +def check_max(obj, type) { + if(type == 'memory'){ + try { + if(obj.compareTo(params.max_memory as nextflow.util.MemoryUnit) == 1) + return params.max_memory as nextflow.util.MemoryUnit + else + return obj + } catch (all) { + println " ### ERROR ### Max memory '${params.max_memory}' is not valid! Using default value: $obj" + return obj + } + } else if(type == 'time'){ + try { + if(obj.compareTo(params.max_time as nextflow.util.Duration) == 1) + return params.max_time as nextflow.util.Duration + else + return obj + } catch (all) { + println " ### ERROR ### Max time '${params.max_time}' is not valid! Using default value: $obj" + return obj + } + } else if(type == 'cpus'){ + try { + return Math.min( obj, params.max_cpus as int ) + } catch (all) { + println " ### ERROR ### Max cpus '${params.max_cpus}' is not valid! Using default value: $obj" + return obj + } + } +} From baa6393c3a80c70a9bf06e2af91fbefbc5946bf8 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 30 Apr 2019 17:42:11 +0200 Subject: [PATCH 002/854] WIP towards nf-core --- .travis.yml | 26 +- README.md | 129 +++- build.nf | 412 +++++++++++ conf/igenomes.config | 187 ++--- docs/images/BTB.svg | 184 +++++ docs/images/BTB_logo.png | Bin 0 -> 13624 bytes docs/images/CAW_logo.png | Bin 0 -> 6165 bytes docs/images/CAW_logo.svg | 670 ++++++++++++++++++ docs/images/NBIS.svg | 287 ++++++++ docs/images/NBIS_logo.png | Bin 0 -> 14424 bytes docs/images/NGI.svg | 333 +++++++++ docs/images/NGI_logo.png | Bin 0 -> 20547 bytes docs/images/Sarek_exome_logo.png | Bin 0 -> 10775 bytes docs/images/Sarek_germline_icon.png | Bin 0 -> 2191 bytes docs/images/Sarek_germline_logo.png | Bin 0 -> 11038 bytes docs/images/Sarek_icon.png | Bin 0 -> 2078 bytes docs/images/Sarek_icon.svg | 188 +++++ docs/images/Sarek_logo.png | Bin 0 -> 8766 bytes docs/images/Sarek_logo.svg | 408 +++++++++++ docs/images/Sarek_no_Border.png | Bin 0 -> 16435 bytes docs/images/Sarek_somatic_icon.png | Bin 0 -> 2108 bytes docs/images/Sarek_somatic_logo.png | Bin 0 -> 11571 bytes docs/images/SciLifeLab.svg | 99 +++ docs/images/SciLifeLab_logo.png | Bin 0 -> 8387 bytes docs/images/logos/Sarek Exome/Sarek_exome.svg | 227 ++++++ .../logos/Sarek Germline/Sarek_germline.svg | 242 +++++++ .../logos/Sarek Somatic/Sarek_somatic.svg | 232 ++++++ docs/images/logos/Sarek/Sarek_color.svg | 201 ++++++ docs/images/logos/Sarek/Sarek_dark_color.svg | 393 ++++++++++ docs/images/logos/Sarek/Sarek_dark_grey.svg | 401 +++++++++++ docs/images/logos/Sarek/Sarek_dark_mono.svg | 193 +++++ docs/images/logos/Sarek/Sarek_grey.svg | 409 +++++++++++ docs/images/logos/Sarek/Sarek_mono.svg | 390 ++++++++++ docs/images/nf-core-logo.svg | 217 ++++++ docs/images/nf-core_logo.png | Bin 0 -> 7915 bytes lib/SarekUtils.groovy | 41 ++ main.nf | 275 ++++--- nextflow.config | 5 + 38 files changed, 5846 insertions(+), 303 deletions(-) create mode 100644 build.nf create mode 100644 docs/images/BTB.svg create mode 100644 docs/images/BTB_logo.png create mode 100644 docs/images/CAW_logo.png create mode 100644 docs/images/CAW_logo.svg create mode 100644 docs/images/NBIS.svg create mode 100644 docs/images/NBIS_logo.png create mode 100644 docs/images/NGI.svg create mode 100644 docs/images/NGI_logo.png create mode 100644 docs/images/Sarek_exome_logo.png create mode 100644 docs/images/Sarek_germline_icon.png create mode 100644 docs/images/Sarek_germline_logo.png create mode 100644 docs/images/Sarek_icon.png create mode 100644 docs/images/Sarek_icon.svg create mode 100644 docs/images/Sarek_logo.png create mode 100644 docs/images/Sarek_logo.svg create mode 100644 docs/images/Sarek_no_Border.png create mode 100644 docs/images/Sarek_somatic_icon.png create mode 100644 docs/images/Sarek_somatic_logo.png create mode 100644 docs/images/SciLifeLab.svg create mode 100644 docs/images/SciLifeLab_logo.png create mode 100644 docs/images/logos/Sarek Exome/Sarek_exome.svg create mode 100644 docs/images/logos/Sarek Germline/Sarek_germline.svg create mode 100644 docs/images/logos/Sarek Somatic/Sarek_somatic.svg create mode 100644 docs/images/logos/Sarek/Sarek_color.svg create mode 100644 docs/images/logos/Sarek/Sarek_dark_color.svg create mode 100644 docs/images/logos/Sarek/Sarek_dark_grey.svg create mode 100644 docs/images/logos/Sarek/Sarek_dark_mono.svg create mode 100644 docs/images/logos/Sarek/Sarek_grey.svg create mode 100644 docs/images/logos/Sarek/Sarek_mono.svg create mode 100644 docs/images/nf-core-logo.svg create mode 100644 docs/images/nf-core_logo.png create mode 100644 lib/SarekUtils.groovy diff --git a/.travis.yml b/.travis.yml index 5477cf5611..fa72533100 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,10 +11,10 @@ before_install: # PRs to master are only ok if coming from dev branch - '[ $TRAVIS_PULL_REQUEST = "false" ] || [ $TRAVIS_BRANCH != "master" ] || ([ $TRAVIS_PULL_REQUEST_SLUG = $TRAVIS_REPO_SLUG ] && [ $TRAVIS_PULL_REQUEST_BRANCH = "dev" ])' # Pull the docker image first so the test doesn't wait for this - - docker pull nfcore/sarek:dev + - docker pull maxulysse/sarek:dev # Fake the tag locally so that the pipeline runs properly # Looks weird when this is :dev to :dev, but makes sense when testing code for a release (:dev to :1.0.1) - - docker tag nfcore/sarek:dev nfcore/sarek:dev + - docker tag maxulysse/sarek:dev maxulysse/sarek:dev install: # Install Nextflow @@ -26,17 +26,17 @@ install: - pip install nf-core # Reset - mkdir ${TRAVIS_BUILD_DIR}/tests && cd ${TRAVIS_BUILD_DIR}/tests - # Install markdownlint-cli - - sudo apt-get install npm && npm install -g markdownlint-cli env: - - NXF_VER='0.32.0' # Specify a minimum NF version that should be tested and work - - NXF_VER='' # Plus: get the latest NF version and check that it works + - NXF_VER=19.04.0 -script: - # Lint the pipeline code - - nf-core lint ${TRAVIS_BUILD_DIR} - # Lint the documentation - - markdownlint ${TRAVIS_BUILD_DIR} -c ${TRAVIS_BUILD_DIR}/.github/markdownlint.yml - # Run the pipeline with the test profile - - nextflow run ${TRAVIS_BUILD_DIR} -profile test,docker +jobs: + include: + - stage: lint + script: nf-core lint ${TRAVIS_BUILD_DIR} + - stage: built + script: skip + script: git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git test-data + script: nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile docker --genome smallGRCh37 --refdir test-data/reference --outdir References + - stage: test + script: nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile docker --help diff --git a/README.md b/README.md index f8efe7afa3..4171c4be8e 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,143 @@ -# nf-core/sarek +# [![Sarek](docs/images/Sarek_logo.png "Sarek")](https://sarek.scilifelab.se/) +[![nf-core](docs/images/nf-core_logo.png "Sarek")](https://nf-co.re/) **An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing**. -[![Build Status](https://travis-ci.com/nf-core/sarek.svg?branch=master)](https://travis-ci.com/nf-core/sarek) -[![Nextflow](https://img.shields.io/badge/nextflow-%E2%89%A50.32.0-brightgreen.svg)](https://www.nextflow.io/) +[![Nextflow version][nextflow-badge]](https://www.nextflow.io) +[![Travis build status][travis-badge]](https://travis-ci.org/nf-core/sarek) -[![install with bioconda](https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg)](http://bioconda.github.io/) -[![Docker](https://img.shields.io/docker/automated/nfcore/sarek.svg)](https://hub.docker.com/r/nfcore/sarek) +[![Install with bioconda][bioconda-badge]](http://bioconda.github.io/) +[![Docker Container available][docker-badge]](https://hub.docker.com/r/nf-core/sarek) + +[![Join us on Slack][slack-badge]](https://nfcore.slack.com/messages/CGFUX04HZ/) ## Introduction -The pipeline is built using [Nextflow](https://www.nextflow.io), a workflow tool to run tasks across multiple compute infrastructures in a very portable manner. It comes with docker containers making installation trivial and results highly reproducible. + + +Previously known as the Cancer Analysis Workflow (CAW), +Sarek is a workflow designed to run analyses on whole genome or targeted sequencing data from regular samples or tumour / normal pairs and could including additional relapses. + +It's built using [Nextflow](https://www.nextflow.io), +a domain specific language for workflow building, +across multiple compute infrastructures in a very portable manner. +Software dependencies are handled using [Docker](https://www.docker.com) or [Singularity](https://www.sylabs.io/singularity/) - container technologies that provide excellent reproducibility and ease of use. +Thus making installation trivial and results highly reproducible +It is listed on the [Elixir - Tools and Data Services Registry](https://bio.tools/Sarek), [Dockstore](https://dockstore.org/workflows/github.com/SciLifeLab/Sarek/) and [omicX - Bioinformatics tools](https://omictools.com/sarek-tool). ## Documentation The nf-core/sarek pipeline comes with documentation about the pipeline, found in the `docs/` directory: 1. [Installation](https://nf-co.re/usage/installation) + * [Installation documentation](docs/INSTALL.md) + * [Installation documentation specific for UPPMAX `rackham`](docs/INSTALL_RACKHAM.md) + * [Installation documentation specific for UPPMAX `bianca`](docs/INSTALL_BIANCA.md) 2. Pipeline configuration * [Local installation](https://nf-co.re/usage/local_installation) * [Adding your own system config](https://nf-co.re/usage/adding_own_config) * [Reference genomes](https://nf-co.re/usage/reference_genomes) 3. [Running the pipeline](docs/usage.md) + * [Tests documentation](docs/TESTS.md) + * [Reference files documentation](docs/REFERENCES.md) + * [Configuration and profiles documentation](docs/CONFIG.md) + * [Intervals documentation](docs/INTERVALS.md) + * [Running the pipeline](docs/USAGE.md) + * [Running the pipeline using Conda](docs/CONDA.md) + * [Command line parameters](docs/PARAMETERS.md) + * [Examples](docs/USE_CASES.md) + * [Input files documentation](docs/INPUT.md) + * [Processes documentation](docs/PROCESS.md) 4. [Output and how to interpret the results](docs/output.md) + * [Documentation about containers](docs/CONTAINERS.md) + * [Complementary information about ASCAT](docs/ASCAT.md) + * [Complementary information about annotations](docs/ANNOTATION.md) + * [Output documentation structure](docs/OUTPUT.md) 5. [Troubleshooting](https://nf-co.re/usage/troubleshooting) - +## Workflow steps + +Sarek is built with several workflow scripts. +A wrapper script contained within the repository makes it easy to run the different workflow scripts as a single job. +To test your installation, follow the [tests documentation.](docs/TESTS.md) + +Raw FastQ files or BAM files (unmapped, aligned or recalibrated) can be used as inputs. +You can choose which variant callers to use, plus the pipeline is capable of accommodating additional variant calling software or CNV callers if required. + +The worflow steps and tools used are as follows: + +1. **Preprocessing** - `main.nf` _(based on [GATK best practices](https://software.broadinstitute.org/gatk/best-practices/))_ + * Map reads to Reference + * [BWA](http://bio-bwa.sourceforge.net/) + * Mark Duplicates + * [GATK MarkDuplicates](https://github.com/broadinstitute/gatk) + * Base (Quality Score) Recalibration + * [GATK BaseRecalibrator](https://github.com/broadinstitute/gatk) + * [GATK ApplyBQSR](https://github.com/broadinstitute/gatk) +2. **Germline variant calling** - `germlineVC.nf` + * SNVs and small indels + * [GATK HaplotyeCaller](https://github.com/broadinstitute/gatk) + * [Strelka2](https://github.com/Illumina/strelka) + * Structural variants + * [Manta](https://github.com/Illumina/manta) +3. **Somatic variant calling** - `somaticVC.nf` _(optional)_ + * SNVs and small indels + * [MuTect2](https://github.com/broadinstitute/gatk) + * [Freebayes](https://github.com/ekg/freebayes) + * [Strelka2](https://github.com/Illumina/strelka) + * Structural variants + * [Manta](https://github.com/Illumina/manta) + * Sample heterogeneity, ploidy and CNVs + * [ASCAT](https://github.com/Crick-CancerGenomics/ascat) +4. **Annotation** - `annotate.nf` _(optional)_ + * Variant annotation + * [SnpEff](http://snpeff.sourceforge.net/) + * [VEP (Variant Effect Predictor)](https://www.ensembl.org/info/docs/tools/vep/index.html) +5. **Reporting** - `runMultiQC.nf` + * Reporting + * [MultiQC](http://multiqc.info) ## Credits -nf-core/sarek was originally written by Maxime Garcia. + +Sarek was developed at the [National Genomics Infastructure][ngi-link] and [National Bioinformatics Infastructure Sweden][nbis-link] which are both platforms at [SciLifeLab][scilifelab-link], with the support of [The Swedish Childhood Tumor Biobank (Barntumörbanken)][btb-link]. + +Main authors: +* [Maxime Garcia](https://github.com/MaxUlysse) +* [Szilveszter Juhos](https://github.com/szilvajuhos) + +Helpful contributors: +* [Johannes Alneberg](https://github.com/alneberg) +* [Phil Ewels](https://github.com/ewels) +* [Jesper Eisfeldt](https://github.com/J35P312) +* [Malin Larsson](https://github.com/malinlarsson) +* [Marcel Martin](https://github.com/marcelm) +* [Alexander Peltzer](https://github.com/apeltzer) +* [Nilesh Tawari](https://github.com/nilesh-tawari) +* [arontommi](https://github.com/arontommi) +* [bjornnystedt](https://github.com/bjornnystedt) +* [gulfshores](https://github.com/gulfshores) +* [KochTobi](https://github.com/KochTobi) +* [pallolason](https://github.com/pallolason) +* [Sebastian-D](https://github.com/Sebastian-D) +* [silviamorins](https://github.com/silviamorins) + +## Contributions & Support + +If you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md). + +For further information or help, don't hesitate to get in touch on [Slack](https://nfcore.slack.com/messages/CGFUX04HZ/) or contact us: maxime.garcia@scilifelab.se, szilveszter.juhos@scilifelab.se + +## CHANGELOG + +* [CHANGELOG](CHANGELOG.md) + +## Aknowledgements +[SciLifeLab logo][scilifelab-link] +[Barntumörbanken logo][btb-link] +[National Genomics Infrastructure logo][ngi-link] +[National Bioinformatics Infrastructure Sweden logo][nbis-link] + +[bioconda-badge]: https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg?style=popout&logo=data:image/png;base64,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 +[docker-badge]: https://img.shields.io/docker/automated/nf-core/sarek.svg?style=popout&logo=docker +[nextflow-badge]: https://img.shields.io/badge/nextflow-%E2%89%A519.04.0-brightgreen.svg?style=popout&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgd2lkdGg9IjEyLjc5OTIyOG1tIiAgIGhlaWdodD0iMTIuODA0ODA5bW0iICAgdmlld0JveD0iMCAwIDQ1LjM1MTU5NCA0NS4zNzEzNjkiICAgaWQ9InN2Zzc2NTIiICAgdmVyc2lvbj0iMS4xIiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTEgcjEzNzI1IiAgIHNvZGlwb2RpOmRvY25hbWU9Im5leHRmbG93LWZhdmljb24td2hpdGUuc3ZnIj4gIDxkZWZzICAgICBpZD0iZGVmczc2NTQiIC8+ICA8c29kaXBvZGk6bmFtZWR2aWV3ICAgICBpZD0iYmFzZSIgICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIgICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIgICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiICAgICBpbmtzY2FwZTp6b29tPSI3LjkxOTU5NTkiICAgICBpbmtzY2FwZTpjeD0iMjAuMTEzMjM1IiAgICAgaW5rc2NhcGU6Y3k9IjIzLjE2MzkwOCIgICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIgICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImxheWVyMSIgICAgIHNob3dncmlkPSJmYWxzZSIgICAgIGZpdC1tYXJnaW4tdG9wPSIwIiAgICAgZml0LW1hcmdpbi1sZWZ0PSIwIiAgICAgZml0LW1hcmdpbi1yaWdodD0iMCIgICAgIGZpdC1tYXJnaW4tYm90dG9tPSIwIiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxOTIwIiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTAxNSIgICAgIGlua3NjYXBlOndpbmRvdy14PSIwIiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjAiICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIiAvPiAgPG1ldGFkYXRhICAgICBpZD0ibWV0YWRhdGE3NjU3Ij4gICAgPHJkZjpSREY+ICAgICAgPGNjOldvcmsgICAgICAgICByZGY6YWJvdXQ9IiI+ICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4gICAgICAgIDxkYzp0eXBlICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+ICAgICAgPC9jYzpXb3JrPiAgICA8L3JkZjpSREY+ICA8L21ldGFkYXRhPiAgPGcgICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciIgICAgIGlkPSJsYXllcjEiICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMTQuMTA0MzcsLTQ1Mi41MzM2NikiPiAgICA8cGF0aCAgICAgICBzdHlsZT0iZmlsbDojZmZmZmZmIiAgICAgICBkPSJtIC0xMTQuMTA0MzcsNDU1LjQ2NTYyIDAsOC44NjEzMyAwLjIwMzEzLDAuMDYwNSBjIDMuODcyOTMsMS4xMzk0MyA4LjY1MjUxLDQuMzgzMiAxMi44MDA3OCw4LjY4NzUgMC45MTM2MywwLjk0ODAxIDEuOTcyNTY0LDIuMTA2ODQgMi4zNTM1MjQsMi41NzYxOCBsIDAuNjkxNCwwLjg1MzUxIC0wLjg2OTE0LDAuNzc1MzkgYyAtNC4xOTk5MDQsMy43NDE5MyAtOC45NzE5MDQsNi43NjYzNyAtMTQuMTA1NDc0LDguOTQxNDEgLTAuMzA5NzUsMC4xMzEyNCAtMC42OTcyMiwwLjI4MTIzIC0xLjA3NDIyLDAuNDI3NzMgbCAwLDkuMzA0NjkgYyAyLjY1OTkzLC0wLjg3NzkyIDUuMzA2MzksLTEuOTc1IDguMDYwNTUsLTMuMzUxNTYgNC4yNTYyMywtMi4xMjczMiA3LjU0MzI1NCwtNC4yNTc2NCAxMS4wMzcxMTQsLTcuMTU2MjUgMC45MjU4MSwtMC43NjgwOCAxLjgyMTA5LC0xLjUwNzAyIDEuOTkwMjMsLTEuNjQyNTggMC4yNzkzMSwtMC4yMjM4NCAwLjQ5MzMyLC0wLjA1MTQgMi4zMjQyMiwxLjg3ODkxIDYuMjIyNjUsNi41NjA0MSAxMy43ODMzNywxMC43NDQ0MyAyMS45Mzk0NiwxMi4yMjI2NSBsIDAsLTguOTQxNCBjIC00Ljc5NTM3LC0xLjE5NTkgLTkuNDIwMzEsLTMuNjQ1MTEgLTEzLjI1NzgyLC03LjA2NDQ2IC0xLjY4MzUxLC0xLjUwMDA2IC00LjI4NjgxLC00LjM1MDA5IC00LjM5MjU4LC00LjgwODU5IC0wLjA2ODYsLTAuMjk3MyA1LjQ3NDgsLTUuNzA5NzcgNy4yOTQ5MywtNy4xMjMwNSAzLjQ4MjczLC0yLjcwNDI0IDYuNTg4MjUsLTQuMTIwNDIgMTAuMjc1MzksLTQuNjg1NTQgMC4wMjc1LC0wLjAwNCAwLjA1MjcsLTAuMDA4IDAuMDgwMSwtMC4wMTE3IGwgMCwtOC43NSBjIC03LjkzOTI3LDIuMDIxMTQgLTE0Ljg3MDAxLDUuODc3MzggLTIxLjUsMTEuOTQzMzYgbCAtMS42MzA4NiwxLjQ5MjE4IC0yLjk5NjEsLTMuMDA3ODEgYyAtMS42NDc1NiwtMS42NTQ3IC0zLjc0MDI1LC0zLjYwMTU3IC00LjY1MjM0LC00LjMyNjE3IC01LjAwODU1NCwtMy45Nzg5OSAtMTAuMTUyOTU0LC02LjQ5OTIzIC0xNC41NzIyNzQsLTcuMTU2MjUgeiIgICAgICAgaWQ9InBhdGg3NjIwIiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY3NjY2NzY2Nzc2NzY2NzY3NjY2NjY2NzYyIgLz4gIDwvZz48L3N2Zz4= +[travis-badge]: https://img.shields.io/travis/nf-core/sarek.svg?style=popout&logo=travis +[slack-badge]: https://img.shields.io/badge/slack-nfcore/sarek-blue.svg?style=popout&logo=slack diff --git a/build.nf b/build.nf new file mode 100644 index 0000000000..c5238c483e --- /dev/null +++ b/build.nf @@ -0,0 +1,412 @@ +#!/usr/bin/env nextflow +/* +======================================================================================== + nf-core/sarek +======================================================================================== + nf-core/sarek Analysis Pipeline. + @Homepage + https://sarek.scilifelab.se/ + @Documentation + https://github.com/nf-core/sarek/README.md +---------------------------------------------------------------------------------------- +*/ + +def helpMessage() { + // TODO nf-core: Add to this help message with new command line parameters + log.info nfcoreHeader() + log.info""" + +Usage: + --help + you're reading it + +BUILD REFERENCES: + nextflow run build.nf [--refdir --outdir ] + --refdir + Specify a directory containing reference files + --outdir + Specify an output directory + +DOWNLOAD CACHE: + nextflow run build.nf --download_cache [--snpEff_cache ] [--vep_cache ] + --snpEff_cache + Specify path to snpEff cache + If none, will use snpEff version specified in configuration + Will use snpEff cache version for ${params.genome}: ${params.genomes[params.genome].snpeffDb} in igenomes configuration file: + Change with --genome or in configuration files + --vep_cache + Specify path to VEP cache + If none, will use VEP version specified in configuration + Will use VEP cache version for ${params.genome}: ${params.genomes[params.genome].vepCacheVersion} in igenomes configuration file: + Change with --genome or in configuration files + --cadd_cache + Specify path to CADD cache + Will use CADD version specified + --cadd_version + Will specify which CADD version to download + """.stripIndent() +} + +/* + * SET UP CONFIGURATION VARIABLES + */ + +// Show help message +if (params.help){ + helpMessage() + exit 0 +} + +ch_referencesFiles = Channel.fromPath("${params.refdir}/*") +params.genome = 'smallGRCh37' + +// Check if genome exists in the config file +if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { + exit 1, "The provided genome '${params.genome}' is not available in the iGenomes file. Currently the available genomes are ${params.genomes.keySet().join(", ")}" +} + +// Has the run name been specified by the user? +// this has the bonus effect of catching both -name and --name +custom_runName = params.name +if ( !(workflow.runName ==~ /[a-z]+_[a-z]+/) ){ + custom_runName = workflow.runName +} + +if ( workflow.profile == 'awsbatch') { + // AWSBatch sanity checking + if (!params.awsqueue || !params.awsregion) exit 1, "Specify correct --awsqueue and --awsregion parameters on AWSBatch!" + // Check outdir paths to be S3 buckets if running on AWSBatch + // related: https://github.com/nextflow-io/nextflow/issues/813 + if (!params.outdir.startsWith('s3:')) exit 1, "Outdir not on S3 - specify S3 Bucket to run on AWSBatch!" + // Prevent trace files to be stored on S3 since S3 does not support rolling files. + if (workflow.tracedir.startsWith('s3:')) exit 1, "Specify a local tracedir or run without trace! S3 cannot be used for tracefiles." +} + +// Header log info +log.info nfcoreHeader() +def summary = [:] +if (workflow.revision) summary['Pipeline Release'] = workflow.revision +summary['Run Name'] = custom_runName ?: workflow.runName +// TODO nf-core: Report custom parameters here +summary['Max Resources'] = "$params.max_memory memory, $params.max_cpus cpus, $params.max_time time per job" +if (workflow.containerEngine) summary['Container'] = "$workflow.containerEngine - $workflow.container" +summary['Output dir'] = params.outdir +summary['Launch dir'] = workflow.launchDir +summary['Working dir'] = workflow.workDir +summary['Script dir'] = workflow.projectDir +summary['User'] = workflow.userName +if (workflow.profile == 'awsbatch'){ + summary['AWS Region'] = params.awsregion + summary['AWS Queue'] = params.awsqueue +} +summary['Config Profile'] = workflow.profile +if (params.config_profile_description) summary['Config Description'] = params.config_profile_description +if (params.config_profile_contact) summary['Config Contact'] = params.config_profile_contact +if (params.config_profile_url) summary['Config URL'] = params.config_profile_url +if (params.email) { + summary['E-mail Address'] = params.email + summary['MultiQC maxsize'] = params.maxMultiqcEmailFileSize +} +log.info summary.collect { k,v -> "${k.padRight(18)}: $v" }.join("\n") +log.info "\033[2m----------------------------------------------------\033[0m" + +// Check the hostnames against configured profiles +checkHostname() + +def create_workflow_summary(summary) { + def yaml_file = workDir.resolve('workflow_summary_mqc.yaml') + yaml_file.text = """ + id: 'nf-core-sarek-summary' + description: " - this information is collected when the pipeline is started." + section_name: 'nf-core/sarek Workflow Summary' + section_href: 'https://github.com/nf-core/sarek' + plot_type: 'html' + data: | +
+${summary.collect { k,v -> "
$k
${v ?: 'N/A'}
" }.join("\n")} +
+ """.stripIndent() + + return yaml_file +} + +/* +================================================================================ += B U I L D R E F E R E N C E S = +================================================================================ +*/ + +ch_compressedfiles = Channel.create() +ch_notCompressedfiles = Channel.create() + +ch_referencesFiles + .choice(ch_compressedfiles, ch_notCompressedfiles) {it =~ ".(gz|tar.bz2)" ? 0 : 1} + +process DecompressFile { + tag {f_reference} + + input: + file(f_reference) from ch_compressedfiles + + output: + file("*.{vcf,fasta,loci}") into ch_decompressedFiles + + script: + realReferenceFile="readlink ${f_reference}" + if (f_reference =~ ".gz") + """ + gzip -d -c \$(${realReferenceFile}) > ${f_reference.baseName} + """ + else if (f_reference =~ ".tar.bz2") + """ + tar xvjf \$(${realReferenceFile}) + """ +} + +ch_decompressedFiles = ch_decompressedFiles.dump(tag:'DecompressedFile') + +ch_fastaFile = Channel.create() +ch_fastaForBWA = Channel.create() +ch_fastaReference = Channel.create() +ch_fastaForSAMTools = Channel.create() +ch_otherFile = Channel.create() +ch_vcfFile = Channel.create() + +ch_decompressedFiles + .choice(ch_fastaFile, ch_vcfFile, ch_otherFile) { + it =~ ".fasta" ? 0 : + it =~ ".vcf" ? 1 : 2} + +(ch_fastaForBWA, ch_fastaReference, ch_fastaForSAMTools, ch_fastaFileToKeep) = ch_fastaFile.into(4) +(ch_vcfFile, ch_vcfFileToKeep) = ch_vcfFile.into(2) + +ch_notCompressedfiles + .mix(ch_fastaFileToKeep, ch_vcfFileToKeep, ch_otherFile) + .collectFile(storeDir: params.outdir) + +process BuildBWAindexes { + tag {f_reference} + + publishDir params.outdir, mode: params.publishDirMode + + input: + file(f_reference) from ch_fastaForBWA + + output: + file("*.{amb,ann,bwt,pac,sa}") into bwaIndexes + + script: + """ + bwa index ${f_reference} + """ +} + +bwaIndexes.dump(tag:'bwaIndexes') + +process BuildReferenceIndex { + tag {f_reference} + + publishDir params.outdir, mode: params.publishDirMode + + input: + file(f_reference) from ch_fastaReference + + output: + file("*.dict") into ch_referenceIndex + + script: + """ + gatk --java-options "-Xmx${task.memory.toGiga()}g" \ + CreateSequenceDictionary \ + --REFERENCE ${f_reference} \ + --OUTPUT ${f_reference.baseName}.dict + """ +} + +ch_referenceIndex.dump(tag:'dict') + +process BuildSAMToolsIndex { + tag {f_reference} + + publishDir params.outdir, mode: params.publishDirMode + + input: + file(f_reference) from ch_fastaForSAMTools + + output: + file("*.fai") into ch_samtoolsIndex + + script: + """ + samtools faidx ${f_reference} + """ +} + +ch_samtoolsIndex.dump(tag:'fai') + +process BuildVCFIndex { + tag {f_reference} + + publishDir params.outdir, mode: params.publishDirMode + + input: + file(f_reference) from ch_vcfFile + + output: + file("${f_reference}.idx") into ch_vcfIndex + + script: + """ + igvtools index ${f_reference} + """ +} + +ch_vcfIndex.dump(tag:'idx') + +/* +================================================================================ += D O W N L O A D C A C H E = +================================================================================ +*/ + +process BuildCache_snpEff { + tag {snpeffDb} + + publishDir params.snpEff_cache, mode: params.publishDirMode + + input: + val snpeffDb from Channel.value(params.genomes[params.genome].snpeffDb) + + output: + file("*") + + when: params.snpEff_cache && params.download_cache + + script: + """ + snpEff download -v ${snpeffDb} -dataDir \${PWD} + """ +} + +process BuildCache_VEP { + tag {"${species}_${cache_version}_${genome}"} + + publishDir "${params.vep_cache}/${species}", mode: params.publishDirMode + + input: + val cache_version from Channel.value(params.genomes[params.genome].vepCacheVersion) + + output: + file("*") + + when: params.vep_cache && params.download_cache + + script: + genome = params.genome == "smallGRCh37" ? "GRCh37" : params.genome + species = genome =~ "GRCh3*" ? "homo_sapiens" : "" + """ + vep_install \ + -a cf \ + -c . \ + -s ${species} \ + -v ${cache_version} \ + -y ${genome} \ + --CACHE_VERSION ${cache_version} \ + --CONVERT \ + --NO_HTSLIB --NO_TEST --NO_BIOPERL --NO_UPDATE + + mv ${species}/* . + rm -rf ${species} + """ +} + +caddFileToDownload = (params.cadd_version) && (params.genome == "GRCh37" || params.genome == "GRCh38") ? + Channel.from( + "https://krishna.gs.washington.edu/download/CADD/${params.cadd_version}/${params.genome}/InDels_inclAnno.tsv.gz", + "https://krishna.gs.washington.edu/download/CADD/${params.cadd_version}/${params.genome}/whole_genome_SNVs_inclAnno.tsv.gz" + ) : Channel.empty() + +process DownloadCADD { + tag {caddFile} + + publishDir "${params.cadd_cache}/${params.genome}", mode: params.publishDirMode + + input: + val(caddFile) from caddFileToDownload + + output: + set file("*.tsv.gz"), file("*.tsv.gz.tbi") + + when: params.cadd_cache && params.download_cache + + script: + """ + wget --quiet ${caddFile} + wget --quiet ${caddFile}.tbi + """ +} + + +def nfcoreHeader(){ + // Log colors ANSI codes + c_black = params.monochrome_logs ? '' : "\033[0;30m"; + c_blue = params.monochrome_logs ? '' : "\033[0;34m"; + c_cyan = params.monochrome_logs ? '' : "\033[0;36m"; + c_dim = params.monochrome_logs ? '' : "\033[2m"; + c_green = params.monochrome_logs ? '' : "\033[0;32m"; + c_purple = params.monochrome_logs ? '' : "\033[0;35m"; + c_reset = params.monochrome_logs ? '' : "\033[0m"; + c_white = params.monochrome_logs ? '' : "\033[0;37m"; + c_yellow = params.monochrome_logs ? '' : "\033[0;33m"; + + return """ ${c_dim}----------------------------------------------------${c_reset} + ${c_green},--.${c_black}/${c_green},-.${c_reset} + ${c_blue} ___ __ __ __ ___ ${c_green}/,-._.--~\'${c_reset} + ${c_blue} |\\ | |__ __ / ` / \\ |__) |__ ${c_yellow}} {${c_reset} + ${c_blue} | \\| | \\__, \\__/ | \\ |___ ${c_green}\\`-._,-`-,${c_reset} + ${c_green}`._,._,\'${c_reset} + ____ _____ _ + .' _ `. / ____| | | + / |\\`-_ \\ | (___ ___ _ __ __ | | __ + | | \\ `-| \\___ \\/__ \\| ´__/ _\\| |/ / + \\ | \\ / ____) | __ | | | __| < + `|____\\' |_____/\\____|_| \\__/|_|\\_\\ + + ${c_purple} nf-core/sarek v${workflow.manifest.version}${c_reset} + ${c_dim}----------------------------------------------------${c_reset} + """.stripIndent() +} + +def checkHostname(){ + def c_reset = params.monochrome_logs ? '' : "\033[0m" + def c_white = params.monochrome_logs ? '' : "\033[0;37m" + def c_red = params.monochrome_logs ? '' : "\033[1;91m" + def c_yellow_bold = params.monochrome_logs ? '' : "\033[1;93m" + if (params.hostnames){ + def hostname = "hostname".execute().text.trim() + params.hostnames.each { prof, hnames -> + hnames.each { hname -> + if (hostname.contains(hname) && !workflow.profile.contains(prof)){ + log.error "====================================================\n" + + " ${c_red}WARNING!${c_reset} You are running with `-profile $workflow.profile`\n" + + " but your machine hostname is ${c_white}'$hostname'${c_reset}\n" + + " ${c_yellow_bold}It's highly recommended that you use `-profile $prof${c_reset}`\n" + + "============================================================" + } + } + } + } +} + +/* +================================================================================ += F U N C T I O N S = +================================================================================ +*/ + +def checkFile(it) { + // Check file existence + final f = file(it) + if (!f.exists()) exit 1, "Missing file: ${it}, see --help for more information" + return true +} \ No newline at end of file diff --git a/conf/igenomes.config b/conf/igenomes.config index d19e61f4b1..c37c8f84b8 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -7,141 +7,52 @@ * path using $params.igenomes_base / --igenomes_base */ -params { - // illumina iGenomes reference file paths - // TODO nf-core: Add new reference types and strip out those that are not needed - genomes { - 'GRCh37' { - bed12 = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/STARIndex/" - } - 'GRCm38' { - bed12 = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/STARIndex/" - } - 'TAIR10' { - bed12 = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/STARIndex/" - } - 'EB2' { - bed12 = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/STARIndex/" - } - 'UMD3.1' { - bed12 = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/STARIndex/" - } - 'WBcel235' { - bed12 = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/STARIndex/" - } - 'CanFam3.1' { - bed12 = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/STARIndex/" - } - 'GRCz10' { - bed12 = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/STARIndex/" - } - 'BDGP6' { - bed12 = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/STARIndex/" - } - 'EquCab2' { - bed12 = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/STARIndex/" - } - 'EB1' { - bed12 = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/STARIndex/" - } - 'Galgal4' { - bed12 = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/STARIndex/" - } - 'Gm01' { - bed12 = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/STARIndex/" - } - 'Mmul_1' { - bed12 = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/STARIndex/" - } - 'IRGSP-1.0' { - bed12 = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/STARIndex/" - } - 'CHIMP2.1.4' { - bed12 = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/STARIndex/" - } - 'Rnor_6.0' { - bed12 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/STARIndex/" - } - 'R64-1-1' { - bed12 = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/STARIndex/" - } - 'EF2' { - bed12 = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/STARIndex/" - } - 'Sbi1' { - bed12 = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/STARIndex/" - } - 'Sscrofa10.2' { - bed12 = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/STARIndex/" - } - 'AGPv3' { - bed12 = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Annotation/Genes/genes.bed" - fasta = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/WholeGenomeFasta/genome.fa" - gtf = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Annotation/Genes/genes.gtf" - star = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/STARIndex/" - } - } -} + params { + genomes { + 'GRCh37' { + acLoci = "${params.igenomes_base}/Annotation/ASCAT/1000G_phase3_20130502_SNP_maf0.3.loci" + acLociGC = "${params.igenomes_base}/Annotation/ASCAT/1000G_phase3_20130502_SNP_maf0.3.loci.gc" + bwaIndex = "${params.igenomes_base}/Sequence/BWAIndex/human_g1k_v37_decoy.fasta.{amb,ann,bwt,pac,sa}" + dbsnp = "${params.igenomes_base}/Annotation/GATKBundle/dbsnp_138.b37.vcf" + dbsnpIndex = "${params.igenomes_base}/Annotation/GATKBundle/dbsnp_138.b37.vcf.idx" + genomeDict = "${params.igenomes_base}/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.dict" + genomeFile = "${params.igenomes_base}/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta" + genomeIndex = "${params.igenomes_base}/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta.fai" + intervals = "${params.igenomes_base}/Annotation/intervals/wgs_calling_regions_CAW.list" + knownIndels = "${params.igenomes_base}/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf" + knownIndelsIndex = "${params.igenomes_base}/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" + snpeffDb = "GRCh37.75" + vepCacheVersion = "95" + } + 'GRCh38' { + acLoci = "${params.igenomes_base}/Annotation/ASCAT/1000G_phase3_GRCh38_maf0.3.loci" + acLociGC = "${params.igenomes_base}/Annotation/ASCAT/1000G_phase3_GRCh38_maf0.3.loci.gc" + bwaIndex = "${params.igenomes_base}/Sequence/BWAIndex/Homo_sapiens_assembly38.fasta.64.{alt,amb,ann,bwt,pac,sa}" + dbsnp = "${params.igenomes_base}/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz" + dbsnpIndex = "${params.igenomes_base}/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz.tbi" + genomeDict = "${params.igenomes_base}/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.dict" + genomeFile = "${params.igenomes_base}/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta" + genomeIndex = "${params.igenomes_base}/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta.fai" + intervals = "${params.igenomes_base}/Annotation/intervals/wgs_calling_regions.hg38.bed" + knownIndels = "${params.igenomes_base}/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" + knownIndelsIndex = "${params.igenomes_base}/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" + snpeffDb = "GRCh38.86" + vepCacheVersion = "95" + } + 'smallGRCh37' { + acLoci = "${params.igenomes_base}/1000G_phase3_20130502_SNP_maf0.3.small.loci" + acLociGC = "${params.igenomes_base}/1000G_phase3_20130502_SNP_maf0.3.small.loci.gc" + bwaIndex = "${params.igenomes_base}/human_g1k_v37_decoy.small.fasta.{amb,ann,bwt,pac,sa}" + dbsnp = "${params.igenomes_base}/dbsnp_138.b37.small.vcf" + dbsnpIndex = "${params.igenomes_base}/dbsnp_138.b37.small.vcf.idx" + genomeDict = "${params.igenomes_base}/human_g1k_v37_decoy.small.dict" + genomeFile = "${params.igenomes_base}/human_g1k_v37_decoy.small.fasta" + genomeIndex = "${params.igenomes_base}/human_g1k_v37_decoy.small.fasta.fai" + intervals = "${params.igenomes_base}/small.intervals" + knownIndels = "${params.igenomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf" + knownIndelsIndex = "${params.igenomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf.idx" + snpeffDb = "GRCh37.75" + vepCacheVersion = "95" + } + } + } diff --git a/docs/images/BTB.svg b/docs/images/BTB.svg new file mode 100644 index 0000000000..099f1101f6 --- /dev/null +++ b/docs/images/BTB.svg @@ -0,0 +1,184 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/docs/images/BTB_logo.png b/docs/images/BTB_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6a197b807508b6722abbe70c49210ca0d693bcdc GIT binary patch literal 13624 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 Kc$KI@!2bhJTgn{( literal 0 HcmV?d00001 diff --git a/docs/images/CAW_logo.png b/docs/images/CAW_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..cc2bbe2613994b32a575081ad24ee2abfd6c55a1 GIT binary patch literal 6165 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 d{ullW>27y_51YF + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + W + + + + + + + A + + + + + + C + + + + + diff --git a/docs/images/NBIS.svg b/docs/images/NBIS.svg new file mode 100644 index 0000000000..337e22cf68 --- /dev/null +++ b/docs/images/NBIS.svg @@ -0,0 +1,287 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/docs/images/NBIS_logo.png b/docs/images/NBIS_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6e5c3031684cc88357d33731facf0e15f3ee8ebc GIT binary patch literal 14424 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 KlB^Lo4*4GrIFLL5 literal 0 HcmV?d00001 diff --git a/docs/images/NGI.svg b/docs/images/NGI.svg new file mode 100644 index 0000000000..aef40fd811 --- /dev/null +++ b/docs/images/NGI.svg @@ -0,0 +1,333 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/docs/images/NGI_logo.png b/docs/images/NGI_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3f4b769e551050a878e22bd1120033b097b22670 GIT binary patch literal 20547 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 SfT=m*;FRRm#mVwAsieAZk(sG&BOK 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 Y18G~bPU|N;o&W#<07*qoM6N<$f}h_;`v3p{ literal 0 HcmV?d00001 diff --git a/docs/images/Sarek_icon.png b/docs/images/Sarek_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..5bdbf966ef9fe03e0a1bfa67b9ca99cd664718f2 GIT binary patch literal 2078 zcmV+(2;ujMP)3CVEI`JLbQcizvLfyLo1;D3M#SXyh*T8mOjlu}cl z0qaqjHsD8#;aDxewg&i%QfiHeOeN;$=TlWxMQLd%1qB5F7=}TAe?P%skYqCX*tt@O z$bH})pm_mWvf^#PeAJ@i^?GIZ?%h&fUoXL6P%O)mbXb-pfj~g&>+7YqwpI!X3Iq_X zwEzZC`z(c*1O1Pj$;OQv<>=9)Vi-nR!SgXTHYP`o9Fgkk>gj>>0xK6=e4W$ce!pLu znwrG6?VN?r#I|i|Y;2Uu%1Qy8`SQ!f5`Wp5ly!A=5|76hP54aW@wn{Yzh4}Gz{Q1% zzoV3rva&L1X=!<8!e`Rl+$^P~rA|+Taupv2WbN9u5(osAOuR!V6cWGRFMt5|vlV|? zDJ7Mal@f_WmR!6;BodK|iVCME&SxsVPHQb?Wo6RY+45|pcbS0wx}BqQS^i@M28=j6$gPA?daXy-8ZeWlb#>({TR zt*s5EGC$+}vF#5$Fz)k>@^7+CF9X1(T&!@f;6=9&pJ(#V$y*2_LUnaD?d|Q@w*3Zh z*7Ydw-$2o!LxL(# zCTS!qisXX*%?DL?(^9tPt5Q~$3nSk0D~ zzKzdQGN+x}<)PTU0-wjni*6sq?qamk^ZFYb8>76u9Md!r5tYZ}WrUqOcV;c#5{r@X z;V06fMwH`$52z}BmCb8j$K&$MYCCQv=rt4cnv;u4ro+zb^|E8f4jLL70N%_4ehpAl zQ{>sEek-g#w-#ZY31p~Mhf4?&^uF7vWtS}zsm z7Xq+t+cqbF19^ZSVC&YcSqIQH(luv(B9-7m%Btn7GOk+?ViPf96EW_O zO&*0jE)PDBk5@Lm;uL#T10J{AO+`gT)&blZy^~S70ds(+U?XR{TZpIPS^IHFSP3FV zgt4L+`R;rGk5)>ls;VknF4uhaPw`;vLB?eTAvhf1*zLb^rMDGZ?5zDcXqTq^pL?-;Ir#-BEG|MRg%%MC3k!3qWFS6}vw(-= zBYYV8J0FEVWGorW+J3qB1w@4T7v41VnSG2~1~~TMVkk$lp+?( zz6F9K!K`i4Vc8Z}dRjT&@jjuE%x;k8SRADkc_PBVK;}c?*5FMpMK5wW`bn;O(=wVI zrTOm1d~x_?HhIPRp+Jj{JnDaFBq2R~QKYX7xvu_Tsd z{RjBn%rfcj1Di!891e%svSrJ2=?NoZaAE%?j9wEF=>onpTe}hl5${h|Hj_uti(2b%i3t85S5mdhk1Id>2Y^hlk`{r6PP$Ho z&{{jgX4aN>$V5rKh$NI!HG}O#ME=`@XQhY2HQt4N&p#c3=%pT7e|weQ*1qWz_UH4N zW+P!Ga7(*%nQhq=eW{4bAFgHf=GEkRa_f;)!XkPhN~kH!=-n9FrLir$2lxszR-1I> z(uTW$KWnX*+qO-fCy!NMFJonO2_@@%EH7V<(z919wqQg}2HS@ixIRE%Yd@((%4u(!F%gFQO0gy_hNIpzr^qAPGCmyr}xX0wt z;OqjlESNWeYfOG~VkxD><#LJAN|b)|`SH(f4B#s8gT-+Cf7APF;mASVQ2+n{07*qo IM6N<$g2~7A9RL6T literal 0 HcmV?d00001 diff --git a/docs/images/Sarek_icon.svg b/docs/images/Sarek_icon.svg new file mode 100644 index 0000000000..a921cd277d --- /dev/null +++ b/docs/images/Sarek_icon.svg @@ -0,0 +1,188 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/Sarek_logo.png b/docs/images/Sarek_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ed5079200fa427501d17edaa974754e211e4a8eb GIT binary patch literal 8766 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 literal 0 HcmV?d00001 diff --git a/docs/images/Sarek_logo.svg b/docs/images/Sarek_logo.svg new file mode 100644 index 0000000000..8491e71bf2 --- /dev/null +++ b/docs/images/Sarek_logo.svg @@ -0,0 +1,408 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + Sarek  + + + + + + + + + diff --git a/docs/images/Sarek_no_Border.png b/docs/images/Sarek_no_Border.png new file mode 100644 index 0000000000000000000000000000000000000000..81f74b561350bf9c74aabeb1d5ca3e030fea9eeb GIT binary patch literal 16435 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 O1bG={=}JlCkpBlstpi>F literal 0 HcmV?d00001 diff --git a/docs/images/Sarek_somatic_icon.png b/docs/images/Sarek_somatic_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8f30b4d45d85e3fad09a9ace8c2e4b67d2325567 GIT binary patch literal 2108 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 literal 0 HcmV?d00001 diff --git a/docs/images/SciLifeLab.svg b/docs/images/SciLifeLab.svg new file mode 100644 index 0000000000..b8a44b794e --- /dev/null +++ b/docs/images/SciLifeLab.svg @@ -0,0 +1,99 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/docs/images/SciLifeLab_logo.png b/docs/images/SciLifeLab_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..bc4dbda623f8f70d82f883c5019638d86016a298 GIT binary patch literal 8387 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 Z^1n)knbg1LpQ-==002ovPDHLkV1kk8bd>-A literal 0 HcmV?d00001 diff --git a/docs/images/logos/Sarek Exome/Sarek_exome.svg b/docs/images/logos/Sarek Exome/Sarek_exome.svg new file mode 100644 index 0000000000..63ab7420f7 --- /dev/null +++ b/docs/images/logos/Sarek Exome/Sarek_exome.svg @@ -0,0 +1,227 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/Sarek Germline/Sarek_germline.svg b/docs/images/logos/Sarek Germline/Sarek_germline.svg new file mode 100644 index 0000000000..13a3447c10 --- /dev/null +++ b/docs/images/logos/Sarek Germline/Sarek_germline.svg @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/Sarek Somatic/Sarek_somatic.svg b/docs/images/logos/Sarek Somatic/Sarek_somatic.svg new file mode 100644 index 0000000000..75b75fc784 --- /dev/null +++ b/docs/images/logos/Sarek Somatic/Sarek_somatic.svg @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/Sarek/Sarek_color.svg b/docs/images/logos/Sarek/Sarek_color.svg new file mode 100644 index 0000000000..207b7297b8 --- /dev/null +++ b/docs/images/logos/Sarek/Sarek_color.svg @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/Sarek/Sarek_dark_color.svg b/docs/images/logos/Sarek/Sarek_dark_color.svg new file mode 100644 index 0000000000..914c3e7e51 --- /dev/null +++ b/docs/images/logos/Sarek/Sarek_dark_color.svg @@ -0,0 +1,393 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/Sarek/Sarek_dark_grey.svg b/docs/images/logos/Sarek/Sarek_dark_grey.svg new file mode 100644 index 0000000000..c000ed4b87 --- /dev/null +++ b/docs/images/logos/Sarek/Sarek_dark_grey.svg @@ -0,0 +1,401 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/Sarek/Sarek_dark_mono.svg b/docs/images/logos/Sarek/Sarek_dark_mono.svg new file mode 100644 index 0000000000..aab15bcd48 --- /dev/null +++ b/docs/images/logos/Sarek/Sarek_dark_mono.svg @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/Sarek/Sarek_grey.svg b/docs/images/logos/Sarek/Sarek_grey.svg new file mode 100644 index 0000000000..e78e5db9be --- /dev/null +++ b/docs/images/logos/Sarek/Sarek_grey.svg @@ -0,0 +1,409 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/Sarek/Sarek_mono.svg b/docs/images/logos/Sarek/Sarek_mono.svg new file mode 100644 index 0000000000..89d79dab16 --- /dev/null +++ b/docs/images/logos/Sarek/Sarek_mono.svg @@ -0,0 +1,390 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/nf-core-logo.svg b/docs/images/nf-core-logo.svg new file mode 100644 index 0000000000..2998cddb8e --- /dev/null +++ b/docs/images/nf-core-logo.svg @@ -0,0 +1,217 @@ + +image/svg+xmlnf- + + +core + + + \ No newline at end of file diff --git a/docs/images/nf-core_logo.png b/docs/images/nf-core_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a68747357dacc55d8368218b2adfe5a94e2ce97b GIT binary patch literal 7915 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 WqF`~=*n9xf08Ldrl{zK6nEwOJN?2q7 literal 0 HcmV?d00001 diff --git a/lib/SarekUtils.groovy b/lib/SarekUtils.groovy new file mode 100644 index 0000000000..b1a90bfcaa --- /dev/null +++ b/lib/SarekUtils.groovy @@ -0,0 +1,41 @@ +import static nextflow.Nextflow.file +import nextflow.Channel + +class SarekUtils { + + // Check parameter existence + static def checkParameterExistence(it, list) { + if (!list.contains(it)) { + println("Unknown parameter: ${it}") + return false + } + return true + } + + // Compare each parameter with a list of parameters + static def checkParameterList(list, realList) { + return list.every{ checkParameterExistence(it, realList) } + } + + // Loop through all the references files to check their existence + static def checkReferenceMap(referenceMap) { + referenceMap.every { + referenceFile, fileToCheck -> + SarekUtils.checkRefExistence(referenceFile, fileToCheck) + } + } + + // Loop through all the references files to check their existence + static def checkRefExistence(referenceFile, fileToCheck) { + if (fileToCheck instanceof List) return fileToCheck.every{ SarekUtils.checkRefExistence(referenceFile, it) } + def f = file(fileToCheck) + // this is an expanded wildcard: we can assume all files exist + if (f instanceof List && f.size() > 0) return true + else if (!f.exists()) { + println "Missing references: ${referenceFile} ${fileToCheck}" + return false + } + return true + } + +} diff --git a/main.nf b/main.nf index 42567aca5c..dc781271f2 100644 --- a/main.nf +++ b/main.nf @@ -4,12 +4,13 @@ nf-core/sarek ======================================================================================== nf-core/sarek Analysis Pipeline. - #### Homepage / Documentation - https://github.com/nf-core/sarek + @Homepage + https://sarek.scilifelab.se/ + @Documentation + https://github.com/nf-core/sarek/README.md ---------------------------------------------------------------------------------------- */ - def helpMessage() { // TODO nf-core: Add to this help message with new command line parameters log.info nfcoreHeader() @@ -49,7 +50,7 @@ def helpMessage() { * SET UP CONFIGURATION VARIABLES */ -// Show help emssage +// Show help message if (params.help){ helpMessage() exit 0 @@ -60,30 +61,29 @@ if (params.genomes && params.genome && !params.genomes.containsKey(params.genome exit 1, "The provided genome '${params.genome}' is not available in the iGenomes file. Currently the available genomes are ${params.genomes.keySet().join(", ")}" } -// TODO nf-core: Add any reference files that are needed -// Configurable reference genomes -fasta = params.genome ? params.genomes[ params.genome ].fasta ?: false : false -if ( params.fasta ){ - fasta = file(params.fasta) - if( !fasta.exists() ) exit 1, "Fasta file not found: ${params.fasta}" -} -// -// NOTE - THIS IS NOT USED IN THIS PIPELINE, EXAMPLE ONLY -// If you want to use the above in a process, define the following: -// input: -// file fasta from fasta -// +stepList = defineStepList() +step = params.step ? params.step.toLowerCase() : '' +if (step == 'preprocessing' || step == '') step = 'mapping' +if (!SarekUtils.checkParameterExistence(step, stepList)) exit 1, 'Unknown step, see --help for more information' +if (step.contains(',')) exit 1, 'You can choose only one step, see --help for more information' +if (step == 'mapping' && !checkExactlyOne([params.test, params.sample, params.sampleDir])) + exit 1, 'Please define which samples to work on by providing exactly one of the --test, --sample or --sampleDir options' + +tools = params.tools ? params.tools.split(',').collect{it.trim().toLowerCase()} : [] +toolList = defineToolList() +if (!SarekUtils.checkParameterList(tools,toolList)) exit 1, 'Unknown tool(s), see --help for more information' +referenceMap = defineReferenceMap(step, tools) +if (!SarekUtils.checkReferenceMap(referenceMap)) exit 1, 'Missing Reference file(s), see --help for more information' // Has the run name been specified by the user? // this has the bonus effect of catching both -name and --name custom_runName = params.name -if( !(workflow.runName ==~ /[a-z]+_[a-z]+/) ){ +if ( !(workflow.runName ==~ /[a-z]+_[a-z]+/) ){ custom_runName = workflow.runName } - -if( workflow.profile == 'awsbatch') { +if ( workflow.profile == 'awsbatch') { // AWSBatch sanity checking if (!params.awsqueue || !params.awsregion) exit 1, "Specify correct --awsqueue and --awsregion parameters on AWSBatch!" // Check outdir paths to be S3 buckets if running on AWSBatch @@ -100,53 +100,41 @@ ch_output_docs = Channel.fromPath("$baseDir/docs/output.md") /* * Create a channel for input read files */ -if(params.readPaths){ - if(params.singleEnd){ - Channel - .from(params.readPaths) - .map { row -> [ row[0], [file(row[1][0])]] } - .ifEmpty { exit 1, "params.readPaths was empty - no input files supplied" } - .into { read_files_fastqc; read_files_trimming } - } else { - Channel - .from(params.readPaths) - .map { row -> [ row[0], [file(row[1][0]), file(row[1][1])]] } - .ifEmpty { exit 1, "params.readPaths was empty - no input files supplied" } - .into { read_files_fastqc; read_files_trimming } - } -} else { - Channel - .fromFilePairs( params.reads, size: params.singleEnd ? 1 : 2 ) - .ifEmpty { exit 1, "Cannot find any reads matching: ${params.reads}\nNB: Path needs to be enclosed in quotes!\nIf this is single-end data, please specify --singleEnd on the command line." } - .into { read_files_fastqc; read_files_trimming } -} - + tsvPath = '' + if (params.sample) tsvPath = params.sample + + // No need for tsv file for step annotate + if (!params.sample && !params.sampleDir) { + tsvPaths = [ + 'mapping': "${workflow.projectDir}/Sarek-data/testdata/tsv/tiny.tsv", + 'recalibrate': "${params.outDir}/Preprocessing/DuplicateMarked/duplicateMarked.tsv", + 'variantcalling': "${params.outDir}/Preprocessing/Recalibrated/recalibrated.tsv" + ] + if (params.test || step != 'mapping') tsvPath = tsvPaths[step] + } // Header log info log.info nfcoreHeader() def summary = [:] -if(workflow.revision) summary['Pipeline Release'] = workflow.revision +if (workflow.revision) summary['Pipeline Release'] = workflow.revision summary['Run Name'] = custom_runName ?: workflow.runName // TODO nf-core: Report custom parameters here -summary['Reads'] = params.reads -summary['Fasta Ref'] = params.fasta -summary['Data Type'] = params.singleEnd ? 'Single-End' : 'Paired-End' summary['Max Resources'] = "$params.max_memory memory, $params.max_cpus cpus, $params.max_time time per job" -if(workflow.containerEngine) summary['Container'] = "$workflow.containerEngine - $workflow.container" +if (workflow.containerEngine) summary['Container'] = "$workflow.containerEngine - $workflow.container" summary['Output dir'] = params.outdir summary['Launch dir'] = workflow.launchDir summary['Working dir'] = workflow.workDir summary['Script dir'] = workflow.projectDir summary['User'] = workflow.userName -if(workflow.profile == 'awsbatch'){ +if (workflow.profile == 'awsbatch'){ summary['AWS Region'] = params.awsregion summary['AWS Queue'] = params.awsqueue } summary['Config Profile'] = workflow.profile -if(params.config_profile_description) summary['Config Description'] = params.config_profile_description -if(params.config_profile_contact) summary['Config Contact'] = params.config_profile_contact -if(params.config_profile_url) summary['Config URL'] = params.config_profile_url -if(params.email) { +if (params.config_profile_description) summary['Config Description'] = params.config_profile_description +if (params.config_profile_contact) summary['Config Contact'] = params.config_profile_contact +if (params.config_profile_url) summary['Config URL'] = params.config_profile_url +if (params.email) { summary['E-mail Address'] = params.email summary['MultiQC maxsize'] = params.maxMultiqcEmailFileSize } @@ -173,7 +161,6 @@ ${summary.collect { k,v -> "

$k
${v ?: ' filename.indexOf(".zip") > 0 ? "zips/$filename" : "$filename"} - - input: - set val(name), file(reads) from read_files_fastqc - - output: - file "*_fastqc.{zip,html}" into fastqc_results - - script: - """ - fastqc -q $reads - """ -} - - - -/* - * STEP 2 - MultiQC - */ -process multiqc { - publishDir "${params.outdir}/MultiQC", mode: 'copy' - - input: - file multiqc_config from ch_multiqc_config - // TODO nf-core: Add in log files from your new processes for MultiQC to find! - file ('fastqc/*') from fastqc_results.collect().ifEmpty([]) - file ('software_versions/*') from software_versions_yaml.collect() - file workflow_summary from create_workflow_summary(summary) - - output: - file "*multiqc_report.html" into multiqc_report - file "*_data" - file "multiqc_plots" - - script: - rtitle = custom_runName ? "--title \"$custom_runName\"" : '' - rfilename = custom_runName ? "--filename " + custom_runName.replaceAll('\\W','_').replaceAll('_+','_') + "_multiqc_report" : '' - // TODO nf-core: Specify which MultiQC modules to use with -m for a faster run time - """ - multiqc -f $rtitle $rfilename --config $multiqc_config . - """ -} - - - -/* - * STEP 3 - Output Description HTML - */ -process output_documentation { - publishDir "${params.outdir}/pipeline_info", mode: 'copy' - - input: - file output_docs from ch_output_docs - - output: - file "results_description.html" - - script: - """ - markdown_to_html.r $output_docs results_description.html - """ -} - - - /* * Completion e-mail notification */ @@ -279,7 +193,7 @@ workflow.onComplete { // Set up the e-mail variables def subject = "[nf-core/sarek] Successful: $workflow.runName" - if(!workflow.success){ + if (!workflow.success){ subject = "[nf-core/sarek] FAILED: $workflow.runName" } def email_fields = [:] @@ -298,10 +212,10 @@ workflow.onComplete { email_fields['summary']['Date Completed'] = workflow.complete email_fields['summary']['Pipeline script file path'] = workflow.scriptFile email_fields['summary']['Pipeline script hash ID'] = workflow.scriptId - if(workflow.repository) email_fields['summary']['Pipeline repository Git URL'] = workflow.repository - if(workflow.commitId) email_fields['summary']['Pipeline repository Git Commit'] = workflow.commitId - if(workflow.revision) email_fields['summary']['Pipeline Git branch/tag'] = workflow.revision - if(workflow.container) email_fields['summary']['Docker image'] = workflow.container + if (workflow.repository) email_fields['summary']['Pipeline repository Git URL'] = workflow.repository + if (workflow.commitId) email_fields['summary']['Pipeline repository Git Commit'] = workflow.commitId + if (workflow.revision) email_fields['summary']['Pipeline Git branch/tag'] = workflow.revision + if (workflow.container) email_fields['summary']['Docker image'] = workflow.container email_fields['summary']['Nextflow Version'] = workflow.nextflow.version email_fields['summary']['Nextflow Build'] = workflow.nextflow.build email_fields['summary']['Nextflow Compile Timestamp'] = workflow.nextflow.timestamp @@ -341,7 +255,7 @@ workflow.onComplete { // Send the HTML e-mail if (params.email) { try { - if( params.plaintext_email ){ throw GroovyException('Send plaintext e-mail, not HTML') } + if ( params.plaintext_email ){ throw GroovyException('Send plaintext e-mail, not HTML') } // Try to send HTML e-mail using sendmail [ 'sendmail', '-t' ].execute() << sendmail_html log.info "[nf-core/sarek] Sent summary e-mail to $params.email (sendmail)" @@ -354,7 +268,7 @@ workflow.onComplete { // Write summary e-mail HTML to a file def output_d = new File( "${params.outdir}/pipeline_info/" ) - if( !output_d.exists() ) { + if ( !output_d.exists() ) { output_d.mkdirs() } def output_hf = new File( output_d, "pipeline_report.html" ) @@ -373,7 +287,7 @@ workflow.onComplete { log.info "${c_green}Number of successfully ran process(es) : ${workflow.stats.succeedCountFmt} ${c_reset}" } - if(workflow.success){ + if (workflow.success){ log.info "${c_purple}[nf-core/sarek]${c_green} Pipeline completed successfully${c_reset}" } else { checkHostname() @@ -382,18 +296,17 @@ workflow.onComplete { } - def nfcoreHeader(){ // Log colors ANSI codes - c_reset = params.monochrome_logs ? '' : "\033[0m"; - c_dim = params.monochrome_logs ? '' : "\033[2m"; - c_black = params.monochrome_logs ? '' : "\033[0;30m"; - c_green = params.monochrome_logs ? '' : "\033[0;32m"; - c_yellow = params.monochrome_logs ? '' : "\033[0;33m"; - c_blue = params.monochrome_logs ? '' : "\033[0;34m"; + c_black = params.monochrome_logs ? '' : "\033[0;30m"; + c_blue = params.monochrome_logs ? '' : "\033[0;34m"; + c_cyan = params.monochrome_logs ? '' : "\033[0;36m"; + c_dim = params.monochrome_logs ? '' : "\033[2m"; + c_green = params.monochrome_logs ? '' : "\033[0;32m"; c_purple = params.monochrome_logs ? '' : "\033[0;35m"; - c_cyan = params.monochrome_logs ? '' : "\033[0;36m"; - c_white = params.monochrome_logs ? '' : "\033[0;37m"; + c_reset = params.monochrome_logs ? '' : "\033[0m"; + c_white = params.monochrome_logs ? '' : "\033[0;37m"; + c_yellow = params.monochrome_logs ? '' : "\033[0;33m"; return """ ${c_dim}----------------------------------------------------${c_reset} ${c_green},--.${c_black}/${c_green},-.${c_reset} @@ -401,6 +314,13 @@ def nfcoreHeader(){ ${c_blue} |\\ | |__ __ / ` / \\ |__) |__ ${c_yellow}} {${c_reset} ${c_blue} | \\| | \\__, \\__/ | \\ |___ ${c_green}\\`-._,-`-,${c_reset} ${c_green}`._,._,\'${c_reset} + ____ _____ _ + .' _ `. / ____| | | + / |\\`-_ \\ | (___ ___ _ __ __ | | __ + | | \\ `-| \\___ \\/__ \\| ´__/ _\\| |/ / + \\ | \\ / ____) | __ | | | __| < + `|____\\' |_____/\\____|_| \\__/|_|\\_\\ + ${c_purple} nf-core/sarek v${workflow.manifest.version}${c_reset} ${c_dim}----------------------------------------------------${c_reset} """.stripIndent() @@ -411,11 +331,11 @@ def checkHostname(){ def c_white = params.monochrome_logs ? '' : "\033[0;37m" def c_red = params.monochrome_logs ? '' : "\033[1;91m" def c_yellow_bold = params.monochrome_logs ? '' : "\033[1;93m" - if(params.hostnames){ + if (params.hostnames){ def hostname = "hostname".execute().text.trim() params.hostnames.each { prof, hnames -> hnames.each { hname -> - if(hostname.contains(hname) && !workflow.profile.contains(prof)){ + if (hostname.contains(hname) && !workflow.profile.contains(prof)){ log.error "====================================================\n" + " ${c_red}WARNING!${c_reset} You are running with `-profile $workflow.profile`\n" + " but your machine hostname is ${c_white}'$hostname'${c_reset}\n" + @@ -426,3 +346,70 @@ def checkHostname(){ } } } + +/* +======================================================================================== + sarek functions +======================================================================================== +*/ + +def checkParamReturnFile(item) { + params."${item}" = params.genomes[params.genome]."${item}" + return file(params."${item}") +} + +def checkExactlyOne(list) { + def n = 0 + list.each{n += it ? 1 : 0} + return n == 1 +} + +def defineReferenceMap(step, tools) { + def referenceMap = + [ + 'genomeDict' : checkParamReturnFile("genomeDict"), + 'genomeFile' : checkParamReturnFile("genomeFile"), + 'genomeIndex' : checkParamReturnFile("genomeIndex"), + 'intervals' : checkParamReturnFile("intervals") + ] + if ('mapping' in step) { + referenceMap.putAll( + 'bwaIndex' : checkParamReturnFile("bwaIndex"), + 'knownIndels' : checkParamReturnFile("knownIndels"), + 'knownIndelsIndex' : checkParamReturnFile("knownIndelsIndex") + ) + } + if ('ascat' in tools) { + referenceMap.putAll( + 'acLoci' : checkParamReturnFile("acLoci"), + 'acLociGC' : checkParamReturnFile("acLociGC") + ) + } + if ('mapping' in step || 'mutect2' in tools) { + referenceMap.putAll( + 'dbsnp' : checkParamReturnFile("dbsnp"), + 'dbsnpIndex' : checkParamReturnFile("dbsnpIndex") + ) + } + return referenceMap +} + +def defineStepList() { + return [ + 'mapping', + 'recalibrate', + 'variantcalling', + 'annotate' + ] +} + +def defineToolList() { + return [ + 'ascat', + 'freebayes', + 'haplotypecaller', + 'manta', + 'mutect2', + 'strelka' + ] +} diff --git a/nextflow.config b/nextflow.config index 283569be80..6e7ff7b57d 100644 --- a/nextflow.config +++ b/nextflow.config @@ -15,6 +15,11 @@ params { outdir = './results' // Boilerplate options + publishDirMode = 'symlink' + snpEff_cache = '' + cadd_version = '' + vep_cache = '' + genome = 'GRCh38' name = false multiqc_config = "$baseDir/assets/multiqc_config.yaml" email = false From 9780f0110dde18c7be729fd41edee76a6c9bdf17 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Wed, 1 May 2019 17:44:09 +0200 Subject: [PATCH 003/854] update README (#1) --- README.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4171c4be8e..3e52b0e833 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,13 @@ **An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing**. +> :warning: This pipeline is a work in progress being ported to nf-core from [SciLifeLab/Sarek](https://github/SciLifeLab/Sarek) + [![Nextflow version][nextflow-badge]](https://www.nextflow.io) [![Travis build status][travis-badge]](https://travis-ci.org/nf-core/sarek) [![Install with bioconda][bioconda-badge]](http://bioconda.github.io/) -[![Docker Container available][docker-badge]](https://hub.docker.com/r/nf-core/sarek) +[![Docker Container available][docker-badge]](https://hub.docker.com/r/nfcore/sarek) [![Join us on Slack][slack-badge]](https://nfcore.slack.com/messages/CGFUX04HZ/) @@ -136,8 +138,12 @@ For further information or help, don't hesitate to get in touch on [Slack](https [National Genomics Infrastructure logo][ngi-link] [National Bioinformatics Infrastructure Sweden logo][nbis-link] -[bioconda-badge]: https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg?style=popout&logo=data:image/png;base64,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 -[docker-badge]: https://img.shields.io/docker/automated/nf-core/sarek.svg?style=popout&logo=docker -[nextflow-badge]: https://img.shields.io/badge/nextflow-%E2%89%A519.04.0-brightgreen.svg?style=popout&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgd2lkdGg9IjEyLjc5OTIyOG1tIiAgIGhlaWdodD0iMTIuODA0ODA5bW0iICAgdmlld0JveD0iMCAwIDQ1LjM1MTU5NCA0NS4zNzEzNjkiICAgaWQ9InN2Zzc2NTIiICAgdmVyc2lvbj0iMS4xIiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTEgcjEzNzI1IiAgIHNvZGlwb2RpOmRvY25hbWU9Im5leHRmbG93LWZhdmljb24td2hpdGUuc3ZnIj4gIDxkZWZzICAgICBpZD0iZGVmczc2NTQiIC8+ICA8c29kaXBvZGk6bmFtZWR2aWV3ICAgICBpZD0iYmFzZSIgICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIgICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIgICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiICAgICBpbmtzY2FwZTp6b29tPSI3LjkxOTU5NTkiICAgICBpbmtzY2FwZTpjeD0iMjAuMTEzMjM1IiAgICAgaW5rc2NhcGU6Y3k9IjIzLjE2MzkwOCIgICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIgICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImxheWVyMSIgICAgIHNob3dncmlkPSJmYWxzZSIgICAgIGZpdC1tYXJnaW4tdG9wPSIwIiAgICAgZml0LW1hcmdpbi1sZWZ0PSIwIiAgICAgZml0LW1hcmdpbi1yaWdodD0iMCIgICAgIGZpdC1tYXJnaW4tYm90dG9tPSIwIiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxOTIwIiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTAxNSIgICAgIGlua3NjYXBlOndpbmRvdy14PSIwIiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjAiICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIiAvPiAgPG1ldGFkYXRhICAgICBpZD0ibWV0YWRhdGE3NjU3Ij4gICAgPHJkZjpSREY+ICAgICAgPGNjOldvcmsgICAgICAgICByZGY6YWJvdXQ9IiI+ICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4gICAgICAgIDxkYzp0eXBlICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+ICAgICAgPC9jYzpXb3JrPiAgICA8L3JkZjpSREY+ICA8L21ldGFkYXRhPiAgPGcgICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciIgICAgIGlkPSJsYXllcjEiICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMTQuMTA0MzcsLTQ1Mi41MzM2NikiPiAgICA8cGF0aCAgICAgICBzdHlsZT0iZmlsbDojZmZmZmZmIiAgICAgICBkPSJtIC0xMTQuMTA0MzcsNDU1LjQ2NTYyIDAsOC44NjEzMyAwLjIwMzEzLDAuMDYwNSBjIDMuODcyOTMsMS4xMzk0MyA4LjY1MjUxLDQuMzgzMiAxMi44MDA3OCw4LjY4NzUgMC45MTM2MywwLjk0ODAxIDEuOTcyNTY0LDIuMTA2ODQgMi4zNTM1MjQsMi41NzYxOCBsIDAuNjkxNCwwLjg1MzUxIC0wLjg2OTE0LDAuNzc1MzkgYyAtNC4xOTk5MDQsMy43NDE5MyAtOC45NzE5MDQsNi43NjYzNyAtMTQuMTA1NDc0LDguOTQxNDEgLTAuMzA5NzUsMC4xMzEyNCAtMC42OTcyMiwwLjI4MTIzIC0xLjA3NDIyLDAuNDI3NzMgbCAwLDkuMzA0NjkgYyAyLjY1OTkzLC0wLjg3NzkyIDUuMzA2MzksLTEuOTc1IDguMDYwNTUsLTMuMzUxNTYgNC4yNTYyMywtMi4xMjczMiA3LjU0MzI1NCwtNC4yNTc2NCAxMS4wMzcxMTQsLTcuMTU2MjUgMC45MjU4MSwtMC43NjgwOCAxLjgyMTA5LC0xLjUwNzAyIDEuOTkwMjMsLTEuNjQyNTggMC4yNzkzMSwtMC4yMjM4NCAwLjQ5MzMyLC0wLjA1MTQgMi4zMjQyMiwxLjg3ODkxIDYuMjIyNjUsNi41NjA0MSAxMy43ODMzNywxMC43NDQ0MyAyMS45Mzk0NiwxMi4yMjI2NSBsIDAsLTguOTQxNCBjIC00Ljc5NTM3LC0xLjE5NTkgLTkuNDIwMzEsLTMuNjQ1MTEgLTEzLjI1NzgyLC03LjA2NDQ2IC0xLjY4MzUxLC0xLjUwMDA2IC00LjI4NjgxLC00LjM1MDA5IC00LjM5MjU4LC00LjgwODU5IC0wLjA2ODYsLTAuMjk3MyA1LjQ3NDgsLTUuNzA5NzcgNy4yOTQ5MywtNy4xMjMwNSAzLjQ4MjczLC0yLjcwNDI0IDYuNTg4MjUsLTQuMTIwNDIgMTAuMjc1MzksLTQuNjg1NTQgMC4wMjc1LC0wLjAwNCAwLjA1MjcsLTAuMDA4IDAuMDgwMSwtMC4wMTE3IGwgMCwtOC43NSBjIC03LjkzOTI3LDIuMDIxMTQgLTE0Ljg3MDAxLDUuODc3MzggLTIxLjUsMTEuOTQzMzYgbCAtMS42MzA4NiwxLjQ5MjE4IC0yLjk5NjEsLTMuMDA3ODEgYyAtMS42NDc1NiwtMS42NTQ3IC0zLjc0MDI1LC0zLjYwMTU3IC00LjY1MjM0LC00LjMyNjE3IC01LjAwODU1NCwtMy45Nzg5OSAtMTAuMTUyOTU0LC02LjQ5OTIzIC0xNC41NzIyNzQsLTcuMTU2MjUgeiIgICAgICAgaWQ9InBhdGg3NjIwIiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY3NjY2NzY2Nzc2NzY2NzY3NjY2NjY2NzYyIgLz4gIDwvZz48L3N2Zz4= -[travis-badge]: https://img.shields.io/travis/nf-core/sarek.svg?style=popout&logo=travis -[slack-badge]: https://img.shields.io/badge/slack-nfcore/sarek-blue.svg?style=popout&logo=slack +[bioconda-badge]: https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg?logo=data:image/png;base64,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 +[btb-link]: https://ki.se/forskning/barntumorbanken-0 +[docker-badge]: https://img.shields.io/docker/automated/nfcore/sarek.svg?logo=docker +[nbis-link]: https://nbis.se +[nextflow-badge]: https://img.shields.io/badge/nextflow-%E2%89%A519.04.0-brightgreen.svg?logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgd2lkdGg9IjEyLjc5OTIyOG1tIiAgIGhlaWdodD0iMTIuODA0ODA5bW0iICAgdmlld0JveD0iMCAwIDQ1LjM1MTU5NCA0NS4zNzEzNjkiICAgaWQ9InN2Zzc2NTIiICAgdmVyc2lvbj0iMS4xIiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTEgcjEzNzI1IiAgIHNvZGlwb2RpOmRvY25hbWU9Im5leHRmbG93LWZhdmljb24td2hpdGUuc3ZnIj4gIDxkZWZzICAgICBpZD0iZGVmczc2NTQiIC8+ICA8c29kaXBvZGk6bmFtZWR2aWV3ICAgICBpZD0iYmFzZSIgICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIgICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIgICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiICAgICBpbmtzY2FwZTp6b29tPSI3LjkxOTU5NTkiICAgICBpbmtzY2FwZTpjeD0iMjAuMTEzMjM1IiAgICAgaW5rc2NhcGU6Y3k9IjIzLjE2MzkwOCIgICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIgICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImxheWVyMSIgICAgIHNob3dncmlkPSJmYWxzZSIgICAgIGZpdC1tYXJnaW4tdG9wPSIwIiAgICAgZml0LW1hcmdpbi1sZWZ0PSIwIiAgICAgZml0LW1hcmdpbi1yaWdodD0iMCIgICAgIGZpdC1tYXJnaW4tYm90dG9tPSIwIiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxOTIwIiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTAxNSIgICAgIGlua3NjYXBlOndpbmRvdy14PSIwIiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjAiICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIiAvPiAgPG1ldGFkYXRhICAgICBpZD0ibWV0YWRhdGE3NjU3Ij4gICAgPHJkZjpSREY+ICAgICAgPGNjOldvcmsgICAgICAgICByZGY6YWJvdXQ9IiI+ICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4gICAgICAgIDxkYzp0eXBlICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+ICAgICAgPC9jYzpXb3JrPiAgICA8L3JkZjpSREY+ICA8L21ldGFkYXRhPiAgPGcgICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciIgICAgIGlkPSJsYXllcjEiICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMTQuMTA0MzcsLTQ1Mi41MzM2NikiPiAgICA8cGF0aCAgICAgICBzdHlsZT0iZmlsbDojZmZmZmZmIiAgICAgICBkPSJtIC0xMTQuMTA0MzcsNDU1LjQ2NTYyIDAsOC44NjEzMyAwLjIwMzEzLDAuMDYwNSBjIDMuODcyOTMsMS4xMzk0MyA4LjY1MjUxLDQuMzgzMiAxMi44MDA3OCw4LjY4NzUgMC45MTM2MywwLjk0ODAxIDEuOTcyNTY0LDIuMTA2ODQgMi4zNTM1MjQsMi41NzYxOCBsIDAuNjkxNCwwLjg1MzUxIC0wLjg2OTE0LDAuNzc1MzkgYyAtNC4xOTk5MDQsMy43NDE5MyAtOC45NzE5MDQsNi43NjYzNyAtMTQuMTA1NDc0LDguOTQxNDEgLTAuMzA5NzUsMC4xMzEyNCAtMC42OTcyMiwwLjI4MTIzIC0xLjA3NDIyLDAuNDI3NzMgbCAwLDkuMzA0NjkgYyAyLjY1OTkzLC0wLjg3NzkyIDUuMzA2MzksLTEuOTc1IDguMDYwNTUsLTMuMzUxNTYgNC4yNTYyMywtMi4xMjczMiA3LjU0MzI1NCwtNC4yNTc2NCAxMS4wMzcxMTQsLTcuMTU2MjUgMC45MjU4MSwtMC43NjgwOCAxLjgyMTA5LC0xLjUwNzAyIDEuOTkwMjMsLTEuNjQyNTggMC4yNzkzMSwtMC4yMjM4NCAwLjQ5MzMyLC0wLjA1MTQgMi4zMjQyMiwxLjg3ODkxIDYuMjIyNjUsNi41NjA0MSAxMy43ODMzNywxMC43NDQ0MyAyMS45Mzk0NiwxMi4yMjI2NSBsIDAsLTguOTQxNCBjIC00Ljc5NTM3LC0xLjE5NTkgLTkuNDIwMzEsLTMuNjQ1MTEgLTEzLjI1NzgyLC03LjA2NDQ2IC0xLjY4MzUxLC0xLjUwMDA2IC00LjI4NjgxLC00LjM1MDA5IC00LjM5MjU4LC00LjgwODU5IC0wLjA2ODYsLTAuMjk3MyA1LjQ3NDgsLTUuNzA5NzcgNy4yOTQ5MywtNy4xMjMwNSAzLjQ4MjczLC0yLjcwNDI0IDYuNTg4MjUsLTQuMTIwNDIgMTAuMjc1MzksLTQuNjg1NTQgMC4wMjc1LC0wLjAwNCAwLjA1MjcsLTAuMDA4IDAuMDgwMSwtMC4wMTE3IGwgMCwtOC43NSBjIC03LjkzOTI3LDIuMDIxMTQgLTE0Ljg3MDAxLDUuODc3MzggLTIxLjUsMTEuOTQzMzYgbCAtMS42MzA4NiwxLjQ5MjE4IC0yLjk5NjEsLTMuMDA3ODEgYyAtMS42NDc1NiwtMS42NTQ3IC0zLjc0MDI1LC0zLjYwMTU3IC00LjY1MjM0LC00LjMyNjE3IC01LjAwODU1NCwtMy45Nzg5OSAtMTAuMTUyOTU0LC02LjQ5OTIzIC0xNC41NzIyNzQsLTcuMTU2MjUgeiIgICAgICAgaWQ9InBhdGg3NjIwIiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY3NjY2NzY2Nzc2NzY2NzY3NjY2NjY2NzYyIgLz4gIDwvZz48L3N2Zz4= +[ngi-link]: https://ngisweden.scilifelab.se/ +[scilifelab-link]: https://scilifelab.se +[slack-badge]: https://img.shields.io/badge/slack-nfcore/sarek-blue.svg?logo=slack +[travis-badge]: https://img.shields.io/travis/nf-core/sarek.svg?logo=travis From c1d03376660ed1cd98599f514eed04415fdbed1d Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Wed, 1 May 2019 18:00:38 +0200 Subject: [PATCH 004/854] More fixes (#2) - update README - update `.travis.yml` - add `Jenkinsfile` - update conda `environment.yml` file --- .travis.yml | 4 ++-- Jenkinsfile | 35 +++++++++++++++++++++++++++++++++++ environment.yml | 21 ++++++++++++++++++++- 3 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 Jenkinsfile diff --git a/.travis.yml b/.travis.yml index fa72533100..e736da2a64 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,10 +11,10 @@ before_install: # PRs to master are only ok if coming from dev branch - '[ $TRAVIS_PULL_REQUEST = "false" ] || [ $TRAVIS_BRANCH != "master" ] || ([ $TRAVIS_PULL_REQUEST_SLUG = $TRAVIS_REPO_SLUG ] && [ $TRAVIS_PULL_REQUEST_BRANCH = "dev" ])' # Pull the docker image first so the test doesn't wait for this - - docker pull maxulysse/sarek:dev + - docker pull nfcore/sarek:dev # Fake the tag locally so that the pipeline runs properly # Looks weird when this is :dev to :dev, but makes sense when testing code for a release (:dev to :1.0.1) - - docker tag maxulysse/sarek:dev maxulysse/sarek:dev + - docker tag nfcore/sarek:dev nfcore/sarek:dev install: # Install Nextflow diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000000..b54e5c7deb --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,35 @@ +pipeline { + agent any + + environment { + JENKINS_API = credentials('api') + } + + stages { + stage('Setup environment') { + steps { + sh "docker pull nfcore/sarek:dev" + } + } + stage('Build') { + steps { + sh "git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git test-data" + sh "nextflow run build.nf -profile docker --genome smallGRCh37 --refdir test-data/reference --outdir References" + } + } + stage('Test') { + steps { + sh "nextflow run main.nf -profile docker --help" + } + } + } + + post { + failure { + script { + def response = sh(script: "curl -u ${JENKINS_API_USR}:${JENKINS_API_PSW} ${BUILD_URL}/consoleText", returnStdout: true).trim().replace('\n', '
') + def comment = pullRequest.comment("## :rotating_light: Buil log output:
${response}
") + } + } + } +} diff --git a/environment.yml b/environment.yml index 4e6811ec55..dcdbe97d7d 100644 --- a/environment.yml +++ b/environment.yml @@ -6,6 +6,25 @@ channels: - bioconda - defaults dependencies: - # TODO nf-core: Add required software dependencies here + - r-rcolorbrewer=1.1 + - r-base=3.5.1 + - bcftools=1.9 + - bioconductor-rtracklayer=1.42.1 + - bwa=0.7.17 + - cancerit-allelecount=2.1.2 + - control-freec=11.4 + - ensembl-vep=96.0 - fastqc=0.11.8 + - freebayes=1.2.0 + - gatk4=4.1.1.0 + - genesplicer=1.0 + - htslib=1.9 + - igvtools=2.3.93 + - manta=1.5.0 - multiqc=1.7 + - qualimap=2.2.2b + - samtools=1.9 + - snpeff=4.3.1t + - strelka=2.9.10 + - vcfanno=0.3.1 + - vcftools=0.1.16 From c46c460191ef831293e029330afc91ba1c0340c4 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Thu, 2 May 2019 16:58:26 +0200 Subject: [PATCH 005/854] Include preprocessing (#3) * update README * update .travis.yml * add Jenkinsfile * update conda environment file * update software_version collect * remove lib/SarekUtils.groovy * add References to .gitignore * improve software versions gathering * fix docker owner * update tests * sort params * add preprocessing * improve multiple TSV * add parrallelized BaseRecalibrator --- .gitignore | 1 + .travis.yml | 30 +- Jenkinsfile | 13 +- bin/scrape_software_versions.py | 34 +- conf/base.config | 7 +- lib/SarekUtils.groovy | 41 -- main.nf | 723 ++++++++++++++++++++++++++++++-- nextflow.config | 8 +- 8 files changed, 759 insertions(+), 98 deletions(-) delete mode 100644 lib/SarekUtils.groovy diff --git a/.gitignore b/.gitignore index 5b54e3e6c2..96675d0154 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .nextflow* work/ data/ +references/ results/ .DS_Store tests/test_data diff --git a/.travis.yml b/.travis.yml index e736da2a64..01d73056b2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,18 +2,26 @@ sudo: required language: python jdk: openjdk8 services: docker + +addons: + apt: + update: true + python: '3.6' cache: pip + matrix: fast_finish: true +env: + - NXF_VER=19.04.0 + before_install: # PRs to master are only ok if coming from dev branch - '[ $TRAVIS_PULL_REQUEST = "false" ] || [ $TRAVIS_BRANCH != "master" ] || ([ $TRAVIS_PULL_REQUEST_SLUG = $TRAVIS_REPO_SLUG ] && [ $TRAVIS_PULL_REQUEST_BRANCH = "dev" ])' # Pull the docker image first so the test doesn't wait for this - docker pull nfcore/sarek:dev # Fake the tag locally so that the pipeline runs properly - # Looks weird when this is :dev to :dev, but makes sense when testing code for a release (:dev to :1.0.1) - docker tag nfcore/sarek:dev nfcore/sarek:dev install: @@ -21,22 +29,10 @@ install: - mkdir /tmp/nextflow && cd /tmp/nextflow - wget -qO- get.nextflow.io | bash - sudo ln -s /tmp/nextflow/nextflow /usr/local/bin/nextflow - # Install nf-core/tools - - pip install --upgrade pip - - pip install nf-core # Reset - mkdir ${TRAVIS_BUILD_DIR}/tests && cd ${TRAVIS_BUILD_DIR}/tests -env: - - NXF_VER=19.04.0 - -jobs: - include: - - stage: lint - script: nf-core lint ${TRAVIS_BUILD_DIR} - - stage: built - script: skip - script: git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git test-data - script: nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile docker --genome smallGRCh37 --refdir test-data/reference --outdir References - - stage: test - script: nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile docker --help +script: + - git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data + - nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile docker --genome smallGRCh37 --refdir data/reference --outdir references --publishDirMode link --max_memory 7.GB --max_cpus 2 + - nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile docker --genome smallGRCh37 --igenomes_base references --sampleDir data/testdata/tiny/normal --publishDirMode link --max_memory 7.GB --max_cpus 2 diff --git a/Jenkinsfile b/Jenkinsfile index b54e5c7deb..7ba61ecfee 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -13,13 +13,18 @@ pipeline { } stage('Build') { steps { - sh "git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git test-data" - sh "nextflow run build.nf -profile docker --genome smallGRCh37 --refdir test-data/reference --outdir References" + sh "git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data" + sh "nextflow run build.nf -profile docker --genome smallGRCh37 --refdir data/reference --outdir references --publishDirMode link" } } - stage('Test') { + stage('SampleDir') { steps { - sh "nextflow run main.nf -profile docker --help" + sh "nextflow run main.nf -profile docker --genome smallGRCh37 --igenomes_base references --sampleDir data/testdata/tiny/normal --publishDirMode link" + } + } + stage('Multiple') { + steps { + sh "nextflow run main.nf -profile docker --genome smallGRCh37 --igenomes_base references --sample data/testdata/tsv/tiny-multiple.tsv --publishDirMode link" } } } diff --git a/bin/scrape_software_versions.py b/bin/scrape_software_versions.py index 0cb269ad8c..5667cd24c8 100755 --- a/bin/scrape_software_versions.py +++ b/bin/scrape_software_versions.py @@ -5,16 +5,46 @@ # TODO nf-core: Add additional regexes for new tools in process get_software_versions regexes = { - 'nf-core/sarek': ['v_pipeline.txt', r"(\S+)"], - 'Nextflow': ['v_nextflow.txt', r"(\S+)"], + 'AlleleCount': ['v_allelecount.txt', r"(\S+)"], + 'ASCAT': ['v_ascat.txt', r"(\d\.\d+)"], + 'bcftools': ['v_bcftools.txt', r"bcftools (\S+)"], + 'BWA': ['v_bwa.txt', r"Version: (\S+)"], 'FastQC': ['v_fastqc.txt', r"FastQC v(\S+)"], + 'FreeBayes': ['v_freebayes.txt', r"version: v(\d\.\d\.\d+)"], + 'GATK': ['v_gatk.txt', r"Version:(\S+)"], + 'htslib': ['v_samtools.txt', r"htslib (\S+)"], + 'Manta': ['v_manta.txt', r"([0-9.]+)"], 'MultiQC': ['v_multiqc.txt', r"multiqc, version (\S+)"], + 'Nextflow': ['v_nextflow.txt', r"(\S+)"], + 'nf-core/sarek': ['v_pipeline.txt', r"(\S+)"], + 'Qualimap': ['v_qualimap.txt', r"QualiMap v.(\S+)"], + 'R': ['v_r.txt', r"R version (\S+)"], + 'samtools': ['v_samtools.txt', r"samtools (\S+)"], + 'SnpEff': ['v_snpeff.txt', r"version SnpEff (\S+)"], + 'Strelka': ['v_strelka.txt', r"([0-9.]+)"], + 'vcftools': ['v_vcftools.txt', r"([0-9.]+)"], + 'VEP': ['v_vep.txt', r"ensembl-vep : (\S+)"], } results = OrderedDict() results['nf-core/sarek'] = 'N/A' results['Nextflow'] = 'N/A' +results['AlleleCount'] = 'N/A' +results['ASCAT'] = 'N/A' +results['bcftools'] = 'N/A' +results['BWA'] = 'N/A' results['FastQC'] = 'N/A' +results['FreeBayes'] = 'N/A' +results['GATK'] = 'N/A' +results['htslib'] = 'N/A' +results['Manta'] = 'N/A' results['MultiQC'] = 'N/A' +results['Qualimap'] = 'N/A' +results['R'] = 'N/A' +results['samtools'] = 'N/A' +results['SnpEff'] = 'N/A' +results['Strelka'] = 'N/A' +results['vcftools'] = 'N/A' +results['VEP'] = 'N/A' # Search each file using its regex for k, v in regexes.items(): diff --git a/conf/base.config b/conf/base.config index bb54f1e010..14c8f70aef 100644 --- a/conf/base.config +++ b/conf/base.config @@ -17,8 +17,8 @@ process { time = { check_max( 2.h * task.attempt, 'time' ) } errorStrategy = { task.exitStatus in [143,137,104,134,139] ? 'retry' : 'finish' } - maxRetries = 1 maxErrors = '-1' + maxRetries = 1 // Process-specific resource requirements // TODO nf-core: Customise requirements for specific processes. @@ -27,8 +27,9 @@ process { params { // Defaults only, expecting to be overwritten - max_memory = 128.GB + igenomes_base = 's3://ngi-igenomes/igenomes/' + markdup_java_options = '"-Xms4000m -Xmx7g"' //Established values for markDuplicate memory consumption, see issue PR #689 for details max_cpus = 16 + max_memory = 128.GB max_time = 240.h - igenomes_base = 's3://ngi-igenomes/igenomes/' } diff --git a/lib/SarekUtils.groovy b/lib/SarekUtils.groovy deleted file mode 100644 index b1a90bfcaa..0000000000 --- a/lib/SarekUtils.groovy +++ /dev/null @@ -1,41 +0,0 @@ -import static nextflow.Nextflow.file -import nextflow.Channel - -class SarekUtils { - - // Check parameter existence - static def checkParameterExistence(it, list) { - if (!list.contains(it)) { - println("Unknown parameter: ${it}") - return false - } - return true - } - - // Compare each parameter with a list of parameters - static def checkParameterList(list, realList) { - return list.every{ checkParameterExistence(it, realList) } - } - - // Loop through all the references files to check their existence - static def checkReferenceMap(referenceMap) { - referenceMap.every { - referenceFile, fileToCheck -> - SarekUtils.checkRefExistence(referenceFile, fileToCheck) - } - } - - // Loop through all the references files to check their existence - static def checkRefExistence(referenceFile, fileToCheck) { - if (fileToCheck instanceof List) return fileToCheck.every{ SarekUtils.checkRefExistence(referenceFile, it) } - def f = file(fileToCheck) - // this is an expanded wildcard: we can assume all files exist - if (f instanceof List && f.size() > 0) return true - else if (!f.exists()) { - println "Missing references: ${referenceFile} ${fileToCheck}" - return false - } - return true - } - -} diff --git a/main.nf b/main.nf index dc781271f2..a554c41a65 100644 --- a/main.nf +++ b/main.nf @@ -3,6 +3,8 @@ ======================================================================================== nf-core/sarek ======================================================================================== +New Germline (+ Somatic) Analysis Workflow. Started March 2016. +---------------------------------------------------------------------------------------- nf-core/sarek Analysis Pipeline. @Homepage https://sarek.scilifelab.se/ @@ -20,16 +22,15 @@ def helpMessage() { The typical command for running the pipeline is as follows: - nextflow run nf-core/sarek --reads '*_R{1,2}.fastq.gz' -profile docker + nextflow run nf-core/sarek --sample sample.tsv -profile docker Mandatory arguments: - --reads Path to input data (must be surrounded with quotes) + --sample Path to TSV input file -profile Configuration profile to use. Can use multiple (comma separated) Available: conda, docker, singularity, awsbatch, test and more. Options: --genome Name of iGenomes reference - --singleEnd Specifies that the input is single end reads References If not specified in the configuration file or you wish to overwrite any of the references. --fasta Path to Fasta reference @@ -61,20 +62,30 @@ if (params.genomes && params.genome && !params.genomes.containsKey(params.genome exit 1, "The provided genome '${params.genome}' is not available in the iGenomes file. Currently the available genomes are ${params.genomes.keySet().join(", ")}" } +params.noReports = false +params.nucleotidesPerSecond = 1000.0 +params.sampleDir = false +params.sample = false +params.sequencing_center = null +params.step = 'mapping' +params.targetBED = null +params.test = false +params.tools = false + stepList = defineStepList() step = params.step ? params.step.toLowerCase() : '' if (step == 'preprocessing' || step == '') step = 'mapping' -if (!SarekUtils.checkParameterExistence(step, stepList)) exit 1, 'Unknown step, see --help for more information' +if (!checkParameterExistence(step, stepList)) exit 1, 'Unknown step, see --help for more information' if (step.contains(',')) exit 1, 'You can choose only one step, see --help for more information' -if (step == 'mapping' && !checkExactlyOne([params.test, params.sample, params.sampleDir])) +if (step == 'mapping' && ([params.test, params.sample, params.sampleDir].size == 1)) exit 1, 'Please define which samples to work on by providing exactly one of the --test, --sample or --sampleDir options' tools = params.tools ? params.tools.split(',').collect{it.trim().toLowerCase()} : [] toolList = defineToolList() -if (!SarekUtils.checkParameterList(tools,toolList)) exit 1, 'Unknown tool(s), see --help for more information' +if (!checkParameterList(tools,toolList)) exit 1, 'Unknown tool(s), see --help for more information' referenceMap = defineReferenceMap(step, tools) -if (!SarekUtils.checkReferenceMap(referenceMap)) exit 1, 'Missing Reference file(s), see --help for more information' +if (!checkReferenceMap(referenceMap)) exit 1, 'Missing Reference file(s), see --help for more information' // Has the run name been specified by the user? // this has the bonus effect of catching both -name and --name @@ -107,12 +118,37 @@ ch_output_docs = Channel.fromPath("$baseDir/docs/output.md") if (!params.sample && !params.sampleDir) { tsvPaths = [ 'mapping': "${workflow.projectDir}/Sarek-data/testdata/tsv/tiny.tsv", - 'recalibrate': "${params.outDir}/Preprocessing/DuplicateMarked/duplicateMarked.tsv", - 'variantcalling': "${params.outDir}/Preprocessing/Recalibrated/recalibrated.tsv" + 'recalibrate': "${params.outdir}/Preprocessing/TSV/duplicateMarked.tsv", + 'variantcalling': "${params.outdir}/Preprocessing/TSV/recalibrated.tsv" ] if (params.test || step != 'mapping') tsvPath = tsvPaths[step] } + // Set up the inputFiles and bamFiles channels. One of them will remain empty + inputFiles = Channel.empty() + bamFiles = Channel.empty() + if (tsvPath) { + tsvFile = file(tsvPath) + switch (step) { + case 'mapping': inputFiles = extractSample(tsvFile); break + case 'recalibrate': bamFiles = extractRecal(tsvFile); break + default: exit 1, "Unknown step ${step}" + } + } else if (params.sampleDir) { + if (step != 'mapping') exit 1, '--sampleDir does not support steps other than "mapping"' + inputFiles = extractFastqFromDir(params.sampleDir) + (inputFiles, fastqTmp) = inputFiles.into(2) + fastqTmp.toList().subscribe onNext: { + if (it.size() == 0) { + exit 1, "No FASTQ files found in --sampleDir directory '${params.sampleDir}'" + } + } + tsvFile = params.sampleDir // used in the reports + } else exit 1, 'No sample were defined, see --help' + + if (step == 'recalibrate') (patientGenders, bamFiles) = extractGenders(bamFiles) + else (patientGenders, inputFiles) = extractGenders(inputFiles) + // Header log info log.info nfcoreHeader() def summary = [:] @@ -165,27 +201,479 @@ ${summary.collect { k,v -> "
$k
${v ?: ' - if (filename.indexOf(".csv") > 0) filename - else null - } + publishDir path:"${params.outdir}/pipeline_info", mode: params.publishDirMode output: file 'software_versions_mqc.yaml' into software_versions_yaml - file "software_versions.csv" script: - // TODO nf-core: Get all tools to print their version number here """ - echo $workflow.manifest.version > v_pipeline.txt - echo $workflow.nextflow.version > v_nextflow.txt - fastqc --version > v_fastqc.txt - multiqc --version > v_multiqc.txt + alleleCounter --version &> v_allelecount.txt || true + bcftools version > v_bcftools.txt 2>&1 || true + bwa &> v_bwa.txt 2>&1 || true + cat ${baseDir}/scripts/ascat.R | grep "ASCAT version" &> v_ascat.txt || true + configManta.py --version > v_manta.txt 2>&1 || true + configureStrelkaGermlineWorkflow.py --version > v_strelka.txt 2>&1 || true + echo "${workflow.manifest.version}" &> v_pipeline.txt 2>&1 || true + echo "${workflow.nextflow.version}" &> v_nextflow.txt 2>&1 || true + echo "SNPEFF version"\$(snpEff -h 2>&1) > v_snpeff.txt + fastqc --version > v_fastqc.txt 2>&1 || true + freebayes --version > v_freebayes.txt 2>&1 || true + gatk ApplyBQSR --help 2>&1 | grep Version: > v_gatk.txt 2>&1 || true + multiqc --version &> v_multiqc.txt 2>&1 || true + qualimap --version &> v_qualimap.txt 2>&1 || true + R --version &> v_r.txt || true + samtools --version &> v_samtools.txt 2>&1 || true + vcftools --version &> v_vcftools.txt 2>&1 || true + vep --help &> v_vep.txt 2>&1 || true + scrape_software_versions.py &> software_versions_mqc.yaml """ } +/* +======================================================================================== + PREPROCESSING +======================================================================================== +*/ + +// STEP ONE: MAPPING + +(inputFiles, inputFilesforFastQC) = inputFiles.into(2) + +inputFiles = inputFiles.dump(tag:'INPUT') + +process RunFastQC { + tag {idPatient + "-" + idRun} + + publishDir "${params.outdir}/Reports/${idSample}/FastQC/${idRun}", mode: params.publishDirMode + + input: + set idPatient, status, idSample, idRun, file(inputFile1), file(inputFile2) from inputFilesforFastQC + + output: + file "*_fastqc.{zip,html}" into fastQCreport + + when: step == 'mapping' && !params.noReports + + script: + inputFiles = (hasExtension(inputFile1,"fastq.gz") || hasExtension(inputFile1,"fq.gz")) ? "${inputFile1} ${inputFile2}" : "${inputFile1}" + """ + fastqc -t 2 -q ${inputFiles} + """ +} + +fastQCreport.dump(tag:'FastQC') + +process MapReads { + tag {idPatient + "-" + idRun} + + input: + set idPatient, status, idSample, idRun, file(inputFile1), file(inputFile2) from inputFiles + set file(genomeFile), file(bwaIndex) from Channel.value([referenceMap.genomeFile, referenceMap.bwaIndex]) + + output: + set idPatient, status, idSample, idRun, file("${idRun}.bam") into (mappedBam, mappedBamForQC) + + when: step == 'mapping' + + script: + CN = params.sequencing_center ? "CN:${params.sequencing_center}\\t" : "" + readGroup = "@RG\\tID:${idRun}\\t${CN}PU:${idRun}\\tSM:${idSample}\\tLB:${idSample}\\tPL:illumina" + // adjust mismatch penalty for tumor samples + extra = status == 1 ? "-B 3" : "" + if (hasExtension(inputFile1,"fastq.gz") || hasExtension(inputFile1,"fq.gz")) + """ + bwa mem -K 100000000 -R \"${readGroup}\" ${extra} -t ${task.cpus} -M \ + ${genomeFile} ${inputFile1} ${inputFile2} | \ + samtools sort --threads ${task.cpus} -m 2G - > ${idRun}.bam + """ + else if (hasExtension(inputFile1,"bam")) + // -K is an hidden option, used to fix the number of reads processed by bwa mem + // Chunk size can affect bwa results, if not specified, the number of threads can change + // which can give not deterministic result. + // cf https://github.com/CCDG/Pipeline-Standardization/blob/master/PipelineStandard.md + // and https://github.com/gatk-workflows/gatk4-data-processing/blob/8ffa26ff4580df4ac3a5aa9e272a4ff6bab44ba2/processing-for-variant-discovery-gatk4.b37.wgs.inputs.json#L29 + """ + gatk --java-options -Xmx${task.memory.toGiga()}g \ + SamToFastq \ + --INPUT=${inputFile1} \ + --FASTQ=/dev/stdout \ + --INTERLEAVE=true \ + --NON_PF=true \ + | \ + bwa mem -K 100000000 -p -R \"${readGroup}\" ${extra} -t ${task.cpus} -M ${genomeFile} \ + /dev/stdin - 2> >(tee ${inputFile1}.bwa.stderr.log >&2) \ + | \ + samtools sort --threads ${task.cpus} -m 2G - > ${idRun}.bam + """ +} + +mappedBam = mappedBam.dump(tag:'Mapped BAM') + +process RunBamQCmapped { + tag {idPatient + "-" + idSample} + + publishDir "${params.outdir}/Reports/${idSample}/bamQC", mode: params.publishDirMode + + input: + set idPatient, status, idSample, idRun, file(bam) from mappedBamForQC + file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") + + output: + file("${bam.baseName}") into bamQCmappedReport + + when: !params.noReports + + script: + use_bed = params.targetBED ? "-gff ${targetBED}" : '' + """ + qualimap --java-mem-size=${task.memory.toGiga()}G \ + bamqc \ + -bam ${bam} \ + --paint-chromosome-limits \ + --genome-gc-distr HUMAN \ + $use_bed \ + -nt ${task.cpus} \ + -skip-duplicated \ + --skip-dup-mode 0 \ + -outdir ${bam.baseName} \ + -outformat HTML + """ +} + +bamQCmappedReport.dump(tag:'BamQC BAM') + +// Sort bam whether they are standalone or should be merged + +singleBam = Channel.create() +groupedBam = Channel.create() +mappedBam.groupTuple(by:[0,1,2]) + .choice(singleBam, groupedBam) {it[3].size() > 1 ? 1 : 0} +singleBam = singleBam.map { + idPatient, status, idSample, idRun, bam -> + [idPatient, status, idSample, bam] +} + +process MergeBams { + tag {idPatient + "-" + idSample} + + input: + set idPatient, status, idSample, idRun, file(bam) from groupedBam + + output: + set idPatient, status, idSample, file("${idSample}.bam") into mergedBam + + when: step == 'mapping' + + script: + """ + samtools merge --threads ${task.cpus} ${idSample}.bam ${bam} + """ +} + +singleBam = singleBam.dump(tag:'Single BAM') +mergedBam = mergedBam.dump(tag:'Merged BAM') +mergedBam = mergedBam.mix(singleBam) +mergedBam = mergedBam.dump(tag:'BAM for MD') + +process MarkDuplicates { + tag {idPatient + "-" + idSample} + + publishDir params.outdir, mode: params.publishDirMode, + saveAs: { + if (it == "${idSample}.bam.metrics") "Reports/${idSample}/MarkDuplicates/${it}" + else "Preprocessing/${idSample}/DuplicateMarked/${it}" + } + + input: + set idPatient, status, idSample, file("${idSample}.bam") from mergedBam + + output: + set idPatient, file("${idSample}_${status}.md.bam"), file("${idSample}_${status}.md.bai") into duplicateMarkedBams + file ("${idSample}.bam.metrics") into markDuplicatesReport + + when: step == 'mapping' + + script: + markdup_java_options = task.memory.toGiga() > 8 ? params.markdup_java_options : "\"-Xms" + (task.memory.toGiga() / 2 ).trunc() + "g -Xmx" + (task.memory.toGiga() - 1) + "g\"" + """ + gatk --java-options ${markdup_java_options} \ + MarkDuplicates \ + --MAX_RECORDS_IN_RAM 50000 \ + --INPUT ${idSample}.bam \ + --METRICS_FILE ${idSample}.bam.metrics \ + --TMP_DIR . \ + --ASSUME_SORT_ORDER coordinate \ + --CREATE_INDEX true \ + --OUTPUT ${idSample}_${status}.md.bam + """ +} + +duplicateMarkedBams = duplicateMarkedBams.map { + idPatient, bam, bai -> + tag = bam.baseName.tokenize('.')[0] + status = tag[-1..-1].toInteger() + idSample = tag.take(tag.length()-2) + [idPatient, status, idSample, bam, bai] +} + +duplicateMarkedBams = duplicateMarkedBams.dump(tag:'MD BAM') + +(mdBam, mdBamToJoin) = duplicateMarkedBams.into(2) + +process CreateIntervalBeds { + tag {intervals.fileName} + + input: + file(intervals) from Channel.value(referenceMap.intervals) + + output: + file '*.bed' into bedIntervals mode flatten + + script: + // If the interval file is BED format, the fifth column is interpreted to + // contain runtime estimates, which is then used to combine short-running jobs + if (hasExtension(intervals,"bed")) + """ + awk -vFS="\t" '{ + t = \$5 # runtime estimate + if (t == "") { + # no runtime estimate in this row, assume default value + t = (\$3 - \$2) / ${params.nucleotidesPerSecond} + } + if (name == "" || (chunk > 600 && (chunk + t) > longest * 1.05)) { + # start a new chunk + name = sprintf("%s_%d-%d.bed", \$1, \$2+1, \$3) + chunk = 0 + longest = 0 + } + if (t > longest) + longest = t + chunk += t + print \$0 > name + }' ${intervals} + """ + else + """ + awk -vFS="[:-]" '{ + name = sprintf("%s_%d-%d", \$1, \$2, \$3); + printf("%s\\t%d\\t%d\\n", \$1, \$2-1, \$3) > name ".bed" + }' ${intervals} + """ +} + +bedIntervals = bedIntervals + .map { intervalFile -> + def duration = 0.0 + for (line in intervalFile.readLines()) { + final fields = line.split('\t') + if (fields.size() >= 5) duration += fields[4].toFloat() + else { + start = fields[1].toInteger() + end = fields[2].toInteger() + duration += (end - start) / params.nucleotidesPerSecond + } + } + [duration, intervalFile] + }.toSortedList({ a, b -> b[0] <=> a[0] }) + .flatten().collate(2) + .map{duration, intervalFile -> intervalFile} + +bedIntervals = bedIntervals.dump(tag:'bedintervals') + +bamForBaseRecalibrator = mdBam.combine(bedIntervals) + +process CreateRecalibrationTable { + tag {idPatient + "-" + idSample + "-" + intervalBed} + + publishDir "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked", mode: params.publishDirMode, overwrite: false + + input: + set idPatient, status, idSample, file(bam), file(bai), file(intervalBed) from bamForBaseRecalibrator + set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex), file(knownIndels), file(knownIndelsIndex) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.genomeDict, + referenceMap.dbsnp, + referenceMap.dbsnpIndex, + referenceMap.knownIndels, + referenceMap.knownIndelsIndex, + ]) + + output: + set idPatient, status, idSample, file("${intervalBed.baseName}_${idSample}.recal.table") into recalIntervals + + when: step == 'mapping' + + script: + known = knownIndels.collect{ "--known-sites ${it}" }.join(' ') + // --use-original-qualities ??? + """ + gatk --java-options -Xmx${task.memory.toGiga()}g \ + BaseRecalibrator \ + -I ${bam} \ + -O ${intervalBed.baseName}_${idSample}.recal.table \ + --tmp-dir /tmp \ + -R ${genomeFile} \ + -L ${intervalBed} \ + --known-sites ${dbsnp} \ + ${known} \ + --verbosity INFO + """ +} + +recalIntervals = recalIntervals.groupTuple(by:[0,1,2]) + +process GatherBQSRReports { + tag {idPatient + "-" + idSample} + + publishDir "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked", mode: params.publishDirMode, overwrite: false + + input: + set idPatient, status, idSample, file(recalTable) from recalIntervals + + output: + set idPatient, status, idSample, file("${idSample}.recal.table") into recalibrationTable + set idPatient, status, idSample, val("${idSample}_${status}.md.bam"), val("${idSample}_${status}.md.bai"), val("${idSample}.recal.table") into (recalibrationTableTSV, recalibrationTableSampleTSV) + + when: step == 'mapping' + + script: + recal = recalTable.collect{ "-I ${it}" }.join(' ') + """ + gatk --java-options -Xmx${task.memory.toGiga()}g \ + GatherBQSRReports \ + ${recal} \ + -O ${idSample}.recal.table \ + """ +} + +// Create TSV files to restart from this step +recalibrationTableTSV.map { idPatient, status, idSample, bam, bai, recalTable -> + gender = patientGenders[idPatient] + "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bam}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bai}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${recalTable}\n" +}.collectFile( + name: 'duplicateMarked.tsv', sort: true, storeDir: "${params.outdir}/Preprocessing/TSV" +) + +recalibrationTableSampleTSV + .collectFile(storeDir: "${params.outdir}/Preprocessing/TSV") { + idPatient, status, idSample, bam, bai, recalTable -> + gender = patientGenders[idPatient] + ["duplicateMarked_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bam}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bai}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${recalTable}\n"] +} + +recalibrationTable = mdBamToJoin.join(recalibrationTable, by:[0,1,2]) + +if (step == 'recalibrate') recalibrationTable = bamFiles + +recalibrationTable = recalibrationTable.dump(tag:'recal.table') + +process RecalibrateBam { + tag {idPatient + "-" + idSample} + + publishDir "${params.outdir}/Preprocessing/${idSample}/Recalibrated", mode: params.publishDirMode + + input: + set idPatient, status, idSample, file(bam), file(bai), file(recalibrationReport) from recalibrationTable + set file(genomeFile), file(genomeIndex), file(genomeDict), file(intervals) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.genomeDict, + referenceMap.intervals, + ]) + + output: + set idPatient, status, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bai") into recalibratedBam, recalibratedBamForStats + set idPatient, status, idSample, val("${idSample}.recal.bam"), val("${idSample}.recal.bai") into (recalibratedBamTSV, recalibratedBamSampleTSV) + + script: + """ + gatk --java-options -Xmx${task.memory.toGiga()}g \ + ApplyBQSR \ + -R ${genomeFile} \ + --input ${bam} \ + --output ${idSample}.recal.bam \ + -L ${intervals} \ + --create-output-bam-index true \ + --bqsr-recal-file ${recalibrationReport} + """ +} + + +// Creating a TSV file to restart from this step +recalibratedBamTSV.map { idPatient, status, idSample, bam, bai -> + gender = patientGenders[idPatient] + "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bam}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bai}\n" +}.collectFile( + name: 'recalibrated.tsv', sort: true, storeDir: "${params.outdir}/Preprocessing/TSV" +) + +recalibratedBamSampleTSV + .collectFile(storeDir: "${params.outdir}/Preprocessing/TSV") { + idPatient, status, idSample, bam, bai -> + gender = patientGenders[idPatient] + ["recalibrated_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bam}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bai}\n"] +} + +recalibratedBam.dump(tag:'recal.bam') + +// Remove recalTable from Channels to match inputs for Process to avoid: +// WARN: Input tuple does not match input set cardinality declared by process... +(bamForBamQC, bamForSamToolsStats) = recalibratedBamForStats.map{ it[0..4] }.into(2) + +process RunSamtoolsStats { + tag {idPatient + "-" + idSample} + + publishDir "${params.outdir}/Reports/${idSample}/SamToolsStats", mode: params.publishDirMode + + input: + set idPatient, status, idSample, file(bam), file(bai) from bamForSamToolsStats + + output: + file ("${bam}.samtools.stats.out") into samtoolsStatsReport + + when: !params.noReports + + script: + """ + samtools stats ${bam} > ${bam}.samtools.stats.out + """ +} + +samtoolsStatsReport.dump(tag:'SAMTools') + +process RunBamQCrecalibrated { + tag {idPatient + "-" + idSample} + + publishDir "${params.outdir}/Reports/${idSample}/bamQC", mode: params.publishDirMode + + input: + set idPatient, status, idSample, file(bam), file(bai) from bamForBamQC + + output: + file("${bam.baseName}") into bamQCrecalibratedReport + + when: !params.noReports + + script: + """ + qualimap --java-mem-size=${task.memory.toGiga()}G \ + bamqc \ + -bam ${bam} \ + --paint-chromosome-limits \ + --genome-gc-distr HUMAN \ + -nt ${task.cpus} \ + -skip-duplicated \ + --skip-dup-mode 0 \ + -outdir ${bam.baseName} \ + -outformat HTML + """ +} + +bamQCrecalibratedReport.dump(tag:'BamQC') + /* * Completion e-mail notification */ @@ -314,12 +802,12 @@ def nfcoreHeader(){ ${c_blue} |\\ | |__ __ / ` / \\ |__) |__ ${c_yellow}} {${c_reset} ${c_blue} | \\| | \\__, \\__/ | \\ |___ ${c_green}\\`-._,-`-,${c_reset} ${c_green}`._,._,\'${c_reset} - ____ _____ _ - .' _ `. / ____| | | - / |\\`-_ \\ | (___ ___ _ __ __ | | __ - | | \\ `-| \\___ \\/__ \\| ´__/ _\\| |/ / - \\ | \\ / ____) | __ | | | __| < - `|____\\' |_____/\\____|_| \\__/|_|\\_\\ + ${c_black} ____ ${c_blue} _____ _ ${c_reset} + ${c_black} .' ${c_green}_${c_black} `. ${c_blue} / ____| | | ${c_reset} + ${c_black} / ${c_green}|\\${c_white}`-_${c_black} \\ ${c_blue} | (___ ___ _ __ __ | | __ ${c_reset} + ${c_black} | ${c_green}| \\ ${c_white}`-${c_black}| ${c_blue} \\___ \\/__ \\| ´__/ _\\| |/ / ${c_reset} + ${c_black} \\ ${c_green}| \\ ${c_black}/ ${c_blue} ____) | __ | | | __| < ${c_reset} + ${c_black} `${c_green}|${c_black}____${c_green}\\${c_black}' ${c_blue} |_____/\\____|_| \\__/|_|\\_\\ ${c_reset} ${c_purple} nf-core/sarek v${workflow.manifest.version}${c_reset} ${c_dim}----------------------------------------------------${c_reset} @@ -353,17 +841,54 @@ def checkHostname(){ ======================================================================================== */ +// Check if a row has the expected number of item +def checkNumberOfItem(row, number) { + if (row.size() != number) exit 1, "Malformed row in TSV file: ${row}, see --help for more information" + return true +} + +// Check parameter existence +def checkParameterExistence(it, list) { + if (!list.contains(it)) { + println("Unknown parameter: ${it}") + return false + } + return true +} + +// Compare each parameter with a list of parameters +def checkParameterList(list, realList) { + return list.every{ checkParameterExistence(it, realList) } +} + +// Check if params.item exists and return params.genomes[params.genome].item otherwise def checkParamReturnFile(item) { params."${item}" = params.genomes[params.genome]."${item}" return file(params."${item}") } -def checkExactlyOne(list) { - def n = 0 - list.each{n += it ? 1 : 0} - return n == 1 +// Loop through all the references files to check their existence +def checkRefExistence(referenceFile, fileToCheck) { + if (fileToCheck instanceof List) return fileToCheck.every{ checkRefExistence(referenceFile, it) } + def f = file(fileToCheck) + // this is an expanded wildcard: we can assume all files exist + if (f instanceof List && f.size() > 0) return true + else if (!f.exists()) { + println "Missing references: ${referenceFile} ${fileToCheck}" + return false + } + return true } +// Loop through all the references files to check their existence +def checkReferenceMap(referenceMap) { + referenceMap.every { + referenceFile, fileToCheck -> + checkRefExistence(referenceFile, fileToCheck) + } +} + +// Define map of reference depending of tools and step def defineReferenceMap(step, tools) { def referenceMap = [ @@ -394,6 +919,7 @@ def defineReferenceMap(step, tools) { return referenceMap } +// Define list of available step def defineStepList() { return [ 'mapping', @@ -403,6 +929,7 @@ def defineStepList() { ] } +// Define list of available tools def defineToolList() { return [ 'ascat', @@ -413,3 +940,139 @@ def defineToolList() { 'strelka' ] } + + // Create a channel of germline FASTQs from a directory pattern: "my_samples/*/" + // All FASTQ files in subdirectories are collected and emitted; + // they must have _R1_ and _R2_ in their names. +def extractFastqFromDir(pattern) { + def fastq = Channel.create() + // a temporary channel does all the work + Channel + .fromPath(pattern, type: 'dir') + .ifEmpty { error "No directories found matching pattern '${pattern}'" } + .subscribe onNext: { sampleDir -> + // the last name of the sampleDir is assumed to be a unique sample id + sampleId = sampleDir.getFileName().toString() + + for (path1 in file("${sampleDir}/**_R1_*.fastq.gz")) { + assert path1.getName().contains('_R1_') + path2 = file(path1.toString().replace('_R1_', '_R2_')) + if (!path2.exists()) error "Path '${path2}' not found" + (flowcell, lane) = flowcellLaneFromFastq(path1) + patient = sampleId + gender = 'ZZ' // unused + status = 0 // normal (not tumor) + rgId = "${flowcell}.${sampleId}.${lane}" + result = [patient, gender, status, sampleId, rgId, path1, path2] + fastq.bind(result) + } + }, onComplete: { fastq.close() } + fastq +} + +// Extract gender from Channel as it's only used for CNVs +def extractGenders(channel) { + def genders = [:] + channel = channel.map{ it -> + def idPatient = it[0] + def gender = it[1] + genders[idPatient] = gender + [idPatient] + it[2..-1] + } + [genders, channel] +} + +// Channeling the TSV file containing FASTQ or BAM +// Format is: "subject gender status sample lane fastq1 fastq2" +// or: "subject gender status sample lane bam" +def extractSample(tsvFile) { + Channel.from(tsvFile) + .splitCsv(sep: '\t') + .map { row -> + def idPatient = row[0] + def gender = row[1] + def status = returnStatus(row[2].toInteger()) + def idSample = row[3] + def idRun = row[4] + def file1 = returnFile(row[5]) + def file2 = file("null") + if (hasExtension(file1,"fastq.gz") || hasExtension(file1,"fq.gz")) { + checkNumberOfItem(row, 7) + file2 = returnFile(row[6]) + if (!hasExtension(file2,"fastq.gz") && !hasExtension(file2,"fq.gz")) exit 1, "File: ${file2} has the wrong extension. See --help for more information" + } + else if (hasExtension(file1,"bam")) checkNumberOfItem(row, 6) + else "No recognisable extention for input file: ${file1}" + + [idPatient, gender, status, idSample, idRun, file1, file2] + } +} + +// Channeling the TSV file containing Recalibration Tables. +// Format is: "subject gender status sample bam bai recalTables" +def extractRecal(tsvFile) { + Channel.from(tsvFile) + .splitCsv(sep: '\t') + .map { row -> + checkNumberOfItem(row, 7) + def idPatient = row[0] + def gender = row[1] + def status = returnStatus(row[2].toInteger()) + def idSample = row[3] + def bamFile = returnFile(row[4]) + def baiFile = returnFile(row[5]) + def recalTable = returnFile(row[6]) + + if (!hasExtension(bamFile,"bam")) exit 1, "File: ${bamFile} has the wrong extension. See --help for more information" + if (!hasExtension(baiFile,"bai")) exit 1, "File: ${baiFile} has the wrong extension. See --help for more information" + if (!hasExtension(recalTable,"recal.table")) exit 1, "File: ${recalTable} has the wrong extension. See --help for more information" + + [ idPatient, gender, status, idSample, bamFile, baiFile, recalTable ] + } +} + +// Parse first line of a FASTQ file, return the flowcell id and lane number. +def flowcellLaneFromFastq(path) { + // expected format: + // xx:yy:FLOWCELLID:LANE:... (seven fields) + // or + // FLOWCELLID:LANE:xx:... (five fields) + InputStream fileStream = new FileInputStream(path.toFile()) + InputStream gzipStream = new java.util.zip.GZIPInputStream(fileStream) + Reader decoder = new InputStreamReader(gzipStream, 'ASCII') + BufferedReader buffered = new BufferedReader(decoder) + def line = buffered.readLine() + assert line.startsWith('@') + line = line.substring(1) + def fields = line.split(' ')[0].split(':') + String fcid + int lane + if (fields.size() == 7) { + // CASAVA 1.8+ format + fcid = fields[2] + lane = fields[3].toInteger() + } + else if (fields.size() == 5) { + fcid = fields[0] + lane = fields[1].toInteger() + } + [fcid, lane] +} + +// Check file extension +def hasExtension(it, extension) { + it.toString().toLowerCase().endsWith(extension.toLowerCase()) +} + +// Return file if it exists +def returnFile(it) { + if (!file(it).exists()) exit 1, "Missing file in TSV file: ${it}, see --help for more information" + return file(it) +} + +// Return status [0,1] +// 0 == Normal, 1 == Tumor +def returnStatus(it) { + if (!(it in [0, 1])) exit 1, "Status is not recognized in TSV file: ${it}, see --help for more information" + return it +} diff --git a/nextflow.config b/nextflow.config index 6e7ff7b57d..a43d967601 100644 --- a/nextflow.config +++ b/nextflow.config @@ -58,7 +58,13 @@ profiles { awsbatch { includeConfig 'conf/awsbatch.config' } conda { process.conda = "$baseDir/environment.yml" } debug { process.beforeScript = 'echo $HOSTNAME' } - docker { docker.enabled = true } + docker { + docker { + enabled = true + fixOwnership = true + runOptions = "-u \$(id -u):\$(id -g)" + } + } singularity { singularity.enabled = true } test { includeConfig 'conf/test.config' } } From c117cbaf9a0a45b1e24127aad054d90ddd51dffc Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Fri, 3 May 2019 13:07:24 +0200 Subject: [PATCH 006/854] Add some Variant Calling (#4) * Update allelecount to 4.0.2 * Update GATK to 4.1.2.0 * Update docs * Add HaplotypeCaller * Add single Strelka and single Manta --- .travis.yml | 4 +- Jenkinsfile | 9 +- bin/concatenateVCFs.sh | 85 ++++++++ environment.yml | 4 +- main.nf | 433 +++++++++++++++++++++++++++++++++++++---- 5 files changed, 489 insertions(+), 46 deletions(-) create mode 100755 bin/concatenateVCFs.sh diff --git a/.travis.yml b/.travis.yml index 01d73056b2..b3847aab0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,5 +34,5 @@ install: script: - git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data - - nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile docker --genome smallGRCh37 --refdir data/reference --outdir references --publishDirMode link --max_memory 7.GB --max_cpus 2 - - nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile docker --genome smallGRCh37 --igenomes_base references --sampleDir data/testdata/tiny/normal --publishDirMode link --max_memory 7.GB --max_cpus 2 + - nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile docker --genome smallGRCh37 --refdir data/reference --outdir references --publishDirMode link --max_memory 7.GB --max_cpus 2 -ansi-log false + - nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile docker --genome smallGRCh37 --sampleDir data/testdata/tiny/normal --tools HaplotypeCaller,Manta,Strelka --igenomes_base references --publishDirMode link --max_memory 7.GB --max_cpus 2 -ansi-log false diff --git a/Jenkinsfile b/Jenkinsfile index 7ba61ecfee..c8a8e4252d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -14,17 +14,20 @@ pipeline { stage('Build') { steps { sh "git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data" - sh "nextflow run build.nf -profile docker --genome smallGRCh37 --refdir data/reference --outdir references --publishDirMode link" + sh "nextflow run build.nf -profile docker --genome smallGRCh37 --refdir data/reference --outdir references --publishDirMode link -ansi-log false" + sh "rm -rf work/ references/pipeline_info .nextflow*" } } stage('SampleDir') { steps { - sh "nextflow run main.nf -profile docker --genome smallGRCh37 --igenomes_base references --sampleDir data/testdata/tiny/normal --publishDirMode link" + sh "nextflow run main.nf -profile docker --sampleDir data/testdata/tiny/normal --tools HaplotypeCaller,Manta,Strelka --genome smallGRCh37 --igenomes_base references --publishDirMode link -ansi-log false" + sh "rm -rf work/ .nextflow* results/" } } stage('Multiple') { steps { - sh "nextflow run main.nf -profile docker --genome smallGRCh37 --igenomes_base references --sample data/testdata/tsv/tiny-multiple.tsv --publishDirMode link" + sh "nextflow run main.nf -profile docker --sample data/testdata/tsv/tiny-multiple.tsv --tools HaplotypeCaller,Manta,Strelka --genome smallGRCh37 --igenomes_base references --publishDirMode link -ansi-log false" + sh "rm -rf work/ .nextflow* results/" } } } diff --git a/bin/concatenateVCFs.sh b/bin/concatenateVCFs.sh new file mode 100755 index 0000000000..89bf9d125e --- /dev/null +++ b/bin/concatenateVCFs.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env bash +# this script concatenates all VCFs that are in the local directory: the +# purpose is to make a single VCF from all the VCFs that were created from different intervals + +usage() { echo "Usage: $0 [-i genome_index_file] [-o output.file.no.gz.extension] <-t target.bed> <-c cpus>" 1>&2; exit 1; } + +while getopts "i:c:o:t:" p; do + case "${p}" in + i) + genomeIndex=${OPTARG} + ;; + c) + cpus=${OPTARG} + ;; + o) + outputFile=${OPTARG} + ;; + t) + targetBED=${OPTARG} + ;; + *) + usage + ;; + esac +done +shift $((OPTIND-1)) + +if [ -z ${genomeIndex} ]; then echo "Missing index file "; usage; fi +if [ -z ${cpus} ]; then echo "No CPUs defined: setting to 1"; cpus=1; fi +if [ -z ${outputFile} ]; then echo "Missing output file name"; usage; fi + +set -euo pipefail + +# first make a header from one of the VCF intervals +# get rid of interval information only from the GATK command-line, but leave the rest +FIRSTVCF=$(ls *.vcf | head -n 1) +sed -n '/^[^#]/q;p' $FIRSTVCF | \ +awk '!/GATKCommandLine/{print}/GATKCommandLine/{for(i=1;i<=NF;i++){if($i!~/intervals=/ && $i !~ /out=/){printf("%s ",$i)}}printf("\n")}' \ +> header + +# Get list of contigs from the FASTA index (.fai). We cannot use the ##contig +# header in the VCF as it is optional (FreeBayes does not save it, for example) +CONTIGS=($(cut -f1 ${genomeIndex})) + +# concatenate VCFs in the correct order +( + cat header + + for chr in "${CONTIGS[@]}"; do + # Skip if globbing would not match any file to avoid errors such as + # "ls: cannot access chr3_*.vcf: No such file or directory" when chr3 + # was not processed. + pattern="${chr}_*.vcf" + if ! compgen -G "${pattern}" > /dev/null; then continue; fi + + # ls -v sorts by numeric value ("version"), which means that chr1_100_ + # is sorted *after* chr1_99_. + for vcf in $(ls -v ${pattern}); do + # Determine length of header. + # The 'q' command makes sed exit when it sees the first non-header + # line, which avoids reading in the entire file. + L=$(sed -n '/^[^#]/q;p' ${vcf} | wc -l) + + # Then print all non-header lines. Since tail is very fast (nearly as + # fast as cat), this is way more efficient than using a single sed, + # awk or grep command. + tail -n +$((L+1)) ${vcf} + done + done +) | bgzip -@${cpus} > rawcalls.vcf.gz +tabix rawcalls.vcf.gz + +set +u + +# now we have the concatenated VCF file, check for WES/panel targets, and generate a subset if there is a BED provided +echo "target is $targetBED" +if [ ! -z ${targetBED+x} ]; then + echo "Selecting subset..." + bcftools isec --targets-file ${targetBED} rawcalls.vcf.gz | bgzip -@${cpus} > ${outputFile}.gz + tabix ${outputFile}.gz +else + # simply rename the raw calls as WGS results + for f in rawcalls*; do mv -v $f ${outputFile}${f#rawcalls.vcf}; done +fi + diff --git a/environment.yml b/environment.yml index dcdbe97d7d..528fe6ca26 100644 --- a/environment.yml +++ b/environment.yml @@ -11,12 +11,12 @@ dependencies: - bcftools=1.9 - bioconductor-rtracklayer=1.42.1 - bwa=0.7.17 - - cancerit-allelecount=2.1.2 + - cancerit-allelecount=4.0.2 - control-freec=11.4 - ensembl-vep=96.0 - fastqc=0.11.8 - freebayes=1.2.0 - - gatk4=4.1.1.0 + - gatk4=4.1.2.0 - genesplicer=1.0 - htslib=1.9 - igvtools=2.3.93 diff --git a/main.nf b/main.nf index a554c41a65..cd3d3ac7a9 100644 --- a/main.nf +++ b/main.nf @@ -1,13 +1,19 @@ #!/usr/bin/env nextflow + /* ======================================================================================== nf-core/sarek ======================================================================================== -New Germline (+ Somatic) Analysis Workflow. Started March 2016. +Started March 2016. +Ported to nf-core May 2019. +---------------------------------------------------------------------------------------- +nf-core/sarek: + An open-source analysis pipeline to detect germline or somatic variants + from whole genome or targeted sequencing ---------------------------------------------------------------------------------------- - nf-core/sarek Analysis Pipeline. @Homepage https://sarek.scilifelab.se/ +---------------------------------------------------------------------------------------- @Documentation https://github.com/nf-core/sarek/README.md ---------------------------------------------------------------------------------------- @@ -26,20 +32,44 @@ def helpMessage() { Mandatory arguments: --sample Path to TSV input file + Multiple TSV files can be specified with quotes -profile Configuration profile to use. Can use multiple (comma separated) Available: conda, docker, singularity, awsbatch, test and more. Options: --genome Name of iGenomes reference + --noGVCF no g.vcf output from HaplotypeCaller + --noReports disable QC reports + --nucleotidesPerSecond To estimate interval size by default 1000.0 + --sampleDir Path to input directory + --sequencing_center Name of sequencing center to be displayed in BAM file + --step Specify starting step + Available: Mapping, Recalibrate, VariantCalling + Default: Mapping + --targetBED target BED file for targeted sequencing + --tools Specify tools to use for variant calling + Available: HaplotypeCaller, References If not specified in the configuration file or you wish to overwrite any of the references. - --fasta Path to Fasta reference + --acLoci acLoci file + --acLociGC acLoci GC file + --bwaIndex bwa indexes + --dbsnp dbsnp file + --dbsnpIndex dbsnp index + --genomeDict genome dict + --genomeFile genome file + --genomeIndex genome index + --intervals intervals + --knownIndels knownIndels file + --knownIndelsIndex knownIndels index + --snpeffDb snpeffDb version + --vepCacheVersion VEP Cache version Other options: --outdir The output directory where the results will be saved --email 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 --maxMultiqcEmailFileSize Theshold size for MultiQC report to be attached in notification email. If file generated by pipeline exceeds the threshold, it will not be attached (Default: 25MB) - -name Name for the pipeline run. If not specified, Nextflow will automatically generate a random mnemonic. + -name Name for the pipeline run. If not specified, Nextflow will automatically generate a random mnemonic AWSBatch options: --awsqueue The AWSBatch JobQueue that needs to be set when running on AWSBatch @@ -52,33 +82,31 @@ def helpMessage() { */ // Show help message -if (params.help){ - helpMessage() - exit 0 -} +if (params.help) exit 0, helpMessage() // Check if genome exists in the config file if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { exit 1, "The provided genome '${params.genome}' is not available in the iGenomes file. Currently the available genomes are ${params.genomes.keySet().join(", ")}" } -params.noReports = false +// Default value for params +params.noGVCF = null +params.noReports = null params.nucleotidesPerSecond = 1000.0 -params.sampleDir = false -params.sample = false +params.sample = null +params.sampleDir = null params.sequencing_center = null params.step = 'mapping' params.targetBED = null -params.test = false -params.tools = false +params.tools = null stepList = defineStepList() step = params.step ? params.step.toLowerCase() : '' if (step == 'preprocessing' || step == '') step = 'mapping' if (!checkParameterExistence(step, stepList)) exit 1, 'Unknown step, see --help for more information' if (step.contains(',')) exit 1, 'You can choose only one step, see --help for more information' -if (step == 'mapping' && ([params.test, params.sample, params.sampleDir].size == 1)) - exit 1, 'Please define which samples to work on by providing exactly one of the --test, --sample or --sampleDir options' +if (step == 'mapping' && ([params.sample, params.sampleDir].size == 1)) + exit 1, 'Please define which samples to work on by providing exactly one of the --sample or --sampleDir options' tools = params.tools ? params.tools.split(',').collect{it.trim().toLowerCase()} : [] toolList = defineToolList() @@ -90,9 +118,7 @@ if (!checkReferenceMap(referenceMap)) exit 1, 'Missing Reference file(s), see -- // Has the run name been specified by the user? // this has the bonus effect of catching both -name and --name custom_runName = params.name -if ( !(workflow.runName ==~ /[a-z]+_[a-z]+/) ){ - custom_runName = workflow.runName -} +if ( !(workflow.runName ==~ /[a-z]+_[a-z]+/) )custom_runName = workflow.runName if ( workflow.profile == 'awsbatch') { // AWSBatch sanity checking @@ -106,7 +132,7 @@ if ( workflow.profile == 'awsbatch') { // Stage config files ch_multiqc_config = Channel.fromPath(params.multiqc_config) -ch_output_docs = Channel.fromPath("$baseDir/docs/output.md") +ch_output_docs = Channel.fromPath("${baseDir}/docs/output.md") /* * Create a channel for input read files @@ -117,11 +143,10 @@ ch_output_docs = Channel.fromPath("$baseDir/docs/output.md") // No need for tsv file for step annotate if (!params.sample && !params.sampleDir) { tsvPaths = [ - 'mapping': "${workflow.projectDir}/Sarek-data/testdata/tsv/tiny.tsv", 'recalibrate': "${params.outdir}/Preprocessing/TSV/duplicateMarked.tsv", 'variantcalling': "${params.outdir}/Preprocessing/TSV/recalibrated.tsv" ] - if (params.test || step != 'mapping') tsvPath = tsvPaths[step] + if (step != 'mapping') tsvPath = tsvPaths[step] } // Set up the inputFiles and bamFiles channels. One of them will remain empty @@ -132,6 +157,7 @@ ch_output_docs = Channel.fromPath("$baseDir/docs/output.md") switch (step) { case 'mapping': inputFiles = extractSample(tsvFile); break case 'recalibrate': bamFiles = extractRecal(tsvFile); break + case 'variantcalling': bamFiles = extractBams(tsvFile); break default: exit 1, "Unknown step ${step}" } } else if (params.sampleDir) { @@ -152,27 +178,35 @@ ch_output_docs = Channel.fromPath("$baseDir/docs/output.md") // Header log info log.info nfcoreHeader() def summary = [:] -if (workflow.revision) summary['Pipeline Release'] = workflow.revision -summary['Run Name'] = custom_runName ?: workflow.runName -// TODO nf-core: Report custom parameters here -summary['Max Resources'] = "$params.max_memory memory, $params.max_cpus cpus, $params.max_time time per job" -if (workflow.containerEngine) summary['Container'] = "$workflow.containerEngine - $workflow.container" -summary['Output dir'] = params.outdir -summary['Launch dir'] = workflow.launchDir -summary['Working dir'] = workflow.workDir -summary['Script dir'] = workflow.projectDir -summary['User'] = workflow.userName +if (workflow.revision) summary['Pipeline Release'] = workflow.revision +summary['Run Name'] = custom_runName ?: workflow.runName +summary['Max Resources'] = "${params.max_memory} memory, ${params.max_cpus} cpus, ${params.max_time} time per job" +if (workflow.containerEngine) summary['Container'] = "${workflow.containerEngine} - ${workflow.container}" +if (params.sample) summary['Sample'] = params.sample +if (params.sampleDir) summary['Sample'] = params.sampleDir +if (params.targetBED) summary['Target BED'] = params.targetBED +if (params.step) summary['Step'] = params.step +if (params.tools) summary['Tools'] = tools.join(', ') +if (params.noReports) summary['Reports'] = params.noReports +if (params.noGVCF) summary['GVCF'] = params.noGVCF +if (params.sequencing_center) summary['Sequencing Center'] = params.sequencing_center +summary['Nucleotides/s'] = params.nucleotidesPerSecond +summary['Output dir'] = params.outdir +summary['Launch dir'] = workflow.launchDir +summary['Working dir'] = workflow.workDir +summary['Script dir'] = workflow.projectDir +summary['User'] = workflow.userName if (workflow.profile == 'awsbatch'){ - summary['AWS Region'] = params.awsregion - summary['AWS Queue'] = params.awsqueue + summary['AWS Region'] = params.awsregion + summary['AWS Queue'] = params.awsqueue } summary['Config Profile'] = workflow.profile if (params.config_profile_description) summary['Config Description'] = params.config_profile_description if (params.config_profile_contact) summary['Config Contact'] = params.config_profile_contact if (params.config_profile_url) summary['Config URL'] = params.config_profile_url if (params.email) { - summary['E-mail Address'] = params.email - summary['MultiQC maxsize'] = params.maxMultiqcEmailFileSize + summary['E-mail Address'] = params.email + summary['MultiQC maxsize'] = params.maxMultiqcEmailFileSize } log.info summary.collect { k,v -> "${k.padRight(18)}: $v" }.join("\n") log.info "\033[2m----------------------------------------------------\033[0m" @@ -482,7 +516,9 @@ bedIntervals = bedIntervals bedIntervals = bedIntervals.dump(tag:'bedintervals') -bamForBaseRecalibrator = mdBam.combine(bedIntervals) +(bedIntervalsBR, bedIntervalsHC) = bedIntervals.into(2) + +bamForBaseRecalibrator = mdBam.combine(bedIntervalsBR) process CreateRecalibrationTable { tag {idPatient + "-" + idSample + "-" + intervalBed} @@ -601,7 +637,6 @@ process RecalibrateBam { """ } - // Creating a TSV file to restart from this step recalibratedBamTSV.map { idPatient, status, idSample, bam, bai -> gender = patientGenders[idPatient] @@ -617,7 +652,7 @@ recalibratedBamSampleTSV ["recalibrated_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bam}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bai}\n"] } -recalibratedBam.dump(tag:'recal.bam') +recalibratedBam = recalibratedBam.dump(tag:'recal.bam') // Remove recalTable from Channels to match inputs for Process to avoid: // WARN: Input tuple does not match input set cardinality declared by process... @@ -674,6 +709,300 @@ process RunBamQCrecalibrated { bamQCrecalibratedReport.dump(tag:'BamQC') +/* +======================================================================================== + GERMLINE VARIANT CALLING +======================================================================================== +*/ + +if (step == 'variantcalling') recalibratedBam = bamFiles + +recalibratedBam = recalibratedBam.dump(tag:'BAM') + +// Here we have a recalibrated bam set +// The TSV file is formatted like: "idPatient status idSample bamFile baiFile" +// Manta will be run in Germline mode, or in Tumor mode depending on status +// HaplotypeCaller and Strelka will be run for Normal and Tumor samples + +(bamsForSingleManta, bamsForSingleStrelka, recalibratedBam) = recalibratedBam.into(3) + +// To speed Variant Callers up we are chopping the reference into smaller pieces +// Do variant calling by this intervals, and re-merge the VCFs + +bamsForHC = recalibratedBam.combine(bedIntervalsHC) + +process RunHaplotypecaller { + tag {idSample + "-" + intervalBed.baseName} + + input: + set idPatient, status, idSample, file(bam), file(bai), file(intervalBed) from bamsForHC + set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.genomeDict, + referenceMap.dbsnp, + referenceMap.dbsnpIndex + ]) + + output: + set val("HaplotypeCallerGVCF"), idPatient, status, idSample, file("${intervalBed.baseName}_${idSample}.g.vcf") into hcGenomicVCF + set idPatient, status, idSample, file(intervalBed), file("${intervalBed.baseName}_${idSample}.g.vcf") into vcfsToGenotype + + when: 'haplotypecaller' in tools + + script: + """ + gatk --java-options "-Xmx${task.memory.toGiga()}g -Xms6000m -XX:GCTimeLimit=50 -XX:GCHeapFreeLimit=10" \ + HaplotypeCaller \ + -R ${genomeFile} \ + -I ${bam} \ + -L ${intervalBed} \ + -D ${dbsnp} \ + -O ${intervalBed.baseName}_${idSample}.g.vcf \ + -ERC GVCF + """ +} + +hcGenomicVCF = hcGenomicVCF.groupTuple(by:[0,1,2,3]) + +if (params.noGVCF) hcGenomicVCF.close() + +process RunGenotypeGVCFs { + tag {idSample + "-" + intervalBed.baseName} + + input: + set idPatient, status, idSample, file(intervalBed), file(gvcf) from vcfsToGenotype + set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.genomeDict, + referenceMap.dbsnp, + referenceMap.dbsnpIndex + ]) + + output: + set val("HaplotypeCaller"), idPatient, status, idSample, file("${intervalBed.baseName}_${idSample}.vcf") into hcGenotypedVCF + + when: 'haplotypecaller' in tools + + script: + // Using -L is important for speed and we have to index the interval files also + """ + gatk --java-options -Xmx${task.memory.toGiga()}g \ + IndexFeatureFile -F ${gvcf} + + gatk --java-options -Xmx${task.memory.toGiga()}g \ + GenotypeGVCFs \ + -R ${genomeFile} \ + -L ${intervalBed} \ + -D ${dbsnp} \ + -V ${gvcf} \ + -O ${intervalBed.baseName}_${idSample}.vcf + """ +} + +hcGenotypedVCF = hcGenotypedVCF.groupTuple(by:[0,1,2,3]) + +// we are merging the VCFs that are called separatelly for different intervals +// so we can have a single sorted VCF containing all the calls for a given caller + +vcfsToMerge = hcGenomicVCF.mix(hcGenotypedVCF) + +vcfsToMerge = vcfsToMerge.dump(tag:'VCFsToMerge') + +process ConcatVCF { + tag {variantCaller + "-" + idSample} + + publishDir "${params.outdir}/VariantCalling/${idSample}/${"$variantCaller"}", mode: params.publishDirMode + + input: + set variantCaller, idPatient, status, idSample, file(vcFiles) from vcfsToMerge + file(genomeIndex) from Channel.value(referenceMap.genomeIndex) + file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") + + output: + // we have this funny *_* pattern to avoid copying the raw calls to publishdir + set variantCaller, idPatient, status, idSample, file("*_*.vcf.gz"), file("*_*.vcf.gz.tbi") into vcfConcatenated + + when: 'haplotypecaller' in tools + + script: + if (variantCaller == 'HaplotypeCaller') outputFile = "${variantCaller}_${idSample}.vcf" + else if (variantCaller == 'HaplotypeCallerGVCF') outputFile = "haplotypecaller_${idSample}.g.vcf" + options = params.targetBED ? "-t ${targetBED}" : "" + """ + concatenateVCFs.sh -i ${genomeIndex} -c ${task.cpus} -o ${outputFile} ${options} + """ +} + +process RunSingleStrelka { + tag {idSample} + + publishDir "${params.outdir}/VariantCalling/${idSample}/Strelka", mode: params.publishDirMode + + input: + set idPatient, status, idSample, file(bam), file(bai) from bamsForSingleStrelka + file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") + set file(genomeFile), file(genomeIndex) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex + ]) + + output: + set val("Strelka"), idPatient, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into singleStrelkaOutput + + when: 'strelka' in tools + + script: + beforeScript = params.targetBED ? "bgzip --threads ${task.cpus} -c ${targetBED} > call_targets.bed.gz ; tabix call_targets.bed.gz" : "" + options = params.targetBED ? "--exome --callRegions call_targets.bed.gz" : "" + """ + ${beforeScript} + configureStrelkaGermlineWorkflow.py \ + --bam ${bam} \ + --referenceFasta ${genomeFile} \ + ${options} \ + --runDir Strelka + + python Strelka/runWorkflow.py -m local -j ${task.cpus} + mv Strelka/results/variants/genome.*.vcf.gz Strelka_${idSample}_genome.vcf.gz + mv Strelka/results/variants/genome.*.vcf.gz.tbi Strelka_${idSample}_genome.vcf.gz.tbi + mv Strelka/results/variants/variants.vcf.gz Strelka_${idSample}_variants.vcf.gz + mv Strelka/results/variants/variants.vcf.gz.tbi Strelka_${idSample}_variants.vcf.gz.tbi + """ +} + +singleStrelkaOutput = singleStrelkaOutput.dump(tag:'Single Strelka') + +process RunSingleManta { + tag {idSample} + + publishDir "${params.outdir}/VariantCalling/${idSample}/Manta", mode: params.publishDirMode + + input: + set idPatient, status, idSample, file(bam), file(bai) from bamsForSingleManta + file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") + set file(genomeFile), file(genomeIndex) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex + ]) + + output: + set val("Manta"), idPatient, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into singleMantaOutput + + when: 'manta' in tools + + script: + beforeScript = params.targetBED ? "bgzip --threads ${task.cpus} -c ${targetBED} > call_targets.bed.gz ; tabix call_targets.bed.gz" : "" + options = params.targetBED ? "--exome --callRegions call_targets.bed.gz" : "" + inputbam = status == 0 ? "--bam" : "--tumorBam" + vcftype = status == 0 ? "diploid" : "tumor" + """ + ${beforeScript} + configManta.py \ + ${inputbam} ${bam} \ + --reference ${genomeFile} \ + ${options} \ + --runDir Manta + + python Manta/runWorkflow.py -m local -j ${task.cpus} + + mv Manta/results/variants/candidateSmallIndels.vcf.gz \ + Manta_${idSample}.candidateSmallIndels.vcf.gz + mv Manta/results/variants/candidateSmallIndels.vcf.gz.tbi \ + Manta_${idSample}.candidateSmallIndels.vcf.gz.tbi + mv Manta/results/variants/candidateSV.vcf.gz \ + Manta_${idSample}.candidateSV.vcf.gz + mv Manta/results/variants/candidateSV.vcf.gz.tbi \ + Manta_${idSample}.candidateSV.vcf.gz.tbi + mv Manta/results/variants/${vcftype}SV.vcf.gz \ + Manta_${idSample}.${vcftype}SV.vcf.gz + mv Manta/results/variants/${vcftype}SV.vcf.gz.tbi \ + Manta_${idSample}.${vcftype}SV.vcf.gz.tbi + """ +} + +singleMantaOutput = singleMantaOutput.dump(tag:'Single Manta') + +vcfForQC = Channel.empty().mix( + vcfConcatenated.map { + variantcaller, idPatient, status, idSample, vcf, tbi -> + [variantcaller, idPatient, idSample, vcf] + }, + singleStrelkaOutput.map { + variantcaller, idPatient, idSample, vcf, tbi -> + [variantcaller, idPatient, idSample, vcf[1]] + }, + singleMantaOutput.map { + variantcaller, idPatient, idSample, vcf, tbi -> + [variantcaller, idPatient, idSample, vcf[2]] + }) + +(vcfForBCFtools, vcfForVCFtools) = vcfForQC.into(2) + +process RunBcftoolsStats { + tag {"${variantCaller} - ${vcf}"} + + publishDir "${params.outdir}/Reports/${idSample}/BCFToolsStats", mode: params.publishDirMode + + input: + set variantCaller, idPatient, idSample, file(vcf) from vcfForBCFtools + + output: + file ("*.bcf.tools.stats.out") into bcfReport + + when: !params.noReports + + script: + """ + bcftools stats ${vcf} > ${reduceVCF(vcf)}.bcf.tools.stats.out + """ + +} + +bcfReport.dump(tag:'BCFTools') + +process RunVcftools { + tag {"${variantCaller} - ${vcf}"} + + publishDir "${params.outdir}/Reports/${idSample}/VCFTools", mode: params.publishDirMode + + input: + set variantCaller, idPatient, idSample, file(vcf) from vcfForVCFtools + + output: + file ("${reduceVCF(vcf)}.*") into vcfReport + + when: !params.noReports + + script: + """ + vcftools \ + --gzvcf ${vcf} \ + --relatedness2 \ + --out ${reduceVCF(vcf)} + + vcftools \ + --gzvcf ${vcf} \ + --TsTv-by-count \ + --out ${reduceVCF(vcf)} + + vcftools \ + --gzvcf ${vcf} \ + --TsTv-by-qual \ + --out ${reduceVCF(vcf)} + + vcftools \ + --gzvcf ${vcf} \ + --FILTER-summary \ + --out ${reduceVCF(vcf)} + + """ +} + +vcfReport.dump(tag:'VCFTools') + + /* * Completion e-mail notification */ @@ -910,7 +1239,7 @@ def defineReferenceMap(step, tools) { 'acLociGC' : checkParamReturnFile("acLociGC") ) } - if ('mapping' in step || 'mutect2' in tools) { + if ('mapping' in step || 'haplotypecaller' in tools || 'mutect2' in tools) { referenceMap.putAll( 'dbsnp' : checkParamReturnFile("dbsnp"), 'dbsnpIndex' : checkParamReturnFile("dbsnpIndex") @@ -941,6 +1270,27 @@ def defineToolList() { ] } +// Channeling the TSV file containing BAM. +// Format is: "subject gender status sample bam bai" +def extractBams(tsvFile) { + Channel.from(tsvFile) + .splitCsv(sep: '\t') + .map { row -> + checkNumberOfItem(row, 6) + def idPatient = row[0] + def gender = row[1] + def status = returnStatus(row[2].toInteger()) + def idSample = row[3] + def bamFile = returnFile(row[4]) + def baiFile = returnFile(row[5]) + + if (!hasExtension(bamFile,"bam")) exit 1, "File: ${bamFile} has the wrong extension. See --help for more information" + if (!hasExtension(baiFile,"bai")) exit 1, "File: ${baiFile} has the wrong extension. See --help for more information" + + return [ idPatient, gender, status, idSample, bamFile, baiFile ] + } +} + // Create a channel of germline FASTQs from a directory pattern: "my_samples/*/" // All FASTQ files in subdirectories are collected and emitted; // they must have _R1_ and _R2_ in their names. @@ -1070,6 +1420,11 @@ def returnFile(it) { return file(it) } +// Remove .ann .gz and .vcf extension from a VCF file +def reduceVCF(file) { + return file.fileName.toString().minus(".ann").minus(".vcf").minus(".gz") +} + // Return status [0,1] // 0 == Normal, 1 == Tumor def returnStatus(it) { From cf29773f27fca21c27d23399f1a23b8f830afb26 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 3 May 2019 13:53:41 +0200 Subject: [PATCH 007/854] fix Jenkins tests --- Jenkinsfile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index c8a8e4252d..97c43e3384 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -13,9 +13,10 @@ pipeline { } stage('Build') { steps { - sh "git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data" - sh "nextflow run build.nf -profile docker --genome smallGRCh37 --refdir data/reference --outdir references --publishDirMode link -ansi-log false" - sh "rm -rf work/ references/pipeline_info .nextflow*" + sh "rm -rf data" + sh "git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data" + sh "nextflow run build.nf -profile docker --genome smallGRCh37 --refdir data/reference --outdir references --publishDirMode link -ansi-log false" + sh "rm -rf work/ references/pipeline_info .nextflow*" } } stage('SampleDir') { From 578e239bf795dace76cc957c3da1bf84682e6be1 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 3 May 2019 13:53:48 +0200 Subject: [PATCH 008/854] sort ansi codes --- build.nf | 25 +++++++++++++------------ main.nf | 11 ++++++----- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/build.nf b/build.nf index c5238c483e..6c7e19e5e3 100644 --- a/build.nf +++ b/build.nf @@ -349,15 +349,16 @@ process DownloadCADD { def nfcoreHeader(){ // Log colors ANSI codes - c_black = params.monochrome_logs ? '' : "\033[0;30m"; - c_blue = params.monochrome_logs ? '' : "\033[0;34m"; - c_cyan = params.monochrome_logs ? '' : "\033[0;36m"; + c_reset = params.monochrome_logs ? '' : "\033[0m"; c_dim = params.monochrome_logs ? '' : "\033[2m"; + c_black = params.monochrome_logs ? '' : "\033[0;30m"; + c_red = params.monochrome_logs ? '' : "\033[0;31m"; c_green = params.monochrome_logs ? '' : "\033[0;32m"; + c_yellow = params.monochrome_logs ? '' : "\033[0;33m"; + c_blue = params.monochrome_logs ? '' : "\033[0;34m"; c_purple = params.monochrome_logs ? '' : "\033[0;35m"; - c_reset = params.monochrome_logs ? '' : "\033[0m"; + c_cyan = params.monochrome_logs ? '' : "\033[0;36m"; c_white = params.monochrome_logs ? '' : "\033[0;37m"; - c_yellow = params.monochrome_logs ? '' : "\033[0;33m"; return """ ${c_dim}----------------------------------------------------${c_reset} ${c_green},--.${c_black}/${c_green},-.${c_reset} @@ -365,12 +366,12 @@ def nfcoreHeader(){ ${c_blue} |\\ | |__ __ / ` / \\ |__) |__ ${c_yellow}} {${c_reset} ${c_blue} | \\| | \\__, \\__/ | \\ |___ ${c_green}\\`-._,-`-,${c_reset} ${c_green}`._,._,\'${c_reset} - ____ _____ _ - .' _ `. / ____| | | - / |\\`-_ \\ | (___ ___ _ __ __ | | __ - | | \\ `-| \\___ \\/__ \\| ´__/ _\\| |/ / - \\ | \\ / ____) | __ | | | __| < - `|____\\' |_____/\\____|_| \\__/|_|\\_\\ + ${c_black} ____ ${c_blue} _____ _ ${c_reset} + ${c_black} .' ${c_green}_${c_black} `. ${c_blue} / ____| | | ${c_reset} + ${c_black} / ${c_green}|\\${c_white}`-_${c_black} \\ ${c_blue} | (___ ___ _ __ __ | | __ ${c_reset} + ${c_black} | ${c_green}| \\ ${c_white}`-${c_black}| ${c_blue} \\___ \\/__ \\| ´__/ _\\| |/ / ${c_reset} + ${c_black} \\ ${c_green}| \\ ${c_black}/ ${c_blue} ____) | __ | | | __| < ${c_reset} + ${c_black} `${c_green}|${c_black}____${c_green}\\${c_black}' ${c_blue} |_____/\\____|_| \\__/|_|\\_\\ ${c_reset} ${c_purple} nf-core/sarek v${workflow.manifest.version}${c_reset} ${c_dim}----------------------------------------------------${c_reset} @@ -409,4 +410,4 @@ def checkFile(it) { final f = file(it) if (!f.exists()) exit 1, "Missing file: ${it}, see --help for more information" return true -} \ No newline at end of file +} diff --git a/main.nf b/main.nf index cd3d3ac7a9..596385569f 100644 --- a/main.nf +++ b/main.nf @@ -1115,15 +1115,16 @@ workflow.onComplete { def nfcoreHeader(){ // Log colors ANSI codes - c_black = params.monochrome_logs ? '' : "\033[0;30m"; - c_blue = params.monochrome_logs ? '' : "\033[0;34m"; - c_cyan = params.monochrome_logs ? '' : "\033[0;36m"; + c_reset = params.monochrome_logs ? '' : "\033[0m"; c_dim = params.monochrome_logs ? '' : "\033[2m"; + c_black = params.monochrome_logs ? '' : "\033[0;30m"; + c_red = params.monochrome_logs ? '' : "\033[0;31m"; c_green = params.monochrome_logs ? '' : "\033[0;32m"; + c_yellow = params.monochrome_logs ? '' : "\033[0;33m"; + c_blue = params.monochrome_logs ? '' : "\033[0;34m"; c_purple = params.monochrome_logs ? '' : "\033[0;35m"; - c_reset = params.monochrome_logs ? '' : "\033[0m"; + c_cyan = params.monochrome_logs ? '' : "\033[0;36m"; c_white = params.monochrome_logs ? '' : "\033[0;37m"; - c_yellow = params.monochrome_logs ? '' : "\033[0;33m"; return """ ${c_dim}----------------------------------------------------${c_reset} ${c_green},--.${c_black}/${c_green},-.${c_reset} From ed447ba0de7a8bd585af3594aac180292b1eca4a Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 3 May 2019 14:44:09 +0200 Subject: [PATCH 009/854] add tests --- .travis.yml | 2 +- Jenkinsfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b3847aab0e..77bfdcdc0a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,4 +35,4 @@ install: script: - git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data - nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile docker --genome smallGRCh37 --refdir data/reference --outdir references --publishDirMode link --max_memory 7.GB --max_cpus 2 -ansi-log false - - nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile docker --genome smallGRCh37 --sampleDir data/testdata/tiny/normal --tools HaplotypeCaller,Manta,Strelka --igenomes_base references --publishDirMode link --max_memory 7.GB --max_cpus 2 -ansi-log false + - nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile docker --genome smallGRCh37 --sampleDir data/testdata/tsv/tiny-manta.tsv --tools HaploTypeCaller,Manta,Strelka,MuTecT2,FreeBayes --igenomes_base references --publishDirMode link --max_memory 7.GB --max_cpus 2 -ansi-log false diff --git a/Jenkinsfile b/Jenkinsfile index 97c43e3384..630e2e2e88 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -27,7 +27,7 @@ pipeline { } stage('Multiple') { steps { - sh "nextflow run main.nf -profile docker --sample data/testdata/tsv/tiny-multiple.tsv --tools HaplotypeCaller,Manta,Strelka --genome smallGRCh37 --igenomes_base references --publishDirMode link -ansi-log false" + sh "nextflow run main.nf -profile docker --sample data/testdata/tsv/tiny-multiple.tsv --tools HaploTypeCaller,Manta,Strelka,MuTecT2,FreeBayes --genome smallGRCh37 --igenomes_base references --publishDirMode link -ansi-log false" sh "rm -rf work/ .nextflow* results/" } } From d93b562e9128cbecc2414320ffb16531c406a77c Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 3 May 2019 14:44:37 +0200 Subject: [PATCH 010/854] add Manta, Strelka, StrelkaBP, MuTecT2, Freebayes, Ascat, Controlfreec --- main.nf | 606 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 566 insertions(+), 40 deletions(-) diff --git a/main.nf b/main.nf index 596385569f..39fb4e8804 100644 --- a/main.nf +++ b/main.nf @@ -46,6 +46,7 @@ def helpMessage() { --step Specify starting step Available: Mapping, Recalibrate, VariantCalling Default: Mapping + --strelkaBP Use Manta candidateSmallIndels for Strelka as Best Practice --targetBED target BED file for targeted sequencing --tools Specify tools to use for variant calling Available: HaplotypeCaller, @@ -97,6 +98,7 @@ params.sample = null params.sampleDir = null params.sequencing_center = null params.step = 'mapping' +params.strelkaBP = true params.targetBED = null params.tools = null @@ -189,6 +191,7 @@ if (params.step) summary['Step'] = params.step if (params.tools) summary['Tools'] = tools.join(', ') if (params.noReports) summary['Reports'] = params.noReports if (params.noGVCF) summary['GVCF'] = params.noGVCF +if (params.strelkaBP) summary['Strelka BP'] = params.strelkaBP if (params.sequencing_center) summary['Sequencing Center'] = params.sequencing_center summary['Nucleotides/s'] = params.nucleotidesPerSecond summary['Output dir'] = params.outdir @@ -516,7 +519,7 @@ bedIntervals = bedIntervals bedIntervals = bedIntervals.dump(tag:'bedintervals') -(bedIntervalsBR, bedIntervalsHC) = bedIntervals.into(2) +(bedIntervalsBR, bedIntervalsHC, bedIntervalsForMpileup, bedIntervals) = bedIntervals.into(4) bamForBaseRecalibrator = mdBam.combine(bedIntervalsBR) @@ -724,12 +727,12 @@ recalibratedBam = recalibratedBam.dump(tag:'BAM') // Manta will be run in Germline mode, or in Tumor mode depending on status // HaplotypeCaller and Strelka will be run for Normal and Tumor samples -(bamsForSingleManta, bamsForSingleStrelka, recalibratedBam) = recalibratedBam.into(3) +(bamsForSingleManta, bamsForSingleStrelka, recalibratedBamTemp, recalibratedBam) = recalibratedBam.into(4) // To speed Variant Callers up we are chopping the reference into smaller pieces // Do variant calling by this intervals, and re-merge the VCFs -bamsForHC = recalibratedBam.combine(bedIntervalsHC) +bamsForHC = recalibratedBamTemp.combine(bedIntervalsHC) process RunHaplotypecaller { tag {idSample + "-" + intervalBed.baseName} @@ -745,8 +748,8 @@ process RunHaplotypecaller { ]) output: - set val("HaplotypeCallerGVCF"), idPatient, status, idSample, file("${intervalBed.baseName}_${idSample}.g.vcf") into hcGenomicVCF - set idPatient, status, idSample, file(intervalBed), file("${intervalBed.baseName}_${idSample}.g.vcf") into vcfsToGenotype + set val("HaplotypeCallerGVCF"), idPatient, idSample, file("${intervalBed.baseName}_${idSample}.g.vcf") into hcGenomicVCF + set idPatient, idSample, file(intervalBed), file("${intervalBed.baseName}_${idSample}.g.vcf") into vcfsToGenotype when: 'haplotypecaller' in tools @@ -763,7 +766,7 @@ process RunHaplotypecaller { """ } -hcGenomicVCF = hcGenomicVCF.groupTuple(by:[0,1,2,3]) +hcGenomicVCF = hcGenomicVCF.groupTuple(by:[0,1,2]) if (params.noGVCF) hcGenomicVCF.close() @@ -771,7 +774,7 @@ process RunGenotypeGVCFs { tag {idSample + "-" + intervalBed.baseName} input: - set idPatient, status, idSample, file(intervalBed), file(gvcf) from vcfsToGenotype + set idPatient, idSample, file(intervalBed), file(gvcf) from vcfsToGenotype set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex) from Channel.value([ referenceMap.genomeFile, referenceMap.genomeIndex, @@ -781,7 +784,7 @@ process RunGenotypeGVCFs { ]) output: - set val("HaplotypeCaller"), idPatient, status, idSample, file("${intervalBed.baseName}_${idSample}.vcf") into hcGenotypedVCF + set val("HaplotypeCaller"), idPatient, idSample, file("${intervalBed.baseName}_${idSample}.vcf") into hcGenotypedVCF when: 'haplotypecaller' in tools @@ -801,40 +804,11 @@ process RunGenotypeGVCFs { """ } -hcGenotypedVCF = hcGenotypedVCF.groupTuple(by:[0,1,2,3]) +hcGenotypedVCF = hcGenotypedVCF.groupTuple(by:[0,1,2]) // we are merging the VCFs that are called separatelly for different intervals // so we can have a single sorted VCF containing all the calls for a given caller -vcfsToMerge = hcGenomicVCF.mix(hcGenotypedVCF) - -vcfsToMerge = vcfsToMerge.dump(tag:'VCFsToMerge') - -process ConcatVCF { - tag {variantCaller + "-" + idSample} - - publishDir "${params.outdir}/VariantCalling/${idSample}/${"$variantCaller"}", mode: params.publishDirMode - - input: - set variantCaller, idPatient, status, idSample, file(vcFiles) from vcfsToMerge - file(genomeIndex) from Channel.value(referenceMap.genomeIndex) - file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") - - output: - // we have this funny *_* pattern to avoid copying the raw calls to publishdir - set variantCaller, idPatient, status, idSample, file("*_*.vcf.gz"), file("*_*.vcf.gz.tbi") into vcfConcatenated - - when: 'haplotypecaller' in tools - - script: - if (variantCaller == 'HaplotypeCaller') outputFile = "${variantCaller}_${idSample}.vcf" - else if (variantCaller == 'HaplotypeCallerGVCF') outputFile = "haplotypecaller_${idSample}.g.vcf" - options = params.targetBED ? "-t ${targetBED}" : "" - """ - concatenateVCFs.sh -i ${genomeIndex} -c ${task.cpus} -o ${outputFile} ${options} - """ -} - process RunSingleStrelka { tag {idSample} @@ -924,9 +898,537 @@ process RunSingleManta { singleMantaOutput = singleMantaOutput.dump(tag:'Single Manta') +/* +======================================================================================== + SOMATIC VARIANT CALLING +======================================================================================== +*/ + +// separate recalibrateBams by status +bamsNormal = Channel.create() +bamsTumor = Channel.create() + +recalibratedBam + .choice(bamsTumor, bamsNormal) {it[1] == 0 ? 1 : 0} + +// Ascat, Control-FREEC, Manta Tumor-only SV +bamsForAscat = Channel.create() +bamsForMpileup = Channel.create() +bamsForSingleManta = Channel.create() + +(bamsTumorTemp, bamsTumor) = bamsTumor.into(2) +(bamsNormalTemp, bamsNormal) = bamsNormal.into(2) +(bamsForAscat, bamsForMpileup, bamsForSingleManta) = bamsNormalTemp.mix(bamsTumorTemp).into(3) + +// Removing status because not relevant anymore +bamsNormal = bamsNormal.map { idPatient, status, idSample, bam, bai -> [idPatient, idSample, bam, bai] } +bamsTumor = bamsTumor.map { idPatient, status, idSample, bam, bai -> [idPatient, idSample, bam, bai] } + +bamsAll = bamsNormal.join(bamsTumor) + +// Manta and Strelka +(bamsForManta, bamsForStrelka, bamsForStrelkaBP, bamsAll) = bamsAll.into(4) + +bamsTumorNormalIntervals = bamsAll.spread(bedIntervals) +bamsForMpileup = bamsForMpileup.spread(bedIntervalsForMpileup) + +// MuTect2, FreeBayes +( bamsFMT2, bamsFFB) = bamsTumorNormalIntervals.into(3) + +// This will give as a list of unfiltered calls for MuTect2. +process RunMutect2 { + tag {idSampleTumor + "_vs_" + idSampleNormal + "-" + intervalBed.baseName} + + input: + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from bamsFMT2 + set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.genomeDict, + referenceMap.dbsnp, + referenceMap.dbsnpIndex + ]) + + output: + set val("MuTect2"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf") into mutect2Output + + when: 'mutect2' in tools + + script: + """ + gatk --java-options "-Xmx${task.memory.toGiga()}g" \ + Mutect2 \ + -R ${genomeFile}\ + -I ${bamTumor} -tumor ${idSampleTumor} \ + -I ${bamNormal} -normal ${idSampleNormal} \ + -L ${intervalBed} \ + -O ${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf + """ +} + +mutect2Output = mutect2Output.groupTuple(by:[0,1,2,3]) + +process RunFreeBayes { + tag {idSampleTumor + "_vs_" + idSampleNormal + "-" + intervalBed.baseName} + + input: + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from bamsFFB + file(genomeFile) from Channel.value(referenceMap.genomeFile) + file(genomeIndex) from Channel.value(referenceMap.genomeIndex) + + output: + set val("FreeBayes"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf") into freebayesOutput + + when: 'freebayes' in tools + + script: + """ + freebayes \ + -f ${genomeFile} \ + --pooled-continuous \ + --pooled-discrete \ + --genotype-qualities \ + --report-genotype-likelihood-max \ + --allele-balance-priors-off \ + --min-alternate-fraction 0.03 \ + --min-repeat-entropy 1 \ + --min-alternate-count 2 \ + -t ${intervalBed} \ + ${bamTumor} \ + ${bamNormal} > ${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf + """ +} + +freebayesOutput = freebayesOutput.groupTuple(by:[0,1,2,3]) + +vcfsToMerge = mutect2Output.mix(freebayesOutput, hcGenotypedVCF) + +vcfsToMerge = vcfsToMerge.dump(tag:'VCF to merge') + +process ConcatVCF { + tag {variantCaller + "-" + idSample} + + publishDir "${params.outdir}/VariantCalling/${idSample}/${"$variantCaller"}", mode: params.publishDirMode + + input: + set variantCaller, idPatient, idSample, file(vcFiles) from vcfsToMerge + file(genomeIndex) from Channel.value(referenceMap.genomeIndex) + file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") + + output: + // we have this funny *_* pattern to avoid copying the raw calls to publishdir + set variantCaller, idPatient, idSample, file("*_*.vcf.gz"), file("*_*.vcf.gz.tbi") into vcfConcatenated + + when: ('haplotypecaller' in tools || 'mutect2' in tools || 'freebayes' in tools) + + script: + if (variantCaller == 'HaplotypeCallerGVCF') outputFile = "haplotypecaller_${idSample}.g.vcf" + else outputFile = "${variantCaller}_${idSample}.vcf" + + options = params.targetBED ? "-t ${targetBED}" : "" + """ + concatenateVCFs.sh -i ${genomeIndex} -c ${task.cpus} -o ${outputFile} ${options} + """ +} + +vcfConcatenated = vcfConcatenated.dump(tag:'VCF') + +process RunStrelka { + tag {idSampleTumor + "_vs_" + idSampleNormal} + + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/Strelka", mode: params.publishDirMode + + input: + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor) from bamsForStrelka + file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") + set file(genomeFile), file(genomeIndex), file(genomeDict) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.genomeDict + ]) + + output: + set val("Strelka"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into strelkaOutput + + when: 'strelka' in tools + + script: + beforeScript = params.targetBED ? "bgzip --threads ${task.cpus} -c ${targetBED} > call_targets.bed.gz ; tabix call_targets.bed.gz" : "" + options = params.targetBED ? "--exome --callRegions call_targets.bed.gz" : "" + """ + ${beforeScript} + configureStrelkaSomaticWorkflow.py \ + --tumor ${bamTumor} \ + --normal ${bamNormal} \ + --referenceFasta ${genomeFile} \ + ${options} \ + --runDir Strelka + + python Strelka/runWorkflow.py -m local -j ${task.cpus} + mv Strelka/results/variants/somatic.indels.vcf.gz Strelka_${idSampleTumor}_vs_${idSampleNormal}_somatic_indels.vcf.gz + mv Strelka/results/variants/somatic.indels.vcf.gz.tbi Strelka_${idSampleTumor}_vs_${idSampleNormal}_somatic_indels.vcf.gz.tbi + mv Strelka/results/variants/somatic.snvs.vcf.gz Strelka_${idSampleTumor}_vs_${idSampleNormal}_somatic_snvs.vcf.gz + mv Strelka/results/variants/somatic.snvs.vcf.gz.tbi Strelka_${idSampleTumor}_vs_${idSampleNormal}_somatic_snvs.vcf.gz.tbi + """ +} + +strelkaOutput = strelkaOutput.dump(tag:'Strelka') + +process RunManta { + tag {idSampleTumor + "_vs_" + idSampleNormal} + + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/Manta", mode: params.publishDirMode + + input: + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor) from bamsForManta + file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") + set file(genomeFile), file(genomeIndex) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex + ]) + + output: + set val("Manta"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into mantaOutput + set idPatient, idSampleNormal, idSampleTumor, file("*.candidateSmallIndels.vcf.gz"), file("*.candidateSmallIndels.vcf.gz.tbi") into mantaToStrelka + + when: 'manta' in tools + + script: + beforeScript = params.targetBED ? "bgzip --threads ${task.cpus} -c ${targetBED} > call_targets.bed.gz ; tabix call_targets.bed.gz" : "" + options = params.targetBED ? "--exome --callRegions call_targets.bed.gz" : "" + """ + ${beforeScript} + configManta.py \ + --normalBam ${bamNormal} \ + --tumorBam ${bamTumor} \ + --reference ${genomeFile} \ + ${options} \ + --runDir Manta + + python Manta/runWorkflow.py -m local -j ${task.cpus} + + mv Manta/results/variants/candidateSmallIndels.vcf.gz \ + Manta_${idSampleTumor}_vs_${idSampleNormal}.candidateSmallIndels.vcf.gz + mv Manta/results/variants/candidateSmallIndels.vcf.gz.tbi \ + Manta_${idSampleTumor}_vs_${idSampleNormal}.candidateSmallIndels.vcf.gz.tbi + mv Manta/results/variants/candidateSV.vcf.gz \ + Manta_${idSampleTumor}_vs_${idSampleNormal}.candidateSV.vcf.gz + mv Manta/results/variants/candidateSV.vcf.gz.tbi \ + Manta_${idSampleTumor}_vs_${idSampleNormal}.candidateSV.vcf.gz.tbi + mv Manta/results/variants/diploidSV.vcf.gz \ + Manta_${idSampleTumor}_vs_${idSampleNormal}.diploidSV.vcf.gz + mv Manta/results/variants/diploidSV.vcf.gz.tbi \ + Manta_${idSampleTumor}_vs_${idSampleNormal}.diploidSV.vcf.gz.tbi + mv Manta/results/variants/somaticSV.vcf.gz \ + Manta_${idSampleTumor}_vs_${idSampleNormal}.somaticSV.vcf.gz + mv Manta/results/variants/somaticSV.vcf.gz.tbi \ + Manta_${idSampleTumor}_vs_${idSampleNormal}.somaticSV.vcf.gz.tbi + """ +} + +mantaOutput = mantaOutput.dump(tag:'Manta') + +bamsForStrelkaBP = bamsForStrelkaBP.map { + idPatientNormal, idSampleNormal, bamNormal, baiNormal, idSampleTumor, bamTumor, baiTumor -> + [idPatientNormal, idSampleNormal, idSampleTumor, bamNormal, baiNormal, bamTumor, baiTumor] +}.join(mantaToStrelka, by:[0,1,2]).map { + idPatientNormal, idSampleNormal, idSampleTumor, bamNormal, baiNormal, bamTumor, baiTumor, mantaCSI, mantaCSIi -> + [idPatientNormal, idSampleNormal, bamNormal, baiNormal, idSampleTumor, bamTumor, baiTumor, mantaCSI, mantaCSIi] +} + +process RunStrelkaBP { + tag {idSampleTumor + "_vs_" + idSampleNormal} + + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/Strelka", mode: params.publishDirMode + + input: + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(mantaCSI), file(mantaCSIi) from bamsForStrelkaBP + file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") + set file(genomeFile), file(genomeIndex), file(genomeDict) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.genomeDict + ]) + + output: + set val("Strelka"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into strelkaBPOutput + + when: 'strelka' in tools && 'manta' in tools && params.strelkaBP + + script: + beforeScript = params.targetBED ? "bgzip --threads ${task.cpus} -c ${targetBED} > call_targets.bed.gz ; tabix call_targets.bed.gz" : "" + options = params.targetBED ? "--exome --callRegions call_targets.bed.gz" : "" + """ + ${beforeScript} + configureStrelkaSomaticWorkflow.py \ + --tumor ${bamTumor} \ + --normal ${bamNormal} \ + --referenceFasta ${genomeFile} \ + --indelCandidates ${mantaCSI} \ + ${options} \ + --runDir Strelka + + python Strelka/runWorkflow.py -m local -j ${task.cpus} + + mv Strelka/results/variants/somatic.indels.vcf.gz \ + StrelkaBP_${idSampleTumor}_vs_${idSampleNormal}_somatic_indels.vcf.gz + mv Strelka/results/variants/somatic.indels.vcf.gz.tbi \ + StrelkaBP_${idSampleTumor}_vs_${idSampleNormal}_somatic_indels.vcf.gz.tbi + mv Strelka/results/variants/somatic.snvs.vcf.gz \ + StrelkaBP_${idSampleTumor}_vs_${idSampleNormal}_somatic_snvs.vcf.gz + mv Strelka/results/variants/somatic.snvs.vcf.gz.tbi \ + StrelkaBP_${idSampleTumor}_vs_${idSampleNormal}_somatic_snvs.vcf.gz.tbi + """ +} + +strelkaBPOutput = strelkaBPOutput.dump(tag:'Strelka BP') + +// Run commands and code from Malin Larsson +// Based on Jesper Eisfeldt's code +process RunAlleleCount { + tag {idSample} + + input: + set idPatient, status, idSample, file(bam), file(bai) from bamsForAscat + set file(acLoci), file(genomeFile), file(genomeIndex), file(genomeDict) from Channel.value([ + referenceMap.acLoci, + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.genomeDict + ]) + + output: + set idPatient, status, idSample, file("${idSample}.alleleCount") into alleleCountOutput + + when: 'ascat' in tools + + script: + """ + alleleCounter \ + -l ${acLoci} \ + -r ${genomeFile} \ + -b ${bam} \ + -o ${idSample}.alleleCount; + """ +} + +alleleCountNormal = Channel.create() +alleleCountTumor = Channel.create() + +alleleCountOutput + .choice(alleleCountTumor, alleleCountNormal) {it[1] == 0 ? 1 : 0} + +alleleCountOutput = alleleCountNormal.combine(alleleCountTumor) + +alleleCountOutput = alleleCountOutput.map { + idPatientNormal, statusNormal, idSampleNormal, alleleCountNormal, + idPatientTumor, statusTumor, idSampleTumor, alleleCountTumor -> + [idPatientNormal, idSampleNormal, idSampleTumor, alleleCountNormal, alleleCountTumor] +} + +// R script from Malin Larssons bitbucket repo: +// https://bitbucket.org/malinlarsson/somatic_wgs_pipeline +process RunConvertAlleleCounts { + tag {idSampleTumor + "_vs_" + idSampleNormal} + + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/ASCAT", mode: params.publishDirMode + + input: + set idPatient, idSampleNormal, idSampleTumor, file(alleleCountNormal), file(alleleCountTumor) from alleleCountOutput + + output: + set idPatient, idSampleNormal, idSampleTumor, file("${idSampleNormal}.BAF"), file("${idSampleNormal}.LogR"), file("${idSampleTumor}.BAF"), file("${idSampleTumor}.LogR") into convertAlleleCountsOutput + + when: 'ascat' in tools + + script: + gender = patientGenders[idPatient] + """ + convertAlleleCounts.r ${idSampleTumor} ${alleleCountTumor} ${idSampleNormal} ${alleleCountNormal} ${gender} + """ +} + +// R scripts from Malin Larssons bitbucket repo: +// https://bitbucket.org/malinlarsson/somatic_wgs_pipeline +process RunAscat { + tag {idSampleTumor + "_vs_" + idSampleNormal} + + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/ASCAT", mode: params.publishDirMode + + input: + set idPatient, idSampleNormal, idSampleTumor, file(bafNormal), file(logrNormal), file(bafTumor), file(logrTumor) from convertAlleleCountsOutput + file(acLociGC) from Channel.value([referenceMap.acLociGC]) + + output: + set val("ASCAT"), idPatient, idSampleNormal, idSampleTumor, file("${idSampleTumor}.*.{png,txt}") into ascatOutput + + when: 'ascat' in tools + + script: + """ + # get rid of "chr" string if there is any + for f in *BAF *LogR; do sed 's/chr//g' \$f > tmpFile; mv tmpFile \$f;done + run_ascat.r ${bafTumor} ${logrTumor} ${bafNormal} ${logrNormal} ${idSampleTumor} ${baseDir} ${acLociGC} + """ +} + +ascatOutput.dump(tag:'ASCAT') + +process RunMpileup { + tag {idSample + "-" + intervalBed.baseName} + + input: + set idPatient, status, idSample, file(bam), file(bai), file(intervalBed) from bamsForMpileup + set file(genomeFile), file(genomeIndex) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex + ]) + + output: + set idPatient, status, idSample, file("${idSample}_${intervalBed.baseName}.pileup.gz") into mpileupToMerge + + when: ('controlfreec' in tools || 'mpileup' in tools) + + script: + """ + samtools mpileup \ + -f ${genomeFile} ${bam} \ + -l ${intervalBed} \ + | bgzip --threads ${task.cpus} -c > ${idSample}_${intervalBed.baseName}.pileup.gz + """ +} + +mpileupToMerge = mpileupToMerge.groupTuple(by:[0,1,2]) + +process MergeMpileup { + tag {idSample} + + publishDir params.outdir, mode: params.publishDirMode, saveAs: { it == "${idSample}.pileup.gz" ? "VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/mpileup/${it}" : '' } + + input: + set idPatient, status, idSample, file(mpileup) from mpileupToMerge + + output: + set idPatient, status, idSample, file("${idSample}.pileup.gz") into mpileupOutput + + when: ('controlfreec' in tools || 'mpileup' in tools) + + script: + """ + for i in `ls -1v *.pileup.gz`; + do zcat \$i >> ${idSample}.pileup + done + bgzip --threads ${task.cpus} -c ${idSample}.pileup > ${idSample}.pileup.gz + rm ${idSample}.pileup + """ +} + +mpileupOutput = mpileupOutput.dump(tag:'mpileup') + +mpileupNormal = Channel.create() +mpileupTumor = Channel.create() + +mpileupOutput + .choice(mpileupTumor, mpileupNormal) {it[1] == 0 ? 1 : 0} + +mpileupOutput = mpileupNormal.combine(mpileupTumor) + +mpileupOutput = mpileupOutput.map { + idPatientNormal, statusNormal, idSampleNormal, mpileupNormal, + idPatientTumor, statusTumor, idSampleTumor, mpileupTumor -> + [idPatientNormal, idSampleNormal, idSampleTumor, mpileupNormal, mpileupTumor] +} + +process RunControlFreec { + tag {idSampleTumor + "_vs_" + idSampleNormal} + + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/controlFREEC", mode: params.publishDirMode + + input: + set idPatient, idSampleNormal, idSampleTumor, file(mpileupNormal), file(mpileupTumor) from mpileupOutput + set file(genomeFile), file(genomeIndex), file(dbsnp), file(dbsnpIndex), file(chrDir), file(chrLength) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.dbsnp, + referenceMap.dbsnpIndex, + referenceMap.chrDir, + referenceMap.chrLength + ]) + + output: + set idPatient, idSampleNormal, idSampleTumor, file("${idSampleTumor}.pileup.gz_CNVs"), file("${idSampleTumor}.pileup.gz_ratio.txt"), file("${idSampleTumor}.pileup.gz_normal_CNVs"), file("${idSampleTumor}.pileup.gz_normal_ratio.txt"), file("${idSampleTumor}.pileup.gz_BAF.txt"), file("${idSampleNormal}.pileup.gz_BAF.txt") into controlFreecOutputVisualization + set file("*.pileup.gz*"), file("${idSampleTumor}_vs_${idSampleNormal}.config.txt") into controlFreecOutput + + when: 'controlfreec' in tools + + script: + config = "${idSampleTumor}_vs_${idSampleNormal}.config.txt" + gender = patientGenders[idPatient] + """ + touch ${config} + echo "[general]" >> ${config} + echo "BedGraphOutput = TRUE" >> ${config} + echo "chrFiles = \${PWD}/${referenceMap.chrDir.fileName}" >> ${config} + echo "chrLenFile = \${PWD}/${referenceMap.chrLength.fileName}" >> ${config} + echo "coefficientOfVariation = 0.05" >> ${config} + echo "contaminationAdjustment = TRUE" >> ${config} + echo "forceGCcontentNormalization = 0" >> ${config} + echo "maxThreads = ${task.cpus}" >> ${config} + echo "minimalSubclonePresence = 20" >> ${config} + echo "ploidy = 2,3,4" >> ${config} + echo "sex = ${gender}" >> ${config} + echo "window = 50000" >> ${config} + echo "" >> ${config} + + echo "[control]" >> ${config} + echo "inputFormat = pileup" >> ${config} + echo "mateFile = \${PWD}/${mpileupNormal}" >> ${config} + echo "mateOrientation = FR" >> ${config} + echo "" >> ${config} + + echo "[sample]" >> ${config} + echo "inputFormat = pileup" >> ${config} + echo "mateFile = \${PWD}/${mpileupTumor}" >> ${config} + echo "mateOrientation = FR" >> ${config} + echo "" >> ${config} + + echo "[BAF]" >> ${config} + echo "SNPfile = ${referenceMap.dbsnp.fileName}" >> ${config} + + freec -conf ${config} + """ +} + +process RunControlFreecVisualization { + + tag {idSampleTumor + "_vs_" + idSampleNormal} + + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/controlFREEC", mode: params.publishDirMode + + input: + set idPatient, idSampleNormal, idSampleTumor, file(cnvTumor), file(ratioTumor), file(cnvNormal), file(ratioNormal), file(bafTumor), file(bafNormal) from controlFreecOutputVisualization + + output: + set file("*.txt"), file("*.png"), file("*.bed") into controlFreecOutputFinal + + when: 'controlfreec' in tools + + """ + cat /opt/conda/envs/sarek-2.3/bin/assess_significance.R | R --slave --args ${cnvTumor} ${ratioTumor} + cat /opt/conda/envs/sarek-2.3/bin/assess_significance.R | R --slave --args ${cnvNormal} ${ratioNormal} + cat /opt/conda/envs/sarek-2.3/bin/makeGraph.R | R --slave --args 2 ${ratioTumor} ${bafTumor} + cat /opt/conda/envs/sarek-2.3/bin/makeGraph.R | R --slave --args 2 ${ratioNormal} ${bafNormal} + perl /opt/conda/envs/sarek-2.3/bin/freec2bed.pl -f ${ratioTumor} > ${idSampleTumor}.bed + perl /opt/conda/envs/sarek-2.3/bin/freec2bed.pl -f ${ratioNormal} > ${idSampleNormal}.bed + """ +} + +(strelkaIndels, strelkaSNVS) = strelkaOutput.into(2) +(mantaSomaticSV, mantaDiploidSV) = mantaOutput.into(2) + vcfForQC = Channel.empty().mix( vcfConcatenated.map { - variantcaller, idPatient, status, idSample, vcf, tbi -> + variantcaller, idPatient, idSample, vcf, tbi -> [variantcaller, idPatient, idSample, vcf] }, singleStrelkaOutput.map { @@ -936,6 +1438,22 @@ vcfForQC = Channel.empty().mix( singleMantaOutput.map { variantcaller, idPatient, idSample, vcf, tbi -> [variantcaller, idPatient, idSample, vcf[2]] + }, + mantaDiploidSV.map { + variantcaller, idPatient, idSample, vcf, tbi -> + [variantcaller, idPatient, idSample, vcf[2]] + }, + mantaSomaticSV.map { + variantcaller, idPatient, idSample, vcf, tbi -> + [variantcaller, idPatient, idSample, vcf[3]] + }, + strelkaIndels.map { + variantcaller, idPatient, idSample, vcf, tbi -> + [variantcaller, idPatient, idSample, vcf[0]] + }, + strelkaSNVS.map { + variantcaller, idPatient, idSample, vcf, tbi -> + [variantcaller, idPatient, idSample, vcf[1]] }) (vcfForBCFtools, vcfForVCFtools) = vcfForQC.into(2) @@ -1234,13 +1752,19 @@ def defineReferenceMap(step, tools) { 'knownIndelsIndex' : checkParamReturnFile("knownIndelsIndex") ) } + if ('controlfreec' in tools) { + referenceMap.putAll( + 'chrDir' : checkParamReturnFile("chrDir"), + 'chrLength' : checkParamReturnFile("chrLength") + ) + } if ('ascat' in tools) { referenceMap.putAll( 'acLoci' : checkParamReturnFile("acLoci"), 'acLociGC' : checkParamReturnFile("acLociGC") ) } - if ('mapping' in step || 'haplotypecaller' in tools || 'mutect2' in tools) { + if ('mapping' in step || 'haplotypecaller' in tools || 'mutect2' in tools || 'controlfreec' in tools) { referenceMap.putAll( 'dbsnp' : checkParamReturnFile("dbsnp"), 'dbsnpIndex' : checkParamReturnFile("dbsnpIndex") @@ -1263,9 +1787,11 @@ def defineStepList() { def defineToolList() { return [ 'ascat', + 'controlfreec', 'freebayes', 'haplotypecaller', 'manta', + 'mpileup', 'mutect2', 'strelka' ] From 45928fc0316a8758e7f437cc207ada9ce72567d0 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 3 May 2019 14:47:02 +0200 Subject: [PATCH 011/854] update docs --- main.nf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main.nf b/main.nf index 39fb4e8804..216f4070d6 100644 --- a/main.nf +++ b/main.nf @@ -49,7 +49,8 @@ def helpMessage() { --strelkaBP Use Manta candidateSmallIndels for Strelka as Best Practice --targetBED target BED file for targeted sequencing --tools Specify tools to use for variant calling - Available: HaplotypeCaller, + Available: ASCAT, ControlFREEC, FreeBayes, HaplotypeCaller + Manta, mpileup, MuTect2, Strelka References If not specified in the configuration file or you wish to overwrite any of the references. --acLoci acLoci file From a1a90141ee723b39c0741d3572f526c92d4a47f2 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 3 May 2019 14:51:48 +0200 Subject: [PATCH 012/854] fix travis tests --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 77bfdcdc0a..ee7db79aa5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,4 +35,4 @@ install: script: - git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data - nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile docker --genome smallGRCh37 --refdir data/reference --outdir references --publishDirMode link --max_memory 7.GB --max_cpus 2 -ansi-log false - - nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile docker --genome smallGRCh37 --sampleDir data/testdata/tsv/tiny-manta.tsv --tools HaploTypeCaller,Manta,Strelka,MuTecT2,FreeBayes --igenomes_base references --publishDirMode link --max_memory 7.GB --max_cpus 2 -ansi-log false + - nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile docker --genome smallGRCh37 --sample data/testdata/tsv/tiny-manta.tsv --tools HaploTypeCaller,Manta,Strelka,MuTecT2,FreeBayes --igenomes_base references --publishDirMode link --max_memory 7.GB --max_cpus 2 -ansi-log false From 8c5a8757645e68c68697a5a4cb57c90e9530017a Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Fri, 3 May 2019 16:33:55 +0200 Subject: [PATCH 013/854] Add default containers for annotation (#6) * add containers for annotation --- README.md | 7 +++---- containers/snpeff/Dockerfile | 17 +++++++++++++++++ containers/snpeff/environment.yml | 10 ++++++++++ containers/vep/Dockerfile | 26 ++++++++++++++++++++++++++ containers/vep/environment.yml | 11 +++++++++++ 5 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 containers/snpeff/Dockerfile create mode 100644 containers/snpeff/environment.yml create mode 100644 containers/vep/Dockerfile create mode 100644 containers/vep/environment.yml diff --git a/README.md b/README.md index 3e52b0e833..001b0622f6 100644 --- a/README.md +++ b/README.md @@ -133,10 +133,9 @@ For further information or help, don't hesitate to get in touch on [Slack](https * [CHANGELOG](CHANGELOG.md) ## Aknowledgements -[SciLifeLab logo][scilifelab-link] -[Barntumörbanken logo][btb-link] -[National Genomics Infrastructure logo][ngi-link] -[National Bioinformatics Infrastructure Sweden logo][nbis-link] +[![Barntumörbanken](docs/images/BTB_logo.png)](https://ki.se/forskning/barntumorbanken-0) | [![SciLifeLab](docs/images/SciLifeLab_logo.png)](https://scilifelab.se) +:-:|:-: +[![National Genomics Infrastructure](docs/images/NGI_logo.png)](https://ngisweden.scilifelab.se/) | [![National Bioinformatics Infrastructure Sweden](docs/images/NBIS_logo.png)](https://nbis.se) [bioconda-badge]: https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADEAAAAyCAYAAAD1CDOyAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAa2SURBVGiBxZprjFVXFcd/e2aA6UAoYGrk0aZYKvXdwWAyoDyswRqhxmpNjQFrNOIHTR+aJhoxrWBoAz4aGz80bdWCsW1qq5IGSlvDQA1aUGw7BEuR4dFCrVSY0qFYYH5+WHt674zzOHdm7sw/uTn7nLP2Put/z9prr7X2SQwh1InASqAJmAyMBcYDbUA7cAR4HngOaAZ2ppTODqUOA4Jar16mTsjnU9THLIYT6j3qPDWNlPI/V29X31T3qV9Ux6tJ/WlBIp14Vl2m1lZb8Tnqwtz+XH54i7olt9eoreqMTOSOComo/kVtrIbyo9Ufqe3qWLVR3azuzg++LR9vzcfvq+/NRO4bAJEz6koLvpWaAgQmAVuAm4DtKaV2YBlwBfBIFuucnOOADmAKsCalJPDriv6xQB3wPeBx9YL+hPskoU4hvEhTvvRCPp7IfccBp4HZ+V4jsBeYASxXa4AVlXN4CwuBreqFfQn1SkJtAL4N7AG2AvuBV/LtscBh4FribSwANgMfBp4G/pRSOgzcCMwdBAmAy4Bt6rRBjtMV6i3qDdl+V+TjLfn4NUtu99QA5kNv2G2sQ/+HHn2zegmwBJgEzAcOAuuB4ymlHVmmFvgK8BFgFvBX4HJgaUrpWfVtwCjgVD5OA94DzMtjTx3A//cosCTPtd6hvl99PbPfpD6S283q17PMSnV2bjeoi8yutwjUWvXThnuuFDcWGXyz4Sr/mzvtVNfl9t1Z7ol8fldRxft43nL13xWQeMOwlF4H/WAWbM9E9ufz/cZCtifL3aduVScPhkTZc6dbWnOK4A99DTY/K38gC/9G/V1uH1NXZLkr1fOGgkDZsyeoT1ZAZF5Pg0xVP5oFHlbvVM+qe9QfG6vovqFUvAcdxqnPFSTxaPfO09WfGK7xP1nouLpK3WG4ytvsb1INDZFLy3ToCx3qzPKOt2alG9Ql6sYspGH7q9TvWu0Is6TPsoJv4wflnf6ZL35LPV+9X12oXmX4+2GFWmOE5v1hb2eHi/KFM+qasoHOM5KV76gb1DnDTGRJwbdxMeoX1O1G6FyrfsaYGzeUCR4wgrnhJJEsufi+cF0N8C8iWhwD3A6sBe4G7gDuyWM+kFLqGE4SObR4qIDoLOCtgK4j/14wXOxydZQReiyuqsa9QP1EgTexKakfB64DJgIX5t+EPM43iaTGlNKJESDxdsJS+sK+pL5KRKsALwOHgKNEmeUUsDqldKhqmvYD9SSRfPWGYxiVip5w1lh0BpOZDRrq4X7M6XQdkSfUAqOJ3HYUUJ+vTQSOjRiDQH8OJdUB19D1db1BVOqOAgeAjVVRrTjO7+f+63XA9UQhYAxB5gKiBNkIfAmYpLallI5XU9OeYKSj/ZFoQ61Tf9bNzl4zQpCp2SavHA6lu0NdUMDFPlkHfBZYRZjNHOBiYDuwDthG5MZNwKYR4FEk5d2LulQ9alQpGtSrjSrf/WVs9zgCBV+LZXvLO3OJThw0MqxLM5GPqavVv6vzh5lAEVNSnVmXUmpVXyJKKE8R5vM34DHgGeBVYCml6t9wEEjA6gKiL6aUnu/stCaz+oD6DXW9USzQiKXWGZHu+6qqfUY26SJYW95pprG/ME09lwVeU39hKRx+ybJ8o4oEphlztAgau3depl6bb/7RrpWHjca+wYtG5je6SgTq83OKoLmnAWoykXvV01mwLZ+fVA+pDxrZ3ga1fogJjFV/X5CA9rZ2GRWPTmyztPfWalT9Dlh6W09YYO+gIIEpRlWlKLbam8tXZxt12HvVI7nDP9SncnujelPZYK+onx8kgWssPgc0agFdHEyXvDlXvK8HvkzET7uIvGIu0EJsoHTmHmeAPwMz1B+qCypQvFb9pLoNeBB4RwW8V6WUWrro3cMDRhHbW4kICmcBuzMZgV8SIfpB4GYikfoUsRFzCbG+PA60EtFwGxHmTyVK+/OBxQystN8MXJFSOtcniUykAfgQEbvUE3sPY4hUcTxwF7EgLiJ2iBYBDwNXD0CxotgPzEkp9ZeulqBOVH9leIynjZJ6u/pVY8+iQ91leLI31WcqsOtK8bI6Y0DUjVrUkW4DXmUpMPttPm6xemhV39WXnn0WxFJKu4md0R1llycD7yZs/fJ8rVop7HZgbkpp76BHMkL0Ow0TWm9EtRvyP1UNUzqnrjWczNDCCM13qjdbCkuah5jALrWpf20GR6RWfadRJdTSvBgsWoywp66qBHogs9j45qNtgIqfMCLlhQ6iYD0kKac6hsjDm4gqyXTgIqCBqKC0AScpfbTVQumjrXM9jVkJ/gfEGHquO3j8DQAAAABJRU5ErkJggg== [btb-link]: https://ki.se/forskning/barntumorbanken-0 diff --git a/containers/snpeff/Dockerfile b/containers/snpeff/Dockerfile new file mode 100644 index 0000000000..046938ba11 --- /dev/null +++ b/containers/snpeff/Dockerfile @@ -0,0 +1,17 @@ +FROM nfcore/base:latest + +LABEL \ + author="Maxime Garcia" \ + description="snpEff image for use in nf-core/sarek" \ + maintainer="maxime.garcia@scilifelab.se" + +COPY environment.yml / +RUN conda env create -f /environment.yml && conda clean -a +ENV PATH /opt/conda/envs/sarek-snpeff-2.5dev/bin:$PATH + +# Setup default ARG variables +ARG CACHE_VERSION=86 +ARG GENOME=GRCh38 + +# Download Genome +RUN snpEff download -v ${GENOME}.{CACHE_VERSION} diff --git a/containers/snpeff/environment.yml b/containers/snpeff/environment.yml new file mode 100644 index 0000000000..5e48bdb781 --- /dev/null +++ b/containers/snpeff/environment.yml @@ -0,0 +1,10 @@ +# You can use this file to create a conda environment for this pipeline: +# conda env create -f environment.yml +name: sarek-snpeff-2.5dev +channels: + - conda-forge + - bioconda + - defaults + +dependencies: + - snpeff=4.3.1t diff --git a/containers/vep/Dockerfile b/containers/vep/Dockerfile new file mode 100644 index 0000000000..0b8949d73c --- /dev/null +++ b/containers/vep/Dockerfile @@ -0,0 +1,26 @@ +FROM nfcore/base:latest + +LABEL \ + author="Maxime Garcia" \ + description="VEP image for use in nf-core/sarek" \ + maintainer="maxime.garcia@scilifelab.se" + +COPY environment.yml / +RUN conda env create -f /environment.yml && conda clean -a +ENV PATH /opt/conda/envs/sarek-vep-2.5dev/bin:$PATH + +# Setup default ARG variables +ARG GENOME=GRCh38 +ARG SPECIES=homo_sapiens +ARG VEP_VERSION=95 + +# Download Genome +RUN vep_install \ + -a c \ + -c .vep \ + -s ${SPECIES} \ + -v ${VEP_VERSION} \ + -y ${GENOME} \ + --CACHE_VERSION ${VEP_VERSION} \ + --CONVERT \ + --NO_HTSLIB --NO_TEST --NO_BIOPERL --NO_UPDATE diff --git a/containers/vep/environment.yml b/containers/vep/environment.yml new file mode 100644 index 0000000000..5fd86c3cdc --- /dev/null +++ b/containers/vep/environment.yml @@ -0,0 +1,11 @@ +# You can use this file to create a conda environment for this pipeline: +# conda env create -f environment.yml +name: sarek-vep-2.5dev +channels: + - conda-forge + - bioconda + - defaults + +dependencies: + - ensembl-vep=95.2 + - genesplicer=1.0 From 3c5f23682c429eb810737cbd413dabfef404de15 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Wed, 8 May 2019 16:31:08 +0200 Subject: [PATCH 014/854] Nf core vc (#7) * Add Annotation * Annotation containers are tagged version.genomeversion * Better indentation * Replace `--sampleDir` by `--sample` * add MultiQC * update Tests * Add parallelized testing on Travis * Add parallelized building of Docker Images for annotation on CircleCI * Update docs --- .circleci/config.yml | 111 ++ .travis.yml | 22 +- Jenkinsfile | 29 +- README.md | 12 +- bin/build_reference.sh | 38 + bin/download_docker.sh | 32 + bin/run_tests.sh | 66 + build.nf | 14 +- containers/snpeff/Dockerfile | 4 +- containers/vep/Dockerfile | 2 +- docs/images/social_preview_image.png | Bin 0 -> 46389 bytes docs/images/social_preview_image.svg | 649 +++++++ main.nf | 2527 ++++++++++++++------------ nextflow.config | 10 + 14 files changed, 2363 insertions(+), 1153 deletions(-) create mode 100644 .circleci/config.yml create mode 100755 bin/build_reference.sh create mode 100755 bin/download_docker.sh create mode 100755 bin/run_tests.sh create mode 100644 docs/images/social_preview_image.png create mode 100644 docs/images/social_preview_image.svg diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000000..0390dca9e0 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,111 @@ +version: 2.0 +jobs: + snpeffgrch37: + docker: + - image: circleci/buildpack-deps:stretch + environment: + GENOME: GRCh37 + SNPEFF_CACHE_VERSION: 75 + steps: + - checkout + - setup_remote_docker + - run: + command: docker build -t nfcore/sareksnpeff:dev.${GENOME} containers/snpeff/. --build-arg GENOME=${GENOME} --build-arg SNPEFF_CACHE_VERSION=${SNPEFF_CACHE_VERSION} + - run: + command: | + echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin + docker push nfcore/sareksnpeff:dev.${GENOME} + + snpeffgrch38: + docker: + - image: circleci/buildpack-deps:stretch + environment: + GENOME: GRCh38 + SNPEFF_CACHE_VERSION: 86 + steps: + - checkout + - setup_remote_docker + - run: + command: docker build -t nfcore/sareksnpeff:dev.${GENOME} containers/snpeff/. --build-arg GENOME=${GENOME} --build-arg SNPEFF_CACHE_VERSION=${SNPEFF_CACHE_VERSION} + - run: + command: | + echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin + docker push nfcore/sareksnpeff:dev.${GENOME} + + snpeffgrcm38: + docker: + - image: circleci/buildpack-deps:stretch + environment: + GENOME: GRCm38 + SNPEFF_CACHE_VERSION: 86 + steps: + - checkout + - setup_remote_docker + - run: + command: docker build -t nfcore/sareksnpeff:dev.${GENOME} containers/snpeff/. --build-arg GENOME=${GENOME} --build-arg SNPEFF_CACHE_VERSION=${SNPEFF_CACHE_VERSION} + - run: + command: | + echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin + docker push nfcore/sareksnpeff:dev.${GENOME} + + vepgrch37: + docker: + - image: circleci/buildpack-deps:stretch + environment: + GENOME: GRCh37 + SPECIES: homo_sapiens + VEP_VERSION: 95 + steps: + - checkout + - setup_remote_docker + - run: + command: docker build -t nfcore/sarekvep:dev.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} + no_output_timeout: 45m + - run: + command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:dev.${GENOME} + no_output_timeout: 45m + + vepgrch38: + docker: + - image: circleci/buildpack-deps:stretch + environment: + GENOME: GRCh38 + SPECIES: homo_sapiens + VEP_VERSION: 95 + steps: + - checkout + - setup_remote_docker + - run: + command: docker build -t nfcore/sarekvep:dev.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} + no_output_timeout: 45m + - run: + command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:dev.${GENOME} + no_output_timeout: 45m + + vepgrcm38: + docker: + - image: circleci/buildpack-deps:stretch + environment: + GENOME: GRCm38 + SPECIES: mus_musculus + VEP_VERSION: 95 + steps: + - checkout + - setup_remote_docker + - run: + command: docker build -t nfcore/sarekvep:dev.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} + no_output_timeout: 45m + - run: + command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:dev.${GENOME} + no_output_timeout: 45m + +workflows: + version: 2 + build: + jobs: + - snpeffgrch37 + - snpeffgrch38 + - snpeffgrcm38 + - vepgrch37 + - vepgrch38 + - vepgrcm38 diff --git a/.travis.yml b/.travis.yml index ee7db79aa5..051ce4ec8e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,15 +14,20 @@ matrix: fast_finish: true env: - - NXF_VER=19.04.0 + global: + - NXF_VER=19.04.0 + matrix: + - TEST=SOMATIC + - TEST=GERMLINE + - TEST=TARGETED + - TEST=ANNOTATEVEP + - TEST=ANNOTATESNPEFF before_install: # PRs to master are only ok if coming from dev branch - '[ $TRAVIS_PULL_REQUEST = "false" ] || [ $TRAVIS_BRANCH != "master" ] || ([ $TRAVIS_PULL_REQUEST_SLUG = $TRAVIS_REPO_SLUG ] && [ $TRAVIS_PULL_REQUEST_BRANCH = "dev" ])' # Pull the docker image first so the test doesn't wait for this - - docker pull nfcore/sarek:dev - # Fake the tag locally so that the pipeline runs properly - - docker tag nfcore/sarek:dev nfcore/sarek:dev + - "travis_retry ./bin/download_docker.sh --test $TEST" install: # Install Nextflow @@ -32,7 +37,10 @@ install: # Reset - mkdir ${TRAVIS_BUILD_DIR}/tests && cd ${TRAVIS_BUILD_DIR}/tests +# Build references if needed +before_script: + - "${TRAVIS_BUILD_DIR}/bin/build_reference.sh --test $TEST --build" + +# Actual tests script: - - git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data - - nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile docker --genome smallGRCh37 --refdir data/reference --outdir references --publishDirMode link --max_memory 7.GB --max_cpus 2 -ansi-log false - - nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile docker --genome smallGRCh37 --sample data/testdata/tsv/tiny-manta.tsv --tools HaploTypeCaller,Manta,Strelka,MuTecT2,FreeBayes --igenomes_base references --publishDirMode link --max_memory 7.GB --max_cpus 2 -ansi-log false + - "${TRAVIS_BUILD_DIR}/bin/run_tests.sh --test $TEST" diff --git a/Jenkinsfile b/Jenkinsfile index 630e2e2e88..b426587cbd 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -8,26 +8,43 @@ pipeline { stages { stage('Setup environment') { steps { - sh "docker pull nfcore/sarek:dev" + sh "./bin/download_docker.sh -t ALL" } } stage('Build') { steps { sh "rm -rf data" - sh "git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data" - sh "nextflow run build.nf -profile docker --genome smallGRCh37 --refdir data/reference --outdir references --publishDirMode link -ansi-log false" + sh "./bin/build_reference.sh --test ALL --build" sh "rm -rf work/ references/pipeline_info .nextflow*" } } - stage('SampleDir') { + stage('Somatic') { steps { - sh "nextflow run main.nf -profile docker --sampleDir data/testdata/tiny/normal --tools HaplotypeCaller,Manta,Strelka --genome smallGRCh37 --igenomes_base references --publishDirMode link -ansi-log false" + sh "./bin/run_tests.sh --test SOMATIC" + sh "rm -rf work/ .nextflow* results/" + } + } + stage('Germline') { + steps { + sh "./bin/run_tests.sh --test GERMLINE" + sh "rm -rf work/ .nextflow* results/" + } + } + stage('targeted') { + steps { + sh "./bin/run_tests.sh --test TARGETED" + sh "rm -rf work/ .nextflow* results/" + } + } + stage('Annotation') { + steps { + sh "./bin/run_tests.sh --test ANNOTATEALL" sh "rm -rf work/ .nextflow* results/" } } stage('Multiple') { steps { - sh "nextflow run main.nf -profile docker --sample data/testdata/tsv/tiny-multiple.tsv --tools HaploTypeCaller,Manta,Strelka,MuTecT2,FreeBayes --genome smallGRCh37 --igenomes_base references --publishDirMode link -ansi-log false" + sh "./bin/run_tests.sh --test MULTIPLE" sh "rm -rf work/ .nextflow* results/" } } diff --git a/README.md b/README.md index 001b0622f6..fadcd83b64 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,11 @@ [![Nextflow version][nextflow-badge]](https://www.nextflow.io) [![Travis build status][travis-badge]](https://travis-ci.org/nf-core/sarek) +[![CircleCi build status][circleci-badge]](https://circleci.com/gh/nf-core/workflows/sarek) [![Install with bioconda][bioconda-badge]](http://bioconda.github.io/) -[![Docker Container available][docker-badge]](https://hub.docker.com/r/nfcore/sarek) +[![Docker Container available][docker-sarek-badge]](https://hub.docker.com/r/nfcore/sarek) +[![Install with Singularity][singularity-badge]](https://www.sylabs.io/docs/) [![Join us on Slack][slack-badge]](https://nfcore.slack.com/messages/CGFUX04HZ/) @@ -77,7 +79,7 @@ The worflow steps and tools used are as follows: * [GATK ApplyBQSR](https://github.com/broadinstitute/gatk) 2. **Germline variant calling** - `germlineVC.nf` * SNVs and small indels - * [GATK HaplotyeCaller](https://github.com/broadinstitute/gatk) + * [GATK HaplotypeCaller](https://github.com/broadinstitute/gatk) * [Strelka2](https://github.com/Illumina/strelka) * Structural variants * [Manta](https://github.com/Illumina/manta) @@ -139,10 +141,14 @@ For further information or help, don't hesitate to get in touch on [Slack](https [bioconda-badge]: https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg?logo=data:image/png;base64,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 [btb-link]: https://ki.se/forskning/barntumorbanken-0 -[docker-badge]: https://img.shields.io/docker/automated/nfcore/sarek.svg?logo=docker +[circleci-badge]: https://img.shields.io/circleci/project/github/nf-core/sarek.svg?logo=circleci +[docker-sarek-badge]: https://img.shields.io/docker/automated/nfcore/sarek.svg?logo=docker +[docker-snpeff-badge]: https://img.shields.io/docker/automated/nfcore/sareksnpeff.svg?logo=docker +[docker-vep-badge]: https://img.shields.io/docker/automated/nfcore/sarekvep.svg?logo=docker [nbis-link]: https://nbis.se [nextflow-badge]: https://img.shields.io/badge/nextflow-%E2%89%A519.04.0-brightgreen.svg?logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgd2lkdGg9IjEyLjc5OTIyOG1tIiAgIGhlaWdodD0iMTIuODA0ODA5bW0iICAgdmlld0JveD0iMCAwIDQ1LjM1MTU5NCA0NS4zNzEzNjkiICAgaWQ9InN2Zzc2NTIiICAgdmVyc2lvbj0iMS4xIiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTEgcjEzNzI1IiAgIHNvZGlwb2RpOmRvY25hbWU9Im5leHRmbG93LWZhdmljb24td2hpdGUuc3ZnIj4gIDxkZWZzICAgICBpZD0iZGVmczc2NTQiIC8+ICA8c29kaXBvZGk6bmFtZWR2aWV3ICAgICBpZD0iYmFzZSIgICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIgICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIgICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiICAgICBpbmtzY2FwZTp6b29tPSI3LjkxOTU5NTkiICAgICBpbmtzY2FwZTpjeD0iMjAuMTEzMjM1IiAgICAgaW5rc2NhcGU6Y3k9IjIzLjE2MzkwOCIgICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIgICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImxheWVyMSIgICAgIHNob3dncmlkPSJmYWxzZSIgICAgIGZpdC1tYXJnaW4tdG9wPSIwIiAgICAgZml0LW1hcmdpbi1sZWZ0PSIwIiAgICAgZml0LW1hcmdpbi1yaWdodD0iMCIgICAgIGZpdC1tYXJnaW4tYm90dG9tPSIwIiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxOTIwIiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTAxNSIgICAgIGlua3NjYXBlOndpbmRvdy14PSIwIiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjAiICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIiAvPiAgPG1ldGFkYXRhICAgICBpZD0ibWV0YWRhdGE3NjU3Ij4gICAgPHJkZjpSREY+ICAgICAgPGNjOldvcmsgICAgICAgICByZGY6YWJvdXQ9IiI+ICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4gICAgICAgIDxkYzp0eXBlICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+ICAgICAgPC9jYzpXb3JrPiAgICA8L3JkZjpSREY+ICA8L21ldGFkYXRhPiAgPGcgICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciIgICAgIGlkPSJsYXllcjEiICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMTQuMTA0MzcsLTQ1Mi41MzM2NikiPiAgICA8cGF0aCAgICAgICBzdHlsZT0iZmlsbDojZmZmZmZmIiAgICAgICBkPSJtIC0xMTQuMTA0MzcsNDU1LjQ2NTYyIDAsOC44NjEzMyAwLjIwMzEzLDAuMDYwNSBjIDMuODcyOTMsMS4xMzk0MyA4LjY1MjUxLDQuMzgzMiAxMi44MDA3OCw4LjY4NzUgMC45MTM2MywwLjk0ODAxIDEuOTcyNTY0LDIuMTA2ODQgMi4zNTM1MjQsMi41NzYxOCBsIDAuNjkxNCwwLjg1MzUxIC0wLjg2OTE0LDAuNzc1MzkgYyAtNC4xOTk5MDQsMy43NDE5MyAtOC45NzE5MDQsNi43NjYzNyAtMTQuMTA1NDc0LDguOTQxNDEgLTAuMzA5NzUsMC4xMzEyNCAtMC42OTcyMiwwLjI4MTIzIC0xLjA3NDIyLDAuNDI3NzMgbCAwLDkuMzA0NjkgYyAyLjY1OTkzLC0wLjg3NzkyIDUuMzA2MzksLTEuOTc1IDguMDYwNTUsLTMuMzUxNTYgNC4yNTYyMywtMi4xMjczMiA3LjU0MzI1NCwtNC4yNTc2NCAxMS4wMzcxMTQsLTcuMTU2MjUgMC45MjU4MSwtMC43NjgwOCAxLjgyMTA5LC0xLjUwNzAyIDEuOTkwMjMsLTEuNjQyNTggMC4yNzkzMSwtMC4yMjM4NCAwLjQ5MzMyLC0wLjA1MTQgMi4zMjQyMiwxLjg3ODkxIDYuMjIyNjUsNi41NjA0MSAxMy43ODMzNywxMC43NDQ0MyAyMS45Mzk0NiwxMi4yMjI2NSBsIDAsLTguOTQxNCBjIC00Ljc5NTM3LC0xLjE5NTkgLTkuNDIwMzEsLTMuNjQ1MTEgLTEzLjI1NzgyLC03LjA2NDQ2IC0xLjY4MzUxLC0xLjUwMDA2IC00LjI4NjgxLC00LjM1MDA5IC00LjM5MjU4LC00LjgwODU5IC0wLjA2ODYsLTAuMjk3MyA1LjQ3NDgsLTUuNzA5NzcgNy4yOTQ5MywtNy4xMjMwNSAzLjQ4MjczLC0yLjcwNDI0IDYuNTg4MjUsLTQuMTIwNDIgMTAuMjc1MzksLTQuNjg1NTQgMC4wMjc1LC0wLjAwNCAwLjA1MjcsLTAuMDA4IDAuMDgwMSwtMC4wMTE3IGwgMCwtOC43NSBjIC03LjkzOTI3LDIuMDIxMTQgLTE0Ljg3MDAxLDUuODc3MzggLTIxLjUsMTEuOTQzMzYgbCAtMS42MzA4NiwxLjQ5MjE4IC0yLjk5NjEsLTMuMDA3ODEgYyAtMS42NDc1NiwtMS42NTQ3IC0zLjc0MDI1LC0zLjYwMTU3IC00LjY1MjM0LC00LjMyNjE3IC01LjAwODU1NCwtMy45Nzg5OSAtMTAuMTUyOTU0LC02LjQ5OTIzIC0xNC41NzIyNzQsLTcuMTU2MjUgeiIgICAgICAgaWQ9InBhdGg3NjIwIiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY3NjY2NzY2Nzc2NzY2NzY3NjY2NjY2NzYyIgLz4gIDwvZz48L3N2Zz4= [ngi-link]: https://ngisweden.scilifelab.se/ [scilifelab-link]: https://scilifelab.se +[singularity-badge]: https://img.shields.io/badge/use%20with-singularity-purple.svg [slack-badge]: https://img.shields.io/badge/slack-nfcore/sarek-blue.svg?logo=slack [travis-badge]: https://img.shields.io/travis/nf-core/sarek.svg?logo=travis diff --git a/bin/build_reference.sh b/bin/build_reference.sh new file mode 100755 index 0000000000..ad01808d69 --- /dev/null +++ b/bin/build_reference.sh @@ -0,0 +1,38 @@ +#!/bin/bash +set -xeuo pipefail + +BUILD=false +TEST=ALL +TRAVIS_BUILD_DIR=${TRAVIS_BUILD_DIR:-.} +TRAVIS=${TRAVIS:-false} + +while [[ $# -gt 0 ]] +do + key=$1 + case $key in + -t|--test) + TEST=$2 + shift # past argument + shift # past value + ;; + -b|--build) + BUILD=true + shift # past value + ;; + *) # unknown option + shift # past argument + ;; + esac +done + +# Always download test data +rm -rf data +git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data + +# Build references for smallGRCh37 +if [[ BUILD ]] && [[ $TEST != ANNOTATESNPEFF ]] && [[ $TEST != ANNOTATEVEP ]] +then + rm -rf references + nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile docker -ansi-log false --publishDirMode link --max_memory 7.GB --max_cpus 2 -dump-channels --genome smallGRCh37 --refdir data/reference --outdir references + rm -rf .nextflow* references/pipeline_info work +fi diff --git a/bin/download_docker.sh b/bin/download_docker.sh new file mode 100755 index 0000000000..a4fac3bdb4 --- /dev/null +++ b/bin/download_docker.sh @@ -0,0 +1,32 @@ +#!/bin/bash +set -xeuo pipefail + +TEST=ALL + +while [[ $# -gt 0 ]] +do + key=$1 + case $key in + -t|--test) + TEST=$2 + shift # past argument + shift # past value + ;; + *) # unknown option + shift # past argument + ;; + esac +done + +if [[ ALL,ANNOTATEALL,ANNOTATEVEP =~ $TEST ]] +then + docker pull nfcore/sarekvep:dev.GRCh37 + docker tag nfcore/sarekvep:dev.GRCh37 nfcore/sarekvep:dev.smallGRCh37 +elif [[ ALL,ANNOTATEALL,ANNOTATESNPEFF =~ $TEST ]] +then + docker pull nfcore/sareksnpeff:dev.GRCh37 + docker tag nfcore/sareksnpeff:dev.GRCh37 nfcore/sareksnpeff:dev.smallGRCh37 +else + docker pull nfcore/sarek:dev + docker tag nfcore/sarek:dev nfcore/sarek:dev +fi diff --git a/bin/run_tests.sh b/bin/run_tests.sh new file mode 100755 index 0000000000..98119c2174 --- /dev/null +++ b/bin/run_tests.sh @@ -0,0 +1,66 @@ +#!/bin/bash +set -xeuo pipefail + +CPUS=2 +TEST=ALL +TRAVIS_BUILD_DIR=${TRAVIS_BUILD_DIR:-.} +TRAVIS=${TRAVIS:-false} + +while [[ $# -gt 0 ]] +do + key=$1 + case $key in + -t|--test) + TEST=$2 + shift # past argument + shift # past value + ;; + -c|--cpus) + CPUS=$2 + shift # past value + ;; + *) # unknown option + shift # past argument + ;; + esac +done + +function run_sarek() { + nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile docker -ansi-log false --publishDirMode link --max_memory 7.GB --max_cpus 2 -dump-channels --genome smallGRCh37 --igenomes_base references $@ +} + +if [[ ALL,GERMLINE =~ $TEST ]] +then + run_sarek --sample data/testdata/tiny/normal --tools HaplotypeCaller,Strelka --noReports + run_sarek --step recalibrate --noReports +fi + +if [[ ALL,SOMATIC =~ $TEST ]] +then + run_sarek --sample data/testdata/tsv/tiny-manta.tsv --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports +fi + +if [[ ALL,TARGETED =~ $TEST ]] +then + run_sarek --sample data/testdata/tsv/tiny-manta.tsv --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports --targetBED data/testdata/target.bed +fi + +if [[ ALL,ANNOTATEALL,ANNOTATESNPEFF,ANNOTATEVEP =~ $TEST ]] +then + if [[ $TEST = ANNOTATESNPEFF ]] + then + ANNOTATOR=snpEFF + elif [[ $TEST = ANNOTATEVEP ]] + then + ANNOTATOR=VEP + elif [[ ALL,ANNOTATEALL =~ $TEST ]] + then + ANNOTATOR=merge,snpEFF,VEP + fi + run_sarek --step annotate --tools ${ANNOTATOR} --annotateVCF data/testdata/vcf/Strelka_1234N_variants.vcf.gz --noReports +fi + +if [[ MULTIPLE =~ $TEST ]] +then + run_sarek --sample data/testdata/tsv/tiny-multiple.tsv --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports +fi diff --git a/build.nf b/build.nf index 6c7e19e5e3..979601371c 100644 --- a/build.nf +++ b/build.nf @@ -52,13 +52,16 @@ DOWNLOAD CACHE: */ // Show help message -if (params.help){ - helpMessage() - exit 0 -} +if (params.help) exit 0, helpMessage() ch_referencesFiles = Channel.fromPath("${params.refdir}/*") + +// Default value for params +params.cadd_cache = null +params.cadd_version = 'v1.5' params.genome = 'smallGRCh37' +params.snpEff_cache = null +params.vep_cache = null // Check if genome exists in the config file if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { @@ -303,7 +306,7 @@ process BuildCache_VEP { script: genome = params.genome == "smallGRCh37" ? "GRCh37" : params.genome - species = genome =~ "GRCh3*" ? "homo_sapiens" : "" + species = genome =~ "GRCh3*" ? "homo_sapiens" : genome =~ "GRCm3*" ? "mus_musculus" : "" """ vep_install \ -a cf \ @@ -346,7 +349,6 @@ process DownloadCADD { """ } - def nfcoreHeader(){ // Log colors ANSI codes c_reset = params.monochrome_logs ? '' : "\033[0m"; diff --git a/containers/snpeff/Dockerfile b/containers/snpeff/Dockerfile index 046938ba11..a0c35d360e 100644 --- a/containers/snpeff/Dockerfile +++ b/containers/snpeff/Dockerfile @@ -10,8 +10,8 @@ RUN conda env create -f /environment.yml && conda clean -a ENV PATH /opt/conda/envs/sarek-snpeff-2.5dev/bin:$PATH # Setup default ARG variables -ARG CACHE_VERSION=86 ARG GENOME=GRCh38 +ARG SNPEFF_CACHE_VERSION=86 # Download Genome -RUN snpEff download -v ${GENOME}.{CACHE_VERSION} +RUN snpEff download -v ${GENOME}.${SNPEFF_CACHE_VERSION} diff --git a/containers/vep/Dockerfile b/containers/vep/Dockerfile index 0b8949d73c..e0bc659d52 100644 --- a/containers/vep/Dockerfile +++ b/containers/vep/Dockerfile @@ -23,4 +23,4 @@ RUN vep_install \ -y ${GENOME} \ --CACHE_VERSION ${VEP_VERSION} \ --CONVERT \ - --NO_HTSLIB --NO_TEST --NO_BIOPERL --NO_UPDATE + --NO_BIOPERL --NO_HTSLIB --NO_TEST --NO_UPDATE diff --git a/docs/images/social_preview_image.png b/docs/images/social_preview_image.png new file mode 100644 index 0000000000000000000000000000000000000000..d43d5d473b04f90a339c3b5d316b740d7e54fadd GIT binary patch literal 46389 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 E16S?Y^Z)<= literal 0 HcmV?d00001 diff --git a/docs/images/social_preview_image.svg b/docs/images/social_preview_image.svg new file mode 100644 index 0000000000..a8e74bd243 --- /dev/null +++ b/docs/images/social_preview_image.svg @@ -0,0 +1,649 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + nf- + + + + + core + + + + + + + + + + + + + Sarek  + + + + + + + + + + An open-source analysis pipeline to detect germline orsomatic variants from whole genome or targeted sequencing + diff --git a/main.nf b/main.nf index 216f4070d6..9775904fb9 100644 --- a/main.nf +++ b/main.nf @@ -1,22 +1,22 @@ #!/usr/bin/env nextflow /* -======================================================================================== - nf-core/sarek -======================================================================================== +================================================================================ + nf-core/sarek +================================================================================ Started March 2016. Ported to nf-core May 2019. ----------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- nf-core/sarek: An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing ----------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- @Homepage https://sarek.scilifelab.se/ ----------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- @Documentation https://github.com/nf-core/sarek/README.md ----------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- */ def helpMessage() { @@ -31,51 +31,51 @@ def helpMessage() { nextflow run nf-core/sarek --sample sample.tsv -profile docker Mandatory arguments: - --sample Path to TSV input file + --sample Path to TSV input file Multiple TSV files can be specified with quotes - -profile Configuration profile to use. Can use multiple (comma separated) + Works also with a directory on mapping step with germline sample only + -profile Configuration profile to use. Can use multiple (comma separated) Available: conda, docker, singularity, awsbatch, test and more. Options: - --genome Name of iGenomes reference - --noGVCF no g.vcf output from HaplotypeCaller - --noReports disable QC reports - --nucleotidesPerSecond To estimate interval size by default 1000.0 - --sampleDir Path to input directory - --sequencing_center Name of sequencing center to be displayed in BAM file - --step Specify starting step + --genome Name of iGenomes reference + --noGVCF no g.vcf output from HaplotypeCaller + --noReports disable QC reports + --nucleotidesPerSecond To estimate interval size by default 1000.0 + --sequencing_center Name of sequencing center to be displayed in BAM file + --step Specify starting step Available: Mapping, Recalibrate, VariantCalling Default: Mapping - --strelkaBP Use Manta candidateSmallIndels for Strelka as Best Practice - --targetBED target BED file for targeted sequencing - --tools Specify tools to use for variant calling + --strelkaBP Use Manta candidateSmallIndels for Strelka as Best Practice + --targetBED target BED file for targeted sequencing + --tools Specify tools to use for variant calling Available: ASCAT, ControlFREEC, FreeBayes, HaplotypeCaller Manta, mpileup, MuTect2, Strelka References If not specified in the configuration file or you wish to overwrite any of the references. - --acLoci acLoci file - --acLociGC acLoci GC file - --bwaIndex bwa indexes - --dbsnp dbsnp file - --dbsnpIndex dbsnp index - --genomeDict genome dict - --genomeFile genome file - --genomeIndex genome index - --intervals intervals - --knownIndels knownIndels file - --knownIndelsIndex knownIndels index - --snpeffDb snpeffDb version - --vepCacheVersion VEP Cache version + --acLoci acLoci file + --acLociGC acLoci GC file + --bwaIndex bwa indexes + --dbsnp dbsnp file + --dbsnpIndex dbsnp index + --genomeDict genome dict + --genomeFile genome file + --genomeIndex genome index + --intervals intervals + --knownIndels knownIndels file + --knownIndelsIndex knownIndels index + --snpeffDb snpeffDb version + --vepCacheVersion VEP Cache version Other options: - --outdir The output directory where the results will be saved - --email 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 - --maxMultiqcEmailFileSize Theshold size for MultiQC report to be attached in notification email. If file generated by pipeline exceeds the threshold, it will not be attached (Default: 25MB) - -name Name for the pipeline run. If not specified, Nextflow will automatically generate a random mnemonic + --outdir The output directory where the results will be saved + --email 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 + --maxMultiqcEmailFileSize Theshold size for MultiQC report to be attached in notification email. If file generated by pipeline exceeds the threshold, it will not be attached (Default: 25MB) + -name Name for the pipeline run. If not specified, Nextflow will automatically generate a random mnemonic AWSBatch options: - --awsqueue The AWSBatch JobQueue that needs to be set when running on AWSBatch - --awsregion The AWS Region for your AWS Batch job to run on + --awsqueue The AWSBatch JobQueue that needs to be set when running on AWSBatch + --awsregion The AWS Region for your AWS Batch job to run on """.stripIndent() } @@ -92,11 +92,17 @@ if (params.genomes && params.genome && !params.genomes.containsKey(params.genome } // Default value for params +params.annotateTools = null +params.annotateVCF = null +params.annotation_cache = null +params.cadd_InDels = null +params.cadd_InDels_tbi = null +params.cadd_WG_SNVs = null +params.cadd_WG_SNVs_tbi = null params.noGVCF = null params.noReports = null params.nucleotidesPerSecond = 1000.0 params.sample = null -params.sampleDir = null params.sequencing_center = null params.step = 'mapping' params.strelkaBP = true @@ -105,32 +111,32 @@ params.tools = null stepList = defineStepList() step = params.step ? params.step.toLowerCase() : '' -if (step == 'preprocessing' || step == '') step = 'mapping' -if (!checkParameterExistence(step, stepList)) exit 1, 'Unknown step, see --help for more information' -if (step.contains(',')) exit 1, 'You can choose only one step, see --help for more information' -if (step == 'mapping' && ([params.sample, params.sampleDir].size == 1)) - exit 1, 'Please define which samples to work on by providing exactly one of the --sample or --sampleDir options' +if ( step == 'preprocessing' ) step = 'mapping' +if ( !checkParameterExistence(step, stepList) ) exit 1, 'Unknown step, see --help for more information' +if ( step.contains(',') ) exit 1, 'You can choose only one step, see --help for more information' tools = params.tools ? params.tools.split(',').collect{it.trim().toLowerCase()} : [] +annotateTools = params.annotateTools ? params.annotateTools.split(',').collect{it.trim().toLowerCase()} : [] +annotateVCF = params.annotateVCF ? params.annotateVCF.split(',').collect{it.trim()} : [] toolList = defineToolList() -if (!checkParameterList(tools,toolList)) exit 1, 'Unknown tool(s), see --help for more information' +if ( !checkParameterList(tools,toolList) ) exit 1, 'Unknown tool(s), see --help for more information' referenceMap = defineReferenceMap(step, tools) -if (!checkReferenceMap(referenceMap)) exit 1, 'Missing Reference file(s), see --help for more information' +if ( !checkReferenceMap(referenceMap) ) exit 1, 'Missing Reference file(s), see --help for more information' // Has the run name been specified by the user? -// this has the bonus effect of catching both -name and --name +// this has the bonus effect of catching both -name and --name custom_runName = params.name -if ( !(workflow.runName ==~ /[a-z]+_[a-z]+/) )custom_runName = workflow.runName +if ( !(workflow.runName ==~ /[a-z]+_[a-z]+/) ) custom_runName = workflow.runName if ( workflow.profile == 'awsbatch') { - // AWSBatch sanity checking - if (!params.awsqueue || !params.awsregion) exit 1, "Specify correct --awsqueue and --awsregion parameters on AWSBatch!" - // Check outdir paths to be S3 buckets if running on AWSBatch - // related: https://github.com/nextflow-io/nextflow/issues/813 - if (!params.outdir.startsWith('s3:')) exit 1, "Outdir not on S3 - specify S3 Bucket to run on AWSBatch!" - // Prevent trace files to be stored on S3 since S3 does not support rolling files. - if (workflow.tracedir.startsWith('s3:')) exit 1, "Specify a local tracedir or run without trace! S3 cannot be used for tracefiles." + // AWSBatch sanity checking + if ( !params.awsqueue || !params.awsregion ) exit 1, "Specify correct --awsqueue and --awsregion parameters on AWSBatch!" + // Check outdir paths to be S3 buckets if running on AWSBatch + // related: https://github.com/nextflow-io/nextflow/issues/813 + if ( !params.outdir.startsWith('s3:') ) exit 1, "Outdir not on S3 - specify S3 Bucket to run on AWSBatch!" + // Prevent trace files to be stored on S3 since S3 does not support rolling files. + if ( workflow.tracedir.startsWith('s3:') ) exit 1, "Specify a local tracedir or run without trace! S3 cannot be used for tracefiles." } // Stage config files @@ -140,77 +146,74 @@ ch_output_docs = Channel.fromPath("${baseDir}/docs/output.md") /* * Create a channel for input read files */ - tsvPath = '' - if (params.sample) tsvPath = params.sample + +tsvPath = null +if (params.sample) if (hasExtension(params.sample,"tsv")) tsvPath = params.sample // No need for tsv file for step annotate - if (!params.sample && !params.sampleDir) { - tsvPaths = [ - 'recalibrate': "${params.outdir}/Preprocessing/TSV/duplicateMarked.tsv", - 'variantcalling': "${params.outdir}/Preprocessing/TSV/recalibrated.tsv" - ] - if (step != 'mapping') tsvPath = tsvPaths[step] - } - - // Set up the inputFiles and bamFiles channels. One of them will remain empty - inputFiles = Channel.empty() - bamFiles = Channel.empty() - if (tsvPath) { - tsvFile = file(tsvPath) - switch (step) { - case 'mapping': inputFiles = extractSample(tsvFile); break - case 'recalibrate': bamFiles = extractRecal(tsvFile); break - case 'variantcalling': bamFiles = extractBams(tsvFile); break - default: exit 1, "Unknown step ${step}" - } - } else if (params.sampleDir) { - if (step != 'mapping') exit 1, '--sampleDir does not support steps other than "mapping"' - inputFiles = extractFastqFromDir(params.sampleDir) - (inputFiles, fastqTmp) = inputFiles.into(2) - fastqTmp.toList().subscribe onNext: { - if (it.size() == 0) { - exit 1, "No FASTQ files found in --sampleDir directory '${params.sampleDir}'" - } - } - tsvFile = params.sampleDir // used in the reports - } else exit 1, 'No sample were defined, see --help' - - if (step == 'recalibrate') (patientGenders, bamFiles) = extractGenders(bamFiles) - else (patientGenders, inputFiles) = extractGenders(inputFiles) +if (!params.sample) { + tsvPaths = [ 'recalibrate': "${params.outdir}/Preprocessing/TSV/duplicateMarked.tsv", + 'variantcalling': "${params.outdir}/Preprocessing/TSV/recalibrated.tsv" ] + if (step != 'mapping') tsvPath = tsvPaths[step] +} + +// Set up the inputFiles and bamFiles channels. One of them will remain empty +inputFiles = Channel.empty() +bamFiles = Channel.empty() +if (tsvPath) { + tsvFile = file(tsvPath) + switch (step) { + case 'mapping': inputFiles = extractSample(tsvFile); break + case 'recalibrate': bamFiles = extractRecal(tsvFile); break + case 'variantcalling': bamFiles = extractBams(tsvFile); break + default: exit 1, "Unknown step ${step}" + } +} else if (params.sample) if (!hasExtension(params.sample,"tsv")) { + println "no tsv file" + if (step != 'mapping') exit 1, 'No other step than "mapping" support a dir as an input' + inputFiles = extractFastqFromDir(params.sample) + (inputFiles, fastqTmp) = inputFiles.into(2) + fastqTmp.toList().subscribe onNext: { + if (it.size() == 0) exit 1, "No FASTQ files found in --sample directory '${params.sample}'" +} +tsvFile = params.sample // used in the reports +} else exit 1, 'No sample were defined, see --help' + +if (step == 'recalibrate') (patientGenders, bamFiles) = extractGenders(bamFiles) +else (patientGenders, inputFiles) = extractGenders(inputFiles) // Header log info log.info nfcoreHeader() def summary = [:] -if (workflow.revision) summary['Pipeline Release'] = workflow.revision -summary['Run Name'] = custom_runName ?: workflow.runName -summary['Max Resources'] = "${params.max_memory} memory, ${params.max_cpus} cpus, ${params.max_time} time per job" -if (workflow.containerEngine) summary['Container'] = "${workflow.containerEngine} - ${workflow.container}" -if (params.sample) summary['Sample'] = params.sample -if (params.sampleDir) summary['Sample'] = params.sampleDir -if (params.targetBED) summary['Target BED'] = params.targetBED -if (params.step) summary['Step'] = params.step -if (params.tools) summary['Tools'] = tools.join(', ') -if (params.noReports) summary['Reports'] = params.noReports -if (params.noGVCF) summary['GVCF'] = params.noGVCF -if (params.strelkaBP) summary['Strelka BP'] = params.strelkaBP -if (params.sequencing_center) summary['Sequencing Center'] = params.sequencing_center -summary['Nucleotides/s'] = params.nucleotidesPerSecond -summary['Output dir'] = params.outdir -summary['Launch dir'] = workflow.launchDir -summary['Working dir'] = workflow.workDir -summary['Script dir'] = workflow.projectDir -summary['User'] = workflow.userName +if (workflow.revision) summary['Pipeline Release'] = workflow.revision +summary['Run Name'] = custom_runName ?: workflow.runName +summary['Max Resources'] = "${params.max_memory} memory, ${params.max_cpus} cpus, ${params.max_time} time per job" +if (workflow.containerEngine) summary['Container'] = "${workflow.containerEngine} - ${workflow.container}" +if (params.sample) summary['Sample'] = params.sample +if (params.targetBED) summary['Target BED'] = params.targetBED +if (params.step) summary['Step'] = params.step +if (params.tools) summary['Tools'] = tools.join(', ') +if (params.noReports) summary['Reports'] = params.noReports +if (params.noGVCF) summary['GVCF'] = params.noGVCF +if (params.strelkaBP) summary['Strelka BP'] = params.strelkaBP +if (params.sequencing_center) summary['Sequenced by '] = params.sequencing_center +summary['Nucleotides/s'] = params.nucleotidesPerSecond +summary['Output dir'] = params.outdir +summary['Launch dir'] = workflow.launchDir +summary['Working dir'] = workflow.workDir +summary['Script dir'] = workflow.projectDir +summary['User'] = workflow.userName if (workflow.profile == 'awsbatch'){ - summary['AWS Region'] = params.awsregion - summary['AWS Queue'] = params.awsqueue + summary['AWS Region'] = params.awsregion + summary['AWS Queue'] = params.awsqueue } summary['Config Profile'] = workflow.profile -if (params.config_profile_description) summary['Config Description'] = params.config_profile_description -if (params.config_profile_contact) summary['Config Contact'] = params.config_profile_contact -if (params.config_profile_url) summary['Config URL'] = params.config_profile_url +if (params.config_profile_description) summary['Config Description'] = params.config_profile_description +if (params.config_profile_contact) summary['Config Contact'] = params.config_profile_contact +if (params.config_profile_url) summary['Config URL'] = params.config_profile_url if (params.email) { - summary['E-mail Address'] = params.email - summary['MultiQC maxsize'] = params.maxMultiqcEmailFileSize + summary['E-mail Address'] = params.email + summary['MultiQC maxsize'] = params.maxMultiqcEmailFileSize } log.info summary.collect { k,v -> "${k.padRight(18)}: $v" }.join("\n") log.info "\033[2m----------------------------------------------------\033[0m" @@ -242,7 +245,9 @@ process get_software_versions { publishDir path:"${params.outdir}/pipeline_info", mode: params.publishDirMode output: - file 'software_versions_mqc.yaml' into software_versions_yaml + file 'software_versions_mqc.yaml' into software_versions_yaml + + when: !params.noReports script: """ @@ -269,10 +274,12 @@ process get_software_versions { """ } +software_versions_yaml = software_versions_yaml.dump(tag: 'SOFTWARE VERSIONS') + /* -======================================================================================== - PREPROCESSING -======================================================================================== +================================================================================ + PREPROCESSING +================================================================================ */ // STEP ONE: MAPPING @@ -282,132 +289,132 @@ process get_software_versions { inputFiles = inputFiles.dump(tag:'INPUT') process RunFastQC { - tag {idPatient + "-" + idRun} + tag {idPatient + "-" + idRun} - publishDir "${params.outdir}/Reports/${idSample}/FastQC/${idRun}", mode: params.publishDirMode + publishDir "${params.outdir}/Reports/${idSample}/FastQC/${idRun}", mode: params.publishDirMode - input: - set idPatient, status, idSample, idRun, file(inputFile1), file(inputFile2) from inputFilesforFastQC + input: + set idPatient, status, idSample, idRun, file(inputFile1), file(inputFile2) from inputFilesforFastQC - output: - file "*_fastqc.{zip,html}" into fastQCreport + output: + file "*_fastqc.{zip,html}" into fastQCreport - when: step == 'mapping' && !params.noReports + when: step == 'mapping' && !params.noReports - script: - inputFiles = (hasExtension(inputFile1,"fastq.gz") || hasExtension(inputFile1,"fq.gz")) ? "${inputFile1} ${inputFile2}" : "${inputFile1}" - """ - fastqc -t 2 -q ${inputFiles} - """ + script: + inputFiles = (hasExtension(inputFile1,"fastq.gz") || hasExtension(inputFile1,"fq.gz")) ? "${inputFile1} ${inputFile2}" : "${inputFile1}" + """ + fastqc -t 2 -q ${inputFiles} + """ } -fastQCreport.dump(tag:'FastQC') +fastQCreport = fastQCreport.dump(tag:'FastQC') process MapReads { - tag {idPatient + "-" + idRun} + tag {idPatient + "-" + idRun} - input: - set idPatient, status, idSample, idRun, file(inputFile1), file(inputFile2) from inputFiles - set file(genomeFile), file(bwaIndex) from Channel.value([referenceMap.genomeFile, referenceMap.bwaIndex]) + input: + set idPatient, status, idSample, idRun, file(inputFile1), file(inputFile2) from inputFiles + set file(genomeFile), file(bwaIndex) from Channel.value([referenceMap.genomeFile, referenceMap.bwaIndex]) - output: - set idPatient, status, idSample, idRun, file("${idRun}.bam") into (mappedBam, mappedBamForQC) + output: + set idPatient, status, idSample, idRun, file("${idRun}.bam") into (mappedBam, mappedBamForQC) - when: step == 'mapping' + when: step == 'mapping' - script: - CN = params.sequencing_center ? "CN:${params.sequencing_center}\\t" : "" - readGroup = "@RG\\tID:${idRun}\\t${CN}PU:${idRun}\\tSM:${idSample}\\tLB:${idSample}\\tPL:illumina" - // adjust mismatch penalty for tumor samples - extra = status == 1 ? "-B 3" : "" - if (hasExtension(inputFile1,"fastq.gz") || hasExtension(inputFile1,"fq.gz")) + script: + // -K is an hidden option, used to fix the number of reads processed by bwa mem + // Chunk size can affect bwa results, if not specified, the number of threads can change + // which can give not deterministic result. + // cf https://github.com/CCDG/Pipeline-Standardization/blob/master/PipelineStandard.md + // and https://github.com/gatk-workflows/gatk4-data-processing/blob/8ffa26ff4580df4ac3a5aa9e272a4ff6bab44ba2/processing-for-variant-discovery-gatk4.b37.wgs.inputs.json#L29 + CN = params.sequencing_center ? "CN:${params.sequencing_center}\\t" : "" + readGroup = "@RG\\tID:${idRun}\\t${CN}PU:${idRun}\\tSM:${idSample}\\tLB:${idSample}\\tPL:illumina" + // adjust mismatch penalty for tumor samples + extra = status == 1 ? "-B 3" : "" + if (hasExtension(inputFile1,"fastq.gz") || hasExtension(inputFile1,"fq.gz")) """ - bwa mem -K 100000000 -R \"${readGroup}\" ${extra} -t ${task.cpus} -M \ - ${genomeFile} ${inputFile1} ${inputFile2} | \ - samtools sort --threads ${task.cpus} -m 2G - > ${idRun}.bam + bwa mem -K 100000000 -R \"${readGroup}\" ${extra} -t ${task.cpus} -M \ + ${genomeFile} ${inputFile1} ${inputFile2} | \ + samtools sort --threads ${task.cpus} -m 2G - > ${idRun}.bam """ - else if (hasExtension(inputFile1,"bam")) - // -K is an hidden option, used to fix the number of reads processed by bwa mem - // Chunk size can affect bwa results, if not specified, the number of threads can change - // which can give not deterministic result. - // cf https://github.com/CCDG/Pipeline-Standardization/blob/master/PipelineStandard.md - // and https://github.com/gatk-workflows/gatk4-data-processing/blob/8ffa26ff4580df4ac3a5aa9e272a4ff6bab44ba2/processing-for-variant-discovery-gatk4.b37.wgs.inputs.json#L29 + else if (hasExtension(inputFile1,"bam")) """ - gatk --java-options -Xmx${task.memory.toGiga()}g \ - SamToFastq \ - --INPUT=${inputFile1} \ - --FASTQ=/dev/stdout \ - --INTERLEAVE=true \ - --NON_PF=true \ - | \ - bwa mem -K 100000000 -p -R \"${readGroup}\" ${extra} -t ${task.cpus} -M ${genomeFile} \ - /dev/stdin - 2> >(tee ${inputFile1}.bwa.stderr.log >&2) \ - | \ - samtools sort --threads ${task.cpus} -m 2G - > ${idRun}.bam + gatk --java-options -Xmx${task.memory.toGiga()}g \ + SamToFastq \ + --INPUT=${inputFile1} \ + --FASTQ=/dev/stdout \ + --INTERLEAVE=true \ + --NON_PF=true \ + | \ + bwa mem -K 100000000 -p -R \"${readGroup}\" ${extra} -t ${task.cpus} -M ${genomeFile} \ + /dev/stdin - 2> >(tee ${inputFile1}.bwa.stderr.log >&2) \ + | \ + samtools sort --threads ${task.cpus} -m 2G - > ${idRun}.bam """ } mappedBam = mappedBam.dump(tag:'Mapped BAM') process RunBamQCmapped { - tag {idPatient + "-" + idSample} + tag {idPatient + "-" + idSample} - publishDir "${params.outdir}/Reports/${idSample}/bamQC", mode: params.publishDirMode + publishDir "${params.outdir}/Reports/${idSample}/bamQC", mode: params.publishDirMode - input: - set idPatient, status, idSample, idRun, file(bam) from mappedBamForQC - file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") + input: + set idPatient, status, idSample, idRun, file(bam) from mappedBamForQC + file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") - output: - file("${bam.baseName}") into bamQCmappedReport + output: + file("${bam.baseName}") into bamQCmappedReport - when: !params.noReports + when: !params.noReports - script: - use_bed = params.targetBED ? "-gff ${targetBED}" : '' - """ - qualimap --java-mem-size=${task.memory.toGiga()}G \ - bamqc \ - -bam ${bam} \ - --paint-chromosome-limits \ - --genome-gc-distr HUMAN \ - $use_bed \ - -nt ${task.cpus} \ - -skip-duplicated \ - --skip-dup-mode 0 \ - -outdir ${bam.baseName} \ - -outformat HTML - """ + script: + use_bed = params.targetBED ? "-gff ${targetBED}" : '' + """ + qualimap --java-mem-size=${task.memory.toGiga()}G \ + bamqc \ + -bam ${bam} \ + --paint-chromosome-limits \ + --genome-gc-distr HUMAN \ + $use_bed \ + -nt ${task.cpus} \ + -skip-duplicated \ + --skip-dup-mode 0 \ + -outdir ${bam.baseName} \ + -outformat HTML + """ } -bamQCmappedReport.dump(tag:'BamQC BAM') +bamQCmappedReport = bamQCmappedReport.dump(tag:'BamQC BAM') // Sort bam whether they are standalone or should be merged singleBam = Channel.create() groupedBam = Channel.create() mappedBam.groupTuple(by:[0,1,2]) - .choice(singleBam, groupedBam) {it[3].size() > 1 ? 1 : 0} + .choice(singleBam, groupedBam) {it[3].size() > 1 ? 1 : 0} singleBam = singleBam.map { - idPatient, status, idSample, idRun, bam -> - [idPatient, status, idSample, bam] + idPatient, status, idSample, idRun, bam -> + [idPatient, status, idSample, bam] } process MergeBams { - tag {idPatient + "-" + idSample} + tag {idPatient + "-" + idSample} - input: - set idPatient, status, idSample, idRun, file(bam) from groupedBam + input: + set idPatient, status, idSample, idRun, file(bam) from groupedBam - output: - set idPatient, status, idSample, file("${idSample}.bam") into mergedBam + output: + set idPatient, status, idSample, file("${idSample}.bam") into mergedBam - when: step == 'mapping' + when: step == 'mapping' - script: - """ - samtools merge --threads ${task.cpus} ${idSample}.bam ${bam} - """ + script: + """ + samtools merge --threads ${task.cpus} ${idSample}.bam ${bam} + """ } singleBam = singleBam.dump(tag:'Single BAM') @@ -416,36 +423,36 @@ mergedBam = mergedBam.mix(singleBam) mergedBam = mergedBam.dump(tag:'BAM for MD') process MarkDuplicates { - tag {idPatient + "-" + idSample} + tag {idPatient + "-" + idSample} - publishDir params.outdir, mode: params.publishDirMode, - saveAs: { - if (it == "${idSample}.bam.metrics") "Reports/${idSample}/MarkDuplicates/${it}" - else "Preprocessing/${idSample}/DuplicateMarked/${it}" - } + publishDir params.outdir, mode: params.publishDirMode, + saveAs: { + if (it == "${idSample}.bam.metrics") "Reports/${idSample}/MarkDuplicates/${it}" + else "Preprocessing/${idSample}/DuplicateMarked/${it}" + } - input: - set idPatient, status, idSample, file("${idSample}.bam") from mergedBam + input: + set idPatient, status, idSample, file("${idSample}.bam") from mergedBam - output: - set idPatient, file("${idSample}_${status}.md.bam"), file("${idSample}_${status}.md.bai") into duplicateMarkedBams - file ("${idSample}.bam.metrics") into markDuplicatesReport + output: + set idPatient, file("${idSample}_${status}.md.bam"), file("${idSample}_${status}.md.bai") into duplicateMarkedBams + file ("${idSample}.bam.metrics") into markDuplicatesReport - when: step == 'mapping' + when: step == 'mapping' - script: - markdup_java_options = task.memory.toGiga() > 8 ? params.markdup_java_options : "\"-Xms" + (task.memory.toGiga() / 2 ).trunc() + "g -Xmx" + (task.memory.toGiga() - 1) + "g\"" - """ - gatk --java-options ${markdup_java_options} \ - MarkDuplicates \ - --MAX_RECORDS_IN_RAM 50000 \ - --INPUT ${idSample}.bam \ - --METRICS_FILE ${idSample}.bam.metrics \ - --TMP_DIR . \ - --ASSUME_SORT_ORDER coordinate \ - --CREATE_INDEX true \ - --OUTPUT ${idSample}_${status}.md.bam - """ + script: + markdup_java_options = task.memory.toGiga() > 8 ? params.markdup_java_options : "\"-Xms" + (task.memory.toGiga() / 2 ).trunc() + "g -Xmx" + (task.memory.toGiga() - 1) + "g\"" + """ + gatk --java-options ${markdup_java_options} \ + MarkDuplicates \ + --MAX_RECORDS_IN_RAM 50000 \ + --INPUT ${idSample}.bam \ + --METRICS_FILE ${idSample}.bam.metrics \ + --TMP_DIR . \ + --ASSUME_SORT_ORDER coordinate \ + --CREATE_INDEX true \ + --OUTPUT ${idSample}_${status}.md.bam + """ } duplicateMarkedBams = duplicateMarkedBams.map { @@ -461,62 +468,64 @@ duplicateMarkedBams = duplicateMarkedBams.dump(tag:'MD BAM') (mdBam, mdBamToJoin) = duplicateMarkedBams.into(2) process CreateIntervalBeds { - tag {intervals.fileName} + tag {intervals.fileName} - input: - file(intervals) from Channel.value(referenceMap.intervals) + input: + file(intervals) from Channel.value(referenceMap.intervals) - output: - file '*.bed' into bedIntervals mode flatten + output: + file '*.bed' into bedIntervals mode flatten - script: - // If the interval file is BED format, the fifth column is interpreted to - // contain runtime estimates, which is then used to combine short-running jobs - if (hasExtension(intervals,"bed")) - """ - awk -vFS="\t" '{ - t = \$5 # runtime estimate - if (t == "") { - # no runtime estimate in this row, assume default value - t = (\$3 - \$2) / ${params.nucleotidesPerSecond} - } - if (name == "" || (chunk > 600 && (chunk + t) > longest * 1.05)) { - # start a new chunk - name = sprintf("%s_%d-%d.bed", \$1, \$2+1, \$3) - chunk = 0 - longest = 0 - } - if (t > longest) - longest = t - chunk += t - print \$0 > name - }' ${intervals} - """ - else - """ - awk -vFS="[:-]" '{ - name = sprintf("%s_%d-%d", \$1, \$2, \$3); - printf("%s\\t%d\\t%d\\n", \$1, \$2-1, \$3) > name ".bed" - }' ${intervals} - """ + when: step != 'annotate' + + script: + // If the interval file is BED format, the fifth column is interpreted to + // contain runtime estimates, which is then used to combine short-running jobs + if (hasExtension(intervals,"bed")) + """ + awk -vFS="\t" '{ + t = \$5 # runtime estimate + if (t == "") { + # no runtime estimate in this row, assume default value + t = (\$3 - \$2) / ${params.nucleotidesPerSecond} + } + if (name == "" || (chunk > 600 && (chunk + t) > longest * 1.05)) { + # start a new chunk + name = sprintf("%s_%d-%d.bed", \$1, \$2+1, \$3) + chunk = 0 + longest = 0 + } + if (t > longest) + longest = t + chunk += t + print \$0 > name + }' ${intervals} + """ + else + """ + awk -vFS="[:-]" '{ + name = sprintf("%s_%d-%d", \$1, \$2, \$3); + printf("%s\\t%d\\t%d\\n", \$1, \$2-1, \$3) > name ".bed" + }' ${intervals} + """ } bedIntervals = bedIntervals - .map { intervalFile -> - def duration = 0.0 - for (line in intervalFile.readLines()) { - final fields = line.split('\t') - if (fields.size() >= 5) duration += fields[4].toFloat() - else { - start = fields[1].toInteger() - end = fields[2].toInteger() - duration += (end - start) / params.nucleotidesPerSecond - } - } - [duration, intervalFile] - }.toSortedList({ a, b -> b[0] <=> a[0] }) - .flatten().collate(2) - .map{duration, intervalFile -> intervalFile} + .map { intervalFile -> + def duration = 0.0 + for (line in intervalFile.readLines()) { + final fields = line.split('\t') + if (fields.size() >= 5) duration += fields[4].toFloat() + else { + start = fields[1].toInteger() + end = fields[2].toInteger() + duration += (end - start) / params.nucleotidesPerSecond + } + } + [duration, intervalFile] + }.toSortedList({ a, b -> b[0] <=> a[0] }) + .flatten().collate(2) + .map{duration, intervalFile -> intervalFile} bedIntervals = bedIntervals.dump(tag:'bedintervals') @@ -525,83 +534,83 @@ bedIntervals = bedIntervals.dump(tag:'bedintervals') bamForBaseRecalibrator = mdBam.combine(bedIntervalsBR) process CreateRecalibrationTable { - tag {idPatient + "-" + idSample + "-" + intervalBed} - - publishDir "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked", mode: params.publishDirMode, overwrite: false - - input: - set idPatient, status, idSample, file(bam), file(bai), file(intervalBed) from bamForBaseRecalibrator - set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex), file(knownIndels), file(knownIndelsIndex) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex, - referenceMap.genomeDict, - referenceMap.dbsnp, - referenceMap.dbsnpIndex, - referenceMap.knownIndels, - referenceMap.knownIndelsIndex, - ]) + tag {idPatient + "-" + idSample + "-" + intervalBed} + + publishDir "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked", mode: params.publishDirMode, overwrite: false + + input: + set idPatient, status, idSample, file(bam), file(bai), file(intervalBed) from bamForBaseRecalibrator + set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex), file(knownIndels), file(knownIndelsIndex) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.genomeDict, + referenceMap.dbsnp, + referenceMap.dbsnpIndex, + referenceMap.knownIndels, + referenceMap.knownIndelsIndex, + ]) - output: - set idPatient, status, idSample, file("${intervalBed.baseName}_${idSample}.recal.table") into recalIntervals + output: + set idPatient, status, idSample, file("${intervalBed.baseName}_${idSample}.recal.table") into recalIntervals - when: step == 'mapping' + when: step == 'mapping' - script: - known = knownIndels.collect{ "--known-sites ${it}" }.join(' ') - // --use-original-qualities ??? - """ - gatk --java-options -Xmx${task.memory.toGiga()}g \ - BaseRecalibrator \ - -I ${bam} \ - -O ${intervalBed.baseName}_${idSample}.recal.table \ - --tmp-dir /tmp \ - -R ${genomeFile} \ - -L ${intervalBed} \ - --known-sites ${dbsnp} \ - ${known} \ - --verbosity INFO - """ + script: + known = knownIndels.collect{ "--known-sites ${it}" }.join(' ') + // --use-original-qualities ??? + """ + gatk --java-options -Xmx${task.memory.toGiga()}g \ + BaseRecalibrator \ + -I ${bam} \ + -O ${intervalBed.baseName}_${idSample}.recal.table \ + --tmp-dir /tmp \ + -R ${genomeFile} \ + -L ${intervalBed} \ + --known-sites ${dbsnp} \ + ${known} \ + --verbosity INFO + """ } recalIntervals = recalIntervals.groupTuple(by:[0,1,2]) process GatherBQSRReports { - tag {idPatient + "-" + idSample} + tag {idPatient + "-" + idSample} - publishDir "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked", mode: params.publishDirMode, overwrite: false + publishDir "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked", mode: params.publishDirMode, overwrite: false - input: + input: set idPatient, status, idSample, file(recalTable) from recalIntervals - output: + output: set idPatient, status, idSample, file("${idSample}.recal.table") into recalibrationTable set idPatient, status, idSample, val("${idSample}_${status}.md.bam"), val("${idSample}_${status}.md.bai"), val("${idSample}.recal.table") into (recalibrationTableTSV, recalibrationTableSampleTSV) - when: step == 'mapping' + when: step == 'mapping' - script: - recal = recalTable.collect{ "-I ${it}" }.join(' ') - """ - gatk --java-options -Xmx${task.memory.toGiga()}g \ - GatherBQSRReports \ - ${recal} \ - -O ${idSample}.recal.table \ - """ + script: + recal = recalTable.collect{ "-I ${it}" }.join(' ') + """ + gatk --java-options -Xmx${task.memory.toGiga()}g \ + GatherBQSRReports \ + ${recal} \ + -O ${idSample}.recal.table \ + """ } // Create TSV files to restart from this step recalibrationTableTSV.map { idPatient, status, idSample, bam, bai, recalTable -> - gender = patientGenders[idPatient] - "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bam}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bai}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${recalTable}\n" + gender = patientGenders[idPatient] + "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bam}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bai}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${recalTable}\n" }.collectFile( - name: 'duplicateMarked.tsv', sort: true, storeDir: "${params.outdir}/Preprocessing/TSV" + name: 'duplicateMarked.tsv', sort: true, storeDir: "${params.outdir}/Preprocessing/TSV" ) recalibrationTableSampleTSV - .collectFile(storeDir: "${params.outdir}/Preprocessing/TSV") { - idPatient, status, idSample, bam, bai, recalTable -> - gender = patientGenders[idPatient] - ["duplicateMarked_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bam}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bai}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${recalTable}\n"] + .collectFile(storeDir: "${params.outdir}/Preprocessing/TSV") { + idPatient, status, idSample, bam, bai, recalTable -> + gender = patientGenders[idPatient] + ["duplicateMarked_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bam}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bai}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${recalTable}\n"] } recalibrationTable = mdBamToJoin.join(recalibrationTable, by:[0,1,2]) @@ -611,49 +620,49 @@ if (step == 'recalibrate') recalibrationTable = bamFiles recalibrationTable = recalibrationTable.dump(tag:'recal.table') process RecalibrateBam { - tag {idPatient + "-" + idSample} + tag {idPatient + "-" + idSample} - publishDir "${params.outdir}/Preprocessing/${idSample}/Recalibrated", mode: params.publishDirMode + publishDir "${params.outdir}/Preprocessing/${idSample}/Recalibrated", mode: params.publishDirMode - input: - set idPatient, status, idSample, file(bam), file(bai), file(recalibrationReport) from recalibrationTable - set file(genomeFile), file(genomeIndex), file(genomeDict), file(intervals) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex, - referenceMap.genomeDict, - referenceMap.intervals, - ]) + input: + set idPatient, status, idSample, file(bam), file(bai), file(recalibrationReport) from recalibrationTable + set file(genomeFile), file(genomeIndex), file(genomeDict), file(intervals) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.genomeDict, + referenceMap.intervals, + ]) - output: - set idPatient, status, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bai") into recalibratedBam, recalibratedBamForStats - set idPatient, status, idSample, val("${idSample}.recal.bam"), val("${idSample}.recal.bai") into (recalibratedBamTSV, recalibratedBamSampleTSV) + output: + set idPatient, status, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bai") into recalibratedBam, recalibratedBamForStats + set idPatient, status, idSample, val("${idSample}.recal.bam"), val("${idSample}.recal.bai") into (recalibratedBamTSV, recalibratedBamSampleTSV) - script: - """ - gatk --java-options -Xmx${task.memory.toGiga()}g \ - ApplyBQSR \ - -R ${genomeFile} \ - --input ${bam} \ - --output ${idSample}.recal.bam \ - -L ${intervals} \ - --create-output-bam-index true \ - --bqsr-recal-file ${recalibrationReport} - """ + script: + """ + gatk --java-options -Xmx${task.memory.toGiga()}g \ + ApplyBQSR \ + -R ${genomeFile} \ + --input ${bam} \ + --output ${idSample}.recal.bam \ + -L ${intervals} \ + --create-output-bam-index true \ + --bqsr-recal-file ${recalibrationReport} + """ } // Creating a TSV file to restart from this step recalibratedBamTSV.map { idPatient, status, idSample, bam, bai -> - gender = patientGenders[idPatient] - "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bam}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bai}\n" + gender = patientGenders[idPatient] + "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bam}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bai}\n" }.collectFile( - name: 'recalibrated.tsv', sort: true, storeDir: "${params.outdir}/Preprocessing/TSV" + name: 'recalibrated.tsv', sort: true, storeDir: "${params.outdir}/Preprocessing/TSV" ) recalibratedBamSampleTSV - .collectFile(storeDir: "${params.outdir}/Preprocessing/TSV") { - idPatient, status, idSample, bam, bai -> - gender = patientGenders[idPatient] - ["recalibrated_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bam}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bai}\n"] + .collectFile(storeDir: "${params.outdir}/Preprocessing/TSV") { + idPatient, status, idSample, bam, bai -> + gender = patientGenders[idPatient] + ["recalibrated_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bam}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bai}\n"] } recalibratedBam = recalibratedBam.dump(tag:'recal.bam') @@ -663,60 +672,60 @@ recalibratedBam = recalibratedBam.dump(tag:'recal.bam') (bamForBamQC, bamForSamToolsStats) = recalibratedBamForStats.map{ it[0..4] }.into(2) process RunSamtoolsStats { - tag {idPatient + "-" + idSample} + tag {idPatient + "-" + idSample} - publishDir "${params.outdir}/Reports/${idSample}/SamToolsStats", mode: params.publishDirMode + publishDir "${params.outdir}/Reports/${idSample}/SamToolsStats", mode: params.publishDirMode - input: + input: set idPatient, status, idSample, file(bam), file(bai) from bamForSamToolsStats - output: + output: file ("${bam}.samtools.stats.out") into samtoolsStatsReport - when: !params.noReports + when: !params.noReports - script: - """ - samtools stats ${bam} > ${bam}.samtools.stats.out - """ + script: + """ + samtools stats ${bam} > ${bam}.samtools.stats.out + """ } -samtoolsStatsReport.dump(tag:'SAMTools') +samtoolsStatsReport = samtoolsStatsReport.dump(tag:'SAMTools') process RunBamQCrecalibrated { - tag {idPatient + "-" + idSample} + tag {idPatient + "-" + idSample} - publishDir "${params.outdir}/Reports/${idSample}/bamQC", mode: params.publishDirMode + publishDir "${params.outdir}/Reports/${idSample}/bamQC", mode: params.publishDirMode - input: + input: set idPatient, status, idSample, file(bam), file(bai) from bamForBamQC - output: + output: file("${bam.baseName}") into bamQCrecalibratedReport - when: !params.noReports + when: !params.noReports - script: - """ - qualimap --java-mem-size=${task.memory.toGiga()}G \ - bamqc \ - -bam ${bam} \ - --paint-chromosome-limits \ - --genome-gc-distr HUMAN \ - -nt ${task.cpus} \ - -skip-duplicated \ - --skip-dup-mode 0 \ - -outdir ${bam.baseName} \ - -outformat HTML - """ + script: + """ + qualimap --java-mem-size=${task.memory.toGiga()}G \ + bamqc \ + -bam ${bam} \ + --paint-chromosome-limits \ + --genome-gc-distr HUMAN \ + -nt ${task.cpus} \ + -skip-duplicated \ + --skip-dup-mode 0 \ + -outdir ${bam.baseName} \ + -outformat HTML + """ } -bamQCrecalibratedReport.dump(tag:'BamQC') +bamQCrecalibratedReport = bamQCrecalibratedReport.dump(tag:'BamQC') /* -======================================================================================== - GERMLINE VARIANT CALLING -======================================================================================== +================================================================================ + GERMLINE VARIANT CALLING +================================================================================ */ if (step == 'variantcalling') recalibratedBam = bamFiles @@ -736,35 +745,35 @@ recalibratedBam = recalibratedBam.dump(tag:'BAM') bamsForHC = recalibratedBamTemp.combine(bedIntervalsHC) process RunHaplotypecaller { - tag {idSample + "-" + intervalBed.baseName} - - input: - set idPatient, status, idSample, file(bam), file(bai), file(intervalBed) from bamsForHC - set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex, - referenceMap.genomeDict, - referenceMap.dbsnp, - referenceMap.dbsnpIndex - ]) + tag {idSample + "-" + intervalBed.baseName} + + input: + set idPatient, status, idSample, file(bam), file(bai), file(intervalBed) from bamsForHC + set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.genomeDict, + referenceMap.dbsnp, + referenceMap.dbsnpIndex + ]) - output: - set val("HaplotypeCallerGVCF"), idPatient, idSample, file("${intervalBed.baseName}_${idSample}.g.vcf") into hcGenomicVCF - set idPatient, idSample, file(intervalBed), file("${intervalBed.baseName}_${idSample}.g.vcf") into vcfsToGenotype + output: + set val("HaplotypeCallerGVCF"), idPatient, idSample, file("${intervalBed.baseName}_${idSample}.g.vcf") into hcGenomicVCF + set idPatient, idSample, file(intervalBed), file("${intervalBed.baseName}_${idSample}.g.vcf") into vcfsToGenotype - when: 'haplotypecaller' in tools + when: 'haplotypecaller' in tools - script: - """ - gatk --java-options "-Xmx${task.memory.toGiga()}g -Xms6000m -XX:GCTimeLimit=50 -XX:GCHeapFreeLimit=10" \ - HaplotypeCaller \ - -R ${genomeFile} \ - -I ${bam} \ - -L ${intervalBed} \ - -D ${dbsnp} \ - -O ${intervalBed.baseName}_${idSample}.g.vcf \ - -ERC GVCF - """ + script: + """ + gatk --java-options "-Xmx${task.memory.toGiga()}g -Xms6000m -XX:GCTimeLimit=50 -XX:GCHeapFreeLimit=10" \ + HaplotypeCaller \ + -R ${genomeFile} \ + -I ${bam} \ + -L ${intervalBed} \ + -D ${dbsnp} \ + -O ${intervalBed.baseName}_${idSample}.g.vcf \ + -ERC GVCF + """ } hcGenomicVCF = hcGenomicVCF.groupTuple(by:[0,1,2]) @@ -772,37 +781,37 @@ hcGenomicVCF = hcGenomicVCF.groupTuple(by:[0,1,2]) if (params.noGVCF) hcGenomicVCF.close() process RunGenotypeGVCFs { - tag {idSample + "-" + intervalBed.baseName} - - input: - set idPatient, idSample, file(intervalBed), file(gvcf) from vcfsToGenotype - set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex, - referenceMap.genomeDict, - referenceMap.dbsnp, - referenceMap.dbsnpIndex - ]) + tag {idSample + "-" + intervalBed.baseName} + + input: + set idPatient, idSample, file(intervalBed), file(gvcf) from vcfsToGenotype + set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.genomeDict, + referenceMap.dbsnp, + referenceMap.dbsnpIndex + ]) - output: + output: set val("HaplotypeCaller"), idPatient, idSample, file("${intervalBed.baseName}_${idSample}.vcf") into hcGenotypedVCF - when: 'haplotypecaller' in tools + when: 'haplotypecaller' in tools - script: - // Using -L is important for speed and we have to index the interval files also - """ - gatk --java-options -Xmx${task.memory.toGiga()}g \ - IndexFeatureFile -F ${gvcf} - - gatk --java-options -Xmx${task.memory.toGiga()}g \ - GenotypeGVCFs \ - -R ${genomeFile} \ - -L ${intervalBed} \ - -D ${dbsnp} \ - -V ${gvcf} \ - -O ${intervalBed.baseName}_${idSample}.vcf - """ + script: + // Using -L is important for speed and we have to index the interval files also + """ + gatk --java-options -Xmx${task.memory.toGiga()}g \ + IndexFeatureFile -F ${gvcf} + + gatk --java-options -Xmx${task.memory.toGiga()}g \ + GenotypeGVCFs \ + -R ${genomeFile} \ + -L ${intervalBed} \ + -D ${dbsnp} \ + -V ${gvcf} \ + -O ${intervalBed.baseName}_${idSample}.vcf + """ } hcGenotypedVCF = hcGenotypedVCF.groupTuple(by:[0,1,2]) @@ -811,98 +820,103 @@ hcGenotypedVCF = hcGenotypedVCF.groupTuple(by:[0,1,2]) // so we can have a single sorted VCF containing all the calls for a given caller process RunSingleStrelka { - tag {idSample} + tag {idSample} - publishDir "${params.outdir}/VariantCalling/${idSample}/Strelka", mode: params.publishDirMode + publishDir "${params.outdir}/VariantCalling/${idSample}/Strelka", mode: params.publishDirMode - input: - set idPatient, status, idSample, file(bam), file(bai) from bamsForSingleStrelka - file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") - set file(genomeFile), file(genomeIndex) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex - ]) + input: + set idPatient, status, idSample, file(bam), file(bai) from bamsForSingleStrelka + file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") + set file(genomeFile), file(genomeIndex) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex + ]) - output: - set val("Strelka"), idPatient, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into singleStrelkaOutput + output: + set val("Strelka"), idPatient, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into singleStrelkaOutput - when: 'strelka' in tools + when: 'strelka' in tools - script: - beforeScript = params.targetBED ? "bgzip --threads ${task.cpus} -c ${targetBED} > call_targets.bed.gz ; tabix call_targets.bed.gz" : "" - options = params.targetBED ? "--exome --callRegions call_targets.bed.gz" : "" - """ - ${beforeScript} - configureStrelkaGermlineWorkflow.py \ - --bam ${bam} \ - --referenceFasta ${genomeFile} \ - ${options} \ - --runDir Strelka - - python Strelka/runWorkflow.py -m local -j ${task.cpus} - mv Strelka/results/variants/genome.*.vcf.gz Strelka_${idSample}_genome.vcf.gz - mv Strelka/results/variants/genome.*.vcf.gz.tbi Strelka_${idSample}_genome.vcf.gz.tbi - mv Strelka/results/variants/variants.vcf.gz Strelka_${idSample}_variants.vcf.gz - mv Strelka/results/variants/variants.vcf.gz.tbi Strelka_${idSample}_variants.vcf.gz.tbi + script: + beforeScript = params.targetBED ? "bgzip --threads ${task.cpus} -c ${targetBED} > call_targets.bed.gz ; tabix call_targets.bed.gz" : "" + options = params.targetBED ? "--exome --callRegions call_targets.bed.gz" : "" + """ + ${beforeScript} + configureStrelkaGermlineWorkflow.py \ + --bam ${bam} \ + --referenceFasta ${genomeFile} \ + ${options} \ + --runDir Strelka + + python Strelka/runWorkflow.py -m local -j ${task.cpus} + + mv Strelka/results/variants/genome.*.vcf.gz \ + Strelka_${idSample}_genome.vcf.gz + mv Strelka/results/variants/genome.*.vcf.gz.tbi \ + Strelka_${idSample}_genome.vcf.gz.tbi + mv Strelka/results/variants/variants.vcf.gz \ + Strelka_${idSample}_variants.vcf.gz + mv Strelka/results/variants/variants.vcf.gz.tbi \ + Strelka_${idSample}_variants.vcf.gz.tbi """ } singleStrelkaOutput = singleStrelkaOutput.dump(tag:'Single Strelka') process RunSingleManta { - tag {idSample} + tag {idSample} - publishDir "${params.outdir}/VariantCalling/${idSample}/Manta", mode: params.publishDirMode + publishDir "${params.outdir}/VariantCalling/${idSample}/Manta", mode: params.publishDirMode - input: - set idPatient, status, idSample, file(bam), file(bai) from bamsForSingleManta - file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") - set file(genomeFile), file(genomeIndex) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex - ]) + input: + set idPatient, status, idSample, file(bam), file(bai) from bamsForSingleManta + file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") + set file(genomeFile), file(genomeIndex) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex + ]) - output: - set val("Manta"), idPatient, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into singleMantaOutput + output: + set val("Manta"), idPatient, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into singleMantaOutput - when: 'manta' in tools + when: 'manta' in tools - script: - beforeScript = params.targetBED ? "bgzip --threads ${task.cpus} -c ${targetBED} > call_targets.bed.gz ; tabix call_targets.bed.gz" : "" - options = params.targetBED ? "--exome --callRegions call_targets.bed.gz" : "" - inputbam = status == 0 ? "--bam" : "--tumorBam" - vcftype = status == 0 ? "diploid" : "tumor" - """ - ${beforeScript} - configManta.py \ - ${inputbam} ${bam} \ - --reference ${genomeFile} \ - ${options} \ - --runDir Manta - - python Manta/runWorkflow.py -m local -j ${task.cpus} - - mv Manta/results/variants/candidateSmallIndels.vcf.gz \ - Manta_${idSample}.candidateSmallIndels.vcf.gz - mv Manta/results/variants/candidateSmallIndels.vcf.gz.tbi \ - Manta_${idSample}.candidateSmallIndels.vcf.gz.tbi - mv Manta/results/variants/candidateSV.vcf.gz \ - Manta_${idSample}.candidateSV.vcf.gz - mv Manta/results/variants/candidateSV.vcf.gz.tbi \ - Manta_${idSample}.candidateSV.vcf.gz.tbi - mv Manta/results/variants/${vcftype}SV.vcf.gz \ - Manta_${idSample}.${vcftype}SV.vcf.gz - mv Manta/results/variants/${vcftype}SV.vcf.gz.tbi \ - Manta_${idSample}.${vcftype}SV.vcf.gz.tbi - """ + script: + beforeScript = params.targetBED ? "bgzip --threads ${task.cpus} -c ${targetBED} > call_targets.bed.gz ; tabix call_targets.bed.gz" : "" + options = params.targetBED ? "--exome --callRegions call_targets.bed.gz" : "" + inputbam = status == 0 ? "--bam" : "--tumorBam" + vcftype = status == 0 ? "diploid" : "tumor" + """ + ${beforeScript} + configManta.py \ + ${inputbam} ${bam} \ + --reference ${genomeFile} \ + ${options} \ + --runDir Manta + + python Manta/runWorkflow.py -m local -j ${task.cpus} + + mv Manta/results/variants/candidateSmallIndels.vcf.gz \ + Manta_${idSample}.candidateSmallIndels.vcf.gz + mv Manta/results/variants/candidateSmallIndels.vcf.gz.tbi \ + Manta_${idSample}.candidateSmallIndels.vcf.gz.tbi + mv Manta/results/variants/candidateSV.vcf.gz \ + Manta_${idSample}.candidateSV.vcf.gz + mv Manta/results/variants/candidateSV.vcf.gz.tbi \ + Manta_${idSample}.candidateSV.vcf.gz.tbi + mv Manta/results/variants/${vcftype}SV.vcf.gz \ + Manta_${idSample}.${vcftype}SV.vcf.gz + mv Manta/results/variants/${vcftype}SV.vcf.gz.tbi \ + Manta_${idSample}.${vcftype}SV.vcf.gz.tbi + """ } singleMantaOutput = singleMantaOutput.dump(tag:'Single Manta') /* -======================================================================================== - SOMATIC VARIANT CALLING -======================================================================================== +================================================================================ + SOMATIC VARIANT CALLING +================================================================================ */ // separate recalibrateBams by status @@ -910,7 +924,7 @@ bamsNormal = Channel.create() bamsTumor = Channel.create() recalibratedBam - .choice(bamsTumor, bamsNormal) {it[1] == 0 ? 1 : 0} + .choice(bamsTumor, bamsNormal) {it[1] == 0 ? 1 : 0} // Ascat, Control-FREEC, Manta Tumor-only SV bamsForAscat = Channel.create() @@ -938,390 +952,399 @@ bamsForMpileup = bamsForMpileup.spread(bedIntervalsForMpileup) // This will give as a list of unfiltered calls for MuTect2. process RunMutect2 { - tag {idSampleTumor + "_vs_" + idSampleNormal + "-" + intervalBed.baseName} - - input: - set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from bamsFMT2 - set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex, - referenceMap.genomeDict, - referenceMap.dbsnp, - referenceMap.dbsnpIndex - ]) + tag {idSampleTumor + "_vs_" + idSampleNormal + "-" + intervalBed.baseName} + + input: + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from bamsFMT2 + set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.genomeDict, + referenceMap.dbsnp, + referenceMap.dbsnpIndex + ]) - output: - set val("MuTect2"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf") into mutect2Output + output: + set val("MuTect2"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf") into mutect2Output - when: 'mutect2' in tools + when: 'mutect2' in tools - script: - """ - gatk --java-options "-Xmx${task.memory.toGiga()}g" \ - Mutect2 \ - -R ${genomeFile}\ - -I ${bamTumor} -tumor ${idSampleTumor} \ - -I ${bamNormal} -normal ${idSampleNormal} \ - -L ${intervalBed} \ - -O ${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf - """ + script: + """ + gatk --java-options "-Xmx${task.memory.toGiga()}g" \ + Mutect2 \ + -R ${genomeFile}\ + -I ${bamTumor} -tumor ${idSampleTumor} \ + -I ${bamNormal} -normal ${idSampleNormal} \ + -L ${intervalBed} \ + -O ${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf + """ } -mutect2Output = mutect2Output.groupTuple(by:[0,1,2,3]) +mutect2Output = mutect2Output.groupTuple(by:[0,1,2]) process RunFreeBayes { - tag {idSampleTumor + "_vs_" + idSampleNormal + "-" + intervalBed.baseName} + tag {idSampleTumor + "_vs_" + idSampleNormal + "-" + intervalBed.baseName} - input: - set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from bamsFFB - file(genomeFile) from Channel.value(referenceMap.genomeFile) - file(genomeIndex) from Channel.value(referenceMap.genomeIndex) + input: + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from bamsFFB + file(genomeFile) from Channel.value(referenceMap.genomeFile) + file(genomeIndex) from Channel.value(referenceMap.genomeIndex) - output: - set val("FreeBayes"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf") into freebayesOutput + output: + set val("FreeBayes"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf") into freebayesOutput - when: 'freebayes' in tools + when: 'freebayes' in tools - script: - """ - freebayes \ - -f ${genomeFile} \ - --pooled-continuous \ - --pooled-discrete \ - --genotype-qualities \ - --report-genotype-likelihood-max \ - --allele-balance-priors-off \ - --min-alternate-fraction 0.03 \ - --min-repeat-entropy 1 \ - --min-alternate-count 2 \ - -t ${intervalBed} \ - ${bamTumor} \ - ${bamNormal} > ${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf - """ + script: + """ + freebayes \ + -f ${genomeFile} \ + --pooled-continuous \ + --pooled-discrete \ + --genotype-qualities \ + --report-genotype-likelihood-max \ + --allele-balance-priors-off \ + --min-alternate-fraction 0.03 \ + --min-repeat-entropy 1 \ + --min-alternate-count 2 \ + -t ${intervalBed} \ + ${bamTumor} \ + ${bamNormal} > ${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf + """ } -freebayesOutput = freebayesOutput.groupTuple(by:[0,1,2,3]) +freebayesOutput = freebayesOutput.groupTuple(by:[0,1,2]) vcfsToMerge = mutect2Output.mix(freebayesOutput, hcGenotypedVCF) vcfsToMerge = vcfsToMerge.dump(tag:'VCF to merge') process ConcatVCF { - tag {variantCaller + "-" + idSample} + tag {variantCaller + "-" + idSample} - publishDir "${params.outdir}/VariantCalling/${idSample}/${"$variantCaller"}", mode: params.publishDirMode + publishDir "${params.outdir}/VariantCalling/${idSample}/${"$variantCaller"}", mode: params.publishDirMode - input: - set variantCaller, idPatient, idSample, file(vcFiles) from vcfsToMerge - file(genomeIndex) from Channel.value(referenceMap.genomeIndex) - file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") + input: + set variantCaller, idPatient, idSample, file(vcFiles) from vcfsToMerge + file(genomeIndex) from Channel.value(referenceMap.genomeIndex) + file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") - output: + output: // we have this funny *_* pattern to avoid copying the raw calls to publishdir - set variantCaller, idPatient, idSample, file("*_*.vcf.gz"), file("*_*.vcf.gz.tbi") into vcfConcatenated + set variantCaller, idPatient, idSample, file("*_*.vcf.gz"), file("*_*.vcf.gz.tbi") into vcfConcatenated - when: ('haplotypecaller' in tools || 'mutect2' in tools || 'freebayes' in tools) + when: ('haplotypecaller' in tools || 'mutect2' in tools || 'freebayes' in tools) - script: - if (variantCaller == 'HaplotypeCallerGVCF') outputFile = "haplotypecaller_${idSample}.g.vcf" - else outputFile = "${variantCaller}_${idSample}.vcf" - - options = params.targetBED ? "-t ${targetBED}" : "" - """ - concatenateVCFs.sh -i ${genomeIndex} -c ${task.cpus} -o ${outputFile} ${options} - """ + script: + if (variantCaller == 'HaplotypeCallerGVCF') outputFile = "HaplotypeCaller_${idSample}.g.vcf" + else outputFile = "${variantCaller}_${idSample}.vcf" + options = params.targetBED ? "-t ${targetBED}" : "" + """ + concatenateVCFs.sh -i ${genomeIndex} -c ${task.cpus} -o ${outputFile} ${options} + """ } vcfConcatenated = vcfConcatenated.dump(tag:'VCF') process RunStrelka { - tag {idSampleTumor + "_vs_" + idSampleNormal} + tag {idSampleTumor + "_vs_" + idSampleNormal} - publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/Strelka", mode: params.publishDirMode + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/Strelka", mode: params.publishDirMode - input: - set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor) from bamsForStrelka - file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") - set file(genomeFile), file(genomeIndex), file(genomeDict) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex, - referenceMap.genomeDict - ]) + input: + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor) from bamsForStrelka + file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") + set file(genomeFile), file(genomeIndex), file(genomeDict) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.genomeDict + ]) - output: - set val("Strelka"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into strelkaOutput + output: + set val("Strelka"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into strelkaOutput - when: 'strelka' in tools + when: 'strelka' in tools - script: - beforeScript = params.targetBED ? "bgzip --threads ${task.cpus} -c ${targetBED} > call_targets.bed.gz ; tabix call_targets.bed.gz" : "" - options = params.targetBED ? "--exome --callRegions call_targets.bed.gz" : "" - """ - ${beforeScript} - configureStrelkaSomaticWorkflow.py \ - --tumor ${bamTumor} \ - --normal ${bamNormal} \ - --referenceFasta ${genomeFile} \ - ${options} \ - --runDir Strelka - - python Strelka/runWorkflow.py -m local -j ${task.cpus} - mv Strelka/results/variants/somatic.indels.vcf.gz Strelka_${idSampleTumor}_vs_${idSampleNormal}_somatic_indels.vcf.gz - mv Strelka/results/variants/somatic.indels.vcf.gz.tbi Strelka_${idSampleTumor}_vs_${idSampleNormal}_somatic_indels.vcf.gz.tbi - mv Strelka/results/variants/somatic.snvs.vcf.gz Strelka_${idSampleTumor}_vs_${idSampleNormal}_somatic_snvs.vcf.gz - mv Strelka/results/variants/somatic.snvs.vcf.gz.tbi Strelka_${idSampleTumor}_vs_${idSampleNormal}_somatic_snvs.vcf.gz.tbi + script: + beforeScript = params.targetBED ? "bgzip --threads ${task.cpus} -c ${targetBED} > call_targets.bed.gz ; tabix call_targets.bed.gz" : "" + options = params.targetBED ? "--exome --callRegions call_targets.bed.gz" : "" + """ + ${beforeScript} + configureStrelkaSomaticWorkflow.py \ + --tumor ${bamTumor} \ + --normal ${bamNormal} \ + --referenceFasta ${genomeFile} \ + ${options} \ + --runDir Strelka + + python Strelka/runWorkflow.py -m local -j ${task.cpus} + + mv Strelka/results/variants/somatic.indels.vcf.gz \ + Strelka_${idSampleTumor}_vs_${idSampleNormal}_somatic_indels.vcf.gz + mv Strelka/results/variants/somatic.indels.vcf.gz.tbi \ + Strelka_${idSampleTumor}_vs_${idSampleNormal}_somatic_indels.vcf.gz.tbi + mv Strelka/results/variants/somatic.snvs.vcf.gz \ + Strelka_${idSampleTumor}_vs_${idSampleNormal}_somatic_snvs.vcf.gz + mv Strelka/results/variants/somatic.snvs.vcf.gz.tbi \ + Strelka_${idSampleTumor}_vs_${idSampleNormal}_somatic_snvs.vcf.gz.tbi """ } strelkaOutput = strelkaOutput.dump(tag:'Strelka') +(strelkaIndels, strelkaSNVS) = strelkaOutput.into(2) process RunManta { - tag {idSampleTumor + "_vs_" + idSampleNormal} + tag {idSampleTumor + "_vs_" + idSampleNormal} - publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/Manta", mode: params.publishDirMode + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/Manta", mode: params.publishDirMode - input: - set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor) from bamsForManta - file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") - set file(genomeFile), file(genomeIndex) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex - ]) + input: + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor) from bamsForManta + file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") + set file(genomeFile), file(genomeIndex) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex + ]) - output: - set val("Manta"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into mantaOutput - set idPatient, idSampleNormal, idSampleTumor, file("*.candidateSmallIndels.vcf.gz"), file("*.candidateSmallIndels.vcf.gz.tbi") into mantaToStrelka + output: + set val("Manta"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into mantaOutput + set idPatient, idSampleNormal, idSampleTumor, file("*.candidateSmallIndels.vcf.gz"), file("*.candidateSmallIndels.vcf.gz.tbi") into mantaToStrelka - when: 'manta' in tools + when: 'manta' in tools - script: - beforeScript = params.targetBED ? "bgzip --threads ${task.cpus} -c ${targetBED} > call_targets.bed.gz ; tabix call_targets.bed.gz" : "" - options = params.targetBED ? "--exome --callRegions call_targets.bed.gz" : "" - """ - ${beforeScript} - configManta.py \ - --normalBam ${bamNormal} \ - --tumorBam ${bamTumor} \ - --reference ${genomeFile} \ - ${options} \ - --runDir Manta - - python Manta/runWorkflow.py -m local -j ${task.cpus} - - mv Manta/results/variants/candidateSmallIndels.vcf.gz \ - Manta_${idSampleTumor}_vs_${idSampleNormal}.candidateSmallIndels.vcf.gz - mv Manta/results/variants/candidateSmallIndels.vcf.gz.tbi \ - Manta_${idSampleTumor}_vs_${idSampleNormal}.candidateSmallIndels.vcf.gz.tbi - mv Manta/results/variants/candidateSV.vcf.gz \ - Manta_${idSampleTumor}_vs_${idSampleNormal}.candidateSV.vcf.gz - mv Manta/results/variants/candidateSV.vcf.gz.tbi \ - Manta_${idSampleTumor}_vs_${idSampleNormal}.candidateSV.vcf.gz.tbi - mv Manta/results/variants/diploidSV.vcf.gz \ - Manta_${idSampleTumor}_vs_${idSampleNormal}.diploidSV.vcf.gz - mv Manta/results/variants/diploidSV.vcf.gz.tbi \ - Manta_${idSampleTumor}_vs_${idSampleNormal}.diploidSV.vcf.gz.tbi - mv Manta/results/variants/somaticSV.vcf.gz \ - Manta_${idSampleTumor}_vs_${idSampleNormal}.somaticSV.vcf.gz - mv Manta/results/variants/somaticSV.vcf.gz.tbi \ - Manta_${idSampleTumor}_vs_${idSampleNormal}.somaticSV.vcf.gz.tbi - """ + script: + beforeScript = params.targetBED ? "bgzip --threads ${task.cpus} -c ${targetBED} > call_targets.bed.gz ; tabix call_targets.bed.gz" : "" + options = params.targetBED ? "--exome --callRegions call_targets.bed.gz" : "" + """ + ${beforeScript} + configManta.py \ + --normalBam ${bamNormal} \ + --tumorBam ${bamTumor} \ + --reference ${genomeFile} \ + ${options} \ + --runDir Manta + + python Manta/runWorkflow.py -m local -j ${task.cpus} + + mv Manta/results/variants/candidateSmallIndels.vcf.gz \ + Manta_${idSampleTumor}_vs_${idSampleNormal}.candidateSmallIndels.vcf.gz + mv Manta/results/variants/candidateSmallIndels.vcf.gz.tbi \ + Manta_${idSampleTumor}_vs_${idSampleNormal}.candidateSmallIndels.vcf.gz.tbi + mv Manta/results/variants/candidateSV.vcf.gz \ + Manta_${idSampleTumor}_vs_${idSampleNormal}.candidateSV.vcf.gz + mv Manta/results/variants/candidateSV.vcf.gz.tbi \ + Manta_${idSampleTumor}_vs_${idSampleNormal}.candidateSV.vcf.gz.tbi + mv Manta/results/variants/diploidSV.vcf.gz \ + Manta_${idSampleTumor}_vs_${idSampleNormal}.diploidSV.vcf.gz + mv Manta/results/variants/diploidSV.vcf.gz.tbi \ + Manta_${idSampleTumor}_vs_${idSampleNormal}.diploidSV.vcf.gz.tbi + mv Manta/results/variants/somaticSV.vcf.gz \ + Manta_${idSampleTumor}_vs_${idSampleNormal}.somaticSV.vcf.gz + mv Manta/results/variants/somaticSV.vcf.gz.tbi \ + Manta_${idSampleTumor}_vs_${idSampleNormal}.somaticSV.vcf.gz.tbi + """ } mantaOutput = mantaOutput.dump(tag:'Manta') +(mantaSomaticSV, mantaDiploidSV) = mantaOutput.into(2) bamsForStrelkaBP = bamsForStrelkaBP.map { - idPatientNormal, idSampleNormal, bamNormal, baiNormal, idSampleTumor, bamTumor, baiTumor -> - [idPatientNormal, idSampleNormal, idSampleTumor, bamNormal, baiNormal, bamTumor, baiTumor] + idPatientNormal, idSampleNormal, bamNormal, baiNormal, idSampleTumor, bamTumor, baiTumor -> + [idPatientNormal, idSampleNormal, idSampleTumor, bamNormal, baiNormal, bamTumor, baiTumor] }.join(mantaToStrelka, by:[0,1,2]).map { - idPatientNormal, idSampleNormal, idSampleTumor, bamNormal, baiNormal, bamTumor, baiTumor, mantaCSI, mantaCSIi -> - [idPatientNormal, idSampleNormal, bamNormal, baiNormal, idSampleTumor, bamTumor, baiTumor, mantaCSI, mantaCSIi] + idPatientNormal, idSampleNormal, idSampleTumor, bamNormal, baiNormal, bamTumor, baiTumor, mantaCSI, mantaCSIi -> + [idPatientNormal, idSampleNormal, bamNormal, baiNormal, idSampleTumor, bamTumor, baiTumor, mantaCSI, mantaCSIi] } process RunStrelkaBP { - tag {idSampleTumor + "_vs_" + idSampleNormal} + tag {idSampleTumor + "_vs_" + idSampleNormal} - publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/Strelka", mode: params.publishDirMode + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/Strelka", mode: params.publishDirMode - input: - set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(mantaCSI), file(mantaCSIi) from bamsForStrelkaBP - file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") - set file(genomeFile), file(genomeIndex), file(genomeDict) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex, - referenceMap.genomeDict - ]) + input: + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(mantaCSI), file(mantaCSIi) from bamsForStrelkaBP + file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") + set file(genomeFile), file(genomeIndex), file(genomeDict) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.genomeDict + ]) - output: - set val("Strelka"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into strelkaBPOutput + output: + set val("Strelka"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into strelkaBPOutput - when: 'strelka' in tools && 'manta' in tools && params.strelkaBP + when: 'strelka' in tools && 'manta' in tools && params.strelkaBP - script: - beforeScript = params.targetBED ? "bgzip --threads ${task.cpus} -c ${targetBED} > call_targets.bed.gz ; tabix call_targets.bed.gz" : "" - options = params.targetBED ? "--exome --callRegions call_targets.bed.gz" : "" - """ - ${beforeScript} - configureStrelkaSomaticWorkflow.py \ - --tumor ${bamTumor} \ - --normal ${bamNormal} \ - --referenceFasta ${genomeFile} \ - --indelCandidates ${mantaCSI} \ - ${options} \ - --runDir Strelka - - python Strelka/runWorkflow.py -m local -j ${task.cpus} - - mv Strelka/results/variants/somatic.indels.vcf.gz \ - StrelkaBP_${idSampleTumor}_vs_${idSampleNormal}_somatic_indels.vcf.gz - mv Strelka/results/variants/somatic.indels.vcf.gz.tbi \ - StrelkaBP_${idSampleTumor}_vs_${idSampleNormal}_somatic_indels.vcf.gz.tbi - mv Strelka/results/variants/somatic.snvs.vcf.gz \ - StrelkaBP_${idSampleTumor}_vs_${idSampleNormal}_somatic_snvs.vcf.gz - mv Strelka/results/variants/somatic.snvs.vcf.gz.tbi \ - StrelkaBP_${idSampleTumor}_vs_${idSampleNormal}_somatic_snvs.vcf.gz.tbi + script: + beforeScript = params.targetBED ? "bgzip --threads ${task.cpus} -c ${targetBED} > call_targets.bed.gz ; tabix call_targets.bed.gz" : "" + options = params.targetBED ? "--exome --callRegions call_targets.bed.gz" : "" + """ + ${beforeScript} + configureStrelkaSomaticWorkflow.py \ + --tumor ${bamTumor} \ + --normal ${bamNormal} \ + --referenceFasta ${genomeFile} \ + --indelCandidates ${mantaCSI} \ + ${options} \ + --runDir Strelka + + python Strelka/runWorkflow.py -m local -j ${task.cpus} + + mv Strelka/results/variants/somatic.indels.vcf.gz \ + StrelkaBP_${idSampleTumor}_vs_${idSampleNormal}_somatic_indels.vcf.gz + mv Strelka/results/variants/somatic.indels.vcf.gz.tbi \ + StrelkaBP_${idSampleTumor}_vs_${idSampleNormal}_somatic_indels.vcf.gz.tbi + mv Strelka/results/variants/somatic.snvs.vcf.gz \ + StrelkaBP_${idSampleTumor}_vs_${idSampleNormal}_somatic_snvs.vcf.gz + mv Strelka/results/variants/somatic.snvs.vcf.gz.tbi \ + StrelkaBP_${idSampleTumor}_vs_${idSampleNormal}_somatic_snvs.vcf.gz.tbi """ } strelkaBPOutput = strelkaBPOutput.dump(tag:'Strelka BP') +(strelkaBPIndels, strelkaBPSNVS) = strelkaBPOutput.into(2) // Run commands and code from Malin Larsson // Based on Jesper Eisfeldt's code process RunAlleleCount { - tag {idSample} + tag {idSample} - input: - set idPatient, status, idSample, file(bam), file(bai) from bamsForAscat - set file(acLoci), file(genomeFile), file(genomeIndex), file(genomeDict) from Channel.value([ - referenceMap.acLoci, - referenceMap.genomeFile, - referenceMap.genomeIndex, - referenceMap.genomeDict - ]) + input: + set idPatient, status, idSample, file(bam), file(bai) from bamsForAscat + set file(acLoci), file(genomeFile), file(genomeIndex), file(genomeDict) from Channel.value([ + referenceMap.acLoci, + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.genomeDict + ]) - output: - set idPatient, status, idSample, file("${idSample}.alleleCount") into alleleCountOutput + output: + set idPatient, status, idSample, file("${idSample}.alleleCount") into alleleCountOutput - when: 'ascat' in tools + when: 'ascat' in tools - script: - """ - alleleCounter \ - -l ${acLoci} \ - -r ${genomeFile} \ - -b ${bam} \ - -o ${idSample}.alleleCount; - """ + script: + """ + alleleCounter \ + -l ${acLoci} \ + -r ${genomeFile} \ + -b ${bam} \ + -o ${idSample}.alleleCount; + """ } alleleCountNormal = Channel.create() alleleCountTumor = Channel.create() alleleCountOutput - .choice(alleleCountTumor, alleleCountNormal) {it[1] == 0 ? 1 : 0} + .choice(alleleCountTumor, alleleCountNormal) {it[1] == 0 ? 1 : 0} alleleCountOutput = alleleCountNormal.combine(alleleCountTumor) alleleCountOutput = alleleCountOutput.map { - idPatientNormal, statusNormal, idSampleNormal, alleleCountNormal, - idPatientTumor, statusTumor, idSampleTumor, alleleCountTumor -> - [idPatientNormal, idSampleNormal, idSampleTumor, alleleCountNormal, alleleCountTumor] + idPatientNormal, statusNormal, idSampleNormal, alleleCountNormal, + idPatientTumor, statusTumor, idSampleTumor, alleleCountTumor -> + [idPatientNormal, idSampleNormal, idSampleTumor, alleleCountNormal, alleleCountTumor] } // R script from Malin Larssons bitbucket repo: // https://bitbucket.org/malinlarsson/somatic_wgs_pipeline process RunConvertAlleleCounts { - tag {idSampleTumor + "_vs_" + idSampleNormal} + tag {idSampleTumor + "_vs_" + idSampleNormal} - publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/ASCAT", mode: params.publishDirMode + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/ASCAT", mode: params.publishDirMode - input: - set idPatient, idSampleNormal, idSampleTumor, file(alleleCountNormal), file(alleleCountTumor) from alleleCountOutput + input: + set idPatient, idSampleNormal, idSampleTumor, file(alleleCountNormal), file(alleleCountTumor) from alleleCountOutput - output: - set idPatient, idSampleNormal, idSampleTumor, file("${idSampleNormal}.BAF"), file("${idSampleNormal}.LogR"), file("${idSampleTumor}.BAF"), file("${idSampleTumor}.LogR") into convertAlleleCountsOutput + output: + set idPatient, idSampleNormal, idSampleTumor, file("${idSampleNormal}.BAF"), file("${idSampleNormal}.LogR"), file("${idSampleTumor}.BAF"), file("${idSampleTumor}.LogR") into convertAlleleCountsOutput - when: 'ascat' in tools + when: 'ascat' in tools - script: - gender = patientGenders[idPatient] - """ - convertAlleleCounts.r ${idSampleTumor} ${alleleCountTumor} ${idSampleNormal} ${alleleCountNormal} ${gender} - """ + script: + gender = patientGenders[idPatient] + """ + convertAlleleCounts.r ${idSampleTumor} ${alleleCountTumor} ${idSampleNormal} ${alleleCountNormal} ${gender} + """ } // R scripts from Malin Larssons bitbucket repo: // https://bitbucket.org/malinlarsson/somatic_wgs_pipeline process RunAscat { - tag {idSampleTumor + "_vs_" + idSampleNormal} + tag {idSampleTumor + "_vs_" + idSampleNormal} - publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/ASCAT", mode: params.publishDirMode + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/ASCAT", mode: params.publishDirMode - input: - set idPatient, idSampleNormal, idSampleTumor, file(bafNormal), file(logrNormal), file(bafTumor), file(logrTumor) from convertAlleleCountsOutput - file(acLociGC) from Channel.value([referenceMap.acLociGC]) + input: + set idPatient, idSampleNormal, idSampleTumor, file(bafNormal), file(logrNormal), file(bafTumor), file(logrTumor) from convertAlleleCountsOutput + file(acLociGC) from Channel.value([referenceMap.acLociGC]) - output: - set val("ASCAT"), idPatient, idSampleNormal, idSampleTumor, file("${idSampleTumor}.*.{png,txt}") into ascatOutput + output: + set val("ASCAT"), idPatient, idSampleNormal, idSampleTumor, file("${idSampleTumor}.*.{png,txt}") into ascatOutput - when: 'ascat' in tools + when: 'ascat' in tools - script: - """ - # get rid of "chr" string if there is any - for f in *BAF *LogR; do sed 's/chr//g' \$f > tmpFile; mv tmpFile \$f;done - run_ascat.r ${bafTumor} ${logrTumor} ${bafNormal} ${logrNormal} ${idSampleTumor} ${baseDir} ${acLociGC} - """ + script: + """ + # get rid of "chr" string if there is any + for f in *BAF *LogR; do sed 's/chr//g' \$f > tmpFile; mv tmpFile \$f;done + run_ascat.r ${bafTumor} ${logrTumor} ${bafNormal} ${logrNormal} ${idSampleTumor} ${baseDir} ${acLociGC} + """ } ascatOutput.dump(tag:'ASCAT') process RunMpileup { - tag {idSample + "-" + intervalBed.baseName} + tag {idSample + "-" + intervalBed.baseName} - input: - set idPatient, status, idSample, file(bam), file(bai), file(intervalBed) from bamsForMpileup - set file(genomeFile), file(genomeIndex) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex - ]) + input: + set idPatient, status, idSample, file(bam), file(bai), file(intervalBed) from bamsForMpileup + set file(genomeFile), file(genomeIndex) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex + ]) - output: - set idPatient, status, idSample, file("${idSample}_${intervalBed.baseName}.pileup.gz") into mpileupToMerge + output: + set idPatient, status, idSample, file("${idSample}_${intervalBed.baseName}.pileup.gz") into mpileupToMerge - when: ('controlfreec' in tools || 'mpileup' in tools) + when: ('controlfreec' in tools || 'mpileup' in tools) - script: - """ - samtools mpileup \ - -f ${genomeFile} ${bam} \ - -l ${intervalBed} \ - | bgzip --threads ${task.cpus} -c > ${idSample}_${intervalBed.baseName}.pileup.gz - """ + script: + """ + samtools mpileup \ + -f ${genomeFile} ${bam} \ + -l ${intervalBed} \ + | bgzip --threads ${task.cpus} -c > ${idSample}_${intervalBed.baseName}.pileup.gz + """ } mpileupToMerge = mpileupToMerge.groupTuple(by:[0,1,2]) process MergeMpileup { - tag {idSample} + tag {idSample} - publishDir params.outdir, mode: params.publishDirMode, saveAs: { it == "${idSample}.pileup.gz" ? "VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/mpileup/${it}" : '' } + publishDir params.outdir, mode: params.publishDirMode, saveAs: { it == "${idSample}.pileup.gz" ? "VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/mpileup/${it}" : '' } - input: - set idPatient, status, idSample, file(mpileup) from mpileupToMerge + input: + set idPatient, status, idSample, file(mpileup) from mpileupToMerge - output: - set idPatient, status, idSample, file("${idSample}.pileup.gz") into mpileupOutput + output: + set idPatient, status, idSample, file("${idSample}.pileup.gz") into mpileupOutput when: ('controlfreec' in tools || 'mpileup' in tools) - script: - """ - for i in `ls -1v *.pileup.gz`; - do zcat \$i >> ${idSample}.pileup - done - bgzip --threads ${task.cpus} -c ${idSample}.pileup > ${idSample}.pileup.gz - rm ${idSample}.pileup - """ + script: + """ + for i in `ls -1v *.pileup.gz`; + do zcat \$i >> ${idSample}.pileup + done + + bgzip --threads ${task.cpus} -c ${idSample}.pileup > ${idSample}.pileup.gz + + rm ${idSample}.pileup + """ } mpileupOutput = mpileupOutput.dump(tag:'mpileup') @@ -1330,197 +1353,425 @@ mpileupNormal = Channel.create() mpileupTumor = Channel.create() mpileupOutput - .choice(mpileupTumor, mpileupNormal) {it[1] == 0 ? 1 : 0} + .choice(mpileupTumor, mpileupNormal) {it[1] == 0 ? 1 : 0} mpileupOutput = mpileupNormal.combine(mpileupTumor) mpileupOutput = mpileupOutput.map { - idPatientNormal, statusNormal, idSampleNormal, mpileupNormal, - idPatientTumor, statusTumor, idSampleTumor, mpileupTumor -> - [idPatientNormal, idSampleNormal, idSampleTumor, mpileupNormal, mpileupTumor] + idPatientNormal, statusNormal, idSampleNormal, mpileupNormal, + idPatientTumor, statusTumor, idSampleTumor, mpileupTumor -> + [idPatientNormal, idSampleNormal, idSampleTumor, mpileupNormal, mpileupTumor] } process RunControlFreec { - tag {idSampleTumor + "_vs_" + idSampleNormal} + tag {idSampleTumor + "_vs_" + idSampleNormal} - publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/controlFREEC", mode: params.publishDirMode + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/controlFREEC", mode: params.publishDirMode - input: - set idPatient, idSampleNormal, idSampleTumor, file(mpileupNormal), file(mpileupTumor) from mpileupOutput - set file(genomeFile), file(genomeIndex), file(dbsnp), file(dbsnpIndex), file(chrDir), file(chrLength) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex, - referenceMap.dbsnp, - referenceMap.dbsnpIndex, - referenceMap.chrDir, - referenceMap.chrLength - ]) + input: + set idPatient, idSampleNormal, idSampleTumor, file(mpileupNormal), file(mpileupTumor) from mpileupOutput + set file(genomeFile), file(genomeIndex), file(dbsnp), file(dbsnpIndex), file(chrDir), file(chrLength) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.dbsnp, + referenceMap.dbsnpIndex, + referenceMap.chrDir, + referenceMap.chrLength + ]) - output: - set idPatient, idSampleNormal, idSampleTumor, file("${idSampleTumor}.pileup.gz_CNVs"), file("${idSampleTumor}.pileup.gz_ratio.txt"), file("${idSampleTumor}.pileup.gz_normal_CNVs"), file("${idSampleTumor}.pileup.gz_normal_ratio.txt"), file("${idSampleTumor}.pileup.gz_BAF.txt"), file("${idSampleNormal}.pileup.gz_BAF.txt") into controlFreecOutputVisualization - set file("*.pileup.gz*"), file("${idSampleTumor}_vs_${idSampleNormal}.config.txt") into controlFreecOutput + output: + set idPatient, idSampleNormal, idSampleTumor, file("${idSampleTumor}.pileup.gz_CNVs"), file("${idSampleTumor}.pileup.gz_ratio.txt"), file("${idSampleTumor}.pileup.gz_normal_CNVs"), file("${idSampleTumor}.pileup.gz_normal_ratio.txt"), file("${idSampleTumor}.pileup.gz_BAF.txt"), file("${idSampleNormal}.pileup.gz_BAF.txt") into controlFreecOutputVisualization + set file("*.pileup.gz*"), file("${idSampleTumor}_vs_${idSampleNormal}.config.txt") into controlFreecOutput - when: 'controlfreec' in tools + when: 'controlfreec' in tools - script: - config = "${idSampleTumor}_vs_${idSampleNormal}.config.txt" - gender = patientGenders[idPatient] - """ - touch ${config} - echo "[general]" >> ${config} - echo "BedGraphOutput = TRUE" >> ${config} - echo "chrFiles = \${PWD}/${referenceMap.chrDir.fileName}" >> ${config} - echo "chrLenFile = \${PWD}/${referenceMap.chrLength.fileName}" >> ${config} - echo "coefficientOfVariation = 0.05" >> ${config} - echo "contaminationAdjustment = TRUE" >> ${config} - echo "forceGCcontentNormalization = 0" >> ${config} - echo "maxThreads = ${task.cpus}" >> ${config} - echo "minimalSubclonePresence = 20" >> ${config} - echo "ploidy = 2,3,4" >> ${config} - echo "sex = ${gender}" >> ${config} - echo "window = 50000" >> ${config} - echo "" >> ${config} - - echo "[control]" >> ${config} - echo "inputFormat = pileup" >> ${config} - echo "mateFile = \${PWD}/${mpileupNormal}" >> ${config} - echo "mateOrientation = FR" >> ${config} - echo "" >> ${config} - - echo "[sample]" >> ${config} - echo "inputFormat = pileup" >> ${config} - echo "mateFile = \${PWD}/${mpileupTumor}" >> ${config} - echo "mateOrientation = FR" >> ${config} - echo "" >> ${config} - - echo "[BAF]" >> ${config} - echo "SNPfile = ${referenceMap.dbsnp.fileName}" >> ${config} - - freec -conf ${config} - """ + script: + config = "${idSampleTumor}_vs_${idSampleNormal}.config.txt" + gender = patientGenders[idPatient] + """ + touch ${config} + echo "[general]" >> ${config} + echo "BedGraphOutput = TRUE" >> ${config} + echo "chrFiles = \${PWD}/${referenceMap.chrDir.fileName}" >> ${config} + echo "chrLenFile = \${PWD}/${referenceMap.chrLength.fileName}" >> ${config} + echo "coefficientOfVariation = 0.05" >> ${config} + echo "contaminationAdjustment = TRUE" >> ${config} + echo "forceGCcontentNormalization = 0" >> ${config} + echo "maxThreads = ${task.cpus}" >> ${config} + echo "minimalSubclonePresence = 20" >> ${config} + echo "ploidy = 2,3,4" >> ${config} + echo "sex = ${gender}" >> ${config} + echo "window = 50000" >> ${config} + echo "" >> ${config} + + echo "[control]" >> ${config} + echo "inputFormat = pileup" >> ${config} + echo "mateFile = \${PWD}/${mpileupNormal}" >> ${config} + echo "mateOrientation = FR" >> ${config} + echo "" >> ${config} + + echo "[sample]" >> ${config} + echo "inputFormat = pileup" >> ${config} + echo "mateFile = \${PWD}/${mpileupTumor}" >> ${config} + echo "mateOrientation = FR" >> ${config} + echo "" >> ${config} + + echo "[BAF]" >> ${config} + echo "SNPfile = ${referenceMap.dbsnp.fileName}" >> ${config} + + freec -conf ${config} + """ } process RunControlFreecVisualization { - tag {idSampleTumor + "_vs_" + idSampleNormal} + tag {idSampleTumor + "_vs_" + idSampleNormal} - publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/controlFREEC", mode: params.publishDirMode + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/controlFREEC", mode: params.publishDirMode - input: + input: set idPatient, idSampleNormal, idSampleTumor, file(cnvTumor), file(ratioTumor), file(cnvNormal), file(ratioNormal), file(bafTumor), file(bafNormal) from controlFreecOutputVisualization - output: + output: set file("*.txt"), file("*.png"), file("*.bed") into controlFreecOutputFinal - when: 'controlfreec' in tools + when: 'controlfreec' in tools - """ - cat /opt/conda/envs/sarek-2.3/bin/assess_significance.R | R --slave --args ${cnvTumor} ${ratioTumor} - cat /opt/conda/envs/sarek-2.3/bin/assess_significance.R | R --slave --args ${cnvNormal} ${ratioNormal} - cat /opt/conda/envs/sarek-2.3/bin/makeGraph.R | R --slave --args 2 ${ratioTumor} ${bafTumor} - cat /opt/conda/envs/sarek-2.3/bin/makeGraph.R | R --slave --args 2 ${ratioNormal} ${bafNormal} - perl /opt/conda/envs/sarek-2.3/bin/freec2bed.pl -f ${ratioTumor} > ${idSampleTumor}.bed - perl /opt/conda/envs/sarek-2.3/bin/freec2bed.pl -f ${ratioNormal} > ${idSampleNormal}.bed - """ + """ + cat /opt/conda/envs/sarek-2.5dev/bin/assess_significance.R | R --slave --args ${cnvTumor} ${ratioTumor} + cat /opt/conda/envs/sarek-2.5dev/bin/assess_significance.R | R --slave --args ${cnvNormal} ${ratioNormal} + cat /opt/conda/envs/sarek-2.5dev/bin/makeGraph.R | R --slave --args 2 ${ratioTumor} ${bafTumor} + cat /opt/conda/envs/sarek-2.5dev/bin/makeGraph.R | R --slave --args 2 ${ratioNormal} ${bafNormal} + perl /opt/conda/envs/sarek-2.5dev/bin/freec2bed.pl -f ${ratioTumor} > ${idSampleTumor}.bed + perl /opt/conda/envs/sarek-2.5dev/bin/freec2bed.pl -f ${ratioNormal} > ${idSampleNormal}.bed + """ } -(strelkaIndels, strelkaSNVS) = strelkaOutput.into(2) -(mantaSomaticSV, mantaDiploidSV) = mantaOutput.into(2) - -vcfForQC = Channel.empty().mix( - vcfConcatenated.map { - variantcaller, idPatient, idSample, vcf, tbi -> - [variantcaller, idPatient, idSample, vcf] - }, - singleStrelkaOutput.map { - variantcaller, idPatient, idSample, vcf, tbi -> - [variantcaller, idPatient, idSample, vcf[1]] - }, - singleMantaOutput.map { - variantcaller, idPatient, idSample, vcf, tbi -> - [variantcaller, idPatient, idSample, vcf[2]] - }, - mantaDiploidSV.map { - variantcaller, idPatient, idSample, vcf, tbi -> - [variantcaller, idPatient, idSample, vcf[2]] - }, - mantaSomaticSV.map { - variantcaller, idPatient, idSample, vcf, tbi -> - [variantcaller, idPatient, idSample, vcf[3]] - }, - strelkaIndels.map { - variantcaller, idPatient, idSample, vcf, tbi -> - [variantcaller, idPatient, idSample, vcf[0]] - }, - strelkaSNVS.map { - variantcaller, idPatient, idSample, vcf, tbi -> - [variantcaller, idPatient, idSample, vcf[1]] - }) - -(vcfForBCFtools, vcfForVCFtools) = vcfForQC.into(2) +vcfToKeep = Channel.empty().mix( + vcfConcatenated.map { + variantcaller, idPatient, idSample, vcf, tbi -> + [variantcaller, idSample, vcf] + }, + singleStrelkaOutput.map { + variantcaller, idPatient, idSample, vcf, tbi -> + [variantcaller, idSample, vcf[1]] + }, + singleMantaOutput.map { + variantcaller, idPatient, idSample, vcf, tbi -> + [variantcaller, idSample, vcf[2]] + }, + mantaDiploidSV.map { + variantcaller, idPatient, idSample, vcf, tbi -> + [variantcaller, idSample, vcf[2]] + }, + mantaSomaticSV.map { + variantcaller, idPatient, idSample, vcf, tbi -> + [variantcaller, idSample, vcf[3]] + }, + strelkaIndels.map { + variantcaller, idPatient, idSample, vcf, tbi -> + [variantcaller, idSample, vcf[0]] + }, + strelkaSNVS.map { + variantcaller, idPatient, idSample, vcf, tbi -> + [variantcaller, idSample, vcf[1]] + }, + strelkaBPIndels.map { + variantcaller, idPatient, idSample, vcf, tbi -> + [variantcaller, idSample, vcf[0]] + }, + strelkaBPSNVS.map { + variantcaller, idPatient, idSample, vcf, tbi -> + [variantcaller, idSample, vcf[1]] + }) + +(vcfForBCFtools, vcfForVCFtools, vcfForAnnotation) = vcfToKeep.into(3) process RunBcftoolsStats { - tag {"${variantCaller} - ${vcf}"} + tag {"${variantCaller} - ${vcf}"} + + publishDir "${params.outdir}/Reports/${idSample}/BCFToolsStats", mode: params.publishDirMode + + input: + set variantCaller, idSample, file(vcf) from vcfForBCFtools - publishDir "${params.outdir}/Reports/${idSample}/BCFToolsStats", mode: params.publishDirMode + output: + file ("*.bcf.tools.stats.out") into bcfReport + + when: !params.noReports + + script: + """ + bcftools stats ${vcf} > ${reduceVCF(vcf)}.bcf.tools.stats.out + """ +} + +bcfReport = bcfReport.dump(tag:'BCFTools') + +process RunVcftools { + tag {"${variantCaller} - ${vcf}"} + + publishDir "${params.outdir}/Reports/${idSample}/VCFTools", mode: params.publishDirMode + + input: + set variantCaller, idSample, file(vcf) from vcfForVCFtools + + output: + file ("${reduceVCF(vcf)}.*") into vcfReport + + when: !params.noReports + + script: + """ + vcftools \ + --gzvcf ${vcf} \ + --relatedness2 \ + --out ${reduceVCF(vcf)} + + vcftools \ + --gzvcf ${vcf} \ + --TsTv-by-count \ + --out ${reduceVCF(vcf)} + + vcftools \ + --gzvcf ${vcf} \ + --TsTv-by-qual \ + --out ${reduceVCF(vcf)} + + vcftools \ + --gzvcf ${vcf} \ + --FILTER-summary \ + --out ${reduceVCF(vcf)} + """ +} + +vcfReport = vcfReport.dump(tag:'VCFTools') + +/* +================================================================================ + ANNOTATION +================================================================================ +*/ + +vcfToAnnotate = Channel.create() + +if (step == 'annotate') { + vcfNotToAnnotate = Channel.create() + + if (annotateVCF == []) { + // Sarek, by default, annotates all available vcfs that it can find in the VariantCalling directory + // Excluding vcfs from FreeBayes, and g.vcf from HaplotypeCaller + // Basically it's: VariantCalling/*/{HaplotypeCaller,Manta,MuTect2,Strelka}/*.vcf.gz + // Without *SmallIndels.vcf.gz from Manta, and *.genome.vcf.gz from Strelka + // The small snippet `vcf.minus(vcf.fileName)[-2]` catches idSample + // This field is used to output final annotated VCFs in the correct directory + Channel.empty().mix( + Channel.fromPath("${params.outdir}/VariantCalling/*/HaplotypeCaller/*.vcf.gz") + .flatten().map{vcf -> ['haplotypecaller', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, + Channel.fromPath("${params.outdir}/VariantCalling/*/Manta/*[!candidate]SV.vcf.gz") + .flatten().map{vcf -> ['manta', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, + Channel.fromPath("${params.outdir}/VariantCalling/*/MuTect2/*.vcf.gz") + .flatten().map{vcf -> ['mutect2', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, + Channel.fromPath("${params.outdir}/VariantCalling/*/Strelka/*{somatic,variant}*.vcf.gz") + .flatten().map{vcf -> ['strelka', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, + ).choice(vcfToAnnotate, vcfNotToAnnotate) { + annotateTools == [] || (annotateTools != [] && it[0] in annotateTools) ? 0 : 1 + } + } else if (annotateTools == []) { + // Annotate user-submitted VCFs + // If user-submitted, Sarek assume that the idSample should be assumed automatically + vcfToAnnotate = Channel.fromPath(annotateVCF) + .map{vcf -> ['userspecified', vcf.minus(vcf.fileName)[-2].toString(), vcf]} + } else exit 1, "specify only tools or files to annotate, not both" + + vcfNotToAnnotate.close() + vcfForAnnotation = vcfForAnnotation.mix(vcfToAnnotate) +} + +// as now have the list of VCFs to annotate, the first step is to annotate with allele frequencies, if there are any + +(vcfForSnpeff, vcfForVep) = vcfForAnnotation.into(2) + +vcfForVep = vcfForVep.map { + variantCaller, idSample, vcf -> + ["VEP", variantCaller, idSample, vcf, null] +} + +process RunSnpeff { + tag {"${idSample} - ${variantCaller} - ${vcf}"} + + publishDir params.outdir, mode: params.publishDirMode, saveAs: { + if (it == "${reducedVCF}_snpEff.ann.vcf") null + else "Annotation/${idSample}/snpEff/${it}" + } input: - set variantCaller, idPatient, idSample, file(vcf) from vcfForBCFtools + set variantCaller, idSample, file(vcf) from vcfForSnpeff + file dataDir from Channel.value(params.snpEff_cache ? file(params.snpEff_cache) : "null") + val snpeffDb from Channel.value(params.genomes[params.genome].snpeffDb) output: - file ("*.bcf.tools.stats.out") into bcfReport + set file("${reducedVCF}_snpEff.genes.txt"), file("${reducedVCF}_snpEff.csv"), file("${reducedVCF}_snpEff.summary.html") into snpeffOutput + set val("snpEff"), variantCaller, idSample, file("${reducedVCF}_snpEff.ann.vcf") into snpeffVCF - when: !params.noReports + when: 'snpeff' in tools || 'merge' in tools script: + reducedVCF = reduceVCF(vcf) + cache = (params.snpEff_cache && params.annotation_cache) ? "-dataDir \${PWD}/${dataDir}" : "" """ - bcftools stats ${vcf} > ${reduceVCF(vcf)}.bcf.tools.stats.out + echo ${task.container} + + snpEff -Xmx${task.memory.toGiga()}g \ + ${snpeffDb} \ + -csvStats ${reducedVCF}_snpEff.csv \ + -nodownload \ + ${cache} \ + -canon \ + -v \ + ${vcf} \ + > ${reducedVCF}_snpEff.ann.vcf + + mv snpEff_summary.html ${reducedVCF}_snpEff.summary.html """ - } -bcfReport.dump(tag:'BCFTools') +snpeffOutput = snpeffOutput.dump(tag:'snpEff') -process RunVcftools { - tag {"${variantCaller} - ${vcf}"} +if ('merge' in tools) { + // When running in the 'merge' mode + // snpEff output is used as VEP input + // Used a feedback loop from vcfCompressed + // https://github.com/nextflow-io/patterns/tree/master/feedback-loop + + vcfCompressed = Channel.create() - publishDir "${params.outdir}/Reports/${idSample}/VCFTools", mode: params.publishDirMode + vcfForVep = Channel.empty().mix( + vcfCompressed.until({ it[0]=="merge" }) + ) +} + +process RunVEP { + tag {"${idSample} - ${variantCaller} - ${vcf}"} + + publishDir params.outdir, mode: params.publishDirMode, saveAs: { + if (it == "${reducedVCF}_VEP.summary.html") "Annotation/${idSample}/VEP/${it}" + else null + } input: - set variantCaller, idPatient, idSample, file(vcf) from vcfForVCFtools + set annotator, variantCaller, idSample, file(vcf), file(idx) from vcfForVep + file dataDir from Channel.value(params.vep_cache ? file(params.vep_cache) : "null") + val cache_version from Channel.value(params.genomes[params.genome].vepCacheVersion) + set file(cadd_WG_SNVs), file(cadd_WG_SNVs_tbi), file(cadd_InDels), file(cadd_InDels_tbi) from Channel.value([ + params.cadd_WG_SNVs ? file(params.cadd_WG_SNVs) : "null", + params.cadd_WG_SNVs_tbi ? file(params.cadd_WG_SNVs_tbi) : "null", + params.cadd_InDels ? file(params.cadd_InDels) : "null", + params.cadd_InDels_tbi ? file(params.cadd_InDels_tbi) : "null" + ]) output: - file ("${reduceVCF(vcf)}.*") into vcfReport + set finalAnnotator, variantCaller, idSample, file("${reducedVCF}_VEP.ann.vcf") into vepVCF + file("${reducedVCF}_VEP.summary.html") into vepReport - when: !params.noReports + when: 'vep' in tools || 'merge' in tools script: + reducedVCF = reduceVCF(vcf) + finalAnnotator = annotator == "snpEff" ? 'merge' : 'VEP' + genome = params.genome == 'smallGRCh37' ? 'GRCh37' : params.genome + dir_cache = (params.vep_cache && params.annotation_cache) ? " \${PWD}/${dataDir}" : "/.vep" + cadd = (params.cadd_cache && params.cadd_WG_SNVs && params.cadd_InDels) ? "--plugin CADD,whole_genome_SNVs.tsv.gz,InDels.tsv.gz" : "" + genesplicer = params.genesplicer ? "--plugin GeneSplicer,/opt/conda/envs/sarek-2.3/bin/genesplicer,/opt/conda/envs/sarek-2.3/share/genesplicer-1.0-1/human,context=200,tmpdir=\$PWD/${reducedVCF}" : "--offline" + """ + mkdir ${reducedVCF} + + vep \ + -i ${vcf} \ + -o ${reducedVCF}_VEP.ann.vcf \ + --assembly ${genome} \ + ${cadd} \ + ${genesplicer} \ + --cache \ + --cache_version ${cache_version} \ + --dir_cache ${dir_cache} \ + --everything \ + --filter_common \ + --fork ${task.cpus} \ + --format vcf \ + --per_gene \ + --stats_file ${reducedVCF}_VEP.summary.html \ + --total_length \ + --vcf + + rm -rf ${reducedVCF} """ - vcftools \ - --gzvcf ${vcf} \ - --relatedness2 \ - --out ${reduceVCF(vcf)} - - vcftools \ - --gzvcf ${vcf} \ - --TsTv-by-count \ - --out ${reduceVCF(vcf)} - - vcftools \ - --gzvcf ${vcf} \ - --TsTv-by-qual \ - --out ${reduceVCF(vcf)} - - vcftools \ - --gzvcf ${vcf} \ - --FILTER-summary \ - --out ${reduceVCF(vcf)} +} + +vepReport = vepReport.dump(tag:'VEP') + +vcfToCompress = snpeffVCF.mix(vepVCF) + +process CompressVCF { + tag {"${idSample} - ${annotator} - ${vcf}"} + + publishDir "${params.outdir}/Annotation/${idSample}/${finalAnnotator}", mode: params.publishDirMode + + input: + set annotator, variantCaller, idSample, file(vcf) from vcfToCompress + + output: + set annotator, variantCaller, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into (vcfCompressed, vcfCompressedoutput) + script: + reducedVCF = reduceVCF(vcf) + finalAnnotator = annotator == "merge" ? "VEP" : annotator + """ + bgzip < ${vcf} > ${vcf}.gz + tabix ${vcf}.gz """ } -vcfReport.dump(tag:'VCFTools') +vcfCompressedoutput = vcfCompressedoutput.dump(tag:'VCF') +/* +================================================================================ + MultiQC +================================================================================ +*/ + +reportsForMultiQC = Channel.empty() + .mix( + bamQCmappedReport, + bamQCrecalibratedReport, + bcfReport, + fastQCreport, + markDuplicatesReport, + samtoolsStatsReport, + snpeffOutput, + vcfReport + ).collect() + +process RunMultiQC { + publishDir "${params.outdir}/Reports/MultiQC", mode: params.publishDirMode + + input: + file (multiqcConfig) from createMultiQCconfig() + file (reports) from reportsForMultiQC + file (versions) from software_versions_yaml + + output: + set file("*multiqc_report.html"), file("*multiqc_data") into multiQCReport + + when: !params.noReports + + script: + """ + multiqc -f -v . + """ +} + +multiQCReport.dump(tag:'MultiQC') /* * Completion e-mail notification @@ -1530,7 +1781,7 @@ workflow.onComplete { // Set up the e-mail variables def subject = "[nf-core/sarek] Successful: $workflow.runName" if (!workflow.success){ - subject = "[nf-core/sarek] FAILED: $workflow.runName" + subject = "[nf-core/sarek] FAILED: $workflow.runName" } def email_fields = [:] email_fields['version'] = workflow.manifest.version @@ -1591,22 +1842,20 @@ workflow.onComplete { // Send the HTML e-mail if (params.email) { try { - if ( params.plaintext_email ){ throw GroovyException('Send plaintext e-mail, not HTML') } - // Try to send HTML e-mail using sendmail - [ 'sendmail', '-t' ].execute() << sendmail_html - log.info "[nf-core/sarek] Sent summary e-mail to $params.email (sendmail)" + if ( params.plaintext_email ){ throw GroovyException('Send plaintext e-mail, not HTML') } + // Try to send HTML e-mail using sendmail + [ 'sendmail', '-t' ].execute() << sendmail_html + log.info "[nf-core/sarek] Sent summary e-mail to $params.email (sendmail)" } catch (all) { - // Catch failures and try with plaintext - [ 'mail', '-s', subject, params.email ].execute() << email_txt - log.info "[nf-core/sarek] Sent summary e-mail to $params.email (mail)" + // Catch failures and try with plaintext + [ 'mail', '-s', subject, params.email ].execute() << email_txt + log.info "[nf-core/sarek] Sent summary e-mail to $params.email (mail)" } } // Write summary e-mail HTML to a file def output_d = new File( "${params.outdir}/pipeline_info/" ) - if ( !output_d.exists() ) { - output_d.mkdirs() - } + if ( !output_d.exists() ) output_d.mkdirs() def output_hf = new File( output_d, "pipeline_report.html" ) output_hf.withWriter { w -> w << email_html } def output_tf = new File( output_d, "pipeline_report.txt" ) @@ -1618,18 +1867,16 @@ workflow.onComplete { c_red = params.monochrome_logs ? '' : "\033[0;31m"; if (workflow.stats.ignoredCountFmt > 0 && workflow.success) { - log.info "${c_purple}Warning, pipeline completed, but with errored process(es) ${c_reset}" - log.info "${c_red}Number of ignored errored process(es) : ${workflow.stats.ignoredCountFmt} ${c_reset}" - log.info "${c_green}Number of successfully ran process(es) : ${workflow.stats.succeedCountFmt} ${c_reset}" + log.info "${c_purple}Warning, pipeline completed, but with errored process(es) ${c_reset}" + log.info "${c_red}Number of ignored errored process(es) : ${workflow.stats.ignoredCountFmt} ${c_reset}" + log.info "${c_green}Number of successfully ran process(es) : ${workflow.stats.succeedCountFmt} ${c_reset}" } - if (workflow.success){ - log.info "${c_purple}[nf-core/sarek]${c_green} Pipeline completed successfully${c_reset}" - } else { + if (workflow.success) log.info "${c_purple}[nf-core/sarek]${c_green} Pipeline completed successfully${c_reset}" + else { checkHostname() log.info "${c_purple}[nf-core/sarek]${c_red} Pipeline completed with errors${c_reset}" } - } def nfcoreHeader(){ @@ -1685,277 +1932,301 @@ def checkHostname(){ } /* -======================================================================================== - sarek functions -======================================================================================== +================================================================================ + sarek functions +================================================================================ */ // Check if a row has the expected number of item def checkNumberOfItem(row, number) { - if (row.size() != number) exit 1, "Malformed row in TSV file: ${row}, see --help for more information" - return true + if (row.size() != number) exit 1, "Malformed row in TSV file: ${row}, see --help for more information" + return true } // Check parameter existence def checkParameterExistence(it, list) { - if (!list.contains(it)) { - println("Unknown parameter: ${it}") - return false - } - return true + if (!list.contains(it)) { + println("Unknown parameter: ${it}") + return false + } + return true } // Compare each parameter with a list of parameters def checkParameterList(list, realList) { - return list.every{ checkParameterExistence(it, realList) } + return list.every{ checkParameterExistence(it, realList) } } // Check if params.item exists and return params.genomes[params.genome].item otherwise def checkParamReturnFile(item) { - params."${item}" = params.genomes[params.genome]."${item}" - return file(params."${item}") + params."${item}" = params.genomes[params.genome]."${item}" + return file(params."${item}") } // Loop through all the references files to check their existence def checkRefExistence(referenceFile, fileToCheck) { - if (fileToCheck instanceof List) return fileToCheck.every{ checkRefExistence(referenceFile, it) } - def f = file(fileToCheck) - // this is an expanded wildcard: we can assume all files exist - if (f instanceof List && f.size() > 0) return true - else if (!f.exists()) { - println "Missing references: ${referenceFile} ${fileToCheck}" - return false - } - return true + if (fileToCheck instanceof List) return fileToCheck.every{ checkRefExistence(referenceFile, it) } + def f = file(fileToCheck) + // this is an expanded wildcard: we can assume all files exist + if (f instanceof List && f.size() > 0) return true + else if (!f.exists()) { + println "Missing references: ${referenceFile} ${fileToCheck}" + return false + } + return true } // Loop through all the references files to check their existence def checkReferenceMap(referenceMap) { - referenceMap.every { - referenceFile, fileToCheck -> - checkRefExistence(referenceFile, fileToCheck) - } + referenceMap.every { + referenceFile, fileToCheck -> + checkRefExistence(referenceFile, fileToCheck) + } +} + +// Personnalise the MultiQC report +def createMultiQCconfig() { + def file = workDir.resolve('multiqc_config.yaml') + file.text = """ + custom_logo: ${baseDir}/docs/images/Sarek_no_Border.png + custom_logo_url: https://sarek.scilifelab.se/ + custom_logo_title: 'nf-core/sarek' + report_header_info: + + top_modules: + - 'fastqc' + - 'picard' + - 'samtools' + - 'qualimap' + - 'bcftools' + - 'vcftools' + - 'snpeff' + """.stripIndent() + + return file } // Define map of reference depending of tools and step def defineReferenceMap(step, tools) { - def referenceMap = - [ - 'genomeDict' : checkParamReturnFile("genomeDict"), - 'genomeFile' : checkParamReturnFile("genomeFile"), - 'genomeIndex' : checkParamReturnFile("genomeIndex"), - 'intervals' : checkParamReturnFile("intervals") - ] - if ('mapping' in step) { - referenceMap.putAll( - 'bwaIndex' : checkParamReturnFile("bwaIndex"), - 'knownIndels' : checkParamReturnFile("knownIndels"), - 'knownIndelsIndex' : checkParamReturnFile("knownIndelsIndex") - ) - } - if ('controlfreec' in tools) { - referenceMap.putAll( - 'chrDir' : checkParamReturnFile("chrDir"), - 'chrLength' : checkParamReturnFile("chrLength") - ) - } - if ('ascat' in tools) { - referenceMap.putAll( - 'acLoci' : checkParamReturnFile("acLoci"), - 'acLociGC' : checkParamReturnFile("acLociGC") - ) - } - if ('mapping' in step || 'haplotypecaller' in tools || 'mutect2' in tools || 'controlfreec' in tools) { - referenceMap.putAll( - 'dbsnp' : checkParamReturnFile("dbsnp"), - 'dbsnpIndex' : checkParamReturnFile("dbsnpIndex") - ) - } - return referenceMap + def referenceMap = [ + 'genomeDict' : checkParamReturnFile("genomeDict"), + 'genomeFile' : checkParamReturnFile("genomeFile"), + 'genomeIndex' : checkParamReturnFile("genomeIndex"), + 'intervals' : checkParamReturnFile("intervals") + ] + if ('mapping' in step) { + referenceMap.putAll( + 'bwaIndex' : checkParamReturnFile("bwaIndex"), + 'knownIndels' : checkParamReturnFile("knownIndels"), + 'knownIndelsIndex' : checkParamReturnFile("knownIndelsIndex") + ) + } + if ('controlfreec' in tools) { + referenceMap.putAll( + 'chrDir' : checkParamReturnFile("chrDir"), + 'chrLength' : checkParamReturnFile("chrLength") + ) + } + if ('ascat' in tools) { + referenceMap.putAll( + 'acLoci' : checkParamReturnFile("acLoci"), + 'acLociGC' : checkParamReturnFile("acLociGC") + ) + } + if ('mapping' in step || 'haplotypecaller' in tools || 'mutect2' in tools || 'controlfreec' in tools) { + referenceMap.putAll( + 'dbsnp' : checkParamReturnFile("dbsnp"), + 'dbsnpIndex' : checkParamReturnFile("dbsnpIndex") + ) + } + if ('annotate' in step) return [] + return referenceMap } // Define list of available step def defineStepList() { - return [ - 'mapping', - 'recalibrate', - 'variantcalling', - 'annotate' - ] + return [ + 'annotate', + 'mapping', + 'recalibrate', + 'variantcalling' + ] } // Define list of available tools def defineToolList() { - return [ - 'ascat', - 'controlfreec', - 'freebayes', - 'haplotypecaller', - 'manta', - 'mpileup', - 'mutect2', - 'strelka' - ] + return [ + 'ascat', + 'controlfreec', + 'freebayes', + 'haplotypecaller', + 'manta', + 'merge', + 'mpileup', + 'mutect2', + 'snpeff', + 'strelka', + 'vep' + ] } // Channeling the TSV file containing BAM. // Format is: "subject gender status sample bam bai" def extractBams(tsvFile) { - Channel.from(tsvFile) - .splitCsv(sep: '\t') - .map { row -> - checkNumberOfItem(row, 6) - def idPatient = row[0] - def gender = row[1] - def status = returnStatus(row[2].toInteger()) - def idSample = row[3] - def bamFile = returnFile(row[4]) - def baiFile = returnFile(row[5]) - - if (!hasExtension(bamFile,"bam")) exit 1, "File: ${bamFile} has the wrong extension. See --help for more information" - if (!hasExtension(baiFile,"bai")) exit 1, "File: ${baiFile} has the wrong extension. See --help for more information" - - return [ idPatient, gender, status, idSample, bamFile, baiFile ] - } + Channel.from(tsvFile) + .splitCsv(sep: '\t') + .map { row -> + checkNumberOfItem(row, 6) + def idPatient = row[0] + def gender = row[1] + def status = returnStatus(row[2].toInteger()) + def idSample = row[3] + def bamFile = returnFile(row[4]) + def baiFile = returnFile(row[5]) + + if (!hasExtension(bamFile,"bam")) exit 1, "File: ${bamFile} has the wrong extension. See --help for more information" + if (!hasExtension(baiFile,"bai")) exit 1, "File: ${baiFile} has the wrong extension. See --help for more information" + + return [ idPatient, gender, status, idSample, bamFile, baiFile ] + } } - // Create a channel of germline FASTQs from a directory pattern: "my_samples/*/" - // All FASTQ files in subdirectories are collected and emitted; - // they must have _R1_ and _R2_ in their names. +// Create a channel of germline FASTQs from a directory pattern: "my_samples/*/" +// All FASTQ files in subdirectories are collected and emitted; +// they must have _R1_ and _R2_ in their names. def extractFastqFromDir(pattern) { - def fastq = Channel.create() - // a temporary channel does all the work - Channel - .fromPath(pattern, type: 'dir') - .ifEmpty { error "No directories found matching pattern '${pattern}'" } - .subscribe onNext: { sampleDir -> - // the last name of the sampleDir is assumed to be a unique sample id - sampleId = sampleDir.getFileName().toString() - - for (path1 in file("${sampleDir}/**_R1_*.fastq.gz")) { - assert path1.getName().contains('_R1_') - path2 = file(path1.toString().replace('_R1_', '_R2_')) - if (!path2.exists()) error "Path '${path2}' not found" - (flowcell, lane) = flowcellLaneFromFastq(path1) - patient = sampleId - gender = 'ZZ' // unused - status = 0 // normal (not tumor) - rgId = "${flowcell}.${sampleId}.${lane}" - result = [patient, gender, status, sampleId, rgId, path1, path2] - fastq.bind(result) - } - }, onComplete: { fastq.close() } - fastq + def fastq = Channel.create() + // a temporary channel does all the work + Channel + .fromPath(pattern, type: 'dir') + .ifEmpty { error "No directories found matching pattern '${pattern}'" } + .subscribe onNext: { sampleDir -> + // the last name of the sampleDir is assumed to be a unique sample id + sampleId = sampleDir.getFileName().toString() + + for (path1 in file("${sampleDir}/**_R1_*.fastq.gz")) { + assert path1.getName().contains('_R1_') + path2 = file(path1.toString().replace('_R1_', '_R2_')) + if (!path2.exists()) error "Path '${path2}' not found" + (flowcell, lane) = flowcellLaneFromFastq(path1) + patient = sampleId + gender = 'ZZ' // unused + status = 0 // normal (not tumor) + rgId = "${flowcell}.${sampleId}.${lane}" + result = [patient, gender, status, sampleId, rgId, path1, path2] + fastq.bind(result) + } + }, onComplete: { fastq.close() } + fastq } // Extract gender from Channel as it's only used for CNVs def extractGenders(channel) { - def genders = [:] - channel = channel.map{ it -> - def idPatient = it[0] - def gender = it[1] - genders[idPatient] = gender - [idPatient] + it[2..-1] - } - [genders, channel] + def genders = [:] + channel = channel.map{ it -> + def idPatient = it[0] + def gender = it[1] + genders[idPatient] = gender + [idPatient] + it[2..-1] + } + [genders, channel] } // Channeling the TSV file containing FASTQ or BAM // Format is: "subject gender status sample lane fastq1 fastq2" // or: "subject gender status sample lane bam" def extractSample(tsvFile) { - Channel.from(tsvFile) - .splitCsv(sep: '\t') - .map { row -> - def idPatient = row[0] - def gender = row[1] - def status = returnStatus(row[2].toInteger()) - def idSample = row[3] - def idRun = row[4] - def file1 = returnFile(row[5]) - def file2 = file("null") - if (hasExtension(file1,"fastq.gz") || hasExtension(file1,"fq.gz")) { - checkNumberOfItem(row, 7) - file2 = returnFile(row[6]) - if (!hasExtension(file2,"fastq.gz") && !hasExtension(file2,"fq.gz")) exit 1, "File: ${file2} has the wrong extension. See --help for more information" - } - else if (hasExtension(file1,"bam")) checkNumberOfItem(row, 6) - else "No recognisable extention for input file: ${file1}" + Channel.from(tsvFile) + .splitCsv(sep: '\t') + .map { row -> + def idPatient = row[0] + def gender = row[1] + def status = returnStatus(row[2].toInteger()) + def idSample = row[3] + def idRun = row[4] + def file1 = returnFile(row[5]) + def file2 = file("null") + if (hasExtension(file1,"fastq.gz") || hasExtension(file1,"fq.gz")) { + checkNumberOfItem(row, 7) + file2 = returnFile(row[6]) + if (!hasExtension(file2,"fastq.gz") && !hasExtension(file2,"fq.gz")) exit 1, "File: ${file2} has the wrong extension. See --help for more information" + } + else if (hasExtension(file1,"bam")) checkNumberOfItem(row, 6) + else "No recognisable extention for input file: ${file1}" - [idPatient, gender, status, idSample, idRun, file1, file2] - } + [idPatient, gender, status, idSample, idRun, file1, file2] + } } // Channeling the TSV file containing Recalibration Tables. // Format is: "subject gender status sample bam bai recalTables" def extractRecal(tsvFile) { - Channel.from(tsvFile) - .splitCsv(sep: '\t') - .map { row -> - checkNumberOfItem(row, 7) - def idPatient = row[0] - def gender = row[1] - def status = returnStatus(row[2].toInteger()) - def idSample = row[3] - def bamFile = returnFile(row[4]) - def baiFile = returnFile(row[5]) - def recalTable = returnFile(row[6]) - - if (!hasExtension(bamFile,"bam")) exit 1, "File: ${bamFile} has the wrong extension. See --help for more information" - if (!hasExtension(baiFile,"bai")) exit 1, "File: ${baiFile} has the wrong extension. See --help for more information" - if (!hasExtension(recalTable,"recal.table")) exit 1, "File: ${recalTable} has the wrong extension. See --help for more information" - - [ idPatient, gender, status, idSample, bamFile, baiFile, recalTable ] - } + Channel.from(tsvFile) + .splitCsv(sep: '\t') + .map { row -> + checkNumberOfItem(row, 7) + def idPatient = row[0] + def gender = row[1] + def status = returnStatus(row[2].toInteger()) + def idSample = row[3] + def bamFile = returnFile(row[4]) + def baiFile = returnFile(row[5]) + def recalTable = returnFile(row[6]) + + if (!hasExtension(bamFile,"bam")) exit 1, "File: ${bamFile} has the wrong extension. See --help for more information" + if (!hasExtension(baiFile,"bai")) exit 1, "File: ${baiFile} has the wrong extension. See --help for more information" + if (!hasExtension(recalTable,"recal.table")) exit 1, "File: ${recalTable} has the wrong extension. See --help for more information" + + [ idPatient, gender, status, idSample, bamFile, baiFile, recalTable ] + } } // Parse first line of a FASTQ file, return the flowcell id and lane number. def flowcellLaneFromFastq(path) { - // expected format: - // xx:yy:FLOWCELLID:LANE:... (seven fields) - // or - // FLOWCELLID:LANE:xx:... (five fields) - InputStream fileStream = new FileInputStream(path.toFile()) - InputStream gzipStream = new java.util.zip.GZIPInputStream(fileStream) - Reader decoder = new InputStreamReader(gzipStream, 'ASCII') - BufferedReader buffered = new BufferedReader(decoder) - def line = buffered.readLine() - assert line.startsWith('@') - line = line.substring(1) - def fields = line.split(' ')[0].split(':') - String fcid - int lane - if (fields.size() == 7) { - // CASAVA 1.8+ format - fcid = fields[2] - lane = fields[3].toInteger() - } - else if (fields.size() == 5) { - fcid = fields[0] - lane = fields[1].toInteger() - } - [fcid, lane] + // expected format: + // xx:yy:FLOWCELLID:LANE:... (seven fields) + // or + // FLOWCELLID:LANE:xx:... (five fields) + InputStream fileStream = new FileInputStream(path.toFile()) + InputStream gzipStream = new java.util.zip.GZIPInputStream(fileStream) + Reader decoder = new InputStreamReader(gzipStream, 'ASCII') + BufferedReader buffered = new BufferedReader(decoder) + def line = buffered.readLine() + assert line.startsWith('@') + line = line.substring(1) + def fields = line.split(' ')[0].split(':') + String fcid + int lane + if (fields.size() == 7) { + // CASAVA 1.8+ format + fcid = fields[2] + lane = fields[3].toInteger() + } else if (fields.size() == 5) { + fcid = fields[0] + lane = fields[1].toInteger() + } + [fcid, lane] } // Check file extension def hasExtension(it, extension) { - it.toString().toLowerCase().endsWith(extension.toLowerCase()) + it.toString().toLowerCase().endsWith(extension.toLowerCase()) } // Return file if it exists def returnFile(it) { - if (!file(it).exists()) exit 1, "Missing file in TSV file: ${it}, see --help for more information" - return file(it) + if (!file(it).exists()) exit 1, "Missing file in TSV file: ${it}, see --help for more information" + return file(it) } // Remove .ann .gz and .vcf extension from a VCF file def reduceVCF(file) { - return file.fileName.toString().minus(".ann").minus(".vcf").minus(".gz") + return file.fileName.toString().minus(".ann").minus(".vcf").minus(".gz") } // Return status [0,1] // 0 == Normal, 1 == Tumor def returnStatus(it) { - if (!(it in [0, 1])) exit 1, "Status is not recognized in TSV file: ${it}, see --help for more information" - return it + if (!(it in [0, 1])) exit 1, "Status is not recognized in TSV file: ${it}, see --help for more information" + return it } diff --git a/nextflow.config b/nextflow.config index a43d967601..c062fb9173 100644 --- a/nextflow.config +++ b/nextflow.config @@ -44,6 +44,16 @@ params { // Developmental code should specify :dev process.container = 'nfcore/sarek:dev' +process { + withName:RunSnpeff { + container = {(params.annotation_cache && params.snpEff_cache) ? 'nfcore/sarek:dev' : "nfcore/sareksnpeff:dev.${params.genome}"} + } + + withName:RunVEP { + container = {(params.annotation_cache && params.vep_cache) ? 'nfcore/sarek:dev' : "nfcore/sarekvep:dev.${params.genome}"} + } +} + // Load base.config by default for all pipelines includeConfig 'conf/base.config' From ffabee76f6b17283cac72a1eeb82fbd6a94acc4d Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Thu, 9 May 2019 14:44:34 +0200 Subject: [PATCH 015/854] Get base requirements set up --- conf/base.config | 124 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 119 insertions(+), 5 deletions(-) diff --git a/conf/base.config b/conf/base.config index 14c8f70aef..543afdd7a3 100644 --- a/conf/base.config +++ b/conf/base.config @@ -10,8 +10,6 @@ */ process { - - // TODO nf-core: Check the defaults for all processes cpus = { check_max( 1 * task.attempt, 'cpus' ) } memory = { check_max( 8.GB * task.attempt, 'memory' ) } time = { check_max( 2.h * task.attempt, 'time' ) } @@ -20,9 +18,125 @@ process { maxErrors = '-1' maxRetries = 1 - // Process-specific resource requirements - // TODO nf-core: Customise requirements for specific processes. - // See https://www.nextflow.io/docs/latest/config.html#config-process-selectors + //We'll have low, medium, high labels + /* + * ------------------------------------------------- + * Nextflow config file for Sarek + * ------------------------------------------------- + * Generalized resource configuration for clusters + * ------------------------------------------------- + */ + +params { + singleCPUMem = 7.GB // for processes that are using more memory but a single CPU only. Use the 'core' queue for these +} + +process { + cpus = { check_max( 10, 'cpus' ) } + memory = { check_max( 16.GB * task.attempt, 'memory' ) } + time = { check_max( 8.h * task.attempt, 'time' ) } + + errorStrategy = {task.exitStatus == 143 ? 'retry' : 'terminate'} + maxErrors = '-1' + maxRetries = 3 + + withName:MapReads { + memory = { check_max( 60.GB * task.attempt, 'memory' ) } + cpus = { check_max( 16, 'cpus' ) } + } + withName:CreateRecalibrationTable { + cpus = { check_max( 1, 'cpus' ) } + memory = { check_max( 60.GB * task.attempt, 'memory') } + } + withName:MarkDuplicates { + // Actually the -Xmx value should be kept lower, + // and is set through the markdup_java_options + cpus = { check_max( 8, 'cpus' ) } + memory = { check_max( 8.GB * task.attempt, 'memory' ) } + } + withName:MergeBams { + cpus = { check_max( 4, 'cpus') } + memory = {params.singleCPUMem * task.attempt} + time = { check_max( 5.h * task.attempt, 'time' ) } + } + withName:RecalibrateBam { + cpus = { check_max( 2, 'cpus' ) } + memory = { check_max( 7.GB * 2 * task.attempt, 'memory' ) } + time = { check_max( 10.h * task.attempt, 'time' ) } + } + withName:RunAlleleCount { + cpus = { check_max( 1, 'cpus' ) } + memory = { check_max( 14.GB * task.attempt, 'memory' ) } + } + withName:RunAscat { + cpus = { check_max( 1, 'cpus' ) } + memory = { check_max( 14.GB * task.attempt, 'memory' ) } + } + withName:RunBamQCmapped { + cpus = { check_max( 6, 'cpus' ) } + memory = { check_max( 70.GB, 'memory' ) } + } + withName:RunBamQCrecalibrated { + cpus = { check_max( 6, 'cpus' ) } + memory = { check_max( 70.GB, 'memory' ) } + } + withName:RunBcftoolsStats { + cpus = { check_max( 1, 'cpus' ) } + } + withName:RunConvertAlleleCounts { + cpus = { check_max( 1, 'cpus' ) } + memory = { check_max( 14.GB * task.attempt, 'memory' ) } + } + withName:RunFastQC { + cpus = { check_max( 2, 'cpus' ) } // FastQC is only capable of running one thread per fastq file. + errorStrategy = { task.exitStatus == 143 ? 'retry' : 'ignore' } + } + withName:RunFreeBayes { + cpus = { check_max( 1, 'cpus' ) } + memory = { check_max( 8.GB * task.attempt, 'memory' ) } + } + withName:RunHaplotypecaller { + cpus = { check_max( 1, 'cpus' ) } + // Increase memory quadratically + memory = { check_max( 7.GB * 2 * task.attempt, 'memory' ) } + time = { check_max( 5.h * task.attempt, 'time' ) } + } + withName:RunGenotypeGVCFs { + cpus = { check_max( 1, 'cpus' ) } + memory = { check_max( 7.GB * task.attempt, 'memory' ) } + } + withName:RunMultiQC { + errorStrategy = { task.exitStatus == 143 ? 'retry' : 'ignore' } + } + withName:RunMutect2 { + cpus = { check_max( 2, 'cpus' ) } + memory = { check_max( 7.GB * task.attempt, 'memory' ) } + time = { check_max( 5.h * task.attempt, 'time' ) } + } + withName:RunSamtoolsStats { + cpus = { check_max( 2, 'cpus' ) } + time = { check_max( 5.h * task.attempt, 'time' ) } + } + withName:RunSingleManta { + cpus = { check_max( 20, 'cpus' ) } + memory = { check_max( 16.GB, 'memory') } + } + withName:RunSingleStrelka { + cpus = { check_max( 20, 'cpus' ) } + memory = { check_max( 16.GB, 'memory') } + time = { check_max( 5.h * task.attempt, 'time' ) } + } + withName:RunSnpeff { + cpus = { check_max( 1, 'cpus' ) } + } + withName:RunStrelka { + cpus = { check_max( 1, 'cpus' ) } + time = { check_max( 5.h * task.attempt, 'time' ) } + } + withName:RunVEP { + cpus = { check_max( 4, 'cpus' ) } + memory = {check_max (32.GB * task.attempt, 'memory' ) } + } } params { From f9e13a45d14ebbaf3dc8b2d67089f8d8fdb306df Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Tue, 14 May 2019 10:50:44 +0200 Subject: [PATCH 016/854] Improve tests and docs (#8) * improve tests + add some docs --- .circleci/config.yml | 9 +++------ README.md | 43 ++++++++++++++++++++++++------------------ bin/build_reference.sh | 13 ++----------- bin/run_tests.sh | 14 ++++++++------ build.nf | 33 +++++++++++++++++++++++++++----- conf/test.config | 18 +++++++++--------- docs/reference.md | 21 +++++++++++++++++++++ main.nf | 21 +++++++++++---------- nextflow.config | 10 ++-------- 9 files changed, 109 insertions(+), 73 deletions(-) create mode 100644 docs/reference.md diff --git a/.circleci/config.yml b/.circleci/config.yml index 0390dca9e0..62e2e17cda 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -60,10 +60,9 @@ jobs: - setup_remote_docker - run: command: docker build -t nfcore/sarekvep:dev.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} - no_output_timeout: 45m + no_output_timeout: 1.5h - run: command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:dev.${GENOME} - no_output_timeout: 45m vepgrch38: docker: @@ -77,10 +76,9 @@ jobs: - setup_remote_docker - run: command: docker build -t nfcore/sarekvep:dev.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} - no_output_timeout: 45m + no_output_timeout: 1.5h - run: command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:dev.${GENOME} - no_output_timeout: 45m vepgrcm38: docker: @@ -94,10 +92,9 @@ jobs: - setup_remote_docker - run: command: docker build -t nfcore/sarekvep:dev.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} - no_output_timeout: 45m + no_output_timeout: 30m - run: command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:dev.${GENOME} - no_output_timeout: 45m workflows: version: 2 diff --git a/README.md b/README.md index fadcd83b64..00749a51c7 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,16 @@ **An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing**. -> :warning: This pipeline is a work in progress being ported to nf-core from [SciLifeLab/Sarek](https://github/SciLifeLab/Sarek) +> :warning: This pipeline is a work in progress being ported to nf-core from [SciLifeLab/Sarek](https://github/SciLifeLab/Sarek/) -[![Nextflow version][nextflow-badge]](https://www.nextflow.io) -[![Travis build status][travis-badge]](https://travis-ci.org/nf-core/sarek) -[![CircleCi build status][circleci-badge]](https://circleci.com/gh/nf-core/workflows/sarek) +[![Nextflow version][nextflow-badge]](https://www.nextflow.io/) +[![nf-core][nf-core-badge]](https://nf-co.re/) + +[![Travis build status][travis-badge]](https://travis-ci.com/nf-core/sarek/) +[![CircleCi build status][circleci-badge]](https://circleci.com/gh/nf-core/sarek/) [![Install with bioconda][bioconda-badge]](http://bioconda.github.io/) -[![Docker Container available][docker-sarek-badge]](https://hub.docker.com/r/nfcore/sarek) +[![Docker Container available][docker-sarek-badge]](https://hub.docker.com/r/nfcore/sarek/) [![Install with Singularity][singularity-badge]](https://www.sylabs.io/docs/) [![Join us on Slack][slack-badge]](https://nfcore.slack.com/messages/CGFUX04HZ/) @@ -33,16 +35,12 @@ It is listed on the [Elixir - Tools and Data Services Registry](https://bio.tool The nf-core/sarek pipeline comes with documentation about the pipeline, found in the `docs/` directory: 1. [Installation](https://nf-co.re/usage/installation) - * [Installation documentation](docs/INSTALL.md) - * [Installation documentation specific for UPPMAX `rackham`](docs/INSTALL_RACKHAM.md) - * [Installation documentation specific for UPPMAX `bianca`](docs/INSTALL_BIANCA.md) 2. Pipeline configuration * [Local installation](https://nf-co.re/usage/local_installation) * [Adding your own system config](https://nf-co.re/usage/adding_own_config) * [Reference genomes](https://nf-co.re/usage/reference_genomes) 3. [Running the pipeline](docs/usage.md) * [Tests documentation](docs/TESTS.md) - * [Reference files documentation](docs/REFERENCES.md) * [Configuration and profiles documentation](docs/CONFIG.md) * [Intervals documentation](docs/INTERVALS.md) * [Running the pipeline](docs/USAGE.md) @@ -51,8 +49,8 @@ The nf-core/sarek pipeline comes with documentation about the pipeline, found in * [Examples](docs/USE_CASES.md) * [Input files documentation](docs/INPUT.md) * [Processes documentation](docs/PROCESS.md) -4. [Output and how to interpret the results](docs/output.md) * [Documentation about containers](docs/CONTAINERS.md) +4. [Output and how to interpret the results](docs/output.md) * [Complementary information about ASCAT](docs/ASCAT.md) * [Complementary information about annotations](docs/ANNOTATION.md) * [Output documentation structure](docs/OUTPUT.md) @@ -69,7 +67,7 @@ You can choose which variant callers to use, plus the pipeline is capable of acc The worflow steps and tools used are as follows: -1. **Preprocessing** - `main.nf` _(based on [GATK best practices](https://software.broadinstitute.org/gatk/best-practices/))_ +1. **Preprocessing** _(based on [GATK best practices](https://software.broadinstitute.org/gatk/best-practices/))_ * Map reads to Reference * [BWA](http://bio-bwa.sourceforge.net/) * Mark Duplicates @@ -77,13 +75,13 @@ The worflow steps and tools used are as follows: * Base (Quality Score) Recalibration * [GATK BaseRecalibrator](https://github.com/broadinstitute/gatk) * [GATK ApplyBQSR](https://github.com/broadinstitute/gatk) -2. **Germline variant calling** - `germlineVC.nf` +2. **Germline variant calling** * SNVs and small indels * [GATK HaplotypeCaller](https://github.com/broadinstitute/gatk) * [Strelka2](https://github.com/Illumina/strelka) * Structural variants * [Manta](https://github.com/Illumina/manta) -3. **Somatic variant calling** - `somaticVC.nf` _(optional)_ +3. **Somatic variant calling** * SNVs and small indels * [MuTect2](https://github.com/broadinstitute/gatk) * [Freebayes](https://github.com/ekg/freebayes) @@ -92,11 +90,19 @@ The worflow steps and tools used are as follows: * [Manta](https://github.com/Illumina/manta) * Sample heterogeneity, ploidy and CNVs * [ASCAT](https://github.com/Crick-CancerGenomics/ascat) -4. **Annotation** - `annotate.nf` _(optional)_ +4. **Annotation** * Variant annotation * [SnpEff](http://snpeff.sourceforge.net/) * [VEP (Variant Effect Predictor)](https://www.ensembl.org/info/docs/tools/vep/index.html) -5. **Reporting** - `runMultiQC.nf` +5. **QC and Reporting** + * QC + * [FastQC](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/) + * [Qualimap bamqc](http://qualimap.bioinfo.cipf.es/doc_html/command_line.html) + * [samtools stats](https://www.htslib.org/doc/samtools.html) + * [GATK MarkDuplicates](https://github.com/broadinstitute/gatk) + * [bcftools stats](http://www.htslib.org/doc/bcftools.html) + * [VCFtools](https://vcftools.github.io/index.html) + * [SnpEff](http://snpeff.sourceforge.net/) * Reporting * [MultiQC](http://multiqc.info) @@ -139,16 +145,17 @@ For further information or help, don't hesitate to get in touch on [Slack](https :-:|:-: [![National Genomics Infrastructure](docs/images/NGI_logo.png)](https://ngisweden.scilifelab.se/) | [![National Bioinformatics Infrastructure Sweden](docs/images/NBIS_logo.png)](https://nbis.se) -[bioconda-badge]: https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg?logo=data:image/png;base64,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 +[bioconda-badge]: https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg?logo=data:image/png;base64,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 [btb-link]: https://ki.se/forskning/barntumorbanken-0 [circleci-badge]: https://img.shields.io/circleci/project/github/nf-core/sarek.svg?logo=circleci [docker-sarek-badge]: https://img.shields.io/docker/automated/nfcore/sarek.svg?logo=docker [docker-snpeff-badge]: https://img.shields.io/docker/automated/nfcore/sareksnpeff.svg?logo=docker [docker-vep-badge]: https://img.shields.io/docker/automated/nfcore/sarekvep.svg?logo=docker [nbis-link]: https://nbis.se -[nextflow-badge]: https://img.shields.io/badge/nextflow-%E2%89%A519.04.0-brightgreen.svg?logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgd2lkdGg9IjEyLjc5OTIyOG1tIiAgIGhlaWdodD0iMTIuODA0ODA5bW0iICAgdmlld0JveD0iMCAwIDQ1LjM1MTU5NCA0NS4zNzEzNjkiICAgaWQ9InN2Zzc2NTIiICAgdmVyc2lvbj0iMS4xIiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTEgcjEzNzI1IiAgIHNvZGlwb2RpOmRvY25hbWU9Im5leHRmbG93LWZhdmljb24td2hpdGUuc3ZnIj4gIDxkZWZzICAgICBpZD0iZGVmczc2NTQiIC8+ICA8c29kaXBvZGk6bmFtZWR2aWV3ICAgICBpZD0iYmFzZSIgICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIgICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIgICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiICAgICBpbmtzY2FwZTp6b29tPSI3LjkxOTU5NTkiICAgICBpbmtzY2FwZTpjeD0iMjAuMTEzMjM1IiAgICAgaW5rc2NhcGU6Y3k9IjIzLjE2MzkwOCIgICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIgICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImxheWVyMSIgICAgIHNob3dncmlkPSJmYWxzZSIgICAgIGZpdC1tYXJnaW4tdG9wPSIwIiAgICAgZml0LW1hcmdpbi1sZWZ0PSIwIiAgICAgZml0LW1hcmdpbi1yaWdodD0iMCIgICAgIGZpdC1tYXJnaW4tYm90dG9tPSIwIiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxOTIwIiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTAxNSIgICAgIGlua3NjYXBlOndpbmRvdy14PSIwIiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjAiICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIiAvPiAgPG1ldGFkYXRhICAgICBpZD0ibWV0YWRhdGE3NjU3Ij4gICAgPHJkZjpSREY+ICAgICAgPGNjOldvcmsgICAgICAgICByZGY6YWJvdXQ9IiI+ICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4gICAgICAgIDxkYzp0eXBlICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+ICAgICAgPC9jYzpXb3JrPiAgICA8L3JkZjpSREY+ICA8L21ldGFkYXRhPiAgPGcgICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciIgICAgIGlkPSJsYXllcjEiICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMTQuMTA0MzcsLTQ1Mi41MzM2NikiPiAgICA8cGF0aCAgICAgICBzdHlsZT0iZmlsbDojZmZmZmZmIiAgICAgICBkPSJtIC0xMTQuMTA0MzcsNDU1LjQ2NTYyIDAsOC44NjEzMyAwLjIwMzEzLDAuMDYwNSBjIDMuODcyOTMsMS4xMzk0MyA4LjY1MjUxLDQuMzgzMiAxMi44MDA3OCw4LjY4NzUgMC45MTM2MywwLjk0ODAxIDEuOTcyNTY0LDIuMTA2ODQgMi4zNTM1MjQsMi41NzYxOCBsIDAuNjkxNCwwLjg1MzUxIC0wLjg2OTE0LDAuNzc1MzkgYyAtNC4xOTk5MDQsMy43NDE5MyAtOC45NzE5MDQsNi43NjYzNyAtMTQuMTA1NDc0LDguOTQxNDEgLTAuMzA5NzUsMC4xMzEyNCAtMC42OTcyMiwwLjI4MTIzIC0xLjA3NDIyLDAuNDI3NzMgbCAwLDkuMzA0NjkgYyAyLjY1OTkzLC0wLjg3NzkyIDUuMzA2MzksLTEuOTc1IDguMDYwNTUsLTMuMzUxNTYgNC4yNTYyMywtMi4xMjczMiA3LjU0MzI1NCwtNC4yNTc2NCAxMS4wMzcxMTQsLTcuMTU2MjUgMC45MjU4MSwtMC43NjgwOCAxLjgyMTA5LC0xLjUwNzAyIDEuOTkwMjMsLTEuNjQyNTggMC4yNzkzMSwtMC4yMjM4NCAwLjQ5MzMyLC0wLjA1MTQgMi4zMjQyMiwxLjg3ODkxIDYuMjIyNjUsNi41NjA0MSAxMy43ODMzNywxMC43NDQ0MyAyMS45Mzk0NiwxMi4yMjI2NSBsIDAsLTguOTQxNCBjIC00Ljc5NTM3LC0xLjE5NTkgLTkuNDIwMzEsLTMuNjQ1MTEgLTEzLjI1NzgyLC03LjA2NDQ2IC0xLjY4MzUxLC0xLjUwMDA2IC00LjI4NjgxLC00LjM1MDA5IC00LjM5MjU4LC00LjgwODU5IC0wLjA2ODYsLTAuMjk3MyA1LjQ3NDgsLTUuNzA5NzcgNy4yOTQ5MywtNy4xMjMwNSAzLjQ4MjczLC0yLjcwNDI0IDYuNTg4MjUsLTQuMTIwNDIgMTAuMjc1MzksLTQuNjg1NTQgMC4wMjc1LC0wLjAwNCAwLjA1MjcsLTAuMDA4IDAuMDgwMSwtMC4wMTE3IGwgMCwtOC43NSBjIC03LjkzOTI3LDIuMDIxMTQgLTE0Ljg3MDAxLDUuODc3MzggLTIxLjUsMTEuOTQzMzYgbCAtMS42MzA4NiwxLjQ5MjE4IC0yLjk5NjEsLTMuMDA3ODEgYyAtMS42NDc1NiwtMS42NTQ3IC0zLjc0MDI1LC0zLjYwMTU3IC00LjY1MjM0LC00LjMyNjE3IC01LjAwODU1NCwtMy45Nzg5OSAtMTAuMTUyOTU0LC02LjQ5OTIzIC0xNC41NzIyNzQsLTcuMTU2MjUgeiIgICAgICAgaWQ9InBhdGg3NjIwIiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY3NjY2NzY2Nzc2NzY2NzY3NjY2NjY2NzYyIgLz4gIDwvZz48L3N2Zz4= +[nextflow-badge]: https://img.shields.io/badge/nextflow-%E2%89%A519.04.0-brightgreen.svg?logo=data:image/png;base64,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 +[nf-core-badge]: https://img.shields.io/badge/nf--core-pipeline-brightgreen.svg?logo=data:image/png;base64,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 [ngi-link]: https://ngisweden.scilifelab.se/ [scilifelab-link]: https://scilifelab.se -[singularity-badge]: https://img.shields.io/badge/use%20with-singularity-purple.svg +[singularity-badge]: https://img.shields.io/badge/use%20with-singularity-purple.svg?logo=data:image/png;base64,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 [slack-badge]: https://img.shields.io/badge/slack-nfcore/sarek-blue.svg?logo=slack [travis-badge]: https://img.shields.io/travis/nf-core/sarek.svg?logo=travis diff --git a/bin/build_reference.sh b/bin/build_reference.sh index ad01808d69..faa7607645 100755 --- a/bin/build_reference.sh +++ b/bin/build_reference.sh @@ -1,7 +1,6 @@ #!/bin/bash set -xeuo pipefail -BUILD=false TEST=ALL TRAVIS_BUILD_DIR=${TRAVIS_BUILD_DIR:-.} TRAVIS=${TRAVIS:-false} @@ -15,24 +14,16 @@ do shift # past argument shift # past value ;; - -b|--build) - BUILD=true - shift # past value - ;; *) # unknown option shift # past argument ;; esac done -# Always download test data -rm -rf data -git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data - # Build references for smallGRCh37 -if [[ BUILD ]] && [[ $TEST != ANNOTATESNPEFF ]] && [[ $TEST != ANNOTATEVEP ]] +if [[ $TEST != ANNOTATESNPEFF ]] && [[ $TEST != ANNOTATEVEP ]] then rm -rf references - nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile docker -ansi-log false --publishDirMode link --max_memory 7.GB --max_cpus 2 -dump-channels --genome smallGRCh37 --refdir data/reference --outdir references + nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile test,docker --build --outdir references -ansi-log false -dump-channels rm -rf .nextflow* references/pipeline_info work fi diff --git a/bin/run_tests.sh b/bin/run_tests.sh index 98119c2174..beb2b77ac6 100755 --- a/bin/run_tests.sh +++ b/bin/run_tests.sh @@ -26,23 +26,25 @@ do done function run_sarek() { - nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile docker -ansi-log false --publishDirMode link --max_memory 7.GB --max_cpus 2 -dump-channels --genome smallGRCh37 --igenomes_base references $@ + nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile test,docker -ansi-log false -dump-channels $@ } if [[ ALL,GERMLINE =~ $TEST ]] then + rm -rf data + git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data run_sarek --sample data/testdata/tiny/normal --tools HaplotypeCaller,Strelka --noReports - run_sarek --step recalibrate --noReports + run_sarek --step recalibrate --sample results/Preprocessing/TSV/duplicateMarked.tsv --noReports fi if [[ ALL,SOMATIC =~ $TEST ]] then - run_sarek --sample data/testdata/tsv/tiny-manta.tsv --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports + run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports fi if [[ ALL,TARGETED =~ $TEST ]] then - run_sarek --sample data/testdata/tsv/tiny-manta.tsv --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports --targetBED data/testdata/target.bed + run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports --targetBED https://github.com/nf-core/test-datasets/raw/sarek/testdata/target.bed fi if [[ ALL,ANNOTATEALL,ANNOTATESNPEFF,ANNOTATEVEP =~ $TEST ]] @@ -57,10 +59,10 @@ then then ANNOTATOR=merge,snpEFF,VEP fi - run_sarek --step annotate --tools ${ANNOTATOR} --annotateVCF data/testdata/vcf/Strelka_1234N_variants.vcf.gz --noReports + run_sarek --step annotate --tools ${ANNOTATOR} --sample https://github.com/nf-core/test-datasets/raw/sarek/testdata/vcf/Strelka_1234N_variants.vcf.gz --noReports fi if [[ MULTIPLE =~ $TEST ]] then - run_sarek --sample data/testdata/tsv/tiny-multiple.tsv --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports + run_sarek --sample https://github.com/nf-core/test-datasets/raw/sarek/testdata/tsv/tiny-multiple.tsv --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports fi diff --git a/build.nf b/build.nf index 979601371c..583fccac5a 100644 --- a/build.nf +++ b/build.nf @@ -21,14 +21,23 @@ Usage: you're reading it BUILD REFERENCES: - nextflow run build.nf [--refdir --outdir ] - --refdir - Specify a directory containing reference files + nextflow run build.nf --build --outdir [--offline] + --build + Will build reference files for smallGRCh37 --outdir Specify an output directory + --offline + Will use data as the source for the reference files + Need to do: + `git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data` + Before transfering the repo to an offline location + DOWNLOAD CACHE: nextflow run build.nf --download_cache [--snpEff_cache ] [--vep_cache ] + [--cadd_cache --cadd_version ] + --download_cache + Will download specified cache --snpEff_cache Specify path to snpEff cache If none, will use snpEff version specified in configuration @@ -54,15 +63,29 @@ DOWNLOAD CACHE: // Show help message if (params.help) exit 0, helpMessage() -ch_referencesFiles = Channel.fromPath("${params.refdir}/*") - // Default value for params +params.build = null +params.offline = null params.cadd_cache = null params.cadd_version = 'v1.5' params.genome = 'smallGRCh37' params.snpEff_cache = null params.vep_cache = null +ch_referencesFiles = Channel.empty() + +if ((params.build) && (params.offline)) ch_referencesFiles = Channel.fromPath("data/reference/*") +if ((params.build) && (!params.offline)) ch_referencesFiles = ch_referencesFiles.mix( + Channel.fromPath("https://github.com/nf-core/test-datasets/raw/sarek/reference/1000G_phase1.indels.b37.small.vcf.gz"), + Channel.fromPath("https://github.com/nf-core/test-datasets/raw/sarek/reference/1000G_phase3_20130502_SNP_maf0.3.small.loci"), + Channel.fromPath("https://github.com/nf-core/test-datasets/raw/sarek/reference/1000G_phase3_20130502_SNP_maf0.3.small.loci.gc"), + Channel.fromPath("https://github.com/nf-core/test-datasets/raw/sarek/reference/Mills_and_1000G_gold_standard.indels.b37.small.vcf.gz"), + Channel.fromPath("https://github.com/nf-core/test-datasets/raw/sarek/reference/dbsnp_138.b37.small.vcf.gz"), + Channel.fromPath("https://github.com/nf-core/test-datasets/raw/sarek/reference/human_g1k_v37_decoy.small.fasta.gz"), + Channel.fromPath("https://github.com/nf-core/test-datasets/raw/sarek/reference/small.intervals")) + +ch_referencesFiles = ch_referencesFiles.dump(tag:'Reference Files') + // Check if genome exists in the config file if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { exit 1, "The provided genome '${params.genome}' is not available in the iGenomes file. Currently the available genomes are ${params.genomes.keySet().join(", ")}" diff --git a/conf/test.config b/conf/test.config index 84e483eb2a..95a9a6ce6d 100644 --- a/conf/test.config +++ b/conf/test.config @@ -8,18 +8,18 @@ */ params { - config_profile_name = 'Test profile' config_profile_description = 'Minimal test dataset to check pipeline function' + config_profile_name = 'Test profile' // Limit resources so that this can run on Travis max_cpus = 2 - max_memory = 6.GB + max_memory = 7.GB max_time = 48.h // Input data - // TODO nf-core: Specify the paths to your test data on nf-core/test-datasets - // TODO nf-core: Give any required params for the test so that command line flags are not needed - singleEnd = false - readPaths = [ - ['Testdata', ['https://github.com/nf-core/test-datasets/raw/exoseq/testdata/Testdata_R1.tiny.fastq.gz', 'https://github.com/nf-core/test-datasets/raw/exoseq/testdata/Testdata_R2.tiny.fastq.gz']], - ['SRR389222', ['https://github.com/nf-core/test-datasets/raw/methylseq/testdata/SRR389222_sub1.fastq.gz', 'https://github.com/nf-core/test-datasets/raw/methylseq/testdata/SRR389222_sub2.fastq.gz']] - ] + sample = 'https://github.com/nf-core/test-datasets/raw/sarek/testdata/tsv/tiny-manta-https.tsv' + // Small reference genome + // To be build with: `nextflow run build.nf --build -profile docker --outdir references` + genome = 'smallGRCh37' + igenomes_base = 'references' + // Use publishDir mode link so that work can be removed + publishDirMode = 'link' } diff --git a/docs/reference.md b/docs/reference.md new file mode 100644 index 0000000000..5d772a2733 --- /dev/null +++ b/docs/reference.md @@ -0,0 +1,21 @@ +# Genomes and reference files + +## AWS iGenomes +Sarek is using [AWS iGenomes](https://ewels.github.io/AWS-iGenomes/), which facilitate storing and sharing references. +Both `GRCh37` and `GRCh38` are available with `--genome GRCh37` or `--genome GRCh38` respectively with any profile using the `conf/igenomes.config` file, or you can specify it with `-c conf/igenomes.config`. + +Sarek currently uses `GRCh38` by default. + +Settings in `igenomes.config` can be tailored to your needs. + +The [`build.nf`](#buildnf) script is used to build the indexes for the reference test. + +Use `--genome smallGRCh37` to map against a small reference genome based on GRCh37. + +## build.nf + +The `build.nf` script can build the files needed for smallGRCh37. + +``` +nextflow run build.nf +``` diff --git a/main.nf b/main.nf index 9775904fb9..cf73043548 100644 --- a/main.nf +++ b/main.nf @@ -93,7 +93,6 @@ if (params.genomes && params.genome && !params.genomes.containsKey(params.genome // Default value for params params.annotateTools = null -params.annotateVCF = null params.annotation_cache = null params.cadd_InDels = null params.cadd_InDels_tbi = null @@ -104,10 +103,12 @@ params.noReports = null params.nucleotidesPerSecond = 1000.0 params.sample = null params.sequencing_center = null +params.snpEff_cache = null params.step = 'mapping' params.strelkaBP = true params.targetBED = null params.tools = null +params.vep_cache = null stepList = defineStepList() step = params.step ? params.step.toLowerCase() : '' @@ -117,7 +118,6 @@ if ( step.contains(',') ) exit 1, 'You can choose only one step, see --help for tools = params.tools ? params.tools.split(',').collect{it.trim().toLowerCase()} : [] annotateTools = params.annotateTools ? params.annotateTools.split(',').collect{it.trim().toLowerCase()} : [] -annotateVCF = params.annotateVCF ? params.annotateVCF.split(',').collect{it.trim()} : [] toolList = defineToolList() if ( !checkParameterList(tools,toolList) ) exit 1, 'Unknown tool(s), see --help for more information' @@ -148,7 +148,7 @@ ch_output_docs = Channel.fromPath("${baseDir}/docs/output.md") */ tsvPath = null -if (params.sample) if (hasExtension(params.sample,"tsv")) tsvPath = params.sample +if (params.sample) if (hasExtension(params.sample,"tsv") || hasExtension(params.sample,"vcf") || hasExtension(params.sample,"vcf.gz")) tsvPath = params.sample // No need for tsv file for step annotate if (!params.sample) { @@ -166,6 +166,7 @@ if (tsvPath) { case 'mapping': inputFiles = extractSample(tsvFile); break case 'recalibrate': bamFiles = extractRecal(tsvFile); break case 'variantcalling': bamFiles = extractBams(tsvFile); break + case 'annotate': break default: exit 1, "Unknown step ${step}" } } else if (params.sample) if (!hasExtension(params.sample,"tsv")) { @@ -174,9 +175,11 @@ if (tsvPath) { inputFiles = extractFastqFromDir(params.sample) (inputFiles, fastqTmp) = inputFiles.into(2) fastqTmp.toList().subscribe onNext: { - if (it.size() == 0) exit 1, "No FASTQ files found in --sample directory '${params.sample}'" -} -tsvFile = params.sample // used in the reports + if (it.size() == 0) exit 1, "No FASTQ files found in --sample directory '${params.sample}'" + } + tsvFile = params.sample // used in the reports +} else if (step == 'annotate') { + println "Annotating ${tsvFile}" } else exit 1, 'No sample were defined, see --help' if (step == 'recalibrate') (patientGenders, bamFiles) = extractGenders(bamFiles) @@ -1558,7 +1561,7 @@ vcfToAnnotate = Channel.create() if (step == 'annotate') { vcfNotToAnnotate = Channel.create() - if (annotateVCF == []) { + if (tsvPath == []) { // Sarek, by default, annotates all available vcfs that it can find in the VariantCalling directory // Excluding vcfs from FreeBayes, and g.vcf from HaplotypeCaller // Basically it's: VariantCalling/*/{HaplotypeCaller,Manta,MuTect2,Strelka}/*.vcf.gz @@ -1580,7 +1583,7 @@ if (step == 'annotate') { } else if (annotateTools == []) { // Annotate user-submitted VCFs // If user-submitted, Sarek assume that the idSample should be assumed automatically - vcfToAnnotate = Channel.fromPath(annotateVCF) + vcfToAnnotate = Channel.fromPath(tsvPath) .map{vcf -> ['userspecified', vcf.minus(vcf.fileName)[-2].toString(), vcf]} } else exit 1, "specify only tools or files to annotate, not both" @@ -1620,8 +1623,6 @@ process RunSnpeff { reducedVCF = reduceVCF(vcf) cache = (params.snpEff_cache && params.annotation_cache) ? "-dataDir \${PWD}/${dataDir}" : "" """ - echo ${task.container} - snpEff -Xmx${task.memory.toGiga()}g \ ${snpeffDb} \ -csvStats ${reducedVCF}_snpEff.csv \ diff --git a/nextflow.config b/nextflow.config index c062fb9173..e6de815088 100644 --- a/nextflow.config +++ b/nextflow.config @@ -9,17 +9,11 @@ params { // Workflow flags - // TODO nf-core: Specify your pipeline's command line flags - reads = "data/*{1,2}.fastq.gz" - singleEnd = false + genome = 'GRCh38' outdir = './results' + publishDirMode = 'symlink' // Boilerplate options - publishDirMode = 'symlink' - snpEff_cache = '' - cadd_version = '' - vep_cache = '' - genome = 'GRCh38' name = false multiqc_config = "$baseDir/assets/multiqc_config.yaml" email = false From 77b98d3a669069e51a3952ae70f34a0621549605 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Tue, 21 May 2019 11:34:53 +0200 Subject: [PATCH 017/854] more docs (#9) * update tests * code polishing * add some docs about QC tools --- .circleci/config.yml | 6 +- .travis.yml | 4 +- Dockerfile | 2 +- Jenkinsfile | 29 +- README.md | 71 +- bin/ascat.R | 2181 +++++++++++++++++++++++++++++++ bin/build_reference.sh | 13 +- bin/download_docker.sh | 13 +- bin/run_tests.sh | 29 +- bin/scrape_software_versions.py | 2 +- containers/snpeff/Dockerfile | 2 +- containers/vep/Dockerfile | 2 +- docs/annotation.md | 72 + docs/containers.md | 80 ++ docs/input.md | 115 ++ docs/output.md | 217 ++- docs/reference.md | 11 +- docs/usage.md | 210 ++- environment.yml | 2 +- main.nf | 977 ++++++++------ nextflow.config | 4 +- 21 files changed, 3451 insertions(+), 591 deletions(-) create mode 100644 bin/ascat.R create mode 100644 docs/annotation.md create mode 100644 docs/containers.md create mode 100644 docs/input.md diff --git a/.circleci/config.yml b/.circleci/config.yml index 62e2e17cda..c7fa3812d4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -60,7 +60,7 @@ jobs: - setup_remote_docker - run: command: docker build -t nfcore/sarekvep:dev.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} - no_output_timeout: 1.5h + no_output_timeout: 3h - run: command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:dev.${GENOME} @@ -76,7 +76,7 @@ jobs: - setup_remote_docker - run: command: docker build -t nfcore/sarekvep:dev.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} - no_output_timeout: 1.5h + no_output_timeout: 3h - run: command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:dev.${GENOME} @@ -92,7 +92,7 @@ jobs: - setup_remote_docker - run: command: docker build -t nfcore/sarekvep:dev.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} - no_output_timeout: 30m + no_output_timeout: 1h - run: command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:dev.${GENOME} diff --git a/.travis.yml b/.travis.yml index 051ce4ec8e..f0dc2b8adb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,8 +39,8 @@ install: # Build references if needed before_script: - - "${TRAVIS_BUILD_DIR}/bin/build_reference.sh --test $TEST --build" + - "${TRAVIS_BUILD_DIR}/bin/build_reference.sh --test $TEST --verbose" # Actual tests script: - - "${TRAVIS_BUILD_DIR}/bin/run_tests.sh --test $TEST" + - "${TRAVIS_BUILD_DIR}/bin/run_tests.sh --test $TEST --verbose" diff --git a/Dockerfile b/Dockerfile index 8cb51fe468..eb660ac656 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM nfcore/base +FROM nfcore/base:1.6 LABEL authors="Maxime Garcia" \ description="Docker image containing all requirements for nf-core/sarek pipeline" diff --git a/Jenkinsfile b/Jenkinsfile index b426587cbd..e210d56d0b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -6,46 +6,43 @@ pipeline { } stages { - stage('Setup environment') { + stage('Docker setup') { steps { - sh "./bin/download_docker.sh -t ALL" + sh "./bin/download_docker.sh" } } - stage('Build') { + stage('Build references') { steps { - sh "rm -rf data" - sh "./bin/build_reference.sh --test ALL --build" - sh "rm -rf work/ references/pipeline_info .nextflow*" + sh "rm -rf references/" + sh "./bin/build_reference.sh" } } - stage('Somatic') { + stage('Germline') { steps { - sh "./bin/run_tests.sh --test SOMATIC" - sh "rm -rf work/ .nextflow* results/" + sh "rm -rf data/" + sh "git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data" + sh "./bin/run_tests.sh --test GERMLINE" + sh "rm -rf data/" } } - stage('Germline') { + stage('Somatic') { steps { - sh "./bin/run_tests.sh --test GERMLINE" - sh "rm -rf work/ .nextflow* results/" + sh "./bin/run_tests.sh --test SOMATIC" } } - stage('targeted') { + stage('Targeted') { steps { sh "./bin/run_tests.sh --test TARGETED" - sh "rm -rf work/ .nextflow* results/" } } stage('Annotation') { steps { sh "./bin/run_tests.sh --test ANNOTATEALL" - sh "rm -rf work/ .nextflow* results/" } } stage('Multiple') { steps { sh "./bin/run_tests.sh --test MULTIPLE" - sh "rm -rf work/ .nextflow* results/" } } } diff --git a/README.md b/README.md index 00749a51c7..4dcdff4454 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ [![Travis build status][travis-badge]](https://travis-ci.com/nf-core/sarek/) [![CircleCi build status][circleci-badge]](https://circleci.com/gh/nf-core/sarek/) -[![Install with bioconda][bioconda-badge]](http://bioconda.github.io/) +[![Install with bioconda][bioconda-badge]](https://bioconda.github.io/) [![Docker Container available][docker-sarek-badge]](https://hub.docker.com/r/nfcore/sarek/) [![Install with Singularity][singularity-badge]](https://www.sylabs.io/docs/) @@ -26,8 +26,8 @@ Sarek is a workflow designed to run analyses on whole genome or targeted sequenc It's built using [Nextflow](https://www.nextflow.io), a domain specific language for workflow building, across multiple compute infrastructures in a very portable manner. -Software dependencies are handled using [Docker](https://www.docker.com) or [Singularity](https://www.sylabs.io/singularity/) - container technologies that provide excellent reproducibility and ease of use. -Thus making installation trivial and results highly reproducible +Software dependencies are handled using [Conda](https://conda.io/), [Docker](https://www.docker.com) or [Singularity](https://www.sylabs.io/singularity/) - environment/container technologies that provide excellent reproducibility and ease of use. +Thus making installation trivial and results highly reproducible. It is listed on the [Elixir - Tools and Data Services Registry](https://bio.tools/Sarek), [Dockstore](https://dockstore.org/workflows/github.com/SciLifeLab/Sarek/) and [omicX - Bioinformatics tools](https://omictools.com/sarek-tool). @@ -39,73 +39,22 @@ The nf-core/sarek pipeline comes with documentation about the pipeline, found in * [Local installation](https://nf-co.re/usage/local_installation) * [Adding your own system config](https://nf-co.re/usage/adding_own_config) * [Reference genomes](https://nf-co.re/usage/reference_genomes) + * [Extra documentation on reference](docs/reference.md) 3. [Running the pipeline](docs/usage.md) - * [Tests documentation](docs/TESTS.md) - * [Configuration and profiles documentation](docs/CONFIG.md) + * [Input files documentation](docs/input.md) + * [Extra documentation on variant calling](docs/variantcalling.md) + * [Documentation about containers](docs/containers.md) + * [Extra documentation for targeted sequencing](docs/targetseq.md) + * [Intervals documentation](docs/INTERVALS.md) - * [Running the pipeline](docs/USAGE.md) - * [Running the pipeline using Conda](docs/CONDA.md) * [Command line parameters](docs/PARAMETERS.md) * [Examples](docs/USE_CASES.md) - * [Input files documentation](docs/INPUT.md) * [Processes documentation](docs/PROCESS.md) - * [Documentation about containers](docs/CONTAINERS.md) 4. [Output and how to interpret the results](docs/output.md) * [Complementary information about ASCAT](docs/ASCAT.md) - * [Complementary information about annotations](docs/ANNOTATION.md) - * [Output documentation structure](docs/OUTPUT.md) + * [Extra documentation on annotation](docs/annotation.md) 5. [Troubleshooting](https://nf-co.re/usage/troubleshooting) -## Workflow steps - -Sarek is built with several workflow scripts. -A wrapper script contained within the repository makes it easy to run the different workflow scripts as a single job. -To test your installation, follow the [tests documentation.](docs/TESTS.md) - -Raw FastQ files or BAM files (unmapped, aligned or recalibrated) can be used as inputs. -You can choose which variant callers to use, plus the pipeline is capable of accommodating additional variant calling software or CNV callers if required. - -The worflow steps and tools used are as follows: - -1. **Preprocessing** _(based on [GATK best practices](https://software.broadinstitute.org/gatk/best-practices/))_ - * Map reads to Reference - * [BWA](http://bio-bwa.sourceforge.net/) - * Mark Duplicates - * [GATK MarkDuplicates](https://github.com/broadinstitute/gatk) - * Base (Quality Score) Recalibration - * [GATK BaseRecalibrator](https://github.com/broadinstitute/gatk) - * [GATK ApplyBQSR](https://github.com/broadinstitute/gatk) -2. **Germline variant calling** - * SNVs and small indels - * [GATK HaplotypeCaller](https://github.com/broadinstitute/gatk) - * [Strelka2](https://github.com/Illumina/strelka) - * Structural variants - * [Manta](https://github.com/Illumina/manta) -3. **Somatic variant calling** - * SNVs and small indels - * [MuTect2](https://github.com/broadinstitute/gatk) - * [Freebayes](https://github.com/ekg/freebayes) - * [Strelka2](https://github.com/Illumina/strelka) - * Structural variants - * [Manta](https://github.com/Illumina/manta) - * Sample heterogeneity, ploidy and CNVs - * [ASCAT](https://github.com/Crick-CancerGenomics/ascat) -4. **Annotation** - * Variant annotation - * [SnpEff](http://snpeff.sourceforge.net/) - * [VEP (Variant Effect Predictor)](https://www.ensembl.org/info/docs/tools/vep/index.html) -5. **QC and Reporting** - * QC - * [FastQC](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/) - * [Qualimap bamqc](http://qualimap.bioinfo.cipf.es/doc_html/command_line.html) - * [samtools stats](https://www.htslib.org/doc/samtools.html) - * [GATK MarkDuplicates](https://github.com/broadinstitute/gatk) - * [bcftools stats](http://www.htslib.org/doc/bcftools.html) - * [VCFtools](https://vcftools.github.io/index.html) - * [SnpEff](http://snpeff.sourceforge.net/) - * Reporting - * [MultiQC](http://multiqc.info) - ## Credits Sarek was developed at the [National Genomics Infastructure][ngi-link] and [National Bioinformatics Infastructure Sweden][nbis-link] which are both platforms at [SciLifeLab][scilifelab-link], with the support of [The Swedish Childhood Tumor Biobank (Barntumörbanken)][btb-link]. diff --git a/bin/ascat.R b/bin/ascat.R new file mode 100644 index 0000000000..85ad6d9042 --- /dev/null +++ b/bin/ascat.R @@ -0,0 +1,2181 @@ +##########LICENCE########## +# Copyright (c) 2014 Genome Research Ltd. +# +# Author: Peter Van Loo +# +# This file is part of AscatNGS. +# +# AscatNGS is free software: you can redistribute it and/or modify it under +# the terms of the GNU Affero General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +##########LICENCE########## + +# ASCAT version 2.3, 15/07/2014 +# author: Peter Van Loo +# PCF and ASPCF: Gro Nilsen +# GC correction: Jiqiu Cheng + +# function to read in SNP array data +# input: filenames of tumor LogR, tumor BAF, germline LogR and germline BAF data +# germline data files can be NULL - in that case these are not read in +# output: a data structure containing: +# 1. Tumor_LogR data matrix +# 2. Tumor_BAF data matrix +# 3. Tumor_LogR_segmented: placeholder, NULL +# 4. Tumor_BAF_segmented: placeholder, NULL +# 5. Germline_LogR data matrix +# 6. Germline_BAF data matrix +# 7. SNPpos: position of all SNPs +# 8. ch: a list containing vectors with the indices for each chromosome (e.g. Tumor_LogR[ch[[13]],] will output the Tumor_LogR data of chromosome 13 +# 9. chr: a list containing vectors with the indices for each distinct part that can be segmented separately (e.g. chromosome arm, stretch of DNA between gaps in the array design) +# 10. gender: a vector of gender for each cases ("XX" or "XY"). Default = NULL: all female ("XX") +ascat.loadData = function(Tumor_LogR_file, Tumor_BAF_file, Germline_LogR_file = NULL, Germline_BAF_file = NULL, chrs = c(1:22,"X","Y"), gender = NULL, sexchromosomes = c("X","Y")) { + + # read in SNP array data files + print.noquote("Reading Tumor LogR data...") + Tumor_LogR <- read.table(Tumor_LogR_file, header=T, row.names=1, comment.char="", sep = "\t", check.names=F) + print.noquote("Reading Tumor BAF data...") + Tumor_BAF <- read.table(Tumor_BAF_file, header=T, row.names=1, comment.char="", sep = "\t", check.names=F) + + #infinite values are a problem - change those + Tumor_LogR[Tumor_LogR==-Inf]=NA + Tumor_LogR[Tumor_LogR==Inf]=NA + + Germline_LogR = NULL + Germline_BAF = NULL + if(!is.null(Germline_LogR_file)) { + print.noquote("Reading Germline LogR data...") + Germline_LogR <- read.table(Germline_LogR_file, header=T, row.names=1, comment.char="", sep = "\t", check.names=F) + print.noquote("Reading Germline BAF data...") + Germline_BAF <- read.table(Germline_BAF_file, header=T, row.names=1, comment.char="", sep = "\t", check.names=F) + + #infinite values are a problem - change those + Germline_LogR[Germline_LogR==-Inf]=NA + Germline_LogR[Germline_LogR==Inf]=NA + } + + # make SNPpos vector that contains genomic position for all SNPs and remove all data not on chromosome 1-22,X,Y (or whatever is given in the input value of chrs) + print.noquote("Registering SNP locations...") + SNPpos <- Tumor_LogR[,1:2] + SNPpos = SNPpos[SNPpos[,1]%in%chrs,] + + # if some chromosomes have no data, just remove them + chrs = intersect(chrs,unique(SNPpos[,1])) + + Tumor_LogR = Tumor_LogR[rownames(SNPpos),c(-1,-2),drop=F] + Tumor_BAF = Tumor_BAF[rownames(SNPpos),c(-1,-2),drop=F] + # make sure it is all converted to numerical values + for (cc in 1:dim(Tumor_LogR)[2]) { + Tumor_LogR[,cc]=as.numeric(as.vector(Tumor_LogR[,cc])) + Tumor_BAF[,cc]=as.numeric(as.vector(Tumor_BAF[,cc])) + } + + if(!is.null(Germline_LogR_file)) { + Germline_LogR = Germline_LogR[rownames(SNPpos),c(-1,-2),drop=F] + Germline_BAF = Germline_BAF[rownames(SNPpos),c(-1,-2),drop=F] + for (cc in 1:dim(Germline_LogR)[2]) { + Germline_LogR[,cc]=as.numeric(as.vector(Germline_LogR[,cc])) + Germline_BAF[,cc]=as.numeric(as.vector(Germline_BAF[,cc])) + } + } + + # sort all data by genomic position + last = 0; + ch = list(); + SNPorder = vector(length=dim(SNPpos)[1]) + for (i in 1:length(chrs)) { + chrke = SNPpos[SNPpos[,1]==chrs[i],] + chrpos = chrke[,2] + names(chrpos) = rownames(chrke) + chrpos = sort(chrpos) + ch[[i]] = (last+1):(last+length(chrpos)) + SNPorder[ch[[i]]] = names(chrpos) + last = last+length(chrpos) + } + SNPpos = SNPpos[SNPorder,] + Tumor_LogR=Tumor_LogR[SNPorder,,drop=F] + Tumor_BAF=Tumor_BAF[SNPorder,,drop=F] + + if(!is.null(Germline_LogR_file)) { + Germline_LogR = Germline_LogR[SNPorder,,drop=F] + Germline_BAF = Germline_BAF[SNPorder,,drop=F] + } + + # split the genome into distinct parts to be used for segmentation (e.g. chromosome arms, parts of genome between gaps in array design) + print.noquote("Splitting genome in distinct chunks...") + chr = split_genome(SNPpos) + + if (is.null(gender)) { + gender = rep("XX",dim(Tumor_LogR)[2]) + } + return(list(Tumor_LogR = Tumor_LogR, Tumor_BAF = Tumor_BAF, + Tumor_LogR_segmented = NULL, Tumor_BAF_segmented = NULL, + Germline_LogR = Germline_LogR, Germline_BAF = Germline_BAF, + SNPpos = SNPpos, ch = ch, chr = chr, chrs = chrs, + samples = colnames(Tumor_LogR), gender = gender, + sexchromosomes = sexchromosomes, + failedarrays = NULL)) +} + + + + +# plots SNP array data +# input: an ASCAT object (e.g. from ASCAT.loaddata and plots the SNP array data +ascat.plotRawData = function(ASCATobj) { + print.noquote("Plotting tumor data") + for (i in 1:dim(ASCATobj$Tumor_LogR)[2]) { + png(filename = paste(ASCATobj$samples[i],".tumour.png",sep=""), width = 2000, height = 1000, res = 200) + par(mar = c(0.5,5,5,0.5), mfrow = c(2,1), cex = 0.4, cex.main=3, cex.axis = 2, pch = ifelse(dim(ASCATobj$Tumor_LogR)[1]>100000,".",20)) + plot(c(1,dim(ASCATobj$Tumor_LogR)[1]), c(-1,1), type = "n", xaxt = "n", main = paste(ASCATobj$samples[i], ", tumor data, LogR", sep = ""), xlab = "", ylab = "") + points(ASCATobj$Tumor_LogR[,i],col="red") + abline(v=0.5,lty=1,col="lightgrey") + chrk_tot_len = 0 + for (j in 1:length(ASCATobj$ch)) { + chrk = ASCATobj$ch[[j]]; + chrk_tot_len_prev = chrk_tot_len + chrk_tot_len = chrk_tot_len + length(chrk) + vpos = chrk_tot_len; + tpos = (chrk_tot_len+chrk_tot_len_prev)/2; + text(tpos,1,ASCATobj$chrs[j], pos = 1, cex = 2) + abline(v=vpos+0.5,lty=1,col="lightgrey") + } + plot(c(1,dim(ASCATobj$Tumor_BAF)[1]), c(0,1), type = "n", xaxt = "n", main = paste(ASCATobj$samples[i], ", tumor data, BAF", sep = ""), xlab = "", ylab = "") + points(ASCATobj$Tumor_BAF[,i],col="red") + abline(v=0.5,lty=1,col="lightgrey") + chrk_tot_len = 0 + for (j in 1:length(ASCATobj$ch)) { + chrk = ASCATobj$ch[[j]]; + chrk_tot_len_prev = chrk_tot_len + chrk_tot_len = chrk_tot_len + length(chrk) + vpos = chrk_tot_len; + tpos = (chrk_tot_len+chrk_tot_len_prev)/2; + text(tpos,1,ASCATobj$chrs[j], pos = 1, cex = 2) + abline(v=vpos+0.5,lty=1,col="lightgrey") + } + dev.off() + } + + if(!is.null(ASCATobj$Germline_LogR)) { + print.noquote("Plotting germline data") + for (i in 1:dim(ASCATobj$Germline_LogR)[2]) { + png(filename = paste(ASCATobj$samples[i],".germline.png",sep=""), width = 2000, height = 1000, res = 200) + par(mar = c(0.5,5,5,0.5), mfrow = c(2,1), cex = 0.4, cex.main=3, cex.axis = 2, pch = ifelse(dim(ASCATobj$Tumor_LogR)[1]>100000,".",20)) + plot(c(1,dim(ASCATobj$Germline_LogR)[1]), c(-1,1), type = "n", xaxt = "n", main = paste(ASCATobj$samples[i], ", germline data, LogR", sep = ""), xlab = "", ylab = "") + points(ASCATobj$Germline_LogR[,i],col="red") + abline(v=0.5,lty=1,col="lightgrey") + chrk_tot_len = 0 + for (j in 1:length(ASCATobj$ch)) { + chrk = ASCATobj$ch[[j]]; + chrk_tot_len_prev = chrk_tot_len + chrk_tot_len = chrk_tot_len + length(chrk) + vpos = chrk_tot_len; + tpos = (chrk_tot_len+chrk_tot_len_prev)/2; + text(tpos,1,ASCATobj$chrs[j], pos = 1, cex = 2) + abline(v=vpos+0.5,lty=1,col="lightgrey") + } + plot(c(1,dim(ASCATobj$Germline_BAF)[1]), c(0,1), type = "n", xaxt = "n", main = paste(ASCATobj$samples[i], ", germline data, BAF", sep = ""), xlab = "", ylab = "") + points(ASCATobj$Germline_BAF[,i],col="red") + abline(v=0.5,lty=1,col="lightgrey") + chrk_tot_len = 0 + for (j in 1:length(ASCATobj$ch)) { + chrk = ASCATobj$ch[[j]]; + chrk_tot_len_prev = chrk_tot_len + chrk_tot_len = chrk_tot_len + length(chrk) + vpos = chrk_tot_len; + tpos = (chrk_tot_len+chrk_tot_len_prev)/2; + text(tpos,1,ASCATobj$chrs[j], pos = 1, cex = 2) + abline(v=vpos+0.5,lty=1,col="lightgrey") + } + dev.off() + } + } +} + + +##################################################################################### +# +# This version of the GCcorrect funtion was debugged by Malin Larsson in July 2016 +# +##################################################################################### + +# note that probes not present in the GCcontentfile will be lost from the results +ascat.GCcorrect = function(ASCATobj, GCcontentfile = NULL) { + if(is.null(GCcontentfile)) { + print.noquote("Error: no GC content file given!") + } + else { + GC_newlist<-read.table(file=GCcontentfile,header=TRUE, row.names=1, as.is=TRUE) + #colnames(GC_newlist)[c(1,2)] = c("Chr","Position") + GC_newlist$Chr<-as.character(GC_newlist$Chr) + GC_newlist$Position<-as.numeric(as.character(GC_newlist$Position)) + + ovl = intersect(row.names(ASCATobj$Tumor_LogR),row.names(GC_newlist)) + + GC_newlist<-GC_newlist[ovl,] + + SNPpos = ASCATobj$SNPpos[ovl,] + Tumor_LogR = ASCATobj$Tumor_LogR[ovl,,drop=F] + Tumor_BAF = ASCATobj$Tumor_BAF[ovl,,drop=F] + + Germline_LogR = NULL + Germline_BAF = NULL + if(!is.null(ASCATobj$Germline_LogR)) { + Germline_LogR = ASCATobj$Germline_LogR[ovl,,drop=F] + Germline_BAF = ASCATobj$Germline_BAF[ovl,,drop=F] + } + + for (s in 1:length(ASCATobj$samples)) { + print.noquote(paste("Sample ", ASCATobj$samples[s], " (",s,"/",length(ASCATobj$samples),")",sep="")) + Tumordata = Tumor_LogR[,s] + names(Tumordata) = rownames(Tumor_LogR) + + # Calculate weighted correlation + length_tot<-NULL + corr_tot<-NULL + for(chrindex in unique(SNPpos[,1])) { + GC_newlist_chr<-GC_newlist[GC_newlist$Chr==chrindex,] + td_chr<-Tumordata[GC_newlist$Chr==chrindex] + + flag_nona<-(complete.cases(td_chr) & complete.cases(GC_newlist_chr)) + corr<-cor(GC_newlist_chr[flag_nona,3:ncol(GC_newlist_chr)],td_chr[flag_nona]) + corr_tot<-cbind(corr_tot,corr) + length_tot<-c(length_tot,length(td_chr)) + } + corr<-apply(corr_tot,1,function(x) sum(abs(x*length_tot))/sum(length_tot)) + + #old code: + #index_1M<-c(which(names(corr)=="X1M"),which(names(corr)=="X1Mb")) + #maxGCcol_short<-which(corr[1:(index_1M-1)]==max(corr[1:(index_1M-1)])) + #maxGCcol_long<-which(corr[index_1M:length(corr)]==max(corr[index_1M:length(corr)])) + #maxGCcol_long<-(maxGCcol_long+(index_1M-1)) + + #Updated by Malin: + index_1000bp<-which(names(corr)=="X1000bp") + maxGCcol_short<-which(corr[1:(index_1000bp-1)]==max(corr[1:(index_1000bp-1)])) + maxGCcol_long<-which(corr[index_1000bp:length(corr)]==max(corr[index_1000bp:length(corr)])) + maxGCcol_long<-(maxGCcol_long+(index_1000bp-1)) + + cat("weighted correlation: ",paste(names(corr),format(corr,digits=2), ";"),"\n") + cat("Short window size: ",names(GC_newlist)[maxGCcol_short+2],"\n") + cat("Long window size: ",names(GC_newlist)[maxGCcol_long+2],"\n") + + # Multiple regression + flag_NA<-(is.na(Tumordata))|(is.na(GC_newlist[,2+maxGCcol_short]))|(is.na(GC_newlist[,2+maxGCcol_long])) + td_select<-Tumordata[!flag_NA] + GC_newlist_select <- GC_newlist[!flag_NA,] + x1<-GC_newlist_select[,2+maxGCcol_short] + x2<-GC_newlist_select[,2+maxGCcol_long] + x3<-(x1)^2 + x4<-(x2)^2 + model<-lm(td_select~x1+x2+x3+x4,y=TRUE) + + GCcorrected<-Tumordata + GCcorrected[]<-NA + GCcorrected[!flag_NA] <- model$residuals + + Tumor_LogR[,s] = GCcorrected + } + + # add some plotting code for each sample while it is generated!!!! + + return(list(Tumor_LogR = Tumor_LogR, Tumor_BAF = Tumor_BAF, + Tumor_LogR_segmented = NULL, Tumor_BAF_segmented = NULL, + Germline_LogR = Germline_LogR, Germline_BAF = Germline_BAF, + SNPpos = SNPpos, ch = ASCATobj$ch, chr = ASCATobj$chr, chrs = ASCATobj$chrs, + samples = colnames(Tumor_LogR), gender = ASCATobj$gender, + sexchromosomes = ASCATobj$sexchromosomes)) + } +} + + + + +# run ASPCF segmentation +# input: (i) an ASCAT object from e.g. ASCAT.loaddata; +# (ii) selectsamples: a vector containing the sample(number)s to PCF otherwise +# (iii) germline genotypes (NULL if germline data is available) +# (iv) penalty: penalty of introducing an additional ASPCF breakpoint (expert parameter, don't adapt unless you know what you're doing) +# output: a data structure containing: +# 1. Tumor_LogR data matrix +# 2. Tumor_BAF data matrix +# 3. Tumor_LogR_segmented: matrix of LogR segmented values +# 4. Tumor_BAF_segmented: list of BAF segmented values; each element in the list is a matrix containing the segmented values for one sample (only for probes that are germline homozygous) +# 5. Germline_LogR data matrix +# 6. Germline_BAF data matrix +# 7. SNPpos: position of all SNPs +# 8. ch: a list containing vectors with the indices for each chromosome (e.g. Tumor_LogR[ch[[13]],] will output the Tumor_LogR data of chromosome 13 +# 9. chr: a list containing vectors with the indices for each distinct part that can be segmented separately (e.g. chromosome arm, stretch of DNA between gaps in the array design) +# note: this function can be easily parallelized by controlling the selectsamples parameter +# it saves the results in LogR_PCFed[sample]_[segment].txt and BAF_PCFed[sample]_[segment].txt +# if these files exist, the results are read from the files +# hence, after parallelization, copy all the files into the current directory, and run this function to read in the results +ascat.aspcf = function(ASCATobj, selectsamples = 1:length(ASCATobj$samples), ascat.gg = NULL, penalty = 25) { + #first, set germline genotypes + gg = NULL + if(!is.null(ascat.gg)) { + gg = ascat.gg$germlinegenotypes + } + else { + gg = ASCATobj$Germline_BAF < 0.3 | ASCATobj$Germline_BAF > 0.7 + } + # calculate germline homozygous stretches for later resegmentation + ghs = predictGermlineHomozygousStretches(ASCATobj$chr, gg) + + segmentlengths = unique(c(penalty,25,50,100,200,400,800)) + segmentlengths = segmentlengths[segmentlengths>=penalty] + + Tumor_LogR_segmented = matrix(nrow = dim(ASCATobj$Tumor_LogR)[1], ncol = dim(ASCATobj$Tumor_LogR)[2]) + rownames(Tumor_LogR_segmented) = rownames(ASCATobj$Tumor_LogR) + colnames(Tumor_LogR_segmented) = colnames(ASCATobj$Tumor_LogR) + Tumor_BAF_segmented = list(); + for (sample in selectsamples) { + print.noquote(paste("Sample ", ASCATobj$samples[sample], " (",sample,"/",length(ASCATobj$samples),")",sep="")) + logrfilename = paste(ASCATobj$samples[sample],".LogR.PCFed.txt",sep="") + baffilename = paste(ASCATobj$samples[sample],".BAF.PCFed.txt",sep="") + logRPCFed = numeric(0) + bafPCFed = numeric(0) + if(length(dir(pattern=logrfilename))==0 || length(dir(pattern=baffilename))==0) { + for (segmentlength in segmentlengths) { + logRPCFed = numeric(0) + bafPCFed = numeric(0) + tbsam = ASCATobj$Tumor_BAF[,sample] + names(tbsam) = rownames(ASCATobj$Tumor_BAF) + homosam = gg[,sample] + for (chrke in 1:length(ASCATobj$chr)) { + lr = ASCATobj$Tumor_LogR[ASCATobj$chr[[chrke]],sample] + #winsorize to remove outliers + #this has a problem with NAs + lrwins = vector(mode="numeric",length=length(lr)) + lrwins[is.na(lr)] = NA + lrwins[!is.na(lr)] = madWins(lr[!is.na(lr)],2.5,25)$ywin + baf = tbsam[ASCATobj$chr[[chrke]]] + homo = homosam[ASCATobj$chr[[chrke]]] + Select_het <- !homo & !is.na(homo) & !is.na(baf) & !is.na(lr) + bafsel = baf[Select_het] + # winsorize BAF as well (as a safeguard) + bafselwinsmirrored = madWins(ifelse(bafsel>0.5,bafsel,1-bafsel),2.5,25)$ywin + bafselwins = ifelse(bafsel>0.5,bafselwinsmirrored,1-bafselwinsmirrored) + indices = which(Select_het) + logRaveraged = NULL; + if(length(indices)!=0) { + averageIndices = c(1,(indices[1:(length(indices)-1)]+indices[2:length(indices)])/2,length(lr)+0.01) + startindices = ceiling(averageIndices[1:(length(averageIndices)-1)]) + endindices = floor(averageIndices[2:length(averageIndices)]-0.01) + if(length(indices)==1) { + startindices = 1 + endindices = length(lr) + } + nrIndices = endindices - startindices + 1 + logRaveraged = vector(mode="numeric",length=length(indices)) + for(i in 1:length(indices)) { + if(is.na(endindices[i])) { + endindices[i]=startindices[i] + } + logRaveraged[i]=mean(lrwins[startindices[i]:endindices[i]], na.rm=T) + } + } + # if there are no probes in the segment (after germline homozygous removal), don't do anything, except add a LogR segment + if(length(logRaveraged)>0) { + logRASPCF = NULL + bafASPCF = NULL + if(length(logRaveraged)<6) { + logRASPCF = rep(mean(logRaveraged),length(logRaveraged)) + bafASPCF = rep(mean(bafselwins),length(logRaveraged)) + } + else { + PCFed = fastAspcf(logRaveraged,bafselwins,6,segmentlength) + logRASPCF = PCFed$yhat1 + bafASPCF = PCFed$yhat2 + } + names(bafASPCF)=names(indices) + logRc = numeric(0) + for(probe in 1:length(logRASPCF)) { + if(probe == 1) { + logRc = rep(logRASPCF[probe],indices[probe]) + } + # if probe is 1, set the beginning, and let the loop go: + if(probe == length(logRASPCF)) { + logRc = c(logRc,rep(logRASPCF[probe],length(lr)-indices[probe])) + } + else if(logRASPCF[probe]==logRASPCF[probe+1]) { + logRc = c(logRc, rep(logRASPCF[probe],indices[probe+1]-indices[probe])) + } + else { + #find best breakpoint + d = numeric(0) + totall = indices[probe+1]-indices[probe] + for (bp in 0:(totall-1)) { + dis = sum(abs(lr[(1:bp)+indices[probe]]-logRASPCF[probe]), na.rm=T) + if(bp!=totall) { + dis = sum(dis, sum(abs(lr[((bp+1):totall)+indices[probe]]-logRASPCF[probe+1]), na.rm=T), na.rm=T) + } + d = c(d,dis) + } + breakpoint = which.min(d)-1 + logRc = c(logRc,rep(logRASPCF[probe],breakpoint),rep(logRASPCF[probe+1],totall-breakpoint)) + } + } + #2nd step: adapt levels! + logRd = numeric(0) + seg = make_seg_lr(logRc) + startprobe = 1 + endprobe = 0 + for (i in 1:length(seg)) { + endprobe = endprobe+seg[i] + level = mean(lr[startprobe:endprobe], na.rm=T) + logRd = c(logRd, rep(level,seg[i])) + startprobe = startprobe + seg[i] + } + logRPCFed = c(logRPCFed,logRd) + bafPCFed = c(bafPCFed,bafASPCF) + } + # add a LogR segment + else { + level = mean(lr,na.rm=T) + reps = length(lr) + logRPCFed = c(logRPCFed,rep(level,reps)) + } + # correct wrong segments in germline homozygous stretches: + homsegs = ghs[[sample]][ghs[[sample]][,1]==chrke,] + startchr = min(ASCATobj$chr[[chrke]]) + endchr = max(ASCATobj$chr[[chrke]]) + # to solve an annoying error when homsegs has length 1: + if(length(homsegs)==3) { + homsegs=t(as.matrix(homsegs)) + } + if(!is.null(homsegs)&&!is.na(homsegs)&&dim(homsegs)[1]!=0) { + for (i in 1:dim(homsegs)[1]) { + # note that only the germline homozygous segment is resegmented, plus a bit extra (but this is NOT replaced) + startpos = max(homsegs[i,2],startchr) + endpos = min(homsegs[i,3],endchr) + # PCF over a larger fragment + startpos2 = max(homsegs[i,2]-100,startchr) + endpos2 = min(homsegs[i,3]+100,endchr) + # take into account a little extra (difference between startpos2 and startpos3 is not changed) + startpos3 = max(homsegs[i,2]-5,startchr) + endpos3 = min(homsegs[i,3]+5,endchr) + # note that the parameters are arbitrary, but <100 seems to work on the ERBB2 example! + # segmentlength is lower here, as in the full data, noise on LogR is higher! + # do this on Winsorized data too! + towins = ASCATobj$Tumor_LogR[startpos2:endpos2,sample] + winsed = madWins(towins[!is.na(towins)],2.5,25)$ywin + pcfed = vector(mode="numeric",length=length(towins)) + pcfed[!is.na(towins)] = exactPcf(winsed,6,floor(segmentlength/4)) + pcfed2 = pcfed[(startpos3-startpos2+1):(endpos3-startpos2+1)] + dif = abs(pcfed2-logRPCFed[startpos3:endpos3]) + #0.3 is hardcoded here, in order not to have too many segments! + #only replace if enough probes differ (in order not to get singular probes with different breakpoints) + if(!is.na(dif)&&sum(dif>0.3)>5) { + #replace a bit more to make sure no 'lone' probes are left (startpos3 instead of startpos) + logRPCFed[startpos3:endpos3]=ifelse(dif>0.3,pcfed2,logRPCFed[startpos3:endpos3]) + } + } + } + } + #fill in NAs (otherwise they cause problems): + #some NA probes are filled in with zero, replace those too: + nakes = c(which(is.na(logRPCFed)),which(logRPCFed==0)) + nonnakes = which(!is.na(logRPCFed)&!(logRPCFed==0)) + if(length(nakes)>0) { + for (nake in 1:length(nakes)) { + pna = nakes[nake] + closestnonna = which.min(abs(nonnakes-pna)) + logRPCFed[pna] = logRPCFed[closestnonna] + } + } + #adapt levels again + seg = make_seg_lr(logRPCFed) + logRPCFed = numeric(0) + startprobe = 1 + endprobe = 0 + prevlevel = 0 + for (i in 1:length(seg)) { + endprobe = endprobe+seg[i] + level = mean(ASCATobj$Tumor_LogR[startprobe:endprobe,sample], na.rm=T) + #making sure no NA's get filled in... + if(is.nan(level)) { + level=prevlevel + } + else { + prevlevel=level + } + logRPCFed = c(logRPCFed, rep(level,seg[i])) + startprobe = startprobe + seg[i] + } + #put in names and write results to files + names(logRPCFed) = rownames(ASCATobj$Tumor_LogR) + + # if less than 800 segments: this segmentlength is ok, otherwise, rerun with higher segmentlength + if(length(unique(logRPCFed))<800) { + break + } + } + + write.table(logRPCFed,logrfilename,sep="\t",col.names=F) + write.table(bafPCFed,baffilename,sep="\t",col.names=F) + bafPCFed = as.matrix(bafPCFed) + } + else { + logRPCFed = read.table(logrfilename, sep="\t", header=F, row.names=1)[,1] + bafPCFed = read.table(baffilename, sep="\t", header=F, row.names=1) + } + Tumor_LogR_segmented[,sample] = logRPCFed + Tumor_BAF_segmented[[sample]] = 1-bafPCFed + } + + ASCATobj = list(Tumor_LogR = ASCATobj$Tumor_LogR, + Tumor_BAF = ASCATobj$Tumor_BAF, + Tumor_LogR_segmented = Tumor_LogR_segmented, + Tumor_BAF_segmented = Tumor_BAF_segmented, + Germline_LogR = ASCATobj$Germline_LogR, + Germline_BAF = ASCATobj$Germline_BAF, + SNPpos = ASCATobj$SNPpos, + ch = ASCATobj$ch, + chr = ASCATobj$chr, + chrs = ASCATobj$chrs, + samples = colnames(ASCATobj$Tumor_LogR), gender = ASCATobj$gender, + sexchromosomes = ASCATobj$sexchromosomes, failedarrays = ascat.gg$failedarrays) + return(ASCATobj) +} + + + +# plots SNP array data +# input: an ASCAT object (e.g. from ASCAT.ASPCF) and plots the SNP array data before and after segmentation +ascat.plotSegmentedData = function(ASCATobj) { + for (arraynr in 1:dim(ASCATobj$Tumor_LogR)[2]) { + Select_nonNAs = rownames(ASCATobj$Tumor_BAF_segmented[[arraynr]]) + AllIDs = 1:dim(ASCATobj$Tumor_LogR)[1] + names(AllIDs) = rownames(ASCATobj$Tumor_LogR) + HetIDs = AllIDs[Select_nonNAs] + png(filename = paste(ASCATobj$samples[arraynr],".ASPCF.png",sep=""), width = 2000, height = 1000, res = 200) + par(mar = c(0.5,5,5,0.5), mfrow = c(2,1), cex = 0.4, cex.main=3, cex.axis = 2) + r = ASCATobj$Tumor_LogR_segmented[rownames(ASCATobj$Tumor_BAF_segmented[[arraynr]]),arraynr] + beta = ASCATobj$Tumor_BAF_segmented[[arraynr]][,] + plot(c(1,length(r)), c(-1,1), type = "n", xaxt = "n", main = paste(colnames(ASCATobj$Tumor_BAF)[arraynr],", LogR",sep=""), xlab = "", ylab = "") + points(ASCATobj$Tumor_LogR[rownames(ASCATobj$Tumor_BAF_segmented[[arraynr]]),arraynr], col = "red", pch=ifelse(dim(ASCATobj$Tumor_LogR)[1]>100000,".",20)) + points(r,col="green") + abline(v=0.5,lty=1,col="lightgrey") + chrk_tot_len = 0 + for (j in 1:length(ASCATobj$ch)) { + chrk = intersect(ASCATobj$ch[[j]],HetIDs); + chrk_tot_len_prev = chrk_tot_len + chrk_tot_len = chrk_tot_len + length(chrk) + vpos = chrk_tot_len; + tpos = (chrk_tot_len+chrk_tot_len_prev)/2; + text(tpos,1,ASCATobj$chrs[j], pos = 1, cex = 2) + abline(v=vpos+0.5,lty=1,col="lightgrey") + } + plot(c(1,length(beta)), c(0,1), type = "n", xaxt = "n", main = paste(colnames(ASCATobj$Tumor_BAF)[arraynr],", BAF",sep=""), xlab = "", ylab = "") + points(ASCATobj$Tumor_BAF[rownames(ASCATobj$Tumor_BAF_segmented[[arraynr]]),arraynr], col = "red", pch=ifelse(dim(ASCATobj$Tumor_LogR)[1]>100000,".",20)) + points(beta, col = "green") + points(1-beta, col = "green") + abline(v=0.5,lty=1,col="lightgrey") + chrk_tot_len = 0 + for (j in 1:length(ASCATobj$ch)) { + chrk = intersect(ASCATobj$ch[[j]],HetIDs); + chrk_tot_len_prev = chrk_tot_len + chrk_tot_len = chrk_tot_len + length(chrk) + vpos = chrk_tot_len; + tpos = (chrk_tot_len+chrk_tot_len_prev)/2; + text(tpos,1,ASCATobj$chrs[j], pos = 1, cex = 2) + abline(v=vpos+0.5,lty=1,col="lightgrey") + } + dev.off() + } +} + + +# the ASCAT main function, calculating the allele-specific copy numbers +# input: (i) an ASCAT object from ascat.aspcf. +# (ii) gamma: technology parameter, compaction of Log R profiles (expected decrease in case of deletion in diploid sample, 100 % aberrant cells; 1 in ideal case, 0.55 of Illumina 109K arrays) +# (iii) rho_manual: optional argument to override ASCAT optimization and supply rho and psi parameters (not recommended) +# (iv) psi_manual: optional argument to override ASCAT optimization and supply rho and psi parameters (not recommended) +# output: an ASCAT output object, containing: +# 1. nA: copy number of the A allele +# 2. nB: copy number of the B allele +# 3. aberrantcellfraction: the aberrant cell fraction of all arrays +# 4. ploidy: the ploidy of all arrays +# 5. psi: ploidy parameter, an estimate of the tumour's ploidy for all arrays +# 6. goodnessOfFit: the goodness of fit for each copy number solution +# 7. failedarrays: arrays on which ASCAT analysis failed +# 8. nonaberrantarrays = arrays on which ASCAT analysis indicates that they so virtually no aberrations +# 9. segments: an array containing the copy number segments of each sample (not including failed arrays) +# 10. segments_raw: an array containing the copy number segments of each sample without any rounding applied +# note: for copy number only probes, nA contains the copy number value and nB = 0. +ascat.runAscat = function(ASCATobj, gamma = 0.55, rho_manual = NA, psi_manual = NA) { + goodarrays=NULL + res = vector("list",dim(ASCATobj$Tumor_LogR)[2]) + for (arraynr in 1:dim(ASCATobj$Tumor_LogR)[2]) { + print.noquote(paste("Sample ", ASCATobj$samples[arraynr], " (",arraynr,"/",length(ASCATobj$samples),")",sep="")) + lrr=ASCATobj$Tumor_LogR[,arraynr] + names(lrr)=rownames(ASCATobj$Tumor_LogR) + baf=ASCATobj$Tumor_BAF[,arraynr] + names(baf)=rownames(ASCATobj$Tumor_BAF) + lrrsegm = ASCATobj$Tumor_LogR_segmented[,arraynr] + names(lrrsegm) = rownames(ASCATobj$Tumor_LogR_segmented) + bafsegm = ASCATobj$Tumor_BAF_segmented[[arraynr]][,] + names(bafsegm) = rownames(ASCATobj$Tumor_BAF_segmented[[arraynr]]) + failedqualitycheck = F + if(ASCATobj$samples[arraynr]%in%ASCATobj$failedarrays) { + failedqualitycheck = T + } + if(is.na(rho_manual)) { + res[[arraynr]] = runASCAT(lrr,baf,lrrsegm,bafsegm,ASCATobj$gender[arraynr],ASCATobj$SNPpos,ASCATobj$ch,ASCATobj$chrs,ASCATobj$sexchromosomes, failedqualitycheck, + paste(ASCATobj$samples[arraynr],".sunrise.png",sep=""),paste(ASCATobj$samples[arraynr],".ASCATprofile.png",sep=""), + paste(ASCATobj$samples[arraynr],".rawprofile.png",sep=""),paste(ASCATobj$samples[arraynr],".aberrationreliability.png",sep=""), + gamma) + } else { + res[[arraynr]] = runASCAT(lrr,baf,lrrsegm,bafsegm,ASCATobj$gender[arraynr],ASCATobj$SNPpos,ASCATobj$ch,ASCATobj$chrs,ASCATobj$sexchromosomes, failedqualitycheck, + paste(ASCATobj$samples[arraynr],".sunrise.png",sep=""),paste(ASCATobj$samples[arraynr],".ASCATprofile.png",sep=""), + paste(ASCATobj$samples[arraynr],".rawprofile.png",sep=""),paste(ASCATobj$samples[arraynr],".aberrationreliability.png",sep=""), + gamma,rho_manual[arraynr],psi_manual[arraynr]) + } + if(!is.na(res[[arraynr]]$rho)) { + goodarrays[length(goodarrays)+1] = arraynr + } + } + + if(length(goodarrays)>0) { + n1 = matrix(nrow = dim(ASCATobj$Tumor_LogR)[1], ncol = length(goodarrays)) + n2 = matrix(nrow = dim(ASCATobj$Tumor_LogR)[1], ncol = length(goodarrays)) + rownames(n1) = rownames(ASCATobj$Tumor_LogR) + rownames(n2) = rownames(ASCATobj$Tumor_LogR) + colnames(n1) = colnames(ASCATobj$Tumor_LogR)[goodarrays] + colnames(n2) = colnames(ASCATobj$Tumor_LogR)[goodarrays] + for (i in 1:length(goodarrays)) { + n1[,i] = res[[goodarrays[i]]]$nA + n2[,i] = res[[goodarrays[i]]]$nB + } + + tp = vector(length=length(goodarrays)) + psi = vector(length=length(goodarrays)) + ploidy = vector(length=length(goodarrays)) + goodnessOfFit = vector(length=length(goodarrays)) + naarrays = NULL + for (i in 1:length(goodarrays)) { + tp[i] = res[[goodarrays[i]]]$rho + psi[i] = res[[goodarrays[i]]]$psi + ploidy[i] = mean(res[[goodarrays[i]]]$nA+res[[goodarrays[i]]]$nB,na.rm=T) + goodnessOfFit[i] = res[[goodarrays[i]]]$goodnessOfFit + if(res[[goodarrays[i]]]$nonaberrant) { + naarrays = c(naarrays,ASCATobj$samples[goodarrays[i]]) + } + } + fa = colnames(ASCATobj$Tumor_LogR)[-goodarrays] + names(tp) = colnames(n1) + names(ploidy) = colnames(n1) + names(psi) = colnames(n1) + names(goodnessOfFit) = colnames(n1) + + seg = NULL + for (i in 1:length(goodarrays)) { + segje = res[[goodarrays[i]]]$seg + seg = rbind(seg,cbind(ASCATobj$samples[goodarrays[i]],as.vector(ASCATobj$SNPpos[segje[,1],1]), + ASCATobj$SNPpos[segje[,1],2], + ASCATobj$SNPpos[segje[,2],2],segje[,3],segje[,4])) + } + colnames(seg) = c("sample","chr","startpos","endpos","nMajor","nMinor") + seg = data.frame(seg,stringsAsFactors=F) + seg[,3]=as.numeric(seg[,3]) + seg[,4]=as.numeric(seg[,4]) + seg[,5]=as.numeric(seg[,5]) + seg[,6]=as.numeric(seg[,6]) + + seg_raw = NULL + for (i in 1:length(goodarrays)) { + segje = res[[goodarrays[i]]]$seg_raw + seg_raw = rbind(seg_raw,cbind(ASCATobj$samples[goodarrays[i]],as.vector(ASCATobj$SNPpos[segje[,1],1]), + ASCATobj$SNPpos[segje[,1],2], + ASCATobj$SNPpos[segje[,2],2],segje[,3],segje[,4:ncol(segje)])) + + } + colnames(seg_raw) = c("sample","chr","startpos","endpos","nMajor","nMinor","nAraw","nBraw") + + seg_raw = data.frame(seg_raw,stringsAsFactors=F) + seg_raw[,3]=as.numeric(seg_raw[,3]) + seg_raw[,4]=as.numeric(seg_raw[,4]) + seg_raw[,5]=as.numeric(seg_raw[,5]) + seg_raw[,6]=as.numeric(seg_raw[,6]) + seg_raw[,7]=as.numeric(seg_raw[,7]) + seg_raw[,8]=as.numeric(seg_raw[,8]) + + } + else { + n1 = NULL + n2 = NULL + tp = NULL + ploidy = NULL + psi = NULL + goodnessOfFit = NULL + fa = colnames(ASCATobj$Tumor_LogR) + naarrays = NULL + seg = NULL + seg_raw = NULL + } + + return(list(nA = n1, nB = n2, aberrantcellfraction = tp, ploidy = ploidy, psi = psi, goodnessOfFit = goodnessOfFit, + failedarrays = fa, nonaberrantarrays = naarrays, segments = seg, segments_raw = seg_raw)) +} + + + + + +# helping function to read segments: +make_seg_lr = function(r) { + pcf_segments = numeric(0); + index = 0; + previousr = 1E10; + for (i in 1:length(r)) { + if (r[i] != previousr) { + index=index+1; + count=1; + } + else { + count = count + 1; + } + pcf_segments[index] = count; + previousr = r[i]; + } + return(pcf_segments); +} + + + +# helper function to split the genome into parts +split_genome = function(SNPpos) { + + # look for gaps of more than 5Mb (arbitrary treshold to account for big centremeres or other gaps) and chromosome borders + bigHoles = which(diff(SNPpos[,2])>=5000000)+1 + chrBorders = which(SNPpos[1:(dim(SNPpos)[1]-1),1]!=SNPpos[2:(dim(SNPpos)[1]),1])+1 + + holes = unique(sort(c(bigHoles,chrBorders))) + + # find which segments are too small + #joincandidates=which(diff(c(0,holes,dim(SNPpos)[1]))<200) + + # if it's the first or last segment, just join to the one next to it, irrespective of chromosome and positions + #while (1 %in% joincandidates) { + # holes=holes[-1] + # joincandidates=which(diff(c(0,holes,dim(SNPpos)[1]))<200) + #} + #while ((length(holes)+1) %in% joincandidates) { + # holes=holes[-length(holes)] + # joincandidates=which(diff(c(0,holes,dim(SNPpos)[1]))<200) + #} + + #while(length(joincandidates)!=0) { + # the while loop is because after joining, segments may still be too small.. + + #startseg = c(1,holes) + #endseg = c(holes-1,dim(SNPpos)[1]) + + # for each segment that is too short, see if it has the same chromosome as the segments before and after + # the next always works because neither the first or the last segment is in joincandidates now + #previoussamechr = SNPpos[endseg[joincandidates-1],1]==SNPpos[startseg[joincandidates],1] + #nextsamechr = SNPpos[endseg[joincandidates],1]==SNPpos[startseg[joincandidates+1],1] + + #distanceprevious = SNPpos[startseg[joincandidates],2]-SNPpos[endseg[joincandidates-1],2] + #distancenext = SNPpos[startseg[joincandidates+1],2]-SNPpos[endseg[joincandidates],2] + + # if both the same, decide based on distance, otherwise if one the same, take the other, if none, just take one. + #joins = ifelse(previoussamechr&nextsamechr, + # ifelse(distanceprevious>distancenext, joincandidates, joincandidates-1), + # ifelse(nextsamechr, joincandidates, joincandidates-1)) + + #holes=holes[-joins] + + #joincandidates=which(diff(c(0,holes,dim(SNPpos)[1]))<200) + #} + # if two neighboring segments are selected, this may make bigger segments then absolutely necessary, but I'm sure this is no problem. + + startseg = c(1,holes) + endseg = c(holes-1,dim(SNPpos)[1]) + + chr=list() + for (i in 1:length(startseg)) { + chr[[i]]=startseg[i]:endseg[i] + } + + return(chr) +} + + + +# helper function to predict germline homozygous segments for later resegmentation +predictGermlineHomozygousStretches = function(chr, hom) { + + # contains the result: a list of vectors of probe numbers in homozygous stretches for each sample + HomoStretches = list() + + for (sam in 1:dim(hom)[2]) { + homsam = hom[,sam] + + perchom = sum(homsam,na.rm=T)/sum(!is.na(homsam)) + + # NOTE THAT A P-VALUE THRESHOLD OF 0.001 IS HARDCODED HERE + homthres = ceiling(log(0.001,perchom)) + + allhprobes = NULL + for (chrke in 1:length(chr)) { + hschr = homsam[chr[[chrke]]] + + hprobes = vector(length=0) + for(probe in 1:length(hschr)) { + if(!is.na(hschr[probe])) { + if(hschr[probe]) { + hprobes = c(hprobes,probe) + } + else { + if(length(hprobes)>=homthres) { + allhprobes = rbind(allhprobes,c(chrke,chr[[chrke]][min(hprobes)],chr[[chrke]][max(hprobes)])) + } + hprobes = vector(length=0) + } + } + } + # if the last probe is homozygous, this is not yet accounted for + if(!is.na(hschr[probe]) & hschr[probe]) { + if(length(hprobes)>=homthres) { + allhprobes = rbind(allhprobes,c(chrke,chr[[chrke]][min(hprobes)],chr[[chrke]][max(hprobes)])) + } + } + + } + + HomoStretches[[sam]]=allhprobes + + } + + return(HomoStretches) +} + + + + + +# function to make segments of constant LRR and BAF +# this function is more general and does not depend on specifically ASPCF output +# it can also handle segmention performed on LRR and BAF separately +make_segments = function(r,b) { + m = matrix(ncol = 2, nrow = length(b)) + m[,1] = r + m[,2] = b + m = as.matrix(na.omit(m)) + pcf_segments = matrix(ncol = 3, nrow = dim(m)[1]) + colnames(pcf_segments) = c("r","b","length"); + index = 0; + previousb = -1; + previousr = 1E10; + for (i in 1:dim(m)[1]) { + if (m[i,2] != previousb || m[i,1] != previousr) { + index=index+1; + count=1; + pcf_segments[index, "r"] = m[i,1]; + pcf_segments[index, "b"] = m[i,2]; + } + else { + count = count + 1; + } + pcf_segments[index, "length"] = count; + previousb = m[i,2]; + previousr = m[i,1]; + } + pcf_segments = as.matrix(na.omit(pcf_segments))[,] + return(pcf_segments); +} + + + +# function to create the distance matrix (distance for a range of ploidy and tumor percentage values) +# input: segmented LRR and BAF and the value for gamma +create_distance_matrix = function(segments, gamma) { + s = segments + psi_pos = seq(1,6,0.05) + rho_pos = seq(0.1,1.05,0.01) + d = matrix(nrow = length(psi_pos), ncol = length(rho_pos)) + rownames(d) = psi_pos + colnames(d) = rho_pos + dmin = 1E20; + for(i in 1:length(psi_pos)) { + psi = psi_pos[i] + for(j in 1:length(rho_pos)) { + rho = rho_pos[j] + nA = (rho-1-(s[,"b"]-1)*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho + nB = (rho-1+s[,"b"]*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho + # choose the minor allele + nMinor = NULL + if (sum(nA,na.rm=T) < sum(nB,na.rm=T)) { + nMinor = nA + } + else { + nMinor = nB + } + d[i,j] = sum(abs(nMinor - pmax(round(nMinor),0))^2 * s[,"length"] * ifelse(s[,"b"]==0.5,0.05,1), na.rm=T) + } + } + return(d) +} + + + +# the ASCAT main function +# lrr: (unsegmented) log R, in genomic sequence (all probes), with probe IDs +# baf: (unsegmented) B Allele Frequency, in genomic sequence (all probes), with probe IDs +# lrrsegmented: log R, segmented, in genomic sequence (all probes), with probe IDs +# bafsegmented: B Allele Frequency, segmented, in genomic sequence (only probes heterozygous in germline), with probe IDs +# chromosomes: a list containing c vectors, where c is the number of chromosomes and every vector contains all probe numbers per chromosome +# chrnames: a vector containing the names for the chromosomes (e.g. c(1:22,"X")) +# sexchromosomes: a vector containing the names for the sex chromosomes +# failedqualitycheck: did the sample fail any previous quality check or not? +# distancepng: if NA: distance is plotted, if filename is given, the plot is written to a .png file +# copynumberprofilespng: if NA: possible copy number profiles are plotted, if filename is given, the plot is written to a .png file +# nonroundedprofilepng: if NA: copy number profile before rounding is plotted (total copy number as well as the copy number of the minor allele), if filename is given, the plot is written to a .png file +# aberrationreliabilitypng: if NA: aberration reliability score is plotted, if filename is given, the plot is written to a .png file +# gamma: technology parameter, compaction of Log R profiles (expected decrease in case of deletion in diploid sample, 100 % aberrant cells; 1 in ideal case, 0.55 of Illumina 109K arrays) +runASCAT = function(lrr, baf, lrrsegmented, bafsegmented, gender, SNPpos, chromosomes, chrnames, sexchromosomes, failedqualitycheck = F, + distancepng = NA, copynumberprofilespng = NA, nonroundedprofilepng = NA, aberrationreliabilitypng = NA, gamma = 0.55, + rho_manual = NA, psi_manual = NA) { + ch = chromosomes + chrs = chrnames + b = bafsegmented + r = lrrsegmented[names(bafsegmented)] + + library(RColorBrewer) + + SNPposhet = SNPpos[names(bafsegmented),] + autoprobes = !(SNPposhet[,1]%in%sexchromosomes) + + b2 = b[autoprobes] + r2 = r[autoprobes] + + s = make_segments(r2,b2) + d = create_distance_matrix(s, gamma) + + if (!is.na(distancepng)) { + png(filename = distancepng, width = 1000, height = 1000, res = 1000/7) + } + + par(mar = c(5,5,0.5,0.5), cex=0.75, cex.lab=2, cex.axis=2) + + hmcol = rev(colorRampPalette(brewer.pal(10, "RdBu"))(256)) + image(log(d), col = hmcol, axes = F, xlab = "Ploidy", ylab = "Aberrant cell fraction") + + axis(1, at = seq(0, 1, by = 1/5), label = seq(1, 6, by = 1)) + axis(2, at = seq(0, 1/1.05, by = 1/3/1.05), label = seq(0.1, 1, by = 3/10)) + + TheoretMaxdist = sum(rep(0.25,dim(s)[1]) * s[,"length"] * ifelse(s[,"b"]==0.5,0.05,1),na.rm=T) + + # flag the sample as non-aberrant if necessary + nonaberrant = F + MINABB = 0.03 + MINABBREGION = 0.005 + + percentAbb = sum(ifelse(s[,"b"]==0.5,0,1)*s[,"length"])/sum(s[,"length"]) + maxsegAbb = max(ifelse(s[,"b"]==0.5,0,s[,"length"]))/sum(s[,"length"]) + if(percentAbb <= MINABB & maxsegAbb <= MINABBREGION) { + nonaberrant = T + } + + + MINPLOIDY = 1.5 + MAXPLOIDY = 5.5 + MINRHO = 0.2 + MINGOODNESSOFFIT = 80 + MINPERCZERO = 0.02 + MINPERCZEROABB = 0.1 + MINPERCODDEVEN = 0.05 + MINPLOIDYSTRICT = 1.7 + MAXPLOIDYSTRICT = 2.3 + + nropt = 0 + localmin = NULL + optima = list() + + if(!failedqualitycheck && is.na(rho_manual)) { + + # first, try with all filters + for (i in 4:(dim(d)[1]-3)) { + for (j in 4:(dim(d)[2]-3)) { + m = d[i,j] + seld = d[(i-3):(i+3),(j-3):(j+3)] + seld[4,4] = max(seld) + if(min(seld) > m) { + psi = as.numeric(rownames(d)[i]) + rho = as.numeric(colnames(d)[j]) + nA = (rho-1-(s[,"b"]-1)*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho + nB = (rho-1+s[,"b"]*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho + + # ploidy is recalculated based on results, to avoid bias (due to differences in normalization of LogR) + ploidy = sum((nA+nB) * s[,"length"]) / sum(s[,"length"]); + + percentzero = (sum((round(nA)==0)*s[,"length"])+sum((round(nB)==0)*s[,"length"]))/sum(s[,"length"]) + + goodnessOfFit = (1-m/TheoretMaxdist) * 100 + + if (!nonaberrant & ploidy > MINPLOIDY & ploidy < MAXPLOIDY & rho >= MINRHO & goodnessOfFit > MINGOODNESSOFFIT & percentzero > MINPERCZERO) { + nropt = nropt + 1 + optima[[nropt]] = c(m,i,j,ploidy,goodnessOfFit) + localmin[nropt] = m + } + } + } + } + + # if no solution, drop the percentzero > MINPERCZERO filter (allow non-aberrant solutions - but limit the ploidy options) + if (nropt == 0) { + for (i in 4:(dim(d)[1]-3)) { + for (j in 4:(dim(d)[2]-3)) { + m = d[i,j] + seld = d[(i-3):(i+3),(j-3):(j+3)] + seld[4,4] = max(seld) + if(min(seld) > m) { + psi = as.numeric(rownames(d)[i]) + rho = as.numeric(colnames(d)[j]) + nA = (rho-1-(s[,"b"]-1)*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho + nB = (rho-1+s[,"b"]*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho + + # ploidy is recalculated based on results, to avoid bias (due to differences in normalization of LogR) + ploidy = sum((nA+nB) * s[,"length"]) / sum(s[,"length"]); + + perczeroAbb = (sum((round(nA)==0)*s[,"length"]*ifelse(s[,"b"]==0.5,0,1))+sum((round(nB)==0)*s[,"length"]*ifelse(s[,"b"]==0.5,0,1)))/sum(s[,"length"]*ifelse(s[,"b"]==0.5,0,1)) + # the next can happen if BAF is a flat line at 0.5 + if (is.na(perczeroAbb)) { + perczeroAbb = 0 + } + + goodnessOfFit = (1-m/TheoretMaxdist) * 100 + + if (ploidy > MINPLOIDYSTRICT & ploidy < MAXPLOIDYSTRICT & rho >= MINRHO & goodnessOfFit > MINGOODNESSOFFIT & perczeroAbb > MINPERCZEROABB) { + nropt = nropt + 1 + optima[[nropt]] = c(m,i,j,ploidy,goodnessOfFit) + localmin[nropt] = m + } + } + } + } + } + + # if still no solution, allow solutions with 100% aberrant cells (include the borders with rho = 1), but in first instance, keep the percentzero > 0.01 filter + if (nropt == 0) { + #first, include borders + cold = which(as.numeric(colnames(d))>1) + d[,cold]=1E20 + for (i in 4:(dim(d)[1]-3)) { + for (j in 4:(dim(d)[2]-3)) { + m = d[i,j] + seld = d[(i-3):(i+3),(j-3):(j+3)] + seld[4,4] = max(seld) + if(min(seld) > m) { + psi = as.numeric(rownames(d)[i]) + rho = as.numeric(colnames(d)[j]) + nA = (rho-1-(s[,"b"]-1)*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho + nB = (rho-1+s[,"b"]*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho + + # ploidy is recalculated based on results, to avoid bias (due to differences in normalization of LogR) + ploidy = sum((nA+nB) * s[,"length"]) / sum(s[,"length"]); + + percentzero = (sum((round(nA)==0)*s[,"length"])+sum((round(nB)==0)*s[,"length"]))/sum(s[,"length"]) + percOddEven = sum((round(nA)%%2==0&round(nB)%%2==1|round(nA)%%2==1&round(nB)%%2==0)*s[,"length"])/sum(s[,"length"]) + perczeroAbb = (sum((round(nA)==0)*s[,"length"]*ifelse(s[,"b"]==0.5,0,1))+sum((round(nB)==0)*s[,"length"]*ifelse(s[,"b"]==0.5,0,1)))/sum(s[,"length"]*ifelse(s[,"b"]==0.5,0,1)) + if (is.na(perczeroAbb)) { + perczeroAbb = 0 + } + + goodnessOfFit = (1-m/TheoretMaxdist) * 100 + + if (!nonaberrant & ploidy > MINPLOIDY & ploidy < MAXPLOIDY & rho >= MINRHO & goodnessOfFit > MINGOODNESSOFFIT & + (perczeroAbb > MINPERCZEROABB | percentzero > MINPERCZERO | percOddEven > MINPERCODDEVEN)) { + nropt = nropt + 1 + optima[[nropt]] = c(m,i,j,ploidy,goodnessOfFit) + localmin[nropt] = m + } + } + } + } + } + + # if still no solution, drop the percentzero > MINPERCENTZERO filter, but strict ploidy borders + if (nropt == 0) { + for (i in 4:(dim(d)[1]-3)) { + for (j in 4:(dim(d)[2]-3)) { + m = d[i,j] + seld = d[(i-3):(i+3),(j-3):(j+3)] + seld[4,4] = max(seld) + if(min(seld) > m) { + psi = as.numeric(rownames(d)[i]) + rho = as.numeric(colnames(d)[j]) + nA = (rho-1-(s[,"b"]-1)*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho + nB = (rho-1+s[,"b"]*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho + + # ploidy is recalculated based on results, to avoid bias (due to differences in normalization of LogR) + ploidy = sum((nA+nB) * s[,"length"]) / sum(s[,"length"]); + + perczeroAbb = (sum((round(nA)==0)*s[,"length"]*ifelse(s[,"b"]==0.5,0,1))+sum((round(nB)==0)*s[,"length"]*ifelse(s[,"b"]==0.5,0,1)))/sum(s[,"length"]*ifelse(s[,"b"]==0.5,0,1)) + # the next can happen if BAF is a flat line at 0.5 + if (is.na(perczeroAbb)) { + perczeroAbb = 0 + } + + goodnessOfFit = (1-m/TheoretMaxdist) * 100 + + if (ploidy > MINPLOIDYSTRICT & ploidy < MAXPLOIDYSTRICT & rho >= MINRHO & goodnessOfFit > MINGOODNESSOFFIT) { + nropt = nropt + 1 + optima[[nropt]] = c(m,i,j,ploidy,goodnessOfFit) + localmin[nropt] = m + } + } + } + } + } + } + + if (!is.na(rho_manual)) { + + rho = rho_manual + psi = psi_manual + + nA = (rho-1-(s[,"b"]-1)*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho + nB = (rho-1+s[,"b"]*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho + + # ploidy is recalculated based on results, to avoid bias (due to differences in normalization of LogR) + ploidy = sum((nA+nB) * s[,"length"]) / sum(s[,"length"]); + + nMinor = NULL + if (sum(nA,na.rm=T) < sum(nB,na.rm=T)) { + nMinor = nA + } + else { + nMinor = nB + } + m = sum(abs(nMinor - pmax(round(nMinor),0))^2 * s[,"length"] * ifelse(s[,"b"]==0.5,0.05,1), na.rm=T) + + goodnessOfFit = (1-m/TheoretMaxdist) * 100 + + nropt = 1 + optima[[1]] = c(m,rho,psi,ploidy,goodnessOfFit) + localmin[1] = m + + } + + + if (nropt>0) { + if (is.na(rho_manual)) { + optlim = sort(localmin)[1] + for (i in 1:length(optima)) { + if(optima[[i]][1] == optlim) { + psi_opt1 = as.numeric(rownames(d)[optima[[i]][2]]) + rho_opt1 = as.numeric(colnames(d)[optima[[i]][3]]) + if(rho_opt1 > 1) { + rho_opt1 = 1 + } + ploidy_opt1 = optima[[i]][4] + goodnessOfFit_opt1 = optima[[i]][5] + points((psi_opt1-1)/5,(rho_opt1-0.1)/0.95,col="green",pch="X", cex = 2) + } + } + } else { + rho_opt1 = optima[[1]][2] + psi_opt1 = optima[[1]][3] + ploidy_opt1 = optima[[1]][4] + goodnessOfFit_opt1 = optima[[1]][5] + points((psi_opt1-1)/5,(rho_opt1-0.1)/0.95,col="green",pch="X", cex = 2) + } + } + + if (!is.na(distancepng)) { + dev.off() + } + + + if(nropt>0) { + + if (!is.na(nonroundedprofilepng)) { + png(filename = nonroundedprofilepng, width = 2000, height = 500, res = 200) + } + else { + windows(10,5) + } + + par(mar = c(0.5,5,5,0.5), cex = 0.4, cex.main=3, cex.axis = 2.5) + + rho = rho_opt1 + psi = psi_opt1 + + SNPposhet = SNPpos[names(bafsegmented),] + haploidchrs = unique(c(substring(gender,1,1),substring(gender,2,2))) + if(substring(gender,1,1)==substring(gender,2,2)) { + haploidchrs = setdiff(haploidchrs,substring(gender,1,1)) + } + diploidprobes = !(SNPposhet[,1]%in%haploidchrs) + nullchrs = setdiff(sexchromosomes,unique(c(substring(gender,1,1),substring(gender,2,2)))) + nullprobes = SNPposhet[,1]%in%nullchrs + + nAfull = ifelse(diploidprobes, + (rho-1-(b-1)*2^(r/gamma)*((1-rho)*2+rho*psi))/rho, + ifelse(nullprobes,0, + ifelse(b<0.5,(rho-1+((1-rho)*2+rho*psi)*2^(r/gamma))/rho,0))) + nBfull = ifelse(diploidprobes, + (rho-1+b*2^(r/gamma)*((1-rho)*2+rho*psi))/rho, + ifelse(nullprobes,0, + ifelse(b<0.5,0,(rho-1+((1-rho)*2+rho*psi)*2^(r/gamma))/rho))) + nA = pmax(round(nAfull),0) + nB = pmax(round(nBfull),0) + + maintitle = paste("Ploidy: ",sprintf("%1.2f",ploidy_opt1),", aberrant cell fraction: ",sprintf("%2.0f",rho_opt1*100),"%, goodness of fit: ",sprintf("%2.1f",goodnessOfFit_opt1),"%", ifelse(nonaberrant,", non-aberrant",""),sep="") + plot(c(1,length(nAfull)), c(0,5), type = "n", xaxt = "n", main = maintitle, xlab = "", ylab = "") + points(nBfull,col="blue",pch = "|") + points(nAfull+nBfull,col="purple",pch = "|") +# don't ask me why, but the "|" sign is not centered, so the lines may need to be shifted.. + abline(v=0,lty=1,col="lightgrey") + chrk_tot_len = 0 + for (i in 1:length(ch)) { + chrk = ch[[i]]; + chrk_hetero = intersect(names(lrr)[chrk],names(bafsegmented)) + chrk_tot_len_prev = chrk_tot_len + chrk_tot_len = chrk_tot_len + length(chrk_hetero) + vpos = chrk_tot_len; + tpos = (chrk_tot_len+chrk_tot_len_prev)/2; + text(tpos,5,chrs[i], pos = 1, cex = 2) + abline(v=vpos,lty=1,col="lightgrey") + } + + if (!is.na(nonroundedprofilepng)) { + dev.off() + } + + rho = rho_opt1 + psi = psi_opt1 + + diploidprobes = !(SNPpos[,1]%in%haploidchrs) + nullprobes = SNPpos[,1]%in%nullchrs + + #this replaces an occurrence of unique that caused problems + tlr2 = rle(lrrsegmented) + tlr = tlr2$values + tlrstart = c(1,cumsum(tlr2$lengths)+1) + tlrstart = tlrstart[1:(length(tlrstart)-1)] + tlrend = cumsum(tlr2$lengths) + seg = NULL + for (i in 1:length(tlr)) { + logR = tlr[i] + #pr = which(lrrsegmented==logR) # this was a problem + pr = tlrstart[i]:tlrend[i] + start = min(pr) + end = max(pr) + bafke = bafsegmented[intersect(names(lrrsegmented)[pr],names(bafsegmented))][1] + #if bafke is NA, this means that we are dealing with a germline homozygous stretch with a copy number change within it. + #in this case, nA and nB are irrelevant, just their sum matters + if(is.na(bafke)) { + bafke=0 + } + + nAraw = ifelse(diploidprobes[start], + (rho-1-(bafke-1)*2^(logR/gamma)*((1-rho)*2+rho*psi))/rho, + ifelse(nullprobes[start],0, + (rho-1+((1-rho)*2+rho*psi)*2^(logR/gamma))/rho)) + nBraw = ifelse(diploidprobes[start],(rho-1+bafke*2^(logR/gamma)*((1-rho)*2+rho*psi))/rho,0) + # correct for negative values: + if (nAraw+nBraw<0) { + nAraw = 0 + nBraw = 0 + } + else if (nAraw<0) { + nBraw = nAraw+nBraw + nAraw = 0 + } + else if (nBraw<0) { + nAraw = nAraw+nBraw + nBraw = 0 + } + # when evidence for odd copy number in segments of BAF = 0.5, assume a deviation.. + limitround = 0.5 + nA = ifelse(bafke==0.5, + ifelse(nAraw+nBraw>round(nAraw)+round(nBraw)+limitround, + round(nAraw)+1, + ifelse(nAraw+nBrawround(nAraw)+round(nBraw)+limitround, + round(nBraw), + ifelse(nAraw+nBraw0.5,nMajor[heteroprobes], nMinor[heteroprobes]) + n1all[homoprobes] = ifelse(baf[homoprobes]<=0.5,nMajor[homoprobes]+nMinor[homoprobes],0) + n2all[homoprobes] = ifelse(baf[homoprobes]>0.5,nMajor[homoprobes]+nMinor[homoprobes],0) + + + # plot ASCAT profile + if (!is.na(copynumberprofilespng)) { + png(filename = copynumberprofilespng, width = 2000, height = 500, res = 200) + } + else { + windows(10,2.5) + } + + par(mar = c(0.5,5,5,0.5), cex = 0.4, cex.main=3, cex.axis = 2.5) + + nA2 = n1all[heteroprobes] + nB2 = n2all[heteroprobes] + nA = ifelse(nA2>nB2,nA2,nB2) + nB = ifelse(nA2>nB2,nB2,nA2) + maintitle = paste("Ploidy: ",sprintf("%1.2f",ploidy_opt1),", aberrant cell fraction: ",sprintf("%2.0f",rho_opt1*100),"%, goodness of fit: ",sprintf("%2.1f",goodnessOfFit_opt1),"%", ifelse(nonaberrant,", non-aberrant",""),sep="") + plot(c(1,length(nAfull)), c(0,5), type = "n", xaxt = "n", main = maintitle, xlab = "", ylab = "") + points(nA-0.1,col="red",pch = "|") + points(nB+0.1,col="green",pch = "|") + # don't ask me why, but the "|" sign is not centered, so the lines may need to be shifted.. + abline(v=0,lty=1,col="lightgrey") + chrk_tot_len = 0 + for (i in 1:length(ch)) { + chrk = ch[[i]]; + chrk_hetero = intersect(names(lrr)[chrk],names(bafsegmented)) + chrk_tot_len_prev = chrk_tot_len + chrk_tot_len = chrk_tot_len + length(chrk_hetero) + vpos = chrk_tot_len; + tpos = (chrk_tot_len+chrk_tot_len_prev)/2; + text(tpos,5,chrs[i], pos = 1, cex = 2) + abline(v=vpos,lty=1,col="lightgrey") + } + + + if (!is.na(copynumberprofilespng)) { + dev.off() + } + + + if (!is.na(aberrationreliabilitypng)) { + png(filename = aberrationreliabilitypng, width = 2000, height = 500, res = 200) + } + else { + windows(10,2.5) + } + + par(mar = c(0.5,5,5,0.5), cex = 0.4, cex.main=3, cex.axis = 2.5) + + diploidprobes = !(SNPposhet[,1]%in%haploidchrs) + nullprobes = SNPposhet[,1]%in%nullchrs + + rBacktransform = ifelse(diploidprobes, + gamma*log((rho*(nA+nB)+(1-rho)*2)/((1-rho)*2+rho*psi),2), + # the value for nullprobes is arbitrary (but doesn't matter, as these are not plotted anyway because BAF=0.5) + ifelse(nullprobes,-10,gamma*log((rho*(nA+nB)+(1-rho))/((1-rho)*2+rho*psi),2))) + + bBacktransform = ifelse(diploidprobes, + (1-rho+rho*nB)/(2-2*rho+rho*(nA+nB)), + ifelse(nullprobes,0.5,0)) + + rConf = ifelse(abs(rBacktransform)>0.15,pmin(100,pmax(0,100*(1-abs(rBacktransform-r)/abs(r)))),NA) + bConf = ifelse(diploidprobes & bBacktransform!=0.5, pmin(100,pmax(0,ifelse(b==0.5,100,100*(1-abs(bBacktransform-b)/abs(b-0.5))))), NA) + confidence = ifelse(is.na(rConf),bConf,ifelse(is.na(bConf),rConf,(rConf+bConf)/2)) + maintitle = paste("Aberration reliability score (%), average: ", sprintf("%2.0f",mean(confidence,na.rm=T)),"%",sep="") + plot(c(1,length(nAfull)), c(0,100), type = "n", xaxt = "n", main = maintitle, xlab = "", ylab = "") + points(confidence,col="blue",pch = "|") + abline(v=0,lty=1,col="lightgrey") + chrk_tot_len = 0 + for (i in 1:length(ch)) { + chrk = ch[[i]]; + chrk_hetero = intersect(names(lrr)[chrk],names(bafsegmented)) + chrk_tot_len_prev = chrk_tot_len + chrk_tot_len = chrk_tot_len + length(chrk_hetero) + vpos = chrk_tot_len; + tpos = (chrk_tot_len+chrk_tot_len_prev)/2; + text(tpos,5,chrs[i], pos = 1, cex = 2) + abline(v=vpos,lty=1,col="lightgrey") + } + + if (!is.na(aberrationreliabilitypng)) { + dev.off() + } + + return(list(rho = rho_opt1, psi = psi_opt1, goodnessOfFit = goodnessOfFit_opt1, nonaberrant = nonaberrant, nA = n1all, nB = n2all, seg = seg, seg_raw = seg_raw)) + + } + + else { + return(list(rho = NA, psi = NA, goodnessOfFit = NA, nonaberrant = F, nA = NA, nB = NA, seg = NA, seg_raw = NA)) + } + +} + + + + + + + + +# +# Enhanced bivariate PCF filter for aCGH data (v. 08.02.2010) +# Whole chromosomes/chromosome arms wrapper function +# + +fastAspcf <- function(logR, allB, kmin, gamma){ + + N <- length(logR) + w <- 1000 #w: windowsize + d <- 100 + + startw = -d + stopw = w-d + + nseg = 0 + var2 = 0 + breakpts = 0 + larger = TRUE + repeat{ + from <- max(c(1,startw)) + to <- min(c(stopw,N)) + logRpart <- logR[from:to] + allBpart <- allB[from:to] + allBflip <- allBpart + allBflip[allBpart > 0.5] <- 1 - allBpart[allBpart > 0.5] + + sd1 <- getMad(logRpart) + sd2 <- getMad(allBflip) + + #Must check that sd1 and sd2 are defined and != 0: + sd.valid <- c(!is.na(sd1),!is.na(sd2),sd1!=0,sd2!=0) + if(all(sd.valid)){ + #run aspcfpart: + #part.res <- aspcfpart(logRpart=logRpart, allBflip=allBflip, a=startw, b=stopw, d=d, sd1=sd1, sd2=sd2, N=N, kmin=kmin, gamma=gamma) + part.res <- aspcfpart(logRpart=logRpart, allBflip=allBflip, a=startw, b=stopw, d=d, sd1=sd1, sd2=sd2, N=N, kmin=kmin, gamma=gamma) + breakptspart <- part.res$breakpts + # the 'larger' is (occasionally) necessary in the last window of the segmentation! + larger = breakptspart>breakpts[length(breakpts)] + breakpts <- c(breakpts, breakptspart[larger]) + var2 <- var2 + sd2^2 + nseg = nseg+1 + } + + if(stopw < N+d){ + startw <- min(stopw-2*d + 1,N-2*d) + stopw <- startw + w + }else{ + break + } + + }#end repeat + breakpts <- unique(c(breakpts, N)) + if(nseg==0){nseg=1} #just in case the sd-test never passes. + sd2 <- sqrt(var2/nseg) + + # On each segment calculate mean of unflipped B allele data + frst <- breakpts[1:length(breakpts)-1] + 1 + last <- breakpts[2:length(breakpts)] + nseg <- length(frst) + + yhat1 <- rep(NA,N) + yhat2 <- rep(NA,N) + + for(i in 1:nseg){ + yhat1[frst[i]:last[i]] <- rep(mean(logR[frst[i]:last[i]]), last[i]-frst[i]+1) + yi2 <- allB[frst[i]:last[i]] + # Center data around zero (by subtracting 0.5) and estimate mean + if(length(yi2)== 0){ + mu <- 0 + }else{ + mu <- mean(abs(yi2-0.5)) + } + + # Make a (slightly arbitrary) decision concerning branches + # This may be improved by a test of equal variances + if(sqrt(sd2^2+mu^2) < 2*sd2){ + mu <- 0 + } + yhat2[frst[i]:last[i]] <- rep(mu+0.5,last[i]-frst[i]+1) + } + + return(list(yhat1=yhat1,yhat2=yhat2)) + +}#end fastAspcf + + + +aspcfpart <- function(logRpart, allBflip, a, b, d, sd1, sd2, N, kmin, gamma){ + + from <- max(c(1,a)) + usefrom <- max(c(1,a+d)) + useto <- min(c(N,b-d)) + + N <- length(logRpart) + y1 <- logRpart + y2 <- allBflip + + #Check that vectors are long enough to run algorithm: + if(N < 2*kmin){ + breakpts <- 0 + return(list(breakpts=breakpts)) + } + + # Find initSum, initKvad, initAve for segment y[1..kmin] + initSum1 <- sum(y1[1:kmin]) + initKvad1 <- sum(y1[1:kmin]^2) + initAve1 <- initSum1/kmin + initSum2 <- sum(y2[1:kmin]) + initKvad2 <- sum(y2[1:kmin]^2) + initAve2 <- initSum2/kmin + + # Define vector of best costs + bestCost <- rep(0,N) + cost1 <- (initKvad1 - initSum1*initAve1)/sd1^2 + cost2 <- (initKvad2 - initSum2*initAve2)/sd2^2 + bestCost[kmin] <- cost1 + cost2 + + # Define vector of best splits + bestSplit <- rep(0,N) + + # Define vector of best averages + bestAver1 <- rep(0,N) + bestAver2 <- rep(0,N) + bestAver1[kmin] <- initAve1 + bestAver2[kmin] <- initAve2 + + + #Initialize + Sum1 <- rep(0,N) + Sum2 <- rep(0,N) + Kvad1 <- rep(0,N) + Kvad2 <- rep(0,N) + Aver1 <- rep(0,N) + Aver2 <- rep(0,N) + Cost <- rep(0,N) + + # We have to treat the region y(1..2*kmin-1) separately, as it + # cannot be split into two full segments + kminP1 <- kmin+1 + for (k in (kminP1):(2*kmin-1)) { + Sum1[kminP1:k] <- Sum1[kminP1:k]+y1[k] + Aver1[kminP1:k] <- Sum1[kminP1:k]/((k-kmin):1) + Kvad1[kminP1:k] <- Kvad1[kminP1:k]+y1[k]^2 + Sum2[kminP1:k] <- Sum2[kminP1:k]+y2[k] + Aver2[kminP1:k] <- Sum2[kminP1:k]/((k-kmin):1) + Kvad2[kminP1:k] <- Kvad2[kminP1:k]+y2[k]^2 + + + bestAver1[k] <- (initSum1+Sum1[kminP1])/k + bestAver2[k] <- (initSum2+Sum2[kminP1])/k + cost1 <- ((initKvad1+Kvad1[kminP1])-k*bestAver1[k]^2)/sd1^2 + cost2 <- ((initKvad2+Kvad2[kminP1])-k*bestAver2[k]^2)/sd2^2 + + bestCost[k] <- cost1 + cost2 + + } + + + for (n in (2*kmin):N) { + + nMkminP1=n-kmin+1 + + Sum1[kminP1:n] <- Sum1[kminP1:n]+ y1[n] + Aver1[kminP1:n] <- Sum1[kminP1:n]/((n-kmin):1) + Kvad1[kminP1:n] <- Kvad1[kminP1:n]+ (y1[n])^2 + + cost1 <- (Kvad1[kminP1:nMkminP1]-Sum1[kminP1:nMkminP1]*Aver1[kminP1:nMkminP1])/sd1^2 + + Sum2[kminP1:n] <- Sum2[kminP1:n]+ y2[n] + Aver2[kminP1:n] <- Sum2[kminP1:n]/((n-kmin):1) + Kvad2[kminP1:n] <- Kvad2[kminP1:n]+ (y2[n])^2 + cost2 <- (Kvad2[kminP1:nMkminP1]-Sum2[kminP1:nMkminP1]*Aver2[kminP1:nMkminP1])/sd2^2 + + Cost[kminP1:nMkminP1] <- bestCost[kmin:(n-kmin)] + cost1 + cost2 + + Pos <- which.min(Cost[kminP1:nMkminP1])+kmin + cost <- Cost[Pos] + gamma + + aver1 <- Aver1[Pos] + aver2 <- Aver2[Pos] + totAver1 <- (Sum1[kminP1]+initSum1)/n + totCost1 <- ((Kvad1[kminP1]+initKvad1) - n*totAver1*totAver1)/sd1^2 + totAver2 <- (Sum2[kminP1]+initSum2)/n + totCost2 <- ((Kvad2[kminP1]+initKvad2) - n*totAver2*totAver2)/sd2^2 + totCost <- totCost1 + totCost2 + + if (totCost < cost) { + Pos <- 1 + cost <- totCost + aver1 <- totAver1 + aver2 <- totAver2 + } + bestCost[n] <- cost + bestAver1[n] <- aver1 + bestAver2[n] <- aver2 + bestSplit[n] <- Pos-1 + + + }#endfor + + + # Trace back + n <- N + breakpts <- n + while(n > 0){ + breakpts <- c(bestSplit[n], breakpts) + n <- bestSplit[n] + }#endwhile + + breakpts <- breakpts + from -1 + breakpts <- breakpts[breakpts>=usefrom & breakpts<=useto] + + return(list(breakpts=breakpts)) + +}#end aspcfpart + + + + + + +div <- function(a, b, c){ + + if(nargs() < 3){ + c <- 0 + }#endif + + if(b > 0){ + v <- a/b + }else{ + v <- c + }#endif + + return(v) +}#endfunction + + +#function v = div(a, b, c) +# if nargin < 3 +# c = 0; +# end +# if b > 0 +# v = a/b; +# else +# v = c; +# end +#end + + + +#Get mad SD (based on KL code) +getMad <- function(x,k=25){ + + #Remove observations that are equal to zero; are likely to be imputed, should not contribute to sd: + x <- x[x!=0] + + #Calculate runMedian + runMedian <- medianFilter(x,k) + + dif <- x-runMedian + SD <- mad(dif) + + return(SD) +} + + + + + +exactPcf <- function(y, kmin, gamma) { +## Implementaion of exact PCF by Potts-filtering + ## x: input array of (log2) copy numbers + ## kmin: Mininal length of plateaus + ## gamma: penalty for each discontinuity + N <- length(y) + yhat <- rep(0,N); + if (N < 2*kmin) { + yhat <- rep(mean(y),N) + return(yhat) + } + initSum <- sum(y[1:kmin]) + initKvad <- sum(y[1:kmin]^2) + initAve <- initSum/kmin; + bestCost <- rep(0,N) + bestCost[kmin] <- initKvad - initSum*initAve + bestSplit <- rep(0,N) + bestAver <- rep(0,N) + bestAver[kmin] <- initAve + Sum <- rep(0,N) + Kvad <- rep(0,N) + Aver <- rep(0,N) + Cost <- rep(0,N) + kminP1=kmin+1 + for (k in (kminP1):(2*kmin-1)) { + Sum[kminP1:k]<-Sum[kminP1:k]+y[k] + Aver[kminP1:k] <- Sum[kminP1:k]/((k-kmin):1) + Kvad[kminP1:k] <- Kvad[kminP1:k]+y[k]^2 + bestAver[k] <- (initSum+Sum[kminP1])/k + bestCost[k] <- (initKvad+Kvad[kminP1])-k*bestAver[k]^2 + } + for (n in (2*kmin):N) { + yn <- y[n] + yn2 <- yn^2 + Sum[kminP1:n] <- Sum[kminP1:n]+yn + Aver[kminP1:n] <- Sum[kminP1:n]/((n-kmin):1) + Kvad[kminP1:n] <- Kvad[kminP1:n]+yn2 + nMkminP1=n-kmin+1 + Cost[kminP1:nMkminP1] <- bestCost[kmin:(n-kmin)]+Kvad[kminP1:nMkminP1]-Sum[kminP1:nMkminP1]*Aver[kminP1:nMkminP1]+gamma + Pos <- which.min(Cost[kminP1:nMkminP1])+kmin + cost <- Cost[Pos] + aver <- Aver[Pos] + totAver <- (Sum[kminP1]+initSum)/n + totCost <- (Kvad[kminP1]+initKvad) - n*totAver*totAver + if (totCost < cost) { + Pos <- 1 + cost <- totCost + aver <- totAver + } + bestCost[n] <- cost + bestAver[n] <- aver + bestSplit[n] <- Pos-1 + } + n <- N + while (n > 0) { + yhat[(bestSplit[n]+1):n] <- bestAver[n] + n <- bestSplit[n] + } + return(yhat) +} + + +#Perform MAD winsorization: +madWins <- function(x,tau,k){ + xhat <- medianFilter(x,k) + d <- x-xhat + SD <- mad(d) + z <- tau*SD + xwin <- xhat + psi(d, z) + outliers <- rep(0, length(x)) + outliers[x > xwin] <- 1 + outliers[x < xwin] <- -1 + return(list(ywin=xwin,sdev=SD,outliers=outliers)) +} + + +######################################################################### +# Function to calculate running median for a given a window size +######################################################################### + +##Input: +### x: vector of numeric values +### k: window size to be used for the sliding window (actually half-window size) + +## Output: +### runMedian : the running median corresponding to each observation + +##Required by: +### getMad +### medianFilter + + +##Requires: +### none + +medianFilter <- function(x,k){ + n <- length(x) + filtWidth <- 2*k + 1 + + #Make sure filtWidth does not exceed n + if(filtWidth > n){ + if(n==0){ + filtWidth <- 1 + }else if(n%%2 == 0){ + #runmed requires filtWidth to be odd, ensure this: + filtWidth <- n - 1 + }else{ + filtWidth <- n + } + } + + runMedian <- runmed(x,k=filtWidth,endrule="median") + + return(runMedian) + +} + + + + + +psi <- function(x,z){ + xwin <- x + xwin[x < -z] <- -z + xwin[x > z] <- z + return(xwin) +} + + + + + + + +ascat.predictGermlineGenotypes = function(ASCATobj, platform = "AffySNP6") { + Homozygous = matrix(nrow = dim(ASCATobj$Tumor_LogR)[1], ncol = dim(ASCATobj$Tumor_LogR)[2]) + colnames(Homozygous) = colnames(ASCATobj$Tumor_LogR) + rownames(Homozygous) = rownames(ASCATobj$Tumor_LogR) + + if (platform=="Custom10k") { + maxHomozygous = 0.05 + proportionHetero = 0.59 + proportionHomo = 0.38 + proportionOpen = 0.02 + segmentLength = 20 + } + else if (platform=="Illumina109k") { + maxHomozygous = 0.05 + proportionHetero = 0.35 + proportionHomo = 0.60 + proportionOpen = 0.02 + segmentLength = 20 + } + else if (platform=="IlluminaCytoSNP") { + maxHomozygous = 0.05 + proportionHetero = 0.28 + proportionHomo = 0.62 + proportionOpen = 0.03 + segmentLength = 100 + } + else if (platform=="Illumina610k") { + maxHomozygous = 0.05 + proportionHetero = 0.295 + proportionHomo = 0.67 + proportionOpen = 0.015 + segmentLength = 30 + } + else if (platform=="Illumina660k") { + maxHomozygous = 0.05 + proportionHetero = 0.295 + proportionHomo = 0.67 + proportionOpen = 0.015 + segmentLength = 30 + } + else if (platform=="Illumina700k") { + maxHomozygous = 0.05 + proportionHetero = 0.295 + proportionHomo = 0.67 + proportionOpen = 0.015 + segmentLength = 30 + } + else if (platform=="Illumina1M") { + maxHomozygous = 0.05 + proportionHetero = 0.22 + proportionHomo = 0.74 + proportionOpen = 0.02 + segmentLength = 100 + #previousvalues: + #proportionHetero = 0.24 + #proportionOpen = 0.01 + #segmentLength = 60 + } + else if (platform=="Illumina2.5M") { + maxHomozygous = 0.05 + proportionHetero = 0.21 + proportionHomo = 0.745 + proportionOpen = 0.03 + segmentLength = 100 + } + else if (platform=="IlluminaOmni5") { + maxHomozygous = 0.05 + proportionHetero = 0.13 + proportionHomo = 0.855 + proportionOpen = 0.01 + segmentLength = 100 + } + else if (platform=="Affy10k") { + maxHomozygous = 0.04 + proportionHetero = 0.355 + proportionHomo = 0.605 + proportionOpen = 0.025 + segmentLength = 20 + } + else if (platform=="Affy100k") { + maxHomozygous = 0.05 + proportionHetero = 0.27 + proportionHomo = 0.62 + proportionOpen = 0.09 + segmentLength = 30 + } + else if (platform=="Affy250k_sty") { + maxHomozygous = 0.05 + proportionHetero = 0.26 + proportionHomo = 0.66 + proportionOpen = 0.05 + segmentLength = 50 + } + else if (platform=="Affy250k_nsp") { + maxHomozygous = 0.05 + proportionHetero = 0.26 + proportionHomo = 0.66 + proportionOpen = 0.05 + segmentLength = 50 + } + else if (platform=="AffySNP6") { + maxHomozygous = 0.05 + proportionHetero = 0.25 + proportionHomo = 0.67 + proportionOpen = 0.04 + segmentLength = 100 + } + else if (platform=="AffyOncoScan") { + maxHomozygous = 0.05 + proportionHetero = 0.24 + proportionHomo = 0.69 + proportionOpen = 0.04 + segmentLength = 30 + } + else if (platform=="AffyCytoScanHD") { + maxHomozygous = 0.05 + proportionHetero = 0.26 + proportionHomo = 0.69 + proportionOpen = 0.03 + segmentLength = 30 + } + else { + print("Error: platform unknown") + } + + failedarrays = NULL + + for (i in 1:dim(ASCATobj$Tumor_LogR)[2]) { + png(filename = paste("tumorSep",colnames(ASCATobj$Tumor_LogR)[i],".png",sep=""), width = 2000, height = 500, res = 200) + par(mar = c(0.5,5,5,0.5), cex = 0.4, cex.main=3, cex.axis = 2, pch = ifelse(dim(ASCATobj$Tumor_LogR)[1]>100000,".",20)) + + Tumor_BAF_noNA = ASCATobj$Tumor_BAF[!is.na(ASCATobj$Tumor_BAF[,i]),i] + names(Tumor_BAF_noNA) = rownames(ASCATobj$Tumor_BAF)[!is.na(ASCATobj$Tumor_BAF[,i])] + Tumor_LogR_noNA = ASCATobj$Tumor_LogR[names(Tumor_BAF_noNA),i] + names(Tumor_LogR_noNA) = names(Tumor_BAF_noNA) + + chr_noNA = list() + prev = 0 + for(j in 1:length(ASCATobj$chr)) { + chrke = ASCATobj$chr[[j]] + next2 = prev + sum(!is.na(ASCATobj$Tumor_BAF[chrke,i])) + chr_noNA[[j]] = (prev+1):next2 + prev = next2 + } + + ch_noNA = list() + prev = 0 + for(j in 1:length(ASCATobj$ch)) { + chrke = ASCATobj$ch[[j]] + next2 = prev + sum(!is.na(ASCATobj$Tumor_BAF[chrke,i])) + ch_noNA[[j]] = (prev+1):next2 + prev = next2 + } + + tbsam = Tumor_BAF_noNA + # sample, mirrored + bsm = ifelse(tbsam<0.5, tbsam, 1-tbsam) + + homoLimit = max(sort(bsm)[round(length(bsm)*proportionHomo)],maxHomozygous) + + if(homoLimit>0.25) { + failedarrays = c(failedarrays,ASCATobj$samples[i]) + } + + Hom = ifelse(bsm0) { + + allProbes=1:length(Tumor_BAF_noNA) + nonHomoProbes = allProbes[is.na(Hom)|Hom==F] + + lowestDist = NULL + + # bsm, with homozygous replaced by NA + bsmHNA=bsm + bsmHNA[!is.na(Hom)&Hom]=NA + + for (chrke in chr_noNA) { + + chrNonHomoProbes = intersect(nonHomoProbes,chrke) + + # there must be a minimum number of probes on the chromosome, otherwise these are called homozygous anyway + if (length(chrNonHomoProbes)>5) { + + #make sure we're not going over any borders.. + segmentLength2 = min(length(chrNonHomoProbes)-1,segmentLength) + + chrNonHomoProbesStartWindowLeft = c(rep(NA,segmentLength2),chrNonHomoProbes[1:(length(chrNonHomoProbes)-segmentLength2)]) + chrNonHomoProbesEndWindowLeft = c(NA,chrNonHomoProbes[1:(length(chrNonHomoProbes)-1)]) + chrNonHomoProbesStartWindowRight = c(chrNonHomoProbes[2:length(chrNonHomoProbes)],NA) + chrNonHomoProbesEndWindowRight = c(chrNonHomoProbes[(segmentLength2+1):length(chrNonHomoProbes)],rep(NA,segmentLength2)) + chrNonHomoProbesStartWindowMiddle = c(rep(NA,segmentLength2/2),chrNonHomoProbes[1:(length(chrNonHomoProbes)-segmentLength2/2)]) + chrNonHomoProbesEndWindowMiddle = c(chrNonHomoProbes[(segmentLength2/2+1):length(chrNonHomoProbes)],rep(NA,segmentLength2/2)) + + chrLowestDist = NULL + + for (probeNr in 1:length(chrNonHomoProbes)) { + probe = chrNonHomoProbes[probeNr] + if(!is.na(chrNonHomoProbesStartWindowLeft[probeNr])&!is.na(chrNonHomoProbesEndWindowLeft[probeNr])) { + medianLeft = median(bsmHNA[chrNonHomoProbesStartWindowLeft[probeNr]:chrNonHomoProbesEndWindowLeft[probeNr]], na.rm=T) + } + else { + medianLeft = NA + } + if(!is.na(chrNonHomoProbesStartWindowRight[probeNr])&!is.na(chrNonHomoProbesEndWindowRight[probeNr])) { + medianRight = median(bsmHNA[chrNonHomoProbesStartWindowRight[probeNr]:chrNonHomoProbesEndWindowRight[probeNr]], na.rm=T) + } + else { + medianRight = NA + } + + if(!is.na(chrNonHomoProbesStartWindowMiddle[probeNr])&!is.na(chrNonHomoProbesEndWindowMiddle[probeNr])) { + medianMiddle = median(c(bsmHNA[chrNonHomoProbesStartWindowMiddle[probeNr]:chrNonHomoProbesEndWindowLeft[probeNr]], + bsmHNA[chrNonHomoProbesStartWindowRight[probeNr]:chrNonHomoProbesEndWindowMiddle[probeNr]]), na.rm=T) + } + else { + medianMiddle = NA + } + + chrLowestDist[probeNr] = min(abs(medianLeft-bsm[probe]),abs(medianRight-bsm[probe]),abs(medianMiddle-bsm[probe]),Inf,na.rm=T) + } + } + + # if too few probes on the chromosome + else { + chrLowestDist = NULL + if (length(chrNonHomoProbes)>0) { + # 1 is higher than any practical distance + chrLowestDist[1:length(chrNonHomoProbes)] = 1 + } + } + + lowestDist = c(lowestDist,chrLowestDist) + } + + lowestDistUndecided = lowestDist[is.na(Hom[nonHomoProbes])] + names(lowestDistUndecided)=names(Tumor_LogR_noNA)[nonHomoProbes[is.na(Hom[nonHomoProbes])]] + + sorted = sort(lowestDistUndecided) + Hom[names(sorted[1:min(length(sorted),extraHetero)])] = F + + Hetero = sum(Hom==F, na.rm=T) + Homo = sum(Hom==T, na.rm=T) + Undecided = sum(is.na(Hom)) + + } + + title = paste(paste(colnames(ASCATobj$Tumor_BAF)[i], Hetero), Homo) + plot(c(1,length(Tumor_BAF_noNA)), c(0,1), type = "n", xaxt = "n", main = title, xlab = "", ylab = "") + points(Tumor_BAF_noNA,col=ifelse(is.na(Hom),"green",ifelse(Hom,"blue","red"))) + + abline(v=0.5,lty=1,col="lightgrey") + chrk_tot_len = 0 + for (j in 1:length(ch_noNA)) { + chrk = ch_noNA[[j]]; + chrk_tot_len_prev = chrk_tot_len + chrk_tot_len = chrk_tot_len + length(chrk) + vpos = chrk_tot_len; + tpos = (chrk_tot_len+chrk_tot_len_prev)/2; + text(tpos,1,ASCATobj$chrs[j], pos = 1, cex = 2) + abline(v=vpos+0.5,lty=1,col="lightgrey") + } + + # set all Undecided to homozygous + Hom[is.na(Hom)] = T + + dev.off() + + Homozygous[names(Hom),i] = Hom + } + + return(list(germlinegenotypes = Homozygous, failedarrays = failedarrays)) + +} diff --git a/bin/build_reference.sh b/bin/build_reference.sh index faa7607645..741a27edb2 100755 --- a/bin/build_reference.sh +++ b/bin/build_reference.sh @@ -1,9 +1,11 @@ #!/bin/bash set -xeuo pipefail +PROFILE=docker TEST=ALL TRAVIS_BUILD_DIR=${TRAVIS_BUILD_DIR:-.} TRAVIS=${TRAVIS:-false} +VERBOSE='' while [[ $# -gt 0 ]] do @@ -14,6 +16,15 @@ do shift # past argument shift # past value ;; + -p|--profile) + PROFILE=$2 + shift # past argument + shift # past value + ;; + -v|--verbose) + VERBOSE="-ansi-log false -dump-channels" + shift # past value + ;; *) # unknown option shift # past argument ;; @@ -24,6 +35,6 @@ done if [[ $TEST != ANNOTATESNPEFF ]] && [[ $TEST != ANNOTATEVEP ]] then rm -rf references - nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile test,docker --build --outdir references -ansi-log false -dump-channels + nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile test,${PROFILE} --build --outdir references ${VERBOSE} rm -rf .nextflow* references/pipeline_info work fi diff --git a/bin/download_docker.sh b/bin/download_docker.sh index a4fac3bdb4..f8fe108664 100755 --- a/bin/download_docker.sh +++ b/bin/download_docker.sh @@ -18,15 +18,20 @@ do esac done +if [[ ALL,ANNOTATEALL,ANNOTATESNPEFF =~ $TEST ]] +then + docker pull nfcore/sareksnpeff:dev.GRCh37 + docker tag nfcore/sareksnpeff:dev.GRCh37 nfcore/sareksnpeff:dev.smallGRCh37 +fi + if [[ ALL,ANNOTATEALL,ANNOTATEVEP =~ $TEST ]] then docker pull nfcore/sarekvep:dev.GRCh37 docker tag nfcore/sarekvep:dev.GRCh37 nfcore/sarekvep:dev.smallGRCh37 -elif [[ ALL,ANNOTATEALL,ANNOTATESNPEFF =~ $TEST ]] +fi + +if [[ ANNOTATEALL,ANNOTATEVEP,ANNOTATESNPEFF != $TEST ]] then - docker pull nfcore/sareksnpeff:dev.GRCh37 - docker tag nfcore/sareksnpeff:dev.GRCh37 nfcore/sareksnpeff:dev.smallGRCh37 -else docker pull nfcore/sarek:dev docker tag nfcore/sarek:dev nfcore/sarek:dev fi diff --git a/bin/run_tests.sh b/bin/run_tests.sh index beb2b77ac6..1a19312a68 100755 --- a/bin/run_tests.sh +++ b/bin/run_tests.sh @@ -2,9 +2,11 @@ set -xeuo pipefail CPUS=2 +PROFILE=docker TEST=ALL TRAVIS_BUILD_DIR=${TRAVIS_BUILD_DIR:-.} TRAVIS=${TRAVIS:-false} +VERBOSE='' while [[ $# -gt 0 ]] do @@ -15,6 +17,15 @@ do shift # past argument shift # past value ;; + -p|--profile) + PROFILE=$2 + shift # past argument + shift # past value + ;; + -v|--verbose) + VERBOSE="-ansi-log false -dump-channels" + shift # past value + ;; -c|--cpus) CPUS=$2 shift # past value @@ -26,25 +37,29 @@ do done function run_sarek() { - nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile test,docker -ansi-log false -dump-channels $@ + nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile test,${PROFILE} ${VERBOSE} --monochrome_logs $@ } if [[ ALL,GERMLINE =~ $TEST ]] then rm -rf data git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data - run_sarek --sample data/testdata/tiny/normal --tools HaplotypeCaller,Strelka --noReports - run_sarek --step recalibrate --sample results/Preprocessing/TSV/duplicateMarked.tsv --noReports + run_sarek --tools=false --sample data/testdata/tiny/normal --noReports + run_sarek --tools=false --sample results/Preprocessing/TSV/duplicateMarked.tsv --step recalibrate --noReports + run_sarek --tools HaplotypeCaller,Strelka --sample results/Preprocessing/TSV/recalibrated.tsv --step variantCalling --noReports + rm -rf .nextflow* results/ work/ fi if [[ ALL,SOMATIC =~ $TEST ]] then - run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports + run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports + rm -rf .nextflow* results/ work/ fi if [[ ALL,TARGETED =~ $TEST ]] then - run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports --targetBED https://github.com/nf-core/test-datasets/raw/sarek/testdata/target.bed + run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports --targetBED https://github.com/nf-core/test-datasets/raw/sarek/testdata/target.bed + rm -rf .nextflow* results/ work/ fi if [[ ALL,ANNOTATEALL,ANNOTATESNPEFF,ANNOTATEVEP =~ $TEST ]] @@ -60,9 +75,11 @@ then ANNOTATOR=merge,snpEFF,VEP fi run_sarek --step annotate --tools ${ANNOTATOR} --sample https://github.com/nf-core/test-datasets/raw/sarek/testdata/vcf/Strelka_1234N_variants.vcf.gz --noReports + rm -rf .nextflow* results/ work/ fi if [[ MULTIPLE =~ $TEST ]] then - run_sarek --sample https://github.com/nf-core/test-datasets/raw/sarek/testdata/tsv/tiny-multiple.tsv --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports + run_sarek --sample https://github.com/nf-core/test-datasets/raw/sarek/testdata/tsv/tiny-multiple-https.tsv --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports + rm -rf .nextflow* results/ work/ fi diff --git a/bin/scrape_software_versions.py b/bin/scrape_software_versions.py index 5667cd24c8..96281d68c5 100755 --- a/bin/scrape_software_versions.py +++ b/bin/scrape_software_versions.py @@ -62,7 +62,7 @@ # Dump to YAML print (''' id: 'software_versions' -section_name: 'nf-core/sarek Software Versions' +section_name: 'nf-core/sarek software versions' section_href: 'https://github.com/nf-core/sarek' plot_type: 'html' description: 'are collected at run time from the software output.' diff --git a/containers/snpeff/Dockerfile b/containers/snpeff/Dockerfile index a0c35d360e..08b47c22b7 100644 --- a/containers/snpeff/Dockerfile +++ b/containers/snpeff/Dockerfile @@ -1,4 +1,4 @@ -FROM nfcore/base:latest +FROM nfcore/base:1.6 LABEL \ author="Maxime Garcia" \ diff --git a/containers/vep/Dockerfile b/containers/vep/Dockerfile index e0bc659d52..06c12a7bb8 100644 --- a/containers/vep/Dockerfile +++ b/containers/vep/Dockerfile @@ -1,4 +1,4 @@ -FROM nfcore/base:latest +FROM nfcore/base:1.6 LABEL \ author="Maxime Garcia" \ diff --git a/docs/annotation.md b/docs/annotation.md new file mode 100644 index 0000000000..718e81b993 --- /dev/null +++ b/docs/annotation.md @@ -0,0 +1,72 @@ +# Annotation + +## Tools + +With Sarek, annotation is done using `snpEff`, `VEP`, or even both consecutively: +- `--tools snpEff` + - To annotate using `snpEff` +- `--tools VEP` + - To annotate using `VEP` +- `--tools snpEff,VEP` + - To annotate using `snpEff` and `VEP` +- `--tools merge` + - To annotate using `snpEff` followed by `VEP` + +VCF produced by Sarek will be annotated if `snpEff` or `VEP` are specified with the `--tools` command. + +In these examples, all command lines will be launched starting with step `annotate`. +It can of course be started directly from any other step instead. + +## Using genome specific containers + +Sarek has already designed containers with `snpEff` and `VEP` files for `GRCh37`, `GRCh38` and `GRCm38`. +Default settings will run using these containers. + +The main Sarek container has also `snpEff` and `VEP` installed, but without the cache files that can be downloaded separatelly. + +## Using downloaded cache + +Both `snpEff` and `VEP` enable usage of cache. +If cache is available on the machine where Sarek is run, it is possible to run annotation using cache. +You need to specify the cache directory using `--snpEff_cache` and `--vep_cache` in the command lines or within configuration files. +The cache will only be used when `--annotation_cache` and cache directories are specified (either in command lines or in a configuration file). + +Example: +```bash +nextflow run nf-core/sarek/main.nf --tools snpEff --step annotate --sample file.vcf.gz --snpEff_cache /Path/To/snpEffCache --annotation_cache +nextflow run nf-core/sarek/main.nf --tools VEP --step annotate --sample file.vcf.gz --vep_cache /Path/To/vepCache --annotation_cache +``` + +## Using VEP CADD plugin + +To enable the use of the VEP CADD plugin: + - Download the CADD files + - Specify them (either on the command line, like in the example or in a configuration file) + - use the `--cadd_cache` flag + +Example: +```bash +nextflow run nf-core/sarek/main.nf --step annotate --tools VEP --sample file.vcf.gz --cadd_cache \ + --cadd_InDels /PathToCADD/InDels.tsv.gz \ + --cadd_InDels_tbi /PathToCADD/InDels.tsv.gz.tbi \ + --cadd_WG_SNVs /PathToCADD/whole_genome_SNVs.tsv.gz \ + --cadd_WG_SNVs_tbi /PathToCADD/whole_genome_SNVs.tsv.gz.tbi +``` + +### Downloading CADD files + +An helper script has been designed to help downloading CADD files. +Such files are meant to be share between multiple users, so this script is mainly meant for people administrating servers, clusters and advanced users. +```bash +nextflow run build.nf --cadd_cache /Path/To/CADDcache --cadd_version --genome +``` + +## Using VEP GeneSplicer plugin + +To enable the use of the VEP GeneSplicer plugin: + - use the `--genesplicer` flag + +Example: +``` +nextflow run annotate.nf --tools VEP --sample file.vcf.gz --genesplicer +``` diff --git a/docs/containers.md b/docs/containers.md new file mode 100644 index 0000000000..14f139c24f --- /dev/null +++ b/docs/containers.md @@ -0,0 +1,80 @@ +# Containers + +Our main container is designed using [Conda](https://conda.io/) to install all tools used in Sarek: +- [sarek](#sarek-) + +For annotation, the main container can be used, but the cache has to be downloaded, or additional containers are available with cache (see [extra annotation documentation](annotation.md)): +- [sareksnpeff](#sareksnpeff-) +- [sarekvep](#sarekvep-) + +## What is actually inside the containers + +### sarek [![sarek-docker status][sarek-docker-badge]][sarek-docker-link] + +- Based on `nfcore/base:latest` +- Contain **[AlleleCount][allelecount-link]** 4.0.2 +- Contain **[BCFTools][bcftools-link]** 1.9 +- Contain **[BWA][bwa-link]** 0.7.17 +- Contain **[FastQC][fastqc-link]** 0.11.8 +- Contain **[FreeBayes][freebayes-link]** 1.2.0 +- Contain **[GATK4][gatk4-link]** 4.1.2.0 +- Contain **[GeneSplicer][genesplicer-link]** 1.0 +- Contain **[HTSlib][htslib-link]** 1.9 +- Contain **[IGVtools][igvtools-link]** 2.3.93 +- Contain **[Manta][manta-link]** 1.5.0 +- Contain **[MultiQC][multiqc-link]** 1.7 +- Contain **[Qualimap][qualimap-link]** 2.2.2b +- Contain **[R][r-link]** 3.5.1 +- Contain **[RColorBrewer][rcolorbrewer-link]** 1.1 +- Contain **[Rtracklayer][rtracklayer-link]** 1.42.1 +- Contain **[samtools][samtools-link]** 1.9 +- Contain **[snpEff][snpeff-link]** 4.3.1t +- Contain **[Strelka2][strelka-link]** 2.9.10 +- Contain **[VCFanno][vcfanno-link]** 0.3.1 +- Contain **[VCFtools][vcftools-link]** 0.1.16 +- Contain **[VEP][vep-link]** 96.0 + +### sareksnpeff [![sareksnpeff-docker status][sareksnpeff-docker-badge]][sareksnpeff-docker-link] + +- Based on `nfcore/base:latest` +- Contain **[snpEff][snpeff-link]** 4.3.1t +- Contain cache for `GRCh37`, `GRCh38`, or `GRCm38` + +### sarekvep [![sarekvep-docker status][sarekvep-docker-badge]][sarekvep-docker-link] + +- Based on `nfcore/base:latest` +- Contain **[GeneSplicer][genesplicer-link]** 1.0 +- Contain **[VEP][vep-link]** 96.0 +- Contain cache for `GRCh37`, `GRCh38`, or `GRCm38` + +## Building your own +Our containers are designed using [Conda](https://conda.io/). +The `environment.yml` file can easilly be modified if particular versions of tools are more suited to your needs. + +[allelecount-link]: https://github.com/cancerit/alleleCount +[bcftools-link]: https://github.com/samtools/bcftools +[bwa-link]: https://github.com/lh3/bwa +[fastqc-link]: http://www.bioinformatics.babraham.ac.uk/projects/fastqc/ +[freebayes-link]: https://github.com/ekg/freebayes +[gatk4-link]: https://github.com/broadinstitute/gatk +[genesplicer-link]: https://ccb.jhu.edu/software/genesplicer/ +[htslib-link]: https://github.com/samtools/htslib +[igvtools-link]: http://software.broadinstitute.org/software/igv/ +[manta-link]: https://github.com/Illumina/manta +[multiqc-link]: https://github.com/ewels/MultiQC/ +[qualimap-link]: http://qualimap.bioinfo.cipf.es +[r-link]: https://www.r-project.org/ +[rcolorbrewer-link]: https://CRAN.R-project.org/package=RColorBrewer +[rtracklayer-link]: https://www.bioconductor.org/packages/release/bioc/html/rtracklayer.html +[samtools-link]: https://github.com/samtools/samtools +[sarek-docker-badge]: https://img.shields.io/docker/automated/nfcore/sarek.svg +[sarek-docker-link]: https://hub.docker.com/r/nfcore/sarek +[snpeff-link]: http://snpeff.sourceforge.net/ +[sareksnpeff-docker-badge]: https://img.shields.io/docker/automated/nfcore/sareksnpeff.svg +[sareksnpeff-docker-link]: https://hub.docker.com/r/nfcore/sareksnpeff +[strelka-link]: https://github.com/Illumina/strelka +[vcfanno-link]: https://github.com/brentp/vcfanno +[vcftools-link]: https://vcftools.github.io/index.html +[vep-link]: https://github.com/Ensembl/ensembl-vep +[sarekvep-docker-badge]: https://img.shields.io/docker/automated/nfcore/sarekvep.svg +[sarekvep-docker-link]: https://hub.docker.com/r/nfcore/sarekvep diff --git a/docs/input.md b/docs/input.md new file mode 100644 index 0000000000..49ec48d344 --- /dev/null +++ b/docs/input.md @@ -0,0 +1,115 @@ +# TSV file for sample(s) + +Input files for Sarek can be specified using a TSV file given to the `--sample` command. +The TSV file is a Tab Separated Value file with columns: +* `subject gender status sample lane fastq1 fastq2` for step `mapping` with paired-end FASTQs +* `subject gender status sample lane bam` for step `mapping` with unmapped BAMs +* `subject gender status sample bam bai recaltable` for step `recalibrate` with BAMs +* `subject gender status sample bam bai` for step `variantcalling` with BAMs + +The content of these columns is quite straight-forward: +* `subject` designate the subject, it should be the ID of the Patient, and it must design only one patient +* `gender` is the gender of the Patient, (XX or XY) +* `status` is the status of the Patient, (0 for Normal or 1 for Tumor) +* `sample` designate the Sample, it should be the ID of the Sample (it is possible to have more than one tumor sample for each patient), it should design only one sample +* `lane` is used when the sample is multiplexed on several lanes +* `fastq1` is the path to the first pair of the fastq file +* `fastq2` is the path to the second pair of the fastq file +* `bam` is the bam file +* `bai` is the bam index file +* `recaltable` is the recalibration table + +It is recommended to add the absolute path of the files, but relative path should work also. +Note, the delimiter is the tab (`\t`) character: + +All examples are given for a normal/tumor pair. +If no tumors are listed in the TSV file, then the workflow will proceed as if it is a normal sample instead of a normal/tumor pair. + +Sarek will output results is a different directory for each sample. +If multiple samples are specified in the TSV file, Sarek will consider all files to be from different samples. +Multiple TSV files can be specified if the path is enclosed in quotes. + +Somatic variant calling output will be in a specific directory for each normal/tumor pair. + +# Example TSV file for a normal/tumor pair with FASTQ files + +In this sample for the normal case there are 3 read groups, and 2 for the tumor. + +``` +G15511 XX 0 C09DFN C09DF_1 pathToFiles/C09DFACXX111207.1_1.fastq.gz pathToFiles/C09DFACXX111207.1_2.fastq.gz +G15511 XX 0 C09DFN C09DF_2 pathToFiles/C09DFACXX111207.2_1.fastq.gz pathToFiles/C09DFACXX111207.2_2.fastq.gz +G15511 XX 0 C09DFN C09DF_3 pathToFiles/C09DFACXX111207.3_1.fastq.gz pathToFiles/C09DFACXX111207.3_2.fastq.gz +G15511 XX 1 D0ENMT D0ENM_1 pathToFiles/D0ENMACXX111207.1_1.fastq.gz pathToFiles/D0ENMACXX111207.1_2.fastq.gz +G15511 XX 1 D0ENMT D0ENM_2 pathToFiles/D0ENMACXX111207.2_1.fastq.gz pathToFiles/D0ENMACXX111207.2_2.fastq.gz +``` + +# Example TSV file for a normal/tumor pair with BAM files + +In this sample for the normal case there are 3 read groups, and 2 for the tumor. + +``` +G15511 XX 0 C09DFN C09DF_1 pathToFiles/C09DFAC_1.bam +G15511 XX 0 C09DFN C09DF_2 pathToFiles/C09DFAC_2.bam +G15511 XX 0 C09DFN C09DF_3 pathToFiles/C09DFAC_3.bam +G15511 XX 1 D0ENMT D0ENM_1 pathToFiles/D0ENMAC_1.bam +G15511 XX 1 D0ENMT D0ENM_2 pathToFiles/D0ENMAC_2.bam +``` + +# Example TSV file for a normal/tumor pair with recalibrated BAM files + +The same way, if you have recalibrated BAMs and their indexes, you should use a structure like: + +``` +G15511 XX 0 C09DFN pathToFiles/G15511.C09DFN.md.real.bam pathToFiles/G15511.C09DFN.md.real.bai +G15511 XX 1 D0ENMT pathToFiles/G15511.D0ENMT.md.real.bam pathToFiles/G15511.D0ENMT.md.real.bai +``` + +## Input FASTQ file name best practices + +The input folder, containing the FASTQ files for one individual (ID) should be organized into one subfolder for every sample. +All fastq files for that sample should be collected here. + +``` +ID ++--sample1 ++------sample1_lib_flowcell-index_lane_R1_1000.fastq.gz ++------sample1_lib_flowcell-index_lane_R2_1000.fastq.gz ++------sample1_lib_flowcell-index_lane_R1_1000.fastq.gz ++------sample1_lib_flowcell-index_lane_R2_1000.fastq.gz ++--sample2 ++------sample2_lib_flowcell-index_lane_R1_1000.fastq.gz ++------sample2_lib_flowcell-index_lane_R2_1000.fastq.gz ++--sample3 ++------sample3_lib_flowcell-index_lane_R1_1000.fastq.gz ++------sample3_lib_flowcell-index_lane_R2_1000.fastq.gz ++------sample3_lib_flowcell-index_lane_R1_1000.fastq.gz ++------sample3_lib_flowcell-index_lane_R2_1000.fastq.gz +``` + +Fastq filename structure: + +- `sample_lib_flowcell-index_lane_R1_1000.fastq.gz` and +- `sample_lib_flowcell-index_lane_R2_1000.fastq.gz` + +Where: + +- `sample` = sample id +- `lib` = indentifier of libaray preparation +- `flowcell` = identifyer of flow cell for the sequencing run +- `lane` = identifier of the lane of the sequencing run + +Read group information will be parsed from fastq file names according to this: + +- `RGID` = "sample_lib_flowcell_index_lane" +- `RGPL` = "Illumina" +- `PU` = sample +- `RGLB` = lib + +# Path to a FASTQ directory for a single normal sample + +Input files for Sarek can be specified using the path to a FASTQ directory given to the `--sample` command only with the `mapping` step. + +# VCF files for annotation + +Input files for Sarek can be specified using the path to a VCF directory given to the `--sample` command only with the `annotate` step. +Multiple VCF files can be specified if the path is enclosed in quotes. diff --git a/docs/output.md b/docs/output.md index 65b4509093..ec70888d40 100644 --- a/docs/output.md +++ b/docs/output.md @@ -1,41 +1,222 @@ # nf-core/sarek: Output -This document describes the output produced by the pipeline. Most of the plots are taken from the MultiQC report, which summarises results at the end of the pipeline. - - +This document describes the output produced by the pipeline. +Most of the plots are taken from the MultiQC report, which summarises results at the end of the pipeline. ## Pipeline overview The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes data using the following steps: -* [FastQC](#fastqc) - read quality control -* [MultiQC](#multiqc) - aggregate report, describing results of the whole pipeline +1. **Preprocessing** _(based on [GATK best practices](https://software.broadinstitute.org/gatk/best-practices/))_ + * Map reads to Reference + * [BWA](#BWA) + * Mark Duplicates + * [GATK MarkDuplicates](#MarkDuplicates) + * Base (Quality Score) Recalibration + * [GATK BaseRecalibrator](#BaseRecalibrator) + * [GATK GatherBQSRReports](#GatherBQSRReports) + * [GATK ApplyBQSR](#ApplyBQSR) +2. **Variant calling** + * SNVs and small indels + * [Freebayes](#Freebayes) + * [GATK HaplotypeCaller](#HaplotypeCaller) + * [GATK GenotypeGVCFs](#GenotypeGVCFs) + * [GATK MuTect2](#MuTect2) + * [Strelka2](#Strelka2) + * Structural variants + * [Manta](#Manta) + * Sample heterogeneity, ploidy and CNVs + * [alleleCounter](#alleleCounter) + * [ConvertAlleleCounts](#ConvertAlleleCounts) + * [ASCAT](#ASCAT) + * [samtools mpileup](#mpileup) + * [Control-FREEC](#Control-FREEC) +3. **Annotation** + * Variant annotation + * [snpEff](#snpEff) + * [VEP (Variant Effect Predictor)](#VEP) +4. **QC and Reporting** + * QC + * [FastQC](#FastQC) + * [Qualimap bamqc](#bamQC) + * [GATK MarkDuplicates](#MarkDuplicates-reports) + * [samtools stats](#Samtools-stats) + * [bcftools stats](#BCFtools) + * [VCFtools](#VCFtools) + * [snpeff](#snpEff-reports) + * Reporting + * [MultiQC](#MultiQC) + +## Preprocessing +Sarek preprocessing raw FastQ files or unmapped BAM files is based on [GATK best practices](https://software.broadinstitute.org/gatk/best-practices/)). +BAM files with Recalibration tables can also be used as an input to start with the recalibration of said BAM files. + +### BWA +[BWA](http://bio-bwa.sourceforge.net/) + +### MarkDuplicates +[GATK MarkDuplicates](https://github.com/broadinstitute/gatk) + +### BaseRecalibrator +[GATK BaseRecalibrator](https://github.com/broadinstitute/gatk) + +### GatherBQSRReports +[GATK GatherBQSRReports](https://github.com/broadinstitute/gatk) + +### ApplyBQSR +[GATK ApplyBQSR](https://github.com/broadinstitute/gatk) + +## Variant Calling + +### Freebayes +[Freebayes](https://github.com/ekg/freebayes) + +### HaplotypeCaller +[GATK HaplotypeCaller](https://github.com/broadinstitute/gatk) + +### GenotypeGVCFs +[GATK GenotypeGVCFs](https://github.com/broadinstitute/gatk) + +### MuTect2 +[MuTect2](https://github.com/broadinstitute/gatk) + +### Strelka2 +[Strelka2](https://github.com/Illumina/strelka) + +### Manta +[Manta](https://github.com/Illumina/manta) + +### alleleCounter + +### ConvertAlleleCounts + +### ASCAT + +### samtools mpileup + +### Control-FREEC + +## Annotation + +### snpEff +[snpeff](http://snpeff.sourceforge.net/) -## FastQC -[FastQC](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/) gives general quality metrics about your reads. It provides information about the quality score distribution across your reads, the per base sequence content (%T/A/G/C). You get information about adapter contamination and other overrepresented sequences. +### VEP +[VEP (Variant Effect Predictor)](https://www.ensembl.org/info/docs/tools/vep/index.html) + +## QC and reports + +### FastQC +[FastQC](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/) gives general quality metrics about your reads. +It provides information about the quality score distribution across your reads, the per base sequence content (%T/A/G/C). +You get information about adapter contamination and other overrepresented sequences. For further reading and documentation see the [FastQC help](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/). -> **NB:** The FastQC plots displayed in the MultiQC report shows _untrimmed_ reads. They may contain adapter sequence and potentially regions with low quality. To see how your reads look after trimming, look at the FastQC reports in the `trim_galore` directory. +**Output directory: `results/Reports/[SAMPLE]/fastqc`** + +* `sample_R1_XXX_fastqc.html` and `sample_R2_XXX_fastqc.html` + * FastQC report, containing quality metrics for each pair of the raw fastq files +* `sample_R1_XXX_fastqc.zip` and `sample_R2_XXX_fastqc.zip` + * zip file containing the FastQC reports, tab-delimited data files and plot images + +### bamQC +[Qualimap bamqc](http://qualimap.bioinfo.cipf.es/) reports information for the evaluation of the quality of the provided alignment data. In short, the basic statistics of the alignment (number of reads, coverage, GC-content, etc.) are summarized and a number of useful graphs are produced. + +Plot will show: +* Stats by non-reference allele frequency, depth distribution, stats by quality and per-sample counts, singleton stats, etc. + +**Output directory: `results/Reports/[SAMPLE]/bamQC`** +* `VariantCaller_Sample.bcf.tools.stats.out` + * RAW statistics used by MultiQC + +For more information about how to use Qualimap bamqc reports, see [Qualimap bamqc manual](http://qualimap.bioinfo.cipf.es/doc_html/analysis.html#id7) + +### MarkDuplicates -reports +[GATK MarkDuplicates](https://github.com/broadinstitute/gatk) locates and tags duplicate reads in a BAM or SAM file, where duplicate reads are defined as originating from a single fragment of DNA. +Duplicates can arise during sample preparation e.g. +library construction using PCR. +Duplicate reads can also result from a single amplification cluster, incorrectly detected as multiple clusters by the optical sensor of the sequencing instrument. +These duplication artifacts are referred to as optical duplicates. + +Plot will show: +* Duplication metrics + +**Output directory: `results/Reports/[SAMPLE]/MarkDuplicates`** +* `Sample.bam.metrics` + * RAW statistics used by MultiQC + +For more information about how to use MarkDuplicates reports, see [MarkDuplicates manual](https://software.broadinstitute.org/gatk/documentation/tooldocs/4.1.2.0/picard_sam_markduplicates_MarkDuplicates.php) + +### samtools stats +[samtools stats](https://www.htslib.org/doc/samtools.html) collects statistics from BAM files and outputs in a text format. +Plots will show: +* Alignment metrics. + +**Output directory: `results/Reports/[SAMPLE]/SamToolsStats`** +* `Sample.bam.samtools.stats.out` + * RAW statistics used by MultiQC + +For more information about how to use samtools stats reports, see [samtools stats manual](http://www.htslib.org/doc/samtools.html#COMMANDS_AND_OPTIONS) + +### bcftools stats +[bcftools stats](https://samtools.github.io/bcftools/) is a program for variant calling and manipulating files in the Variant Call Format. +Plot will show: +* Stats by non-reference allele frequency, depth distribution, stats by quality and per-sample counts, singleton stats, etc. + +**Output directory: `results/Reports/[SAMPLE]/BCFToolsStats`** +* `VariantCaller_Sample.bcf.tools.stats.out` + * RAW statistics used by MultiQC + +For more information about how to use bcftools stats reports, see [bcftools stats manual](https://samtools.github.io/bcftools/bcftools.html#stats) + +### VCFtools +[VCFtools](https://vcftools.github.io/) is a program package designed for working with VCF files. +Plots will show: +* the summary counts of each type of transition to transversion ratio for each FILTER category. +* the transition to transversion ratio as a function of alternative allele count (using only bi-allelic SNPs). +* the transition to transversion ratio as a function of SNP quality threshold (using only bi-allelic SNPs). + +**Output directory: `results/Reports/[SAMPLE]/VCFTools`** +* `VariantCaller_Sample.FILTER.summary` + * RAW statistics used by MultiQC +* `VariantCaller_Sample.TsTv.count` + * RAW statistics used by MultiQC +* `VariantCaller_Sample.TsTv.qual` + * RAW statistics used by MultiQC + +For more information about how to use VCFtools reports, see [VCFtools manual](https://vcftools.github.io/man_latest.html#OUTPUT%20OPTIONS) -**Output directory: `results/fastqc`** +### snpEff reports +[snpeff](http://snpeff.sourceforge.net/) is a genetic variant annotation and effect prediction toolbox. +It annotates and predicts the effects of variants on genes (such as amino acid changes). +Plots will shows : +* locations of detected variants in the genome and the number of variants for each location. +* the putative impact of detected variants and the number of variants for each impact. +* the effect of variants at protein level and the number of variants for each effect type. +* the quantity as function of the variant quality score. -* `sample_fastqc.html` - * FastQC report, containing quality metrics for your untrimmed raw fastq files -* `zips/sample_fastqc.zip` - * zip file containing the FastQC report, tab-delimited data file and plot images +**Output directory: `results/Reports/[SAMPLE]/snpEff`** +* `VariantCaller_Sample_snpEff.csv` + * RAW statistics used by MultiQC +* `VariantCaller_Sample_snpEff.html` + * Statistics to be visualised with a web browser +* `VariantCaller_Sample_snpEff.txt` + * TXT (tab separated) summary counts for variants affecting each transcript and gene +For more information about how to use snpEff reports, see [snpEff manual](http://snpeff.sourceforge.net/SnpEff_manual.html#outputSummary) -## MultiQC -[MultiQC](http://multiqc.info) is a visualisation tool that generates a single HTML report summarising all samples in your project. Most of the pipeline QC results are visualised in the report and further statistics are available in within the report data directory. +### MultiQC +[MultiQC](http://multiqc.info) is a visualisation tool that generates a single HTML report summarising all samples in your project. +Most of the pipeline QC results are visualised in the report and further statistics are available in within the report data directory. The pipeline has special steps which allow the software versions used to be reported in the MultiQC output for future traceability. -**Output directory: `results/multiqc`** +**Output directory: `results/Reports/MultiQC`** -* `Project_multiqc_report.html` +* `multiqc_report.html` * MultiQC report - a standalone HTML file that can be viewed in your web browser -* `Project_multiqc_data/` +* `multiqc_data/` * Directory containing parsed statistics from the different tools used in the pipeline For more information about how to use MultiQC reports, see [http://multiqc.info](http://multiqc.info) diff --git a/docs/reference.md b/docs/reference.md index 5d772a2733..55d267d023 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -2,19 +2,14 @@ ## AWS iGenomes Sarek is using [AWS iGenomes](https://ewels.github.io/AWS-iGenomes/), which facilitate storing and sharing references. -Both `GRCh37` and `GRCh38` are available with `--genome GRCh37` or `--genome GRCh38` respectively with any profile using the `conf/igenomes.config` file, or you can specify it with `-c conf/igenomes.config`. - Sarek currently uses `GRCh38` by default. - -Settings in `igenomes.config` can be tailored to your needs. - -The [`build.nf`](#buildnf) script is used to build the indexes for the reference test. - +Both `GRCh37` and `GRCh38` are available with `--genome GRCh37` or `--genome GRCh38` respectively with any profile using the `conf/igenomes.config` file, or you can specify it with `-c conf/igenomes.config`. Use `--genome smallGRCh37` to map against a small reference genome based on GRCh37. +Settings in `igenomes.config` can be tailored to your needs. ## build.nf -The `build.nf` script can build the files needed for smallGRCh37. +The [`build.nf`](#buildnf) script is used to build reference needed for smallGRCh37. ``` nextflow run build.nf diff --git a/docs/usage.md b/docs/usage.md index ee1162992a..bf63ec88fb 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -11,11 +11,29 @@ * [Reproducibility](#reproducibility) * [Main arguments](#main-arguments) * [`-profile`](#-profile) - * [`--reads`](#--reads) - * [`--singleEnd`](#--singleend) + * [`--sample`](#--sample) + * [`--noGVCF`](#--nogvcf) + * [`--noReports`](#--noreports) + * [`--nucleotidesPerSecond`](#--nucleotidespersecond) + * [`--step`](#--step) + * [`--tools`](#--tools) + * [`--noStrelkaBP`](#--nostrelkabp) + * [`--targetBED`](#--targetbed) * [Reference genomes](#reference-genomes) * [`--genome` (using iGenomes)](#--genome-using-igenomes) - * [`--fasta`](#--fasta) + * [`--acLoci`](#--acloci) + * [`--acLociGC`](#--aclocigc) + * [`--bwaIndex`](#--bwaindex) + * [`--dbsnp`](#--dbsnp) + * [`--dbsnpIndex`](#--dbsnpindex) + * [`--genomeDict`](#--genomedict) + * [`--genomeFile`](#--genomefile) + * [`--genomeIndex`](#--genomeindex) + * [`--intervals`](#--intervals) + * [`--knownIndels`](#--knownindels) + * [`--knownIndelsIndex`](#--knownindelsindex) + * [`--snpeffDb`](#--snpeffdb) + * [`--vepCacheVersion`](#--vepcacheversion) * [`--igenomesIgnore`](#--igenomesignore) * [Job resources](#job-resources) * [Automatic resubmission](#automatic-resubmission) @@ -25,6 +43,7 @@ * [`--awsregion`](#--awsregion) * [Other command line parameters](#other-command-line-parameters) * [`--outdir`](#--outdir) + * [`--sequencing_center`](#--sequencing_center) * [`--email`](#--email) * [`-name`](#-name) * [`-resume`](#-resume) @@ -39,7 +58,6 @@ * [`--multiqc_config`](#--multiqc_config) - ## Introduction Nextflow handles job submissions on SLURM or other environments, and supervises running the jobs. Thus the Nextflow process must run until the pipeline is finished. We recommend that you put the process running in the background through `screen` / `tmux` or similar tool. Alternatively you can run nextflow within a cluster job submitted your job scheduler. @@ -49,13 +67,11 @@ It is recommended to limit the Nextflow Java virtual machines memory. We recomme NXF_OPTS='-Xms1g -Xmx4g' ``` - - ## Running the pipeline The typical command for running the pipeline is as follows: ```bash -nextflow run nf-core/sarek --reads '*_R{1,2}.fastq.gz' -profile docker +nextflow run nf-core/sarek --sample sample.tsv -profile docker ``` This will launch the pipeline with the `docker` configuration profile. See below for more information about profiles. @@ -69,6 +85,10 @@ results # Finished results (configurable, see below) # Other nextflow hidden files, eg. history of pipeline runs and old logs. ``` +The nf-core/sarek pipeline comes with more documentation about running the pipeline, found in the `docs/` directory: + * [Extra Documentation on variant calling](docs/variantcalling.md) + * [Extra Documentation on annotation](docs/annotation.md) + ### Updating the pipeline When you run the above command, Nextflow automatically pulls the pipeline code from GitHub and stores it as a cached version. When running the pipeline after this, it will always use the cached version if available - even if the pipeline has been updated since. To make sure that you're running the latest version of the pipeline, make sure that you regularly update the cached version of the pipeline: @@ -79,11 +99,10 @@ nextflow pull nf-core/sarek ### Reproducibility It's a good idea to specify a pipeline version when running the pipeline on your data. This ensures that a specific version of the pipeline code and software are used when you run your pipeline. If you keep using the same tag, you'll be running the same version of the pipeline, even if there have been changes to the code since. -First, go to the [nf-core/sarek releases page](https://github.com/nf-core/sarek/releases) and find the latest version number - numeric only (eg. `1.3.1`). Then specify this when running the pipeline with `-r` (one hyphen) - eg. `-r 1.3.1`. +First, go to the [nf-core/sarek releases page](https://github.com/nf-core/sarek/releases) and find the latest version number - numeric only (eg. `2.5.0`). Then specify this when running the pipeline with `-r` (one hyphen) - eg. `-r 2.5.0`. This version number will be logged in reports when you run the pipeline, so that you'll know what you used when you look back in the future. - ## Main arguments ### `-profile` @@ -106,76 +125,184 @@ If `-profile` is not specified at all the pipeline will be run locally and expec * A profile with a complete configuration for automated testing * Includes links to test data so needs no other parameters - -### `--reads` -Use this to specify the location of your input FastQ files. For example: +### `--sample` +Use this to specify the location of your input TSV file, on `mapping`, `recalibrate` and `variantcalling` steps. +For example: ```bash ---reads 'path/to/data/sample_*_{1,2}.fastq' +--sample sample.tsv ``` +Multiple TSV files can be specified if the path must be enclosed in quotes -Please note the following requirements: - -1. The path must be enclosed in quotes -2. The path must have at least one `*` wildcard character -3. When using the pipeline with paired end data, the path must use `{1,2}` notation to specify read pairs. +Use this to specify the location to a directory on `mapping` step with a single germline sample only. +For example: -If left unspecified, a default pattern is used: `data/*{1,2}.fastq.gz` +```bash +--sample PathToDirectory +``` -### `--singleEnd` -By default, the pipeline expects paired-end data. If you have single-end data, you need to specify `--singleEnd` on the command line when you launch the pipeline. A normal glob pattern, enclosed in quotation marks, can then be used for `--reads`. For example: +Use this to specify the location of your VCF input file on `annotate` step. +For example: ```bash ---singleEnd --reads '*.fastq' +--sample sample.vcf ``` +Multiple VCF files can be specified if the path must be enclosed in quotes + +### `--noGVCF` +Use this to disable g.vcf from `HaplotypeCaller`. + +### `--noReports` +Use this to disable all QC an Reporting tools. + +### `--nucleotidesPerSecond` +Use this to estimate of how many seconds it will take to call variants on any interval, the default value is `1000` is it's not specified in the `.bed` file. -It is not possible to run a mixture of single-end and paired-end files in one run. +### `--step` +Use this to specify the starting step: +Default `mapping` +Available: `mapping`, `recalibrate`, `variantcalling` and `annotate` +### `--tools` +Use this to specify the tools to run: +Available: `ASCAT`, `ControlFREEC`, `FreeBayes`, `HaplotypeCaller`, `Manta`, `mpileup`, `MuTect2`, `Strelka` + +### `--noStrelkaBP` +Use this not to use `Manta` `candidateSmallIndels` for `Strelka` as Best Practice. + +### `--targetBED` +Use this to specify the target BED file for targeted or whole exome sequencing. ## Reference genomes The pipeline config files come bundled with paths to the illumina iGenomes reference index files. If running with docker or AWS, the configuration is set up to use the [AWS-iGenomes](https://ewels.github.io/AWS-iGenomes/) resource. ### `--genome` (using iGenomes) -There are 31 different species supported in the iGenomes references. To run the pipeline, you must specify which to use with the `--genome` flag. +There are 2 different species supported by Sarek in the iGenomes references. To run the pipeline, you must specify which to use with the `--genome` flag. -You can find the keys to specify the genomes in the [iGenomes config file](../conf/igenomes.config). Common genomes that are supported are: +You can find the keys to specify the genomes in the [iGenomes config file](../conf/igenomes.config). Genomes that are supported are: * Human * `--genome GRCh37` -* Mouse - * `--genome GRCm38` -* _Drosophila_ - * `--genome BDGP6` -* _S. cerevisiae_ - * `--genome 'R64-1-1'` - -> There are numerous others - check the config file for more. + * `--genome GRCh38` Note that you can use the same configuration setup to save sets of reference files for your own use, even if they are not part of the iGenomes resource. See the [Nextflow documentation](https://www.nextflow.io/docs/latest/config.html) for instructions on where to save such a file. The syntax for this reference configuration is as follows: - - ```nextflow params { genomes { 'GRCh37' { - fasta = '' // Used if no star index given + acLoci = '' + acLociGC = '' + bwaIndex = '' + dbsnp = '' + dbsnpIndex = '' + genomeDict = '' + genomeFile = '' + genomeIndex = '' + intervals = '' + knownIndels = '' + knownIndelsIndex = '' + snpeffDb = '' + vepCacheVersion = '' } // Any number of additional genomes, key is used with --genome } } ``` - -### `--fasta` +### `--acLoci` +If you prefer, you can specify the full path to your reference genome when you run the pipeline: + +```bash +--acLoci '[path to the acLoci file]' +``` + +### `--acLociGC` +If you prefer, you can specify the full path to your reference genome when you run the pipeline: + +```bash +--acLociGC '[path to the acLociGC file]' +``` + +### `--bwaIndex` +If you prefer, you can specify the full path to your reference genome when you run the pipeline: + +```bash +--bwaIndex '[path to the bwa indexes]' +``` + +### `--dbsnp` +If you prefer, you can specify the full path to your reference genome when you run the pipeline: + +```bash +--dbsnp '[path to the dbsnp file]' +``` + +### `--dbsnpIndex` +If you prefer, you can specify the full path to your reference genome when you run the pipeline: + +```bash +--dbsnpIndex '[path to the dbsnp index]' +``` + +### `--genomeDict` +If you prefer, you can specify the full path to your reference genome when you run the pipeline: + +```bash +--genomeDict '[path to the genomeDict file]' +``` + +### `--genomeFile` If you prefer, you can specify the full path to your reference genome when you run the pipeline: ```bash ---fasta '[path to Fasta reference]' +--genomeFile '[path to the genome file]' +``` + +### `--genomeIndex` +If you prefer, you can specify the full path to your reference genome when you run the pipeline: + +```bash +--genomeIndex '[path to the genome Index]' +``` + +### `--intervals` +If you prefer, you can specify the full path to your reference genome when you run the pipeline: + +```bash +--intervals '[path to the intervals file]' +``` + +### `--knownIndels` +If you prefer, you can specify the full path to your reference genome when you run the pipeline: + +```bash +--knownIndels '[path to the knownIndels file]' +``` + +### `--knownIndelsIndex` +If you prefer, you can specify the full path to your reference genome when you run the pipeline: + +```bash +--knownIndelsIndex '[path to the knownIndels index]' +``` + +### `--snpeffDb` +If you prefer, you can specify the DB version when you run the pipeline: + +```bash +--snpeffDb '[version of the snpEff DB]' +``` + +### `--vepCacheVersion` +If you prefer, you can specify the cache version when you run the pipeline: + +```bash +--vepCacheVersion '[version of the VEP cache]' ``` ### `--igenomesIgnore` @@ -203,11 +330,12 @@ Please make sure to also set the `-w/--work-dir` and `--outdir` parameters to a ## Other command line parameters - - ### `--outdir` The output directory where the results will be saved. +### `--sequencing_center` +The sequencing center that will be used in the BAM CN field + ### `--email` 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. diff --git a/environment.yml b/environment.yml index 528fe6ca26..891322f26e 100644 --- a/environment.yml +++ b/environment.yml @@ -13,7 +13,7 @@ dependencies: - bwa=0.7.17 - cancerit-allelecount=4.0.2 - control-freec=11.4 - - ensembl-vep=96.0 + - ensembl-vep=95.2 - fastqc=0.11.8 - freebayes=1.2.0 - gatk4=4.1.2.0 diff --git a/main.nf b/main.nf index cf73043548..44cbb28c91 100644 --- a/main.nf +++ b/main.nf @@ -31,26 +31,31 @@ def helpMessage() { nextflow run nf-core/sarek --sample sample.tsv -profile docker Mandatory arguments: - --sample Path to TSV input file + --sample Path to input TSV file on mapping, recalibrate and variantcalling steps Multiple TSV files can be specified with quotes - Works also with a directory on mapping step with germline sample only + Works also with the path to a directory on mapping step with a single germline sample only + Alternatively, path to VCF input file on annotate step + Multiple VCF files can be specified with quotes + -profile Configuration profile to use. Can use multiple (comma separated) Available: conda, docker, singularity, awsbatch, test and more. Options: --genome Name of iGenomes reference - --noGVCF no g.vcf output from HaplotypeCaller - --noReports disable QC reports + --noGVCF No g.vcf output from HaplotypeCaller + --noStrelkaBP Will not use Manta candidateSmallIndels for Strelka as Best Practice + --noReports Disable all QC reports --nucleotidesPerSecond To estimate interval size by default 1000.0 - --sequencing_center Name of sequencing center to be displayed in BAM file --step Specify starting step - Available: Mapping, Recalibrate, VariantCalling + Available: Mapping, Recalibrate, VariantCalling, Annotate Default: Mapping - --strelkaBP Use Manta candidateSmallIndels for Strelka as Best Practice - --targetBED target BED file for targeted sequencing + --targetBED Target BED file for targeted or whole exome sequencing --tools Specify tools to use for variant calling Available: ASCAT, ControlFREEC, FreeBayes, HaplotypeCaller Manta, mpileup, MuTect2, Strelka + Default: HaplotypeCaller, Manta, Strelka + --annotateTools Specify from which tools Sarek will annotate VCF, only for step annotate + Available: HaplotypeCaller, Manta, MuTect2, Strelka References If not specified in the configuration file or you wish to overwrite any of the references. --acLoci acLoci file @@ -69,6 +74,8 @@ def helpMessage() { Other options: --outdir The output directory where the results will be saved + --sequencing_center Name of sequencing center to be displayed in BAM file + --monochrome_logs Logs will be without colors --email 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 --maxMultiqcEmailFileSize Theshold size for MultiQC report to be attached in notification email. If file generated by pipeline exceeds the threshold, it will not be attached (Default: 25MB) -name Name for the pipeline run. If not specified, Nextflow will automatically generate a random mnemonic @@ -94,87 +101,85 @@ if (params.genomes && params.genome && !params.genomes.containsKey(params.genome // Default value for params params.annotateTools = null params.annotation_cache = null +params.cadd_cache = null params.cadd_InDels = null params.cadd_InDels_tbi = null params.cadd_WG_SNVs = null params.cadd_WG_SNVs_tbi = null +params.genesplicer = null +params.monochrome_logs = null +params.multiqc_config = null params.noGVCF = null params.noReports = null +params.noStrelkaBP = null params.nucleotidesPerSecond = 1000.0 params.sample = null params.sequencing_center = null params.snpEff_cache = null params.step = 'mapping' -params.strelkaBP = true params.targetBED = null -params.tools = null +params.tools = "HaplotypeCaller,Manta,Strelka" params.vep_cache = null stepList = defineStepList() step = params.step ? params.step.toLowerCase() : '' -if ( step == 'preprocessing' ) step = 'mapping' -if ( !checkParameterExistence(step, stepList) ) exit 1, 'Unknown step, see --help for more information' -if ( step.contains(',') ) exit 1, 'You can choose only one step, see --help for more information' +if (step == 'preprocessing') step = 'mapping' +if (step.contains(',')) exit 1, 'You can choose only one step, see --help for more information' +if (!checkParameterExistence(step, stepList)) exit 1, "Unknown step ${step}, see --help for more information" tools = params.tools ? params.tools.split(',').collect{it.trim().toLowerCase()} : [] annotateTools = params.annotateTools ? params.annotateTools.split(',').collect{it.trim().toLowerCase()} : [] toolList = defineToolList() -if ( !checkParameterList(tools,toolList) ) exit 1, 'Unknown tool(s), see --help for more information' +if (!checkParameterList(tools,toolList)) exit 1, 'Unknown tool(s), see --help for more information' referenceMap = defineReferenceMap(step, tools) -if ( !checkReferenceMap(referenceMap) ) exit 1, 'Missing Reference file(s), see --help for more information' +if (!checkReferenceMap(referenceMap)) exit 1, 'Missing Reference file(s), see --help for more information' // Has the run name been specified by the user? -// this has the bonus effect of catching both -name and --name +// This has the bonus effect of catching both -name and --name custom_runName = params.name -if ( !(workflow.runName ==~ /[a-z]+_[a-z]+/) ) custom_runName = workflow.runName +if (!(workflow.runName ==~ /[a-z]+_[a-z]+/)) custom_runName = workflow.runName -if ( workflow.profile == 'awsbatch') { +if (workflow.profile == 'awsbatch') { // AWSBatch sanity checking - if ( !params.awsqueue || !params.awsregion ) exit 1, "Specify correct --awsqueue and --awsregion parameters on AWSBatch!" + if (!params.awsqueue || !params.awsregion) exit 1, "Specify correct --awsqueue and --awsregion parameters on AWSBatch!" // Check outdir paths to be S3 buckets if running on AWSBatch // related: https://github.com/nextflow-io/nextflow/issues/813 - if ( !params.outdir.startsWith('s3:') ) exit 1, "Outdir not on S3 - specify S3 Bucket to run on AWSBatch!" + if (!params.outdir.startsWith('s3:')) exit 1, "Outdir not on S3 - specify S3 Bucket to run on AWSBatch!" // Prevent trace files to be stored on S3 since S3 does not support rolling files. - if ( workflow.tracedir.startsWith('s3:') ) exit 1, "Specify a local tracedir or run without trace! S3 cannot be used for tracefiles." + if (workflow.tracedir.startsWith('s3:')) exit 1, "Specify a local tracedir or run without trace! S3 cannot be used for tracefiles." } // Stage config files -ch_multiqc_config = Channel.fromPath(params.multiqc_config) ch_output_docs = Channel.fromPath("${baseDir}/docs/output.md") -/* - * Create a channel for input read files - */ - tsvPath = null if (params.sample) if (hasExtension(params.sample,"tsv") || hasExtension(params.sample,"vcf") || hasExtension(params.sample,"vcf.gz")) tsvPath = params.sample +if (params.sample) if (hasExtension(params.sample,"vcf") || hasExtension(params.sample,"vcf.gz")) step = "annotate" - // No need for tsv file for step annotate -if (!params.sample) { - tsvPaths = [ 'recalibrate': "${params.outdir}/Preprocessing/TSV/duplicateMarked.tsv", - 'variantcalling': "${params.outdir}/Preprocessing/TSV/recalibrated.tsv" ] - if (step != 'mapping') tsvPath = tsvPaths[step] +// If no input file specified, trying to get TSV files corresponding to step in the TSV directory +// only for steps recalibrate and variantCalling +if (!params.sample && step != 'mapping' && step != 'annotate') { + tsvPath = step == 'recalibrate' ? "${params.outdir}/Preprocessing/TSV/duplicateMarked.tsv": "${params.outdir}/Preprocessing/TSV/recalibrated.tsv" } -// Set up the inputFiles and bamFiles channels. One of them will remain empty -inputFiles = Channel.empty() -bamFiles = Channel.empty() +inputSample = Channel.empty() if (tsvPath) { tsvFile = file(tsvPath) switch (step) { - case 'mapping': inputFiles = extractSample(tsvFile); break - case 'recalibrate': bamFiles = extractRecal(tsvFile); break - case 'variantcalling': bamFiles = extractBams(tsvFile); break + case 'mapping': inputSample = extractFastq(tsvFile); break + case 'recalibrate': inputSample = extractRecal(tsvFile); break + case 'variantcalling': inputSample = extractBam(tsvFile); break case 'annotate': break default: exit 1, "Unknown step ${step}" } } else if (params.sample) if (!hasExtension(params.sample,"tsv")) { - println "no tsv file" + println "No TSV file" if (step != 'mapping') exit 1, 'No other step than "mapping" support a dir as an input' - inputFiles = extractFastqFromDir(params.sample) - (inputFiles, fastqTmp) = inputFiles.into(2) - fastqTmp.toList().subscribe onNext: { + println "Reading ${params.sample} directory" + inputSample = extractFastqFromDir(params.sample) + (inputSample, fastqTMP) = inputSample.into(2) + fastqTMP.toList().subscribe onNext: { if (it.size() == 0) exit 1, "No FASTQ files found in --sample directory '${params.sample}'" } tsvFile = params.sample // used in the reports @@ -182,13 +187,12 @@ if (tsvPath) { println "Annotating ${tsvFile}" } else exit 1, 'No sample were defined, see --help' -if (step == 'recalibrate') (patientGenders, bamFiles) = extractGenders(bamFiles) -else (patientGenders, inputFiles) = extractGenders(inputFiles) +(genderMap, statusMap, inputSample) = extractInfos(inputSample) // Header log info log.info nfcoreHeader() def summary = [:] -if (workflow.revision) summary['Pipeline Release'] = workflow.revision +if (workflow.revision) summary['Pipeline Release'] = workflow.revision summary['Run Name'] = custom_runName ?: workflow.runName summary['Max Resources'] = "${params.max_memory} memory, ${params.max_cpus} cpus, ${params.max_time} time per job" if (workflow.containerEngine) summary['Container'] = "${workflow.containerEngine} - ${workflow.container}" @@ -196,9 +200,9 @@ if (params.sample) summary['Sample'] = params.sample if (params.targetBED) summary['Target BED'] = params.targetBED if (params.step) summary['Step'] = params.step if (params.tools) summary['Tools'] = tools.join(', ') -if (params.noReports) summary['Reports'] = params.noReports -if (params.noGVCF) summary['GVCF'] = params.noGVCF -if (params.strelkaBP) summary['Strelka BP'] = params.strelkaBP +if (params.noReports) summary['No Reports'] = params.noReports +if (params.noGVCF) summary['No GVCF'] = params.noGVCF +if (params.noStrelkaBP) summary['No Strelka BP'] = params.noStrelkaBP if (params.sequencing_center) summary['Sequenced by '] = params.sequencing_center summary['Nucleotides/s'] = params.nucleotidesPerSecond summary['Output dir'] = params.outdir @@ -206,7 +210,7 @@ summary['Launch dir'] = workflow.launchDir summary['Working dir'] = workflow.workDir summary['Script dir'] = workflow.projectDir summary['User'] = workflow.userName -if (workflow.profile == 'awsbatch'){ +if (workflow.profile == 'awsbatch') { summary['AWS Region'] = params.awsregion summary['AWS Queue'] = params.awsqueue } @@ -224,31 +228,14 @@ log.info "\033[2m----------------------------------------------------\033[0m" // Check the hostnames against configured profiles checkHostname() -def create_workflow_summary(summary) { - def yaml_file = workDir.resolve('workflow_summary_mqc.yaml') - yaml_file.text = """ - id: 'nf-core-sarek-summary' - description: " - this information is collected when the pipeline is started." - section_name: 'nf-core/sarek Workflow Summary' - section_href: 'https://github.com/nf-core/sarek' - plot_type: 'html' - data: | - - """.stripIndent() - - return yaml_file -} - /* * Parse software version numbers */ -process get_software_versions { +process GetSoftwareVersions { publishDir path:"${params.outdir}/pipeline_info", mode: params.publishDirMode output: - file 'software_versions_mqc.yaml' into software_versions_yaml + file 'software_versions_mqc.yaml' into yamlSoftwareVersion when: !params.noReports @@ -257,7 +244,7 @@ process get_software_versions { alleleCounter --version &> v_allelecount.txt || true bcftools version > v_bcftools.txt 2>&1 || true bwa &> v_bwa.txt 2>&1 || true - cat ${baseDir}/scripts/ascat.R | grep "ASCAT version" &> v_ascat.txt || true + cat ${baseDir}/bin/ascat.R | grep "ASCAT version" &> v_ascat.txt || true configManta.py --version > v_manta.txt 2>&1 || true configureStrelkaGermlineWorkflow.py --version > v_strelka.txt 2>&1 || true echo "${workflow.manifest.version}" &> v_pipeline.txt 2>&1 || true @@ -277,7 +264,7 @@ process get_software_versions { """ } -software_versions_yaml = software_versions_yaml.dump(tag: 'SOFTWARE VERSIONS') +yamlSoftwareVersion = yamlSoftwareVersion.dump(tag:'SOFTWARE VERSIONS') /* ================================================================================ @@ -285,55 +272,161 @@ software_versions_yaml = software_versions_yaml.dump(tag: 'SOFTWARE VERSIONS') ================================================================================ */ -// STEP ONE: MAPPING +// STEP 0: CREATING INTERVALS FOR PARALLELIZATION (PREPROCESSING AND VARIANT CALLING) -(inputFiles, inputFilesforFastQC) = inputFiles.into(2) +process CreateIntervalBeds { + tag {intervals.fileName} -inputFiles = inputFiles.dump(tag:'INPUT') + input: + file(intervals) from Channel.value(referenceMap.intervals) + + output: + file '*.bed' into bedIntervals mode flatten + + when: step != 'annotate' + + script: + // If the interval file is BED format, the fifth column is interpreted to + // contain runtime estimates, which is then used to combine short-running jobs + if (hasExtension(intervals,"bed")) + """ + awk -vFS="\t" '{ + t = \$5 # runtime estimate + if (t == "") { + # no runtime estimate in this row, assume default value + t = (\$3 - \$2) / ${params.nucleotidesPerSecond} + } + if (name == "" || (chunk > 600 && (chunk + t) > longest * 1.05)) { + # start a new chunk + name = sprintf("%s_%d-%d.bed", \$1, \$2+1, \$3) + chunk = 0 + longest = 0 + } + if (t > longest) + longest = t + chunk += t + print \$0 > name + }' ${intervals} + """ + else + """ + awk -vFS="[:-]" '{ + name = sprintf("%s_%d-%d", \$1, \$2, \$3); + printf("%s\\t%d\\t%d\\n", \$1, \$2-1, \$3) > name ".bed" + }' ${intervals} + """ +} -process RunFastQC { +bedIntervals = bedIntervals + .map { intervalFile -> + def duration = 0.0 + for (line in intervalFile.readLines()) { + final fields = line.split('\t') + if (fields.size() >= 5) duration += fields[4].toFloat() + else { + start = fields[1].toInteger() + end = fields[2].toInteger() + duration += (end - start) / params.nucleotidesPerSecond + } + } + [duration, intervalFile] + }.toSortedList({ a, b -> b[0] <=> a[0] }) + .flatten().collate(2) + .map{duration, intervalFile -> intervalFile} + +bedIntervals = bedIntervals.dump(tag:'bedintervals') + +(intBaseRecalibrator, intApplyBQSR, intHaplotypeCaller, intMpileup, bedIntervals) = bedIntervals.into(5) + +// PREPARING CHANNELS FOR PREPROCESSING AND QC + +if (step == 'mapping') (inputReads, inputReadsFastQC) = inputSample.into(2) +else (inputReads, inputReadsFastQC) = Channel.empty().into(2) + +inputPairReadsFastQC = Channel.create() +inputBAMFastQC = Channel.create() + +inputReadsFastQC.choice(inputPairReadsFastQC, inputBAMFastQC) {hasExtension(it[4],"bam")? 1 : 0} + +// Removing inputFile2 wich is null in case of uBAM +inputBAMFastQC = inputBAMFastQC.map { + idPatient, idSample, idRun, inputFile1, inputFile2 -> + [idPatient, idSample, idRun, inputFile1] +} + +inputReads = inputReads.dump(tag:'INPUT') + +// STEP 0.5: QC ON READS + +// TODO: Use only one process for FastQC for FASTQ files and uBAM files +// FASTQ and uBAM files are renamed based on the sample name + +process FastQCFQ { tag {idPatient + "-" + idRun} publishDir "${params.outdir}/Reports/${idSample}/FastQC/${idRun}", mode: params.publishDirMode input: - set idPatient, status, idSample, idRun, file(inputFile1), file(inputFile2) from inputFilesforFastQC + set idPatient, idSample, idRun, file("${idRun}_R1.fastq.gz"), file("${idRun}_R2.fastq.gz") from inputPairReadsFastQC output: - file "*_fastqc.{zip,html}" into fastQCreport + file "*_fastqc.{zip,html}" into fastQCFQReport when: step == 'mapping' && !params.noReports script: - inputFiles = (hasExtension(inputFile1,"fastq.gz") || hasExtension(inputFile1,"fq.gz")) ? "${inputFile1} ${inputFile2}" : "${inputFile1}" """ - fastqc -t 2 -q ${inputFiles} + fastqc -t 2 -q ${idRun}_R1.fastq.gz ${idRun}_R2.fastq.gz """ } -fastQCreport = fastQCreport.dump(tag:'FastQC') +process FastQCBAM { + tag {idPatient + "-" + idRun} + + publishDir "${params.outdir}/Reports/${idSample}/FastQC/${idRun}", mode: params.publishDirMode + + input: + set idPatient, idSample, idRun, file("${idRun}.bam") from inputBAMFastQC + + output: + file "*_fastqc.{zip,html}" into fastQCBAMReport + + when: step == 'mapping' && !params.noReports + + script: + """ + fastqc -t 2 -q "${idRun}.bam" + """ +} + +fastQCReport = fastQCFQReport.mix(fastQCBAMReport) + +fastQCReport = fastQCReport.dump(tag:'FastQC') + +// STEP 1: MAPPING READS TO REFERENCE GENOME WITH BWA MEM process MapReads { tag {idPatient + "-" + idRun} input: - set idPatient, status, idSample, idRun, file(inputFile1), file(inputFile2) from inputFiles + set idPatient, idSample, idRun, file(inputFile1), file(inputFile2) from inputReads set file(genomeFile), file(bwaIndex) from Channel.value([referenceMap.genomeFile, referenceMap.bwaIndex]) output: - set idPatient, status, idSample, idRun, file("${idRun}.bam") into (mappedBam, mappedBamForQC) + set idPatient, idSample, idRun, file("${idRun}.bam") into (bamMapped, bamMappedQC) when: step == 'mapping' script: // -K is an hidden option, used to fix the number of reads processed by bwa mem - // Chunk size can affect bwa results, if not specified, the number of threads can change - // which can give not deterministic result. + // Chunk size can affect bwa results, if not specified, + // the number of threads can change which can give not deterministic result. // cf https://github.com/CCDG/Pipeline-Standardization/blob/master/PipelineStandard.md // and https://github.com/gatk-workflows/gatk4-data-processing/blob/8ffa26ff4580df4ac3a5aa9e272a4ff6bab44ba2/processing-for-variant-discovery-gatk4.b37.wgs.inputs.json#L29 CN = params.sequencing_center ? "CN:${params.sequencing_center}\\t" : "" readGroup = "@RG\\tID:${idRun}\\t${CN}PU:${idRun}\\tSM:${idSample}\\tLB:${idSample}\\tPL:illumina" // adjust mismatch penalty for tumor samples + status = statusMap[idPatient, idSample] extra = status == 1 ? "-B 3" : "" if (hasExtension(inputFile1,"fastq.gz") || hasExtension(inputFile1,"fq.gz")) """ @@ -357,15 +450,17 @@ process MapReads { """ } -mappedBam = mappedBam.dump(tag:'Mapped BAM') +bamMapped = bamMapped.dump(tag:'Mapped BAM') + +// QC -process RunBamQCmapped { +process BamQCmapped { tag {idPatient + "-" + idSample} publishDir "${params.outdir}/Reports/${idSample}/bamQC", mode: params.publishDirMode input: - set idPatient, status, idSample, idRun, file(bam) from mappedBamForQC + set idPatient, idSample, idRun, file(bam) from bamMappedQC file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") output: @@ -392,25 +487,28 @@ process RunBamQCmapped { bamQCmappedReport = bamQCmappedReport.dump(tag:'BamQC BAM') -// Sort bam whether they are standalone or should be merged +// Sort BAM whether they are standalone or should be merged singleBam = Channel.create() -groupedBam = Channel.create() -mappedBam.groupTuple(by:[0,1,2]) - .choice(singleBam, groupedBam) {it[3].size() > 1 ? 1 : 0} +multipleBam = Channel.create() +bamMapped.groupTuple(by:[0,1]) + .choice(singleBam, multipleBam) {it[2].size() > 1 ? 1 : 0} singleBam = singleBam.map { - idPatient, status, idSample, idRun, bam -> - [idPatient, status, idSample, bam] + idPatient, idSample, idRun, bam -> + [idPatient, idSample, bam] } +singleBam = singleBam.dump(tag:'Single BAM') + +// STEP 1.5: MERGING BAM FROM MULTIPLE LANES -process MergeBams { +process MergeBamMapped { tag {idPatient + "-" + idSample} input: - set idPatient, status, idSample, idRun, file(bam) from groupedBam + set idPatient, idSample, idRun, file(bam) from multipleBam output: - set idPatient, status, idSample, file("${idSample}.bam") into mergedBam + set idPatient, idSample, file("${idSample}.bam") into mergedBam when: step == 'mapping' @@ -420,10 +518,11 @@ process MergeBams { """ } -singleBam = singleBam.dump(tag:'Single BAM') mergedBam = mergedBam.dump(tag:'Merged BAM') mergedBam = mergedBam.mix(singleBam) -mergedBam = mergedBam.dump(tag:'BAM for MD') +mergedBam = mergedBam.dump(tag:'BAMs for MD') + +// STEP 2: MARKING DUPLICATES process MarkDuplicates { tag {idPatient + "-" + idSample} @@ -435,16 +534,16 @@ process MarkDuplicates { } input: - set idPatient, status, idSample, file("${idSample}.bam") from mergedBam + set idPatient, idSample, file("${idSample}.bam") from mergedBam output: - set idPatient, file("${idSample}_${status}.md.bam"), file("${idSample}_${status}.md.bai") into duplicateMarkedBams + set idPatient, idSample, file("${idSample}.md.bam"), file("${idSample}.md.bai") into duplicateMarkedBams file ("${idSample}.bam.metrics") into markDuplicatesReport when: step == 'mapping' script: - markdup_java_options = task.memory.toGiga() > 8 ? params.markdup_java_options : "\"-Xms" + (task.memory.toGiga() / 2 ).trunc() + "g -Xmx" + (task.memory.toGiga() - 1) + "g\"" + markdup_java_options = task.memory.toGiga() > 8 ? params.markdup_java_options : "\"-Xms" + (task.memory.toGiga() / 2).trunc() + "g -Xmx" + (task.memory.toGiga() - 1) + "g\"" """ gatk --java-options ${markdup_java_options} \ MarkDuplicates \ @@ -454,95 +553,23 @@ process MarkDuplicates { --TMP_DIR . \ --ASSUME_SORT_ORDER coordinate \ --CREATE_INDEX true \ - --OUTPUT ${idSample}_${status}.md.bam + --OUTPUT ${idSample}.md.bam """ } -duplicateMarkedBams = duplicateMarkedBams.map { - idPatient, bam, bai -> - tag = bam.baseName.tokenize('.')[0] - status = tag[-1..-1].toInteger() - idSample = tag.take(tag.length()-2) - [idPatient, status, idSample, bam, bai] -} - duplicateMarkedBams = duplicateMarkedBams.dump(tag:'MD BAM') +markDuplicatesReport = markDuplicatesReport.dump(tag:'MD Report') -(mdBam, mdBamToJoin) = duplicateMarkedBams.into(2) +(bamMD, bamMDToJoin) = duplicateMarkedBams.into(2) +bamBaseRecalibrator = bamMD.combine(intBaseRecalibrator) -process CreateIntervalBeds { - tag {intervals.fileName} +// STEP 3: CREATING RECALIBRATION TABLES - input: - file(intervals) from Channel.value(referenceMap.intervals) - - output: - file '*.bed' into bedIntervals mode flatten - - when: step != 'annotate' - - script: - // If the interval file is BED format, the fifth column is interpreted to - // contain runtime estimates, which is then used to combine short-running jobs - if (hasExtension(intervals,"bed")) - """ - awk -vFS="\t" '{ - t = \$5 # runtime estimate - if (t == "") { - # no runtime estimate in this row, assume default value - t = (\$3 - \$2) / ${params.nucleotidesPerSecond} - } - if (name == "" || (chunk > 600 && (chunk + t) > longest * 1.05)) { - # start a new chunk - name = sprintf("%s_%d-%d.bed", \$1, \$2+1, \$3) - chunk = 0 - longest = 0 - } - if (t > longest) - longest = t - chunk += t - print \$0 > name - }' ${intervals} - """ - else - """ - awk -vFS="[:-]" '{ - name = sprintf("%s_%d-%d", \$1, \$2, \$3); - printf("%s\\t%d\\t%d\\n", \$1, \$2-1, \$3) > name ".bed" - }' ${intervals} - """ -} - -bedIntervals = bedIntervals - .map { intervalFile -> - def duration = 0.0 - for (line in intervalFile.readLines()) { - final fields = line.split('\t') - if (fields.size() >= 5) duration += fields[4].toFloat() - else { - start = fields[1].toInteger() - end = fields[2].toInteger() - duration += (end - start) / params.nucleotidesPerSecond - } - } - [duration, intervalFile] - }.toSortedList({ a, b -> b[0] <=> a[0] }) - .flatten().collate(2) - .map{duration, intervalFile -> intervalFile} - -bedIntervals = bedIntervals.dump(tag:'bedintervals') - -(bedIntervalsBR, bedIntervalsHC, bedIntervalsForMpileup, bedIntervals) = bedIntervals.into(4) - -bamForBaseRecalibrator = mdBam.combine(bedIntervalsBR) - -process CreateRecalibrationTable { +process BaseRecalibrator { tag {idPatient + "-" + idSample + "-" + intervalBed} - publishDir "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked", mode: params.publishDirMode, overwrite: false - input: - set idPatient, status, idSample, file(bam), file(bai), file(intervalBed) from bamForBaseRecalibrator + set idPatient, idSample, file(bam), file(bai), file(intervalBed) from bamBaseRecalibrator set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex), file(knownIndels), file(knownIndelsIndex) from Channel.value([ referenceMap.genomeFile, referenceMap.genomeIndex, @@ -550,16 +577,16 @@ process CreateRecalibrationTable { referenceMap.dbsnp, referenceMap.dbsnpIndex, referenceMap.knownIndels, - referenceMap.knownIndelsIndex, + referenceMap.knownIndelsIndex ]) output: - set idPatient, status, idSample, file("${intervalBed.baseName}_${idSample}.recal.table") into recalIntervals + set idPatient, idSample, file("${intervalBed.baseName}_${idSample}.recal.table") into tableGatherBQSRReports when: step == 'mapping' script: - known = knownIndels.collect{ "--known-sites ${it}" }.join(' ') + known = knownIndels.collect{"--known-sites ${it}"}.join(' ') // --use-original-qualities ??? """ gatk --java-options -Xmx${task.memory.toGiga()}g \ @@ -575,7 +602,9 @@ process CreateRecalibrationTable { """ } -recalIntervals = recalIntervals.groupTuple(by:[0,1,2]) +tableGatherBQSRReports = tableGatherBQSRReports.groupTuple(by:[0,1]) + +// STEP 3.5: MERGING RECALIBRATION TABLES process GatherBQSRReports { tag {idPatient + "-" + idSample} @@ -583,62 +612,64 @@ process GatherBQSRReports { publishDir "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked", mode: params.publishDirMode, overwrite: false input: - set idPatient, status, idSample, file(recalTable) from recalIntervals + set idPatient, idSample, file(recal) from tableGatherBQSRReports output: - set idPatient, status, idSample, file("${idSample}.recal.table") into recalibrationTable - set idPatient, status, idSample, val("${idSample}_${status}.md.bam"), val("${idSample}_${status}.md.bai"), val("${idSample}.recal.table") into (recalibrationTableTSV, recalibrationTableSampleTSV) + set idPatient, idSample, file("${idSample}.recal.table") into recalTable + set idPatient, idSample, val("${idSample}.md.bam"), val("${idSample}.md.bai"), val("${idSample}.recal.table") into (recalTableTSV, recalTableSampleTSV) when: step == 'mapping' script: - recal = recalTable.collect{ "-I ${it}" }.join(' ') + input = recal.collect{"-I ${it}"}.join(' ') """ gatk --java-options -Xmx${task.memory.toGiga()}g \ GatherBQSRReports \ - ${recal} \ + ${input} \ -O ${idSample}.recal.table \ """ } // Create TSV files to restart from this step -recalibrationTableTSV.map { idPatient, status, idSample, bam, bai, recalTable -> - gender = patientGenders[idPatient] +recalTableTSV.map { idPatient, idSample, bam, bai, recalTable -> + status = statusMap[idPatient, idSample] + gender = genderMap[idPatient] "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bam}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bai}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${recalTable}\n" }.collectFile( name: 'duplicateMarked.tsv', sort: true, storeDir: "${params.outdir}/Preprocessing/TSV" ) -recalibrationTableSampleTSV - .collectFile(storeDir: "${params.outdir}/Preprocessing/TSV") { - idPatient, status, idSample, bam, bai, recalTable -> - gender = patientGenders[idPatient] +recalTableSampleTSV + .collectFile(storeDir: "${params.outdir}/Preprocessing/TSV/") { + idPatient, idSample, bam, bai, recalTable -> + status = statusMap[idPatient, idSample] + gender = genderMap[idPatient] ["duplicateMarked_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bam}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bai}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${recalTable}\n"] } -recalibrationTable = mdBamToJoin.join(recalibrationTable, by:[0,1,2]) +bamApplyBQSR = bamMDToJoin.join(recalTable, by:[0,1]) -if (step == 'recalibrate') recalibrationTable = bamFiles +if (step == 'recalibrate') bamApplyBQSR = inputSample -recalibrationTable = recalibrationTable.dump(tag:'recal.table') +bamApplyBQSR = bamApplyBQSR.dump(tag:'recal.table') -process RecalibrateBam { - tag {idPatient + "-" + idSample} +bamApplyBQSR = bamApplyBQSR.combine(intApplyBQSR) - publishDir "${params.outdir}/Preprocessing/${idSample}/Recalibrated", mode: params.publishDirMode +// STEP 4: RECALIBRATING + +process ApplyBQSR { + tag {idPatient + "-" + idSample + "-" + intervalBed.baseName} input: - set idPatient, status, idSample, file(bam), file(bai), file(recalibrationReport) from recalibrationTable - set file(genomeFile), file(genomeIndex), file(genomeDict), file(intervals) from Channel.value([ + set idPatient, idSample, file(bam), file(bai), file(recalibrationReport), file(intervalBed) from bamApplyBQSR + set file(genomeFile), file(genomeIndex), file(genomeDict)from Channel.value([ referenceMap.genomeFile, referenceMap.genomeIndex, - referenceMap.genomeDict, - referenceMap.intervals, + referenceMap.genomeDict ]) output: - set idPatient, status, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bai") into recalibratedBam, recalibratedBamForStats - set idPatient, status, idSample, val("${idSample}.recal.bam"), val("${idSample}.recal.bai") into (recalibratedBamTSV, recalibratedBamSampleTSV) + set idPatient, idSample, file("${intervalBed.baseName}_${idSample}.recal.bam") into bamMergeBamRecal script: """ @@ -646,41 +677,62 @@ process RecalibrateBam { ApplyBQSR \ -R ${genomeFile} \ --input ${bam} \ - --output ${idSample}.recal.bam \ - -L ${intervals} \ - --create-output-bam-index true \ + --output ${intervalBed.baseName}_${idSample}.recal.bam \ + -L ${intervalBed} \ --bqsr-recal-file ${recalibrationReport} """ } +bamMergeBamRecal = bamMergeBamRecal.groupTuple(by:[0,1]) + +// STEP 4.5: MERGING THE RECALIBRATED BAM FILES + +process MergeBamRecal { + tag {idPatient + "-" + idSample} + + publishDir "${params.outdir}/Preprocessing/${idSample}/Recalibrated", mode: params.publishDirMode + + input: + set idPatient, idSample, file(bam) from bamMergeBamRecal + + output: + set idPatient, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bai") into (bamRecal, bamRecalBamQC, bamRecalSamToolsStats) + set idPatient, idSample, val("${idSample}.recal.bam"), val("${idSample}.recal.bai") into (bamRecalTSV, bamRecalSampleTSV) + + script: + """ + samtools merge --threads ${task.cpus} ${idSample}.recal.bam ${bam} + samtools index ${idSample}.recal.bam + mv ${idSample}.recal.bam.bai ${idSample}.recal.bai + """ +} + // Creating a TSV file to restart from this step -recalibratedBamTSV.map { idPatient, status, idSample, bam, bai -> - gender = patientGenders[idPatient] +bamRecalTSV.map { idPatient, idSample, bam, bai -> + gender = genderMap[idPatient] + status = statusMap[idPatient, idSample] "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bam}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bai}\n" }.collectFile( name: 'recalibrated.tsv', sort: true, storeDir: "${params.outdir}/Preprocessing/TSV" ) -recalibratedBamSampleTSV +bamRecalSampleTSV .collectFile(storeDir: "${params.outdir}/Preprocessing/TSV") { - idPatient, status, idSample, bam, bai -> - gender = patientGenders[idPatient] + idPatient, idSample, bam, bai -> + status = statusMap[idPatient, idSample] + gender = genderMap[idPatient] ["recalibrated_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bam}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bai}\n"] } -recalibratedBam = recalibratedBam.dump(tag:'recal.bam') +// STEP 5: QC -// Remove recalTable from Channels to match inputs for Process to avoid: -// WARN: Input tuple does not match input set cardinality declared by process... -(bamForBamQC, bamForSamToolsStats) = recalibratedBamForStats.map{ it[0..4] }.into(2) - -process RunSamtoolsStats { +process SamtoolsStats { tag {idPatient + "-" + idSample} publishDir "${params.outdir}/Reports/${idSample}/SamToolsStats", mode: params.publishDirMode input: - set idPatient, status, idSample, file(bam), file(bai) from bamForSamToolsStats + set idPatient, idSample, file(bam), file(bai) from bamRecalSamToolsStats output: file ("${bam}.samtools.stats.out") into samtoolsStatsReport @@ -695,13 +747,13 @@ process RunSamtoolsStats { samtoolsStatsReport = samtoolsStatsReport.dump(tag:'SAMTools') -process RunBamQCrecalibrated { +process BamQCrecalibrated { tag {idPatient + "-" + idSample} publishDir "${params.outdir}/Reports/${idSample}/bamQC", mode: params.publishDirMode input: - set idPatient, status, idSample, file(bam), file(bai) from bamForBamQC + set idPatient, idSample, file(bam), file(bai) from bamRecalBamQC output: file("${bam.baseName}") into bamQCrecalibratedReport @@ -731,27 +783,29 @@ bamQCrecalibratedReport = bamQCrecalibratedReport.dump(tag:'BamQC') ================================================================================ */ -if (step == 'variantcalling') recalibratedBam = bamFiles +if (step == 'variantcalling') bamRecal = inputSample -recalibratedBam = recalibratedBam.dump(tag:'BAM') +bamRecal = bamRecal.dump(tag:'BAM') // Here we have a recalibrated bam set // The TSV file is formatted like: "idPatient status idSample bamFile baiFile" // Manta will be run in Germline mode, or in Tumor mode depending on status // HaplotypeCaller and Strelka will be run for Normal and Tumor samples -(bamsForSingleManta, bamsForSingleStrelka, recalibratedBamTemp, recalibratedBam) = recalibratedBam.into(4) +(bamMantaSingle, bamStrelkaSingle, bamRecalAllTemp, bamRecalAll) = bamRecal.into(4) // To speed Variant Callers up we are chopping the reference into smaller pieces // Do variant calling by this intervals, and re-merge the VCFs -bamsForHC = recalibratedBamTemp.combine(bedIntervalsHC) +bamHaplotypeCaller = bamRecalAllTemp.combine(intHaplotypeCaller) + +// STEP GATK HAPLOTYPECALLER.1 -process RunHaplotypecaller { +process HaplotypeCaller { tag {idSample + "-" + intervalBed.baseName} input: - set idPatient, status, idSample, file(bam), file(bai), file(intervalBed) from bamsForHC + set idPatient, idSample, file(bam), file(bai), file(intervalBed) from bamHaplotypeCaller set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex) from Channel.value([ referenceMap.genomeFile, referenceMap.genomeIndex, @@ -761,8 +815,8 @@ process RunHaplotypecaller { ]) output: - set val("HaplotypeCallerGVCF"), idPatient, idSample, file("${intervalBed.baseName}_${idSample}.g.vcf") into hcGenomicVCF - set idPatient, idSample, file(intervalBed), file("${intervalBed.baseName}_${idSample}.g.vcf") into vcfsToGenotype + set val("HaplotypeCallerGVCF"), idPatient, idSample, file("${intervalBed.baseName}_${idSample}.g.vcf") into gvcfHaplotypeCaller + set idPatient, idSample, file(intervalBed), file("${intervalBed.baseName}_${idSample}.g.vcf") into gvcfGenotypeGVCFs when: 'haplotypecaller' in tools @@ -779,15 +833,18 @@ process RunHaplotypecaller { """ } -hcGenomicVCF = hcGenomicVCF.groupTuple(by:[0,1,2]) +gvcfHaplotypeCaller = gvcfHaplotypeCaller.groupTuple(by:[0,1,2]) -if (params.noGVCF) hcGenomicVCF.close() +if (params.noGVCF) gvcfHaplotypeCaller.close() +else gvcfHaplotypeCaller = gvcfHaplotypeCaller.dump(tag:'GVCF HaplotypeCaller') -process RunGenotypeGVCFs { +// STEP GATK HAPLOTYPECALLER.2 + +process GenotypeGVCFs { tag {idSample + "-" + intervalBed.baseName} input: - set idPatient, idSample, file(intervalBed), file(gvcf) from vcfsToGenotype + set idPatient, idSample, file(intervalBed), file(gvcf) from gvcfGenotypeGVCFs set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex) from Channel.value([ referenceMap.genomeFile, referenceMap.genomeIndex, @@ -797,7 +854,7 @@ process RunGenotypeGVCFs { ]) output: - set val("HaplotypeCaller"), idPatient, idSample, file("${intervalBed.baseName}_${idSample}.vcf") into hcGenotypedVCF + set val("HaplotypeCaller"), idPatient, idSample, file("${intervalBed.baseName}_${idSample}.vcf") into vcfGenotypeGVCFs when: 'haplotypecaller' in tools @@ -817,18 +874,17 @@ process RunGenotypeGVCFs { """ } -hcGenotypedVCF = hcGenotypedVCF.groupTuple(by:[0,1,2]) +vcfGenotypeGVCFs = vcfGenotypeGVCFs.groupTuple(by:[0,1,2]) -// we are merging the VCFs that are called separatelly for different intervals -// so we can have a single sorted VCF containing all the calls for a given caller +// STEP STRELKA.1 - SINGLE MODE -process RunSingleStrelka { +process StrelkaSingle { tag {idSample} publishDir "${params.outdir}/VariantCalling/${idSample}/Strelka", mode: params.publishDirMode input: - set idPatient, status, idSample, file(bam), file(bai) from bamsForSingleStrelka + set idPatient, idSample, file(bam), file(bai) from bamStrelkaSingle file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") set file(genomeFile), file(genomeIndex) from Channel.value([ referenceMap.genomeFile, @@ -836,7 +892,7 @@ process RunSingleStrelka { ]) output: - set val("Strelka"), idPatient, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into singleStrelkaOutput + set val("Strelka"), idPatient, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into vcfStrelkaSingle when: 'strelka' in tools @@ -864,15 +920,17 @@ process RunSingleStrelka { """ } -singleStrelkaOutput = singleStrelkaOutput.dump(tag:'Single Strelka') +vcfStrelkaSingle = vcfStrelkaSingle.dump(tag:'Strelka - Single Mode') + +// STEP MANTA.1 - SINGLE MODE -process RunSingleManta { +process MantaSingle { tag {idSample} publishDir "${params.outdir}/VariantCalling/${idSample}/Manta", mode: params.publishDirMode input: - set idPatient, status, idSample, file(bam), file(bai) from bamsForSingleManta + set idPatient, idSample, file(bam), file(bai) from bamMantaSingle file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") set file(genomeFile), file(genomeIndex) from Channel.value([ referenceMap.genomeFile, @@ -880,13 +938,14 @@ process RunSingleManta { ]) output: - set val("Manta"), idPatient, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into singleMantaOutput + set val("Manta"), idPatient, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into vcfMantaSingle when: 'manta' in tools script: beforeScript = params.targetBED ? "bgzip --threads ${task.cpus} -c ${targetBED} > call_targets.bed.gz ; tabix call_targets.bed.gz" : "" options = params.targetBED ? "--exome --callRegions call_targets.bed.gz" : "" + status = statusMap[idPatient, idSample] inputbam = status == 0 ? "--bam" : "--tumorBam" vcftype = status == 0 ? "diploid" : "tumor" """ @@ -914,7 +973,7 @@ process RunSingleManta { """ } -singleMantaOutput = singleMantaOutput.dump(tag:'Single Manta') +vcfMantaSingle = vcfMantaSingle.dump(tag:'Single Manta') /* ================================================================================ @@ -922,43 +981,44 @@ singleMantaOutput = singleMantaOutput.dump(tag:'Single Manta') ================================================================================ */ -// separate recalibrateBams by status -bamsNormal = Channel.create() -bamsTumor = Channel.create() +// Ascat, Control-FREEC +bamAscat = Channel.create() +bamMpileup = Channel.create() -recalibratedBam - .choice(bamsTumor, bamsNormal) {it[1] == 0 ? 1 : 0} +(bamAscat, bamMpileup, bamRecalAll) = bamRecalAll.into(3) -// Ascat, Control-FREEC, Manta Tumor-only SV -bamsForAscat = Channel.create() -bamsForMpileup = Channel.create() -bamsForSingleManta = Channel.create() +// separate BAM by status +bamNormal = Channel.create() +bamTumor = Channel.create() -(bamsTumorTemp, bamsTumor) = bamsTumor.into(2) -(bamsNormalTemp, bamsNormal) = bamsNormal.into(2) -(bamsForAscat, bamsForMpileup, bamsForSingleManta) = bamsNormalTemp.mix(bamsTumorTemp).into(3) +bamRecalAll + .choice(bamTumor, bamNormal) {statusMap[it[0], it[1]] == 0 ? 1 : 0} -// Removing status because not relevant anymore -bamsNormal = bamsNormal.map { idPatient, status, idSample, bam, bai -> [idPatient, idSample, bam, bai] } -bamsTumor = bamsTumor.map { idPatient, status, idSample, bam, bai -> [idPatient, idSample, bam, bai] } +// Crossing Normal and Tumor to get a T/N pair for Somatic Variant Calling +// Remapping channel to remove common key idPatient +pairBam = bamNormal.cross(bamTumor).map { + normal, tumor -> + [normal[0], normal[1], normal[2], normal[3], tumor[1], tumor[2], tumor[3]] +} -bamsAll = bamsNormal.join(bamsTumor) +pairBam = pairBam.dump(tag:'BAM Somatic Pair') // Manta and Strelka -(bamsForManta, bamsForStrelka, bamsForStrelkaBP, bamsAll) = bamsAll.into(4) +(pairBamManta, pairBamStrelka, pairBamStrelkaBP, pairBam) = pairBam.into(4) -bamsTumorNormalIntervals = bamsAll.spread(bedIntervals) -bamsForMpileup = bamsForMpileup.spread(bedIntervalsForMpileup) +intPairBam = pairBam.spread(bedIntervals) +bamMpileup = bamMpileup.spread(intMpileup) // MuTect2, FreeBayes -( bamsFMT2, bamsFFB) = bamsTumorNormalIntervals.into(3) +(pairBamMuTect2, pairBamFreeBayes) = intPairBam.into(3) + +// STEP GATK MUTECT2 -// This will give as a list of unfiltered calls for MuTect2. -process RunMutect2 { +process Mutect2 { tag {idSampleTumor + "_vs_" + idSampleNormal + "-" + intervalBed.baseName} input: - set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from bamsFMT2 + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from pairBamMuTect2 set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex) from Channel.value([ referenceMap.genomeFile, referenceMap.genomeIndex, @@ -968,7 +1028,7 @@ process RunMutect2 { ]) output: - set val("MuTect2"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf") into mutect2Output + set val("MuTect2"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf") into vcfMuTect2 when: 'mutect2' in tools @@ -984,18 +1044,20 @@ process RunMutect2 { """ } -mutect2Output = mutect2Output.groupTuple(by:[0,1,2]) +vcfMuTect2 = vcfMuTect2.groupTuple(by:[0,1,2]) -process RunFreeBayes { +// STEP FREEBAYES + +process FreeBayes { tag {idSampleTumor + "_vs_" + idSampleNormal + "-" + intervalBed.baseName} input: - set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from bamsFFB + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from pairBamFreeBayes file(genomeFile) from Channel.value(referenceMap.genomeFile) file(genomeIndex) from Channel.value(referenceMap.genomeIndex) output: - set val("FreeBayes"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf") into freebayesOutput + set val("FreeBayes"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf") into vcfFreeBayes when: 'freebayes' in tools @@ -1017,11 +1079,16 @@ process RunFreeBayes { """ } -freebayesOutput = freebayesOutput.groupTuple(by:[0,1,2]) +// we are merging the VCFs that are called separatelly for different intervals +// so we can have a single sorted VCF containing all the calls for a given caller + +vcfFreeBayes = vcfFreeBayes.groupTuple(by:[0,1,2]) -vcfsToMerge = mutect2Output.mix(freebayesOutput, hcGenotypedVCF) +// STEP MERGING VCF - FREEBAYES, GATK HAPLOTYPECALLER & GATK MUTECT2 -vcfsToMerge = vcfsToMerge.dump(tag:'VCF to merge') +vcfConcatenateVCFs = vcfMuTect2.mix(vcfFreeBayes, vcfGenotypeGVCFs, gvcfHaplotypeCaller) + +vcfConcatenateVCFs = vcfConcatenateVCFs.dump(tag:'VCF to merge') process ConcatVCF { tag {variantCaller + "-" + idSample} @@ -1029,7 +1096,7 @@ process ConcatVCF { publishDir "${params.outdir}/VariantCalling/${idSample}/${"$variantCaller"}", mode: params.publishDirMode input: - set variantCaller, idPatient, idSample, file(vcFiles) from vcfsToMerge + set variantCaller, idPatient, idSample, file(vcFiles) from vcfConcatenateVCFs file(genomeIndex) from Channel.value(referenceMap.genomeIndex) file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") @@ -1050,13 +1117,15 @@ process ConcatVCF { vcfConcatenated = vcfConcatenated.dump(tag:'VCF') -process RunStrelka { +// STEP STRELKA.2 - SOMATIC PAIR + +process Strelka { tag {idSampleTumor + "_vs_" + idSampleNormal} publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/Strelka", mode: params.publishDirMode input: - set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor) from bamsForStrelka + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor) from pairBamStrelka file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") set file(genomeFile), file(genomeIndex), file(genomeDict) from Channel.value([ referenceMap.genomeFile, @@ -1065,7 +1134,7 @@ process RunStrelka { ]) output: - set val("Strelka"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into strelkaOutput + set val("Strelka"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into vcfStrelka when: 'strelka' in tools @@ -1094,16 +1163,17 @@ process RunStrelka { """ } -strelkaOutput = strelkaOutput.dump(tag:'Strelka') -(strelkaIndels, strelkaSNVS) = strelkaOutput.into(2) +vcfStrelka = vcfStrelka.dump(tag:'Strelka') -process RunManta { +// STEP MANTA.2 - SOMATIC PAIR + +process Manta { tag {idSampleTumor + "_vs_" + idSampleNormal} publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/Manta", mode: params.publishDirMode input: - set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor) from bamsForManta + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor) from pairBamManta file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") set file(genomeFile), file(genomeIndex) from Channel.value([ referenceMap.genomeFile, @@ -1111,7 +1181,7 @@ process RunManta { ]) output: - set val("Manta"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into mantaOutput + set val("Manta"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into vcfManta set idPatient, idSampleNormal, idSampleTumor, file("*.candidateSmallIndels.vcf.gz"), file("*.candidateSmallIndels.vcf.gz.tbi") into mantaToStrelka when: 'manta' in tools @@ -1149,10 +1219,10 @@ process RunManta { """ } -mantaOutput = mantaOutput.dump(tag:'Manta') -(mantaSomaticSV, mantaDiploidSV) = mantaOutput.into(2) +vcfManta = vcfManta.dump(tag:'Manta') -bamsForStrelkaBP = bamsForStrelkaBP.map { +// Remmaping channels to match input for StrelkaBP +pairBamStrelkaBP = pairBamStrelkaBP.map { idPatientNormal, idSampleNormal, bamNormal, baiNormal, idSampleTumor, bamTumor, baiTumor -> [idPatientNormal, idSampleNormal, idSampleTumor, bamNormal, baiNormal, bamTumor, baiTumor] }.join(mantaToStrelka, by:[0,1,2]).map { @@ -1160,13 +1230,15 @@ bamsForStrelkaBP = bamsForStrelkaBP.map { [idPatientNormal, idSampleNormal, bamNormal, baiNormal, idSampleTumor, bamTumor, baiTumor, mantaCSI, mantaCSIi] } -process RunStrelkaBP { +// STEP STRELKA.3 - SOMATIC PAIR - BEST PRACTICES + +process StrelkaBP { tag {idSampleTumor + "_vs_" + idSampleNormal} publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/Strelka", mode: params.publishDirMode input: - set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(mantaCSI), file(mantaCSIi) from bamsForStrelkaBP + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(mantaCSI), file(mantaCSIi) from pairBamStrelkaBP file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") set file(genomeFile), file(genomeIndex), file(genomeDict) from Channel.value([ referenceMap.genomeFile, @@ -1175,9 +1247,9 @@ process RunStrelkaBP { ]) output: - set val("Strelka"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into strelkaBPOutput + set val("Strelka"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into vcfStrelkaBP - when: 'strelka' in tools && 'manta' in tools && params.strelkaBP + when: 'strelka' in tools && 'manta' in tools && !params.noStrelkaBP script: beforeScript = params.targetBED ? "bgzip --threads ${task.cpus} -c ${targetBED} > call_targets.bed.gz ; tabix call_targets.bed.gz" : "" @@ -1205,16 +1277,17 @@ process RunStrelkaBP { """ } -strelkaBPOutput = strelkaBPOutput.dump(tag:'Strelka BP') -(strelkaBPIndels, strelkaBPSNVS) = strelkaBPOutput.into(2) +vcfStrelkaBP = vcfStrelkaBP.dump(tag:'Strelka BP') + +// STEP ASCAT.1 - ALLELECOUNTER // Run commands and code from Malin Larsson // Based on Jesper Eisfeldt's code -process RunAlleleCount { +process AlleleCounter { tag {idSample} input: - set idPatient, status, idSample, file(bam), file(bai) from bamsForAscat + set idPatient, idSample, file(bam), file(bai) from bamAscat set file(acLoci), file(genomeFile), file(genomeIndex), file(genomeDict) from Channel.value([ referenceMap.acLoci, referenceMap.genomeFile, @@ -1223,7 +1296,7 @@ process RunAlleleCount { ]) output: - set idPatient, status, idSample, file("${idSample}.alleleCount") into alleleCountOutput + set idPatient, idSample, file("${idSample}.alleleCount") into alleleCounterOut when: 'ascat' in tools @@ -1237,55 +1310,59 @@ process RunAlleleCount { """ } -alleleCountNormal = Channel.create() -alleleCountTumor = Channel.create() +alleleCountOutNormal = Channel.create() +alleleCountOutTumor = Channel.create() -alleleCountOutput - .choice(alleleCountTumor, alleleCountNormal) {it[1] == 0 ? 1 : 0} +alleleCounterOut + .choice(alleleCountOutTumor, alleleCountOutNormal) {statusMap[it[0], it[1]] == 0 ? 1 : 0} -alleleCountOutput = alleleCountNormal.combine(alleleCountTumor) +alleleCounterOut = alleleCountOutNormal.combine(alleleCountOutTumor) -alleleCountOutput = alleleCountOutput.map { - idPatientNormal, statusNormal, idSampleNormal, alleleCountNormal, - idPatientTumor, statusTumor, idSampleTumor, alleleCountTumor -> - [idPatientNormal, idSampleNormal, idSampleTumor, alleleCountNormal, alleleCountTumor] +alleleCounterOut = alleleCounterOut.map { + idPatientNormal, idSampleNormal, alleleCountOutNormal, + idPatientTumor, idSampleTumor, alleleCountOutTumor -> + [idPatientNormal, idSampleNormal, idSampleTumor, alleleCountOutNormal, alleleCountOutTumor] } +// STEP ASCAT.2 - CONVERTALLELECOUNTS + // R script from Malin Larssons bitbucket repo: // https://bitbucket.org/malinlarsson/somatic_wgs_pipeline -process RunConvertAlleleCounts { +process ConvertAlleleCounts { tag {idSampleTumor + "_vs_" + idSampleNormal} publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/ASCAT", mode: params.publishDirMode input: - set idPatient, idSampleNormal, idSampleTumor, file(alleleCountNormal), file(alleleCountTumor) from alleleCountOutput + set idPatient, idSampleNormal, idSampleTumor, file(alleleCountNormal), file(alleleCountTumor) from alleleCounterOut output: - set idPatient, idSampleNormal, idSampleTumor, file("${idSampleNormal}.BAF"), file("${idSampleNormal}.LogR"), file("${idSampleTumor}.BAF"), file("${idSampleTumor}.LogR") into convertAlleleCountsOutput + set idPatient, idSampleNormal, idSampleTumor, file("${idSampleNormal}.BAF"), file("${idSampleNormal}.LogR"), file("${idSampleTumor}.BAF"), file("${idSampleTumor}.LogR") into convertAlleleCountsOut when: 'ascat' in tools script: - gender = patientGenders[idPatient] + gender = genderMap[idPatient] """ convertAlleleCounts.r ${idSampleTumor} ${alleleCountTumor} ${idSampleNormal} ${alleleCountNormal} ${gender} """ } +// STEP ASCAT.3 - ASCAT + // R scripts from Malin Larssons bitbucket repo: // https://bitbucket.org/malinlarsson/somatic_wgs_pipeline -process RunAscat { +process Ascat { tag {idSampleTumor + "_vs_" + idSampleNormal} publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/ASCAT", mode: params.publishDirMode input: - set idPatient, idSampleNormal, idSampleTumor, file(bafNormal), file(logrNormal), file(bafTumor), file(logrTumor) from convertAlleleCountsOutput + set idPatient, idSampleNormal, idSampleTumor, file(bafNormal), file(logrNormal), file(bafTumor), file(logrTumor) from convertAlleleCountsOut file(acLociGC) from Channel.value([referenceMap.acLociGC]) output: - set val("ASCAT"), idPatient, idSampleNormal, idSampleTumor, file("${idSampleTumor}.*.{png,txt}") into ascatOutput + set val("ASCAT"), idPatient, idSampleNormal, idSampleTumor, file("${idSampleTumor}.*.{png,txt}") into ascatOut when: 'ascat' in tools @@ -1297,20 +1374,22 @@ process RunAscat { """ } -ascatOutput.dump(tag:'ASCAT') +ascatOut.dump(tag:'ASCAT') -process RunMpileup { +// STEP CONTROLFREEC.1 - MPILEUP + +process Mpileup { tag {idSample + "-" + intervalBed.baseName} input: - set idPatient, status, idSample, file(bam), file(bai), file(intervalBed) from bamsForMpileup + set idPatient, idSample, file(bam), file(bai), file(intervalBed) from bamMpileup set file(genomeFile), file(genomeIndex) from Channel.value([ referenceMap.genomeFile, referenceMap.genomeIndex ]) output: - set idPatient, status, idSample, file("${idSample}_${intervalBed.baseName}.pileup.gz") into mpileupToMerge + set idPatient, idSample, file("${intervalBed.baseName}_${idSample}.pileup.gz") into mpileupMerge when: ('controlfreec' in tools || 'mpileup' in tools) @@ -1319,11 +1398,13 @@ process RunMpileup { samtools mpileup \ -f ${genomeFile} ${bam} \ -l ${intervalBed} \ - | bgzip --threads ${task.cpus} -c > ${idSample}_${intervalBed.baseName}.pileup.gz + | bgzip --threads ${task.cpus} -c > ${intervalBed.baseName}_${idSample}.pileup.gz """ } -mpileupToMerge = mpileupToMerge.groupTuple(by:[0,1,2]) +mpileupMerge = mpileupMerge.groupTuple(by:[0,1]) + +// STEP CONTROLFREEC.2 - MERGE MPILEUP process MergeMpileup { tag {idSample} @@ -1331,10 +1412,10 @@ process MergeMpileup { publishDir params.outdir, mode: params.publishDirMode, saveAs: { it == "${idSample}.pileup.gz" ? "VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/mpileup/${it}" : '' } input: - set idPatient, status, idSample, file(mpileup) from mpileupToMerge + set idPatient, idSample, file(mpileup) from mpileupMerge output: - set idPatient, status, idSample, file("${idSample}.pileup.gz") into mpileupOutput + set idPatient, idSample, file("${idSample}.pileup.gz") into mpileupOut when: ('controlfreec' in tools || 'mpileup' in tools) @@ -1350,29 +1431,31 @@ process MergeMpileup { """ } -mpileupOutput = mpileupOutput.dump(tag:'mpileup') +mpileupOut = mpileupOut.dump(tag:'mpileup') -mpileupNormal = Channel.create() -mpileupTumor = Channel.create() +mpileupOutNormal = Channel.create() +mpileupOutTumor = Channel.create() -mpileupOutput - .choice(mpileupTumor, mpileupNormal) {it[1] == 0 ? 1 : 0} +mpileupOut + .choice(mpileupOutTumor, mpileupOutNormal) {statusMap[it[0], it[1]] == 0 ? 1 : 0} -mpileupOutput = mpileupNormal.combine(mpileupTumor) +mpileupOut = mpileupOutNormal.combine(mpileupOutTumor) -mpileupOutput = mpileupOutput.map { - idPatientNormal, statusNormal, idSampleNormal, mpileupNormal, - idPatientTumor, statusTumor, idSampleTumor, mpileupTumor -> - [idPatientNormal, idSampleNormal, idSampleTumor, mpileupNormal, mpileupTumor] +mpileupOut = mpileupOut.map { + idPatientNormal, idSampleNormal, mpileupOutNormal, + idPatientTumor, idSampleTumor, mpileupOutTumor -> + [idPatientNormal, idSampleNormal, idSampleTumor, mpileupOutNormal, mpileupOutTumor] } -process RunControlFreec { +// STEP CONTROLFREEC.3 - CONTROLFREEC + +process ControlFREEC { tag {idSampleTumor + "_vs_" + idSampleNormal} publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/controlFREEC", mode: params.publishDirMode input: - set idPatient, idSampleNormal, idSampleTumor, file(mpileupNormal), file(mpileupTumor) from mpileupOutput + set idPatient, idSampleNormal, idSampleTumor, file(mpileupNormal), file(mpileupTumor) from mpileupOut set file(genomeFile), file(genomeIndex), file(dbsnp), file(dbsnpIndex), file(chrDir), file(chrLength) from Channel.value([ referenceMap.genomeFile, referenceMap.genomeIndex, @@ -1383,14 +1466,14 @@ process RunControlFreec { ]) output: - set idPatient, idSampleNormal, idSampleTumor, file("${idSampleTumor}.pileup.gz_CNVs"), file("${idSampleTumor}.pileup.gz_ratio.txt"), file("${idSampleTumor}.pileup.gz_normal_CNVs"), file("${idSampleTumor}.pileup.gz_normal_ratio.txt"), file("${idSampleTumor}.pileup.gz_BAF.txt"), file("${idSampleNormal}.pileup.gz_BAF.txt") into controlFreecOutputVisualization - set file("*.pileup.gz*"), file("${idSampleTumor}_vs_${idSampleNormal}.config.txt") into controlFreecOutput + set idPatient, idSampleNormal, idSampleTumor, file("${idSampleTumor}.pileup.gz_CNVs"), file("${idSampleTumor}.pileup.gz_ratio.txt"), file("${idSampleTumor}.pileup.gz_normal_CNVs"), file("${idSampleTumor}.pileup.gz_normal_ratio.txt"), file("${idSampleTumor}.pileup.gz_BAF.txt"), file("${idSampleNormal}.pileup.gz_BAF.txt") into controlFreecViz + set file("*.pileup.gz*"), file("${idSampleTumor}_vs_${idSampleNormal}.config.txt") into controlFreecOut when: 'controlfreec' in tools script: config = "${idSampleTumor}_vs_${idSampleNormal}.config.txt" - gender = patientGenders[idPatient] + gender = genderMap[idPatient] """ touch ${config} echo "[general]" >> ${config} @@ -1426,17 +1509,21 @@ process RunControlFreec { """ } -process RunControlFreecVisualization { +controlFreecOut.dump(tag:'ControlFREEC') + +// STEP CONTROLFREEC.3 - VISUALIZATION + +process ControlFreecViz { tag {idSampleTumor + "_vs_" + idSampleNormal} publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/controlFREEC", mode: params.publishDirMode input: - set idPatient, idSampleNormal, idSampleTumor, file(cnvTumor), file(ratioTumor), file(cnvNormal), file(ratioNormal), file(bafTumor), file(bafNormal) from controlFreecOutputVisualization + set idPatient, idSampleNormal, idSampleTumor, file(cnvTumor), file(ratioTumor), file(cnvNormal), file(ratioNormal), file(bafTumor), file(bafNormal) from controlFreecViz output: - set file("*.txt"), file("*.png"), file("*.bed") into controlFreecOutputFinal + set file("*.txt"), file("*.png"), file("*.bed") into controlFreecVizOut when: 'controlfreec' in tools @@ -1450,56 +1537,66 @@ process RunControlFreecVisualization { """ } -vcfToKeep = Channel.empty().mix( +controlFreecVizOut.dump(tag:'ControlFreecViz') + +// Remapping channels for QC and annotation + +(vcfStrelkaIndels, vcfStrelkaSNVS) = vcfStrelka.into(2) +(vcfStrelkaBPIndels, vcfStrelkaBPSNVS) = vcfStrelkaBP.into(2) +(vcfMantaSomaticSV, vcfMantaDiploidSV) = vcfManta.into(2) + +vcfKeep = Channel.empty().mix( vcfConcatenated.map { variantcaller, idPatient, idSample, vcf, tbi -> [variantcaller, idSample, vcf] }, - singleStrelkaOutput.map { + vcfStrelkaSingle.map { variantcaller, idPatient, idSample, vcf, tbi -> [variantcaller, idSample, vcf[1]] }, - singleMantaOutput.map { + vcfMantaSingle.map { variantcaller, idPatient, idSample, vcf, tbi -> [variantcaller, idSample, vcf[2]] }, - mantaDiploidSV.map { + vcfMantaDiploidSV.map { variantcaller, idPatient, idSample, vcf, tbi -> [variantcaller, idSample, vcf[2]] }, - mantaSomaticSV.map { + vcfMantaSomaticSV.map { variantcaller, idPatient, idSample, vcf, tbi -> [variantcaller, idSample, vcf[3]] }, - strelkaIndels.map { + vcfStrelkaIndels.map { variantcaller, idPatient, idSample, vcf, tbi -> [variantcaller, idSample, vcf[0]] }, - strelkaSNVS.map { + vcfStrelkaSNVS.map { variantcaller, idPatient, idSample, vcf, tbi -> [variantcaller, idSample, vcf[1]] }, - strelkaBPIndels.map { + vcfStrelkaBPIndels.map { variantcaller, idPatient, idSample, vcf, tbi -> [variantcaller, idSample, vcf[0]] }, - strelkaBPSNVS.map { + vcfStrelkaBPSNVS.map { variantcaller, idPatient, idSample, vcf, tbi -> [variantcaller, idSample, vcf[1]] }) -(vcfForBCFtools, vcfForVCFtools, vcfForAnnotation) = vcfToKeep.into(3) +(vcfBCFtools, vcfVCFtools, vcfAnnotation) = vcfKeep.into(3) -process RunBcftoolsStats { +// STEP VCF.QC + +process BcftoolsStats { tag {"${variantCaller} - ${vcf}"} publishDir "${params.outdir}/Reports/${idSample}/BCFToolsStats", mode: params.publishDirMode input: - set variantCaller, idSample, file(vcf) from vcfForBCFtools + set variantCaller, idSample, file(vcf) from vcfBCFtools output: - file ("*.bcf.tools.stats.out") into bcfReport + file ("*.bcf.tools.stats.out") into bcftoolsReport when: !params.noReports @@ -1509,28 +1606,23 @@ process RunBcftoolsStats { """ } -bcfReport = bcfReport.dump(tag:'BCFTools') +bcftoolsReport = bcftoolsReport.dump(tag:'BCFTools') -process RunVcftools { +process Vcftools { tag {"${variantCaller} - ${vcf}"} publishDir "${params.outdir}/Reports/${idSample}/VCFTools", mode: params.publishDirMode input: - set variantCaller, idSample, file(vcf) from vcfForVCFtools + set variantCaller, idSample, file(vcf) from vcfVCFtools output: - file ("${reduceVCF(vcf)}.*") into vcfReport + file ("${reduceVCF(vcf)}.*") into vcftoolsReport when: !params.noReports script: """ - vcftools \ - --gzvcf ${vcf} \ - --relatedness2 \ - --out ${reduceVCF(vcf)} - vcftools \ --gzvcf ${vcf} \ --TsTv-by-count \ @@ -1548,7 +1640,7 @@ process RunVcftools { """ } -vcfReport = vcfReport.dump(tag:'VCFTools') +vcftoolsReport = vcftoolsReport.dump(tag:'VCFTools') /* ================================================================================ @@ -1556,10 +1648,9 @@ vcfReport = vcfReport.dump(tag:'VCFTools') ================================================================================ */ -vcfToAnnotate = Channel.create() - if (step == 'annotate') { - vcfNotToAnnotate = Channel.create() + vcfToAnnotate = Channel.create() + vcfNoAnnotate = Channel.create() if (tsvPath == []) { // Sarek, by default, annotates all available vcfs that it can find in the VariantCalling directory @@ -1577,7 +1668,7 @@ if (step == 'annotate') { .flatten().map{vcf -> ['mutect2', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, Channel.fromPath("${params.outdir}/VariantCalling/*/Strelka/*{somatic,variant}*.vcf.gz") .flatten().map{vcf -> ['strelka', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, - ).choice(vcfToAnnotate, vcfNotToAnnotate) { + ).choice(vcfToAnnotate, vcfNoAnnotate) { annotateTools == [] || (annotateTools != [] && it[0] in annotateTools) ? 0 : 1 } } else if (annotateTools == []) { @@ -1587,34 +1678,37 @@ if (step == 'annotate') { .map{vcf -> ['userspecified', vcf.minus(vcf.fileName)[-2].toString(), vcf]} } else exit 1, "specify only tools or files to annotate, not both" - vcfNotToAnnotate.close() - vcfForAnnotation = vcfForAnnotation.mix(vcfToAnnotate) + vcfNoAnnotate.close() + vcfAnnotation = vcfAnnotation.mix(vcfToAnnotate) } // as now have the list of VCFs to annotate, the first step is to annotate with allele frequencies, if there are any -(vcfForSnpeff, vcfForVep) = vcfForAnnotation.into(2) +(vcfSnpeff, vcfVep) = vcfAnnotation.into(2) -vcfForVep = vcfForVep.map { +vcfVep = vcfVep.map { variantCaller, idSample, vcf -> ["VEP", variantCaller, idSample, vcf, null] } -process RunSnpeff { +// STEP SNPEFF + +process Snpeff { tag {"${idSample} - ${variantCaller} - ${vcf}"} publishDir params.outdir, mode: params.publishDirMode, saveAs: { if (it == "${reducedVCF}_snpEff.ann.vcf") null - else "Annotation/${idSample}/snpEff/${it}" + else "Reports/${idSample}/snpEff/${it}" } input: - set variantCaller, idSample, file(vcf) from vcfForSnpeff + set variantCaller, idSample, file(vcf) from vcfSnpeff file dataDir from Channel.value(params.snpEff_cache ? file(params.snpEff_cache) : "null") val snpeffDb from Channel.value(params.genomes[params.genome].snpeffDb) output: - set file("${reducedVCF}_snpEff.genes.txt"), file("${reducedVCF}_snpEff.csv"), file("${reducedVCF}_snpEff.summary.html") into snpeffOutput + set file("${reducedVCF}_snpEff.txt"), file("${reducedVCF}_snpEff.html") into snpeffOut + file("${reducedVCF}_snpEff.csv") into snpeffReport set val("snpEff"), variantCaller, idSample, file("${reducedVCF}_snpEff.ann.vcf") into snpeffVCF when: 'snpeff' in tools || 'merge' in tools @@ -1633,11 +1727,13 @@ process RunSnpeff { ${vcf} \ > ${reducedVCF}_snpEff.ann.vcf - mv snpEff_summary.html ${reducedVCF}_snpEff.summary.html + mv snpEff_summary.html ${reducedVCF}_snpEff.html + mv ${reducedVCF}_snpEff.genes.txt ${reducedVCF}_snpEff.txt """ } -snpeffOutput = snpeffOutput.dump(tag:'snpEff') +snpeffOut = snpeffOut.dump(tag:'snpEff output') +snpeffReport = snpeffReport.dump(tag:'snpEff report') if ('merge' in tools) { // When running in the 'merge' mode @@ -1647,12 +1743,14 @@ if ('merge' in tools) { vcfCompressed = Channel.create() - vcfForVep = Channel.empty().mix( + vcfVep = Channel.empty().mix( vcfCompressed.until({ it[0]=="merge" }) ) } -process RunVEP { +// STEP VEP + +process VEP { tag {"${idSample} - ${variantCaller} - ${vcf}"} publishDir params.outdir, mode: params.publishDirMode, saveAs: { @@ -1661,7 +1759,7 @@ process RunVEP { } input: - set annotator, variantCaller, idSample, file(vcf), file(idx) from vcfForVep + set annotator, variantCaller, idSample, file(vcf), file(idx) from vcfVep file dataDir from Channel.value(params.vep_cache ? file(params.vep_cache) : "null") val cache_version from Channel.value(params.genomes[params.genome].vepCacheVersion) set file(cadd_WG_SNVs), file(cadd_WG_SNVs_tbi), file(cadd_InDels), file(cadd_InDels_tbi) from Channel.value([ @@ -1683,7 +1781,7 @@ process RunVEP { genome = params.genome == 'smallGRCh37' ? 'GRCh37' : params.genome dir_cache = (params.vep_cache && params.annotation_cache) ? " \${PWD}/${dataDir}" : "/.vep" cadd = (params.cadd_cache && params.cadd_WG_SNVs && params.cadd_InDels) ? "--plugin CADD,whole_genome_SNVs.tsv.gz,InDels.tsv.gz" : "" - genesplicer = params.genesplicer ? "--plugin GeneSplicer,/opt/conda/envs/sarek-2.3/bin/genesplicer,/opt/conda/envs/sarek-2.3/share/genesplicer-1.0-1/human,context=200,tmpdir=\$PWD/${reducedVCF}" : "--offline" + genesplicer = params.genesplicer ? "--plugin GeneSplicer,/opt/conda/envs/sarek-2.5dev/bin/genesplicer,/opt/conda/envs/sarek-2.5dev/share/genesplicer-1.0-1/human,context=200,tmpdir=\$PWD/${reducedVCF}" : "--offline" """ mkdir ${reducedVCF} @@ -1711,7 +1809,9 @@ process RunVEP { vepReport = vepReport.dump(tag:'VEP') -vcfToCompress = snpeffVCF.mix(vepVCF) +vcfCompressVCF = snpeffVCF.mix(vepVCF) + +// STEP COMPRESS AND INDEX VCF process CompressVCF { tag {"${idSample} - ${annotator} - ${vcf}"} @@ -1719,10 +1819,10 @@ process CompressVCF { publishDir "${params.outdir}/Annotation/${idSample}/${finalAnnotator}", mode: params.publishDirMode input: - set annotator, variantCaller, idSample, file(vcf) from vcfToCompress + set annotator, variantCaller, idSample, file(vcf) from vcfCompressVCF output: - set annotator, variantCaller, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into (vcfCompressed, vcfCompressedoutput) + set annotator, variantCaller, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into (vcfCompressed, compressVCFOut) script: reducedVCF = reduceVCF(vcf) @@ -1733,7 +1833,7 @@ process CompressVCF { """ } -vcfCompressedoutput = vcfCompressedoutput.dump(tag:'VCF') +compressVCFOut.dump(tag:'VCF') /* ================================================================================ @@ -1741,28 +1841,32 @@ vcfCompressedoutput = vcfCompressedoutput.dump(tag:'VCF') ================================================================================ */ -reportsForMultiQC = Channel.empty() +// STEP MULTIQC + +multiQCReport = Channel.empty() .mix( bamQCmappedReport, bamQCrecalibratedReport, - bcfReport, - fastQCreport, + bcftoolsReport, + fastQCReport, markDuplicatesReport, samtoolsStatsReport, - snpeffOutput, - vcfReport + snpeffReport, + vcftoolsReport ).collect() +Channel.fromPath(params.multiqc_config) + process RunMultiQC { publishDir "${params.outdir}/Reports/MultiQC", mode: params.publishDirMode input: - file (multiqcConfig) from createMultiQCconfig() - file (reports) from reportsForMultiQC - file (versions) from software_versions_yaml + file (multiqcConfig) from Channel.value(params.multiqc_config ? file(params.multiqc_config) : createMultiQCconfig()) + file (reports) from multiQCReport + file (versions) from yamlSoftwareVersion output: - set file("*multiqc_report.html"), file("*multiqc_data") into multiQCReport + set file("*multiqc_report.html"), file("*multiqc_data") into multiQCOut when: !params.noReports @@ -1772,7 +1876,7 @@ process RunMultiQC { """ } -multiQCReport.dump(tag:'MultiQC') +multiQCOut.dump(tag:'MultiQC') /* * Completion e-mail notification @@ -1780,10 +1884,8 @@ multiQCReport.dump(tag:'MultiQC') workflow.onComplete { // Set up the e-mail variables - def subject = "[nf-core/sarek] Successful: $workflow.runName" - if (!workflow.success){ - subject = "[nf-core/sarek] FAILED: $workflow.runName" - } + def subject = "[nf-core/sarek] Successful: ${workflow.runName}" + if (!workflow.success) subject = "[nf-core/sarek] FAILED: ${workflow.runName}" def email_fields = [:] email_fields['version'] = workflow.manifest.version email_fields['runName'] = custom_runName ?: workflow.runName @@ -1814,7 +1916,7 @@ workflow.onComplete { try { if (workflow.success) { mqc_report = multiqc_report.getVal() - if (mqc_report.getClass() == ArrayList){ + if (mqc_report.getClass() == ArrayList) { log.warn "[nf-core/sarek] Found multiple reports from process 'multiqc', will use only one" mqc_report = mqc_report[0] } @@ -1843,7 +1945,7 @@ workflow.onComplete { // Send the HTML e-mail if (params.email) { try { - if ( params.plaintext_email ){ throw GroovyException('Send plaintext e-mail, not HTML') } + if (params.plaintext_email) { throw GroovyException('Send plaintext e-mail, not HTML') } // Try to send HTML e-mail using sendmail [ 'sendmail', '-t' ].execute() << sendmail_html log.info "[nf-core/sarek] Sent summary e-mail to $params.email (sendmail)" @@ -1855,17 +1957,17 @@ workflow.onComplete { } // 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_d = new File("${params.outdir}/pipeline_info/") + if (!output_d.exists()) output_d.mkdirs() + def output_hf = new File(output_d, "pipeline_report.html") output_hf.withWriter { w -> w << email_html } - def output_tf = new File( output_d, "pipeline_report.txt" ) + def output_tf = new File(output_d, "pipeline_report.txt") output_tf.withWriter { w -> w << email_txt } - c_reset = params.monochrome_logs ? '' : "\033[0m"; + c_reset = params.monochrome_logs ? '' : "\033[0m"; + c_red = params.monochrome_logs ? '' : "\033[0;31m"; + c_green = params.monochrome_logs ? '' : "\033[0;32m"; c_purple = params.monochrome_logs ? '' : "\033[0;35m"; - c_green = params.monochrome_logs ? '' : "\033[0;32m"; - c_red = params.monochrome_logs ? '' : "\033[0;31m"; if (workflow.stats.ignoredCountFmt > 0 && workflow.success) { log.info "${c_purple}Warning, pipeline completed, but with errored process(es) ${c_reset}" @@ -1880,7 +1982,30 @@ workflow.onComplete { } } -def nfcoreHeader(){ +/* +================================================================================ + nf-core functions +================================================================================ +*/ + +def create_workflow_summary(summary) { + def yaml_file = workDir.resolve('workflow_summary_mqc.yaml') + yaml_file.text = """ + id: 'nf-core-sarek-summary' + description: " - this information is collected when the pipeline is started." + section_name: 'nf-core/sarek Workflow Summary' + section_href: 'https://github.com/nf-core/sarek' + plot_type: 'html' + data: | +
+${summary.collect { k,v -> "
$k
${v ?: 'N/A'}
" }.join("\n")} +
+ """.stripIndent() + + return yaml_file +} + +def nfcoreHeader() { // Log colors ANSI codes c_reset = params.monochrome_logs ? '' : "\033[0m"; c_dim = params.monochrome_logs ? '' : "\033[2m"; @@ -1911,16 +2036,16 @@ def nfcoreHeader(){ """.stripIndent() } -def checkHostname(){ +def checkHostname() { def c_reset = params.monochrome_logs ? '' : "\033[0m" def c_white = params.monochrome_logs ? '' : "\033[0;37m" def c_red = params.monochrome_logs ? '' : "\033[1;91m" def c_yellow_bold = params.monochrome_logs ? '' : "\033[1;93m" - if (params.hostnames){ + if (params.hostnames) { def hostname = "hostname".execute().text.trim() params.hostnames.each { prof, hnames -> hnames.each { hname -> - if (hostname.contains(hname) && !workflow.profile.contains(prof)){ + if (hostname.contains(hname) && !workflow.profile.contains(prof)) { log.error "====================================================\n" + " ${c_red}WARNING!${c_reset} You are running with `-profile $workflow.profile`\n" + " but your machine hostname is ${c_white}'$hostname'${c_reset}\n" + @@ -1989,8 +2114,8 @@ def checkReferenceMap(referenceMap) { def createMultiQCconfig() { def file = workDir.resolve('multiqc_config.yaml') file.text = """ - custom_logo: ${baseDir}/docs/images/Sarek_no_Border.png - custom_logo_url: https://sarek.scilifelab.se/ + custom_logo: ${baseDir}/docs/images/nf-core_logo.png + custom_logo_url: https://github.com/nf-core/sarek/ custom_logo_title: 'nf-core/sarek' report_header_info: @@ -2073,7 +2198,7 @@ def defineToolList() { // Channeling the TSV file containing BAM. // Format is: "subject gender status sample bam bai" -def extractBams(tsvFile) { +def extractBam(tsvFile) { Channel.from(tsvFile) .splitCsv(sep: '\t') .map { row -> @@ -2088,7 +2213,7 @@ def extractBams(tsvFile) { if (!hasExtension(bamFile,"bam")) exit 1, "File: ${bamFile} has the wrong extension. See --help for more information" if (!hasExtension(baiFile,"bai")) exit 1, "File: ${baiFile} has the wrong extension. See --help for more information" - return [ idPatient, gender, status, idSample, bamFile, baiFile ] + return [idPatient, gender, status, idSample, bamFile, baiFile] } } @@ -2121,22 +2246,26 @@ def extractFastqFromDir(pattern) { fastq } -// Extract gender from Channel as it's only used for CNVs -def extractGenders(channel) { - def genders = [:] +// Extract gender and status from Channel +def extractInfos(channel) { + def genderMap = [:] + def statusMap = [:] channel = channel.map{ it -> def idPatient = it[0] def gender = it[1] - genders[idPatient] = gender - [idPatient] + it[2..-1] + def status = it[2] + def idSample = it[3] + genderMap[idPatient] = gender + statusMap[idPatient, idSample] = status + [idPatient] + it[3..-1] } - [genders, channel] + [genderMap, statusMap, channel] } // Channeling the TSV file containing FASTQ or BAM // Format is: "subject gender status sample lane fastq1 fastq2" // or: "subject gender status sample lane bam" -def extractSample(tsvFile) { +def extractFastq(tsvFile) { Channel.from(tsvFile) .splitCsv(sep: '\t') .map { row -> @@ -2178,7 +2307,7 @@ def extractRecal(tsvFile) { if (!hasExtension(baiFile,"bai")) exit 1, "File: ${baiFile} has the wrong extension. See --help for more information" if (!hasExtension(recalTable,"recal.table")) exit 1, "File: ${recalTable} has the wrong extension. See --help for more information" - [ idPatient, gender, status, idSample, bamFile, baiFile, recalTable ] + [idPatient, gender, status, idSample, bamFile, baiFile, recalTable] } } diff --git a/nextflow.config b/nextflow.config index e6de815088..833a55d974 100644 --- a/nextflow.config +++ b/nextflow.config @@ -39,11 +39,11 @@ params { process.container = 'nfcore/sarek:dev' process { - withName:RunSnpeff { + withName:Snpeff { container = {(params.annotation_cache && params.snpEff_cache) ? 'nfcore/sarek:dev' : "nfcore/sareksnpeff:dev.${params.genome}"} } - withName:RunVEP { + withName:VEP { container = {(params.annotation_cache && params.vep_cache) ? 'nfcore/sarek:dev' : "nfcore/sarekvep:dev.${params.genome}"} } } From 61799e2d46508858e7cf5848af8a7c8a3fbe591b Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Mon, 3 Jun 2019 14:26:33 +0200 Subject: [PATCH 018/854] Docs (#11) * better docs * add docs about annotation * move helper scripts to scripts * add helper script to filter FreeBayes output * add docs about Variant Calling and Preprocessing * add scripts for ASCAT * fix publishDir for MergeMpileup * fix intra link * completed docs about ASCAT * add building container for dogs * add Abstracts & Posters * improve tests * update docs --- .circleci/config.yml | 34 + .travis.yml | 6 +- Jenkinsfile | 14 +- README.md | 14 +- bin/convertAlleleCounts.r | 93 + bin/run_ascat.r | 58 + docs/abstracts/2016-09-KICR.md | 44 + docs/abstracts/2017-05-ESHG.md | 31 + docs/abstracts/2018-05-PMC.md | 48 + docs/abstracts/2018-06-EACR25.md | 59 + docs/abstracts/2018-06-NPMI.md | 50 + docs/abstracts/2018-07-JOBIM.md | 43 + docs/ascat.md | 138 + docs/input.md | 64 +- docs/output.md | 387 +- docs/posters/ESHG_2017_Mgarcia.pdf | Bin 0 -> 317239 bytes docs/posters/ESHG_2017_Mgarcia.svg | 11017 +++++++++++++++++++++++ docs/posters/PMC_2018_Mgarcia.pdf | Bin 0 -> 307620 bytes docs/posters/PMC_2018_Mgarcia.svg | 12095 ++++++++++++++++++++++++++ docs/reference.md | 29 + docs/usage.md | 2 +- docs/use_cases.md | 122 + main.nf | 13 +- {bin => scripts}/ascat.R | 0 {bin => scripts}/build_reference.sh | 0 {bin => scripts}/download_docker.sh | 0 {bin => scripts}/run_tests.sh | 37 +- scripts/speedseq.filter.awk | 50 + 28 files changed, 24307 insertions(+), 141 deletions(-) create mode 100644 bin/convertAlleleCounts.r create mode 100644 bin/run_ascat.r create mode 100644 docs/abstracts/2016-09-KICR.md create mode 100644 docs/abstracts/2017-05-ESHG.md create mode 100644 docs/abstracts/2018-05-PMC.md create mode 100644 docs/abstracts/2018-06-EACR25.md create mode 100644 docs/abstracts/2018-06-NPMI.md create mode 100644 docs/abstracts/2018-07-JOBIM.md create mode 100644 docs/ascat.md create mode 100644 docs/posters/ESHG_2017_Mgarcia.pdf create mode 100644 docs/posters/ESHG_2017_Mgarcia.svg create mode 100644 docs/posters/PMC_2018_Mgarcia.pdf create mode 100644 docs/posters/PMC_2018_Mgarcia.svg create mode 100644 docs/use_cases.md rename {bin => scripts}/ascat.R (100%) rename {bin => scripts}/build_reference.sh (100%) rename {bin => scripts}/download_docker.sh (100%) rename {bin => scripts}/run_tests.sh (89%) create mode 100644 scripts/speedseq.filter.awk diff --git a/.circleci/config.yml b/.circleci/config.yml index c7fa3812d4..2a805a0ea4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -48,6 +48,22 @@ jobs: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin docker push nfcore/sareksnpeff:dev.${GENOME} + snpeffcanfam3_1: + docker: + - image: circleci/buildpack-deps:stretch + environment: + GENOME: CanFam3.1 + SNPEFF_CACHE_VERSION: 86 + steps: + - checkout + - setup_remote_docker + - run: + command: docker build -t nfcore/sareksnpeff:dev.${GENOME} containers/snpeff/. --build-arg GENOME=${GENOME} --build-arg SNPEFF_CACHE_VERSION=${SNPEFF_CACHE_VERSION} + - run: + command: | + echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin + docker push nfcore/sareksnpeff:dev.${GENOME} + vepgrch37: docker: - image: circleci/buildpack-deps:stretch @@ -96,13 +112,31 @@ jobs: - run: command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:dev.${GENOME} + vepcanfam3_1: + docker: + - image: circleci/buildpack-deps:stretch + environment: + GENOME: CanFam3.1 + SPECIES: canis_familiaris + VEP_VERSION: 95 + steps: + - checkout + - setup_remote_docker + - run: + command: docker build -t nfcore/sarekvep:dev.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} + no_output_timeout: 1h + - run: + command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:dev.${GENOME} + workflows: version: 2 build: jobs: + - snpeffcanfam3_1 - snpeffgrch37 - snpeffgrch38 - snpeffgrcm38 + - vepcanfam3_1 - vepgrch37 - vepgrch38 - vepgrcm38 diff --git a/.travis.yml b/.travis.yml index f0dc2b8adb..08f48f99a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ before_install: # PRs to master are only ok if coming from dev branch - '[ $TRAVIS_PULL_REQUEST = "false" ] || [ $TRAVIS_BRANCH != "master" ] || ([ $TRAVIS_PULL_REQUEST_SLUG = $TRAVIS_REPO_SLUG ] && [ $TRAVIS_PULL_REQUEST_BRANCH = "dev" ])' # Pull the docker image first so the test doesn't wait for this - - "travis_retry ./bin/download_docker.sh --test $TEST" + - "travis_retry ./scripts/download_docker.sh --test $TEST" install: # Install Nextflow @@ -39,8 +39,8 @@ install: # Build references if needed before_script: - - "${TRAVIS_BUILD_DIR}/bin/build_reference.sh --test $TEST --verbose" + - "${TRAVIS_BUILD_DIR}/scripts/build_reference.sh --test $TEST --verbose" # Actual tests script: - - "${TRAVIS_BUILD_DIR}/bin/run_tests.sh --test $TEST --verbose" + - "${TRAVIS_BUILD_DIR}/scripts/run_tests.sh --test $TEST --verbose" diff --git a/Jenkinsfile b/Jenkinsfile index e210d56d0b..42d6074d46 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -8,41 +8,41 @@ pipeline { stages { stage('Docker setup') { steps { - sh "./bin/download_docker.sh" + sh "./scripts/download_docker.sh" } } stage('Build references') { steps { sh "rm -rf references/" - sh "./bin/build_reference.sh" + sh "./scripts/build_reference.sh" } } stage('Germline') { steps { sh "rm -rf data/" sh "git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data" - sh "./bin/run_tests.sh --test GERMLINE" + sh "./scripts/run_tests.sh --test GERMLINE" sh "rm -rf data/" } } stage('Somatic') { steps { - sh "./bin/run_tests.sh --test SOMATIC" + sh "./scripts/run_tests.sh --test SOMATIC" } } stage('Targeted') { steps { - sh "./bin/run_tests.sh --test TARGETED" + sh "./scripts/run_tests.sh --test TARGETED" } } stage('Annotation') { steps { - sh "./bin/run_tests.sh --test ANNOTATEALL" + sh "./scripts/run_tests.sh --test ANNOTATEALL" } } stage('Multiple') { steps { - sh "./bin/run_tests.sh --test MULTIPLE" + sh "./scripts/run_tests.sh --test MULTIPLE" } } } diff --git a/README.md b/README.md index 4dcdff4454..a055578752 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # [![Sarek](docs/images/Sarek_logo.png "Sarek")](https://sarek.scilifelab.se/) [![nf-core](docs/images/nf-core_logo.png "Sarek")](https://nf-co.re/) -**An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing**. +**An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing** > :warning: This pipeline is a work in progress being ported to nf-core from [SciLifeLab/Sarek](https://github/SciLifeLab/Sarek/) @@ -21,7 +21,7 @@ Previously known as the Cancer Analysis Workflow (CAW), -Sarek is a workflow designed to run analyses on whole genome or targeted sequencing data from regular samples or tumour / normal pairs and could including additional relapses. +Sarek is a workflow designed to run analyses on whole genome or targeted sequencing data from regular samples or tumour / normal pairs and could include additional relapses. It's built using [Nextflow](https://www.nextflow.io), a domain specific language for workflow building, @@ -29,7 +29,7 @@ across multiple compute infrastructures in a very portable manner. Software dependencies are handled using [Conda](https://conda.io/), [Docker](https://www.docker.com) or [Singularity](https://www.sylabs.io/singularity/) - environment/container technologies that provide excellent reproducibility and ease of use. Thus making installation trivial and results highly reproducible. -It is listed on the [Elixir - Tools and Data Services Registry](https://bio.tools/Sarek), [Dockstore](https://dockstore.org/workflows/github.com/SciLifeLab/Sarek/) and [omicX - Bioinformatics tools](https://omictools.com/sarek-tool). +It's listed on the [Elixir - Tools and Data Services Registry](https://bio.tools/Sarek), [Dockstore](https://dockstore.org/workflows/github.com/SciLifeLab/Sarek/) and [omicX - Bioinformatics tools](https://omictools.com/sarek-tool). ## Documentation The nf-core/sarek pipeline comes with documentation about the pipeline, found in the `docs/` directory: @@ -41,17 +41,13 @@ The nf-core/sarek pipeline comes with documentation about the pipeline, found in * [Reference genomes](https://nf-co.re/usage/reference_genomes) * [Extra documentation on reference](docs/reference.md) 3. [Running the pipeline](docs/usage.md) + * [Examples](docs/use_cases.md) * [Input files documentation](docs/input.md) * [Extra documentation on variant calling](docs/variantcalling.md) * [Documentation about containers](docs/containers.md) * [Extra documentation for targeted sequencing](docs/targetseq.md) - - * [Intervals documentation](docs/INTERVALS.md) - * [Command line parameters](docs/PARAMETERS.md) - * [Examples](docs/USE_CASES.md) - * [Processes documentation](docs/PROCESS.md) 4. [Output and how to interpret the results](docs/output.md) - * [Complementary information about ASCAT](docs/ASCAT.md) + * [Complementary information about ASCAT](docs/ascat.md) * [Extra documentation on annotation](docs/annotation.md) 5. [Troubleshooting](https://nf-co.re/usage/troubleshooting) diff --git a/bin/convertAlleleCounts.r b/bin/convertAlleleCounts.r new file mode 100644 index 0000000000..302e45384c --- /dev/null +++ b/bin/convertAlleleCounts.r @@ -0,0 +1,93 @@ +#!/bin/env Rscript +# Description: +# R-script for converting output from AlleleCount to BAF and LogR values. +# +# Input: +# AlleleCounter output file for tumor and normal samples +# The first line should contain a header describing the data +# The following columns and headers should be present: +# CHR POS Count_A Count_C Count_G Count_T Good_depth +# +# Output: +# BAF and LogR tables (tab delimited text files) +################################################################################ + +##First read in the arguments listed at the command line +args = commandArgs(trailingOnly=TRUE) + +## args is now a list of character vectors +## First check to see if arguments are passed. +if(length(args)<5){ + stop("No input files supplied\n\nUsage:\nRscript convertAlleleCounts.r tumorid tumorac normalid normalac gender\nWhere:\ntumorid - id of tumor sample\ntumorac - output from AlleleCount for the tumor\nnormalid - id of normal sample\nnormalac - output from AlleleCount for the normal\ngender - XX or XY\n\n") +} else{ + tumorid = args[1] + tumorac = args[2] + normalid = args[3] + normalac = args[4] + gender = args[5] +} + +tumorcounts = read.table(tumorac, header=F, sep="\t") +normalcounts = read.table(normalac, header=F, sep="\t") + +SNPpos = matrix(nrow = dim(normalcounts)[1],ncol = 2) + +rownames(SNPpos) = paste("snp",1:dim(SNPpos)[1],sep="") + +#Change rownames to "chr_pos" instead, such as 1_44552 +#This does not exactly work: +#rownames(SNPpos) = apply(cbind(tumorcounts[,1], tumorcounts[,2]), 1, paste, collapse="_") +#This is for compatibility with gc correction file + +colnames(SNPpos) = c("Chr","Position") +SNPpos[,1] = as.vector(normalcounts[,1]) +SNPpos[,2] = normalcounts[,2] + +#Caclulate BAF +Tumor_BAF = matrix(nrow = dim(normalcounts)[1],ncol = 1) +rownames(Tumor_BAF) = rownames(SNPpos) +colnames(Tumor_BAF) = c(tumorid) +acgt = tumorcounts[,c(3:6)] +acgts = t(apply(acgt,1,sort)) +Tumor_BAF[,1] = acgts[,4]/(acgts[,3]+acgts[,4]) +Tumor_BAF[,1] = ifelse(runif(length(Tumor_BAF[,1]))<0.5,Tumor_BAF[,1],1-Tumor_BAF[,1]) +Tumor_BAF[is.nan(Tumor_BAF)]=NA + +Germline_BAF = matrix(nrow = dim(normalcounts)[1],ncol = 1) +rownames(Germline_BAF) = rownames(SNPpos) +colnames(Germline_BAF) = c(normalid) +acgt = normalcounts[,c(3:6)] +acgts = t(apply(acgt,1,sort)) +Germline_BAF[,1] = acgts[,4]/(acgts[,3]+acgts[,4]) +Germline_BAF[,1] = ifelse(runif(length(Germline_BAF[,1]))<0.5,Germline_BAF[,1],1-Germline_BAF[,1]) +Germline_BAF[is.nan(Germline_BAF)]=NA + + +Tumor_LogR = matrix(nrow = dim(normalcounts)[1],ncol = 1) +Germline_LogR = matrix(nrow = dim(normalcounts)[1],ncol = 1) +rownames(Tumor_LogR) = rownames(SNPpos) +colnames(Tumor_LogR) = c(tumorid) +rownames(Germline_LogR) = rownames(SNPpos) +colnames(Germline_LogR) = c(normalid) +Tumor_LogR[,1] = log(tumorcounts[,7]/normalcounts[,7],2) +Germline_LogR[,1] = 0 +Tumor_LogR[is.infinite(Tumor_LogR)]=NA +if(gender=="XY") { + Tumor_LogR[SNPpos[,1]=="X",1] = Tumor_LogR[SNPpos[,1]=="X",1]-1 + Germline_LogR[SNPpos[,1]=="X",1] = Germline_LogR[SNPpos[,1]=="X",1]-1 +} +Tumor_LogR[,1] = Tumor_LogR[,1] - median(Tumor_LogR[,1],na.rm=T) +# set regions with 0 reads in tumor and normal to a LogR of 0. +Tumor_LogR[is.na(Tumor_LogR[,1]),1] = 0 + +# limit the number of digits: +Tumor_LogR = round(Tumor_LogR,4) +Tumor_BAF = round(Tumor_BAF,4) +Germline_LogR = round(Germline_LogR,4) +Germline_BAF = round(Germline_BAF,4) + +# write output to files +write.table(cbind(SNPpos,Tumor_LogR),paste(tumorid,".LogR",sep=""),sep="\t",row.names=T,col.names=NA,quote=F) +write.table(cbind(SNPpos,Tumor_BAF),paste(tumorid,".BAF",sep=""),sep="\t",row.names=T,col.names=NA,quote=F) +write.table(cbind(SNPpos,Germline_LogR),paste(normalid,".LogR",sep=""),sep="\t",row.names=T,col.names=NA,quote=F) +write.table(cbind(SNPpos,Germline_BAF),paste(normalid,".BAF",sep=""),sep="\t",row.names=T,col.names=NA,quote=F) diff --git a/bin/run_ascat.r b/bin/run_ascat.r new file mode 100644 index 0000000000..6921f98c82 --- /dev/null +++ b/bin/run_ascat.r @@ -0,0 +1,58 @@ +#!/bin/env Rscript +args = commandArgs(trailingOnly=TRUE) +if(length(args)<6){ + stop("No input files supplied\n\nUsage:\nRscript run_ascat.r tumor_baf tumor_logr normal_baf normal_logr tumor_sample_name baseDir gcfile\n\n") +} else{ + tumorbaf = args[1] + tumorlogr = args[2] + normalbaf = args[3] + normallogr = args[4] + tumorname = args[5] + baseDir = args[6] + gcfile = args[7] +} + +source(paste(baseDir,"/scripts/ascat.R", sep="")) + +if(!require(RColorBrewer)){ + source("http://bioconductor.org/biocLite.R") + biocLite("RColorBrewer", suppressUpdates=TRUE, lib="$baseDir/scripts") + library(RColorBrewer) +} +options(bitmapType='cairo') + +#Load the data +ascat.bc <- ascat.loadData(Tumor_LogR_file=tumorlogr, Tumor_BAF_file=tumorbaf, Germline_LogR_file=normallogr, Germline_BAF_file=normalbaf) + +#GC wave correction +ascat.bc = ascat.GCcorrect(ascat.bc, gcfile) + +#Plot the raw data +ascat.plotRawData(ascat.bc) + +#Segment the data +ascat.bc <- ascat.aspcf(ascat.bc) + +#Plot the segmented data +ascat.plotSegmentedData(ascat.bc) + +#Run ASCAT to fit every tumor to a model, inferring ploidy, normal cell contamination, and discrete copy numbers +ascat.output <- ascat.runAscat(ascat.bc, gamma=1) + +#Write out segmented regions (including regions with one copy of each allele) +#write.table(ascat.output$segments, file=paste(tumorname, ".segments.txt", sep=""), sep="\t", quote=F, row.names=F) + +#Write out CNVs in bed format +cnvs=ascat.output$segments[2:6] +write.table(cnvs, file=paste(tumorname,".cnvs.txt",sep=""), sep="\t", quote=F, row.names=F, col.names=T) + +#Write out purity and ploidy info +summary <- tryCatch({ + matrix(c(ascat.output$aberrantcellfraction, ascat.output$ploidy), ncol=2, byrow=TRUE)}, error = function(err) { + # error handler picks up where error was generated + print(paste("Could not find optimal solution: ",err)) + return(matrix(c(0,0),nrow=1,ncol=2,byrow = TRUE)) + } +) +colnames(summary) <- c("AberrantCellFraction","Ploidy") +write.table(summary, file=paste(tumorname,".purityploidy.txt",sep=""), sep="\t", quote=F, row.names=F, col.names=T) diff --git a/docs/abstracts/2016-09-KICR.md b/docs/abstracts/2016-09-KICR.md new file mode 100644 index 0000000000..3b3df35eec --- /dev/null +++ b/docs/abstracts/2016-09-KICR.md @@ -0,0 +1,44 @@ +# The XVth KICancer Retreat 2016 + +## Cancer Analysis Workflow Of Tumor/Normal Pairs At The National Genomics Infrastructure Of SciLifeLab + +Maxime Garcia +Pelin Akan, +Teresita Díaz de Ståhl, +Jesper Eisfeldt, +Szilveszter Juhos, +Malin Larsson, +Björn Nystedt, +Pall Olason, +Monica Nistér, +Max Käller + +BarnTumörBanken, Department of Oncology Pathology, Karolinska Institutet, Science for Life Laboratory + +One of the most prominent usage of NGS is whole genome sequencing (WGS). The +National Genomics Infrastructure (NGI) at Science for Life Laboratory is today +providing WGS and germ line variant analysis. However, building a robust and +reliable bioinformatics workflow to find somatic mutations is challenging: +tumor samples are heterogeneous, likely contain structural variants and +multiple sub-clones besides the normal tissue. + +We are presenting our workflow that is designed to analyze WGS tumor/normal +data in a high-throughput environment. The framework is based on the Nextflow +domain-specific language on top of Java/Groovy. Using Nextflow we are able to +utilize both the Slurm load balancing environment and local execution, +implementing data flow forks and joins, call external software etc. Individual +sub-steps of a complex flow can be connected and restarted after failure from +the last execution point. + +The actual preprocessing workflow is based on BWA as an aligner and GATK best +practice steps. To achieve a consensus variant call different variant callers +can be added, currently MuTect2, Strelka and VarDict are supported, more to be +added. Structural variants are going to be estimated by Manta, ploidy and +sample heterogeneity is measured by ASCAT. The expected output of the workflow +is a VCF file presenting filtered, prioritized and annotated polymorphisms. + +As the Nextflow environment is flexible, we can add other tools or remove +obsolete ones as development progresses. The goal is to build a workflow for +cancer genome analysis that can be deployed to both research and clinical +environments and are going to be included as a standard workflow at NGI during +the fall of 2016. diff --git a/docs/abstracts/2017-05-ESHG.md b/docs/abstracts/2017-05-ESHG.md new file mode 100644 index 0000000000..d87f473a96 --- /dev/null +++ b/docs/abstracts/2017-05-ESHG.md @@ -0,0 +1,31 @@ +# European Human Genetics Conference 2017 + +## CAW - Cancer Analysis Workflow to process normal/tumor WGS data + +Maxime Garcia 1, +Szilveszter Juhos 2, +Malin Larsson 3, +Teresita Díaz de Ståhl 4, +Jesper Eisfeldt 5, +Sebastian DiLorenzo 6, +Pall Olason 7, +Björn Nystedt 7, +Monica Nistér 4, +Max Käller 8 + +1. BarnTumörBanken, Department of Oncology Pathology, Science for Life Laboratory, Karolinska Institutet +2. Department of Biochemistry and Biophysics, Science for Life Laboratory, Stockholm University +3. Science for Life laboratory, Department of Physics, Chemistry and Biology, Linköping University +4. BarnTumörBanken, Department of Oncology Pathology, Karolinska Institutet +5. Clinical Genetics, Department of Molecular Medicine and Surgery, Karolinska Institutet +6. Department of Medical Sciences, National Bioinformatics Infrastructure Sweden, Science for Life Laboratory, Uppsala University +7. Science for Life Laboratory, Department of Cell and Molecular Biology, Uppsala University +8. Science for Life Laboratory, School of Biotechnology, Division of Gene Technology, Royal Institute of Technology + +As whole genome sequencing is getting cheaper, it is viable to compare NGS data from normal and tumor samples of numerous patients. There are still many challenges, mostly regarding bioinformatics: datasets are huge, workflows are complex, and there are multiple tools to choose from for somatic and structural variants and quality control. + +We are presenting CAW (Cancer Analysis Workflow) a complete open source pipeline to resolve somatic variants from WGS data: it is written in Nextflow, a domain specific language for workflow building. We are utilizing GATK best practices to align, realign and recalibrate short-read data in parallel for both tumor and normal sample. After these preprocessing steps several somatic variant callers scan the resulting BAM files; MuTect1, MuTect2 and Strelka are used to find somatic SNVs and small indels.For structural variants we use Manta. Furthermore, we are applying ASCAT to estimate sample heterogeneity, ploidy and CNVs. + +The software can start the analysis from raw FASTQ files, from the realignment step, or directly with any subset of variant callers. At the end of the analysis the resulting VCF files are merged to facilitate further downstream processing, though the individual results are also retained. The flow is capable of accommodating further variant calling software or CNV callers. It is also prepared to process normal - tumor - and several relapse samples. + +Besides variant calls, the workflow provides quality controls presented by MultiQC. A docker image is also available, the open source software can be downloaded from https://github.com/SciLifeLab/CAW . diff --git a/docs/abstracts/2018-05-PMC.md b/docs/abstracts/2018-05-PMC.md new file mode 100644 index 0000000000..7e25e269b4 --- /dev/null +++ b/docs/abstracts/2018-05-PMC.md @@ -0,0 +1,48 @@ +# Keystone Symposia - Precision Medicine in Cancer + +## Sarek, a workflow for WGS analysis of germline and somatic mutations + +Maxime Garcia 123*, +Szilveszter Juhos 123*, +Malin Larsson 456, +Teresita Díaz de Ståhl 13, +Johanna Sandgren 13, +Jesper Eisfeldt 73, +Sebastian DiLorenzo 85A, +Marcel Martin B3C, +Pall Olason 95A, +Phil Ewels B2C, +Björn Nystedt 95A*, +Monica Nistér 13, +Max Käller 2D, +*Corresponding Author + +1. Barntumörbanken, Dept. of Oncology Pathology; +2. Science for Life Laboratory; +3. Karolinska Institutet; +4. Dept. of Physics, Chemistry and Biology; +5. National Bioinformatics Infrastructure Sweden, Science for Life Laboratory; +6. Linköping University; +7. Clinical Genetics, Dept. of Molecular Medicine and Surgery; +8. Dept. of Medical Sciences; +9. Dept. of Cell and Molecular Biology; +A. Uppsala University; +B. Dept. of Biochemistry and Biophysics; +C. Stockholm University; +D. School of Biotechnology, Division of Gene Technology, Royal Institute of Technology + +We present Sarek, a complete Open Source pipeline to resolve germline and somatic variants from WGS data: it is written in Nextflow, a domain-specific language for workflow building. +Sarek is based on GATK best practices to prepare short-read data, in parallel for a tumor/normal pair sample. +After these preprocessing steps several variant callers scan the resulting BAM files; For structural variants we use Manta. +Strelka and GATK HaplotypeCaller are used to find germline variants and for somatic calls we use MuTect2 and Strelka. +Finally, we apply ASCAT to estimate sample heterogeneity, ploidy and CNVs. +Checkpoints allow to start the software from different states. +At the end of the analysis the resulting VCF files are annotated to facilitate further downstream processing. +The flow is capable of accommodating further variant callers. +It can also process only the normal sample, tumor/normal pairs or even normal, tumor and several relapse samples. +Besides variant calls, the workflow provides quality controls presented by MultiQC. +For easy sharing, installation, and to ensure reproducibility, containers (Docker and Singularity) are available. +The MIT licensed open source code can be downloaded from GitHub. + +The authors thank the Swedish Childhood Cancer Foundation for the funding of Barntumörbanken. +We would like to acknowledge support from Science for Life Laboratory, the National Genomics Infrastructure, NGI, and UPPMAX for providing assistance in massive parallel sequencing and computational infrastructure. diff --git a/docs/abstracts/2018-06-EACR25.md b/docs/abstracts/2018-06-EACR25.md new file mode 100644 index 0000000000..ca86f2e658 --- /dev/null +++ b/docs/abstracts/2018-06-EACR25.md @@ -0,0 +1,59 @@ +# 25th Biennial Congress Of The European Association For Cancer Research 2018 + +## Somatic and germline calls from tumour/normal whole genome data: bioinformatics workflow for reproducible research + + +Szilveszter Juhos 1, +Maxime Garcia 2, +Teresita Díaz de Ståhl 3, +Johanna Sandgren 3, +Markus Mayrhofer 4, +Max Käller 5, +Björn Nystedt 6, +Monica Nistér 3 + +1. Karolinska Institutet, Department of Oncology Pathology, Stockholm, Sweden. +2. Karolinska Institutet- Science for Life Laboratory, Department of Oncology-Pathology, Stockholm, Sweden. +3. Karolinska Institutet, Department of Oncology-Pathology, Stockholm, Sweden. +4. Science for Life Laboratory, Uppsala University, Uppsala, Sweden. +5. Science for Life Laboratory, Royal Institute of Technology- School of Biotechnology- Division of Gene Technology, Stockholm, Sweden. +6. Science for Life Laboratory, Department of Cell and Molecular Biology- National Bioinformatics Infrastructure Sweden- Uppsala University, Uppsala, Sweden. + +### Introduction + +Whole-genome sequencing of cancer tumours is more a research tool nowadays, but going to be used in clinical settings in +the near future to facilitate precision medicine. While large institutions have built up in-house bioinformatics +solutions for their own data analysis, robust and portable workflows combining multiple software have been lacking, +making it difficult for individual research groups to utilise the potential of this research field. Here we present +Sarek, a robust, easy-to-install workflow for identification of both somatic and germline mutations from paired +tumour/normal/relapse samples. + +### Material and Methods + +Sarek is open source and implemented in Nextflow; a domain specific programming language to enable portability and +reproducibility. With the help of docker containers the versions of the underlying software can be maintained. +Furthermore, with Singularity it is possible to run the workflow on protected clusters with no internet connection. + +The workflow starts from raw FASTQ files, and follows the GATK best practices to prepare the recalibrated files with +joint realignment around indels for both the tumour and the normal data. Reads are alignment to the GRCh38 human +reference in an ALT-aware settings using BWA, however, it is possible to assign other references. HaplotypeCaller and +Strelka2 germline calls are collected for both the tumour and the normal sample, and Manta provides germline structural +variants. The somatic variations are calculated by running MuTect2, Strelka and FreeBayes (and MuTect1 optionally). +Somatic structural variants are delivered by Manta, and ASCAT estimates ploidy, tumour heterogeneity and CNVs. The +resulting variant call files are annotated by SnpEff and Ensembl-VEP. The annotated calls are further filtered and +prioritised by our custom methods. During running the workflow quality control metrics are also calculated and +aggregated by MultiQC. + +### Results and Discussions + +Sarek was validated on a real dataset with known golden set of somatic mutations. In a real settings, whole-genome +sequencing (WGS, 45-60x coverage) of patient-matched tumor and blood derived-DNA is being performed on a set of 80 +pediatric brain tumor samples of the Swedish Childhood Tumor Biobank. The workflow helps to produce, filter, prioritise +and characterise both germline and somatic variations. + +### Conclusion + +Sarek is a portable bioinformatics pipeline for WGS normal/tumour matched samples, aiding precision medicine by improved +subtyping and to gain novel functional insights in a reproducible framework. + + diff --git a/docs/abstracts/2018-06-NPMI.md b/docs/abstracts/2018-06-NPMI.md new file mode 100644 index 0000000000..ef15cc035f --- /dev/null +++ b/docs/abstracts/2018-06-NPMI.md @@ -0,0 +1,50 @@ +# The Nordic Precision Medicine Initiative - Meeting No 5 + +## Sarek, a portable workflow for WGS analysis of germline and somatic mutations + +Maxime Garcia 123*, +Szilveszter Juhos 123*, +Malin Larsson 456, +Teresita Díaz de Ståhl 13, +Johanna Sandgren 13, +Jesper Eisfeldt 73, +Sebastian DiLorenzo 85A, +Marcel Martin B5C, +Pall Olason 95A, +Phil Ewels B2C, +Björn Nystedt 95A*, +Monica Nistér 13, +Max Käller 2D, +*Corresponding Author + +1. Barntumörbanken, Dept. of Oncology Pathology; +2. Science for Life Laboratory; +3. Karolinska Institutet; +4. Dept. of Physics, Chemistry and Biology; +5. National Bioinformatics Infrastructure Sweden, Science for Life Laboratory; +6. Linköping University; +7. Clinical Genetics, Dept. of Molecular Medicine and Surgery; +8. Dept. of Medical Sciences; +9. Dept. of Cell and Molecular Biology; +A. Uppsala University; +B. Dept. of Biochemistry and Biophysics; +C. Stockholm University; +D. School of Biotechnology, Division of Gene Technology, Royal Institute of Technology + +We present Sarek, a portable Open Source pipeline to resolve germline and somatic variants from WGS data: it is written in Nextflow, a domain-specific language for workflow building. +It processes normal samples or normal/tumor pairs (with the option to include matched relapses). + +Sarek is based on GATK best practices to prepare short-read data, which is done in parallel for a tumor/normal pair sample. +After these preprocessing steps several variant callers scan the resulting BAM files: Manta for structural variants; Strelka and GATK HaplotypeCaller for germline variants; Freebayes, MuTect1, MuTect2 and Strelka for somatic variants; ASCAT to estimate sample heterogeneity, ploidy and CNVs. +At the end of the analysis the resulting VCF files can be annotated by SNPEff and/or VEP to facilitate further downstream processing. +Our ongoing effort focuses in filtering and prioritizing the annotated variants. + +Sarek is based on Docker and Singularity containers, enabling version tracking, reproducibility and handling sensitive data. +It is designed with flexible environments in mind, like running on a local fat node, a HTC cluster or in a cloud environment like AWS. +The workflow is capable of accommodating further variant callers. +Besides variant calls, the workflow provides quality controls presented by MultiQC. +Checkpoints allow the software to be started from FastQ, BAM or VCF. +Besides WGS data, it is capable to process inputs from WES or gene panels. +The pipeline currently use GRCh37 or GRCh38 as a reference genome, it is also possible to add custom genomes. +It has been successfully used to analyze more than two hundred WGS samples sent to National Genomics Infrastructure (Science for Life Laboratory) from different users. +The MIT licensed Open Source code can be downloaded from GitHub. diff --git a/docs/abstracts/2018-07-JOBIM.md b/docs/abstracts/2018-07-JOBIM.md new file mode 100644 index 0000000000..19e42d372c --- /dev/null +++ b/docs/abstracts/2018-07-JOBIM.md @@ -0,0 +1,43 @@ +# Journées Ouvertes en Biologie, Informatique et Mathématiques 2018 + +## Sarek, a portable workflow for WGS analysis of germline and somatic mutations + +Maxime Garcia 123, +Szilveszter Juhos 123, +Malin Larsson 456, +Teresita Díaz de Ståhl 13, +Johanna Sandgren 13, +Jesper Eisfeldt 73, +Sebastian DiLorenzo 85A, +Marcel Martin B5C, +Pall Olason 95A, +Phil Ewels B2C, +Björn Nystedt 95A, +Monica Nistér 13, +Max Käller 2D + + Max Käller + +1. Barntumörbanken, Dept. of Oncology Pathology; +2. Science for Life Laboratory; +3. Karolinska Institutet; +4. Dept. of Physics, Chemistry and Biology; +5. National Bioinformatics Infrastructure Sweden, Science for Life Laboratory; +6. Linköping University; +7. Clinical Genetics, Dept. of Molecular Medicine and Surgery; +8. Dept. of Medical Sciences; +9. Dept. of Cell and Molecular Biology; +A. Uppsala University; +B. Dept. of Biochemistry and Biophysics; +C. Stockholm University; +D. School of Biotechnology, Division of Gene Technology, Royal Institute of Technology + +We present Sarek, a portable Open Source pipeline to resolve germline and somatic variants from WGS data: it is written in Nextflow, a domain-specific language for workflow building. It processes normal samples or normal/tumor pairs (with the option to include matched relapses). + +Sarek is based on GATK best practices to prepare short-read data, which is done in parallel for a tumor/normal pair sample. After these preprocessing steps several variant callers scan the resulting BAM files: Manta for structural variants; Strelka and GATK HaplotypeCaller for germline variants; Freebayes, MuTect2 and Strelka for somatic variants; ASCAT and Control-FREEC to estimate sample heterogeneity, ploidy and CNVs. At the end of the analysis the resulting VCF files can be annotated by SNPEff and/or VEP to facilitate further downstream processing. Our ongoing effort focuses in filtering and prioritizing the annotated variants. + +Sarek is based on Docker and Singularity containers, enabling version tracking, reproducibility and handling sensitive data. It is designed with flexible environments in mind, like running on a local fat node, a HTC cluster or in a cloud environment like AWS. The workflow is modular and capable of accommodating further variant callers. Besides variant calls, the workflow provides quality controls presented by MultiQC. Checkpoints allow the software to be started from FastQ, BAM or VCF. Besides WGS data, it is capable to process inputs from WES or gene panels. + +The pipeline currently uses GRCh37 or GRCh38 as a reference genome, it is also possible to add custom genomes. It has been successfully used to analyze more than two hundred WGS samples sent to National Genomics Infrastructure (Science for Life Laboratory) from different users. The MIT licensed Open Source code can be downloaded from GitHub. + +The authors thank the Swedish Childhood Cancer Foundation for the funding of Barntumörbanken. We would like to acknowledge support from Science for Life Laboratory, the National Genomics Infrastructure, NGI, and UPPMAX for providing assistance in massive parallel sequencing and computational infrastructure. diff --git a/docs/ascat.md b/docs/ascat.md new file mode 100644 index 0000000000..695795f60b --- /dev/null +++ b/docs/ascat.md @@ -0,0 +1,138 @@ +# ASCAT + +## Introduction + +ASCAT is a software for performing allele-specific copy number analysis of tumor samples and for estimating tumor ploidy and purity (normal contamination). +ASCAT is written in R and available here: [github.com/Crick-CancerGenomics/ascat](https://github.com/Crick-CancerGenomics/ascat). + +To run ASCAT on NGS data we need BAM files for the tumor and normal samples, as well as a loci file with SNP positions. +If ASCAT is run on SNP array data, the loci file contains the SNPs on the chip. +When runnig ASCAT on NGS data we can use the same loci file, for exampe the one corresponding to the AffymetrixGenome-Wide Human SNP Array 6.0, but we can also choose a loci file of our choice with i.e. SNPs detected in the 1000 Genomes project. + +### BAF and LogR values + +Running ASCAT on NGS data requires that the BAM files are converted into BAF and LogR values. +This can be done using the software [AlleleCount](https://github.com/cancerit/alleleCount) followed by a simple R script. +AlleleCount extracts the number of reads in a BAM file supporting each allele at specified SNP positions. +Based on this, BAF and logR can be calculated for every SNP position i as: + +``` +BAFi(tumor)=countsBi(tumor)/(countsAi(tumor)+countsBi(tumor)) +BAFi(normal)=countsBi(normal)/(countsAi(normal)+countsBi(normal)) +LogRi(tumor)=log2((countsAi(tumor)+countsBi(tumor))/(countsAi(normal)+countsBi(normal)) - median(log2((countsA(tumor)+countsB(tumor))/(countsA(normal)+countsB(normal))) +LogRi(normal)=0 +``` + +For male samples, the X chromosome markers have special treatment: + +``` +LogRi(tumor)=log2((countsAi(tumor)+countsBi(tumor))/(countsAi(normal)+countsBi(normal))-1 - median(log2((countsA(tumor)+countsB(tumor))/(countsA(normal)+countsB(normal))-1) +``` + +where: +*i* corresponds to the postions of all SNPs in the loci file. +*CountsA* and *CountsB* are vectors containing number of reads supporting the *A* and *B* alleles of all SNPs +*A* = the major allele +*B* = the minor allele +*Minor* and *major* alleles are defined in the loci file (it actually doesn't matter which one is defied as A and B in this application) + +Calculation of LogR and BAF based on AlleleCount output is done as in [runASCAT.R](https://github.com/cancerit/ascatNgs/tree/dev/perl/share/ascat/runASCAT.R) in the ascatNgs repository on Github. + +### Loci file + +The loci file was created based on the 1000Genomes latest release (phase 3, releasedate 20130502), available [here](ftp://ftp.1000genomes.ebi.ac.uk/vol1/ftp//release/20130502/ALL.wgs.phase3_shapeit2_mvncall_integrated_v5b.20130502.sites.vcf.gz). +The following filter was applied: Only bi-allelc SNPs with minor allele frequencies > 0.3. + +The loci file was originally generated for GRCh37. +It was translated into GRCh38 using the tool liftOver available at the UCSC Genome Browser. +To run liftOver the loci file was first written in bed format: + +```bash +awk '{print "chr"$1":"$2"-"$2}' 1000G_phase3_20130502_SNP_maf0.3.loci > 1000G_phase3_20130502_SNP_maf0.3.bed +``` + +Using the web interface to liftOver at [genome.ucsc.edu](https://genome.ucsc.edu/cgi-bin/hgLiftOver) the file was translated into GRCh38 coordinates. +LiftOver was possible for 3261270 out of 3268043 SNPs. +The converted SNP positions were printed in the format required by AlleleCounter by: + +```bash +more hglft_genome_5834_13aba0.bed | awk 'BEGIN{FS="chr"} {print $2}' | awk 'BEGIN{FS="-"} {print $1}' | awk 'BEGIN{FS=":";OFS="\t"} {print $1,$2}' > 1000G_phase3_GRCh38_maf0.3.loci +``` + +### GC correction file +Input files for ASCAT's GC correction were created for the above loci files, using the scripts and instructions for this on [ASCAT's github repository](https://github.com/Crick-CancerGenomics/ascat/tree/master/gcProcessing) + +#### scripts and data for generating the GC correction file +The following scripts were downloaded from https://github.com/Crick-CancerGenomics/ascat/tree/master/gcProcessing: +- *createGCcontentFile.R* +- *createWindowBed.pl* +- *GCfileCreation.sh*. +To generate the GC correction file additional files are needed: +- *locifile* described above. +- *reference.fasta* is the genome reference file in fasta format. +The files are descibed in [Genomes and reference files documentation](REFERENCES.md). +- *chromosomesizes.txt* is a tab delimited text file containing the size of all chromosomes included in the loci file. +An example file is available in https://github.com/Crick-CancerGenomics/ascat/tree/master/gcProcessing/hg19.chrom.sizes + +#### Modification of createWindowBed.pl for our GRCh37 loci file +The genomc reference file we use in Sarek for GRCh37 is coded without "chr" in the chromosome names, while the genomcd referece file we use in Sarek for GRCh38 includes "chr" in the chromosome names. +The script https://github.com/Crick-CancerGenomics/ascat/tree/master/gcProcessing/createWindowBed.pl assumes that "chr" is included in the chromosome names of the reference file, so a small modification of this script was done for the process to work on our GRCh37 loci file. + +These two lines in createWindowBed.pl generate output (lines 61 and 64): +```perl +(61) print OUT "chr".$tab[1]."\t".$start."\t".$stop."\t".$tab[0]."\t".$tab[2]."\t".($w*2+1)."\n"; +(64) print OUT "chr".$tab[1]."\t".$start."\t".$stop."\t".$tab[0]."\t".$tab[2]."\t".($w*2)."\n"; +``` +and were changed to: +```perl +(61) print OUT $tab[1]."\t".$start."\t".$stop."\t".$tab[0]."\t".$tab[2]."\t".($w*2+1)."\n"; +(64) print OUT $tab[1]."\t".$start."\t".$stop."\t".$tab[0]."\t".$tab[2]."\t".($w*2)."\n"; +``` +After this modification the script works for our GRCh37 loci file. + +#### Process +The following sbatch script was run on the Uppmax cluster Rackham, to generate the CG correction files: +```bash +#!/bin/bash -l +#SBATCH -A projid +#SBATCH -p node +#SBATCH -t 24:00:00 +#SBATCH -J createGCfile +module load bioinfo-tools +module load BEDTools +module load R/3.5.0 +module load R_packages/3.5.0 +./GCfileCreation.sh 1000G_phase3_20130502_SNP_maf0.3.loci chrom.sizes 19 human_g1k_v37_decoy.fasta +``` +where: +*1000G_phase3_20130502_SNP_maf0.3.loci* is the loci file for GRCh37 described above +*human_g1k_v37_decoy.fasta* is the genome reference file used for GRCh37 +*chrom.sizes* is the list of the chromosome lengths in GRCh37. +Names of the chromosomes in chrom.sizes file must be the same as in the genome reference, so in case of GRCh37 we used "1", "2" etc and in GRCh38 we used "chr1", "chr2" etc. +*19* means that 19 cores are available for the script. + +This created GC correction files with the following column headers: +Chr Position 25 50 100 200 500 1000 2000 5000 10000 20000 50000 100000 200000 500000 1M 2M 5M 10M +This file gave an error when running ASCAT, and the error message suggested that it had to do with the column headers. +The Readme.txt in https://github.com/Crick-CancerGenomics/ascat/tree/master/gcProcessing suggested that the column headers should be: +Chr Position 25bp 50bp 100bp 200bp 500bp 1000bp 2000bp 5000bp 10000bp 20000bp 50000bp 100000bp 200000bp 500000bp 1M 2M 5M 10M +The column headers headers of the generated GC correction files were therefore manually edited. + +#### Format of GC correction file +The final files are tab-delimited with the following columns (and some example data): +Chr Position 25bp 50bp 100bp 200bp 500bp 1000bp 2000bp 5000bp 10000bp 20000bp 50000bp 100000bp 200000bp 500000bp 1M 2M 5M 10M +snp1 1 14930 0.541667 0.58 0.61 0.585 0.614 0.62 0.6 0.5888 0.588 0.4277 0.395041 0.380702 0.383259 0.341592 0.339747 0.386343 0.500537 0.511514 +snp2 1 15211 0.625 0.64 0.67 0.63 0.61 0.612 0.6135 0.591 0.5922 0.4358 0.39616 0.380411 0.383167 0.34163 0.339771 0.386417 0.500558 0.511511 +snp3 1 15820 0.541667 0.56 0.62 0.655 0.65 0.612 0.5885 0.5936 0.5797 0.4511 0.397771 0.379945 0.382999 0.341791 0.339832 0.386554 0.500579 0.511504 + +### Output +The ASCAT process gives several images as output, described in detail in this [book chapter](http://www.ncbi.nlm.nih.gov/pubmed/22130873). +The script also gives out a text file (*tumor.cnvs.txt*) with information about copy number state for all the segments predicted by ASCAT. +The output is a tab delimited text file with the following columns: chr startpos endpos nMajor nMinor +Where: +*chr* is the chromosome number +*startpos* is the start position of the segment +*endpos* is the end position of the segment +*nMajor* is number of copies of one of the allels (for example the chromosome inherited from the father) +*nMinor* is the number of copies of the other allele (for example the chromosome inherited of the mother) +The file *tumor.cnvs.txt* contains all segments predicted by ASCAT, both those with normal copy number (nMinor = 1 and nMajor =1) and those corresponding to copy number aberrations. diff --git a/docs/input.md b/docs/input.md index 49ec48d344..3b4502f039 100644 --- a/docs/input.md +++ b/docs/input.md @@ -1,5 +1,6 @@ -# TSV file for sample(s) +# Input Documentation +## Information about the TSV files Input files for Sarek can be specified using a TSV file given to the `--sample` command. The TSV file is a Tab Separated Value file with columns: * `subject gender status sample lane fastq1 fastq2` for step `mapping` with paired-end FASTQs @@ -11,8 +12,8 @@ The content of these columns is quite straight-forward: * `subject` designate the subject, it should be the ID of the Patient, and it must design only one patient * `gender` is the gender of the Patient, (XX or XY) * `status` is the status of the Patient, (0 for Normal or 1 for Tumor) -* `sample` designate the Sample, it should be the ID of the Sample (it is possible to have more than one tumor sample for each patient), it should design only one sample -* `lane` is used when the sample is multiplexed on several lanes +* `sample` designate the Sample, it should be the ID of the sample (it is possible to have more than one tumor sample for each patient, i.e. a tumor and a relapse), it must design only one sample +* `lane` is used when the sample is multiplexed on several lanes, it must be unique for each lane in the same sample * `fastq1` is the path to the first pair of the fastq file * `fastq2` is the path to the second pair of the fastq file * `bam` is the bam file @@ -31,7 +32,7 @@ Multiple TSV files can be specified if the path is enclosed in quotes. Somatic variant calling output will be in a specific directory for each normal/tumor pair. -# Example TSV file for a normal/tumor pair with FASTQ files +# Example TSV file for a normal/tumor pair with FASTQ files (step mapping) In this sample for the normal case there are 3 read groups, and 2 for the tumor. @@ -43,25 +44,12 @@ G15511 XX 1 D0ENMT D0ENM_1 pathToFiles/D0ENMACXX111207.1_1.fastq. G15511 XX 1 D0ENMT D0ENM_2 pathToFiles/D0ENMACXX111207.2_1.fastq.gz pathToFiles/D0ENMACXX111207.2_2.fastq.gz ``` -# Example TSV file for a normal/tumor pair with BAM files +# Path to a FASTQ directory for a single normal sample (step mapping) -In this sample for the normal case there are 3 read groups, and 2 for the tumor. - -``` -G15511 XX 0 C09DFN C09DF_1 pathToFiles/C09DFAC_1.bam -G15511 XX 0 C09DFN C09DF_2 pathToFiles/C09DFAC_2.bam -G15511 XX 0 C09DFN C09DF_3 pathToFiles/C09DFAC_3.bam -G15511 XX 1 D0ENMT D0ENM_1 pathToFiles/D0ENMAC_1.bam -G15511 XX 1 D0ENMT D0ENM_2 pathToFiles/D0ENMAC_2.bam -``` - -# Example TSV file for a normal/tumor pair with recalibrated BAM files - -The same way, if you have recalibrated BAMs and their indexes, you should use a structure like: +Input files for Sarek can be specified using the path to a FASTQ directory given to the `--sample` command only with the `mapping` step. -``` -G15511 XX 0 C09DFN pathToFiles/G15511.C09DFN.md.real.bam pathToFiles/G15511.C09DFN.md.real.bai -G15511 XX 1 D0ENMT pathToFiles/G15511.D0ENMT.md.real.bam pathToFiles/G15511.D0ENMT.md.real.bai +```bash +nextflow run nf-core/sarek --sample pathToDirectory ... ``` ## Input FASTQ file name best practices @@ -105,11 +93,41 @@ Read group information will be parsed from fastq file names according to this: - `PU` = sample - `RGLB` = lib -# Path to a FASTQ directory for a single normal sample +# Example TSV file for a normal/tumor pair with uBAM files (step mapping) -Input files for Sarek can be specified using the path to a FASTQ directory given to the `--sample` command only with the `mapping` step. +In this sample for the normal case there are 3 read groups, and 2 for the tumor. + +``` +G15511 XX 0 C09DFN C09DF_1 pathToFiles/C09DFAC_1.bam +G15511 XX 0 C09DFN C09DF_2 pathToFiles/C09DFAC_2.bam +G15511 XX 0 C09DFN C09DF_3 pathToFiles/C09DFAC_3.bam +G15511 XX 1 D0ENMT D0ENM_1 pathToFiles/D0ENMAC_1.bam +G15511 XX 1 D0ENMT D0ENM_2 pathToFiles/D0ENMAC_2.bam +``` + +# Example TSV file for a normal/tumor pair with non recalibrated BAM files (step recalibrate) + +The same way, if you have non recalibrated BAMs, their indexes and their recalibration tables, you should use a structure like: + +``` +G15511 XX 0 C09DFN pathToFiles/G15511.C09DFN.md.bam pathToFiles/G15511.C09DFN.md.bai pathToFiles/G15511.C09DFN.md.recal.table +G15511 XX 1 D0ENMT pathToFiles/G15511.D0ENMT.md.bam pathToFiles/G15511.D0ENMT.md.bai pathToFiles/G15511.D0ENMT.md.recal.table +``` + +# Example TSV file for a normal/tumor pair with recalibrated BAM files (step variantcalling) + +The same way, if you have recalibrated BAMs and their indexes, you should use a structure like: + +``` +G15511 XX 0 C09DFN pathToFiles/G15511.C09DFN.md.recal.bam pathToFiles/G15511.C09DFN.md.recal.bai +G15511 XX 1 D0ENMT pathToFiles/G15511.D0ENMT.md.recal.bam pathToFiles/G15511.D0ENMT.md.recal.bai +``` # VCF files for annotation Input files for Sarek can be specified using the path to a VCF directory given to the `--sample` command only with the `annotate` step. Multiple VCF files can be specified if the path is enclosed in quotes. + +```bash +nextflow run nf-core/sarek --step annotate --sample "results/VariantCalling/*/.vcf.gz" ... +``` diff --git a/docs/output.md b/docs/output.md index ec70888d40..08bd9b3b66 100644 --- a/docs/output.md +++ b/docs/output.md @@ -1,110 +1,325 @@ # nf-core/sarek: Output This document describes the output produced by the pipeline. -Most of the plots are taken from the MultiQC report, which summarises results at the end of the pipeline. ## Pipeline overview -The pipeline is built using [Nextflow](https://www.nextflow.io/) -and processes data using the following steps: +The pipeline processes data using the following steps: -1. **Preprocessing** _(based on [GATK best practices](https://software.broadinstitute.org/gatk/best-practices/))_ +1. [**Preprocessing**](#Preprocessing) _(based on [GATK best practices](https://software.broadinstitute.org/gatk/best-practices/))_ * Map reads to Reference - * [BWA](#BWA) + * `BWA mem` * Mark Duplicates - * [GATK MarkDuplicates](#MarkDuplicates) + * `GATK MarkDuplicates` * Base (Quality Score) Recalibration - * [GATK BaseRecalibrator](#BaseRecalibrator) - * [GATK GatherBQSRReports](#GatherBQSRReports) - * [GATK ApplyBQSR](#ApplyBQSR) -2. **Variant calling** + * `GATK BaseRecalibrator` + * `GATK GatherBQSRReports` + * `GATK ApplyBQSR` +2. [**Variant calling**](#Variant-Calling) * SNVs and small indels - * [Freebayes](#Freebayes) - * [GATK HaplotypeCaller](#HaplotypeCaller) - * [GATK GenotypeGVCFs](#GenotypeGVCFs) - * [GATK MuTect2](#MuTect2) - * [Strelka2](#Strelka2) + * [`FreeBayes`](#FreeBayes) + * [`GATK HaplotypeCaller`](#HaplotypeCaller) + * [`GATK GenotypeGVCFs`](#GenotypeGVCFs) + * [`GATK MuTect2`](#MuTect2) + * [`Strelka2`](#Strelka2) * Structural variants - * [Manta](#Manta) + * [`Manta`](#Manta) * Sample heterogeneity, ploidy and CNVs - * [alleleCounter](#alleleCounter) - * [ConvertAlleleCounts](#ConvertAlleleCounts) - * [ASCAT](#ASCAT) - * [samtools mpileup](#mpileup) - * [Control-FREEC](#Control-FREEC) -3. **Annotation** + * `alleleCounter` + * [`ConvertAlleleCounts`](#ConvertAlleleCounts) + * [`ASCAT`](#ASCAT) + * [`samtools mpileup`](#mpileup) + * [`Control-FREEC`](#Control-FREEC) +3. [**Annotation**](#Annotation) * Variant annotation - * [snpEff](#snpEff) - * [VEP (Variant Effect Predictor)](#VEP) -4. **QC and Reporting** + * [`snpEff`](#snpEff) + * [`VEP` (Variant Effect Predictor)](#VEP) +4. [**QC and Reporting**](#QC-and-reporting) * QC - * [FastQC](#FastQC) - * [Qualimap bamqc](#bamQC) - * [GATK MarkDuplicates](#MarkDuplicates-reports) - * [samtools stats](#Samtools-stats) - * [bcftools stats](#BCFtools) - * [VCFtools](#VCFtools) - * [snpeff](#snpEff-reports) + * [`FastQC`](#FastQC) + * [`Qualimap bamqc`](#bamQC) + * [`GATK MarkDuplicates`](#MarkDuplicates-reports) + * [`samtools stats`](#Samtools-stats) + * [`bcftools stats`](#bcftools-stats) + * [`VCFtools`](#VCFtools) + * [`snpeff`](#snpEff-reports) + * [`VEP`](#snpEff-reports) * Reporting - * [MultiQC](#MultiQC) + * [`MultiQC`](#MultiQC) ## Preprocessing -Sarek preprocessing raw FastQ files or unmapped BAM files is based on [GATK best practices](https://software.broadinstitute.org/gatk/best-practices/)). -BAM files with Recalibration tables can also be used as an input to start with the recalibration of said BAM files. +Sarek preprocesses raw FastQ files or unmapped BAM files, based on [GATK best practices](https://software.broadinstitute.org/gatk/best-practices/). -### BWA -[BWA](http://bio-bwa.sourceforge.net/) +BAM files with Recalibration tables can also be used as an input to start with the recalibration of said BAM files, for more information see [TSV files output information](#TSV-files) -### MarkDuplicates -[GATK MarkDuplicates](https://github.com/broadinstitute/gatk) +### Duplicate Marked BAM file(s) with Recalibration Table(s) -### BaseRecalibrator -[GATK BaseRecalibrator](https://github.com/broadinstitute/gatk) +This directory is the location for the BAM files delivered to users. Besides the duplicate marked BAM files, the recalibration tables (`*.recal.table`) are also stored, and can be used to create base recalibrated files. -### GatherBQSRReports -[GATK GatherBQSRReports](https://github.com/broadinstitute/gatk) +For further reading and documentation see the [data pre-processing workflow from the GATK best practices](https://software.broadinstitute.org/gatk/best-practices/workflow?id=11165). -### ApplyBQSR -[GATK ApplyBQSR](https://github.com/broadinstitute/gatk) +For all samples: +**Output directory: `results/Preprocessing/[SAMPLE]/DuplicateMarked`** + +* `[SAMPLE].md.bam`, `[SAMPLE].md.bai` and `[SAMPLE].recal.table` + * BAM file and index with Recalibration Table + +### Recalibrated BAM file(s) + +This directory is usually empty, it is the location for the final recalibrated BAM files. +Recalibrated BAM files are usually 2-3 times larger than the duplicate marked BAM files. +To re-generate recalibrated BAM file you have to apply the recalibration table delivered to the `DuplicateMarked` directory either within Sarek, or doing this recalibration step yourself. + +For further reading and documentation see the [data pre-processing workflow from the GATK best practices](https://software.broadinstitute.org/gatk/best-practices/workflow?id=11165). + +For all samples: +**Output directory: `results/Preprocessing/[SAMPLE]/Recalibrated`** + +* `[SAMPLE].recal.bam` and `[SAMPLE].recal.bai` + * BAM file and index + +### TSV files +The TSV files are autogenerated and can be used by Sarek for further processing and/or variant calling. + +For further reading and documentation see the [input documentation](https://github.com/nf-core/sarek/blob/master/docs/input.md). + +For all samples: +**Output directory: `results/Preprocessing/TSV`** + +* `duplicateMarked.tsv` and `recalibrated.tsv` + * TSV files to start Sarek from `recalibration` or `variantcalling` steps. +* `duplicateMarked_[SAMPLE].tsv` and `recalibrated_[SAMPLE].tsv` + * TSV files to start Sarek from `recalibration` or `variantcalling` steps for a specific sample. ## Variant Calling +All the results regarding variant-calling are collected in this directory. + +Recalibrated BAM files can also be used as an input to start the Variant Calling, for more information see [TSV files output information](#TSV-files) + +### FreeBayes +[FreeBayes](https://github.com/ekg/freebayes) is a Bayesian genetic variant detector designed to find small polymorphisms, specifically SNPs, indels, MNPs, and complex events smaller than the length of a short-read sequencing alignment.. +The single VCF file generated by `FreeBayes` being huge, it is recommended to flatten and filter this VCF, i.e. using the provided [SpeedSeq](https://github.com/nf-core/sarek/blob/master/scripts/speedseq.filter.awk) filter. + +For further reading and documentation see the [FreeBayes manual](https://github.com/ekg/freebayes/blob/master/README.md#user-manual-and-guide). -### Freebayes -[Freebayes](https://github.com/ekg/freebayes) +For a Tumor/Normal pair only: +**Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/FreeBayes`** + +* `FreeBayes_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz` and `FreeBayes_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.tbi` + * VCF with Tabix index ### HaplotypeCaller -[GATK HaplotypeCaller](https://github.com/broadinstitute/gatk) +[GATK HaplotypeCaller](https://github.com/broadinstitute/gatk) calls germline SNPs and indels via local re-assembly of haplotypes. + +Germline calls are provided for all samples, to able comparison of both tumor and normal for possible mixup. + +For further reading and documentation see the [HaplotypeCaller manual](https://software.broadinstitute.org/gatk/documentation/tooldocs/4.1.2.0/org_broadinstitute_hellbender_tools_walkers_haplotypecaller_HaplotypeCaller.php). + +For all samples: +**Output directory: `results/VariantCalling/[SAMPLE]/HaploTypeCaller`** + +* `HaplotypeCaller_[SAMPLE].vcf.gz` and `HaplotypeCaller_[SAMPLE].vcf.gz.tbi` + * VCF with Tabix index ### GenotypeGVCFs -[GATK GenotypeGVCFs](https://github.com/broadinstitute/gatk) +[GATK GenotypeGVCFs](https://github.com/broadinstitute/gatk) performs joint genotyping on one or more samples pre-called with HaplotypeCaller. + +Germline calls are provided for all samples, to able comparison of both tumor and normal for possible mixup. + +For further reading and documentation see the [GenotypeGVCFs manual](https://software.broadinstitute.org/gatk/documentation/tooldocs/4.1.2.0/org_broadinstitute_hellbender_tools_walkers_GenotypeGVCFs.php). + +For all samples: +**Output directory: `results/VariantCalling/[SAMPLE]/HaplotypeCallerGVCF`** + +* `HaplotypeCaller_[SAMPLE].g.vcf.gz` and `HaplotypeCaller_[SAMPLE].g.vcf.gz.tbi` + * VCF with Tabix index ### MuTect2 -[MuTect2](https://github.com/broadinstitute/gatk) +[GATK MuTect2](https://github.com/broadinstitute/gatk) calls somatic SNVs and indels via local assembly of haplotypes. + +For further reading and documentation see the [MuTect2 manual](https://software.broadinstitute.org/gatk/documentation/tooldocs/4.1.2.0/org_broadinstitute_hellbender_tools_walkers_mutect_Mutect2.php). + +For a Tumor/Normal pair only: +**Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/MuTect2`** + +* `MuTect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz` and `MuTect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.tbi` + * VCF with Tabix index ### Strelka2 -[Strelka2](https://github.com/Illumina/strelka) +[Strelka2](https://github.com/Illumina/strelka) is a fast and accurate small variant caller optimized for analysis of germline variation in small cohorts and somatic variation in tumor/normal sample pairs. + +For further reading and documentation see the [Strelka2 user guide](https://github.com/Illumina/strelka/blob/v2.9.x/docs/userGuide/README.md). + +For all samples: +**Output directory: `results/VariantCalling/[SAMPLE]/Strelka`** + +* `Strelka_Sample_genome.vcf.gz` and `Strelka_Sample_genome.vcf.gz.tbi` + * VCF with Tabix index +* `Strelka_Sample_variants.vcf.gz` and `Strelka_Sample_variants.vcf.gz.tbi` + * VCF with Tabix index + +For a Tumor/Normal pair: +**Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/Strelka`** + +* `Strelka_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_indels.vcf.gz` and `Strelka_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_indels.vcf.gz.tbi` + * VCF with Tabix index +* `Strelka_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_snvs.vcf.gz` and `Strelka_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_snvs.vcf.gz.tbi` + * VCF with Tabix index + +Using [Strelka Best Practices](https://github.com/Illumina/strelka/blob/v2.9.x/docs/userGuide/README.md#somatic-configuration-example) with the `candidateSmallIndels` from `Manta`: +**Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/Strelka`** +* `StrelkaBP_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_indels.vcf.gz` and `StrelkaBP_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_indels.vcf.gz.tbi` + * VCF with Tabix index +* `StrelkaBP_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_snvs.vcf.gz` and `StrelkaBP_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_snvs.vcf.gz.tbi` + * VCF with Tabix index ### Manta -[Manta](https://github.com/Illumina/manta) +[Manta](https://github.com/Illumina/manta) calls structural variants (SVs) and indels from mapped paired-end sequencing reads. +It is optimized for analysis of germline variation in small sets of individuals and somatic variation in tumor/normal sample pairs. +`Manta` provides a candidate list for small indels also that can be fed to `Strelka` following [Strelka Best Practices](https://github.com/Illumina/strelka/blob/v2.9.x/docs/userGuide/README.md#somatic-configuration-example. + +For further reading and documentation see the [Manta user guide](https://github.com/Illumina/manta/blob/master/docs/userGuide/README.md). + +For all samples: +**Output directory: `results/VariantCalling/[SAMPLE]/Manta`** -### alleleCounter +* `Manta_[SAMPLE].candidateSmallIndels.vcf.gz` and `Manta_[SAMPLE].candidateSmallIndels.vcf.gz.tbi` + * VCF with Tabix index +* `Manta_[SAMPLE].candidateSV.vcf.gz` and `Manta_[SAMPLE].candidateSV.vcf.gz.tbi` + * VCF with Tabix index + +For Normal sample only: +* `Manta_[NORMALSAMPLE].diploidSV.vcf.gz` and `Manta_[NORMALSAMPLE].diploidSV.vcf.gz.tbi` + * VCF with Tabix index + +For a Tumor sample only: +* `Manta_[TUMORSAMPLE].tumorSV.vcf.gz` and `Manta_[TUMORSAMPLE].tumorSV.vcf.gz.tbi` + * VCF with Tabix index + +For a Tumor/Normal pair only: +**Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/Manta`** + +* `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].candidateSmallIndels.vcf.gz` and `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].candidateSmallIndels.vcf.gz.tbi` + * VCF with Tabix index +* `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].candidateSV.vcf.gz` and `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].candidateSV.vcf.gz.tbi` + * VCF with Tabix index +* `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].diploidSV.vcf.gz` and `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].diploidSV.vcf.gz.tbi` + * VCF with Tabix index +* `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].somaticSV.vcf.gz` and `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].somaticSV.vcf.gz.tbi` + * VCF with Tabix index ### ConvertAlleleCounts +[ConvertAlleleCounts](https://github.com/nf-core/sarek/blob/master/bin/convertAlleleCounts.r) is a R-script for converting output from AlleleCount to BAF and LogR values. -### ASCAT +For a Tumor/Normal pair only: +**Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/ASCAT`** + +* `[TUMORSAMPLE].BAF` and `[NORMALSAMPLE].BAF` + * file with beta allele frequencies +* `[TUMORSAMPLE].LogR` and `[NORMALSAMPLE].LogR` + * file with total copy number on a logarithmic scale -### samtools mpileup +### ASCAT +[ASCAT](https://github.com/Crick-CancerGenomics/ascat) is a method to derive copy number profiles of tumor cells, accounting for normal cell admixture and tumor aneuploidy. +ASCAT infers tumor purity and ploidy and calculates whole-genome allele-specific copy number profiles. + +For further reading and documentation see [the Sarek documentation about ASCAT](https://github.com/nf-core/sarek/blob/master/docs/ascat.md) or the [ASCAT manual](https://www.crick.ac.uk/research/labs/peter-van-loo/software). + +For a Tumor/Normal pair only: +**Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/ASCAT`** + +* `[TUMORSAMPLE].aberrationreliability.png` + * Image with information about aberration reliability +* `[TUMORSAMPLE].ASCATprofile.png` + * Image with information about ASCAT profile +* `[TUMORSAMPLE].ASPCF.png` + * Image with information about ASPCF +* `[TUMORSAMPLE].rawprofile.png` + * Image with information about raw profile +* `[TUMORSAMPLE].sunrise.png` + * Image with information about sunrise +* `[TUMORSAMPLE].tumour.png` + * Image with information about tumor +* `[TUMORSAMPLE].cnvs.txt` + * file with information about CNVS +* `[TUMORSAMPLE].LogR.PCFed.txt` + * file with information about LogR +* `[TUMORSAMPLE].purityploidy.txt` + * file with information about purity ploidy + +### mpileup +[samtools mpileup](https://www.htslib.org/doc/samtools.html) generate pileup for a BAM file. + +For further reading and documentation see the [samtools manual](https://www.htslib.org/doc/samtools.html#COMMANDS_AND_OPTIONS). + +For all samples: +**Output directory: `results/VariantCalling/[SAMPLE]/mpileup`** +* `[SAMPLE].pileup.gz` + * The pileup format is a text-based format for summarizing the base calls of aligned reads to a reference sequence. Alignment records are grouped by sample (SM) identifiers in @RG header lines. ### Control-FREEC +[Control-FREEC](https://github.com/BoevaLab/FREEC) is a tool for detection of copy-number changes and allelic imbalances (including LOH) using deep-sequencing data. +Control-FREEC automatically computes, normalizes, segments copy number and beta allele frequency profiles, then calls copy number alterations and LOH. +And also detects subclonal gains and losses and evaluate the likeliest average ploidy of the sample. + +For further reading and documentation see the [Control-FREEC manual](http://boevalab.com/FREEC/tutorial.html). + +For a Tumor/Normal pair only: +**Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/ControlFREEC`** +* `[TUMORSAMPLE]_vs_[NORMALSAMPLE].config.txt` + * Configuration file used to run Control-FREEC +* `[TUMORSAMPLE].pileup.gz_CNVs` and `[TUMORSAMPLE].pileup.gz_normal_CNVs` + * file with coordinates of predicted copy number alterations +* `[TUMORSAMPLE].pileup.gz_ratio.txt` and `[TUMORSAMPLE].pileup.gz_normal_ratio.txt` + * file with ratios and predicted copy number alterations for each window +* `[TUMORSAMPLE].pileup.gz_BAF.txt` and `[NORMALSAMPLE].pileup.gz_BAF.txt` + * file with beta allele frequencies for each possibly heterozygous SNP position ## Annotation +This directory contains results from the final annotation steps: two software are used for annotation, [snpEff](http://snpeff.sourceforge.net/) and [VEP](https://www.ensembl.org/info/docs/tools/vep/index.html). +Only a subset of the VCF files are annotated, and only variants that have a PASS filter. +FreeBayes results are not annotated in the moment yet as we are lacking a decent somatic filter. +For HaplotypeCaller the germline variations are annotated for both the tumor and the normal sample. + ### snpEff -[snpeff](http://snpeff.sourceforge.net/) +[snpeff](http://snpeff.sourceforge.net/) is a genetic variant annotation and effect prediction toolbox. +It annotates and predicts the effects of variants on genes (such as amino acid changes) using multiple databases for annotations. +The generated VCF header contains the software version and the used command line. -### VEP -[VEP (Variant Effect Predictor)](https://www.ensembl.org/info/docs/tools/vep/index.html) +For further reading and documentation see the [snpEff manual](http://snpeff.sourceforge.net/SnpEff_manual.html#outputSummary) -## QC and reports +For all samples: +**Output directory: `results/Annotation/[SAMPLE]/snpEff`** + +* `VariantCaller_Sample_snpEff.ann.vcf.gz` and `VariantCaller_Sample_snpEff.ann.vcf.gz.tbi` + * VCF with Tabix index + +### VEP +[VEP (Variant Effect Predictor)](https://www.ensembl.org/info/docs/tools/vep/index.html), based on Ensembl, is a tools to determine the effects of all sorts of variants, including SNPs, indels, structural variants, CNVs. +The generated VCF header contains the software version, also the version numbers for additional databases like Clinvar or dbSNP used in the "VEP" line. +The format of the [consequence annotations](https://www.ensembl.org/info/genome/variation/prediction/predicted_data.html) is also in the VCF header describing the INFO field. +In the moment it contains: +* Consequence: impact of the variation, if there is any +* Codons: the codon change, i.e. cGt/cAt +* Amino_acids: change in amino acids, i.e. R/H if there is any +* Gene: ENSEMBL gene name +* SYMBOL: gene symbol +* Feature: actual transcript name +* EXON: affected exon +* PolyPhen: prediction based on [PolyPhen](http://genetics.bwh.harvard.edu/pph2/) +* SIFT: prediction by [SIFT](http://sift.bii.a-star.edu.sg/) +* Protein_position: Relative position of amino acid in protein +* BIOTYPE: Biotype of transcript or regulatory feature + +For further reading and documentation see the [VEP manual](https://www.ensembl.org/info/docs/tools/vep/index.html) + +For all samples: +**Output directory: `results/Annotation/[SAMPLE]/VEP`** + +* `VariantCaller_Sample_VEP.ann.vcf.gz` and `VariantCaller_Sample_VEP.ann.vcf.gz.tbi` + * VCF with Tabix index + +## QC and reporting ### FastQC [FastQC](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/) gives general quality metrics about your reads. @@ -113,6 +328,7 @@ You get information about adapter contamination and other overrepresented sequen For further reading and documentation see the [FastQC help](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/). +For all samples: **Output directory: `results/Reports/[SAMPLE]/fastqc`** * `sample_R1_XXX_fastqc.html` and `sample_R2_XXX_fastqc.html` @@ -126,49 +342,50 @@ For further reading and documentation see the [FastQC help](http://www.bioinform Plot will show: * Stats by non-reference allele frequency, depth distribution, stats by quality and per-sample counts, singleton stats, etc. +For all samples: **Output directory: `results/Reports/[SAMPLE]/bamQC`** -* `VariantCaller_Sample.bcf.tools.stats.out` +* `VariantCaller_[SAMPLE].bcf.tools.stats.out` * RAW statistics used by MultiQC For more information about how to use Qualimap bamqc reports, see [Qualimap bamqc manual](http://qualimap.bioinfo.cipf.es/doc_html/analysis.html#id7) -### MarkDuplicates -reports +### MarkDuplicates reports [GATK MarkDuplicates](https://github.com/broadinstitute/gatk) locates and tags duplicate reads in a BAM or SAM file, where duplicate reads are defined as originating from a single fragment of DNA. Duplicates can arise during sample preparation e.g. library construction using PCR. Duplicate reads can also result from a single amplification cluster, incorrectly detected as multiple clusters by the optical sensor of the sequencing instrument. These duplication artifacts are referred to as optical duplicates. -Plot will show: -* Duplication metrics - +For all samples: **Output directory: `results/Reports/[SAMPLE]/MarkDuplicates`** -* `Sample.bam.metrics` +* `[SAMPLE].bam.metrics` * RAW statistics used by MultiQC -For more information about how to use MarkDuplicates reports, see [MarkDuplicates manual](https://software.broadinstitute.org/gatk/documentation/tooldocs/4.1.2.0/picard_sam_markduplicates_MarkDuplicates.php) +For further reading and documentation see the [MarkDuplicates manual](https://software.broadinstitute.org/gatk/documentation/tooldocs/4.1.2.0/picard_sam_markduplicates_MarkDuplicates.php). ### samtools stats [samtools stats](https://www.htslib.org/doc/samtools.html) collects statistics from BAM files and outputs in a text format. Plots will show: * Alignment metrics. +For all samples: **Output directory: `results/Reports/[SAMPLE]/SamToolsStats`** -* `Sample.bam.samtools.stats.out` +* `[SAMPLE].bam.samtools.stats.out` * RAW statistics used by MultiQC -For more information about how to use samtools stats reports, see [samtools stats manual](http://www.htslib.org/doc/samtools.html#COMMANDS_AND_OPTIONS) +For further reading and documentation see the [samtools manual](https://www.htslib.org/doc/samtools.html#COMMANDS_AND_OPTIONS) ### bcftools stats -[bcftools stats](https://samtools.github.io/bcftools/) is a program for variant calling and manipulating files in the Variant Call Format. +[bcftools](https://samtools.github.io/bcftools/) is a program for variant calling and manipulating files in the Variant Call Format. Plot will show: * Stats by non-reference allele frequency, depth distribution, stats by quality and per-sample counts, singleton stats, etc. +For all samples: **Output directory: `results/Reports/[SAMPLE]/BCFToolsStats`** -* `VariantCaller_Sample.bcf.tools.stats.out` +* `VariantCaller_[SAMPLE].bcf.tools.stats.out` * RAW statistics used by MultiQC -For more information about how to use bcftools stats reports, see [bcftools stats manual](https://samtools.github.io/bcftools/bcftools.html#stats) +For further reading and documentation see the [bcftools stats manual](https://samtools.github.io/bcftools/bcftools.html#stats) ### VCFtools [VCFtools](https://vcftools.github.io/) is a program package designed for working with VCF files. @@ -177,25 +394,28 @@ Plots will show: * the transition to transversion ratio as a function of alternative allele count (using only bi-allelic SNPs). * the transition to transversion ratio as a function of SNP quality threshold (using only bi-allelic SNPs). +For all samples: **Output directory: `results/Reports/[SAMPLE]/VCFTools`** -* `VariantCaller_Sample.FILTER.summary` +* `VariantCaller_[SAMPLE].FILTER.summary` * RAW statistics used by MultiQC -* `VariantCaller_Sample.TsTv.count` +* `VariantCaller_[SAMPLE].TsTv.count` * RAW statistics used by MultiQC -* `VariantCaller_Sample.TsTv.qual` +* `VariantCaller_[SAMPLE].TsTv.qual` * RAW statistics used by MultiQC -For more information about how to use VCFtools reports, see [VCFtools manual](https://vcftools.github.io/man_latest.html#OUTPUT%20OPTIONS) +For further reading and documentation see the [VCFtools manual](https://vcftools.github.io/man_latest.html#OUTPUT%20OPTIONS) ### snpEff reports [snpeff](http://snpeff.sourceforge.net/) is a genetic variant annotation and effect prediction toolbox. -It annotates and predicts the effects of variants on genes (such as amino acid changes). +It annotates and predicts the effects of variants on genes (such as amino acid changes) using multiple databases for annotations. + Plots will shows : * locations of detected variants in the genome and the number of variants for each location. * the putative impact of detected variants and the number of variants for each impact. * the effect of variants at protein level and the number of variants for each effect type. * the quantity as function of the variant quality score. +For all samples: **Output directory: `results/Reports/[SAMPLE]/snpEff`** * `VariantCaller_Sample_snpEff.csv` * RAW statistics used by MultiQC @@ -204,7 +424,17 @@ Plots will shows : * `VariantCaller_Sample_snpEff.txt` * TXT (tab separated) summary counts for variants affecting each transcript and gene -For more information about how to use snpEff reports, see [snpEff manual](http://snpeff.sourceforge.net/SnpEff_manual.html#outputSummary) +For further reading and documentation see the [snpEff manual](http://snpeff.sourceforge.net/SnpEff_manual.html#outputSummary) + +### VEP reports +[VEP (Variant Effect Predictor)](https://www.ensembl.org/info/docs/tools/vep/index.html), based on Ensembl, is a tools to determine the effects of all sorts of variants, including SNPs, indels, structural variants, CNVs. + +For all samples: +**Output directory: `results/Reports/[SAMPLE]/VEP`** +* `VariantCaller_Sample_VEP.summary.html` + * Summary of the VEP run to be visualised with a web browser + +For further reading and documentation see the [VEP manual](https://www.ensembl.org/info/docs/tools/vep/index.html) ### MultiQC [MultiQC](http://multiqc.info) is a visualisation tool that generates a single HTML report summarising all samples in your project. @@ -212,6 +442,7 @@ Most of the pipeline QC results are visualised in the report and further statist The pipeline has special steps which allow the software versions used to be reported in the MultiQC output for future traceability. +For the whole Sarek run: **Output directory: `results/Reports/MultiQC`** * `multiqc_report.html` @@ -219,4 +450,4 @@ The pipeline has special steps which allow the software versions used to be repo * `multiqc_data/` * Directory containing parsed statistics from the different tools used in the pipeline -For more information about how to use MultiQC reports, see [http://multiqc.info](http://multiqc.info) +For further reading and documentation see the [MultiQC website](http://multiqc.info) diff --git a/docs/posters/ESHG_2017_Mgarcia.pdf b/docs/posters/ESHG_2017_Mgarcia.pdf new file mode 100644 index 0000000000000000000000000000000000000000..618fc37a36e4cb8c14c3eeec823b39842b7eb0f1 GIT binary patch literal 317239 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

D9Mluj@ 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 z zlfudGt^KOCGMG2Oa--p8&|QPQv(Bf~U8B4z*zTMr0lN;^^8k9DiDD0heSzEO3as`3 zumtXb?Lh~=ndIGAY0UJbd_By&@*)v+EZdWC+g)Vl-arF5-;2h|FD;VL4mz< zCsAVq^=3WSS)z8uNCl%m>ivbCpQ1AiEIh0Y23GWk1!Nx!V*m!$T2BoO%l$UF+^mpL ze}6y81mgiFQ5NC!4Ok*@jYKffhEQaNc*KXV7vk0qrm`?YU#_0WzFwo4$!}pshO+=3 znA(BQZouOzf=x1{eP|Xz4${s{Tjx%s&l)nWdwV{SWG~)N?fY zZS;?iv;V_4RIT`F>wsS{L)UIl`0YZVM*ND9gwmTq{a>b*@Bm@+gi#2f?kDTh(d9C0 zfFBX}uL;QHTu#%O*{ma5`}*!1JfZPx5A zTeM|n1n)VMP7x|AJgY_n;Gh7j8VwlaKEa#IrOApukh|a}57-A~R=s(|?a724a7=

MiSq)VW(qPZJ7NRkesY4!}$|%?DQ3 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 literal 0 HcmV?d00001 diff --git a/docs/posters/ESHG_2019.svg b/docs/posters/ESHG_2019.svg new file mode 100644 index 0000000000..3aaf7052f5 --- /dev/null +++ b/docs/posters/ESHG_2019.svg @@ -0,0 +1,5580 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + Analysis of genome sequencing data with a minimal investment IT-infrastructure Johannes Alneberg1,*, Maxime Ulysse Garcia2, Alexander Peltzer3, Tobias Koch3, Martin Proks4, Andreas Wilm5, Philip A Ewels6,* 1. School of Engineering Sciences in Chemistry, Biotechnology and Health, Royal Institute of Technology KTH, Sweden2. Department of Oncology, Karolinska Institute, Stockholm, Sweden3. Quantitative Biology Center (QBiC), University of Tübingen, Tübingen, Germany4. University of Southern Denmark, Odense, Denmark5. A*STAR Genome Institute of Singapore, Bioinformatics Core Unit, Singapore, Singapore6. Department of Biochemistry and Biophysics, Stockholm University, Stockholm, Sweden* National Genomics Infrastructure Stockholm, Science for Life Laboratory + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This work was supported by the AWS Cloud Credits for Research program in the form of a computational credit grant received by Philip A Ewels. + + + + + + + + + + + + + + 30X Human Genome:Storage: $2.43Compute: $46.42 + NextFlow has native support for major cloud providers, including AWS Batch. Sarek is a whole genome sequencing analysis pipeline implemented in NextFlow. + + + + + + + fastq + + + + bam + + + + + vcf + + + + + vcf + + + + + vcf + + + + + Based on GATK Best Practices Preprocessing + + + + + HaplotypeCaller, Strelka2, Manta Variant Calling + + snpEff, VEP + + snpEff, VEP Annotation + + + + Reports + + + + + + + + + + + + + + + + + + + + + + Analysis steps + + $ aws batch create-compute-environment --region eu-west-1 \--compute-environment-name $COMPUTE_ENV \--compute-resources type=SPOT,instanceTypes="m5d",bidPercentage=50$ aws batch create-job-queue --region eu-west-1 --job-queue-name $AWS_QUEUE \--compute-environment-order "order=1,computeEnvironment=$COMPUTE_ENV"$ nextflow run Sarek/main.nf -profile awsbatch --awsqueue $AWS_QUEUE + Commands outline + While large high-performance computing might be already available to larger research groups, especially smaller research groups would greatly benefit from a publicly accessible commercial alternative.Cloud computing offers a complete computational infrastructure without upfront infrastructure investment. Using Sarek on the AWS cloud infrastructure; mapping, germline variant calling and annotation for a human WGS sample (30X coverage) was performed for less than US-$ 50. Summary + + Beware that storing sensitive data with US companies might be violating GDPR due to the "cloud act". If this is the case, other local cloud providers might be more appropriate. Caveat + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A container (Amazon machine image) was constructed to automatically mount the physical ssd drives. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To scale storage space with instance size, m5d instances with physical ssd storage were used. + + + + + + + AWS Batch executes batch jobs much like a HPC scheduler. + The analysis finishes in roughly 30 hours. + + + + + diff --git a/docs/reference.md b/docs/reference.md index eb77557ddc..0dc33be6a5 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -9,7 +9,7 @@ Settings in `igenomes.config` can be tailored to your needs. ### Intervals -To speed up the variant calling processes, the reference is chopped into smaller pieces. +To speed up some preprocessing and variant calling processes, the reference is chopped into smaller pieces. The intervals are chromosomes cut at their centromeres (so each chromosome arm processed separately) also additional unassigned contigs. We are ignoring the hs37d5 contig that contains concatenated decoy sequences. Parts of preprocessing and variant calling are done by this intervals, and the different resulting files are then merged. diff --git a/main.nf b/main.nf index 7bff7070ea..724f49b0bb 100644 --- a/main.nf +++ b/main.nf @@ -222,7 +222,8 @@ if (params.email) { summary['MultiQC maxsize'] = params.maxMultiqcEmailFileSize } log.info summary.collect { k,v -> "${k.padRight(18)}: $v" }.join("\n") -log.info "\033[2m----------------------------------------------------\033[0m" +if (params.monochrome_logs) log.info "----------------------------------------------------" +else log.info "\033[2m----------------------------------------------------\033[0m" // Check the hostnames against configured profiles checkHostname() @@ -405,6 +406,8 @@ fastQCReport = fastQCReport.dump(tag:'FastQC') // STEP 1: MAPPING READS TO REFERENCE GENOME WITH BWA MEM process MapReads { + label 'max_cpus' + tag {idPatient + "-" + idRun} input: @@ -454,6 +457,8 @@ bamMapped = bamMapped.dump(tag:'Mapped BAM') // QC process BamQCmapped { + label 'max_memory' + tag {idPatient + "-" + idSample} publishDir "${params.outdir}/Reports/${idSample}/bamQC", mode: params.publishDirMode @@ -501,6 +506,8 @@ singleBam = singleBam.dump(tag:'Single BAM') // STEP 1.5: MERGING BAM FROM MULTIPLE LANES process MergeBamMapped { + label 'singleCPUmem_x_task' + tag {idPatient + "-" + idSample} input: @@ -524,6 +531,8 @@ mergedBam = mergedBam.dump(tag:'BAMs for MD') // STEP 2: MARKING DUPLICATES process MarkDuplicates { + label 'singleCPUmem_x_task' + tag {idPatient + "-" + idSample} publishDir params.outdir, mode: params.publishDirMode, @@ -565,6 +574,8 @@ bamBaseRecalibrator = bamMD.combine(intBaseRecalibrator) // STEP 3: CREATING RECALIBRATION TABLES process BaseRecalibrator { + label 'max_memory' + tag {idPatient + "-" + idSample + "-" + intervalBed} input: @@ -606,6 +617,8 @@ tableGatherBQSRReports = tableGatherBQSRReports.groupTuple(by:[0,1]) // STEP 3.5: MERGING RECALIBRATION TABLES process GatherBQSRReports { + label 'singleCPUmem_2x_task' + tag {idPatient + "-" + idSample} publishDir "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked", mode: params.publishDirMode, overwrite: false @@ -657,6 +670,8 @@ bamApplyBQSR = bamApplyBQSR.combine(intApplyBQSR) // STEP 4: RECALIBRATING process ApplyBQSR { + label 'singleCPUmem_2x_task' + tag {idPatient + "-" + idSample + "-" + intervalBed.baseName} input: @@ -687,6 +702,8 @@ bamMergeBamRecal = bamMergeBamRecal.groupTuple(by:[0,1]) // STEP 4.5: MERGING THE RECALIBRATED BAM FILES process MergeBamRecal { + label 'singleCPUmem_x_task' + tag {idPatient + "-" + idSample} publishDir "${params.outdir}/Preprocessing/${idSample}/Recalibrated", mode: params.publishDirMode @@ -747,6 +764,8 @@ process SamtoolsStats { samtoolsStatsReport = samtoolsStatsReport.dump(tag:'SAMTools') process BamQCrecalibrated { + label 'max_memory' + tag {idPatient + "-" + idSample} publishDir "${params.outdir}/Reports/${idSample}/bamQC", mode: params.publishDirMode @@ -801,6 +820,8 @@ bamHaplotypeCaller = bamRecalAllTemp.combine(intHaplotypeCaller) // STEP GATK HAPLOTYPECALLER.1 process HaplotypeCaller { + label 'singleCPUmem_x2_task' + tag {idSample + "-" + intervalBed.baseName} input: @@ -878,6 +899,9 @@ vcfGenotypeGVCFs = vcfGenotypeGVCFs.groupTuple(by:[0,1,2]) // STEP STRELKA.1 - SINGLE MODE process StrelkaSingle { + label 'max_cpus' + label 'max_memory' + tag {idSample} publishDir "${params.outdir}/VariantCalling/${idSample}/Strelka", mode: params.publishDirMode @@ -924,6 +948,9 @@ vcfStrelkaSingle = vcfStrelkaSingle.dump(tag:'Strelka - Single Mode') // STEP MANTA.1 - SINGLE MODE process MantaSingle { + label 'max_cpus' + label 'max_memory' + tag {idSample} publishDir "${params.outdir}/VariantCalling/${idSample}/Manta", mode: params.publishDirMode @@ -1014,6 +1041,8 @@ bamMpileup = bamMpileup.spread(intMpileup) // STEP GATK MUTECT2 process Mutect2 { + label 'singleCPUmem_x_task' + tag {idSampleTumor + "_vs_" + idSampleNormal + "-" + intervalBed.baseName} input: @@ -1048,6 +1077,8 @@ vcfMuTect2 = vcfMuTect2.groupTuple(by:[0,1,2]) // STEP FREEBAYES process FreeBayes { + label 'singleCPUmem_x_task' + tag {idSampleTumor + "_vs_" + idSampleNormal + "-" + intervalBed.baseName} input: @@ -1119,6 +1150,9 @@ vcfConcatenated = vcfConcatenated.dump(tag:'VCF') // STEP STRELKA.2 - SOMATIC PAIR process Strelka { + label 'max_cpus' + label 'max_memory' + tag {idSampleTumor + "_vs_" + idSampleNormal} publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/Strelka", mode: params.publishDirMode @@ -1167,6 +1201,9 @@ vcfStrelka = vcfStrelka.dump(tag:'Strelka') // STEP MANTA.2 - SOMATIC PAIR process Manta { + label 'max_cpus' + label 'max_memory' + tag {idSampleTumor + "_vs_" + idSampleNormal} publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/Manta", mode: params.publishDirMode @@ -1232,6 +1269,9 @@ pairBamStrelkaBP = pairBamStrelkaBP.map { // STEP STRELKA.3 - SOMATIC PAIR - BEST PRACTICES process StrelkaBP { + label 'max_cpus' + label 'max_memory' + tag {idSampleTumor + "_vs_" + idSampleNormal} publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/Strelka", mode: params.publishDirMode @@ -1283,6 +1323,8 @@ vcfStrelkaBP = vcfStrelkaBP.dump(tag:'Strelka BP') // Run commands and code from Malin Larsson // Based on Jesper Eisfeldt's code process AlleleCounter { + label 'singleCPUmem_2x_task' + tag {idSample} input: @@ -1328,6 +1370,8 @@ alleleCounterOut = alleleCounterOut.map { // R script from Malin Larssons bitbucket repo: // https://bitbucket.org/malinlarsson/somatic_wgs_pipeline process ConvertAlleleCounts { + label 'singleCPUmem_2x_task' + tag {idSampleTumor + "_vs_" + idSampleNormal} publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/ASCAT", mode: params.publishDirMode @@ -1352,6 +1396,8 @@ process ConvertAlleleCounts { // R scripts from Malin Larssons bitbucket repo: // https://bitbucket.org/malinlarsson/somatic_wgs_pipeline process Ascat { + label 'singleCPUmem_2x_task' + tag {idSampleTumor + "_vs_" + idSampleNormal} publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/ASCAT", mode: params.publishDirMode @@ -1378,6 +1424,8 @@ ascatOut.dump(tag:'ASCAT') // STEP CONTROLFREEC.1 - MPILEUP process Mpileup { + label 'singleCPUmem_2x_task' + tag {idSample + "-" + intervalBed.baseName} input: @@ -1406,6 +1454,8 @@ mpileupMerge = mpileupMerge.groupTuple(by:[0,1]) // STEP CONTROLFREEC.2 - MERGE MPILEUP process MergeMpileup { + label 'singleCPUmem_x_task' + tag {idSample} publishDir params.outdir, mode: params.publishDirMode, saveAs: { it == "${idSample}.pileup.gz" ? "VariantCalling/${idSample}/mpileup/${it}" : '' } @@ -1449,6 +1499,8 @@ mpileupOut = mpileupOut.map { // STEP CONTROLFREEC.3 - CONTROLFREEC process ControlFREEC { + label 'singleCPUmem_2x_task' + tag {idSampleTumor + "_vs_" + idSampleNormal} publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/controlFREEC", mode: params.publishDirMode @@ -1513,6 +1565,7 @@ controlFreecOut.dump(tag:'ControlFREEC') // STEP CONTROLFREEC.3 - VISUALIZATION process ControlFreecViz { + label 'singleCPUmem_2x_task' tag {idSampleTumor + "_vs_" + idSampleNormal} @@ -1693,41 +1746,43 @@ vcfVep = vcfVep.map { // STEP SNPEFF process Snpeff { - tag {"${idSample} - ${variantCaller} - ${vcf}"} + label 'singleCPUmem_x_task' - publishDir params.outdir, mode: params.publishDirMode, saveAs: { - if (it == "${reducedVCF}_snpEff.ann.vcf") null - else "Reports/${idSample}/snpEff/${it}" - } + tag {"${idSample} - ${variantCaller} - ${vcf}"} - input: - set variantCaller, idSample, file(vcf) from vcfSnpeff - file dataDir from Channel.value(params.snpEff_cache ? file(params.snpEff_cache) : "null") - val snpeffDb from Channel.value(params.genomes[params.genome].snpeffDb) + publishDir params.outdir, mode: params.publishDirMode, saveAs: { + if (it == "${reducedVCF}_snpEff.ann.vcf") null + else "Reports/${idSample}/snpEff/${it}" + } - output: - set file("${reducedVCF}_snpEff.txt"), file("${reducedVCF}_snpEff.html"), file("${reducedVCF}_snpEff.csv") into snpeffReport - set val("snpEff"), variantCaller, idSample, file("${reducedVCF}_snpEff.ann.vcf") into snpeffVCF + input: + set variantCaller, idSample, file(vcf) from vcfSnpeff + file dataDir from Channel.value(params.snpEff_cache ? file(params.snpEff_cache) : "null") + val snpeffDb from Channel.value(params.genomes[params.genome].snpeffDb) - when: 'snpeff' in tools || 'merge' in tools + output: + set file("${reducedVCF}_snpEff.txt"), file("${reducedVCF}_snpEff.html"), file("${reducedVCF}_snpEff.csv") into snpeffReport + set val("snpEff"), variantCaller, idSample, file("${reducedVCF}_snpEff.ann.vcf") into snpeffVCF - script: - reducedVCF = reduceVCF(vcf) - cache = (params.snpEff_cache && params.annotation_cache) ? "-dataDir \${PWD}/${dataDir}" : "" - """ - snpEff -Xmx${task.memory.toGiga()}g \ - ${snpeffDb} \ - -csvStats ${reducedVCF}_snpEff.csv \ - -nodownload \ - ${cache} \ - -canon \ - -v \ - ${vcf} \ - > ${reducedVCF}_snpEff.ann.vcf - - mv snpEff_summary.html ${reducedVCF}_snpEff.html - mv ${reducedVCF}_snpEff.genes.txt ${reducedVCF}_snpEff.txt - """ + when: 'snpeff' in tools || 'merge' in tools + + script: + reducedVCF = reduceVCF(vcf) + cache = (params.snpEff_cache && params.annotation_cache) ? "-dataDir \${PWD}/${dataDir}" : "" + """ + snpEff -Xmx${task.memory.toGiga()}g \ + ${snpeffDb} \ + -csvStats ${reducedVCF}_snpEff.csv \ + -nodownload \ + ${cache} \ + -canon \ + -v \ + ${vcf} \ + > ${reducedVCF}_snpEff.ann.vcf + + mv snpEff_summary.html ${reducedVCF}_snpEff.html + mv ${reducedVCF}_snpEff.genes.txt ${reducedVCF}_snpEff.txt + """ } snpeffReport = snpeffReport.dump(tag:'snpEff report') @@ -1748,60 +1803,60 @@ if ('merge' in tools) { // STEP VEP process VEP { - tag {"${idSample} - ${variantCaller} - ${vcf}"} - - publishDir params.outdir, mode: params.publishDirMode, saveAs: { - if (it == "${reducedVCF}_VEP.summary.html") "Reports/${idSample}/VEP/${it}" - else null - } - - input: - set annotator, variantCaller, idSample, file(vcf), file(idx) from vcfVep - file dataDir from Channel.value(params.vep_cache ? file(params.vep_cache) : "null") - val cache_version from Channel.value(params.genomes[params.genome].vepCacheVersion) - set file(cadd_WG_SNVs), file(cadd_WG_SNVs_tbi), file(cadd_InDels), file(cadd_InDels_tbi) from Channel.value([ - params.cadd_WG_SNVs ? file(params.cadd_WG_SNVs) : "null", - params.cadd_WG_SNVs_tbi ? file(params.cadd_WG_SNVs_tbi) : "null", - params.cadd_InDels ? file(params.cadd_InDels) : "null", - params.cadd_InDels_tbi ? file(params.cadd_InDels_tbi) : "null" - ]) - - output: - set finalAnnotator, variantCaller, idSample, file("${reducedVCF}_VEP.ann.vcf") into vepVCF - file("${reducedVCF}_VEP.summary.html") into vepReport - - when: 'vep' in tools || 'merge' in tools - - script: - reducedVCF = reduceVCF(vcf) - finalAnnotator = annotator == "snpEff" ? 'merge' : 'VEP' - genome = params.genome == 'smallGRCh37' ? 'GRCh37' : params.genome - dir_cache = (params.vep_cache && params.annotation_cache) ? " \${PWD}/${dataDir}" : "/.vep" - cadd = (params.cadd_cache && params.cadd_WG_SNVs && params.cadd_InDels) ? "--plugin CADD,whole_genome_SNVs.tsv.gz,InDels.tsv.gz" : "" - genesplicer = params.genesplicer ? "--plugin GeneSplicer,/opt/conda/envs/sarek-2.5dev/bin/genesplicer,/opt/conda/envs/sarek-2.5dev/share/genesplicer-1.0-1/human,context=200,tmpdir=\$PWD/${reducedVCF}" : "--offline" - """ - mkdir ${reducedVCF} - - vep \ - -i ${vcf} \ - -o ${reducedVCF}_VEP.ann.vcf \ - --assembly ${genome} \ - ${cadd} \ - ${genesplicer} \ - --cache \ - --cache_version ${cache_version} \ - --dir_cache ${dir_cache} \ - --everything \ - --filter_common \ - --fork ${task.cpus} \ - --format vcf \ - --per_gene \ - --stats_file ${reducedVCF}_VEP.summary.html \ - --total_length \ - --vcf - - rm -rf ${reducedVCF} - """ + tag {"${idSample} - ${variantCaller} - ${vcf}"} + + publishDir params.outdir, mode: params.publishDirMode, saveAs: { + if (it == "${reducedVCF}_VEP.summary.html") "Reports/${idSample}/VEP/${it}" + else null + } + + input: + set annotator, variantCaller, idSample, file(vcf), file(idx) from vcfVep + file dataDir from Channel.value(params.vep_cache ? file(params.vep_cache) : "null") + val cache_version from Channel.value(params.genomes[params.genome].vepCacheVersion) + set file(cadd_WG_SNVs), file(cadd_WG_SNVs_tbi), file(cadd_InDels), file(cadd_InDels_tbi) from Channel.value([ + params.cadd_WG_SNVs ? file(params.cadd_WG_SNVs) : "null", + params.cadd_WG_SNVs_tbi ? file(params.cadd_WG_SNVs_tbi) : "null", + params.cadd_InDels ? file(params.cadd_InDels) : "null", + params.cadd_InDels_tbi ? file(params.cadd_InDels_tbi) : "null" + ]) + + output: + set finalAnnotator, variantCaller, idSample, file("${reducedVCF}_VEP.ann.vcf") into vepVCF + file("${reducedVCF}_VEP.summary.html") into vepReport + + when: 'vep' in tools || 'merge' in tools + + script: + reducedVCF = reduceVCF(vcf) + finalAnnotator = annotator == "snpEff" ? 'merge' : 'VEP' + genome = params.genome == 'smallGRCh37' ? 'GRCh37' : params.genome + dir_cache = (params.vep_cache && params.annotation_cache) ? " \${PWD}/${dataDir}" : "/.vep" + cadd = (params.cadd_cache && params.cadd_WG_SNVs && params.cadd_InDels) ? "--plugin CADD,whole_genome_SNVs.tsv.gz,InDels.tsv.gz" : "" + genesplicer = params.genesplicer ? "--plugin GeneSplicer,/opt/conda/envs/sarek-2.5dev/bin/genesplicer,/opt/conda/envs/sarek-2.5dev/share/genesplicer-1.0-1/human,context=200,tmpdir=\$PWD/${reducedVCF}" : "--offline" + """ + mkdir ${reducedVCF} + + vep \ + -i ${vcf} \ + -o ${reducedVCF}_VEP.ann.vcf \ + --assembly ${genome} \ + ${cadd} \ + ${genesplicer} \ + --cache \ + --cache_version ${cache_version} \ + --dir_cache ${dir_cache} \ + --everything \ + --filter_common \ + --fork ${task.cpus} \ + --format vcf \ + --per_gene \ + --stats_file ${reducedVCF}_VEP.summary.html \ + --total_length \ + --vcf + + rm -rf ${reducedVCF} + """ } vepReport = vepReport.dump(tag:'VEP') @@ -1811,23 +1866,23 @@ vcfCompressVCF = snpeffVCF.mix(vepVCF) // STEP COMPRESS AND INDEX VCF process CompressVCF { - tag {"${idSample} - ${annotator} - ${vcf}"} + tag {"${idSample} - ${annotator} - ${vcf}"} - publishDir "${params.outdir}/Annotation/${idSample}/${finalAnnotator}", mode: params.publishDirMode + publishDir "${params.outdir}/Annotation/${idSample}/${finalAnnotator}", mode: params.publishDirMode - input: - set annotator, variantCaller, idSample, file(vcf) from vcfCompressVCF + input: + set annotator, variantCaller, idSample, file(vcf) from vcfCompressVCF - output: - set annotator, variantCaller, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into (vcfCompressed, compressVCFOut) + output: + set annotator, variantCaller, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into (vcfCompressed, compressVCFOut) - script: - reducedVCF = reduceVCF(vcf) - finalAnnotator = annotator == "merge" ? "VEP" : annotator - """ - bgzip < ${vcf} > ${vcf}.gz - tabix ${vcf}.gz - """ + script: + reducedVCF = reduceVCF(vcf) + finalAnnotator = annotator == "merge" ? "VEP" : annotator + """ + bgzip < ${vcf} > ${vcf}.gz + tabix ${vcf}.gz + """ } compressVCFOut.dump(tag:'VCF') @@ -2021,12 +2076,12 @@ def nfcoreHeader() { ${c_blue} |\\ | |__ __ / ` / \\ |__) |__ ${c_yellow}} {${c_reset} ${c_blue} | \\| | \\__, \\__/ | \\ |___ ${c_green}\\`-._,-`-,${c_reset} ${c_green}`._,._,\'${c_reset} - ${c_black} ____ ${c_blue} _____ _ ${c_reset} - ${c_black} .' ${c_green}_${c_black} `. ${c_blue} / ____| | | ${c_reset} - ${c_black} / ${c_green}|\\${c_white}`-_${c_black} \\ ${c_blue} | (___ ___ _ __ __ | | __ ${c_reset} - ${c_black} | ${c_green}| \\ ${c_white}`-${c_black}| ${c_blue} \\___ \\/__ \\| ´__/ _\\| |/ / ${c_reset} - ${c_black} \\ ${c_green}| \\ ${c_black}/ ${c_blue} ____) | __ | | | __| < ${c_reset} - ${c_black} `${c_green}|${c_black}____${c_green}\\${c_black}' ${c_blue} |_____/\\____|_| \\__/|_|\\_\\ ${c_reset} + ${c_white} ____ ${c_blue} _____ _ ${c_reset} + ${c_white} .' _ `. ${c_blue} / ____| | | ${c_reset} + ${c_white} / ${c_green}|\\${c_white}`-_${c_white} \\ ${c_blue} | (___ ___ _ __ __ | | __ ${c_reset} + ${c_white} | ${c_green}| \\ ${c_white}`-${c_white}| ${c_blue} \\___ \\/__ \\| ´__/ _\\| |/ / ${c_reset} + ${c_white} \\ ${c_green}| \\ ${c_white}/ ${c_blue} ____) | __ | | | __| < ${c_reset} + ${c_white} `${c_green}|${c_white}____${c_green}\\${c_white}' ${c_blue} |_____/\\____|_| \\__/|_|\\_\\ ${c_reset} ${c_purple} nf-core/sarek v${workflow.manifest.version}${c_reset} ${c_dim}----------------------------------------------------${c_reset} diff --git a/nextflow.config b/nextflow.config index 833a55d974..d5689a380f 100644 --- a/nextflow.config +++ b/nextflow.config @@ -38,16 +38,6 @@ params { // Developmental code should specify :dev process.container = 'nfcore/sarek:dev' -process { - withName:Snpeff { - container = {(params.annotation_cache && params.snpEff_cache) ? 'nfcore/sarek:dev' : "nfcore/sareksnpeff:dev.${params.genome}"} - } - - withName:VEP { - container = {(params.annotation_cache && params.vep_cache) ? 'nfcore/sarek:dev' : "nfcore/sarekvep:dev.${params.genome}"} - } -} - // Load base.config by default for all pipelines includeConfig 'conf/base.config' @@ -60,7 +50,11 @@ try { profiles { awsbatch { includeConfig 'conf/awsbatch.config' } - conda { process.conda = "$baseDir/environment.yml" } + conda { + docker.enabled = false + process.conda = "$baseDir/environment.yml" + singularity.enabled = false + } debug { process.beforeScript = 'echo $HOSTNAME' } docker { docker { @@ -68,8 +62,12 @@ profiles { fixOwnership = true runOptions = "-u \$(id -u):\$(id -g)" } + singularity.enabled = false + } + singularity { + docker.enabled = false + singularity.enabled = true } - singularity { singularity.enabled = true } test { includeConfig 'conf/test.config' } } @@ -110,33 +108,17 @@ manifest { // Function to ensure that resource requirements don't go beyond // a maximum limit -def check_max(obj, type) { - if(type == 'memory'){ +def check_max(obj) { try { - if(obj.compareTo(params.max_memory as nextflow.util.MemoryUnit) == 1) + if (obj.getClass() == nextflow.util.MemoryUnit && obj.compareTo(params.max_memory as nextflow.util.MemoryUnit) == 1) return params.max_memory as nextflow.util.MemoryUnit - else - return obj - } catch (all) { - println " ### ERROR ### Max memory '${params.max_memory}' is not valid! Using default value: $obj" - return obj - } - } else if(type == 'time'){ - try { - if(obj.compareTo(params.max_time as nextflow.util.Duration) == 1) + else if (obj.getClass() == nextflow.util.Duration && obj.compareTo(params.max_time as nextflow.util.Duration) == 1) return params.max_time as nextflow.util.Duration + else if (obj.getClass() == java.lang.Integer) + return Math.min(obj, params.max_cpus as int) else return obj } catch (all) { - println " ### ERROR ### Max time '${params.max_time}' is not valid! Using default value: $obj" - return obj + println " ### ERROR ### Max params '${params.max_memory}', '${params.max_time}' or '${params.max_cpus}' is not valid! Using default value: $obj" } - } else if(type == 'cpus'){ - try { - return Math.min( obj, params.max_cpus as int ) - } catch (all) { - println " ### ERROR ### Max cpus '${params.max_cpus}' is not valid! Using default value: $obj" - return obj - } - } } diff --git a/scripts/build_reference.sh b/scripts/build_reference.sh index 741a27edb2..99c9f422f2 100755 --- a/scripts/build_reference.sh +++ b/scripts/build_reference.sh @@ -1,6 +1,13 @@ #!/bin/bash set -xeuo pipefail +# This script build small reference for sarek tests +# https://github.com/nf-core/test-datasets/raw/sarek + +usage() { echo "Usage: $0 <-p profile> <-t test> <-v>" 1>&2; exit 1; } + +NXF_SINGULARITY_CACHEDIR=${NXF_SINGULARITY_CACHEDIR:-work/singularity/.} +OFFLINE='' PROFILE=docker TEST=ALL TRAVIS_BUILD_DIR=${TRAVIS_BUILD_DIR:-.} @@ -16,6 +23,10 @@ do shift # past argument shift # past value ;; + --offline) + OFFLINE="--offline" + shift # past value + ;; -p|--profile) PROFILE=$2 shift # past argument @@ -26,6 +37,7 @@ do shift # past value ;; *) # unknown option + usage shift # past argument ;; esac @@ -35,6 +47,6 @@ done if [[ $TEST != ANNOTATESNPEFF ]] && [[ $TEST != ANNOTATEVEP ]] then rm -rf references - nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile test,${PROFILE} --build --outdir references ${VERBOSE} + nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile test,${PROFILE} --build --outdir references ${VERBOSE} ${OFFLINE} rm -rf .nextflow* references/pipeline_info work fi diff --git a/scripts/download_docker.sh b/scripts/download_docker.sh deleted file mode 100755 index f8fe108664..0000000000 --- a/scripts/download_docker.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -set -xeuo pipefail - -TEST=ALL - -while [[ $# -gt 0 ]] -do - key=$1 - case $key in - -t|--test) - TEST=$2 - shift # past argument - shift # past value - ;; - *) # unknown option - shift # past argument - ;; - esac -done - -if [[ ALL,ANNOTATEALL,ANNOTATESNPEFF =~ $TEST ]] -then - docker pull nfcore/sareksnpeff:dev.GRCh37 - docker tag nfcore/sareksnpeff:dev.GRCh37 nfcore/sareksnpeff:dev.smallGRCh37 -fi - -if [[ ALL,ANNOTATEALL,ANNOTATEVEP =~ $TEST ]] -then - docker pull nfcore/sarekvep:dev.GRCh37 - docker tag nfcore/sarekvep:dev.GRCh37 nfcore/sarekvep:dev.smallGRCh37 -fi - -if [[ ANNOTATEALL,ANNOTATEVEP,ANNOTATESNPEFF != $TEST ]] -then - docker pull nfcore/sarek:dev - docker tag nfcore/sarek:dev nfcore/sarek:dev -fi diff --git a/scripts/download_image.sh b/scripts/download_image.sh new file mode 100755 index 0000000000..dd581a8022 --- /dev/null +++ b/scripts/download_image.sh @@ -0,0 +1,73 @@ +#!/bin/bash +set -xeuo pipefail + +# This script download and tag image for sarek tests + +usage() { echo "Usage: $0 <-t test> <-n engine>" 1>&2; exit 1; } + +ENGINE=docker +NXF_SINGULARITY_CACHEDIR=${NXF_SINGULARITY_CACHEDIR:-work/singularity/.} +TEST=ALL + +while [[ $# -gt 0 ]] +do + key=$1 + case $key in + -n|--engine) + ENGINE=$2 + shift # past argument + shift # past value + ;; + -t|--test) + TEST=$2 + shift # past argument + shift # past value + ;; + *) # unknown option + usage + shift # past argument + ;; + esac +done + +if [[ ALL,ANNOTATEALL,ANNOTATESNPEFF =~ $TEST ]] +then + if [[ docker =~ $ENGINE ]] + then + docker pull nfcore/sareksnpeff:dev.GRCh37 + docker tag nfcore/sareksnpeff:dev.GRCh37 nfcore/sareksnpeff:dev.smallGRCh37 + elif [[ singularity =~ $ENGINE ]] + then + mkdir -p work/singularity + singularity build nfcore-sareksnpeff-dev.GRCh37.img docker://nfcore/sareksnpeff:dev.GRCh37 + mv nfcore-sareksnpeff-dev.GRCh37.img ${NXF_SINGULARITY_CACHEDIR}/. + fi +fi + +if [[ ALL,ANNOTATEALL,ANNOTATEVEP =~ $TEST ]] +then + if [[ docker =~ $ENGINE ]] + then + docker pull nfcore/sarekvep:dev.GRCh37 + docker tag nfcore/sarekvep:dev.GRCh37 nfcore/sarekvep:dev.smallGRCh37 + elif [[ singularity =~ $ENGINE ]] + then + mkdir -p work/singularity + singularity build nfcore-sarekvep-dev.GRCh37.img docker://nfcore/sarekvep:dev.GRCh37 + mv nfcore-sarekvep-dev.GRCh37.img ${NXF_SINGULARITY_CACHEDIR}/. + fi +fi + +if [[ ANNOTATEALL,ANNOTATEVEP,ANNOTATESNPEFF != $TEST ]] +then + if [[ docker =~ $ENGINE ]] + then + docker pull nfcore/sarek:dev + docker tag nfcore/sarek:dev nfcore/sarek:dev + elif [[ singularity =~ $ENGINE ]] + then + mkdir -p work/singularity + singularity build nfcore-sarek-dev.img docker://nfcore/sarek:dev + mv nfcore-sarek-dev.img ${NXF_SINGULARITY_CACHEDIR}/. + fi +fi diff --git a/scripts/filter_locifile.py b/scripts/filter_locifile.py new file mode 100644 index 0000000000..6f34f1437e --- /dev/null +++ b/scripts/filter_locifile.py @@ -0,0 +1,25 @@ +#! /usr/bin/env python + +import sys, re, math, random + +#VCF file whould be downloaded from ftp://ftp.1000genomes.ebi.ac.uk/vol1/ftp//release/20130502/ALL.wgs.phase3_shapeit2_mvncall_integrated_v5b.20130502.sites.vcf.gz + +vcffile = "ALL.wgs.phase3_shapeit2_mvncall_integrated_v5b.20130502.sites.vcf" + +outfile = "1000Genomes_20130502_SNP_maf0.3.vcf" +of=open(outfile, 'w') +for line in open(vcffile, 'r'): + line=line.strip() + if not line.startswith("#"): + pma=re.compile('MULTI_ALLELIC') + ma=pma.search(line) + if not (ma): + psnp=re.compile('VT=SNP') + snp=psnp.search(line) + if(snp): + info=line.split("\t")[7] + af_info=info.split(";")[1] + fq=float(af_info.split("=")[1]) + if fq > 0.3: + of.write("%s\t%s\n" %(line.split("\t")[0], line.split("\t")[1])) + diff --git a/scripts/make_snapshot.sh b/scripts/make_snapshot.sh new file mode 100755 index 0000000000..16ae81b5e3 --- /dev/null +++ b/scripts/make_snapshot.sh @@ -0,0 +1,53 @@ +#!/bin/bash +set -euo pipefail + +# This script makes an archive of sarek, with or without configs and test datasets +# https://github.com/nf-core/sarek + +usage() { echo "Usage: $0 <-t> <-c>" 1>&2; exit 1; } + +CONFIGS=false +NAME=sarek-$(git describe --tags --always) +TEST=false + +while [[ $# -gt 0 ]] +do + key="$1" + case $key in + -i|-t|--include-test-data) + TEST=true + shift # past argument + ;; + -c|--include-configs) + CONFIGS=true + shift # past argument + ;; + *) # unknown option + shift # past argument + usage + ;; + esac +done + +if [[ $CONFIGS == true ]] +then + echo "Archiving nf-core/configs" + git submodule add -f https://github.com/nf-core/configs.git configs +fi + +if [[ $TEST == true ]] +then + echo "Archiving nf-core/test-datasets:sarek" + git submodule add -f --branch sarek https://github.com/nf-core/test-datasets.git data +fi + +echo "Archiving nf-core/sarek" + +if [[ $CONFIGS == true ]] || [[ $TEST == true ]] +then + git-archive-all --prefix=${NAME} --force-submodules ${NAME}.tar.gz +else + git archive --format=tar.gz HEAD --prefix=${NAME}/ > ${NAME}.tar.gz +fi + +echo "Wrote ${NAME}.tar.gz" diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index 8b9c49c4f0..2e04744bfd 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -1,8 +1,15 @@ #!/bin/bash set -xeuo pipefail +# This script run sarek tests +# https://github.com/nf-core/test-datasets/raw/sarek + +usage() { echo "Usage: $0 <-p profile> <-t test> <-c cpus> <-n> <-v>" 1>&2; exit 1; } + CPUS=2 LOGS='' +NXF_SINGULARITY_CACHEDIR=${NXF_SINGULARITY_CACHEDIR:-work/singularity/.} +OFFLINE=false PROFILE=docker TEST=ALL TRAVIS_BUILD_DIR=${TRAVIS_BUILD_DIR:-.} @@ -21,6 +28,10 @@ do LOGS=true shift # past value ;; + --offline) + OFFLINE=true + shift # past value + ;; -p|--profile) PROFILE=$2 shift # past argument @@ -36,6 +47,7 @@ do shift # past value ;; *) # unknown option + usage shift # past argument ;; esac @@ -54,27 +66,50 @@ function run_sarek() { if [[ ALL,GERMLINE =~ $TEST ]] then - rm -rf data - git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data + if [[ $OFFLINE == false ]] + then + rm -rf data + git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data + fi run_sarek --tools=false --sample data/testdata/tiny/normal --noReports run_sarek --tools=false --sample results/Preprocessing/TSV/duplicateMarked.tsv --step recalibrate --noReports - run_sarek --tools HaplotypeCaller,Strelka --sample results/Preprocessing/TSV/recalibrated.tsv --step variantCalling --noReports - rm -rf data/ + run_sarek --tools HaplotypeCaller --sample results/Preprocessing/TSV/recalibrated.tsv --step variantCalling --noReports + if [[ $OFFLINE == false ]] + then + rm -rf data + fi manage_logs fi if [[ ALL,SOMATIC =~ $TEST ]] then - run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports + if [[ $OFFLINE == false ]] + then + run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports + else + run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports --sample data/testdata/tsv/tiny-manta.tsv + fi manage_logs fi if [[ ALL,TARGETED =~ $TEST ]] then - run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports --targetBED https://github.com/nf-core/test-datasets/raw/sarek/testdata/target.bed + if [[ $OFFLINE == false ]] + then + run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports --targetBED https://github.com/nf-core/test-datasets/raw/sarek/testdata/target.bed + else + run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports --sample data/testdata/tsv/tiny-manta.tsv --targetBED data/testdata/target.bed + fi manage_logs fi +if [[ $OFFLINE == false ]] +then + pathToSample="https://github.com/nf-core/test-datasets/raw/sarek/testdata" +else + pathToSample="data/testdata" +fi + if [[ ALL,ANNOTATEALL,ANNOTATESNPEFF,ANNOTATEVEP =~ $TEST ]] then if [[ $TEST = ANNOTATESNPEFF ]] @@ -87,12 +122,17 @@ then then ANNOTATOR=merge,snpEFF,VEP fi - run_sarek --step annotate --tools ${ANNOTATOR} --sample https://github.com/nf-core/test-datasets/raw/sarek/testdata/vcf/Strelka_1234N_variants.vcf.gz --noReports + run_sarek --step annotate --tools ${ANNOTATOR} --sample ${pathToSample}/vcf/Strelka_1234N_variants.vcf.gz --noReports manage_logs fi if [[ MULTIPLE =~ $TEST ]] then - run_sarek --sample https://github.com/nf-core/test-datasets/raw/sarek/testdata/tsv/tiny-multiple-https.tsv --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports + if [[ $OFFLINE == false ]] + then + run_sarek --sample https://github.com/nf-core/test-datasets/raw/sarek/testdata/tsv/tiny-multiple-https.tsv --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports + else + run_sarek --sample data/testdata/tsv/tiny-multiple.tsv --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports + fi manage_logs fi diff --git a/scripts/selectROI.py b/scripts/selectROI.py new file mode 100644 index 0000000000..af2620f88a --- /dev/null +++ b/scripts/selectROI.py @@ -0,0 +1,232 @@ +#!/usr/bin/env python +# +# The MIT License (MIT) +# +# Copyright (c) 2018 Szilveszter Juhos +# the reduce() code shamelessly copied from +# https://github.com/brentp/interlap +# Copyright (c) 2014 Brent S. Pedersen +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import os +import sys +import copy +import argparse +import subprocess + +def parse_args(): + parser = argparse.ArgumentParser(description='Selecting Region Of Interest from BAM files') + parser.add_argument('-v', help='List of VCF files to process like -v tumour.vcf,normal.vcf', dest="vcfs") + parser.add_argument('-a', help='The BAM files (indexed) to read from like -b tumour.bam,normal.bam', required=True, dest="bams") + parser.add_argument('-b', help='The BED file with gene coordinates', dest="beds") + parser.add_argument('-p', help='The prefix of the target BAM file to write to (postfix is the input filename)', dest="prefix", default="ROI.") + parser.add_argument('-t', help='Number of threads used by samtools [8]', dest="threads", default=8, type=int) + parser.add_argument('-w', help='Region width for VCF loci [200]', dest="width", default=200, type=int) + parser.add_argument('-r', help='Readlength for region padding [151]', dest="pad", default=151, type=int) + parser.add_argument('-c', help='Number of variants in a chunk [150]', dest="maxRegions", default=150, type=int) + + return parser.parse_args() + +def reduce(args): + """ + >>> reduce([(2, 4), (4, 9)]) + [(2, 4), (4, 9)] + + >>> reduce([(2, 6), (4, 10)]) + [(2, 10)] + """ + if len(args) < 2: return args + args.sort() + ret = [args[0]] + for next_i, (s, e) in enumerate(args, start=1): + if next_i == len(args): + ret[-1] = ret[-1][0], max(ret[-1][1], e) + break + + ns, ne = args[next_i] + if e > ns or ret[-1][1] > ns: + ret[-1] = ret[-1][0], max(e, ne, ret[-1][1]) + else: + ret.append((ns, ne)) + return ret + +class ROISelector: + """Class to selet region of interest (ROI) from a set of BAM files. ROI is defined by input VCFs and BEDs""" + + def __init__(self, threads, maxRegions, prefix, width, pad): + # this is the set where loci are stored + # for every chromosome there is a list in the dict + # VCF records are int-s in the list, + # BED entries are (start,end) tuples + self.callDict = dict() + # number of samtools threads + self.threads = threads + # number of variants in a chunk + self.maxRegions = maxRegions + # prefix of the ROI BAM file + self.prefix = prefix + # width of region for VCF records + self.pad = pad + # add readlength padding + self.width = width + pad + + def selectROI(self,vcfs,bams,beds): + if not vcfs and not beds: + print("At least a single VCF (-v) or BED (-b) file is expected") + sys.exit() + + # first we MUST process BED intervals, since we want to ignore all the + # variants that are already in any of the intervals + bedRecordCount = 0 + if beds: # if there are any BEDs + print("Processing BED files: ") + bedFiles = beds.split(",") + for bedLoci in bedFiles: + print("\t" + bedLoci) + self.addBEDRecords(bedLoci) + for chrom in self.callDict: + bedRecordCount = bedRecordCount + len(self.callDict[chrom]) + print("Collected " + str(bedRecordCount) + " entries from BEDs") + + if vcfs: # if there are any VCFs given + print("Processing VCF files: ") + vcfFiles = vcfs.split(",") + for vcfCalls in vcfFiles: + print("\t" + vcfCalls) + self.addVCFRecords(vcfCalls) + vcfRecordCount = 0 + # report the number of records added + for chrom in self.callDict: + vcfRecordCount = vcfRecordCount + len(self.callDict[chrom]) + print("Collected " + str(vcfRecordCount-bedRecordCount) + " entries from VCFs") + # now collapse overlapping intervals + for chrom in self.callDict: + self.callDict[chrom] = reduce( self.callDict[chrom] ) + # we still have to collapse intervals that are too close to each other + # if they are closer than the readlength, there can be cases when a read is picked + # in both interval, so we have to merge them + self.mergeCloseIntervals(chrom) + + # save intervals to a BAM + print("Saving reads from BAMs:") + self.saveCallsToBAM(bams) + + def mergeCloseIntervals(self,chrom): + # we are assuming the intervals are ordered (they should to be) + mergedChrom = [] + start = (0,0) + for interv in self.callDict[chrom]: + # (start[0], start[1]) + # (interv[0], interv[1]) + # |------------------| |--------------------| + if interv[0] - start[1] <= self.pad*2: + # merge the two intervals + start = (start[0],interv[1]) + elif start[1]!= 0: # if its not the very first one and have enough space between the intervals + # add to the new interval set + mergedChrom.append(start) + start = interv + else: # most of the intervals should fall here + start = interv + self.callDict[chrom] = mergedChrom + + def writeChunk(self,bam,chrom,regions): + # from the regions list make a list of lists - sublists have 50 entries max + sublists = [regions[i:i+self.maxRegions] for i in range(0, len(regions), self.maxRegions)] + regionCount = 0 + filesToMerge = "" + for rlist in sublists: + chunkBAM = chrom +"_"+ str(regionCount) + "_tmpROI.bam " + regionCount = regionCount + 1 + filesToMerge = filesToMerge + chunkBAM + loci = "" + for locus in rlist: + loci = loci + locus + " " + subprocess.call("samtools view -@" + str(self.threads) + " " + bam + " -bo " + chunkBAM + loci, shell=True) + print("Wrote chunk for " + chrom + " to " + chunkBAM) + return filesToMerge + + def saveCallsToBAM(self,bams): + bamFiles = bams.split(",") + for bam in bamFiles: + print("\t" + bam) + # getting reads one-by-one takes aages. We are going to try to use htslib/samtools + # by making a command line to get ROI for each chromosome, and + # merge/sort the BAMs later + filesToMerge = "" + for chrom in self.callDict: + regionCount = 0; + regions = [] + for gcoord in self.callDict[chrom]: + if type(gcoord) is tuple: # BED record in tuple + start = gcoord[0] + end = gcoord[1] + else: # VCF record + start = gcoord - self.width + end = gcoord + self.width + regions.append(chrom + ":" + str(start) + "-" + str(end)) + # let's write the file for the chromosome + filesToMerge = filesToMerge + self.writeChunk(bam,chrom,regions) + print("Merging ...") + subprocess.call("samtools merge -@"+str(self.threads)+" -f merged.roi.bam " + filesToMerge, shell=True) + target = os.path.dirname(bam) + if len(target) > 0: + target = target + "/" + target = target + self.prefix + os.path.basename(bam) + print("Sorting ...") + subprocess.call("samtools sort -@" + str(self.threads) + " -o " + target + " merged.roi.bam", shell=True) + print("Sorted file written to " + target) + print("Indexing ...") + subprocess.call("samtools index -@" + str(self.threads) + " " + target, shell=True) + + def addVCFRecords(self,VCFFile): + """ + Store VCF record CHROM,POS in a dict + """ + VCFlines = [line.rstrip() for line in open(VCFFile,'rt')] + for variant in VCFlines: + if not variant.startswith("#"): # ignore header + vcfCols = variant.split() + chrom = vcfCols[0] + locus = int(vcfCols[1]) + if chrom not in self.callDict: # if chromosome not in dictionary yet + self.callDict[chrom] = [] + self.callDict[chrom].append( (locus-self.width, locus+self.width) ) + + def addBEDRecords(self,BEDFile): + """ + Store BED record CHROM,START,END in a set + """ + BEDlines = [line.rstrip() for line in open(BEDFile,'rt')] + for locus in BEDlines: + BEDrecord = locus.split() + chrom = BEDrecord[0] + if chrom not in self.callDict: + self.callDict[chrom] = [] + self.callDict[chrom].append( (int(BEDrecord[1]),int(BEDrecord[2])) ) + +######################## end of class ROISelector ###################################### + + +if __name__ == "__main__": + args = parse_args() + rois = ROISelector(args.threads, args.maxRegions, args.prefix, args.width, args.pad) + rois.selectROI(args.vcfs,args.bams,args.beds) + diff --git a/scripts/speedseq.filter.awk b/scripts/speedseq.filter.awk deleted file mode 100644 index d5d9ab0020..0000000000 --- a/scripts/speedseq.filter.awk +++ /dev/null @@ -1,50 +0,0 @@ -# somatic filter for FreeBayes VCF files, based on SpeedSeq: https://github.com/hall-lab/speedseq -# recommended to filter the large VCF files like: -# vcfsamplediff -s VT normal tumour freebayesresult.vcf | \ -# awk '/^#/{print}!/^#/&&!/germline/' |\ -# vcffilter -f "QUAL > 20" | vcfflatten |\ -# awk -f speedseq.filter.awk -v NORMAL_IDX=10 -v TUMOUR_IDX=11 > filtered.vcf -# where "normal" and "tumour" are the sample names in the VCF respectively, and the IDX variables are their 1-based column numbers in the #CHROM line of the VCF -# also check the index for these sample names also -BEGIN{ - MINQUAL=1; - SSC_THRES=1; # somatic score threshold ssc = LOD_T + LOD_N, log of odds (LOD) is the genotype quality ratio (http://www.nature.com/nmeth/journal/v12/n10/pdf/nmeth.3505.pdf) - ONLY_SOMATIC=1; # prints out only somatic lines if not zero - GL_IDX=0; # GL in the original: PL is the Normalized, Phred-scaled likelihoods for genotypes -} -{ - OFS="\t"; - - if ($0~"^#" && $0!~"^#CHROM") { print ; next; } - # add extra header line - if ($0~"^#CHROM") { - print "##INFO=" - print ; - } - if (! GL_IDX) { - split($9,fmt,":") - for (i=1;i<=length(fmt);++i) { if (fmt[i]=="GL") GL_IDX=i } - } - split($NORMAL_IDX,N,":"); # split field 10 and put values into - split(N[GL_IDX],NGL,","); - split($TUMOR_IDX,T,":"); - split(T[GL_IDX],TGL,","); - LOD_NORM=NGL[1]-NGL[2]; - LOD_TUMOR_HET=TGL[2]-TGL[1]; - LOD_TUMOR_HOM=TGL[3]-TGL[1]; - - if (LOD_TUMOR_HET > LOD_TUMOR_HOM) { LOD_TUMOR=LOD_TUMOR_HET } - else { LOD_TUMOR=LOD_TUMOR_HOM } - - DQUAL=LOD_TUMOR+LOD_NORM; - - if (DQUAL>=SSC_THRES && $NORMAL_IDX~"^0/0") { - $7="PASS" - $8="DQUAL="DQUAL";"$8 - print - } - else if (!ONLY_SOMATIC && $6>=MINQUAL && $NORMAL_IDX~"^0/0" && ! match($TUMOUR_IDX,"^0/0")) { - $8="DQUAL="DQUAL";"$8 - print - } -} From 818d760655679b8afc0acf6e886597982171f799 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Fri, 14 Jun 2019 15:30:16 +0200 Subject: [PATCH 020/854] Fix merged annotation (#13) * Add BamQC, CompressVCFsnpEff and CompressVCFvep processes * Add Citation documentation * Fix merge in annotation * Merge BamQCmapped and BamQCrecalibrated processes into BamQC process * Removed BamQCmapped, BamQCrecalibrated and CompressVCF processes * Split CompressVCF process into CompressVCFsnpEff and CompressVCFvep processes --- CHANGELOG.md | 8 +++ README.md | 12 ++++ conf/base.config | 8 +-- conf/test.config | 9 +++ main.nf | 183 +++++++++++++++++++++++++++++------------------ 5 files changed, 144 insertions(+), 76 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3f5c33d86..25df131630 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,9 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#12](https://github.com/nf-core/sarek/pull/12) - Use `label` for processes configation - [#12](https://github.com/nf-core/sarek/pull/12) - Add helper scripts `filter_locifile.py` and `selectROI.py` - [#12](https://github.com/nf-core/sarek/pull/12) - Add helper script `make_snapshot.sh` to make an archive for usage on a secure cluster +- [#13](https://github.com/nf-core/sarek/pull/13) - Add Citation documentation +- [#13](https://github.com/nf-core/sarek/pull/13) - Add `BamQC` process +- [#13](https://github.com/nf-core/sarek/pull/13) - Add `CompressVCFsnpEff` and `CompressVCFvep` processes ### `Changed` - [#1](https://github.com/nf-core/sarek/pull/1), [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#6](https://github.com/nf-core/sarek/pull/6), [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Update docs @@ -47,14 +50,19 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#12](https://github.com/nf-core/sarek/pull/12) - Disable `Singularity` in `docker` profile - [#12](https://github.com/nf-core/sarek/pull/12) - Disable `Docker` and `Singularity` in `conda` profile - [#12](https://github.com/nf-core/sarek/pull/12) - Simplify `check_max()` function +- [#13](https://github.com/nf-core/sarek/pull/13) - Merge `BamQCmapped` and `BamQCrecalibrated` processes into `BamQC` process +- [#13](https://github.com/nf-core/sarek/pull/13) - Split `CompressVCF` process into `CompressVCFsnpEff` and `CompressVCFvep` processes ### `Removed` - [#9](https://github.com/nf-core/sarek/pull/9) - Removed `relatedness2` graph from `vcftools stats` +- [#13](https://github.com/nf-core/sarek/pull/13) - Removed `BamQCmapped` and `BamQCrecalibrated` processes +- [#13](https://github.com/nf-core/sarek/pull/13) - Removed `CompressVCF` ### `Fixed` - [#3](https://github.com/nf-core/sarek/pull/3) - Fix Docker ownership - [#11](https://github.com/nf-core/sarek/pull/11) - Fix MergeMpileup PublishDir +- [#13](https://github.com/nf-core/sarek/pull/13) - Fix merge in annotation ## [2.3.FIX1] - 2019-03-04 diff --git a/README.md b/README.md index d2b544541c..f2ef9393c4 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,18 @@ For further information or help, don't hesitate to get in touch on [Slack](https :-:|:-: [![National Genomics Infrastructure](docs/images/NGI_logo.png)](https://ngisweden.scilifelab.se/) | [![National Bioinformatics Infrastructure Sweden](docs/images/NBIS_logo.png)](https://nbis.se) + +## Citation + +If you use nf-core/sarek for your analysis, please cite the `Sarek` pre-print as follows: +Garcia MU, Juhos S, Larsson M, Olason PI, Martin M, Eisfeldt J, DiLorenzo S, Sandgren J, de Ståhl TD, Wirta V, Nistér M, Nystedt B, Käller M. **Sarek: A portable workflow for whole-genome sequencing analysis of germline and somatic variants**. *bioRxiv*. 2018. p. 316976. [doi: 10.1101/316976](https://www.biorxiv.org/content/10.1101/316976v1). + +You can cite the sarek zenodo record for a specific version using the following [doi: 10.5281/zenodo.2582812](https://doi.org/10.5281/zenodo.2582812) + +You can cite the `nf-core` pre-print as follows: +Ewels PA, Peltzer A, Fillinger S, Alneberg JA, Patel H, Wilm A, Garcia MU, Di Tommaso P, Nahnsen S. **nf-core: Community curated bioinformatics pipelines**. *bioRxiv*. 2019. p. 610741. [doi: 10.1101/610741](https://www.biorxiv.org/content/10.1101/610741v3). + + [bioconda-badge]: https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg?logo=data:image/png;base64,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 [btb-link]: https://ki.se/forskning/barntumorbanken-0 [circleci-badge]: https://img.shields.io/circleci/project/github/nf-core/sarek.svg?logo=circleci diff --git a/conf/base.config b/conf/base.config index cb98eb8e6e..7db37b80c8 100644 --- a/conf/base.config +++ b/conf/base.config @@ -45,11 +45,7 @@ process { withLabel:max_memory { memory = {check_max(params.max_memory)} } - - withName:BamQCmapped { - cpus = {check_max(16)} - } - withName:BamQCrecalibrated { + withName:BamQC { cpus = {check_max(16)} } withName:BaseRecalibrator { @@ -95,7 +91,7 @@ process { container = {(params.annotation_cache && params.snpEff_cache) ? 'nfcore/sarek:dev' : "nfcore/sareksnpeff:dev.${params.genome}"} errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} } - withName:VEP { + withLabel:VEP { container = {(params.annotation_cache && params.vep_cache) ? 'nfcore/sarek:dev' : "nfcore/sarekvep:dev.${params.genome}"} cpus = {check_max(4)} errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} diff --git a/conf/test.config b/conf/test.config index 95a9a6ce6d..ddffd07edb 100644 --- a/conf/test.config +++ b/conf/test.config @@ -23,3 +23,12 @@ params { // Use publishDir mode link so that work can be removed publishDirMode = 'link' } + +process { + withName:Snpeff { + maxForks = 1 + } + withName:VEP { + maxForks = 1 + } +} diff --git a/main.nf b/main.nf index 724f49b0bb..1eca25289c 100644 --- a/main.nf +++ b/main.nf @@ -415,7 +415,8 @@ process MapReads { set file(genomeFile), file(bwaIndex) from Channel.value([referenceMap.genomeFile, referenceMap.bwaIndex]) output: - set idPatient, idSample, idRun, file("${idRun}.bam") into (bamMapped, bamMappedQC) + set idPatient, idSample, idRun, file("${idRun}.bam") into bamMapped + set idPatient, idSample, file("${idRun}.bam") into bamMappedBamQC when: step == 'mapping' @@ -454,43 +455,6 @@ process MapReads { bamMapped = bamMapped.dump(tag:'Mapped BAM') -// QC - -process BamQCmapped { - label 'max_memory' - - tag {idPatient + "-" + idSample} - - publishDir "${params.outdir}/Reports/${idSample}/bamQC", mode: params.publishDirMode - - input: - set idPatient, idSample, idRun, file(bam) from bamMappedQC - file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") - - output: - file("${bam.baseName}") into bamQCmappedReport - - when: !params.noReports - - script: - use_bed = params.targetBED ? "-gff ${targetBED}" : '' - """ - qualimap --java-mem-size=${task.memory.toGiga()}G \ - bamqc \ - -bam ${bam} \ - --paint-chromosome-limits \ - --genome-gc-distr HUMAN \ - $use_bed \ - -nt ${task.cpus} \ - -skip-duplicated \ - --skip-dup-mode 0 \ - -outdir ${bam.baseName} \ - -outformat HTML - """ -} - -bamQCmappedReport = bamQCmappedReport.dump(tag:'BamQC BAM') - // Sort BAM whether they are standalone or should be merged singleBam = Channel.create() @@ -712,7 +676,8 @@ process MergeBamRecal { set idPatient, idSample, file(bam) from bamMergeBamRecal output: - set idPatient, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bai") into (bamRecal, bamRecalBamQC, bamRecalSamToolsStats) + set idPatient, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bai") into (bamRecal, bamRecalSamToolsStats) + set idPatient, idSample, file("${idSample}.recal.bam") into bamRecalBamQC set idPatient, idSample, val("${idSample}.recal.bam"), val("${idSample}.recal.bai") into (bamRecalTSV, bamRecalSampleTSV) script: @@ -763,7 +728,11 @@ process SamtoolsStats { samtoolsStatsReport = samtoolsStatsReport.dump(tag:'SAMTools') -process BamQCrecalibrated { +// QC + +bamBamQC = bamMappedBamQC.mix(bamRecalBamQC) + +process BamQC { label 'max_memory' tag {idPatient + "-" + idSample} @@ -771,20 +740,23 @@ process BamQCrecalibrated { publishDir "${params.outdir}/Reports/${idSample}/bamQC", mode: params.publishDirMode input: - set idPatient, idSample, file(bam), file(bai) from bamRecalBamQC + set idPatient, idSample, file(bam) from bamBamQC + file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") output: - file("${bam.baseName}") into bamQCrecalibratedReport + file("${bam.baseName}") into bamQCReport when: !params.noReports script: + use_bed = params.targetBED ? "-gff ${targetBED}" : '' """ qualimap --java-mem-size=${task.memory.toGiga()}G \ bamqc \ -bam ${bam} \ --paint-chromosome-limits \ --genome-gc-distr HUMAN \ + $use_bed \ -nt ${task.cpus} \ -skip-duplicated \ --skip-dup-mode 0 \ @@ -793,7 +765,7 @@ process BamQCrecalibrated { """ } -bamQCrecalibratedReport = bamQCrecalibratedReport.dump(tag:'BamQC') +bamQCReport = bamQCReport.dump(tag:'BamQC') /* ================================================================================ @@ -1740,7 +1712,7 @@ if (step == 'annotate') { vcfVep = vcfVep.map { variantCaller, idSample, vcf -> - ["VEP", variantCaller, idSample, vcf, null] + [variantCaller, idSample, vcf, null] } // STEP SNPEFF @@ -1762,7 +1734,7 @@ process Snpeff { output: set file("${reducedVCF}_snpEff.txt"), file("${reducedVCF}_snpEff.html"), file("${reducedVCF}_snpEff.csv") into snpeffReport - set val("snpEff"), variantCaller, idSample, file("${reducedVCF}_snpEff.ann.vcf") into snpeffVCF + set variantCaller, idSample, file("${reducedVCF}_snpEff.ann.vcf") into snpeffVCF when: 'snpeff' in tools || 'merge' in tools @@ -1787,22 +1759,34 @@ process Snpeff { snpeffReport = snpeffReport.dump(tag:'snpEff report') -if ('merge' in tools) { - // When running in the 'merge' mode - // snpEff output is used as VEP input - // Used a feedback loop from vcfCompressed - // https://github.com/nextflow-io/patterns/tree/master/feedback-loop +// STEP COMPRESS AND INDEX VCF.1 - snpEff + +process CompressVCFsnpEff { + tag {"${idSample} - ${vcf}"} - vcfCompressed = Channel.create() + publishDir "${params.outdir}/Annotation/${idSample}/snpEff", mode: params.publishDirMode - vcfVep = Channel.empty().mix( - vcfCompressed.until({ it[0]=="merge" }) - ) + input: + set variantCaller, idSample, file(vcf) from snpeffVCF + + output: + set variantCaller, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into (compressVCFsnpEffOut) + + script: + reducedVCF = reduceVCF(vcf) + """ + bgzip < ${vcf} > ${vcf}.gz + tabix ${vcf}.gz + """ } -// STEP VEP +compressVCFsnpEffOut = compressVCFsnpEffOut.dump(tag:'VCF') + +// STEP VEP.1 process VEP { + label 'VEP' + tag {"${idSample} - ${variantCaller} - ${vcf}"} publishDir params.outdir, mode: params.publishDirMode, saveAs: { @@ -1811,7 +1795,7 @@ process VEP { } input: - set annotator, variantCaller, idSample, file(vcf), file(idx) from vcfVep + set variantCaller, idSample, file(vcf), file(idx) from vcfVep file dataDir from Channel.value(params.vep_cache ? file(params.vep_cache) : "null") val cache_version from Channel.value(params.genomes[params.genome].vepCacheVersion) set file(cadd_WG_SNVs), file(cadd_WG_SNVs_tbi), file(cadd_InDels), file(cadd_InDels_tbi) from Channel.value([ @@ -1822,14 +1806,13 @@ process VEP { ]) output: - set finalAnnotator, variantCaller, idSample, file("${reducedVCF}_VEP.ann.vcf") into vepVCF + set variantCaller, idSample, file("${reducedVCF}_VEP.ann.vcf") into vepVCF file("${reducedVCF}_VEP.summary.html") into vepReport - when: 'vep' in tools || 'merge' in tools + when: 'vep' in tools script: reducedVCF = reduceVCF(vcf) - finalAnnotator = annotator == "snpEff" ? 'merge' : 'VEP' genome = params.genome == 'smallGRCh37' ? 'GRCh37' : params.genome dir_cache = (params.vep_cache && params.annotation_cache) ? " \${PWD}/${dataDir}" : "/.vep" cadd = (params.cadd_cache && params.cadd_WG_SNVs && params.cadd_InDels) ? "--plugin CADD,whole_genome_SNVs.tsv.gz,InDels.tsv.gz" : "" @@ -1861,31 +1844,92 @@ process VEP { vepReport = vepReport.dump(tag:'VEP') -vcfCompressVCF = snpeffVCF.mix(vepVCF) +// STEP VEP.2 - VEP after snpEff + +process VEPmerge { + label 'VEP' + + tag {"${idSample} - ${variantCaller} - ${vcf}"} + + publishDir params.outdir, mode: params.publishDirMode, saveAs: { + if (it == "${reducedVCF}_VEP.summary.html") "Reports/${idSample}/VEP/${it}" + else null + } + + input: + set variantCaller, idSample, file(vcf), file(idx) from compressVCFsnpEffOut + file dataDir from Channel.value(params.vep_cache ? file(params.vep_cache) : "null") + val cache_version from Channel.value(params.genomes[params.genome].vepCacheVersion) + set file(cadd_WG_SNVs), file(cadd_WG_SNVs_tbi), file(cadd_InDels), file(cadd_InDels_tbi) from Channel.value([ + params.cadd_WG_SNVs ? file(params.cadd_WG_SNVs) : "null", + params.cadd_WG_SNVs_tbi ? file(params.cadd_WG_SNVs_tbi) : "null", + params.cadd_InDels ? file(params.cadd_InDels) : "null", + params.cadd_InDels_tbi ? file(params.cadd_InDels_tbi) : "null" + ]) + + output: + set variantCaller, idSample, file("${reducedVCF}_VEP.ann.vcf") into vepVCFmerge + file("${reducedVCF}_VEP.summary.html") into vepReportMerge + + when: 'merge' in tools + + script: + reducedVCF = reduceVCF(vcf) + genome = params.genome == 'smallGRCh37' ? 'GRCh37' : params.genome + dir_cache = (params.vep_cache && params.annotation_cache) ? " \${PWD}/${dataDir}" : "/.vep" + cadd = (params.cadd_cache && params.cadd_WG_SNVs && params.cadd_InDels) ? "--plugin CADD,whole_genome_SNVs.tsv.gz,InDels.tsv.gz" : "" + genesplicer = params.genesplicer ? "--plugin GeneSplicer,/opt/conda/envs/sarek-2.5dev/bin/genesplicer,/opt/conda/envs/sarek-2.5dev/share/genesplicer-1.0-1/human,context=200,tmpdir=\$PWD/${reducedVCF}" : "--offline" + """ + mkdir ${reducedVCF} + + vep \ + -i ${vcf} \ + -o ${reducedVCF}_VEP.ann.vcf \ + --assembly ${genome} \ + ${cadd} \ + ${genesplicer} \ + --cache \ + --cache_version ${cache_version} \ + --dir_cache ${dir_cache} \ + --everything \ + --filter_common \ + --fork ${task.cpus} \ + --format vcf \ + --per_gene \ + --stats_file ${reducedVCF}_VEP.summary.html \ + --total_length \ + --vcf + + rm -rf ${reducedVCF} + """ +} + +vepReportMerge = vepReportMerge.dump(tag:'VEP') + +vcfCompressVCFvep = vepVCF.mix(vepVCFmerge) -// STEP COMPRESS AND INDEX VCF +// STEP COMPRESS AND INDEX VCF.2 - VEP -process CompressVCF { - tag {"${idSample} - ${annotator} - ${vcf}"} +process CompressVCFvep { + tag {"${idSample} - ${vcf}"} - publishDir "${params.outdir}/Annotation/${idSample}/${finalAnnotator}", mode: params.publishDirMode + publishDir "${params.outdir}/Annotation/${idSample}/VEP", mode: params.publishDirMode input: - set annotator, variantCaller, idSample, file(vcf) from vcfCompressVCF + set variantCaller, idSample, file(vcf) from vcfCompressVCFvep output: - set annotator, variantCaller, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into (vcfCompressed, compressVCFOut) + set variantCaller, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into compressVCFOutVEP script: reducedVCF = reduceVCF(vcf) - finalAnnotator = annotator == "merge" ? "VEP" : annotator """ bgzip < ${vcf} > ${vcf}.gz tabix ${vcf}.gz """ } -compressVCFOut.dump(tag:'VCF') +compressVCFOutVEP = compressVCFOutVEP.dump(tag:'VCF') /* ================================================================================ @@ -1897,8 +1941,7 @@ compressVCFOut.dump(tag:'VCF') multiQCReport = Channel.empty() .mix( - bamQCmappedReport, - bamQCrecalibratedReport, + bamQCReport, bcftoolsReport, fastQCReport, markDuplicatesReport, From 2a2c499c9a2c45791c309f5f7e77d8fecbcad75e Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 17 Jun 2019 11:22:47 +0200 Subject: [PATCH 021/854] fix output name for vcf --- main.nf | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/main.nf b/main.nf index 1eca25289c..3ea0e4f310 100644 --- a/main.nf +++ b/main.nf @@ -1626,7 +1626,7 @@ process BcftoolsStats { script: """ - bcftools stats ${vcf} > ${reduceVCF(vcf)}.bcf.tools.stats.out + bcftools stats ${vcf} > ${reduceVCF(vcf.fileName)}.bcf.tools.stats.out """ } @@ -1641,7 +1641,7 @@ process Vcftools { set variantCaller, idSample, file(vcf) from vcfVCFtools output: - file ("${reduceVCF(vcf)}.*") into vcftoolsReport + file ("${reduceVCF(vcf.fileName)}.*") into vcftoolsReport when: !params.noReports @@ -1650,17 +1650,17 @@ process Vcftools { vcftools \ --gzvcf ${vcf} \ --TsTv-by-count \ - --out ${reduceVCF(vcf)} + --out ${reduceVCF(vcf.fileName)} vcftools \ --gzvcf ${vcf} \ --TsTv-by-qual \ - --out ${reduceVCF(vcf)} + --out ${reduceVCF(vcf.fileName)} vcftools \ --gzvcf ${vcf} \ --FILTER-summary \ - --out ${reduceVCF(vcf)} + --out ${reduceVCF(vcf.fileName)} """ } @@ -1739,7 +1739,7 @@ process Snpeff { when: 'snpeff' in tools || 'merge' in tools script: - reducedVCF = reduceVCF(vcf) + reducedVCF = reduceVCF(vcf.fileName) cache = (params.snpEff_cache && params.annotation_cache) ? "-dataDir \${PWD}/${dataDir}" : "" """ snpEff -Xmx${task.memory.toGiga()}g \ @@ -1773,7 +1773,6 @@ process CompressVCFsnpEff { set variantCaller, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into (compressVCFsnpEffOut) script: - reducedVCF = reduceVCF(vcf) """ bgzip < ${vcf} > ${vcf}.gz tabix ${vcf}.gz @@ -1812,7 +1811,7 @@ process VEP { when: 'vep' in tools script: - reducedVCF = reduceVCF(vcf) + reducedVCF = reduceVCF(vcf.fileName) genome = params.genome == 'smallGRCh37' ? 'GRCh37' : params.genome dir_cache = (params.vep_cache && params.annotation_cache) ? " \${PWD}/${dataDir}" : "/.vep" cadd = (params.cadd_cache && params.cadd_WG_SNVs && params.cadd_InDels) ? "--plugin CADD,whole_genome_SNVs.tsv.gz,InDels.tsv.gz" : "" @@ -1874,7 +1873,7 @@ process VEPmerge { when: 'merge' in tools script: - reducedVCF = reduceVCF(vcf) + reducedVCF = reduceVCF(vcf.fileName) genome = params.genome == 'smallGRCh37' ? 'GRCh37' : params.genome dir_cache = (params.vep_cache && params.annotation_cache) ? " \${PWD}/${dataDir}" : "/.vep" cadd = (params.cadd_cache && params.cadd_WG_SNVs && params.cadd_InDels) ? "--plugin CADD,whole_genome_SNVs.tsv.gz,InDels.tsv.gz" : "" @@ -1922,7 +1921,6 @@ process CompressVCFvep { set variantCaller, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into compressVCFOutVEP script: - reducedVCF = reduceVCF(vcf) """ bgzip < ${vcf} > ${vcf}.gz tabix ${vcf}.gz From 10eff4e8ff71e672d73a3bf4aa43a3693342bfb2 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Mon, 24 Jun 2019 16:38:59 +0200 Subject: [PATCH 022/854] Fix R scripts (#16) * chmod +x * add correct path to Rscript * update CHANGELOG --- CHANGELOG.md | 3 +++ bin/convertAlleleCounts.r | 0 bin/run_ascat.r | 0 main.nf | 4 ++-- scripts/ascat.R | 0 scripts/filter_locifile.py | 0 scripts/selectROI.py | 0 7 files changed, 5 insertions(+), 2 deletions(-) mode change 100644 => 100755 bin/convertAlleleCounts.r mode change 100644 => 100755 bin/run_ascat.r mode change 100644 => 100755 scripts/ascat.R mode change 100644 => 100755 scripts/filter_locifile.py mode change 100644 => 100755 scripts/selectROI.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 25df131630..77dce5c5a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#12](https://github.com/nf-core/sarek/pull/12) - Simplify `check_max()` function - [#13](https://github.com/nf-core/sarek/pull/13) - Merge `BamQCmapped` and `BamQCrecalibrated` processes into `BamQC` process - [#13](https://github.com/nf-core/sarek/pull/13) - Split `CompressVCF` process into `CompressVCFsnpEff` and `CompressVCFvep` processes +- [#16](https://github.com/nf-core/sarek/pull/16) - Make scripts in `bin/` and `scripts/` executable ### `Removed` @@ -63,6 +64,8 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#3](https://github.com/nf-core/sarek/pull/3) - Fix Docker ownership - [#11](https://github.com/nf-core/sarek/pull/11) - Fix MergeMpileup PublishDir - [#13](https://github.com/nf-core/sarek/pull/13) - Fix merge in annotation +- [#14](https://github.com/nf-core/sarek/pull/14) - Fix output name for vcf files +- [#16](https://github.com/nf-core/sarek/pull/16) - Fix path to Rscript ## [2.3.FIX1] - 2019-03-04 diff --git a/bin/convertAlleleCounts.r b/bin/convertAlleleCounts.r old mode 100644 new mode 100755 diff --git a/bin/run_ascat.r b/bin/run_ascat.r old mode 100644 new mode 100755 diff --git a/main.nf b/main.nf index 3ea0e4f310..68854e5dfa 100644 --- a/main.nf +++ b/main.nf @@ -1359,7 +1359,7 @@ process ConvertAlleleCounts { script: gender = genderMap[idPatient] """ - convertAlleleCounts.r ${idSampleTumor} ${alleleCountTumor} ${idSampleNormal} ${alleleCountNormal} ${gender} + Rscript ${workflow.projectDir}/bin/convertAlleleCounts.r ${idSampleTumor} ${alleleCountTumor} ${idSampleNormal} ${alleleCountNormal} ${gender} """ } @@ -1387,7 +1387,7 @@ process Ascat { """ # get rid of "chr" string if there is any for f in *BAF *LogR; do sed 's/chr//g' \$f > tmpFile; mv tmpFile \$f;done - run_ascat.r ${bafTumor} ${logrTumor} ${bafNormal} ${logrNormal} ${idSampleTumor} ${baseDir} ${acLociGC} + Rscript ${workflow.projectDir}/bin/run_ascat.r ${bafTumor} ${logrTumor} ${bafNormal} ${logrNormal} ${idSampleTumor} ${baseDir} ${acLociGC} """ } diff --git a/scripts/ascat.R b/scripts/ascat.R old mode 100644 new mode 100755 diff --git a/scripts/filter_locifile.py b/scripts/filter_locifile.py old mode 100644 new mode 100755 diff --git a/scripts/selectROI.py b/scripts/selectROI.py old mode 100644 new mode 100755 From 0d66968f32fb3ea4bd25e8979c1d57caa312d0ee Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Fri, 5 Jul 2019 14:30:31 +0200 Subject: [PATCH 023/854] More improvments (#18) * Improve cpu usage * Use same font for nf-core and sarek in ascii art * Improve syntax * Add --no-reports option for tests + add snpEff,VEP,merge to MULTIPLE test * Use --no-reports for TravisCI testing * Add possibility to download other genome for sareksnpeff and sarekvep containers * Update docs * Add --no-reports for all tests but MULTIPLE * Use sensible label selectors for configs * Enhance the old --noReports with --skip to skip QC on demand * Replace --noReports by --skip all * Update logos with new nf-core/sarek logo * Add logo to MultiQC report * Remove createMultiQCconfig() * Improve docs about offline usage with bianca * Code polishing * Update CHANGELOG --- .travis.yml | 2 +- CHANGELOG.md | 21 +- Jenkinsfile | 10 +- assets/multiqc_config.yaml | 15 +- build.nf | 12 +- conf/base.config | 69 +- docs/containers.md | 31 + docs/images/{BTB.svg => BTB_logo.svg} | 0 docs/images/CAW_logo.png | Bin 6165 -> 9692 bytes docs/images/CAW_logo.svg | 185 ++--- docs/images/{NBIS.svg => NBIS_logo.svg} | 0 docs/images/{NGI.svg => NGI_logo.svg} | 0 docs/images/Sarek_exome_logo.png | Bin 10775 -> 0 bytes docs/images/Sarek_germline_icon.png | Bin 2191 -> 0 bytes docs/images/Sarek_germline_logo.png | Bin 11038 -> 0 bytes docs/images/Sarek_icon.png | Bin 2078 -> 0 bytes docs/images/Sarek_icon.svg | 188 ----- docs/images/Sarek_logo.png | Bin 8766 -> 0 bytes docs/images/Sarek_logo.svg | 408 ---------- docs/images/Sarek_no_Border.png | Bin 16435 -> 0 bytes docs/images/Sarek_somatic_icon.png | Bin 2108 -> 0 bytes docs/images/Sarek_somatic_logo.png | Bin 11571 -> 0 bytes .../{SciLifeLab.svg => SciLifeLab_logo.svg} | 0 docs/images/logos/Sarek Exome/Sarek_exome.svg | 227 ------ .../logos/Sarek Germline/Sarek_germline.svg | 242 ------ .../logos/Sarek Somatic/Sarek_somatic.svg | 232 ------ docs/images/logos/Sarek/Sarek_color.svg | 201 ----- docs/images/logos/Sarek/Sarek_dark_color.svg | 393 ---------- docs/images/logos/Sarek/Sarek_dark_grey.svg | 401 ---------- docs/images/logos/Sarek/Sarek_dark_mono.svg | 193 ----- docs/images/logos/Sarek/Sarek_grey.svg | 409 ---------- docs/images/logos/Sarek/Sarek_mono.svg | 390 ---------- .../nf-core_sarek/nf-core_sarek_color.svg | 355 +++++++++ .../nf-core_sarek_dark_color.svg | 352 +++++++++ .../nf-core_sarek/nf-core_sarek_dark_grey.svg | 376 ++++++++++ .../nf-core_sarek/nf-core_sarek_dark_mono.svg | 292 ++++++++ .../nf-core_sarek/nf-core_sarek_grey.svg | 364 +++++++++ .../nf-core_sarek/nf-core_sarek_mono.svg | 348 +++++++++ .../logos/sarek-germline/sarek-germline.svg | 315 ++++++++ .../sarek-somatic/sarek-somatic_logo.svg | 308 ++++++++ docs/images/logos/sarek/sarek_color.svg | 247 ++++++ docs/images/logos/sarek/sarek_dark_color.svg | 248 ++++++ docs/images/logos/sarek/sarek_dark_grey.svg | 288 +++++++ docs/images/logos/sarek/sarek_dark_mono.svg | 243 ++++++ docs/images/logos/sarek/sarek_grey.svg | 256 +++++++ docs/images/logos/sarek/sarek_mono.svg | 248 ++++++ docs/images/nf-core_sarek-germline_logo.svg | 423 +++++++++++ docs/images/nf-core_sarek-somatic_logo.svg | 416 +++++++++++ docs/images/nf-core_sarek_logo.png | Bin 0 -> 14773 bytes docs/images/nf-core_sarek_logo.svg | 355 +++++++++ docs/images/sarek_icon.svg | 215 ++++++ docs/images/sarek_logo.svg | 247 ++++++ docs/images/social_preview_image.png | Bin 46389 -> 51946 bytes docs/images/social_preview_image.svg | 705 +++++++----------- docs/install_bianca.md | 4 +- main.nf | 201 ++--- nextflow.config | 9 +- scripts/build_reference.sh | 4 +- scripts/download_image.sh | 69 +- scripts/run_tests.sh | 36 +- 60 files changed, 6543 insertions(+), 4010 deletions(-) rename docs/images/{BTB.svg => BTB_logo.svg} (100%) rename docs/images/{NBIS.svg => NBIS_logo.svg} (100%) rename docs/images/{NGI.svg => NGI_logo.svg} (100%) delete mode 100644 docs/images/Sarek_exome_logo.png delete mode 100644 docs/images/Sarek_germline_icon.png delete mode 100644 docs/images/Sarek_germline_logo.png delete mode 100644 docs/images/Sarek_icon.png delete mode 100644 docs/images/Sarek_icon.svg delete mode 100644 docs/images/Sarek_logo.png delete mode 100644 docs/images/Sarek_logo.svg delete mode 100644 docs/images/Sarek_no_Border.png delete mode 100644 docs/images/Sarek_somatic_icon.png delete mode 100644 docs/images/Sarek_somatic_logo.png rename docs/images/{SciLifeLab.svg => SciLifeLab_logo.svg} (100%) delete mode 100644 docs/images/logos/Sarek Exome/Sarek_exome.svg delete mode 100644 docs/images/logos/Sarek Germline/Sarek_germline.svg delete mode 100644 docs/images/logos/Sarek Somatic/Sarek_somatic.svg delete mode 100644 docs/images/logos/Sarek/Sarek_color.svg delete mode 100644 docs/images/logos/Sarek/Sarek_dark_color.svg delete mode 100644 docs/images/logos/Sarek/Sarek_dark_grey.svg delete mode 100644 docs/images/logos/Sarek/Sarek_dark_mono.svg delete mode 100644 docs/images/logos/Sarek/Sarek_grey.svg delete mode 100644 docs/images/logos/Sarek/Sarek_mono.svg create mode 100644 docs/images/logos/nf-core_sarek/nf-core_sarek_color.svg create mode 100644 docs/images/logos/nf-core_sarek/nf-core_sarek_dark_color.svg create mode 100644 docs/images/logos/nf-core_sarek/nf-core_sarek_dark_grey.svg create mode 100644 docs/images/logos/nf-core_sarek/nf-core_sarek_dark_mono.svg create mode 100644 docs/images/logos/nf-core_sarek/nf-core_sarek_grey.svg create mode 100644 docs/images/logos/nf-core_sarek/nf-core_sarek_mono.svg create mode 100644 docs/images/logos/sarek-germline/sarek-germline.svg create mode 100644 docs/images/logos/sarek-somatic/sarek-somatic_logo.svg create mode 100644 docs/images/logos/sarek/sarek_color.svg create mode 100644 docs/images/logos/sarek/sarek_dark_color.svg create mode 100644 docs/images/logos/sarek/sarek_dark_grey.svg create mode 100644 docs/images/logos/sarek/sarek_dark_mono.svg create mode 100644 docs/images/logos/sarek/sarek_grey.svg create mode 100644 docs/images/logos/sarek/sarek_mono.svg create mode 100644 docs/images/nf-core_sarek-germline_logo.svg create mode 100644 docs/images/nf-core_sarek-somatic_logo.svg create mode 100644 docs/images/nf-core_sarek_logo.png create mode 100644 docs/images/nf-core_sarek_logo.svg create mode 100644 docs/images/sarek_icon.svg create mode 100644 docs/images/sarek_logo.svg diff --git a/.travis.yml b/.travis.yml index 4db211fa00..cb01d2c317 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,4 +43,4 @@ before_script: # Actual tests script: - - "${TRAVIS_BUILD_DIR}/scripts/run_tests.sh --test $TEST --verbose" + - "${TRAVIS_BUILD_DIR}/scripts/run_tests.sh --test $TEST --verbose --no-reports" diff --git a/CHANGELOG.md b/CHANGELOG.md index 77dce5c5a0..ac96e27021 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## Unreleased + Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) template. ### `Added` + - [#2](https://github.com/nf-core/sarek/pull/2) - Create `nf-core/sarek` `environment.yml` file - [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#7](https://github.com/nf-core/sarek/pull/7), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Add CI for `nf-core/sarek` - [#3](https://github.com/nf-core/sarek/pull/3) - Add preprocessing to `nf-core/sarek` @@ -32,9 +34,14 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#13](https://github.com/nf-core/sarek/pull/13) - Add Citation documentation - [#13](https://github.com/nf-core/sarek/pull/13) - Add `BamQC` process - [#13](https://github.com/nf-core/sarek/pull/13) - Add `CompressVCFsnpEff` and `CompressVCFvep` processes +- [#18](https://github.com/nf-core/sarek/pull/18) - Add --no-reports option for tests + add snpEff,VEP,merge to MULTIPLE test +- [#18](https://github.com/nf-core/sarek/pull/18) - Add possibility to download other genome for sareksnpeff and sarekvep containers +- [#18](https://github.com/nf-core/sarek/pull/18) - Add params `--skip` to skip specified QC tools +- [#18](https://github.com/nf-core/sarek/pull/18) - Add logo to MultiQC report ### `Changed` -- [#1](https://github.com/nf-core/sarek/pull/1), [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#6](https://github.com/nf-core/sarek/pull/6), [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Update docs + +- [#1](https://github.com/nf-core/sarek/pull/1), [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#6](https://github.com/nf-core/sarek/pull/6), [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12), [#18](https://github.com/nf-core/sarek/pull/18) - Update docs - [#4](https://github.com/nf-core/sarek/pull/4) - Update `cancerit-allelecount` from `2.1.2` to `4.0.2` - [#4](https://github.com/nf-core/sarek/pull/4) - Update `gatk4` from `4.1.1.0` to `4.1.2.0` - [#7](https://github.com/nf-core/sarek/pull/7) - `--sampleDir` is now deprecated, use `--sample` instead @@ -53,28 +60,38 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#13](https://github.com/nf-core/sarek/pull/13) - Merge `BamQCmapped` and `BamQCrecalibrated` processes into `BamQC` process - [#13](https://github.com/nf-core/sarek/pull/13) - Split `CompressVCF` process into `CompressVCFsnpEff` and `CompressVCFvep` processes - [#16](https://github.com/nf-core/sarek/pull/16) - Make scripts in `bin/` and `scripts/` executable +- [#18](https://github.com/nf-core/sarek/pull/18) - Use --no-reports for TravisCI testing +- [#18](https://github.com/nf-core/sarek/pull/18) - Add --no-reports for all tests but MULTIPLE in Jenkins +- [#18](https://github.com/nf-core/sarek/pull/18) - `--noReports` is now `--skip all` +- [#18](https://github.com/nf-core/sarek/pull/18) - Update logo ### `Removed` - [#9](https://github.com/nf-core/sarek/pull/9) - Removed `relatedness2` graph from `vcftools stats` - [#13](https://github.com/nf-core/sarek/pull/13) - Removed `BamQCmapped` and `BamQCrecalibrated` processes - [#13](https://github.com/nf-core/sarek/pull/13) - Removed `CompressVCF` +- [#18](https://github.com/nf-core/sarek/pull/18) - Removed params `--noReports` ### `Fixed` + - [#3](https://github.com/nf-core/sarek/pull/3) - Fix Docker ownership - [#11](https://github.com/nf-core/sarek/pull/11) - Fix MergeMpileup PublishDir - [#13](https://github.com/nf-core/sarek/pull/13) - Fix merge in annotation - [#14](https://github.com/nf-core/sarek/pull/14) - Fix output name for vcf files - [#16](https://github.com/nf-core/sarek/pull/16) - Fix path to Rscript +- [#18](https://github.com/nf-core/sarek/pull/18) - Improve cpu usage +- [#18](https://github.com/nf-core/sarek/pull/18) - Use same font for nf-core and sarek in ascii art ## [2.3.FIX1] - 2019-03-04 ### `Fixed` + - [#742](https://github.com/SciLifeLab/Sarek/pull/742) - Fix output dirs (HaplotypeCaller that was not recognized by annotate.nf introduced by [#728](https://github.com/SciLifeLab/Sarek/pull/728)) ## [2.3] - Äpar - 2019-02-27 ### `Added` + - [#628](https://github.com/SciLifeLab/Sarek/pull/628), [#722](https://github.com/SciLifeLab/Sarek/pull/722) - `ASCAT` now use `.gc` file - [#712](https://github.com/SciLifeLab/Sarek/pull/712), [#718](https://github.com/SciLifeLab/Sarek/pull/718) - Added possibilities to run Sarek with `conda` - [#719](https://github.com/SciLifeLab/Sarek/pull/719) - Annotation documentation @@ -116,6 +133,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Update VEP from `95.1` to `95.2` ### `Removed` + - [#715](https://github.com/SciLifeLab/Sarek/pull/715) - Remove `defReferencesFiles` function from `buildReferences.nf` - [#719](https://github.com/SciLifeLab/Sarek/pull/719) - `snpEff` base container is no longer used - [#721](https://github.com/SciLifeLab/Sarek/pull/721) - Remove COSMIC docs @@ -123,6 +141,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Removed `--database` option for VEP cf: [VEP docs](https://www.ensembl.org/info/docs/tools/vep/script/vep_other.html) ### `Fixed` + - [#720](https://github.com/SciLifeLab/Sarek/pull/720) - bamQC is now run on the recalibrated bams, and not after MarkDuplicates - [#726](https://github.com/SciLifeLab/Sarek/pull/726) - Fix Ascat ref file input (one file can't be a set) - [#727](https://github.com/SciLifeLab/Sarek/pull/727) - bamQC outputs are no longer overwritten (name of dir is now the file instead of sample) diff --git a/Jenkinsfile b/Jenkinsfile index b4b5aa501f..a6a974eb67 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -8,7 +8,7 @@ pipeline { stages { stage('Docker setup') { steps { - sh "./scripts/download_image.sh -n docker -t ALL" + sh "./scripts/download_image.sh -n docker -t ALL -T dev -g smallGRCh37" } } stage('Build references') { @@ -21,23 +21,23 @@ pipeline { steps { sh "rm -rf data/" sh "git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data" - sh "./scripts/run_tests.sh --test GERMLINE" + sh "./scripts/run_tests.sh --test GERMLINE --no-reports" sh "rm -rf data/" } } stage('Somatic') { steps { - sh "./scripts/run_tests.sh --test SOMATIC" + sh "./scripts/run_tests.sh --test SOMATIC --no-reports" } } stage('Targeted') { steps { - sh "./scripts/run_tests.sh --test TARGETED" + sh "./scripts/run_tests.sh --test TARGETED --no-reports" } } stage('Annotation') { steps { - sh "./scripts/run_tests.sh --test ANNOTATEALL" + sh "./scripts/run_tests.sh --test ANNOTATEBOTH --no-reports" } } stage('Multiple') { diff --git a/assets/multiqc_config.yaml b/assets/multiqc_config.yaml index fe8d008cb4..c1ca9983e0 100644 --- a/assets/multiqc_config.yaml +++ b/assets/multiqc_config.yaml @@ -1,9 +1,22 @@ +custom_logo: ../../../docs/images/nf-core_sarek_logo.png +custom_logo_url: https://github.com/nf-core/sarek/ +custom_logo_title: 'nf-core/sarek' + report_comment: > This report has been generated by the nf-core/sarek analysis pipeline. For information about how to interpret these results, please see the - documentation. + documentation. report_section_order: nf-core/sarek-software-versions: order: -1000 export_plots: true + +top_modules: +- 'fastqc' +- 'picard' +- 'samtools' +- 'qualimap' +- 'bcftools' +- 'vcftools' +- 'snpeff' diff --git a/build.nf b/build.nf index bcf1fe38d4..9c828f6f36 100644 --- a/build.nf +++ b/build.nf @@ -387,12 +387,12 @@ def nfcoreHeader(){ ${c_blue} |\\ | |__ __ / ` / \\ |__) |__ ${c_yellow}} {${c_reset} ${c_blue} | \\| | \\__, \\__/ | \\ |___ ${c_green}\\`-._,-`-,${c_reset} ${c_green}`._,._,\'${c_reset} - ${c_white} ____ ${c_blue} _____ _ ${c_reset} - ${c_white} .' _ `. ${c_blue} / ____| | | ${c_reset} - ${c_white} / ${c_green}|\\${c_white}`-_${c_white} \\ ${c_blue} | (___ ___ _ __ __ | | __ ${c_reset} - ${c_white} | ${c_green}| \\ ${c_white}`-${c_white}| ${c_blue} \\___ \\/__ \\| ´__/ _\\| |/ / ${c_reset} - ${c_white} \\ ${c_green}| \\ ${c_white}/ ${c_blue} ____) | __ | | | __| < ${c_reset} - ${c_white} `${c_green}|${c_white}____${c_green}\\${c_white}' ${c_blue} |_____/\\____|_| \\__/|_|\\_\\ ${c_reset} + ${c_white}____${c_reset} + ${c_white}.´ _ `.${c_reset} + ${c_white}/ ${c_green}|\\${c_reset}`-_ \\${c_reset} ${c_blue} __ __ ___ ${c_reset} + ${c_white}| ${c_green}| \\${c_reset} `-|${c_reset} ${c_blue}|__` /\\ |__) |__ |__/${c_reset} + ${c_white}\\ ${c_green}| \\${c_reset} /${c_reset} ${c_blue}.__| /¯¯\\ | \\ |___ | \\${c_reset} + ${c_white}`${c_green}|${c_reset}____${c_green}\\${c_reset}´${c_reset} ${c_purple} nf-core/sarek v${workflow.manifest.version}${c_reset} ${c_dim}----------------------------------------------------${c_reset} diff --git a/conf/base.config b/conf/base.config index 7db37b80c8..942acc7a91 100644 --- a/conf/base.config +++ b/conf/base.config @@ -3,7 +3,7 @@ * nf-core/sarek Nextflow base config file * ------------------------------------------------- * A 'blank slate' config file, appropriate for general - * use on most high performace compute environments. + * use on most high performance compute environments. * Assumes that all software is installed and available * on the PATH. Runs in `local` mode - all jobs will be * run on the logged in environment. @@ -11,7 +11,7 @@ params { // Defaults only, expecting to be overwritten - cpus = 10 + cpus = 8 igenomes_base = 's3://ngi-igenomes/igenomes/' markdup_java_options = '"-Xms4000m -Xmx7g"' //Established values for markDuplicate memory consumption, see issue PR #689 for details max_cpus = 16 // Base specifications @@ -21,79 +21,68 @@ params { } process { - cpus = {check_max(params.cpus * task.attempt)} - memory = {check_max(15.GB * task.attempt)} - time = {check_max(24.h * task.attempt)} + cpus = {check_resource(params.cpus * task.attempt)} + memory = {check_resource(params.singleCPUMem * task.attempt)} + time = {check_resource(24.h * task.attempt)} shell = ['/bin/bash', '-euo', 'pipefail'] errorStrategy = {task.exitStatus in [143,137,104,134,139] ? 'retry' : 'finish'} maxErrors = '-1' maxRetries = 3 - withLabel:singleCPUmem_x_task { - memory = {check_max(params.singleCPUMem * task.attempt)} + withLabel:cpus_1 { + cpus = {check_resource(1)} } - withLabel:singleCPUmem_x2_task { - memory = {check_max(params.singleCPUMem * task.attempt * task.attempt)} - } - withLabel:singleCPUmem_2x_task { - memory = {check_max(params.singleCPUMem * 2 * task.attempt)} + withLabel:cpus_2 { + cpus = {check_resource(2)} } - withLabel:max_cpus { + withLabel:cpus_4 { + cpus = {check_resource(4)} + } + withLabel:cpus_8 { + cpus = {check_resource(8)} + } + withLabel:cpus_16 { + cpus = {check_resource(16)} + } + withLabel:cpus_max { cpus = {params.max_cpus} } - withLabel:max_memory { - memory = {check_max(params.max_memory)} + + withLabel:memory_singleCPU_2_task { + memory = {check_resource(params.singleCPUMem * 2 * task.attempt)} } - withName:BamQC { - cpus = {check_max(16)} + withLabel:memory_singleCPU_task_sq { + memory = {check_resource(params.singleCPUMem * task.attempt * task.attempt)} } - withName:BaseRecalibrator { - cpus = {check_max(16)} + + withLabel:memory_max { + memory = {check_resource(params.max_memory)} } + withName:ConcatVCF { - cpus = {check_max(8)} // For unknown reasons, ConcatVCF sometimes fails with SIGPIPE // (exit code 141). Rerunning the process will usually work. errorStrategy = {task.exitStatus == 141 ? 'retry' : 'terminate'} } withName:FastQCBAM { - cpus = {check_max(2)} errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} } withName:FastQCFQ { - // FastQC is only capable of running one thread per fastq file. - cpus = {check_max(2)} errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} } - withName:GatherBQSRReports { - cpus = {check_max(2)} - } withName:MapReads { - memory = {check_max(check_max(60.GB * task.attempt))} - } - withName:MarkDuplicates { - cpus = {check_max(16)} - } - withName:MergeBamMapped { - cpus = {check_max(8)} - } - withName:MergeBamRecal { - cpus = {check_max(8)} + memory = {check_resource(check_resource(60.GB * task.attempt))} } withName:MultiQC { errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} } - withName:SamtoolsStats { - cpus = {check_max(2)} - } withName:Snpeff { container = {(params.annotation_cache && params.snpEff_cache) ? 'nfcore/sarek:dev' : "nfcore/sareksnpeff:dev.${params.genome}"} errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} } withLabel:VEP { container = {(params.annotation_cache && params.vep_cache) ? 'nfcore/sarek:dev' : "nfcore/sarekvep:dev.${params.genome}"} - cpus = {check_max(4)} errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} } } diff --git a/docs/containers.md b/docs/containers.md index 14f139c24f..be1c31a85e 100644 --- a/docs/containers.md +++ b/docs/containers.md @@ -47,6 +47,37 @@ For annotation, the main container can be used, but the cache has to be download - Contain **[VEP][vep-link]** 96.0 - Contain cache for `GRCh37`, `GRCh38`, or `GRCm38` +## Using helper script + +An helper script, used for testing can also be used to help with pulling docker containers, or building singularity images. +The following parameters can be used: + +### Engine: -n + +Specify which container engine to use: `docker` or `singularity`. +Default:`docker` + +### Containers: -c + +Specify which containers to build: `SNPEFF`, `VEP` or `ALL`. +Default:`ALL` + +### Version: -T + +Specify which release to pull or build: any tagged release, or `dev`. +Default:`dev` + +### Genome: -g +Specify which release genome to use for annotation containers (`sareksnpeff`, `sarekvep`): `GRCh37`, `GRCh38`, `smallGRCh37`, `CanFan3.1`, `GRCm38`. +Default:`smallGRCh37` + +### Singularity +To specify where to build singularity image, use the Nextflow ENV variable `NXF_SINGULARITY_CACHEDIR`, ie: +```bash +NXF_SINGULARITY_CACHEDIR=/data/singularity ./scripts/download_image.sh -n singularity -t ALL -T dev -g GRCh38 +``` +That will build the main container, plus the annotation containers (`sareksnpeff`, `sarekvep`) for `GRCh38`, in the `/data/singularity` folder + ## Building your own Our containers are designed using [Conda](https://conda.io/). The `environment.yml` file can easilly be modified if particular versions of tools are more suited to your needs. diff --git a/docs/images/BTB.svg b/docs/images/BTB_logo.svg similarity index 100% rename from docs/images/BTB.svg rename to docs/images/BTB_logo.svg diff --git a/docs/images/CAW_logo.png b/docs/images/CAW_logo.png index cc2bbe2613994b32a575081ad24ee2abfd6c55a1..285d7274089e79ade109491e7103fad4758d204e 100644 GIT binary patch literal 9692 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 rHPwD=?T>lm=HdSZd3Vtt delta 6160 zcmZ`-bx_m+(*~uH5Dt(&4(XCcxk0u^O>?SFpYpW5JH{j)*==k3W1 zRQNdMXlOX)=zQOvJWW<)0Vq;b9#jA78p=HMxFy>G)-W3DXE( zs>P0UcQw=@$HZ)qxelY(%?q*Blb^oQ)uK-#e{NfjjuBGycdHO^&a^5Ele z-p9794yiIn=G29;PJg>eukL)Je4^21@5AA(heLOXZbr12xVZ13jerYJ&wy>o23|y* zDyUYgwN?IqA!J8$&g$F!fwWS61{Jr4pP{p(V?tQdM+0pkczv*ov9T%gPZ#vt)hwiP zxIYWooAem8RKL4C1LEd>+bX;9izI^M|AzrcA9LKlVQ4=)j{y4tX~I{`s?Jp5a3qnZ zN12nw+R-jaY9n5Revqve#$)7`E5;GSLZk%+>Yy~k;)jegiJH>VvoI?3OtjBa zA@0}<3>&Xar|8(-92bg24P=$2S!wa9(ffnHi|Xy1V1<{%#lLzrKV60%b$<3WeT2HY zqU5(r6+PENu4q|c0R_#?%~W9&CqMgQl({ju(U?ob4S`r&x|n$$uxv0coBjMp4)ueK z<9Il-wxlzpc<4Cq<4m>wBg;=6V`FIbNUNapZ1CGRfsX&;k__CAqMLoHsmU$j-}0_Q=_bH7n2l(mzy^SvKM;4P{J`bJe%$sD-9p#3Uol8~uACWm|?BDilu zh@`N&3X>>Eh)w76*Qmud6(%LT|r zWaQ~7sd}q;UCR{>x^44eJ{78Wd6@u9T+;Dqbyu6u``t~FVk$-PiMSN&Dm+o4#_;nF zVS)WXESZ00ym4ocFM)^Uzcw+&US%_t2G=$>`_+!L22|iEu!KXCmlX(b*B;(e#8Kb? zXJt$>Iz&{|Z-N6@Myu3}G(mIsP3Sc;oMX9&x(%B`D-1J&5(3 z#Zyt=#j+!M?)~?`STSBhOp{2x4R}1}iK{@@DElMf%kjb((L>H)w%P3`KW1817oUJ? zD{69=&9uE}WKA^YvDq3MBj?X?{-&m#0vjopmlU&~%fsX(dVK?%*U~Cq{dWJ`GAUR`=;47#@WPQN{`cr{8A^$m91)-ScB3{!1%qW zz=?+HII^Oz_B|lzUj#yl3W@7%seL7gG4rws{A|y*1 z7H(Q-`esvcf3t~(mwTP4vyKnYIE$WGmDThGjE{ZOJxLgV(>ddD%I3tEo3n+Uv=j|o zJ0*Wcm=Ta;LAHLpl25vZZ~_5~WRO*|Y7uEg|>8b>3=fcd;%Bte||@lwV4$FW08)aiJMY}NKt}vOI= #QV&LHl%P^aC0G?V5*jek#1kxkgKC^ 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 image/svg+xml - + @@ -508,31 +508,10 @@ inkscape:groupmode="layer" id="layer1" transform="translate(424.22498,-1533.4112)"> - + + id="g279"> - - W + + + + + + + + id="g269"> - - A + + + + + + + + id="g259"> - - C + + + + + + + + d="m -424.22497,1533.4112 v 8 h 315 v -8 z" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:27.4412365;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> diff --git a/docs/images/NBIS.svg b/docs/images/NBIS_logo.svg similarity index 100% rename from docs/images/NBIS.svg rename to docs/images/NBIS_logo.svg diff --git a/docs/images/NGI.svg b/docs/images/NGI_logo.svg similarity index 100% rename from docs/images/NGI.svg rename to docs/images/NGI_logo.svg diff --git a/docs/images/Sarek_exome_logo.png b/docs/images/Sarek_exome_logo.png deleted file mode 100644 index b1e11e37a832f7cfd48176a8819688552b0e93d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10775 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 SfT=m*;FRRm#mVwAsieAZk(sG&BOK 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 Y18G~bPU|N;o&W#<07*qoM6N<$f}h_;`v3p{ diff --git a/docs/images/Sarek_icon.png b/docs/images/Sarek_icon.png deleted file mode 100644 index 5bdbf966ef9fe03e0a1bfa67b9ca99cd664718f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2078 zcmV+(2;ujMP)3CVEI`JLbQcizvLfyLo1;D3M#SXyh*T8mOjlu}cl z0qaqjHsD8#;aDxewg&i%QfiHeOeN;$=TlWxMQLd%1qB5F7=}TAe?P%skYqCX*tt@O z$bH})pm_mWvf^#PeAJ@i^?GIZ?%h&fUoXL6P%O)mbXb-pfj~g&>+7YqwpI!X3Iq_X zwEzZC`z(c*1O1Pj$;OQv<>=9)Vi-nR!SgXTHYP`o9Fgkk>gj>>0xK6=e4W$ce!pLu znwrG6?VN?r#I|i|Y;2Uu%1Qy8`SQ!f5`Wp5ly!A=5|76hP54aW@wn{Yzh4}Gz{Q1% zzoV3rva&L1X=!<8!e`Rl+$^P~rA|+Taupv2WbN9u5(osAOuR!V6cWGRFMt5|vlV|? zDJ7Mal@f_WmR!6;BodK|iVCME&SxsVPHQb?Wo6RY+45|pcbS0wx}BqQS^i@M28=j6$gPA?daXy-8ZeWlb#>({TR zt*s5EGC$+}vF#5$Fz)k>@^7+CF9X1(T&!@f;6=9&pJ(#V$y*2_LUnaD?d|Q@w*3Zh z*7Ydw-$2o!LxL(# zCTS!qisXX*%?DL?(^9tPt5Q~$3nSk0D~ zzKzdQGN+x}<)PTU0-wjni*6sq?qamk^ZFYb8>76u9Md!r5tYZ}WrUqOcV;c#5{r@X z;V06fMwH`$52z}BmCb8j$K&$MYCCQv=rt4cnv;u4ro+zb^|E8f4jLL70N%_4ehpAl zQ{>sEek-g#w-#ZY31p~Mhf4?&^uF7vWtS}zsm z7Xq+t+cqbF19^ZSVC&YcSqIQH(luv(B9-7m%Btn7GOk+?ViPf96EW_O zO&*0jE)PDBk5@Lm;uL#T10J{AO+`gT)&blZy^~S70ds(+U?XR{TZpIPS^IHFSP3FV zgt4L+`R;rGk5)>ls;VknF4uhaPw`;vLB?eTAvhf1*zLb^rMDGZ?5zDcXqTq^pL?-;Ir#-BEG|MRg%%MC3k!3qWFS6}vw(-= zBYYV8J0FEVWGorW+J3qB1w@4T7v41VnSG2~1~~TMVkk$lp+?( zz6F9K!K`i4Vc8Z}dRjT&@jjuE%x;k8SRADkc_PBVK;}c?*5FMpMK5wW`bn;O(=wVI zrTOm1d~x_?HhIPRp+Jj{JnDaFBq2R~QKYX7xvu_Tsd z{RjBn%rfcj1Di!891e%svSrJ2=?NoZaAE%?j9wEF=>onpTe}hl5${h|Hj_uti(2b%i3t85S5mdhk1Id>2Y^hlk`{r6PP$Ho z&{{jgX4aN>$V5rKh$NI!HG}O#ME=`@XQhY2HQt4N&p#c3=%pT7e|weQ*1qWz_UH4N zW+P!Ga7(*%nQhq=eW{4bAFgHf=GEkRa_f;)!XkPhN~kH!=-n9FrLir$2lxszR-1I> z(uTW$KWnX*+qO-fCy!NMFJonO2_@@%EH7V<(z919wqQg}2HS@ixIRE%Yd@((%4u(!F%gFQO0gy_hNIpzr^qAPGCmyr}xX0wt z;OqjlESNWeYfOG~VkxD><#LJAN|b)|`SH(f4B#s8gT-+Cf7APF;mASVQ2+n{07*qo IM6N<$g2~7A9RL6T diff --git a/docs/images/Sarek_icon.svg b/docs/images/Sarek_icon.svg deleted file mode 100644 index a921cd277d..0000000000 --- a/docs/images/Sarek_icon.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/images/Sarek_logo.png b/docs/images/Sarek_logo.png deleted file mode 100644 index ed5079200fa427501d17edaa974754e211e4a8eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8766 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 diff --git a/docs/images/Sarek_logo.svg b/docs/images/Sarek_logo.svg deleted file mode 100644 index 8491e71bf2..0000000000 --- a/docs/images/Sarek_logo.svg +++ /dev/null @@ -1,408 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - Sarek  - - - - - - - - - diff --git a/docs/images/Sarek_no_Border.png b/docs/images/Sarek_no_Border.png deleted file mode 100644 index 81f74b561350bf9c74aabeb1d5ca3e030fea9eeb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16435 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 O1bG={=}JlCkpBlstpi>F diff --git a/docs/images/Sarek_somatic_icon.png b/docs/images/Sarek_somatic_icon.png deleted file mode 100644 index 8f30b4d45d85e3fad09a9ace8c2e4b67d2325567..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2108 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 diff --git a/docs/images/SciLifeLab.svg b/docs/images/SciLifeLab_logo.svg similarity index 100% rename from docs/images/SciLifeLab.svg rename to docs/images/SciLifeLab_logo.svg diff --git a/docs/images/logos/Sarek Exome/Sarek_exome.svg b/docs/images/logos/Sarek Exome/Sarek_exome.svg deleted file mode 100644 index 63ab7420f7..0000000000 --- a/docs/images/logos/Sarek Exome/Sarek_exome.svg +++ /dev/null @@ -1,227 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/images/logos/Sarek Germline/Sarek_germline.svg b/docs/images/logos/Sarek Germline/Sarek_germline.svg deleted file mode 100644 index 13a3447c10..0000000000 --- a/docs/images/logos/Sarek Germline/Sarek_germline.svg +++ /dev/null @@ -1,242 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/images/logos/Sarek Somatic/Sarek_somatic.svg b/docs/images/logos/Sarek Somatic/Sarek_somatic.svg deleted file mode 100644 index 75b75fc784..0000000000 --- a/docs/images/logos/Sarek Somatic/Sarek_somatic.svg +++ /dev/null @@ -1,232 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/images/logos/Sarek/Sarek_color.svg b/docs/images/logos/Sarek/Sarek_color.svg deleted file mode 100644 index 207b7297b8..0000000000 --- a/docs/images/logos/Sarek/Sarek_color.svg +++ /dev/null @@ -1,201 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/images/logos/Sarek/Sarek_dark_color.svg b/docs/images/logos/Sarek/Sarek_dark_color.svg deleted file mode 100644 index 914c3e7e51..0000000000 --- a/docs/images/logos/Sarek/Sarek_dark_color.svg +++ /dev/null @@ -1,393 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/images/logos/Sarek/Sarek_dark_grey.svg b/docs/images/logos/Sarek/Sarek_dark_grey.svg deleted file mode 100644 index c000ed4b87..0000000000 --- a/docs/images/logos/Sarek/Sarek_dark_grey.svg +++ /dev/null @@ -1,401 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/images/logos/Sarek/Sarek_dark_mono.svg b/docs/images/logos/Sarek/Sarek_dark_mono.svg deleted file mode 100644 index aab15bcd48..0000000000 --- a/docs/images/logos/Sarek/Sarek_dark_mono.svg +++ /dev/null @@ -1,193 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/images/logos/Sarek/Sarek_grey.svg b/docs/images/logos/Sarek/Sarek_grey.svg deleted file mode 100644 index e78e5db9be..0000000000 --- a/docs/images/logos/Sarek/Sarek_grey.svg +++ /dev/null @@ -1,409 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/images/logos/Sarek/Sarek_mono.svg b/docs/images/logos/Sarek/Sarek_mono.svg deleted file mode 100644 index 89d79dab16..0000000000 --- a/docs/images/logos/Sarek/Sarek_mono.svg +++ /dev/null @@ -1,390 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/images/logos/nf-core_sarek/nf-core_sarek_color.svg b/docs/images/logos/nf-core_sarek/nf-core_sarek_color.svg new file mode 100644 index 0000000000..1a11a859e4 --- /dev/null +++ b/docs/images/logos/nf-core_sarek/nf-core_sarek_color.svg @@ -0,0 +1,355 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/nf-core_sarek/nf-core_sarek_dark_color.svg b/docs/images/logos/nf-core_sarek/nf-core_sarek_dark_color.svg new file mode 100644 index 0000000000..7892026424 --- /dev/null +++ b/docs/images/logos/nf-core_sarek/nf-core_sarek_dark_color.svg @@ -0,0 +1,352 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/nf-core_sarek/nf-core_sarek_dark_grey.svg b/docs/images/logos/nf-core_sarek/nf-core_sarek_dark_grey.svg new file mode 100644 index 0000000000..f64eb12904 --- /dev/null +++ b/docs/images/logos/nf-core_sarek/nf-core_sarek_dark_grey.svg @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/nf-core_sarek/nf-core_sarek_dark_mono.svg b/docs/images/logos/nf-core_sarek/nf-core_sarek_dark_mono.svg new file mode 100644 index 0000000000..392bd8d5af --- /dev/null +++ b/docs/images/logos/nf-core_sarek/nf-core_sarek_dark_mono.svg @@ -0,0 +1,292 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/nf-core_sarek/nf-core_sarek_grey.svg b/docs/images/logos/nf-core_sarek/nf-core_sarek_grey.svg new file mode 100644 index 0000000000..4dfe2b1a91 --- /dev/null +++ b/docs/images/logos/nf-core_sarek/nf-core_sarek_grey.svg @@ -0,0 +1,364 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/nf-core_sarek/nf-core_sarek_mono.svg b/docs/images/logos/nf-core_sarek/nf-core_sarek_mono.svg new file mode 100644 index 0000000000..e93a485d59 --- /dev/null +++ b/docs/images/logos/nf-core_sarek/nf-core_sarek_mono.svg @@ -0,0 +1,348 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/sarek-germline/sarek-germline.svg b/docs/images/logos/sarek-germline/sarek-germline.svg new file mode 100644 index 0000000000..f02c125528 --- /dev/null +++ b/docs/images/logos/sarek-germline/sarek-germline.svg @@ -0,0 +1,315 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/sarek-somatic/sarek-somatic_logo.svg b/docs/images/logos/sarek-somatic/sarek-somatic_logo.svg new file mode 100644 index 0000000000..8f580298e8 --- /dev/null +++ b/docs/images/logos/sarek-somatic/sarek-somatic_logo.svg @@ -0,0 +1,308 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/sarek/sarek_color.svg b/docs/images/logos/sarek/sarek_color.svg new file mode 100644 index 0000000000..7a8ccdfe9b --- /dev/null +++ b/docs/images/logos/sarek/sarek_color.svg @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/sarek/sarek_dark_color.svg b/docs/images/logos/sarek/sarek_dark_color.svg new file mode 100644 index 0000000000..40f3b88e00 --- /dev/null +++ b/docs/images/logos/sarek/sarek_dark_color.svg @@ -0,0 +1,248 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/sarek/sarek_dark_grey.svg b/docs/images/logos/sarek/sarek_dark_grey.svg new file mode 100644 index 0000000000..a503af1444 --- /dev/null +++ b/docs/images/logos/sarek/sarek_dark_grey.svg @@ -0,0 +1,288 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/sarek/sarek_dark_mono.svg b/docs/images/logos/sarek/sarek_dark_mono.svg new file mode 100644 index 0000000000..d14308f6b2 --- /dev/null +++ b/docs/images/logos/sarek/sarek_dark_mono.svg @@ -0,0 +1,243 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/sarek/sarek_grey.svg b/docs/images/logos/sarek/sarek_grey.svg new file mode 100644 index 0000000000..68e2b116d2 --- /dev/null +++ b/docs/images/logos/sarek/sarek_grey.svg @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logos/sarek/sarek_mono.svg b/docs/images/logos/sarek/sarek_mono.svg new file mode 100644 index 0000000000..be66c6fe84 --- /dev/null +++ b/docs/images/logos/sarek/sarek_mono.svg @@ -0,0 +1,248 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/nf-core_sarek-germline_logo.svg b/docs/images/nf-core_sarek-germline_logo.svg new file mode 100644 index 0000000000..bf5fb0d09e --- /dev/null +++ b/docs/images/nf-core_sarek-germline_logo.svg @@ -0,0 +1,423 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/nf-core_sarek-somatic_logo.svg b/docs/images/nf-core_sarek-somatic_logo.svg new file mode 100644 index 0000000000..86a3b16715 --- /dev/null +++ b/docs/images/nf-core_sarek-somatic_logo.svg @@ -0,0 +1,416 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/nf-core_sarek_logo.png b/docs/images/nf-core_sarek_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..208d16951ec22c8a30b7e217de1257d8cd1d2cd6 GIT binary patch literal 14773 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 literal 0 HcmV?d00001 diff --git a/docs/images/nf-core_sarek_logo.svg b/docs/images/nf-core_sarek_logo.svg new file mode 100644 index 0000000000..5d2e490b59 --- /dev/null +++ b/docs/images/nf-core_sarek_logo.svg @@ -0,0 +1,355 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/sarek_icon.svg b/docs/images/sarek_icon.svg new file mode 100644 index 0000000000..4202555569 --- /dev/null +++ b/docs/images/sarek_icon.svg @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/docs/images/sarek_logo.svg b/docs/images/sarek_logo.svg new file mode 100644 index 0000000000..7a8ccdfe9b --- /dev/null +++ b/docs/images/sarek_logo.svg @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/social_preview_image.png b/docs/images/social_preview_image.png index d43d5d473b04f90a339c3b5d316b740d7e54fadd..ed11f7fab59693aa794b9dca58179ac036e85372 100644 GIT binary patch literal 51946 zcmeFY^qR(Fpz*iAaaEKb2ShMANUjEPecH`bR3Rm z0xx(j&k!0!z>hbPSt#&7v7@}M3kXEfiF<Z{Bv5)p1pKuyFNw<7^J{@bKWX zvbS+DedB1(=iqFavLnd=0^I>2oD&mzb)Vbh5u&u)%QwAy%Zh10!c6{!&T$ z{Vq2N_q2c0Gn!W#BSTKi%tA}`KbytLzTOKAttVu&g)V-q_a`N~2YwbJTnt7<)x_+G z@3N|9rA6g7ol73My7|DzH52lh2CildH29B-s{COH)c%|`^KdR^RNxXu>WrjS19iE<^=2}UQKg$mgYIocJ$Mh%`hA6Y}qR7 zzC;l)K%e|0wKO70`f9YI=)l0Z=kI8TdE4pqe7b^>Hj04af8Vf=NEX@Vjqb~}Jv&-` z7+NQ@j(EoO%#7?8!Pap0Vn7C^Zqv@}dShHpKriSeZq?ZE?Bg^M_D)a1ms5Xe12z@o z_TmJ8)6KY^ExX!1wAdKQeimlrknf5&faHvq_VqwsG*%lZ4x^XY?))SAPsFT4M)rfa zJ)tiR(;*pQu@-aQC$r*c2o$^#^!A-MAfGu7GhC^liYY1a%By2DDk+!usj!;aYK{zu^O6K9pUB|cE2 zn#l0mMw9WB$vW{#JB~4G(ws(TJ825JM`fYW?2s+i zDqTi)q(HS$d)AZs7@ad2?S{XHghueyGCY$xDMi$IN!SyKm!&3K*Jz^{_us}5$*qGD zkcDA;*4NjYO}mreuQx`3gTZJCQb1W-@7fHq{2rY=%cE)Lt-St1UnQFDl{6!ap9pax zVM~2g`h2Q1wMI|E<<{y@6|8`-Ib)-}E#uAUxFtt>zsQvVi+#_YD(ajZI0I_RN{z=` zvohMNArI2xJP6v2^EVJE8U{$J?()PT?eS3gU8dGaxm!1Xhrz5Aal&m#7TEp!?L)Gh z@27#%NSU|WNBVFCs&<#h*!AYpE$}$kPVNGeCnn%$vBB)vl_^_b&qqM`f1d$z&6%k- zkUHehNF=PVyEuu56>x(+9pX&+(dLCdBHptfd!wCQP9nQ>-Zg*qg(3JgxB-hZj2>}c z{#5spxD85%g(2Q~-L&;Ox1}rr@hML$m=QkbG zr%d{;{HPr8?hJR20SS-lgj@#+o65|ksd=L~$y-@e^-UZ}Ih=zT?;Zw(?|XcL-S@LY z+Z58%1(X4sc+*AS(~2>Tm7#8tN7eqIvqa^XO_e4Jv!R(TukIoWKcBps-A!fmN79}Q zmn*y>1si_?<{ODTg(#z9Rqh+&ZRxl&qH=--n8d33D(GNa*$Z9uLGxF+Vqg8WUj-`G%`^XeK^%4-p3ri28=W%H%r z&wB2^E2<=DJsu#)ab|49QoS@?Ft?~ZTK0quVNG8~a9m(ALxPbALsD1V?>EC{+Pt(H zⅆ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 literal 46389 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 E16S?Y^Z)<= diff --git a/docs/images/social_preview_image.svg b/docs/images/social_preview_image.svg index a8e74bd243..fd06c47252 100644 --- a/docs/images/social_preview_image.svg +++ b/docs/images/social_preview_image.svg @@ -7,7 +7,6 @@ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="1280" @@ -69,20 +68,6 @@ id="path26" d="M 0,266 H 1022 V 0 H 0 Z" /> - - @@ -155,6 +140,130 @@ id="path32" d="M 0,600 H 1500 V 0 H 0 Z" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - nf- - - - - - core - - - - - - - + An open-source analysis pipeline to detect germline orsomatic variants from whole genome or targeted sequencing diff --git a/docs/install_bianca.md b/docs/install_bianca.md index 667aa850a3..5bb8c176c8 100644 --- a/docs/install_bianca.md +++ b/docs/install_bianca.md @@ -149,13 +149,13 @@ So every member of the project who wants to use nf-core/sarek will need to do: And then nf-core/sarek can be used with: ```bash -> nextflow run ~/sarek/main.nf -c ~/sarek/configs/conf/uppmax.config --project [PROJECT] --genome [GENOME ASSEMBLY] ... +> nextflow run ~/sarek/main.nf -profile uppmax --custom_config_base ~/sarek/configs --project [PROJECT] --genome [GENOME ASSEMBLY] ... ``` This is an example of how to run sarek with the tool Manta and the genome assembly version GRCh38: ```bash -> nextflow run ~/sarek/main.nf -c ~/sarek/configs/conf/uppmax.config --project [PROJECT] --tools Manta --sample [SAMPLE.TSV] --genome GRCh38 +> nextflow run ~/sarek/main.nf -profile uppmax --custom_config_base ~/sarek/configs --project [PROJECT] --tools Manta --sample [SAMPLE.TSV] --genome GRCh38 ``` ## Update nf-core/sarek diff --git a/main.nf b/main.nf index 68854e5dfa..d5f95a61db 100644 --- a/main.nf +++ b/main.nf @@ -44,17 +44,24 @@ def helpMessage() { --genome Name of iGenomes reference --noGVCF No g.vcf output from HaplotypeCaller --noStrelkaBP Will not use Manta candidateSmallIndels for Strelka as Best Practice - --noReports Disable all QC reports --nucleotidesPerSecond To estimate interval size by default 1000.0 + --targetBED Target BED file for targeted or whole exome sequencing --step Specify starting step Available: Mapping, Recalibrate, VariantCalling, Annotate Default: Mapping - --targetBED Target BED file for targeted or whole exome sequencing - --tools Specify tools to use for variant calling + --tools Specify tools to use for variant calling, and annotation Available: ASCAT, ControlFREEC, FreeBayes, HaplotypeCaller - Manta, mpileup, MuTect2, Strelka - --annotateTools Specify from which tools Sarek will annotate VCF, only for step annotate + Manta, mpileup, MuTect2, Strelka, snpEff, VEP, merge + Default: None + --skip Specify which QC tools to skip when running Sarek + Available: bamQC, BCFtools, FastQC, MultiQC, samtools, vcftools, versions + Default: None + --annotateTools Specify from which tools Sarek will look for VCF files to annotate, only for step annotate Available: HaplotypeCaller, Manta, MuTect2, Strelka + Default: None + --annotation_cache Enable the use of cache for annotation, to be used with --snpEff_cache and/or --vep_cache + --snpEff_cache Specity the path to snpEff cache, to be used with --annotation_cache + --vep_cache Specity the path to VEP cache, to be used with --annotation_cache References If not specified in the configuration file or you wish to overwrite any of the references. --acLoci acLoci file @@ -74,6 +81,7 @@ def helpMessage() { Other options: --outdir The output directory where the results will be saved --sequencing_center Name of sequencing center to be displayed in BAM file + --multiqc_config Specify a custom config file for MultiQC --monochrome_logs Logs will be without colors --email 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 --maxMultiqcEmailFileSize Theshold size for MultiQC report to be attached in notification email. If file generated by pipeline exceeds the threshold, it will not be attached (Default: 25MB) @@ -100,20 +108,20 @@ if (params.genomes && params.genome && !params.genomes.containsKey(params.genome // Default value for params params.annotateTools = null params.annotation_cache = null -params.cadd_cache = null params.cadd_InDels = null params.cadd_InDels_tbi = null params.cadd_WG_SNVs = null params.cadd_WG_SNVs_tbi = null +params.cadd_cache = null params.genesplicer = null params.monochrome_logs = null params.multiqc_config = null params.noGVCF = null -params.noReports = null params.noStrelkaBP = null params.nucleotidesPerSecond = 1000.0 params.sample = null params.sequencing_center = null +params.skip = null params.snpEff_cache = null params.step = 'mapping' params.targetBED = null @@ -126,11 +134,18 @@ if (step == 'preprocessing') step = 'mapping' if (step.contains(',')) exit 1, 'You can choose only one step, see --help for more information' if (!checkParameterExistence(step, stepList)) exit 1, "Unknown step ${step}, see --help for more information" -tools = params.tools ? params.tools.split(',').collect{it.trim().toLowerCase()} : [] -annotateTools = params.annotateTools ? params.annotateTools.split(',').collect{it.trim().toLowerCase()} : [] toolList = defineToolList() +tools = params.tools ? params.tools.split(',').collect{it.trim().toLowerCase()} : [] if (!checkParameterList(tools,toolList)) exit 1, 'Unknown tool(s), see --help for more information' +skipList = defineSkipList() +skip = params.skip ? params.skip == 'all' ? skipList : params.skip.split(',').collect{it.trim().toLowerCase()} : [] +if (!checkParameterList(skip,skipList)) exit 1, 'Unknown QC tool(s), see --help for more information' + +annoList = defineAnnoList() +annotateTools = params.annotateTools ? params.annotateTools.split(',').collect{it.trim().toLowerCase()} : [] +if (!checkParameterList(annotateTools,annoList)) exit 1, 'Unknown tool(s) to annotate, see --help for more information' + referenceMap = defineReferenceMap(step, tools) if (!checkReferenceMap(referenceMap)) exit 1, 'Missing Reference file(s), see --help for more information' @@ -199,7 +214,7 @@ if (params.sample) summary['Sample'] = params.sample if (params.targetBED) summary['Target BED'] = params.targetBED if (params.step) summary['Step'] = params.step if (params.tools) summary['Tools'] = tools.join(', ') -if (params.noReports) summary['No Reports'] = params.noReports +if (params.skip) summary['QC tools skip'] = skip.join(', ') if (params.noGVCF) summary['No GVCF'] = params.noGVCF if (params.noStrelkaBP) summary['No Strelka BP'] = params.noStrelkaBP if (params.sequencing_center) summary['Sequenced by '] = params.sequencing_center @@ -237,14 +252,14 @@ process GetSoftwareVersions { output: file 'software_versions_mqc.yaml' into yamlSoftwareVersion - when: !params.noReports + when: !('versions' in skip) script: """ alleleCounter --version &> v_allelecount.txt || true bcftools version > v_bcftools.txt 2>&1 || true bwa &> v_bwa.txt 2>&1 || true - cat ${baseDir}/bin/ascat.R | grep "ASCAT version" &> v_ascat.txt || true + cat ${baseDir}/scripts/ascat.R | grep "ASCAT version" &> v_ascat.txt || true configManta.py --version > v_manta.txt 2>&1 || true configureStrelkaGermlineWorkflow.py --version > v_strelka.txt 2>&1 || true echo "${workflow.manifest.version}" &> v_pipeline.txt 2>&1 || true @@ -362,6 +377,8 @@ inputReads = inputReads.dump(tag:'INPUT') // FASTQ and uBAM files are renamed based on the sample name process FastQCFQ { + label 'cpus_2' + tag {idPatient + "-" + idRun} publishDir "${params.outdir}/Reports/${idSample}/FastQC/${idRun}", mode: params.publishDirMode @@ -372,7 +389,8 @@ process FastQCFQ { output: file "*_fastqc.{zip,html}" into fastQCFQReport - when: step == 'mapping' && !params.noReports + when: step == 'mapping' && !('fastqc' in skip) + script: """ @@ -381,6 +399,8 @@ process FastQCFQ { } process FastQCBAM { + label 'cpus_2' + tag {idPatient + "-" + idRun} publishDir "${params.outdir}/Reports/${idSample}/FastQC/${idRun}", mode: params.publishDirMode @@ -391,7 +411,7 @@ process FastQCBAM { output: file "*_fastqc.{zip,html}" into fastQCBAMReport - when: step == 'mapping' && !params.noReports + when: step == 'mapping' && !('fastqc' in skip) script: """ @@ -406,7 +426,7 @@ fastQCReport = fastQCReport.dump(tag:'FastQC') // STEP 1: MAPPING READS TO REFERENCE GENOME WITH BWA MEM process MapReads { - label 'max_cpus' + label 'cpus_max' tag {idPatient + "-" + idRun} @@ -470,7 +490,7 @@ singleBam = singleBam.dump(tag:'Single BAM') // STEP 1.5: MERGING BAM FROM MULTIPLE LANES process MergeBamMapped { - label 'singleCPUmem_x_task' + label 'cpus_8' tag {idPatient + "-" + idSample} @@ -495,13 +515,13 @@ mergedBam = mergedBam.dump(tag:'BAMs for MD') // STEP 2: MARKING DUPLICATES process MarkDuplicates { - label 'singleCPUmem_x_task' + label 'cpus_16' tag {idPatient + "-" + idSample} publishDir params.outdir, mode: params.publishDirMode, saveAs: { - if (it == "${idSample}.bam.metrics") "Reports/${idSample}/MarkDuplicates/${it}" + if (it == "${idSample}.bam.metrics" && 'markduplicates' in skip) "Reports/${idSample}/MarkDuplicates/${it}" else "Preprocessing/${idSample}/DuplicateMarked/${it}" } @@ -529,6 +549,8 @@ process MarkDuplicates { """ } +if ('markduplicates' in skip) markDuplicatesReport.close() + duplicateMarkedBams = duplicateMarkedBams.dump(tag:'MD BAM') markDuplicatesReport = markDuplicatesReport.dump(tag:'MD Report') @@ -538,7 +560,8 @@ bamBaseRecalibrator = bamMD.combine(intBaseRecalibrator) // STEP 3: CREATING RECALIBRATION TABLES process BaseRecalibrator { - label 'max_memory' + label 'memory_max' + label 'cpus_1' tag {idPatient + "-" + idSample + "-" + intervalBed} @@ -581,7 +604,8 @@ tableGatherBQSRReports = tableGatherBQSRReports.groupTuple(by:[0,1]) // STEP 3.5: MERGING RECALIBRATION TABLES process GatherBQSRReports { - label 'singleCPUmem_2x_task' + label 'memory_singleCPU_2_task' + label 'cpus_2' tag {idPatient + "-" + idSample} @@ -634,7 +658,8 @@ bamApplyBQSR = bamApplyBQSR.combine(intApplyBQSR) // STEP 4: RECALIBRATING process ApplyBQSR { - label 'singleCPUmem_2x_task' + label 'memory_singleCPU_2_task' + label 'cpus_2' tag {idPatient + "-" + idSample + "-" + intervalBed.baseName} @@ -666,7 +691,7 @@ bamMergeBamRecal = bamMergeBamRecal.groupTuple(by:[0,1]) // STEP 4.5: MERGING THE RECALIBRATED BAM FILES process MergeBamRecal { - label 'singleCPUmem_x_task' + label 'cpus_8' tag {idPatient + "-" + idSample} @@ -708,6 +733,8 @@ bamRecalSampleTSV // STEP 5: QC process SamtoolsStats { + label 'cpus_2' + tag {idPatient + "-" + idSample} publishDir "${params.outdir}/Reports/${idSample}/SamToolsStats", mode: params.publishDirMode @@ -718,7 +745,7 @@ process SamtoolsStats { output: file ("${bam}.samtools.stats.out") into samtoolsStatsReport - when: !params.noReports + when: !('samtools' in skip) script: """ @@ -733,7 +760,8 @@ samtoolsStatsReport = samtoolsStatsReport.dump(tag:'SAMTools') bamBamQC = bamMappedBamQC.mix(bamRecalBamQC) process BamQC { - label 'max_memory' + label 'memory_max' + label 'cpus_16' tag {idPatient + "-" + idSample} @@ -746,7 +774,7 @@ process BamQC { output: file("${bam.baseName}") into bamQCReport - when: !params.noReports + when: !('bamqc' in skip) script: use_bed = params.targetBED ? "-gff ${targetBED}" : '' @@ -792,7 +820,8 @@ bamHaplotypeCaller = bamRecalAllTemp.combine(intHaplotypeCaller) // STEP GATK HAPLOTYPECALLER.1 process HaplotypeCaller { - label 'singleCPUmem_x2_task' + label 'memory_singleCPU_task_sq' + label 'cpus_2' tag {idSample + "-" + intervalBed.baseName} @@ -871,8 +900,8 @@ vcfGenotypeGVCFs = vcfGenotypeGVCFs.groupTuple(by:[0,1,2]) // STEP STRELKA.1 - SINGLE MODE process StrelkaSingle { - label 'max_cpus' - label 'max_memory' + label 'cpus_max' + label 'memory_max' tag {idSample} @@ -920,8 +949,8 @@ vcfStrelkaSingle = vcfStrelkaSingle.dump(tag:'Strelka - Single Mode') // STEP MANTA.1 - SINGLE MODE process MantaSingle { - label 'max_cpus' - label 'max_memory' + label 'cpus_max' + label 'memory_max' tag {idSample} @@ -1013,8 +1042,6 @@ bamMpileup = bamMpileup.spread(intMpileup) // STEP GATK MUTECT2 process Mutect2 { - label 'singleCPUmem_x_task' - tag {idSampleTumor + "_vs_" + idSampleNormal + "-" + intervalBed.baseName} input: @@ -1049,8 +1076,6 @@ vcfMuTect2 = vcfMuTect2.groupTuple(by:[0,1,2]) // STEP FREEBAYES process FreeBayes { - label 'singleCPUmem_x_task' - tag {idSampleTumor + "_vs_" + idSampleNormal + "-" + intervalBed.baseName} input: @@ -1093,6 +1118,8 @@ vcfConcatenateVCFs = vcfMuTect2.mix(vcfFreeBayes, vcfGenotypeGVCFs, gvcfHaplotyp vcfConcatenateVCFs = vcfConcatenateVCFs.dump(tag:'VCF to merge') process ConcatVCF { + label 'cpus_8' + tag {variantCaller + "-" + idSample} publishDir "${params.outdir}/VariantCalling/${idSample}/${"$variantCaller"}", mode: params.publishDirMode @@ -1122,8 +1149,8 @@ vcfConcatenated = vcfConcatenated.dump(tag:'VCF') // STEP STRELKA.2 - SOMATIC PAIR process Strelka { - label 'max_cpus' - label 'max_memory' + label 'cpus_max' + label 'memory_max' tag {idSampleTumor + "_vs_" + idSampleNormal} @@ -1173,8 +1200,8 @@ vcfStrelka = vcfStrelka.dump(tag:'Strelka') // STEP MANTA.2 - SOMATIC PAIR process Manta { - label 'max_cpus' - label 'max_memory' + label 'cpus_max' + label 'memory_max' tag {idSampleTumor + "_vs_" + idSampleNormal} @@ -1241,8 +1268,8 @@ pairBamStrelkaBP = pairBamStrelkaBP.map { // STEP STRELKA.3 - SOMATIC PAIR - BEST PRACTICES process StrelkaBP { - label 'max_cpus' - label 'max_memory' + label 'cpus_max' + label 'memory_max' tag {idSampleTumor + "_vs_" + idSampleNormal} @@ -1295,7 +1322,7 @@ vcfStrelkaBP = vcfStrelkaBP.dump(tag:'Strelka BP') // Run commands and code from Malin Larsson // Based on Jesper Eisfeldt's code process AlleleCounter { - label 'singleCPUmem_2x_task' + label 'memory_singleCPU_2_task' tag {idSample} @@ -1342,7 +1369,7 @@ alleleCounterOut = alleleCounterOut.map { // R script from Malin Larssons bitbucket repo: // https://bitbucket.org/malinlarsson/somatic_wgs_pipeline process ConvertAlleleCounts { - label 'singleCPUmem_2x_task' + label 'memory_singleCPU_2_task' tag {idSampleTumor + "_vs_" + idSampleNormal} @@ -1368,7 +1395,7 @@ process ConvertAlleleCounts { // R scripts from Malin Larssons bitbucket repo: // https://bitbucket.org/malinlarsson/somatic_wgs_pipeline process Ascat { - label 'singleCPUmem_2x_task' + label 'memory_singleCPU_2_task' tag {idSampleTumor + "_vs_" + idSampleNormal} @@ -1396,7 +1423,7 @@ ascatOut.dump(tag:'ASCAT') // STEP CONTROLFREEC.1 - MPILEUP process Mpileup { - label 'singleCPUmem_2x_task' + label 'memory_singleCPU_2_task' tag {idSample + "-" + intervalBed.baseName} @@ -1426,8 +1453,6 @@ mpileupMerge = mpileupMerge.groupTuple(by:[0,1]) // STEP CONTROLFREEC.2 - MERGE MPILEUP process MergeMpileup { - label 'singleCPUmem_x_task' - tag {idSample} publishDir params.outdir, mode: params.publishDirMode, saveAs: { it == "${idSample}.pileup.gz" ? "VariantCalling/${idSample}/mpileup/${it}" : '' } @@ -1471,7 +1496,7 @@ mpileupOut = mpileupOut.map { // STEP CONTROLFREEC.3 - CONTROLFREEC process ControlFREEC { - label 'singleCPUmem_2x_task' + label 'memory_singleCPU_2_task' tag {idSampleTumor + "_vs_" + idSampleNormal} @@ -1537,7 +1562,7 @@ controlFreecOut.dump(tag:'ControlFREEC') // STEP CONTROLFREEC.3 - VISUALIZATION process ControlFreecViz { - label 'singleCPUmem_2x_task' + label 'memory_singleCPU_2_task' tag {idSampleTumor + "_vs_" + idSampleNormal} @@ -1612,6 +1637,8 @@ vcfKeep = Channel.empty().mix( // STEP VCF.QC process BcftoolsStats { + label 'cpus_1' + tag {"${variantCaller} - ${vcf}"} publishDir "${params.outdir}/Reports/${idSample}/BCFToolsStats", mode: params.publishDirMode @@ -1622,7 +1649,7 @@ process BcftoolsStats { output: file ("*.bcf.tools.stats.out") into bcftoolsReport - when: !params.noReports + when: !('bcftools' in skip) script: """ @@ -1633,6 +1660,8 @@ process BcftoolsStats { bcftoolsReport = bcftoolsReport.dump(tag:'BCFTools') process Vcftools { + label 'cpus_1' + tag {"${variantCaller} - ${vcf}"} publishDir "${params.outdir}/Reports/${idSample}/VCFTools", mode: params.publishDirMode @@ -1643,7 +1672,7 @@ process Vcftools { output: file ("${reduceVCF(vcf.fileName)}.*") into vcftoolsReport - when: !params.noReports + when: !('vcftools' in skip) script: """ @@ -1718,8 +1747,6 @@ vcfVep = vcfVep.map { // STEP SNPEFF process Snpeff { - label 'singleCPUmem_x_task' - tag {"${idSample} - ${variantCaller} - ${vcf}"} publishDir params.outdir, mode: params.publishDirMode, saveAs: { @@ -1785,6 +1812,7 @@ compressVCFsnpEffOut = compressVCFsnpEffOut.dump(tag:'VCF') process VEP { label 'VEP' + label 'cpus_4' tag {"${idSample} - ${variantCaller} - ${vcf}"} @@ -1847,6 +1875,7 @@ vepReport = vepReport.dump(tag:'VEP') process VEPmerge { label 'VEP' + label 'cpus_4' tag {"${idSample} - ${variantCaller} - ${vcf}"} @@ -1954,14 +1983,14 @@ process MultiQC { publishDir "${params.outdir}/Reports/MultiQC", mode: params.publishDirMode input: - file (multiqcConfig) from Channel.value(params.multiqc_config ? file(params.multiqc_config) : createMultiQCconfig()) + file (multiqcConfig) from Channel.value(params.multiqc_config ? file(params.multiqc_config) : "") file (reports) from multiQCReport file (versions) from yamlSoftwareVersion output: set file("*multiqc_report.html"), file("*multiqc_data") into multiQCOut - when: !params.noReports + when: !('multiqc' in skip) script: """ @@ -2063,9 +2092,9 @@ workflow.onComplete { c_purple = params.monochrome_logs ? '' : "\033[0;35m"; if (workflow.stats.ignoredCountFmt > 0 && workflow.success) { - log.info "${c_purple}Warning, pipeline completed, but with errored process(es) ${c_reset}" - log.info "${c_red}Number of ignored errored process(es) : ${workflow.stats.ignoredCountFmt} ${c_reset}" - log.info "${c_green}Number of successfully ran process(es) : ${workflow.stats.succeedCountFmt} ${c_reset}" + log.info "${c_purple}Warning, pipeline completed, but with errored process(es)${c_reset}" + log.info "${c_red}Number of ignored errored process(es) : ${workflow.stats.ignoredCountFmt}${c_reset}" + log.info "${c_green}Number of successfully ran process(es) : ${workflow.stats.succeedCountFmt}${c_reset}" } if (workflow.success) log.info "${c_purple}[nf-core/sarek]${c_green} Pipeline completed successfully${c_reset}" @@ -2117,12 +2146,12 @@ def nfcoreHeader() { ${c_blue} |\\ | |__ __ / ` / \\ |__) |__ ${c_yellow}} {${c_reset} ${c_blue} | \\| | \\__, \\__/ | \\ |___ ${c_green}\\`-._,-`-,${c_reset} ${c_green}`._,._,\'${c_reset} - ${c_white} ____ ${c_blue} _____ _ ${c_reset} - ${c_white} .' _ `. ${c_blue} / ____| | | ${c_reset} - ${c_white} / ${c_green}|\\${c_white}`-_${c_white} \\ ${c_blue} | (___ ___ _ __ __ | | __ ${c_reset} - ${c_white} | ${c_green}| \\ ${c_white}`-${c_white}| ${c_blue} \\___ \\/__ \\| ´__/ _\\| |/ / ${c_reset} - ${c_white} \\ ${c_green}| \\ ${c_white}/ ${c_blue} ____) | __ | | | __| < ${c_reset} - ${c_white} `${c_green}|${c_white}____${c_green}\\${c_white}' ${c_blue} |_____/\\____|_| \\__/|_|\\_\\ ${c_reset} + ${c_white}____${c_reset} + ${c_white}.´ _ `.${c_reset} + ${c_white}/ ${c_green}|\\${c_reset}`-_ \\${c_reset} ${c_blue} __ __ ___ ${c_reset} + ${c_white}| ${c_green}| \\${c_reset} `-|${c_reset} ${c_blue}|__` /\\ |__) |__ |__/${c_reset} + ${c_white}\\ ${c_green}| \\${c_reset} /${c_reset} ${c_blue}.__| /¯¯\\ | \\ |___ | \\${c_reset} + ${c_white}`${c_green}|${c_reset}____${c_green}\\${c_reset}´${c_reset} ${c_purple} nf-core/sarek v${workflow.manifest.version}${c_reset} ${c_dim}----------------------------------------------------${c_reset} @@ -2203,28 +2232,6 @@ def checkReferenceMap(referenceMap) { } } -// Personnalise the MultiQC report -def createMultiQCconfig() { - def file = workDir.resolve('multiqc_config.yaml') - file.text = """ - custom_logo: ${baseDir}/docs/images/nf-core_logo.png - custom_logo_url: https://github.com/nf-core/sarek/ - custom_logo_title: 'nf-core/sarek' - report_header_info: - - top_modules: - - 'fastqc' - - 'picard' - - 'samtools' - - 'qualimap' - - 'bcftools' - - 'vcftools' - - 'snpeff' - """.stripIndent() - - return file -} - // Define map of reference depending of tools and step def defineReferenceMap(step, tools) { def referenceMap = [ @@ -2262,6 +2269,30 @@ def defineReferenceMap(step, tools) { return referenceMap } +// Define list of available tools to annotate +def defineAnnoList() { + return [ + 'HaplotypeCaller', + 'Manta', + 'MuTect2', + 'Strelka' + ] +} + +// Define list of skipable QC tools +def defineSkipList() { + return [ + 'bamqc', + 'bcftools', + 'fastqc', + 'markduplicates', + 'multiqc', + 'samtools', + 'vcftools', + 'versions' + ] +} + // Define list of available step def defineStepList() { return [ diff --git a/nextflow.config b/nextflow.config index d5689a380f..6923a077a3 100644 --- a/nextflow.config +++ b/nextflow.config @@ -15,7 +15,7 @@ params { // Boilerplate options name = false - multiqc_config = "$baseDir/assets/multiqc_config.yaml" + multiqc_config = "${baseDir}/assets/multiqc_config.yaml" email = false maxMultiqcEmailFileSize = 25.MB plaintext_email = false @@ -106,9 +106,8 @@ manifest { version = '2.5dev' } -// Function to ensure that resource requirements don't go beyond -// a maximum limit -def check_max(obj) { +// Return the minimum between requirements and a maximum limit to ensure that resource requirements don't go over +def check_resource(obj) { try { if (obj.getClass() == nextflow.util.MemoryUnit && obj.compareTo(params.max_memory as nextflow.util.MemoryUnit) == 1) return params.max_memory as nextflow.util.MemoryUnit @@ -119,6 +118,6 @@ def check_max(obj) { else return obj } catch (all) { - println " ### ERROR ### Max params '${params.max_memory}', '${params.max_time}' or '${params.max_cpus}' is not valid! Using default value: $obj" + println " ### ERROR ### Max params max_memory:'${params.max_memory}', max_time:'${params.max_time}' or max_cpus:'${params.max_cpus}' is not valid! Using default value: $obj" } } diff --git a/scripts/build_reference.sh b/scripts/build_reference.sh index 99c9f422f2..2e34a04d0d 100755 --- a/scripts/build_reference.sh +++ b/scripts/build_reference.sh @@ -44,8 +44,8 @@ do done # Build references for smallGRCh37 -if [[ $TEST != ANNOTATESNPEFF ]] && [[ $TEST != ANNOTATEVEP ]] -then +if ! [[ ANNOTATESNPEFF,ANNOTATEVEP =~ $TEST ]] + then rm -rf references nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile test,${PROFILE} --build --outdir references ${VERBOSE} ${OFFLINE} rm -rf .nextflow* references/pipeline_info work diff --git a/scripts/download_image.sh b/scripts/download_image.sh index dd581a8022..862f265033 100755 --- a/scripts/download_image.sh +++ b/scripts/download_image.sh @@ -3,22 +3,34 @@ set -xeuo pipefail # This script download and tag image for sarek tests -usage() { echo "Usage: $0 <-t test> <-n engine>" 1>&2; exit 1; } +usage() { echo "Usage: $0 <-t test|annotation tool> <-n engine> <-T version to pull/build> <-g genome>" 1>&2; exit 1; } ENGINE=docker +GENOME=smallGRCh37 NXF_SINGULARITY_CACHEDIR=${NXF_SINGULARITY_CACHEDIR:-work/singularity/.} TEST=ALL +VERSION=dev while [[ $# -gt 0 ]] do key=$1 case $key in + -g|--genome) + GENOME=$2 + shift # past argument + shift # past value + ;; -n|--engine) ENGINE=$2 shift # past argument shift # past value ;; - -t|--test) + -T|--tagged-version) + VERSION=$2 + shift # past argument + shift # past value + ;; + -t|--test|--tool) TEST=$2 shift # past argument shift # past value @@ -30,44 +42,39 @@ do esac done -if [[ ALL,ANNOTATEALL,ANNOTATESNPEFF =~ $TEST ]] +SOURCEGENOME=${GENOME} + +if [[ smallGRCh37 =~ $SOURCEGENOME ]] then + SOURCEGENOME=GRCh37 +fi + +get_image(){ + CONTAINER=$1 + SOURCE=$2 + TARGET=$3 if [[ docker =~ $ENGINE ]] then - docker pull nfcore/sareksnpeff:dev.GRCh37 - docker tag nfcore/sareksnpeff:dev.GRCh37 nfcore/sareksnpeff:dev.smallGRCh37 - elif [[ singularity =~ $ENGINE ]] + docker pull nfcore/${1}:${2} + docker tag nfcore/${1}:${2} nfcore/${1}:${3} + elif [[ singularity =~ $ENGINE ]] then - mkdir -p work/singularity - singularity build nfcore-sareksnpeff-dev.GRCh37.img docker://nfcore/sareksnpeff:dev.GRCh37 - mv nfcore-sareksnpeff-dev.GRCh37.img ${NXF_SINGULARITY_CACHEDIR}/. + mkdir -p ${NXF_SINGULARITY_CACHEDIR} + singularity build ${NXF_SINGULARITY_CACHEDIR}/nfcore-${1}-${3}.img docker://nfcore/${1}:${2} fi +} + +if [[ ALL,ANNOTATEBOTH,ANNOTATESNPEFF,SNPEFF =~ $TEST ]] +then + get_image sareksnpeff ${VERSION}.${SOURCEGENOME} ${VERSION}.${GENOME} fi -if [[ ALL,ANNOTATEALL,ANNOTATEVEP =~ $TEST ]] +if [[ ALL,ANNOTATEBOTH,ANNOTATEVEP,VEP =~ $TEST ]] then - if [[ docker =~ $ENGINE ]] - then - docker pull nfcore/sarekvep:dev.GRCh37 - docker tag nfcore/sarekvep:dev.GRCh37 nfcore/sarekvep:dev.smallGRCh37 - elif [[ singularity =~ $ENGINE ]] - then - mkdir -p work/singularity - singularity build nfcore-sarekvep-dev.GRCh37.img docker://nfcore/sarekvep:dev.GRCh37 - mv nfcore-sarekvep-dev.GRCh37.img ${NXF_SINGULARITY_CACHEDIR}/. - fi + get_image sarekvep ${VERSION}.${SOURCEGENOME} ${VERSION}.${GENOME} fi -if [[ ANNOTATEALL,ANNOTATEVEP,ANNOTATESNPEFF != $TEST ]] +if ! [[ ANNOTATEBOTH,ANNOTATESNPEFF,ANNOTATEVEP,SNPEFF,VEP =~ $TEST ]] then - if [[ docker =~ $ENGINE ]] - then - docker pull nfcore/sarek:dev - docker tag nfcore/sarek:dev nfcore/sarek:dev - elif [[ singularity =~ $ENGINE ]] - then - mkdir -p work/singularity - singularity build nfcore-sarek-dev.img docker://nfcore/sarek:dev - mv nfcore-sarek-dev.img ${NXF_SINGULARITY_CACHEDIR}/. - fi + get_image sarek ${VERSION} ${VERSION} fi diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index 2e04744bfd..43661935ed 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -8,12 +8,13 @@ usage() { echo "Usage: $0 <-p profile> <-t test> <-c cpus> <-n> <-v>" 1>&2; exit CPUS=2 LOGS='' +REPORTS='' NXF_SINGULARITY_CACHEDIR=${NXF_SINGULARITY_CACHEDIR:-work/singularity/.} OFFLINE=false PROFILE=docker TEST=ALL -TRAVIS_BUILD_DIR=${TRAVIS_BUILD_DIR:-.} TRAVIS=${TRAVIS:-false} +TRAVIS_BUILD_DIR=${TRAVIS_BUILD_DIR:-.} VERBOSE='' while [[ $# -gt 0 ]] @@ -28,6 +29,10 @@ do LOGS=true shift # past value ;; + --no-reports) + REPORTS="--skip all" + shift # past value + ;; --offline) OFFLINE=true shift # past value @@ -61,7 +66,7 @@ function manage_logs() { } function run_sarek() { - nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile test,${PROFILE} ${VERBOSE} --monochrome_logs $@ + nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile test,${PROFILE} ${VERBOSE} --monochrome_logs ${REPORTS} $@ } if [[ ALL,GERMLINE =~ $TEST ]] @@ -71,9 +76,9 @@ then rm -rf data git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data fi - run_sarek --tools=false --sample data/testdata/tiny/normal --noReports - run_sarek --tools=false --sample results/Preprocessing/TSV/duplicateMarked.tsv --step recalibrate --noReports - run_sarek --tools HaplotypeCaller --sample results/Preprocessing/TSV/recalibrated.tsv --step variantCalling --noReports + run_sarek --tools=false --sample data/testdata/tiny/normal + run_sarek --tools=false --sample results/Preprocessing/TSV/duplicateMarked.tsv --step recalibrate + run_sarek --tools HaplotypeCaller --sample results/Preprocessing/TSV/recalibrated.tsv --step variantCalling if [[ $OFFLINE == false ]] then rm -rf data @@ -83,22 +88,24 @@ fi if [[ ALL,SOMATIC =~ $TEST ]] then + OPTIONS="--tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2" if [[ $OFFLINE == false ]] then - run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports + run_sarek ${OPTIONS} else - run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports --sample data/testdata/tsv/tiny-manta.tsv + run_sarek ${OPTIONS} --sample data/testdata/tsv/tiny-manta.tsv fi manage_logs fi if [[ ALL,TARGETED =~ $TEST ]] then + OPTIONS="--tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2" if [[ $OFFLINE == false ]] then - run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports --targetBED https://github.com/nf-core/test-datasets/raw/sarek/testdata/target.bed + run_sarek ${OPTIONS} --targetBED https://github.com/nf-core/test-datasets/raw/sarek/testdata/target.bed else - run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports --sample data/testdata/tsv/tiny-manta.tsv --targetBED data/testdata/target.bed + run_sarek ${OPTIONS} --sample data/testdata/tsv/tiny-manta.tsv --targetBED data/testdata/target.bed fi manage_logs fi @@ -110,7 +117,7 @@ else pathToSample="data/testdata" fi -if [[ ALL,ANNOTATEALL,ANNOTATESNPEFF,ANNOTATEVEP =~ $TEST ]] +if [[ ALL,ANNOTATEBOTH,ANNOTATESNPEFF,ANNOTATEVEP =~ $TEST ]] then if [[ $TEST = ANNOTATESNPEFF ]] then @@ -118,21 +125,22 @@ then elif [[ $TEST = ANNOTATEVEP ]] then ANNOTATOR=VEP - elif [[ ALL,ANNOTATEALL =~ $TEST ]] + elif [[ ALL,ANNOTATEBOTH =~ $TEST ]] then ANNOTATOR=merge,snpEFF,VEP fi - run_sarek --step annotate --tools ${ANNOTATOR} --sample ${pathToSample}/vcf/Strelka_1234N_variants.vcf.gz --noReports + run_sarek --step annotate --tools ${ANNOTATOR} --sample ${pathToSample}/vcf/Strelka_1234N_variants.vcf.gz manage_logs fi if [[ MULTIPLE =~ $TEST ]] then + OPTIONS="--tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2,snpEff,VEP,merge" if [[ $OFFLINE == false ]] then - run_sarek --sample https://github.com/nf-core/test-datasets/raw/sarek/testdata/tsv/tiny-multiple-https.tsv --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports + run_sarek ${OPTIONS} --sample https://github.com/nf-core/test-datasets/raw/sarek/testdata/tsv/tiny-multiple-https.tsv else - run_sarek --sample data/testdata/tsv/tiny-multiple.tsv --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports + run_sarek ${OPTIONS} --sample data/testdata/tsv/tiny-multiple.tsv fi manage_logs fi From c9088ffed8377bb55db95609c265f6d3e2ef1f1b Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Tue, 23 Jul 2019 16:15:45 +0200 Subject: [PATCH 024/854] More fixes (#20) * fix: fix logo * fix: Fix path to reference genomes * feat: add markdownlint config file * fix: lint all md files + small typos corrected * feat: update CHANGELOG --- .markdownlint.json | 4 + CHANGELOG.md | 583 ++++++++++++++++++++++--------------------- README.md | 20 +- conf/igenomes.config | 44 ++-- docs/annotation.md | 17 +- docs/ascat.md | 91 +++++-- docs/containers.md | 9 +- docs/input.md | 55 ++-- docs/output.md | 30 +++ docs/reference.md | 3 +- docs/usage.md | 140 ++++++++--- docs/use_cases.md | 11 +- 12 files changed, 594 insertions(+), 413 deletions(-) create mode 100644 .markdownlint.json diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000000..7ca973f0c2 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,4 @@ +{ + "MD013": false, + "MD024": { "siblings_only": true } +} diff --git a/CHANGELOG.md b/CHANGELOG.md index ac96e27021..910f48ef5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,446 +11,449 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) ### `Added` -- [#2](https://github.com/nf-core/sarek/pull/2) - Create `nf-core/sarek` `environment.yml` file -- [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#7](https://github.com/nf-core/sarek/pull/7), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Add CI for `nf-core/sarek` -- [#3](https://github.com/nf-core/sarek/pull/3) - Add preprocessing to `nf-core/sarek` -- [#4](https://github.com/nf-core/sarek/pull/4) - Add variant calling to `nf-core/sarek` with `HaplotypeCaller`, and single mode `Manta` and `Strelka` -- [#5](https://github.com/nf-core/sarek/pull/5) - Add variant calling to `nf-core/sarek` with `Manta`, `Strelka`, `Strelka Best Practices`, `MuTecT2`, `FreeBayes`, `ASCAT`, `ControlFREEC` -- [#6](https://github.com/nf-core/sarek/pull/6) - Add default containers for annotation to `nf-core/sarek` -- [#7](https://github.com/nf-core/sarek/pull/7) - Add annotation -- [#7](https://github.com/nf-core/sarek/pull/7) - Add MultiQC -- [#7](https://github.com/nf-core/sarek/pull/7) - Add social preview image in `png` and `svg` format -- [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#11](https://github.com/nf-core/sarek/pull/11) - Add helper script `run_tests.sh` to run different tests -- [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9) - Add automatic build of specific containers for annotation for `GRCh37`, `GRCh38` and `GRCm38` using `CircleCI` -- [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11) - Add helper script `build_reference.sh` to build small reference from [nf-core/test-datasets:sarek](https://github.com/nf-core/test-datasets/tree/sarek) -- [#7](https://github.com/nf-core/sarek/pull/7), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Add helper script `download_image.sh` to download containers for testing -- [#8](https://github.com/nf-core/sarek/pull/8) - Add test configation for easier testing -- [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11) - Add scripts for `ASCAT` -- [#11](https://github.com/nf-core/sarek/pull/11) - Add automatic build of specific containers for annotation for `CanFam3.1` using `CircleCI` -- [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Add posters and abstracts -- [#12](https://github.com/nf-core/sarek/pull/12) - Use `label` for processes configation -- [#12](https://github.com/nf-core/sarek/pull/12) - Add helper scripts `filter_locifile.py` and `selectROI.py` -- [#12](https://github.com/nf-core/sarek/pull/12) - Add helper script `make_snapshot.sh` to make an archive for usage on a secure cluster -- [#13](https://github.com/nf-core/sarek/pull/13) - Add Citation documentation -- [#13](https://github.com/nf-core/sarek/pull/13) - Add `BamQC` process -- [#13](https://github.com/nf-core/sarek/pull/13) - Add `CompressVCFsnpEff` and `CompressVCFvep` processes -- [#18](https://github.com/nf-core/sarek/pull/18) - Add --no-reports option for tests + add snpEff,VEP,merge to MULTIPLE test -- [#18](https://github.com/nf-core/sarek/pull/18) - Add possibility to download other genome for sareksnpeff and sarekvep containers -- [#18](https://github.com/nf-core/sarek/pull/18) - Add params `--skip` to skip specified QC tools -- [#18](https://github.com/nf-core/sarek/pull/18) - Add logo to MultiQC report +- [#2](https://github.com/nf-core/sarek/pull/2) - Create `nf-core/sarek` `environment.yml` file +- [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#7](https://github.com/nf-core/sarek/pull/7), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Add CI for `nf-core/sarek` +- [#3](https://github.com/nf-core/sarek/pull/3) - Add preprocessing to `nf-core/sarek` +- [#4](https://github.com/nf-core/sarek/pull/4) - Add variant calling to `nf-core/sarek` with `HaplotypeCaller`, and single mode `Manta` and `Strelka` +- [#5](https://github.com/nf-core/sarek/pull/5) - Add variant calling to `nf-core/sarek` with `Manta`, `Strelka`, `Strelka Best Practices`, `MuTecT2`, `FreeBayes`, `ASCAT`, `ControlFREEC` +- [#6](https://github.com/nf-core/sarek/pull/6) - Add default containers for annotation to `nf-core/sarek` +- [#7](https://github.com/nf-core/sarek/pull/7) - Add annotation +- [#7](https://github.com/nf-core/sarek/pull/7) - Add MultiQC +- [#7](https://github.com/nf-core/sarek/pull/7) - Add social preview image in `png` and `svg` format +- [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#11](https://github.com/nf-core/sarek/pull/11) - Add helper script `run_tests.sh` to run different tests +- [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9) - Add automatic build of specific containers for annotation for `GRCh37`, `GRCh38` and `GRCm38` using `CircleCI` +- [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11) - Add helper script `build_reference.sh` to build small reference from [nf-core/test-datasets:sarek](https://github.com/nf-core/test-datasets/tree/sarek) +- [#7](https://github.com/nf-core/sarek/pull/7), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Add helper script `download_image.sh` to download containers for testing +- [#8](https://github.com/nf-core/sarek/pull/8) - Add test configation for easier testing +- [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11) - Add scripts for `ASCAT` +- [#11](https://github.com/nf-core/sarek/pull/11) - Add automatic build of specific containers for annotation for `CanFam3.1` using `CircleCI` +- [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Add posters and abstracts +- [#12](https://github.com/nf-core/sarek/pull/12) - Use `label` for processes configation +- [#12](https://github.com/nf-core/sarek/pull/12) - Add helper scripts `filter_locifile.py` and `selectROI.py` +- [#12](https://github.com/nf-core/sarek/pull/12) - Add helper script `make_snapshot.sh` to make an archive for usage on a secure cluster +- [#13](https://github.com/nf-core/sarek/pull/13) - Add Citation documentation +- [#13](https://github.com/nf-core/sarek/pull/13) - Add `BamQC` process +- [#13](https://github.com/nf-core/sarek/pull/13) - Add `CompressVCFsnpEff` and `CompressVCFvep` processes +- [#18](https://github.com/nf-core/sarek/pull/18) - Add `--no-reports` option for tests + add snpEff,VEP,merge to MULTIPLE test +- [#18](https://github.com/nf-core/sarek/pull/18) - Add possibility to download other genome for `sareksnpeff` and `sarekvep` containers +- [#18](https://github.com/nf-core/sarek/pull/18) - Add params `--skip` to skip specified QC tools +- [#18](https://github.com/nf-core/sarek/pull/18) - Add logo to MultiQC report +- [#20](https://github.com/nf-core/sarek/pull/20) - Add `markdownlint` config file ### `Changed` -- [#1](https://github.com/nf-core/sarek/pull/1), [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#6](https://github.com/nf-core/sarek/pull/6), [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12), [#18](https://github.com/nf-core/sarek/pull/18) - Update docs -- [#4](https://github.com/nf-core/sarek/pull/4) - Update `cancerit-allelecount` from `2.1.2` to `4.0.2` -- [#4](https://github.com/nf-core/sarek/pull/4) - Update `gatk4` from `4.1.1.0` to `4.1.2.0` -- [#7](https://github.com/nf-core/sarek/pull/7) - `--sampleDir` is now deprecated, use `--sample` instead -- [#7](https://github.com/nf-core/sarek/pull/8) - `--annotateVCF` is now deprecated, use `--sample` instead -- [#8](https://github.com/nf-core/sarek/pull/8), [#12](https://github.com/nf-core/sarek/pull/12) - Improve helper script `build.nf` for downloading and building reference files -- [#9](https://github.com/nf-core/sarek/pull/9) - ApplyBQSR is now parallelized -- [#9](https://github.com/nf-core/sarek/pull/9) - Fastq files are named following "${idRun}_R1.fastq.gz" in the FastQC output for easier reporting -- [#9](https://github.com/nf-core/sarek/pull/9) - Status is now a map with `idpatient`, `idsample` as keys (ie: `status = statusMap[idPatient, idSample]`) -- [#9](https://github.com/nf-core/sarek/pull/9) - Use `ensembl-vep` `95.2` instead of `96.0` -- [#11](https://github.com/nf-core/sarek/pull/11) - Summary HTML from VWP is now in the `Reports` directory -- [#12](https://github.com/nf-core/sarek/pull/12) - Update configuration files -- [#12](https://github.com/nf-core/sarek/pull/12) - Disable `Docker` in `singularity` profile -- [#12](https://github.com/nf-core/sarek/pull/12) - Disable `Singularity` in `docker` profile -- [#12](https://github.com/nf-core/sarek/pull/12) - Disable `Docker` and `Singularity` in `conda` profile -- [#12](https://github.com/nf-core/sarek/pull/12) - Simplify `check_max()` function -- [#13](https://github.com/nf-core/sarek/pull/13) - Merge `BamQCmapped` and `BamQCrecalibrated` processes into `BamQC` process -- [#13](https://github.com/nf-core/sarek/pull/13) - Split `CompressVCF` process into `CompressVCFsnpEff` and `CompressVCFvep` processes -- [#16](https://github.com/nf-core/sarek/pull/16) - Make scripts in `bin/` and `scripts/` executable -- [#18](https://github.com/nf-core/sarek/pull/18) - Use --no-reports for TravisCI testing -- [#18](https://github.com/nf-core/sarek/pull/18) - Add --no-reports for all tests but MULTIPLE in Jenkins -- [#18](https://github.com/nf-core/sarek/pull/18) - `--noReports` is now `--skip all` -- [#18](https://github.com/nf-core/sarek/pull/18) - Update logo +- [#1](https://github.com/nf-core/sarek/pull/1), [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#6](https://github.com/nf-core/sarek/pull/6), [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12), [#18](https://github.com/nf-core/sarek/pull/18), [#20](https://github.com/nf-core/sarek/pull/20) - Update docs +- [#4](https://github.com/nf-core/sarek/pull/4) - Update `cancerit-allelecount` from `2.1.2` to `4.0.2` +- [#4](https://github.com/nf-core/sarek/pull/4) - Update `gatk4` from `4.1.1.0` to `4.1.2.0` +- [#7](https://github.com/nf-core/sarek/pull/7) - `--sampleDir` is now deprecated, use `--sample` instead +- [#7](https://github.com/nf-core/sarek/pull/8) - `--annotateVCF` is now deprecated, use `--sample` instead +- [#8](https://github.com/nf-core/sarek/pull/8), [#12](https://github.com/nf-core/sarek/pull/12) - Improve helper script `build.nf` for downloading and building reference files +- [#9](https://github.com/nf-core/sarek/pull/9) - ApplyBQSR is now parallelized +- [#9](https://github.com/nf-core/sarek/pull/9) - Fastq files are named following "${idRun}_R1.fastq.gz" in the FastQC output for easier reporting +- [#9](https://github.com/nf-core/sarek/pull/9) - Status is now a map with `idpatient`, `idsample` as keys (ie: `status = statusMap[idPatient, idSample]`) +- [#9](https://github.com/nf-core/sarek/pull/9) - Use `ensembl-vep` `95.2` instead of `96.0` +- [#11](https://github.com/nf-core/sarek/pull/11) - Summary HTML from VWP is now in the `Reports` directory +- [#12](https://github.com/nf-core/sarek/pull/12) - Update configuration files +- [#12](https://github.com/nf-core/sarek/pull/12) - Disable `Docker` in `singularity` profile +- [#12](https://github.com/nf-core/sarek/pull/12) - Disable `Singularity` in `docker` profile +- [#12](https://github.com/nf-core/sarek/pull/12) - Disable `Docker` and `Singularity` in `conda` profile +- [#12](https://github.com/nf-core/sarek/pull/12) - Simplify `check_max()` function +- [#13](https://github.com/nf-core/sarek/pull/13) - Merge `BamQCmapped` and `BamQCrecalibrated` processes into `BamQC` process +- [#13](https://github.com/nf-core/sarek/pull/13) - Split `CompressVCF` process into `CompressVCFsnpEff` and `CompressVCFvep` processes +- [#16](https://github.com/nf-core/sarek/pull/16) - Make scripts in `bin/` and `scripts/` executable +- [#18](https://github.com/nf-core/sarek/pull/18) - Use `--no-reports` for TravisCI testing +- [#18](https://github.com/nf-core/sarek/pull/18) - Add `--no-reports` for all tests but MULTIPLE in Jenkins +- [#18](https://github.com/nf-core/sarek/pull/18) - `--noReports` is now `--skip all` +- [#18](https://github.com/nf-core/sarek/pull/18) - Update logo ### `Removed` -- [#9](https://github.com/nf-core/sarek/pull/9) - Removed `relatedness2` graph from `vcftools stats` -- [#13](https://github.com/nf-core/sarek/pull/13) - Removed `BamQCmapped` and `BamQCrecalibrated` processes -- [#13](https://github.com/nf-core/sarek/pull/13) - Removed `CompressVCF` -- [#18](https://github.com/nf-core/sarek/pull/18) - Removed params `--noReports` +- [#9](https://github.com/nf-core/sarek/pull/9) - Removed `relatedness2` graph from `vcftools stats` +- [#13](https://github.com/nf-core/sarek/pull/13) - Removed `BamQCmapped` and `BamQCrecalibrated` processes +- [#13](https://github.com/nf-core/sarek/pull/13) - Removed `CompressVCF` +- [#18](https://github.com/nf-core/sarek/pull/18) - Removed params `--noReports` ### `Fixed` -- [#3](https://github.com/nf-core/sarek/pull/3) - Fix Docker ownership -- [#11](https://github.com/nf-core/sarek/pull/11) - Fix MergeMpileup PublishDir -- [#13](https://github.com/nf-core/sarek/pull/13) - Fix merge in annotation -- [#14](https://github.com/nf-core/sarek/pull/14) - Fix output name for vcf files -- [#16](https://github.com/nf-core/sarek/pull/16) - Fix path to Rscript -- [#18](https://github.com/nf-core/sarek/pull/18) - Improve cpu usage -- [#18](https://github.com/nf-core/sarek/pull/18) - Use same font for nf-core and sarek in ascii art +- [#3](https://github.com/nf-core/sarek/pull/3) - Fix Docker ownership +- [#11](https://github.com/nf-core/sarek/pull/11) - Fix MergeMpileup PublishDir +- [#13](https://github.com/nf-core/sarek/pull/13) - Fix merge in annotation +- [#14](https://github.com/nf-core/sarek/pull/14) - Fix output name for vcf files +- [#16](https://github.com/nf-core/sarek/pull/16) - Fix path to Rscript +- [#18](https://github.com/nf-core/sarek/pull/18) - Improve cpu usage +- [#18](https://github.com/nf-core/sarek/pull/18) - Use same font for nf-core and sarek in ascii art +- [#20](https://github.com/nf-core/sarek/pull/20) - Use new logo in README +- [#20](https://github.com/nf-core/sarek/pull/20) - Fix path to references genomes ## [2.3.FIX1] - 2019-03-04 ### `Fixed` -- [#742](https://github.com/SciLifeLab/Sarek/pull/742) - Fix output dirs (HaplotypeCaller that was not recognized by annotate.nf introduced by [#728](https://github.com/SciLifeLab/Sarek/pull/728)) +- [#742](https://github.com/SciLifeLab/Sarek/pull/742) - Fix output dirs (HaplotypeCaller that was not recognized by annotate.nf introduced by [#728](https://github.com/SciLifeLab/Sarek/pull/728)) ## [2.3] - Äpar - 2019-02-27 ### `Added` -- [#628](https://github.com/SciLifeLab/Sarek/pull/628), [#722](https://github.com/SciLifeLab/Sarek/pull/722) - `ASCAT` now use `.gc` file -- [#712](https://github.com/SciLifeLab/Sarek/pull/712), [#718](https://github.com/SciLifeLab/Sarek/pull/718) - Added possibilities to run Sarek with `conda` -- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - Annotation documentation -- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - Helper script to download `snpeff` and `VEP` cache files -- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - New `--annotation_cache`, `--snpEff_cache`, `--vep_cache` parameters -- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - Possibility to use cache wen annotating with `snpEff` and `VEP` -- [#722](https://github.com/SciLifeLab/Sarek/pull/722) - Add path to ASCAT `.gc` file in `igenomes.config` -- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Update `Sarek-data` submodule with multiple patients TSV file -- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Add `cadd_WG_SNVs`, `cadd_WG_SNVs_tbi`, `cadd_InDels`, `cadd_InDels_tbi` and `cadd_cache` params -- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Add tabix indexed cache for VEP -- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - New `DownloadCADD` process to download CADD files -- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Specify values for `cadd_WG_SNVs`, `cadd_WG_SNVs_tbi`, `cadd_InDels`, `cadd_InDels_tbi` and `cadd_cache` params in `munin.conf` file -- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Use `cadd_cache` param for optional use of CADD VEP plugin in `annotate.nf` -- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - VEP cache has now fasta files for `--HGVS` -- [#735](https://github.com/SciLifeLab/Sarek/pull/735) - Added `--exome` for Manta, and for StrelkaBP -- [#735](https://github.com/SciLifeLab/Sarek/pull/735) - Added Travis CI test for targeted +- [#628](https://github.com/SciLifeLab/Sarek/pull/628), [#722](https://github.com/SciLifeLab/Sarek/pull/722) - `ASCAT` now use `.gc` file +- [#712](https://github.com/SciLifeLab/Sarek/pull/712), [#718](https://github.com/SciLifeLab/Sarek/pull/718) - Added possibilities to run Sarek with `conda` +- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - Annotation documentation +- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - Helper script to download `snpeff` and `VEP` cache files +- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - New `--annotation_cache`, `--snpEff_cache`, `--vep_cache` parameters +- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - Possibility to use cache wen annotating with `snpEff` and `VEP` +- [#722](https://github.com/SciLifeLab/Sarek/pull/722) - Add path to ASCAT `.gc` file in `igenomes.config` +- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Update `Sarek-data` submodule with multiple patients TSV file +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Add `cadd_WG_SNVs`, `cadd_WG_SNVs_tbi`, `cadd_InDels`, `cadd_InDels_tbi` and `cadd_cache` params +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Add tabix indexed cache for VEP +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - New `DownloadCADD` process to download CADD files +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Specify values for `cadd_WG_SNVs`, `cadd_WG_SNVs_tbi`, `cadd_InDels`, `cadd_InDels_tbi` and `cadd_cache` params in `munin.conf` file +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Use `cadd_cache` param for optional use of CADD VEP plugin in `annotate.nf` +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - VEP cache has now fasta files for `--HGVS` +- [#735](https://github.com/SciLifeLab/Sarek/pull/735) - Added `--exome` for Manta, and for StrelkaBP +- [#735](https://github.com/SciLifeLab/Sarek/pull/735) - Added Travis CI test for targeted ### `Changed` -- [#710](https://github.com/SciLifeLab/Sarek/pull/710) - Improve release checklist and script -- [#711](https://github.com/SciLifeLab/Sarek/pull/711) - Improve configuration priorities -- [#716](https://github.com/SciLifeLab/Sarek/pull/716) - Update paths to containers and iGenomes -- [#717](https://github.com/SciLifeLab/Sarek/pull/717) - `checkFileExtension` has changed to `hasExtension`, and now only verify if file has extension -- [#717](https://github.com/SciLifeLab/Sarek/pull/717) - `fastqFiles` renamed to `inputFiles` -- [#717](https://github.com/SciLifeLab/Sarek/pull/717) - `mapping` step can now map BAM files too -- [#717](https://github.com/SciLifeLab/Sarek/pull/717) - `MapReads` can now convert BAM to FASTQ and feed it to BWA on the fly -- [#717](https://github.com/SciLifeLab/Sarek/pull/717), [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Update documentation -- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - `snpeff` and `vep` containers are now built with conda -- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - `vepCacheVersion` is now defined in `conf/genomes.config` or `conf/igenomes.config` -- [#722](https://github.com/SciLifeLab/Sarek/pull/722) - Add path to ASCAT `.gc` file in `igenomes.config` -- [#722](https://github.com/SciLifeLab/Sarek/pull/722) - Update `Sarek-data` submodule -- [#723](https://github.com/SciLifeLab/Sarek/pull/723), [#725](https://github.com/SciLifeLab/Sarek/pull/725) - Update docs -- [#724](https://github.com/SciLifeLab/Sarek/pull/724) - Improved AwsBatch configuration -- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Improved usage of `targetBED` params -- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Strelka Best Practices output is now prefixed with `StrelkaBP_` -- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - VCFs and Annotated VCFs are now ordered by Patient, then tools -- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Merge `buildContainers.nf` and `buildReferences.nf` in `build.nf` -- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Reduce number of CPUs for `RunVEP` to `4` cf: [VEP docs](https://www.ensembl.org/info/docs/tools/vep/script/vep_other.html) -- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Update VEP from `95.1` to `95.2` +- [#710](https://github.com/SciLifeLab/Sarek/pull/710) - Improve release checklist and script +- [#711](https://github.com/SciLifeLab/Sarek/pull/711) - Improve configuration priorities +- [#716](https://github.com/SciLifeLab/Sarek/pull/716) - Update paths to containers and iGenomes +- [#717](https://github.com/SciLifeLab/Sarek/pull/717) - `checkFileExtension` has changed to `hasExtension`, and now only verify if file has extension +- [#717](https://github.com/SciLifeLab/Sarek/pull/717) - `fastqFiles` renamed to `inputFiles` +- [#717](https://github.com/SciLifeLab/Sarek/pull/717) - `mapping` step can now map BAM files too +- [#717](https://github.com/SciLifeLab/Sarek/pull/717) - `MapReads` can now convert BAM to FASTQ and feed it to BWA on the fly +- [#717](https://github.com/SciLifeLab/Sarek/pull/717), [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Update documentation +- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - `snpeff` and `vep` containers are now built with conda +- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - `vepCacheVersion` is now defined in `conf/genomes.config` or `conf/igenomes.config` +- [#722](https://github.com/SciLifeLab/Sarek/pull/722) - Add path to ASCAT `.gc` file in `igenomes.config` +- [#722](https://github.com/SciLifeLab/Sarek/pull/722) - Update `Sarek-data` submodule +- [#723](https://github.com/SciLifeLab/Sarek/pull/723), [#725](https://github.com/SciLifeLab/Sarek/pull/725) - Update docs +- [#724](https://github.com/SciLifeLab/Sarek/pull/724) - Improved AwsBatch configuration +- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Improved usage of `targetBED` params +- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Strelka Best Practices output is now prefixed with `StrelkaBP_` +- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - VCFs and Annotated VCFs are now ordered by Patient, then tools +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Merge `buildContainers.nf` and `buildReferences.nf` in `build.nf` +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Reduce number of CPUs for `RunVEP` to `4` cf: [VEP docs](https://www.ensembl.org/info/docs/tools/vep/script/vep_other.html) +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Update VEP from `95.1` to `95.2` ### `Removed` -- [#715](https://github.com/SciLifeLab/Sarek/pull/715) - Remove `defReferencesFiles` function from `buildReferences.nf` -- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - `snpEff` base container is no longer used -- [#721](https://github.com/SciLifeLab/Sarek/pull/721) - Remove COSMIC docs -- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Remove `defineDirectoryMap()` -- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Removed `--database` option for VEP cf: [VEP docs](https://www.ensembl.org/info/docs/tools/vep/script/vep_other.html) +- [#715](https://github.com/SciLifeLab/Sarek/pull/715) - Remove `defReferencesFiles` function from `buildReferences.nf` +- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - `snpEff` base container is no longer used +- [#721](https://github.com/SciLifeLab/Sarek/pull/721) - Remove COSMIC docs +- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Remove `defineDirectoryMap()` +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Removed `--database` option for VEP cf: [VEP docs](https://www.ensembl.org/info/docs/tools/vep/script/vep_other.html) ### `Fixed` -- [#720](https://github.com/SciLifeLab/Sarek/pull/720) - bamQC is now run on the recalibrated bams, and not after MarkDuplicates -- [#726](https://github.com/SciLifeLab/Sarek/pull/726) - Fix Ascat ref file input (one file can't be a set) -- [#727](https://github.com/SciLifeLab/Sarek/pull/727) - bamQC outputs are no longer overwritten (name of dir is now the file instead of sample) -- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Fix issue with annotation that was consuming `cache` channels -- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Fix multi sample TSV file [#691](https://github.com/SciLifeLab/Sarek/issues/691) -- [#733](https://github.com/SciLifeLab/Sarek/pull/733) - Fix the possibility to specify reference files on the command line +- [#720](https://github.com/SciLifeLab/Sarek/pull/720) - bamQC is now run on the recalibrated bams, and not after MarkDuplicates +- [#726](https://github.com/SciLifeLab/Sarek/pull/726) - Fix Ascat ref file input (one file can't be a set) +- [#727](https://github.com/SciLifeLab/Sarek/pull/727) - bamQC outputs are no longer overwritten (name of dir is now the file instead of sample) +- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Fix issue with annotation that was consuming `cache` channels +- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Fix multi sample TSV file [#691](https://github.com/SciLifeLab/Sarek/issues/691) +- [#733](https://github.com/SciLifeLab/Sarek/pull/733) - Fix the possibility to specify reference files on the command line ## [2.2.2] - 2018-12-19 ### `Added` -- [#671](https://github.com/SciLifeLab/Sarek/pull/671) - New `publishDirMode` param and docs -- [#673](https://github.com/SciLifeLab/Sarek/pull/673), [#675](https://github.com/SciLifeLab/Sarek/pull/675), [#676](https://github.com/SciLifeLab/Sarek/pull/676) - Profiles for BinAC and CFC clusters in Tübingen -- [#679](https://github.com/SciLifeLab/Sarek/pull/679) - Add container for `CreateIntervalBeds` -- [#692](https://github.com/SciLifeLab/Sarek/pull/692), [#697](https://github.com/SciLifeLab/Sarek/pull/697) - Add AWS iGenomes possibilities (within `conf/igenomes.conf`) -- [#694](https://github.com/SciLifeLab/Sarek/pull/694) - Add monochrome and grey logos for light or dark background -- [#698](https://github.com/SciLifeLab/Sarek/pull/698) - Add btb profile for munin server -- [#702](https://github.com/SciLifeLab/Sarek/pull/702) - Add font-ttf-dejavu-sans-mono `2.37` and fontconfig `2.12.6` to container +- [#671](https://github.com/SciLifeLab/Sarek/pull/671) - New `publishDirMode` param and docs +- [#673](https://github.com/SciLifeLab/Sarek/pull/673), [#675](https://github.com/SciLifeLab/Sarek/pull/675), [#676](https://github.com/SciLifeLab/Sarek/pull/676) - Profiles for BinAC and CFC clusters in Tübingen +- [#679](https://github.com/SciLifeLab/Sarek/pull/679) - Add container for `CreateIntervalBeds` +- [#692](https://github.com/SciLifeLab/Sarek/pull/692), [#697](https://github.com/SciLifeLab/Sarek/pull/697) - Add AWS iGenomes possibilities (within `conf/igenomes.conf`) +- [#694](https://github.com/SciLifeLab/Sarek/pull/694) - Add monochrome and grey logos for light or dark background +- [#698](https://github.com/SciLifeLab/Sarek/pull/698) - Add btb profile for munin server +- [#702](https://github.com/SciLifeLab/Sarek/pull/702) - Add font-ttf-dejavu-sans-mono `2.37` and fontconfig `2.12.6` to container ### `Changed` -- [#663](https://github.com/SciLifeLab/Sarek/pull/663) - Update `do_release.sh` script -- [#671](https://github.com/SciLifeLab/Sarek/pull/671) - publishDir modes are now params -- [#677](https://github.com/SciLifeLab/Sarek/pull/677), [#698](https://github.com/SciLifeLab/Sarek/pull/698), [#703](https://github.com/SciLifeLab/Sarek/pull/703) - Update docs -- [#678](https://github.com/SciLifeLab/Sarek/pull/678) - Changing VEP to v92 and adjusting CPUs for VEP -- [#679](https://github.com/SciLifeLab/Sarek/pull/679) - Update old awsbatch configuration -- [#682](https://github.com/SciLifeLab/Sarek/pull/682) - Specifications for memory and cpus for awsbatch -- [#693](https://github.com/SciLifeLab/Sarek/pull/693) - Qualimap bamQC is now ran after mapping and after recalibration for better QC -- [#700](https://github.com/SciLifeLab/Sarek/pull/700) - Update GATK to `4.0.9.0` -- [#702](https://github.com/SciLifeLab/Sarek/pull/702) - Update FastQC to `0.11.8` -- [#705](https://github.com/SciLifeLab/Sarek/pull/705) - Change `--TMP_DIR` by `--tmp-dir` for GATK `4.0.9.0` BaseRecalibrator -- [#706](https://github.com/SciLifeLab/Sarek/pull/706) - Update TravisCI testing +- [#663](https://github.com/SciLifeLab/Sarek/pull/663) - Update `do_release.sh` script +- [#671](https://github.com/SciLifeLab/Sarek/pull/671) - publishDir modes are now params +- [#677](https://github.com/SciLifeLab/Sarek/pull/677), [#698](https://github.com/SciLifeLab/Sarek/pull/698), [#703](https://github.com/SciLifeLab/Sarek/pull/703) - Update docs +- [#678](https://github.com/SciLifeLab/Sarek/pull/678) - Changing VEP to v92 and adjusting CPUs for VEP +- [#679](https://github.com/SciLifeLab/Sarek/pull/679) - Update old awsbatch configuration +- [#682](https://github.com/SciLifeLab/Sarek/pull/682) - Specifications for memory and cpus for awsbatch +- [#693](https://github.com/SciLifeLab/Sarek/pull/693) - Qualimap bamQC is now ran after mapping and after recalibration for better QC +- [#700](https://github.com/SciLifeLab/Sarek/pull/700) - Update GATK to `4.0.9.0` +- [#702](https://github.com/SciLifeLab/Sarek/pull/702) - Update FastQC to `0.11.8` +- [#705](https://github.com/SciLifeLab/Sarek/pull/705) - Change `--TMP_DIR` by `--tmp-dir` for GATK `4.0.9.0` BaseRecalibrator +- [#706](https://github.com/SciLifeLab/Sarek/pull/706) - Update TravisCI testing ### `Fixed` -- [#665](https://github.com/SciLifeLab/Sarek/pull/665) - Input bam file now has always the same name (whether it is from a single fastq pair or multiple) in the MarkDuplicates process, so metrics too -- [#672](https://github.com/SciLifeLab/Sarek/pull/672) - process `PullSingularityContainers` from `buildContainers.nf` now expect a file with the correct `.simg` extension for singularity images, and no longer the `.img` one. -- [#679](https://github.com/SciLifeLab/Sarek/pull/679) - Add publishDirMode for `germlineVC.nf` -- [#700](https://github.com/SciLifeLab/Sarek/pull/700) - Fix [#699](https://github.com/SciLifeLab/Sarek/issues/699) missing DP in the FORMAT column VCFs for MuTect2 -- [#702](https://github.com/SciLifeLab/Sarek/pull/702) - Fix [#701](https://github.com/SciLifeLab/Sarek/issues/701) -- [#705](https://github.com/SciLifeLab/Sarek/pull/705) - Fix [#704](https://github.com/SciLifeLab/Sarek/issues/704) +- [#665](https://github.com/SciLifeLab/Sarek/pull/665) - Input bam file now has always the same name (whether it is from a single fastq pair or multiple) in the MarkDuplicates process, so metrics too +- [#672](https://github.com/SciLifeLab/Sarek/pull/672) - process `PullSingularityContainers` from `buildContainers.nf` now expect a file with the correct `.simg` extension for singularity images, and no longer the `.img` one. +- [#679](https://github.com/SciLifeLab/Sarek/pull/679) - Add publishDirMode for `germlineVC.nf` +- [#700](https://github.com/SciLifeLab/Sarek/pull/700) - Fix [#699](https://github.com/SciLifeLab/Sarek/issues/699) missing DP in the FORMAT column VCFs for MuTect2 +- [#702](https://github.com/SciLifeLab/Sarek/pull/702) - Fix [#701](https://github.com/SciLifeLab/Sarek/issues/701) +- [#705](https://github.com/SciLifeLab/Sarek/pull/705) - Fix [#704](https://github.com/SciLifeLab/Sarek/issues/704) ## [2.2.1] - 2018-10-04 ### `Changed` -- [#646](https://github.com/SciLifeLab/Sarek/pull/646) - Update [`pathfindr`](https://github.com/NBISweden/pathfindr) submodule -- [#659](https://github.com/SciLifeLab/Sarek/pull/659) - Update Nextflow to `0.32.0` -- [#660](https://github.com/SciLifeLab/Sarek/pull/660) - Update docs +- [#646](https://github.com/SciLifeLab/Sarek/pull/646) - Update [`pathfindr`](https://github.com/NBISweden/pathfindr) submodule +- [#659](https://github.com/SciLifeLab/Sarek/pull/659) - Update Nextflow to `0.32.0` +- [#660](https://github.com/SciLifeLab/Sarek/pull/660) - Update docs ### `Fixed` -- [#657](https://github.com/SciLifeLab/Sarek/pull/657) - Fix `RunMultiQC.nf` bug -- [#659](https://github.com/SciLifeLab/Sarek/pull/659) - Fix bugs due to updating Nextflow +- [#657](https://github.com/SciLifeLab/Sarek/pull/657) - Fix `RunMultiQC.nf` bug +- [#659](https://github.com/SciLifeLab/Sarek/pull/659) - Fix bugs due to updating Nextflow ## [2.2.0] - Skårki - 2018-09-21 ### `Added` -- [#613](https://github.com/SciLifeLab/Sarek/pull/613) - Add Issue Templates (bug report and feature request) -- [#614](https://github.com/SciLifeLab/Sarek/pull/614) - Add PR Template -- [#615](https://github.com/SciLifeLab/Sarek/pull/615) - Add presentation -- [#616](https://github.com/SciLifeLab/Sarek/pull/616) - Update documentation -- [#620](https://github.com/SciLifeLab/Sarek/pull/620) - Add `tmp/` to `.gitignore` -- [#625](https://github.com/SciLifeLab/Sarek/pull/625) - Add [`pathfindr`](https://github.com/NBISweden/pathfindr) as a submodule -- [#635](https://github.com/SciLifeLab/Sarek/pull/635) - To process targeted sequencing with a target BED -- [#639](https://github.com/SciLifeLab/Sarek/pull/639) - Add a complete example analysis to docs -- [#640](https://github.com/SciLifeLab/Sarek/pull/640), [#642](https://github.com/SciLifeLab/Sarek/pull/642) - Add helper script for changing version number +- [#613](https://github.com/SciLifeLab/Sarek/pull/613) - Add Issue Templates (bug report and feature request) +- [#614](https://github.com/SciLifeLab/Sarek/pull/614) - Add PR Template +- [#615](https://github.com/SciLifeLab/Sarek/pull/615) - Add presentation +- [#616](https://github.com/SciLifeLab/Sarek/pull/616) - Update documentation +- [#620](https://github.com/SciLifeLab/Sarek/pull/620) - Add `tmp/` to `.gitignore` +- [#625](https://github.com/SciLifeLab/Sarek/pull/625) - Add [`pathfindr`](https://github.com/NBISweden/pathfindr) as a submodule +- [#635](https://github.com/SciLifeLab/Sarek/pull/635) - To process targeted sequencing with a target BED +- [#639](https://github.com/SciLifeLab/Sarek/pull/639) - Add a complete example analysis to docs +- [#640](https://github.com/SciLifeLab/Sarek/pull/640), [#642](https://github.com/SciLifeLab/Sarek/pull/642) - Add helper script for changing version number ### `Changed` -- [#608](https://github.com/SciLifeLab/Sarek/pull/608) - Update Nextflow required version -- [#615](https://github.com/SciLifeLab/Sarek/pull/615) - Use `splitCsv` instead of `readlines` -- [#616](https://github.com/SciLifeLab/Sarek/pull/616) - Update CHANGELOG -- [#621](https://github.com/SciLifeLab/Sarek/pull/621), [#638](https://github.com/SciLifeLab/Sarek/pull/638) - Improve install script -- [#621](https://github.com/SciLifeLab/Sarek/pull/621), [#638](https://github.com/SciLifeLab/Sarek/pull/638) - Simplify tests -- [#627](https://github.com/SciLifeLab/Sarek/pull/627), [#629](https://github.com/SciLifeLab/Sarek/pull/629), [#637](https://github.com/SciLifeLab/Sarek/pull/637) - Refactor docs -- [#629](https://github.com/SciLifeLab/Sarek/pull/629) - Refactor config -- [#632](https://github.com/SciLifeLab/Sarek/pull/632) - Use 2 threads and 2 cpus FastQC processes -- [#637](https://github.com/SciLifeLab/Sarek/pull/637) - Update tool version gathering -- [#638](https://github.com/SciLifeLab/Sarek/pull/638) - Use correct `.simg` extension for Singularity images -- [#639](https://github.com/SciLifeLab/Sarek/pull/639) - Smaller refactoring of the docs -- [#640](https://github.com/SciLifeLab/Sarek/pull/640) - Update RELEASE_CHECKLIST -- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - MultiQC 1.5 -> 1.6 -- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - Qualimap 2.2.2a -> 2.2.2b -- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - Update conda channel order priorities -- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - VCFanno 0.2.8 -> 0.3.0 -- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - VCFtools 0.1.15 -> 0.1.16 +- [#608](https://github.com/SciLifeLab/Sarek/pull/608) - Update Nextflow required version +- [#615](https://github.com/SciLifeLab/Sarek/pull/615) - Use `splitCsv` instead of `readlines` +- [#616](https://github.com/SciLifeLab/Sarek/pull/616) - Update CHANGELOG +- [#621](https://github.com/SciLifeLab/Sarek/pull/621), [#638](https://github.com/SciLifeLab/Sarek/pull/638) - Improve install script +- [#621](https://github.com/SciLifeLab/Sarek/pull/621), [#638](https://github.com/SciLifeLab/Sarek/pull/638) - Simplify tests +- [#627](https://github.com/SciLifeLab/Sarek/pull/627), [#629](https://github.com/SciLifeLab/Sarek/pull/629), [#637](https://github.com/SciLifeLab/Sarek/pull/637) - Refactor docs +- [#629](https://github.com/SciLifeLab/Sarek/pull/629) - Refactor config +- [#632](https://github.com/SciLifeLab/Sarek/pull/632) - Use 2 threads and 2 cpus FastQC processes +- [#637](https://github.com/SciLifeLab/Sarek/pull/637) - Update tool version gathering +- [#638](https://github.com/SciLifeLab/Sarek/pull/638) - Use correct `.simg` extension for Singularity images +- [#639](https://github.com/SciLifeLab/Sarek/pull/639) - Smaller refactoring of the docs +- [#640](https://github.com/SciLifeLab/Sarek/pull/640) - Update RELEASE_CHECKLIST +- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - MultiQC 1.5 -> 1.6 +- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - Qualimap 2.2.2a -> 2.2.2b +- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - Update conda channel order priorities +- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - VCFanno 0.2.8 -> 0.3.0 +- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - VCFtools 0.1.15 -> 0.1.16 ### `Removed` -- [#616](https://github.com/SciLifeLab/Sarek/pull/616) - Remove old Issue Template -- [#629](https://github.com/SciLifeLab/Sarek/pull/629) - Remove old Dockerfiles -- [#637](https://github.com/SciLifeLab/Sarek/pull/637) - Remove old comments +- [#616](https://github.com/SciLifeLab/Sarek/pull/616) - Remove old Issue Template +- [#629](https://github.com/SciLifeLab/Sarek/pull/629) - Remove old Dockerfiles +- [#637](https://github.com/SciLifeLab/Sarek/pull/637) - Remove old comments ### `Fixed` -- [#621](https://github.com/SciLifeLab/Sarek/pull/621) - Fix VEP tests -- [#637](https://github.com/SciLifeLab/Sarek/pull/637) - Fix links in MD files +- [#621](https://github.com/SciLifeLab/Sarek/pull/621) - Fix VEP tests +- [#637](https://github.com/SciLifeLab/Sarek/pull/637) - Fix links in MD files ## [2.1.0] - Ruotes - 2018-08-14 ### `Added` -- [#555](https://github.com/SciLifeLab/Sarek/pull/555) - `snpEff` output into `VEP` -- [#556](https://github.com/SciLifeLab/Sarek/pull/556) - `Strelka` Best Practices -- [#563](https://github.com/SciLifeLab/Sarek/pull/563) - Use `SnpEFF` reports in `MultiQC` -- [#568](https://github.com/SciLifeLab/Sarek/pull/568) - `VCFTools` process `RunVcftools` for QC -- [#574](https://github.com/SciLifeLab/Sarek/pull/574), [#580](https://github.com/SciLifeLab/Sarek/pull/580) - Abstracts for NPMI, JOBIM and EACR25 -- [#577](https://github.com/SciLifeLab/Sarek/pull/577) - New repository for testing: [Sarek-data](https://github.com/SciLifeLab/Sarek-data) -- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - New library `QC` for functions `bamQC`, `bcftools`, `samtoolsStats`, `vcftools`, `getVersionBCFtools`, `getVersionGATK`, `getVersionManta`, `getVersionSnpEFF`, `getVersionStrelka`, `getVersionVCFtools`, `getVersionVEP` -- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - New Processes `GetVersionBCFtools`, `GetVersionGATK`, `GetVersionManta`, `GetVersionSnpEFF`, `GetVersionStrelka`, `GetVersionVCFtools`, `GetVersionVEP` -- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - new Python script `bin/scrape_tool_versions.py` inspired by @ewels and @apeltzer -- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - New QC Process `RunVcftools` -- [#596](https://github.com/SciLifeLab/Sarek/pull/596) - New profile for BinAC cluster -- [#597](https://github.com/SciLifeLab/Sarek/pull/597) - New function `sarek_ascii()` in `SarekUtils` -- [#599](https://github.com/SciLifeLab/Sarek/pull/599), [#602](https://github.com/SciLifeLab/Sarek/pull/602) - New Process `CompressVCF` -- [#601](https://github.com/SciLifeLab/Sarek/pull/601), [#603](https://github.com/SciLifeLab/Sarek/pull/603) - Container for GATK4 -- [#606](https://github.com/SciLifeLab/Sarek/pull/606) - Add test data as a submodule from [`Sarek-data`](https://github.com/SciLifeLab/Sarek-data) -- [#608](https://github.com/SciLifeLab/Sarek/pull/608) - Add documentation on how to install Nextflow on `bianca` +- [#555](https://github.com/SciLifeLab/Sarek/pull/555) - `snpEff` output into `VEP` +- [#556](https://github.com/SciLifeLab/Sarek/pull/556) - `Strelka` Best Practices +- [#563](https://github.com/SciLifeLab/Sarek/pull/563) - Use `SnpEFF` reports in `MultiQC` +- [#568](https://github.com/SciLifeLab/Sarek/pull/568) - `VCFTools` process `RunVcftools` for QC +- [#574](https://github.com/SciLifeLab/Sarek/pull/574), [#580](https://github.com/SciLifeLab/Sarek/pull/580) - Abstracts for NPMI, JOBIM and EACR25 +- [#577](https://github.com/SciLifeLab/Sarek/pull/577) - New repository for testing: [Sarek-data](https://github.com/SciLifeLab/Sarek-data) +- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - New library `QC` for functions `bamQC`, `bcftools`, `samtoolsStats`, `vcftools`, `getVersionBCFtools`, `getVersionGATK`, `getVersionManta`, `getVersionSnpEFF`, `getVersionStrelka`, `getVersionVCFtools`, `getVersionVEP` +- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - New Processes `GetVersionBCFtools`, `GetVersionGATK`, `GetVersionManta`, `GetVersionSnpEFF`, `GetVersionStrelka`, `GetVersionVCFtools`, `GetVersionVEP` +- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - new Python script `bin/scrape_tool_versions.py` inspired by @ewels and @apeltzer +- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - New QC Process `RunVcftools` +- [#596](https://github.com/SciLifeLab/Sarek/pull/596) - New profile for BinAC cluster +- [#597](https://github.com/SciLifeLab/Sarek/pull/597) - New function `sarek_ascii()` in `SarekUtils` +- [#599](https://github.com/SciLifeLab/Sarek/pull/599), [#602](https://github.com/SciLifeLab/Sarek/pull/602) - New Process `CompressVCF` +- [#601](https://github.com/SciLifeLab/Sarek/pull/601), [#603](https://github.com/SciLifeLab/Sarek/pull/603) - Container for GATK4 +- [#606](https://github.com/SciLifeLab/Sarek/pull/606) - Add test data as a submodule from [`Sarek-data`](https://github.com/SciLifeLab/Sarek-data) +- [#608](https://github.com/SciLifeLab/Sarek/pull/608) - Add documentation on how to install Nextflow on `bianca` ### `Changed` -- [#557](https://github.com/SciLifeLab/Sarek/pull/557), [#583](https://github.com/SciLifeLab/Sarek/pull/583), [#585](https://github.com/SciLifeLab/Sarek/pull/585), [#588](https://github.com/SciLifeLab/Sarek/pull/588) - Update help -- [#560](https://github.com/SciLifeLab/Sarek/pull/560) - GitHub langage for the repository is now `Nextflow` -- [#561](https://github.com/SciLifeLab/Sarek/pull/561) - `do_all.sh` build only containers for one genome reference (default `GRCh38`) only -- [#571](https://github.com/SciLifeLab/Sarek/pull/571) - Only one container for all QC tools -- [#582](https://github.com/SciLifeLab/Sarek/pull/582), [#587](https://github.com/SciLifeLab/Sarek/pull/587) - Update figures -- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - Function `defineDirectoryMap()` is now part of `SarekUtils` -- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - Process `GenerateMultiQCconfig` replace by function `createMultiQCconfig()` -- [#597](https://github.com/SciLifeLab/Sarek/pull/597) - `extractBams()` now takes an extra parameter. -- [#597](https://github.com/SciLifeLab/Sarek/pull/597) - Move `checkFileExtension()`, `checkParameterExistence()`, `checkParameterList()`, `checkReferenceMap()`, `checkRefExistence()`, `extractBams()`, `extractGenders()`, `returnFile()`, `returnStatus()` and `returnTSV()` functions to `SarekUtils` -- [#597](https://github.com/SciLifeLab/Sarek/pull/597) - Reduce data footprint for Process `CreateRecalibrationTable` -- [#597](https://github.com/SciLifeLab/Sarek/pull/597) - Replace deprecated operator `phase` by `join`. -- [#599](https://github.com/SciLifeLab/Sarek/pull/599) - Merge is tested with `ANNOTATEALL` -- [#604](https://github.com/SciLifeLab/Sarek/pull/604) - Synching `GRCh38` `wgs_calling_regions` bedfiles -- [#607](https://github.com/SciLifeLab/Sarek/pull/607) - One container approach -- [#607](https://github.com/SciLifeLab/Sarek/pull/607) - Update to GATK4 -- [#608](https://github.com/SciLifeLab/Sarek/pull/608) - Update Nextflow required version -- [#616](https://github.com/SciLifeLab/Sarek/pull/616) - Update CHANGELOG -- [#617](https://github.com/SciLifeLab/Sarek/pull/617) - Replace deprecated $name syntax with withName +- [#557](https://github.com/SciLifeLab/Sarek/pull/557), [#583](https://github.com/SciLifeLab/Sarek/pull/583), [#585](https://github.com/SciLifeLab/Sarek/pull/585), [#588](https://github.com/SciLifeLab/Sarek/pull/588) - Update help +- [#560](https://github.com/SciLifeLab/Sarek/pull/560) - GitHub langage for the repository is now `Nextflow` +- [#561](https://github.com/SciLifeLab/Sarek/pull/561) - `do_all.sh` build only containers for one genome reference (default `GRCh38`) only +- [#571](https://github.com/SciLifeLab/Sarek/pull/571) - Only one container for all QC tools +- [#582](https://github.com/SciLifeLab/Sarek/pull/582), [#587](https://github.com/SciLifeLab/Sarek/pull/587) - Update figures +- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - Function `defineDirectoryMap()` is now part of `SarekUtils` +- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - Process `GenerateMultiQCconfig` replace by function `createMultiQCconfig()` +- [#597](https://github.com/SciLifeLab/Sarek/pull/597) - `extractBams()` now takes an extra parameter. +- [#597](https://github.com/SciLifeLab/Sarek/pull/597) - Move `checkFileExtension()`, `checkParameterExistence()`, `checkParameterList()`, `checkReferenceMap()`, `checkRefExistence()`, `extractBams()`, `extractGenders()`, `returnFile()`, `returnStatus()` and `returnTSV()` functions to `SarekUtils` +- [#597](https://github.com/SciLifeLab/Sarek/pull/597) - Reduce data footprint for Process `CreateRecalibrationTable` +- [#597](https://github.com/SciLifeLab/Sarek/pull/597) - Replace deprecated operator `phase` by `join`. +- [#599](https://github.com/SciLifeLab/Sarek/pull/599) - Merge is tested with `ANNOTATEALL` +- [#604](https://github.com/SciLifeLab/Sarek/pull/604) - Synching `GRCh38` `wgs_calling_regions` bedfiles +- [#607](https://github.com/SciLifeLab/Sarek/pull/607) - One container approach +- [#607](https://github.com/SciLifeLab/Sarek/pull/607) - Update to GATK4 +- [#608](https://github.com/SciLifeLab/Sarek/pull/608) - Update Nextflow required version +- [#616](https://github.com/SciLifeLab/Sarek/pull/616) - Update CHANGELOG +- [#617](https://github.com/SciLifeLab/Sarek/pull/617) - Replace deprecated $name syntax with withName ### `Fixed` -- [#560](https://github.com/SciLifeLab/Sarek/pull/560) - Display message for `repository` and `containerPath` -- [#566](https://github.com/SciLifeLab/Sarek/pull/566) - `slurmDownload` profile -- [#579](https://github.com/SciLifeLab/Sarek/pull/579), [#584](https://github.com/SciLifeLab/Sarek/pull/584) - `Manta` output reorganized after modification for `Strelka Best Practices` process -- [#585](https://github.com/SciLifeLab/Sarek/pull/583) - Trace file is plain txt -- [#590](https://github.com/SciLifeLab/Sarek/pull/590), [#593](https://github.com/SciLifeLab/Sarek/pull/593) - Fix Singularity installation in Travis CI testing -- [#598](https://github.com/SciLifeLab/Sarek/pull/598), [#601](https://github.com/SciLifeLab/Sarek/pull/601) - Fixes for Python script `selectROI.py` to work with CLC viewer +- [#560](https://github.com/SciLifeLab/Sarek/pull/560) - Display message for `repository` and `containerPath` +- [#566](https://github.com/SciLifeLab/Sarek/pull/566) - `slurmDownload` profile +- [#579](https://github.com/SciLifeLab/Sarek/pull/579), [#584](https://github.com/SciLifeLab/Sarek/pull/584) - `Manta` output reorganized after modification for `Strelka Best Practices` process +- [#585](https://github.com/SciLifeLab/Sarek/pull/583) - Trace file is plain txt +- [#590](https://github.com/SciLifeLab/Sarek/pull/590), [#593](https://github.com/SciLifeLab/Sarek/pull/593) - Fix Singularity installation in Travis CI testing +- [#598](https://github.com/SciLifeLab/Sarek/pull/598), [#601](https://github.com/SciLifeLab/Sarek/pull/601) - Fixes for Python script `selectROI.py` to work with CLC viewer ### `Removed` -- [#607](https://github.com/SciLifeLab/Sarek/pull/607) - Remove Mutect1 +- [#607](https://github.com/SciLifeLab/Sarek/pull/607) - Remove Mutect1 ## [2.0.0] - 2018-03-23 ### `Added` -- basic wrapper script -- Abstract, posters and figures -- ROI selector and FreeBayes sanitizer scripts -- New logo and icon for the project -- check for existing tumor/normal channel -- `SarekUtils` with `checkParams()`, `checkParameterList()`, `checkParameterExistence()` and `isAllowedParams()` functions -- some `runOptions` for `docker` (prevent some user right problem) -- This `CHANGELOG` +- basic wrapper script +- Abstract, posters and figures +- ROI selector and FreeBayes sanitizer scripts +- New logo and icon for the project +- check for existing tumor/normal channel +- `SarekUtils` with `checkParams()`, `checkParameterList()`, `checkParameterExistence()` and `isAllowedParams()` functions +- some `runOptions` for `docker` (prevent some user right problem) +- This `CHANGELOG` ### `Changed` -- `CAW` is now `Sarek` -- Dissect Workflow in 5 new scripts: `annotate.nf`, `main.nf`, `germlineVC.nf`, `runMultiQC.nf` and `somaticVC.nf` -- `report.html`, `timeline.html` and `trace.html` are generated in `Reports/` -- `--version` is now used to define the workflow version -- most params are now defined in the base.config file instead of in the scripts -- update RELEASE_CHECKLIST.md -- `checkParams()`, `checkParameterList()`, `checkParameterExistence()` and `isAllowedParams()` in script functions are now called within `SarekUtils` -- `nf_required_version` is now `params.nfRequiredVersion` -- in `buildReferences.nf` script, channels now begin by `ch_`, and files by `f_` -- use `PublishDir mode: 'link'` instead of `copy` -- `directoryMap` now contains `params.outDir` -- [#539](https://github.com/SciLifeLab/Sarek/issues/539) - use Nextflow support of scratch -- reordered Travis CI tests -- update documentation -- `MultiQC` version in container from v`1.4` to v`1.5` -- `vepgrch37` container base image from `release_90.6` to `release_92` -- `vepgrch38` container base image from `release_90.6` to `release_92` -- `VEP` version in containers from v`90` to v`91` -- `nucleotidesPerSecond` is now `params.nucleotidesPerSecond` -- default `params.tag` is now `latest` instead of current version, so --tag needs to be specified with the right version to be sure of using the `containers` corresponding +- `CAW` is now `Sarek` +- Dissect Workflow in 5 new scripts: `annotate.nf`, `main.nf`, `germlineVC.nf`, `runMultiQC.nf` and `somaticVC.nf` +- `report.html`, `timeline.html` and `trace.html` are generated in `Reports/` +- `--version` is now used to define the workflow version +- most params are now defined in the base.config file instead of in the scripts +- update RELEASE_CHECKLIST.md +- `checkParams()`, `checkParameterList()`, `checkParameterExistence()` and `isAllowedParams()` in script functions are now called within `SarekUtils` +- `nf_required_version` is now `params.nfRequiredVersion` +- in `buildReferences.nf` script, channels now begin by `ch_`, and files by `f_` +- use `PublishDir mode: 'link'` instead of `copy` +- `directoryMap` now contains `params.outDir` +- [#539](https://github.com/SciLifeLab/Sarek/issues/539) - use Nextflow support of scratch +- reordered Travis CI tests +- update documentation +- `MultiQC` version in container from v`1.4` to v`1.5` +- `vepgrch37` container base image from `release_90.6` to `release_92` +- `vepgrch38` container base image from `release_90.6` to `release_92` +- `VEP` version in containers from v`90` to v`91` +- `nucleotidesPerSecond` is now `params.nucleotidesPerSecond` +- default `params.tag` is now `latest` instead of current version, so --tag needs to be specified with the right version to be sure of using the `containers` corresponding ### `Deprecated` -- `standard` profile -- `uppmax-localhost.config` file +- `standard` profile +- `uppmax-localhost.config` file ### `Removed` -- `scripts/skeleton_batch.sh` -- old data and tsv files -- UPPMAX directories from containers -- `--step` in `annotate.nf`, `germlineVC.nf` and `somatic.nf` -- some `runOptions` for Singularity (binding not needed anymore on UPPMAX) -- `download` profile +- `scripts/skeleton_batch.sh` +- old data and tsv files +- UPPMAX directories from containers +- `--step` in `annotate.nf`, `germlineVC.nf` and `somatic.nf` +- some `runOptions` for Singularity (binding not needed anymore on UPPMAX) +- `download` profile ### `Fixed` -- [#530](https://github.com/SciLifeLab/Sarek/issues/530) - use `$PWD` for default `outDir` -- [#533](https://github.com/SciLifeLab/Sarek/issues/533) - Replace `VEP` `--pick` option by `--per_gene` +- [#530](https://github.com/SciLifeLab/Sarek/issues/530) - use `$PWD` for default `outDir` +- [#533](https://github.com/SciLifeLab/Sarek/issues/533) - Replace `VEP` `--pick` option by `--per_gene` ## [1.2.5] - 2018-01-18 ### `Added` -- Zenodo for DOI -- Delivery README -- Document use of the `--sampleDir` option -- Contributing Guidelines -- Issue Templates -- Release Checklist -- `--outDir` -- `awsbatch` profile -- `aws-batch.config` config file -- `--noBAMQC` params (failing sometimes on Bianca) +- Zenodo for DOI +- Delivery README +- Document use of the `--sampleDir` option +- Contributing Guidelines +- Issue Templates +- Release Checklist +- `--outDir` +- `awsbatch` profile +- `aws-batch.config` config file +- `--noBAMQC` params (failing sometimes on Bianca) ### `Changed` -- Update `Nextflow` to `0.26.0` (new fancy report + AWS Batch) -- Extra time on Travis CI testing -- Replace `bundleDir` by `params.genome_base` -- Update `MultiQC` to `1.3` (MEGAQC FTW) -- Move and rename some test files +- Update `Nextflow` to `0.26.0` (new fancy report + AWS Batch) +- Extra time on Travis CI testing +- Replace `bundleDir` by `params.genome_base` +- Update `MultiQC` to `1.3` (MEGAQC FTW) +- Move and rename some test files ### `Fixed` -- Version of COSMIC GRCh37 v83 -- Write an error message when `--sampleDir` does not find any FASTQ files -- `base.config` for ConcatVCF process -- File specification for recalibrationReport in RecalibrateBam process (got error on AWS Batch) +- Version of COSMIC GRCh37 v83 +- Write an error message when `--sampleDir` does not find any FASTQ files +- `base.config` for ConcatVCF process +- File specification for recalibrationReport in RecalibrateBam process (got error on AWS Batch) ## [1.2.4] - 2017-10-27 ### `Fixed` -- [#488](https://github.com/SciLifeLab/Sarek/issues/488) - Better CPU requirements for `ConcatVCF` -- [#489](https://github.com/SciLifeLab/Sarek/issues/489) - Exception handling for `ASCAT` -- [#490](https://github.com/SciLifeLab/Sarek/issues/490) - CPU requirements for `runSingleStrelka` and `runSingleManta` +- [#488](https://github.com/SciLifeLab/Sarek/issues/488) - Better CPU requirements for `ConcatVCF` +- [#489](https://github.com/SciLifeLab/Sarek/issues/489) - Exception handling for `ASCAT` +- [#490](https://github.com/SciLifeLab/Sarek/issues/490) - CPU requirements for `runSingleStrelka` and `runSingleManta` ## [1.2.3] - 2017-10-18 ### `Fixed` -- [#357](https://github.com/SciLifeLab/Sarek/issues/357) - `ASCAT` works for GRCh38 -- [#471](https://github.com/SciLifeLab/Sarek/issues/471) - Running `Singularity` on `/scratch` -- [#475](https://github.com/SciLifeLab/Sarek/issues/475) - 16 cpus for local executor -- [#480](https://github.com/SciLifeLab/Sarek/issues/480) - No `tsv` file needed for step `annotate` +- [#357](https://github.com/SciLifeLab/Sarek/issues/357) - `ASCAT` works for GRCh38 +- [#471](https://github.com/SciLifeLab/Sarek/issues/471) - Running `Singularity` on `/scratch` +- [#475](https://github.com/SciLifeLab/Sarek/issues/475) - 16 cpus for local executor +- [#480](https://github.com/SciLifeLab/Sarek/issues/480) - No `tsv` file needed for step `annotate` ## [1.2.2] - 2017-10-06 ### `Fixed` -- [#479](https://github.com/SciLifeLab/Sarek/issues/479) - Typo in `uppmax-localhost.config` +- [#479](https://github.com/SciLifeLab/Sarek/issues/479) - Typo in `uppmax-localhost.config` ## [1.2.1] - 2017-10-06 ### `Changed` -- `runascat` and `runconvertallelecounts` containers are now replaced by `r-base` -- `willmclaren/ensembl-vep:release_90.5` is now base for `vepgrch37` and `vepgrch38` +- `runascat` and `runconvertallelecounts` containers are now replaced by `r-base` +- `willmclaren/ensembl-vep:release_90.5` is now base for `vepgrch37` and `vepgrch38` ### `Removed` -- `vep` container -- `strelka_config.ini` file +- `vep` container +- `strelka_config.ini` file ### `Fixed` -- [#471](https://github.com/SciLifeLab/Sarek/issues/471) - Running `Singularity` on /scratch -- [#472](https://github.com/SciLifeLab/Sarek/issues/472) - Update function to check Nextflow version -- [#473](https://github.com/SciLifeLab/Sarek/issues/473) - Remove `returnMin()` function +- [#471](https://github.com/SciLifeLab/Sarek/issues/471) - Running `Singularity` on /scratch +- [#472](https://github.com/SciLifeLab/Sarek/issues/472) - Update function to check Nextflow version +- [#473](https://github.com/SciLifeLab/Sarek/issues/473) - Remove `returnMin()` function ## [1.2.0] - 2017-10-02 ### `Changed` -- Fix version for Manuscript +- Fix version for Manuscript ## [1.1] - 2017-09-15 ### `Added` -- Singularity possibilities +- Singularity possibilities ### `Changed` -- Reports made by default -- Intervals file can be a bed file -- Normal sample preprocessing + HaplotypeCaller is possible -- Better Travis CI tests +- Reports made by default +- Intervals file can be a bed file +- Normal sample preprocessing + HaplotypeCaller is possible +- Better Travis CI tests ### `Fixed` -- Memory requirements +- Memory requirements ## [1.0] - 2017-02-16 ### `Added` -- Docker possibilities +- Docker possibilities ## [0.9] - 2016-11-16 diff --git a/README.md b/README.md index f2ef9393c4..d5ffd4f7dd 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,6 @@ -# [![Sarek](docs/images/Sarek_logo.png "Sarek")](https://sarek.scilifelab.se/) -[![nf-core](docs/images/nf-core_logo.png "Sarek")](https://nf-co.re/) +# [![Sarek](docs/images/nf-core_sarek_logo.png "Sarek")](https://sarek.scilifelab.se/) -**An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing** - -> :warning: This pipeline is a work in progress being ported to nf-core from [SciLifeLab/Sarek](https://github/SciLifeLab/Sarek/) +> **An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing** [![Nextflow version][nextflow-badge]](https://www.nextflow.io/) [![nf-core][nf-core-badge]](https://nf-co.re/) @@ -17,7 +14,10 @@ [![Join us on Slack][slack-badge]](https://nfcore.slack.com/messages/CGFUX04HZ/) +> :warning: This pipeline is a work in progress being ported to nf-core from [SciLifeLab/Sarek](https://github/SciLifeLab/Sarek/) + ## Introduction + Previously known as the Cancer Analysis Workflow (CAW), @@ -32,6 +32,7 @@ Thus making installation trivial and results highly reproducible. It's listed on the [Elixir - Tools and Data Services Registry](https://bio.tools/Sarek), [Dockstore](https://dockstore.org/workflows/github.com/SciLifeLab/Sarek/) and [omicX - Bioinformatics tools](https://omictools.com/sarek-tool). ## Documentation + The nf-core/sarek pipeline comes with documentation about the pipeline, found in the `docs/` directory: 1. [Installation](https://nf-co.re/usage/installation) @@ -57,10 +58,12 @@ The nf-core/sarek pipeline comes with documentation about the pipeline, found in Sarek was developed at the [National Genomics Infastructure][ngi-link] and [National Bioinformatics Infastructure Sweden][nbis-link] which are both platforms at [SciLifeLab][scilifelab-link], with the support of [The Swedish Childhood Tumor Biobank (Barntumörbanken)][btb-link]. Main authors: + * [Maxime Garcia](https://github.com/MaxUlysse) * [Szilveszter Juhos](https://github.com/szilvajuhos) Helpful contributors: + * [Johannes Alneberg](https://github.com/alneberg) * [Phil Ewels](https://github.com/ewels) * [Jesper Eisfeldt](https://github.com/J35P312) @@ -87,21 +90,20 @@ For further information or help, don't hesitate to get in touch on [Slack](https * [CHANGELOG](CHANGELOG.md) ## Aknowledgements + [![Barntumörbanken](docs/images/BTB_logo.png)](https://ki.se/forskning/barntumorbanken-0) | [![SciLifeLab](docs/images/SciLifeLab_logo.png)](https://scilifelab.se) :-:|:-: [![National Genomics Infrastructure](docs/images/NGI_logo.png)](https://ngisweden.scilifelab.se/) | [![National Bioinformatics Infrastructure Sweden](docs/images/NBIS_logo.png)](https://nbis.se) - ## Citation If you use nf-core/sarek for your analysis, please cite the `Sarek` pre-print as follows: -Garcia MU, Juhos S, Larsson M, Olason PI, Martin M, Eisfeldt J, DiLorenzo S, Sandgren J, de Ståhl TD, Wirta V, Nistér M, Nystedt B, Käller M. **Sarek: A portable workflow for whole-genome sequencing analysis of germline and somatic variants**. *bioRxiv*. 2018. p. 316976. [doi: 10.1101/316976](https://www.biorxiv.org/content/10.1101/316976v1). +> Garcia MU, Juhos S, Larsson M, Olason PI, Martin M, Eisfeldt J, DiLorenzo S, Sandgren J, de Ståhl TD, Wirta V, Nistér M, Nystedt B, Käller M. **Sarek: A portable workflow for whole-genome sequencing analysis of germline and somatic variants**. *bioRxiv*. 2018. p. 316976. [doi: 10.1101/316976](https://www.biorxiv.org/content/10.1101/316976v1). You can cite the sarek zenodo record for a specific version using the following [doi: 10.5281/zenodo.2582812](https://doi.org/10.5281/zenodo.2582812) You can cite the `nf-core` pre-print as follows: -Ewels PA, Peltzer A, Fillinger S, Alneberg JA, Patel H, Wilm A, Garcia MU, Di Tommaso P, Nahnsen S. **nf-core: Community curated bioinformatics pipelines**. *bioRxiv*. 2019. p. 610741. [doi: 10.1101/610741](https://www.biorxiv.org/content/10.1101/610741v3). - +> Ewels PA, Peltzer A, Fillinger S, Alneberg JA, Patel H, Wilm A, Garcia MU, Di Tommaso P, Nahnsen S. **nf-core: Community curated bioinformatics pipelines**. *bioRxiv*. 2019. p. 610741. [doi: 10.1101/610741](https://www.biorxiv.org/content/10.1101/610741v3). [bioconda-badge]: https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4wUJDSc29Eu32QAACDBJREFUWMO1mGtwVOUZx//P875nz16zSxIgASKxI4URbWurDrYzWlr90GIRQZM14aK0oxVn1A86fvKD44eOnVHH6ThgR4cSLiaUFhzsdFov2NJ4+4C3ip2iYkwg2JIEsmd3z57zvu/TD8o9ASLp82nP7tk9v32e//vcCOdpql3B9tjj1+kV6YY4jn+mlb48tvFUxUqY+FBkon0ABgF8xsz9DemG4NBzh9z5PofOCtGmYLfak6F+oki1OnE8s2Hmtv7D/deIyJMCaT3zh8mC8BaB3tBab4+2RL0AkF2RRbAxmDiQLmqYbgO6hRoKucK8KI6iSlT5KxP/2zk3Xym1W0TW+56/u1qr7hFI01n+W1WxetX22BsBQLdrmB4z5o18+hv1d9QDAEy3gSqqZcR0eGT9SK8VuxBAQESjAEIIktbZZxbMWXBEsbqBiGpnAUpZZxdRG8WqXS06BjPrl7PODtR0ZxOG1w/jigevSFAbrbXWbtNK/4bbOFWLa/clVOKP1tprFavXBdJIIOzZv+fKbCo7BKB2Ln2IiLbOvki30mMAMLBuAE13NZ07ZN5t3pLYxDcqVlMJ1CWQvSLSC+BjYjoCh5lKqfeNNVctnLdw/q6PdvU6uO9hAsbM21yPu/UM3Z5ydTXgX+dnxcmAc+7vWumeS2df+kEYhSUAfcaapcxcIaIREcnnM/niJ//95CoRWUBEB4gpEpEYQHIsOZzmrUv5Mk7Jh/KyLmq4f7oTHvI7fNS21JBflZ9Rqpb+wMTTnTgNoCGXyhWDMPgHga6bVT/rjYHhgZsUq6RA9kfPRztPf1DLXS1TDh45uFRErhRIu4hMGf9EEZRSPzXd5s/ZlVkEXcGpIVPtaqcipSMbLSSiQ0QUisi7GT9zf6VWOZDQiXvCLeG6ZEdSh1tCg0VAa2srPnv6MwBAbkUOpY0lAEDhjoKqRtVZ1tqnjDU3jQtFFMpWSZ2A/AGAXiB/ez5VCSsHjDXkaW9XbOLriajf056xsb0qkUisrmyurMssz6C8qXxOjdStqsPohtEvNVn0no5tvGbcfMdqq+2x7cdDll6RbnXWDRlrPnRwZQIFIpIFkNKsD0Xd0QJcgGV+keFaqbbWOHPneHlKs/6h6TFv87TV0ziKooejONICecU5N8+Jm5nQifcF0uBp78Fj30oUExOG0UWN8rNlZ3rMXZ7y/jJunhK7pOXuFuKRykjGOnsZGM9m/Mwa3/M3Q9AV2ej1DfdvKJT3lncfS2BRdzRhINN9IiNbsWuIaLy68f2Dwwez7JybTURzxUm/0grN+ea7AQwyuHn1U6vvLVxW0APrBnCh5hU9pBKpzwFsHTsP4GoRmcHJRNICWDanec5zQTXo7h/unw/Cj40zDwEIj3QdMZgEi7tjlDeWDYHeAeDO5JEUM7dwzdY+Fcht+wb3vWusmZfQiTtvvvzmJUy8J5/K78QkW1Oh6U9ENDLWZ05cM3Ebd4CwAcCQiBgmTilWr13SfEnn3if2hvg/GLVRn4hcNMbxf4i10jc467Szbro4mWmdnSKQpQcOH1gOAINHBycN5HDl8Jd1jDgYR0fNuiHXsHuoNJTxtV/1tIdStcQEuiiIghEAaM43TxpQY7rxGJCzsGPWEj14ZNAj0K2xjQOEcCAoxWpL2kvvKaF0vM5NhqWWp1DdVEVs49w4te0L1qQ3kNAmAFkQEkz8QcpP/ToIg93ZVdnGyYIBgOqmKgqrCzMApMeOmBxkrfS3mPnlXDL3o4yf+dWU9JTOoBLsEMjMMAyXTLagR4PRxQDqxym0gzo2cdXB/a5cK79GoLtFpJWYniOhFhCm1a2s06NHRw1euDCQdGcaSikVhMF3zujDvkpV1tp+ZsV9AN62ztZnk9mGmqk9y+AOEBpSXuq90WCU66fXX7BnKpsrCKNwFoD2cbzzJjMPcNJLlgH8K+kl7wvC4F5r7cVO3DcYPL8Ull70k/7Dw78dxrFGbqKW7EieSHxwj4tIYZxb38wms2UudZWsVnp77OKPBNLGzAdBiK3YFsXqUwBrACC9PJ39OgIPt4R4ZO0jpIv6SWvtsrOMSS8c3XDUMQDEz8c7nHPfdOJgrZ1BoC8AeE5cRiBlbufrIhM9drwNue3cbUimM3P89aN/e/QJY83947YoSr9quk3vKWNQPpN/H0CY8BLvOHFzScgSEZx17zHxXGPNGl3U6/wOf1pduu64KOtW1o0ZHmZWiWJitiqqbWeDISJrus2Np4xByc4kws0h/A7/+lpce0krPWCd9UVkaiFTeLpULYXE1OSsu4aI+jTrt5y4fTOmzNjet7bvlEKZX5WfVg7LS6zY7wJoO2eTz2qx6TE7uZ3hetyJJj/VmQKBWCt9bVANHnJw0xIq8ZKnvVdiG/vW2icdXIti9R8RqXPifAiOAqhopYcBkLGmXiBpAA3jHO3TvfO4bJUHTh6txxwUcytyC6tx9QZn3cWseFkqkWoLwmC7Zj1gnZ0KQuCca7iQNMDg7e73buk5Z3sAaMw2vu3ENTm4orHGIyLvq37FBxARSF0IDBE9fgzmZA2OvWy4vR771+4vr1+1frXH3i1EhHJY/jkzf2ydrQehZp3Nf00Qq5RaLFvlAQDIr8xjtGv0/NYxiWICUXeE6fdM94eHhp8B0BjbeJFiVbLO5iZaVxWrXbbHLjp51TPhhZXf6aO2+ctkqNv1t524TqXU3NjEi88DwhLR6wDe0krviJ+PewFAFRVst/16G7QzxL48p0ITZqyzs4moBYImZm7VWjdBILGNB0WkD8CgiHzOxAN5Px8MdQ2d90rvf5LI8eoQ7hrVAAAAAElFTkSuQmCC [btb-link]: https://ki.se/forskning/barntumorbanken-0 diff --git a/conf/igenomes.config b/conf/igenomes.config index c37c8f84b8..f35979bc3d 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -10,32 +10,32 @@ params { genomes { 'GRCh37' { - acLoci = "${params.igenomes_base}/Annotation/ASCAT/1000G_phase3_20130502_SNP_maf0.3.loci" - acLociGC = "${params.igenomes_base}/Annotation/ASCAT/1000G_phase3_20130502_SNP_maf0.3.loci.gc" - bwaIndex = "${params.igenomes_base}/Sequence/BWAIndex/human_g1k_v37_decoy.fasta.{amb,ann,bwt,pac,sa}" - dbsnp = "${params.igenomes_base}/Annotation/GATKBundle/dbsnp_138.b37.vcf" - dbsnpIndex = "${params.igenomes_base}/Annotation/GATKBundle/dbsnp_138.b37.vcf.idx" - genomeDict = "${params.igenomes_base}/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.dict" - genomeFile = "${params.igenomes_base}/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta" - genomeIndex = "${params.igenomes_base}/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta.fai" - intervals = "${params.igenomes_base}/Annotation/intervals/wgs_calling_regions_CAW.list" - knownIndels = "${params.igenomes_base}/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf" - knownIndelsIndex = "${params.igenomes_base}/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" + acLoci = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/ASCAT/1000G_phase3_20130502_SNP_maf0.3.loci" + acLociGC = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/ASCAT/1000G_phase3_20130502_SNP_maf0.3.loci.gc" + bwaIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/BWAIndex/human_g1k_v37_decoy.fasta.{amb,ann,bwt,pac,sa}" + dbsnp = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/dbsnp_138.b37.vcf" + dbsnpIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/dbsnp_138.b37.vcf.idx" + genomeDict = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.dict" + genomeFile = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta" + genomeIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta.fai" + intervals = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/intervals/wgs_calling_regions_CAW.list" + knownIndels = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf" + knownIndelsIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" snpeffDb = "GRCh37.75" vepCacheVersion = "95" } 'GRCh38' { - acLoci = "${params.igenomes_base}/Annotation/ASCAT/1000G_phase3_GRCh38_maf0.3.loci" - acLociGC = "${params.igenomes_base}/Annotation/ASCAT/1000G_phase3_GRCh38_maf0.3.loci.gc" - bwaIndex = "${params.igenomes_base}/Sequence/BWAIndex/Homo_sapiens_assembly38.fasta.64.{alt,amb,ann,bwt,pac,sa}" - dbsnp = "${params.igenomes_base}/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz" - dbsnpIndex = "${params.igenomes_base}/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz.tbi" - genomeDict = "${params.igenomes_base}/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.dict" - genomeFile = "${params.igenomes_base}/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta" - genomeIndex = "${params.igenomes_base}/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta.fai" - intervals = "${params.igenomes_base}/Annotation/intervals/wgs_calling_regions.hg38.bed" - knownIndels = "${params.igenomes_base}/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" - knownIndelsIndex = "${params.igenomes_base}/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" + acLoci = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/ASCAT/1000G_phase3_GRCh38_maf0.3.loci" + acLociGC = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/ASCAT/1000G_phase3_GRCh38_maf0.3.loci.gc" + bwaIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/BWAIndex/Homo_sapiens_assembly38.fasta.64.{alt,amb,ann,bwt,pac,sa}" + dbsnp = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz" + dbsnpIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz.tbi" + genomeDict = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.dict" + genomeFile = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta" + genomeIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta.fai" + intervals = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/intervals/wgs_calling_regions.hg38.bed" + knownIndels = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" + knownIndelsIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" snpeffDb = "GRCh38.86" vepCacheVersion = "95" } diff --git a/docs/annotation.md b/docs/annotation.md index 718e81b993..8e426e2140 100644 --- a/docs/annotation.md +++ b/docs/annotation.md @@ -3,6 +3,7 @@ ## Tools With Sarek, annotation is done using `snpEff`, `VEP`, or even both consecutively: + - `--tools snpEff` - To annotate using `snpEff` - `--tools VEP` @@ -32,6 +33,7 @@ You need to specify the cache directory using `--snpEff_cache` and `--vep_cache` The cache will only be used when `--annotation_cache` and cache directories are specified (either in command lines or in a configuration file). Example: + ```bash nextflow run nf-core/sarek/main.nf --tools snpEff --step annotate --sample file.vcf.gz --snpEff_cache /Path/To/snpEffCache --annotation_cache nextflow run nf-core/sarek/main.nf --tools VEP --step annotate --sample file.vcf.gz --vep_cache /Path/To/vepCache --annotation_cache @@ -40,11 +42,13 @@ nextflow run nf-core/sarek/main.nf --tools VEP --step annotate --sample file.vcf ## Using VEP CADD plugin To enable the use of the VEP CADD plugin: - - Download the CADD files - - Specify them (either on the command line, like in the example or in a configuration file) - - use the `--cadd_cache` flag + +- Download the CADD files +- Specify them (either on the command line, like in the example or in a configuration file) +- use the `--cadd_cache` flag Example: + ```bash nextflow run nf-core/sarek/main.nf --step annotate --tools VEP --sample file.vcf.gz --cadd_cache \ --cadd_InDels /PathToCADD/InDels.tsv.gz \ @@ -57,6 +61,7 @@ nextflow run nf-core/sarek/main.nf --step annotate --tools VEP --sample file.vcf An helper script has been designed to help downloading CADD files. Such files are meant to be share between multiple users, so this script is mainly meant for people administrating servers, clusters and advanced users. + ```bash nextflow run build.nf --cadd_cache /Path/To/CADDcache --cadd_version --genome ``` @@ -64,9 +69,11 @@ nextflow run build.nf --cadd_cache /Path/To/CADDcache --cadd_version : + - *createGCcontentFile.R* - *createWindowBed.pl* - *GCfileCreation.sh*. + To generate the GC correction file additional files are needed: -- *locifile* described above. -- *reference.fasta* is the genome reference file in fasta format. -The files are descibed in [Genomes and reference files documentation](REFERENCES.md). + +- *locifile* described above +- *reference.fasta* is the genome reference file in fasta format + +The files are descibed in [Genomes and reference files documentation](reference.md) + - *chromosomesizes.txt* is a tab delimited text file containing the size of all chromosomes included in the loci file. -An example file is available in https://github.com/Crick-CancerGenomics/ascat/tree/master/gcProcessing/hg19.chrom.sizes + +An example file is available in #### Modification of createWindowBed.pl for our GRCh37 loci file -The genomc reference file we use in Sarek for GRCh37 is coded without "chr" in the chromosome names, while the genomcd referece file we use in Sarek for GRCh38 includes "chr" in the chromosome names. -The script https://github.com/Crick-CancerGenomics/ascat/tree/master/gcProcessing/createWindowBed.pl assumes that "chr" is included in the chromosome names of the reference file, so a small modification of this script was done for the process to work on our GRCh37 loci file. + +The genomc reference file we use in Sarek for GRCh37 is coded without "chr" in the chromosome names, while the genome reference file we use in Sarek for GRCh38 includes "chr" in the chromosome names. +The script [createWindowBed.pl](https://github.com/Crick-CancerGenomics/ascat/tree/master/gcProcessing/createWindowBed.pl) assumes that `chr` is included in the chromosome names of the reference file, so a small modification of this script was done for the process to work on our GRCh37 loci file. These two lines in createWindowBed.pl generate output (lines 61 and 64): + ```perl (61) print OUT "chr".$tab[1]."\t".$start."\t".$stop."\t".$tab[0]."\t".$tab[2]."\t".($w*2+1)."\n"; (64) print OUT "chr".$tab[1]."\t".$start."\t".$stop."\t".$tab[0]."\t".$tab[2]."\t".($w*2)."\n"; ``` + and were changed to: + ```perl (61) print OUT $tab[1]."\t".$start."\t".$stop."\t".$tab[0]."\t".$tab[2]."\t".($w*2+1)."\n"; (64) print OUT $tab[1]."\t".$start."\t".$stop."\t".$tab[0]."\t".$tab[2]."\t".($w*2)."\n"; ``` + After this modification the script works for our GRCh37 loci file. #### Process + The following sbatch script was run on the Uppmax cluster Rackham, to generate the CG correction files: + ```bash #!/bin/bash -l #SBATCH -A projid @@ -104,35 +119,59 @@ module load R/3.5.0 module load R_packages/3.5.0 ./GCfileCreation.sh 1000G_phase3_20130502_SNP_maf0.3.loci chrom.sizes 19 human_g1k_v37_decoy.fasta ``` + where: -*1000G_phase3_20130502_SNP_maf0.3.loci* is the loci file for GRCh37 described above -*human_g1k_v37_decoy.fasta* is the genome reference file used for GRCh37 -*chrom.sizes* is the list of the chromosome lengths in GRCh37. + +- *1000G_phase3_20130502_SNP_maf0.3.loci* is the loci file for GRCh37 described above +- *human_g1k_v37_decoy.fasta* is the genome reference file used for GRCh37 +- *chrom.sizes* is the list of the chromosome lengths in GRCh37 + Names of the chromosomes in chrom.sizes file must be the same as in the genome reference, so in case of GRCh37 we used "1", "2" etc and in GRCh38 we used "chr1", "chr2" etc. -*19* means that 19 cores are available for the script. + +- *19* means that 19 cores are available for the script. This created GC correction files with the following column headers: -Chr Position 25 50 100 200 500 1000 2000 5000 10000 20000 50000 100000 200000 500000 1M 2M 5M 10M + +```text +Chr Position 25 50 100 200 500 1000 2000 5000 10000 20000 50000 100000 200000 500000 1M 2M 5M 10M +``` + This file gave an error when running ASCAT, and the error message suggested that it had to do with the column headers. -The Readme.txt in https://github.com/Crick-CancerGenomics/ascat/tree/master/gcProcessing suggested that the column headers should be: -Chr Position 25bp 50bp 100bp 200bp 500bp 1000bp 2000bp 5000bp 10000bp 20000bp 50000bp 100000bp 200000bp 500000bp 1M 2M 5M 10M +The Readme.txt in suggested that the column headers should be: + +```text +Chr Position 25bp 50bp 100bp 200bp 500bp 1000bp 2000bp 5000bp 10000bp 20000bp 50000bp 100000bp 200000bp 500000bp 1M 2M 5M 10M +``` + The column headers headers of the generated GC correction files were therefore manually edited. #### Format of GC correction file + The final files are tab-delimited with the following columns (and some example data): -Chr Position 25bp 50bp 100bp 200bp 500bp 1000bp 2000bp 5000bp 10000bp 20000bp 50000bp 100000bp 200000bp 500000bp 1M 2M 5M 10M -snp1 1 14930 0.541667 0.58 0.61 0.585 0.614 0.62 0.6 0.5888 0.588 0.4277 0.395041 0.380702 0.383259 0.341592 0.339747 0.386343 0.500537 0.511514 -snp2 1 15211 0.625 0.64 0.67 0.63 0.61 0.612 0.6135 0.591 0.5922 0.4358 0.39616 0.380411 0.383167 0.34163 0.339771 0.386417 0.500558 0.511511 -snp3 1 15820 0.541667 0.56 0.62 0.655 0.65 0.612 0.5885 0.5936 0.5797 0.4511 0.397771 0.379945 0.382999 0.341791 0.339832 0.386554 0.500579 0.511504 + +```text +Chr Position 25bp 50bp 100bp 200bp 500bp 1000bp 2000bp 5000bp 10000bp 20000bp 50000bp 100000bp 200000bp 500000bp 1M 2M 5M 10M +snp1 1 14930 0.541667 0.58 0.61 0.585 0.614 0.62 0.6 0.5888 0.588 0.4277 0.395041 0.380702 0.383259 0.341592 0.339747 0.386343 0.500537 0.511514 +snp2 1 15211 0.625 0.64 0.67 0.63 0.61 0.612 0.6135 0.591 0.5922 0.4358 0.39616 0.380411 0.383167 0.34163 0.339771 0.386417 0.500558 0.511511 +snp3 1 15820 0.541667 0.56 0.62 0.655 0.65 0.612 0.5885 0.5936 0.5797 0.4511 0.397771 0.379945 0.382999 0.341791 0.339832 0.386554 0.500579 0.511504 +``` ### Output + The ASCAT process gives several images as output, described in detail in this [book chapter](http://www.ncbi.nlm.nih.gov/pubmed/22130873). The script also gives out a text file (*tumor.cnvs.txt*) with information about copy number state for all the segments predicted by ASCAT. -The output is a tab delimited text file with the following columns: chr startpos endpos nMajor nMinor +The output is a tab delimited text file with the following columns: + +```text +chr startpos endpos nMajor nMinor +``` + Where: -*chr* is the chromosome number -*startpos* is the start position of the segment -*endpos* is the end position of the segment -*nMajor* is number of copies of one of the allels (for example the chromosome inherited from the father) -*nMinor* is the number of copies of the other allele (for example the chromosome inherited of the mother) + +- *chr* is the chromosome number +- *startpos* is the start position of the segment +- *endpos* is the end position of the segment +- *nMajor* is number of copies of one of the allels (for example the chromosome inherited from the father) +- *nMinor* is the number of copies of the other allele (for example the chromosome inherited of the mother) + The file *tumor.cnvs.txt* contains all segments predicted by ASCAT, both those with normal copy number (nMinor = 1 and nMajor =1) and those corresponding to copy number aberrations. diff --git a/docs/containers.md b/docs/containers.md index be1c31a85e..fd5de52105 100644 --- a/docs/containers.md +++ b/docs/containers.md @@ -1,9 +1,11 @@ # Containers Our main container is designed using [Conda](https://conda.io/) to install all tools used in Sarek: + - [sarek](#sarek-) For annotation, the main container can be used, but the cache has to be downloaded, or additional containers are available with cache (see [extra annotation documentation](annotation.md)): + - [sareksnpeff](#sareksnpeff-) - [sarekvep](#sarekvep-) @@ -68,17 +70,22 @@ Specify which release to pull or build: any tagged release, or `dev`. Default:`dev` ### Genome: -g + Specify which release genome to use for annotation containers (`sareksnpeff`, `sarekvep`): `GRCh37`, `GRCh38`, `smallGRCh37`, `CanFan3.1`, `GRCm38`. Default:`smallGRCh37` ### Singularity + To specify where to build singularity image, use the Nextflow ENV variable `NXF_SINGULARITY_CACHEDIR`, ie: + ```bash NXF_SINGULARITY_CACHEDIR=/data/singularity ./scripts/download_image.sh -n singularity -t ALL -T dev -g GRCh38 ``` -That will build the main container, plus the annotation containers (`sareksnpeff`, `sarekvep`) for `GRCh38`, in the `/data/singularity` folder + +That will build the main container, plus the annotation containers (`sareksnpeff`, `sarekvep`) for `GRCh38`, in the `/data/singularity` folder. ## Building your own + Our containers are designed using [Conda](https://conda.io/). The `environment.yml` file can easilly be modified if particular versions of tools are more suited to your needs. diff --git a/docs/input.md b/docs/input.md index 3b4502f039..094ca38169 100644 --- a/docs/input.md +++ b/docs/input.md @@ -1,24 +1,27 @@ # Input Documentation ## Information about the TSV files + Input files for Sarek can be specified using a TSV file given to the `--sample` command. The TSV file is a Tab Separated Value file with columns: -* `subject gender status sample lane fastq1 fastq2` for step `mapping` with paired-end FASTQs -* `subject gender status sample lane bam` for step `mapping` with unmapped BAMs -* `subject gender status sample bam bai recaltable` for step `recalibrate` with BAMs -* `subject gender status sample bam bai` for step `variantcalling` with BAMs + +- `subject gender status sample lane fastq1 fastq2` for step `mapping` with paired-end FASTQs +- `subject gender status sample lane bam` for step `mapping` with unmapped BAMs +- `subject gender status sample bam bai recaltable` for step `recalibrate` with BAMs +- `subject gender status sample bam bai` for step `variantcalling` with BAMs The content of these columns is quite straight-forward: -* `subject` designate the subject, it should be the ID of the Patient, and it must design only one patient -* `gender` is the gender of the Patient, (XX or XY) -* `status` is the status of the Patient, (0 for Normal or 1 for Tumor) -* `sample` designate the Sample, it should be the ID of the sample (it is possible to have more than one tumor sample for each patient, i.e. a tumor and a relapse), it must design only one sample -* `lane` is used when the sample is multiplexed on several lanes, it must be unique for each lane in the same sample -* `fastq1` is the path to the first pair of the fastq file -* `fastq2` is the path to the second pair of the fastq file -* `bam` is the bam file -* `bai` is the bam index file -* `recaltable` is the recalibration table + +- `subject` designate the subject, it should be the ID of the Patient, and it must design only one patient +- `gender` is the gender of the Patient, (XX or XY) +- `status` is the status of the Patient, (0 for Normal or 1 for Tumor) +- `sample` designate the Sample, it should be the ID of the sample (it is possible to have more than one tumor sample for each patient, i.e. a tumor and a relapse), it must design only one sample +- `lane` is used when the sample is multiplexed on several lanes, it must be unique for each lane in the same sample +- `fastq1` is the path to the first pair of the fastq file +- `fastq2` is the path to the second pair of the fastq file +- `bam` is the bam file +- `bai` is the bam index file +- `recaltable` is the recalibration table It is recommended to add the absolute path of the files, but relative path should work also. Note, the delimiter is the tab (`\t`) character: @@ -32,11 +35,11 @@ Multiple TSV files can be specified if the path is enclosed in quotes. Somatic variant calling output will be in a specific directory for each normal/tumor pair. -# Example TSV file for a normal/tumor pair with FASTQ files (step mapping) +## Example TSV file for a normal/tumor pair with FASTQ files (step mapping) In this sample for the normal case there are 3 read groups, and 2 for the tumor. -``` +```text G15511 XX 0 C09DFN C09DF_1 pathToFiles/C09DFACXX111207.1_1.fastq.gz pathToFiles/C09DFACXX111207.1_2.fastq.gz G15511 XX 0 C09DFN C09DF_2 pathToFiles/C09DFACXX111207.2_1.fastq.gz pathToFiles/C09DFACXX111207.2_2.fastq.gz G15511 XX 0 C09DFN C09DF_3 pathToFiles/C09DFACXX111207.3_1.fastq.gz pathToFiles/C09DFACXX111207.3_2.fastq.gz @@ -44,7 +47,7 @@ G15511 XX 1 D0ENMT D0ENM_1 pathToFiles/D0ENMACXX111207.1_1.fastq. G15511 XX 1 D0ENMT D0ENM_2 pathToFiles/D0ENMACXX111207.2_1.fastq.gz pathToFiles/D0ENMACXX111207.2_2.fastq.gz ``` -# Path to a FASTQ directory for a single normal sample (step mapping) +## Path to a FASTQ directory for a single normal sample (step mapping) Input files for Sarek can be specified using the path to a FASTQ directory given to the `--sample` command only with the `mapping` step. @@ -52,12 +55,12 @@ Input files for Sarek can be specified using the path to a FASTQ directory given nextflow run nf-core/sarek --sample pathToDirectory ... ``` -## Input FASTQ file name best practices +### Input FASTQ file name best practices The input folder, containing the FASTQ files for one individual (ID) should be organized into one subfolder for every sample. All fastq files for that sample should be collected here. -``` +```text ID +--sample1 +------sample1_lib_flowcell-index_lane_R1_1000.fastq.gz @@ -93,11 +96,11 @@ Read group information will be parsed from fastq file names according to this: - `PU` = sample - `RGLB` = lib -# Example TSV file for a normal/tumor pair with uBAM files (step mapping) +## Example TSV file for a normal/tumor pair with uBAM files (step mapping) In this sample for the normal case there are 3 read groups, and 2 for the tumor. -``` +```text G15511 XX 0 C09DFN C09DF_1 pathToFiles/C09DFAC_1.bam G15511 XX 0 C09DFN C09DF_2 pathToFiles/C09DFAC_2.bam G15511 XX 0 C09DFN C09DF_3 pathToFiles/C09DFAC_3.bam @@ -105,25 +108,25 @@ G15511 XX 1 D0ENMT D0ENM_1 pathToFiles/D0ENMAC_1.bam G15511 XX 1 D0ENMT D0ENM_2 pathToFiles/D0ENMAC_2.bam ``` -# Example TSV file for a normal/tumor pair with non recalibrated BAM files (step recalibrate) +## Example TSV file for a normal/tumor pair with non recalibrated BAM files (step recalibrate) The same way, if you have non recalibrated BAMs, their indexes and their recalibration tables, you should use a structure like: -``` +```text G15511 XX 0 C09DFN pathToFiles/G15511.C09DFN.md.bam pathToFiles/G15511.C09DFN.md.bai pathToFiles/G15511.C09DFN.md.recal.table G15511 XX 1 D0ENMT pathToFiles/G15511.D0ENMT.md.bam pathToFiles/G15511.D0ENMT.md.bai pathToFiles/G15511.D0ENMT.md.recal.table ``` -# Example TSV file for a normal/tumor pair with recalibrated BAM files (step variantcalling) +## Example TSV file for a normal/tumor pair with recalibrated BAM files (step variantcalling) The same way, if you have recalibrated BAMs and their indexes, you should use a structure like: -``` +```text G15511 XX 0 C09DFN pathToFiles/G15511.C09DFN.md.recal.bam pathToFiles/G15511.C09DFN.md.recal.bai G15511 XX 1 D0ENMT pathToFiles/G15511.D0ENMT.md.recal.bam pathToFiles/G15511.D0ENMT.md.recal.bai ``` -# VCF files for annotation +## VCF files for annotation Input files for Sarek can be specified using the path to a VCF directory given to the `--sample` command only with the `annotate` step. Multiple VCF files can be specified if the path is enclosed in quotes. diff --git a/docs/output.md b/docs/output.md index 2987103493..105010936c 100644 --- a/docs/output.md +++ b/docs/output.md @@ -3,6 +3,7 @@ This document describes the output produced by the pipeline. ## Pipeline overview + The pipeline processes data using the following steps: 1. [**Preprocessing**](#Preprocessing) _(based on [GATK best practices](https://software.broadinstitute.org/gatk/best-practices/))_ @@ -218,6 +219,7 @@ For a Tumor/Normal pair only: * file with total copy number on a logarithmic scale ### ASCAT + [ASCAT](https://github.com/Crick-CancerGenomics/ascat) is a method to derive copy number profiles of tumor cells, accounting for normal cell admixture and tumor aneuploidy. ASCAT infers tumor purity and ploidy and calculates whole-genome allele-specific copy number profiles. @@ -246,16 +248,19 @@ For a Tumor/Normal pair only: * file with information about purity ploidy ### mpileup + [samtools mpileup](https://www.htslib.org/doc/samtools.html) generate pileup for a BAM file. For further reading and documentation see the [samtools manual](https://www.htslib.org/doc/samtools.html#COMMANDS_AND_OPTIONS). For all samples: **Output directory: `results/VariantCalling/[SAMPLE]/mpileup`** + * `[SAMPLE].pileup.gz` * The pileup format is a text-based format for summarizing the base calls of aligned reads to a reference sequence. Alignment records are grouped by sample (SM) identifiers in @RG header lines. ### Control-FREEC + [Control-FREEC](https://github.com/BoevaLab/FREEC) is a tool for detection of copy-number changes and allelic imbalances (including LOH) using deep-sequencing data. Control-FREEC automatically computes, normalizes, segments copy number and beta allele frequency profiles, then calls copy number alterations and LOH. And also detects subclonal gains and losses and evaluate the likeliest average ploidy of the sample. @@ -264,6 +269,7 @@ For further reading and documentation see the [Control-FREEC manual](http://boev For a Tumor/Normal pair only: **Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/ControlFREEC`** + * `[TUMORSAMPLE]_vs_[NORMALSAMPLE].config.txt` * Configuration file used to run Control-FREEC * `[TUMORSAMPLE].pileup.gz_CNVs` and `[TUMORSAMPLE].pileup.gz_normal_CNVs` @@ -281,6 +287,7 @@ FreeBayes results are not annotated in the moment yet as we are lacking a decent For HaplotypeCaller the germline variations are annotated for both the tumor and the normal sample. ### snpEff + [snpeff](http://snpeff.sourceforge.net/) is a genetic variant annotation and effect prediction toolbox. It annotates and predicts the effects of variants on genes (such as amino acid changes) using multiple databases for annotations. The generated VCF header contains the software version and the used command line. @@ -294,10 +301,12 @@ For all samples: * VCF with Tabix index ### VEP + [VEP (Variant Effect Predictor)](https://www.ensembl.org/info/docs/tools/vep/index.html), based on Ensembl, is a tools to determine the effects of all sorts of variants, including SNPs, indels, structural variants, CNVs. The generated VCF header contains the software version, also the version numbers for additional databases like Clinvar or dbSNP used in the "VEP" line. The format of the [consequence annotations](https://www.ensembl.org/info/genome/variation/prediction/predicted_data.html) is also in the VCF header describing the INFO field. In the moment it contains: + * Consequence: impact of the variation, if there is any * Codons: the codon change, i.e. cGt/cAt * Amino_acids: change in amino acids, i.e. R/H if there is any @@ -321,6 +330,7 @@ For all samples: ## QC and reporting ### FastQC + [FastQC](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/) gives general quality metrics about your reads. It provides information about the quality score distribution across your reads, the per base sequence content (%T/A/G/C). You get information about adapter contamination and other overrepresented sequences. @@ -336,19 +346,23 @@ For all samples: * zip file containing the FastQC reports, tab-delimited data files and plot images ### bamQC + [Qualimap bamqc](http://qualimap.bioinfo.cipf.es/) reports information for the evaluation of the quality of the provided alignment data. In short, the basic statistics of the alignment (number of reads, coverage, GC-content, etc.) are summarized and a number of useful graphs are produced. Plot will show: + * Stats by non-reference allele frequency, depth distribution, stats by quality and per-sample counts, singleton stats, etc. For all samples: **Output directory: `results/Reports/[SAMPLE]/bamQC`** + * `VariantCaller_[SAMPLE].bcf.tools.stats.out` * RAW statistics used by MultiQC For more information about how to use Qualimap bamqc reports, see [Qualimap bamqc manual](http://qualimap.bioinfo.cipf.es/doc_html/analysis.html#id7) ### MarkDuplicates reports + [GATK MarkDuplicates](https://github.com/broadinstitute/gatk) locates and tags duplicate reads in a BAM or SAM file, where duplicate reads are defined as originating from a single fragment of DNA. Duplicates can arise during sample preparation e.g. library construction using PCR. @@ -357,44 +371,54 @@ These duplication artifacts are referred to as optical duplicates. For all samples: **Output directory: `results/Reports/[SAMPLE]/MarkDuplicates`** + * `[SAMPLE].bam.metrics` * RAW statistics used by MultiQC For further reading and documentation see the [MarkDuplicates manual](https://software.broadinstitute.org/gatk/documentation/tooldocs/4.1.2.0/picard_sam_markduplicates_MarkDuplicates.php). ### samtools stats + [samtools stats](https://www.htslib.org/doc/samtools.html) collects statistics from BAM files and outputs in a text format. Plots will show: + * Alignment metrics. For all samples: **Output directory: `results/Reports/[SAMPLE]/SamToolsStats`** + * `[SAMPLE].bam.samtools.stats.out` * RAW statistics used by MultiQC For further reading and documentation see the [samtools manual](https://www.htslib.org/doc/samtools.html#COMMANDS_AND_OPTIONS) ### bcftools stats + [bcftools](https://samtools.github.io/bcftools/) is a program for variant calling and manipulating files in the Variant Call Format. Plot will show: + * Stats by non-reference allele frequency, depth distribution, stats by quality and per-sample counts, singleton stats, etc. For all samples: **Output directory: `results/Reports/[SAMPLE]/BCFToolsStats`** + * `VariantCaller_[SAMPLE].bcf.tools.stats.out` * RAW statistics used by MultiQC For further reading and documentation see the [bcftools stats manual](https://samtools.github.io/bcftools/bcftools.html#stats) ### VCFtools + [VCFtools](https://vcftools.github.io/) is a program package designed for working with VCF files. Plots will show: + * the summary counts of each type of transition to transversion ratio for each FILTER category. * the transition to transversion ratio as a function of alternative allele count (using only bi-allelic SNPs). * the transition to transversion ratio as a function of SNP quality threshold (using only bi-allelic SNPs). For all samples: **Output directory: `results/Reports/[SAMPLE]/VCFTools`** + * `VariantCaller_[SAMPLE].FILTER.summary` * RAW statistics used by MultiQC * `VariantCaller_[SAMPLE].TsTv.count` @@ -405,10 +429,12 @@ For all samples: For further reading and documentation see the [VCFtools manual](https://vcftools.github.io/man_latest.html#OUTPUT%20OPTIONS) ### snpEff reports + [snpeff](http://snpeff.sourceforge.net/) is a genetic variant annotation and effect prediction toolbox. It annotates and predicts the effects of variants on genes (such as amino acid changes) using multiple databases for annotations. Plots will shows : + * locations of detected variants in the genome and the number of variants for each location. * the putative impact of detected variants and the number of variants for each impact. * the effect of variants at protein level and the number of variants for each effect type. @@ -416,6 +442,7 @@ Plots will shows : For all samples: **Output directory: `results/Reports/[SAMPLE]/snpEff`** + * `VariantCaller_Sample_snpEff.csv` * RAW statistics used by MultiQC * `VariantCaller_Sample_snpEff.html` @@ -426,16 +453,19 @@ For all samples: For further reading and documentation see the [snpEff manual](http://snpeff.sourceforge.net/SnpEff_manual.html#outputSummary) ### VEP reports + [VEP (Variant Effect Predictor)](https://www.ensembl.org/info/docs/tools/vep/index.html), based on Ensembl, is a tools to determine the effects of all sorts of variants, including SNPs, indels, structural variants, CNVs. For all samples: **Output directory: `results/Reports/[SAMPLE]/VEP`** + * `VariantCaller_Sample_VEP.summary.html` * Summary of the VEP run to be visualised with a web browser For further reading and documentation see the [VEP manual](https://www.ensembl.org/info/docs/tools/vep/index.html) ### MultiQC + [MultiQC](http://multiqc.info) is a visualisation tool that generates a single HTML report summarising all samples in your project. Most of the pipeline QC results are visualised in the report and further statistics are available in within the report data directory. diff --git a/docs/reference.md b/docs/reference.md index 0dc33be6a5..1d5d10c729 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1,6 +1,7 @@ # Genomes and reference files ## AWS iGenomes + Sarek is using [AWS iGenomes](https://ewels.github.io/AWS-iGenomes/), which facilitate storing and sharing references. Sarek currently uses `GRCh38` by default. Both `GRCh37` and `GRCh38` are available with `--genome GRCh37` or `--genome GRCh38` respectively with any profile using the `conf/igenomes.config` file, or you can specify it with `-c conf/igenomes.config`. @@ -40,6 +41,6 @@ Actual figures vary from 2 nucleotides/second to 30000 nucleotides/second. The [`build.nf`](#buildnf) script is used to build reference needed for smallGRCh37. -``` +```bash nextflow run build.nf ``` diff --git a/docs/usage.md b/docs/usage.md index 48d5864794..29b239294c 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -59,22 +59,29 @@ ## Introduction -Nextflow handles job submissions on SLURM or other environments, and supervises running the jobs. Thus the Nextflow process must run until the pipeline is finished. We recommend that you put the process running in the background through `screen` / `tmux` or similar tool. Alternatively you can run nextflow within a cluster job submitted your job scheduler. -It is recommended to limit the Nextflow Java virtual machines memory. We recommend adding the following line to your environment (typically in `~/.bashrc` or `~./bash_profile`): +Nextflow handles job submissions on SLURM or other environments, and supervises running the jobs. +Thus the Nextflow process must run until the pipeline is finished. +We recommend that you put the process running in the background through `screen` / `tmux` or similar tool. +Alternatively you can run nextflow within a cluster job submitted your job scheduler. + +It is recommended to limit the Nextflow Java virtual machines memory. +We recommend adding the following line to your environment (typically in `~/.bashrc` or `~./bash_profile`): ```bash NXF_OPTS='-Xms1g -Xmx4g' ``` ## Running the pipeline + The typical command for running the pipeline is as follows: ```bash nextflow run nf-core/sarek --sample sample.tsv -profile docker ``` -This will launch the pipeline with the `docker` configuration profile. See below for more information about profiles. +This will launch the pipeline with the `docker` configuration profile. +See below for more information about profiles. Note that the pipeline will create the following files in your working directory: @@ -90,23 +97,33 @@ The nf-core/sarek pipeline comes with more documentation about running the pipel * [Extra Documentation on annotation](docs/annotation.md) ### Updating the pipeline -When you run the above command, Nextflow automatically pulls the pipeline code from GitHub and stores it as a cached version. When running the pipeline after this, it will always use the cached version if available - even if the pipeline has been updated since. To make sure that you're running the latest version of the pipeline, make sure that you regularly update the cached version of the pipeline: + +When you run the above command, Nextflow automatically pulls the pipeline code from GitHub and stores it as a cached version. +When running the pipeline after this, it will always use the cached version if available - even if the pipeline has been updated since. +To make sure that you're running the latest version of the pipeline, make sure that you regularly update the cached version of the pipeline: ```bash nextflow pull nf-core/sarek ``` ### Reproducibility -It's a good idea to specify a pipeline version when running the pipeline on your data. This ensures that a specific version of the pipeline code and software are used when you run your pipeline. If you keep using the same tag, you'll be running the same version of the pipeline, even if there have been changes to the code since. -First, go to the [nf-core/sarek releases page](https://github.com/nf-core/sarek/releases) and find the latest version number - numeric only (eg. `2.5.0`). Then specify this when running the pipeline with `-r` (one hyphen) - eg. `-r 2.5.0`. +It's a good idea to specify a pipeline version when running the pipeline on your data. +This ensures that a specific version of the pipeline code and software are used when you run your pipeline. +If you keep using the same tag, you'll be running the same version of the pipeline, even if there have been changes to the code since. + +First, go to the [nf-core/sarek releases page](https://github.com/nf-core/sarek/releases) and find the latest version number - numeric only (eg. `2.5.0`). +Then specify this when running the pipeline with `-r` (one hyphen) - eg. `-r 2.5.0`. This version number will be logged in reports when you run the pipeline, so that you'll know what you used when you look back in the future. ## Main arguments ### `-profile` -Use this parameter to choose a configuration profile. Profiles can give configuration presets for different compute environments. Note that multiple profiles can be loaded, for example: `-profile docker` - the order of arguments is important! + +Use this parameter to choose a configuration profile. +Profiles can give configuration presets for different compute environments. +Note that multiple profiles can be loaded, for example: `-profile docker` - the order of arguments is important! If `-profile` is not specified at all the pipeline will be run locally and expects all software to be installed and available on the `PATH`. @@ -125,14 +142,15 @@ If `-profile` is not specified at all the pipeline will be run locally and expec * A profile with a complete configuration for automated testing * Includes links to test data so needs no other parameters - ### `--sample` + Use this to specify the location of your input TSV file, on `mapping`, `recalibrate` and `variantcalling` steps. For example: ```bash --sample sample.tsv ``` + Multiple TSV files can be specified if the path must be enclosed in quotes Use this to specify the location to a directory on `mapping` step with a single germline sample only. @@ -148,46 +166,59 @@ For example: ```bash --sample sample.vcf ``` + Multiple VCF files can be specified if the path must be enclosed in quotes ### `--noGVCF` + Use this to disable g.vcf from `HaplotypeCaller`. ### `--noReports` + Use this to disable all QC an Reporting tools. ### `--nucleotidesPerSecond` + Use this to estimate of how many seconds it will take to call variants on any interval, the default value is `1000` is it's not specified in the `.bed` file. ### `--step` + Use this to specify the starting step: Default `mapping` Available: `mapping`, `recalibrate`, `variantcalling` and `annotate` ### `--tools` + Use this to specify the tools to run: Available: `ASCAT`, `ControlFREEC`, `FreeBayes`, `HaplotypeCaller`, `Manta`, `mpileup`, `MuTect2`, `Strelka` ### `--noStrelkaBP` + Use this not to use `Manta` `candidateSmallIndels` for `Strelka` as Best Practice. ### `--targetBED` + Use this to specify the target BED file for targeted or whole exome sequencing. ## Reference genomes -The pipeline config files come bundled with paths to the illumina iGenomes reference index files. If running with docker or AWS, the configuration is set up to use the [AWS-iGenomes](https://ewels.github.io/AWS-iGenomes/) resource. +The pipeline config files come bundled with paths to the illumina iGenomes reference index files. +If running with docker or AWS, the configuration is set up to use the [AWS-iGenomes](https://ewels.github.io/AWS-iGenomes/) resource. ### `--genome` (using iGenomes) -There are 2 different species supported by Sarek in the iGenomes references. To run the pipeline, you must specify which to use with the `--genome` flag. -You can find the keys to specify the genomes in the [iGenomes config file](../conf/igenomes.config). Genomes that are supported are: +There are 2 different species supported by Sarek in the iGenomes references. +To run the pipeline, you must specify which to use with the `--genome` flag. + +You can find the keys to specify the genomes in the [iGenomes config file](../conf/igenomes.config). +Genomes that are supported are: * Human * `--genome GRCh37` * `--genome GRCh38` -Note that you can use the same configuration setup to save sets of reference files for your own use, even if they are not part of the iGenomes resource. See the [Nextflow documentation](https://www.nextflow.io/docs/latest/config.html) for instructions on where to save such a file. +Note that you can use the same configuration setup to save sets of reference files for your own use, even if they are not part of the iGenomes resource. +See the [Nextflow documentation](https://www.nextflow.io/docs/latest/config.html) for instructions on where to save such a file. The syntax for this reference configuration is as follows: @@ -215,6 +246,7 @@ params { ``` ### `--acLoci` + If you prefer, you can specify the full path to your reference genome when you run the pipeline: ```bash @@ -222,6 +254,7 @@ If you prefer, you can specify the full path to your reference genome when you r ``` ### `--acLociGC` + If you prefer, you can specify the full path to your reference genome when you run the pipeline: ```bash @@ -229,6 +262,7 @@ If you prefer, you can specify the full path to your reference genome when you r ``` ### `--bwaIndex` + If you prefer, you can specify the full path to your reference genome when you run the pipeline: ```bash @@ -236,6 +270,7 @@ If you prefer, you can specify the full path to your reference genome when you r ``` ### `--dbsnp` + If you prefer, you can specify the full path to your reference genome when you run the pipeline: ```bash @@ -243,6 +278,7 @@ If you prefer, you can specify the full path to your reference genome when you r ``` ### `--dbsnpIndex` + If you prefer, you can specify the full path to your reference genome when you run the pipeline: ```bash @@ -250,6 +286,7 @@ If you prefer, you can specify the full path to your reference genome when you r ``` ### `--genomeDict` + If you prefer, you can specify the full path to your reference genome when you run the pipeline: ```bash @@ -257,6 +294,7 @@ If you prefer, you can specify the full path to your reference genome when you r ``` ### `--genomeFile` + If you prefer, you can specify the full path to your reference genome when you run the pipeline: ```bash @@ -264,6 +302,7 @@ If you prefer, you can specify the full path to your reference genome when you r ``` ### `--genomeIndex` + If you prefer, you can specify the full path to your reference genome when you run the pipeline: ```bash @@ -271,6 +310,7 @@ If you prefer, you can specify the full path to your reference genome when you r ``` ### `--intervals` + If you prefer, you can specify the full path to your reference genome when you run the pipeline: ```bash @@ -278,6 +318,7 @@ If you prefer, you can specify the full path to your reference genome when you r ``` ### `--knownIndels` + If you prefer, you can specify the full path to your reference genome when you run the pipeline: ```bash @@ -285,6 +326,7 @@ If you prefer, you can specify the full path to your reference genome when you r ``` ### `--knownIndelsIndex` + If you prefer, you can specify the full path to your reference genome when you run the pipeline: ```bash @@ -292,6 +334,7 @@ If you prefer, you can specify the full path to your reference genome when you r ``` ### `--snpeffDb` + If you prefer, you can specify the DB version when you run the pipeline: ```bash @@ -299,6 +342,7 @@ If you prefer, you can specify the DB version when you run the pipeline: ``` ### `--vepCacheVersion` + If you prefer, you can specify the cache version when you run the pipeline: ```bash @@ -306,54 +350,81 @@ If you prefer, you can specify the cache version when you run the pipeline: ``` ### `--igenomesIgnore` -Do not load `igenomes.config` when running the pipeline. You may choose this option if you observe clashes between custom parameters and those supplied in `igenomes.config`. + +Do not load `igenomes.config` when running the pipeline. +You may choose this option if you observe clashes between custom parameters and those supplied in `igenomes.config`. ## Job resources + ### Automatic resubmission -Each step in the pipeline has a default set of requirements for number of CPUs, memory and time. For most of the steps in the pipeline, if the job exits with an error code of `143` (exceeded requested resources) it will automatically resubmit with higher requests (2 x original, then 3 x original). If it still fails after three times then the pipeline is stopped. + +Each step in the pipeline has a default set of requirements for number of CPUs, memory and time. +For most of the steps in the pipeline, if the job exits with an error code of `143` (exceeded requested resources) it will automatically resubmit with higher requests (2 x original, then 3 x original). +If it still fails after three times then the pipeline is stopped. ### Custom resource requests -Wherever process-specific requirements are set in the pipeline, the default value can be changed by creating a custom config file. See the files hosted at [`nf-core/configs`](https://github.com/nf-core/configs/tree/master/conf) for examples. -If you are likely to be running `nf-core` pipelines regularly it may be a good idea to request that your custom config file is uploaded to the `nf-core/configs` git repository. Before you do this please can you test that the config file works with your pipeline of choice using the `-c` parameter (see definition below). You can then create a pull request to the `nf-core/configs` repository with the addition of your config file, associated documentation file (see examples in [`nf-core/configs/docs`](https://github.com/nf-core/configs/tree/master/docs)), and amending [`nfcore_custom.config`](https://github.com/nf-core/configs/blob/master/nfcore_custom.config) to include your custom profile. +Wherever process-specific requirements are set in the pipeline, the default value can be changed by creating a custom config file. +See the files hosted at [`nf-core/configs`](https://github.com/nf-core/configs/tree/master/conf) for examples. + +If you are likely to be running `nf-core` pipelines regularly it may be a good idea to request that your custom config file is uploaded to the `nf-core/configs` git repository. +Before you do this please can you test that the config file works with your pipeline of choice using the `-c` parameter (see definition below). +You can then create a pull request to the `nf-core/configs` repository with the addition of your config file, associated documentation file (see examples in [`nf-core/configs/docs`](https://github.com/nf-core/configs/tree/master/docs)), and amending [`nfcore_custom.config`](https://github.com/nf-core/configs/blob/master/nfcore_custom.config) to include your custom profile. If you have any questions or issues please send us a message on [Slack](https://nf-core-invite.herokuapp.com/). ## AWS Batch specific parameters -Running the pipeline on AWS Batch requires a couple of specific parameters to be set according to your AWS Batch configuration. Please use the `-awsbatch` profile and then specify all of the following parameters. + +Running the pipeline on AWS Batch requires a couple of specific parameters to be set according to your AWS Batch configuration. +Please use the `-awsbatch` profile and then specify all of the following parameters. + ### `--awsqueue` + The JobQueue that you intend to use on AWS Batch. + ### `--awsregion` -The AWS region to run your job in. Default is set to `eu-west-1` but can be adjusted to your needs. + +The AWS region to run your job in. +Default is set to `eu-west-1` but can be adjusted to your needs. Please make sure to also set the `-w/--work-dir` and `--outdir` parameters to a S3 storage bucket of your choice - you'll get an error message notifying you if you didn't. ## Other command line parameters ### `--outdir` + The output directory where the results will be saved. ### `--sequencing_center` + The sequencing center that will be used in the BAM CN field ### `--email` -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. + +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. ### `-name` -Name for the pipeline run. If not specified, Nextflow will automatically generate a random mnemonic. + +Name for the pipeline run. +If not specified, Nextflow will automatically generate a random mnemonic. This is used in the MultiQC report (if not default) and in the summary HTML / e-mail (always). **NB:** Single hyphen (core Nextflow option) ### `-resume` -Specify this when restarting a pipeline. Nextflow will used cached results from any pipeline steps where the inputs are the same, continuing from where it got to previously. -You can also supply a run name to resume a specific run: `-resume [run-name]`. Use the `nextflow log` command to show previous run names. +Specify this when restarting a pipeline. +Nextflow will used cached results from any pipeline steps where the inputs are the same, continuing from where it got to previously. + +You can also supply a run name to resume a specific run: `-resume [run-name]`. +Use the `nextflow log` command to show previous run names. **NB:** Single hyphen (core Nextflow option) ### `-c` + Specify the path to a specific config file (this is a core NextFlow command). **NB:** Single hyphen (core Nextflow option) @@ -361,7 +432,10 @@ Specify the path to a specific config file (this is a core NextFlow command). Note - you can use this to override pipeline defaults. ### `--custom_config_version` -Provide git commit id for custom Institutional configs hosted at `nf-core/configs`. This was implemented for reproducibility purposes. Default is set to `master`. + +Provide git commit id for custom Institutional configs hosted at `nf-core/configs`. +This was implemented for reproducibility purposes. +Default is set to `master`. ```bash ## Download and use config file with following git commid id @@ -369,10 +443,12 @@ Provide git commit id for custom Institutional configs hosted at `nf-core/config ``` ### `--custom_config_base` + If you're running offline, nextflow will not be able to fetch the institutional config files -from the internet. If you don't need them, then this is not a problem. If you do need them, -you should download the files from the repo and tell nextflow where to find them with the -`custom_config_base` option. For example: +from the internet. +If you don't need them, then this is not a problem. +If you do need them, you should download the files from the repo and tell nextflow where to find them with the `custom_config_base` option. +For example: ```bash ## Download and unzip the config files @@ -389,22 +465,28 @@ nextflow run /path/to/pipeline/ --custom_config_base /path/to/my/configs/configs > files + singularity containers + institutional configs in one go for you, to make this process easier. ### `--max_memory` + Use to set a top-limit for the default memory requirement for each process. -Should be a string in the format integer-unit. eg. `--max_memory '8.GB'` +Should be a string in the format integer-unit eg. `--max_memory '8.GB'` ### `--max_time` + Use to set a top-limit for the default time requirement for each process. -Should be a string in the format integer-unit. eg. `--max_time '2.h'` +Should be a string in the format integer-unit eg. `--max_time '2.h'` ### `--max_cpus` + Use to set a top-limit for the default CPU requirement for each process. -Should be a string in the format integer-unit. eg. `--max_cpus 1` +Should be a string in the format integer-unit eg. `--max_cpus 1` ### `--plaintext_email` + Set to receive plain-text e-mails instead of HTML formatted. ### `--monochrome_logs` + Set to disable colourful command line output and live life in monochrome. ### `--multiqc_config` + Specify a path to a custom MultiQC configuration file. diff --git a/docs/use_cases.md b/docs/use_cases.md index 894343f37c..c47ad93387 100644 --- a/docs/use_cases.md +++ b/docs/use_cases.md @@ -24,7 +24,8 @@ nextflow run nf-core/sarek/main.nf --sample mysample.tsv --tools ``` The TSV file should look like: -``` + +```text SUBJECT_ID XX 0 SAMPLE_ID 1 /samples/normal_1.fastq.gz /samples/normal_2.fastq.gz ``` @@ -33,9 +34,11 @@ See the [input files documentation](docs/input.md) for more information. ## Starting from raw FASTQ - a directory with normal sample only The `--sample` option can be also used to point Sarek to a directory with FASTQ files: + ```bash nextflow run nf-core/sarek/main.nf --sample path/to/FASTQ/files --tools ``` + The given directory is searched recursively for FASTQ files that are named `*_R1_*.fastq.gz`, and a matching pair with the same name except `_R2_` instead of `_R1_` is expected to exist alongside. All of the found FASTQ files are considered to belong to the sample. Each FASTQ file pair gets its own read group (`@RG`) in the resulting BAM file. @@ -60,7 +63,7 @@ This is captured in the TSV file only in the following manner, adding read group All lanes belonging to the same Sample will be merged together after the FASTQ pairs are mapped to the reference genome. Obviously, if you do not have relapse samples, you can leave out the two last lines. -``` +```text SUBJECT_ID XX 0 SAMPLE_ID_N 1 /samples/normal1_1.fastq.gz /samples/normal1_2.fastq.gz SUBJECT_ID XX 0 SAMPLE_ID_N 2 /samples/normal2_1.fastq.gz /samples/normal2_2.fastq.gz SUBJECT_ID XX 1 SAMPLE_ID_T 3 /samples/tumor3_1.fastq.gz /samples/tumor3_2.fastq.gz @@ -81,7 +84,7 @@ nextflow run nf-core/sarek/main.nf --sample mysample.tsv --step recalibrate --to And the corresponding TSV file should be like: Obviously, if you do not have tumor or relapse samples, you can leave out the two last lines. -``` +```text SUBJECT_ID XX 0 SAMPLE_ID_N /samples/SAMPLE_ID_N.bam /samples/SAMPLE_ID_N.bai /samples/SAMPLE_ID_N.recal.table SUBJECT_ID XX 1 SAMPLE_ID_T /samples/SAMPLE_ID_T.bam /samples/SAMPLE_ID_T.bai /samples/SAMPLE_ID_T.recal.table SUBJECT_ID XX 1 SAMPLE_ID_R /samples/SAMPLE_ID_R.bam /samples/SAMPLE_ID_R.bai /samples/SAMPLE_ID_R.recal.table @@ -99,7 +102,7 @@ nextflow run nf-core/sarek/main.nf --step variantcalling --tools And the corresponding TSV file should be like: -``` +```text SUBJECT_ID XX 0 SAMPLE_ID_N /samples/SAMPLE_ID_N.bam /samples/SAMPLE_ID_N.bai SUBJECT_ID XX 1 SAMPLE_ID_T /samples/SAMPLE_ID_T.bam /samples/SAMPLE_ID_T.bai SUBJECT_ID XX 1 SAMPLE_ID_R /samples/SAMPLE_ID_R.bam /samples/SAMPLE_ID_R.bai From d0f03fe78325a202c93a082b9da0719444c783c1 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Wed, 7 Aug 2019 10:41:37 +0200 Subject: [PATCH 025/854] Add Tiddit (#10) * add tiddit to container * add process for TIDDIT * update TIDDIT to 2.7.1 * fix merge issues * feat: add tests for TIDDIT * feat: update CHANGELOG * feat: Add documentation for TIDDIT * fix: arrange TIDDIT output * feat: filter out low quality calls from TIDDIT * feat: complete TIDDIT docs * fix: syntac error, bad grep --- CHANGELOG.md | 15 ++++----- docs/containers.md | 2 ++ docs/output.md | 43 +++++++++++++++++++++++-- environment.yml | 1 + main.nf | 75 ++++++++++++++++++++++++++++++++++++-------- scripts/run_tests.sh | 6 ++-- 6 files changed, 117 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 910f48ef5b..a5cf4380c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,13 +12,13 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) ### `Added` - [#2](https://github.com/nf-core/sarek/pull/2) - Create `nf-core/sarek` `environment.yml` file -- [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#7](https://github.com/nf-core/sarek/pull/7), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Add CI for `nf-core/sarek` +- [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#7](https://github.com/nf-core/sarek/pull/7), [#9](https://github.com/nf-core/sarek/pull/9), [#10](https://github.com/nf-core/sarek/pull/10), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Add CI for `nf-core/sarek` - [#3](https://github.com/nf-core/sarek/pull/3) - Add preprocessing to `nf-core/sarek` - [#4](https://github.com/nf-core/sarek/pull/4) - Add variant calling to `nf-core/sarek` with `HaplotypeCaller`, and single mode `Manta` and `Strelka` - [#5](https://github.com/nf-core/sarek/pull/5) - Add variant calling to `nf-core/sarek` with `Manta`, `Strelka`, `Strelka Best Practices`, `MuTecT2`, `FreeBayes`, `ASCAT`, `ControlFREEC` - [#6](https://github.com/nf-core/sarek/pull/6) - Add default containers for annotation to `nf-core/sarek` -- [#7](https://github.com/nf-core/sarek/pull/7) - Add annotation - [#7](https://github.com/nf-core/sarek/pull/7) - Add MultiQC +- [#7](https://github.com/nf-core/sarek/pull/7) - Add annotation - [#7](https://github.com/nf-core/sarek/pull/7) - Add social preview image in `png` and `svg` format - [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#11](https://github.com/nf-core/sarek/pull/11) - Add helper script `run_tests.sh` to run different tests - [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9) - Add automatic build of specific containers for annotation for `GRCh37`, `GRCh38` and `GRCm38` using `CircleCI` @@ -26,23 +26,24 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#7](https://github.com/nf-core/sarek/pull/7), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Add helper script `download_image.sh` to download containers for testing - [#8](https://github.com/nf-core/sarek/pull/8) - Add test configation for easier testing - [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11) - Add scripts for `ASCAT` +- [#10](https://github.com/nf-core/sarek/pull/10) - Add `TIDDIT` to detect structural variants - [#11](https://github.com/nf-core/sarek/pull/11) - Add automatic build of specific containers for annotation for `CanFam3.1` using `CircleCI` - [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Add posters and abstracts -- [#12](https://github.com/nf-core/sarek/pull/12) - Use `label` for processes configation -- [#12](https://github.com/nf-core/sarek/pull/12) - Add helper scripts `filter_locifile.py` and `selectROI.py` - [#12](https://github.com/nf-core/sarek/pull/12) - Add helper script `make_snapshot.sh` to make an archive for usage on a secure cluster +- [#12](https://github.com/nf-core/sarek/pull/12) - Add helper scripts `filter_locifile.py` and `selectROI.py` +- [#12](https://github.com/nf-core/sarek/pull/12) - Use `label` for processes configation - [#13](https://github.com/nf-core/sarek/pull/13) - Add Citation documentation - [#13](https://github.com/nf-core/sarek/pull/13) - Add `BamQC` process - [#13](https://github.com/nf-core/sarek/pull/13) - Add `CompressVCFsnpEff` and `CompressVCFvep` processes - [#18](https://github.com/nf-core/sarek/pull/18) - Add `--no-reports` option for tests + add snpEff,VEP,merge to MULTIPLE test -- [#18](https://github.com/nf-core/sarek/pull/18) - Add possibility to download other genome for `sareksnpeff` and `sarekvep` containers -- [#18](https://github.com/nf-core/sarek/pull/18) - Add params `--skip` to skip specified QC tools - [#18](https://github.com/nf-core/sarek/pull/18) - Add logo to MultiQC report +- [#18](https://github.com/nf-core/sarek/pull/18) - Add params `--skip` to skip specified QC tools +- [#18](https://github.com/nf-core/sarek/pull/18) - Add possibility to download other genome for `sareksnpeff` and `sarekvep` containers - [#20](https://github.com/nf-core/sarek/pull/20) - Add `markdownlint` config file ### `Changed` -- [#1](https://github.com/nf-core/sarek/pull/1), [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#6](https://github.com/nf-core/sarek/pull/6), [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12), [#18](https://github.com/nf-core/sarek/pull/18), [#20](https://github.com/nf-core/sarek/pull/20) - Update docs +- [#1](https://github.com/nf-core/sarek/pull/1), [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#6](https://github.com/nf-core/sarek/pull/6), [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9), [#10](https://github.com/nf-core/sarek/pull/10), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12), [#18](https://github.com/nf-core/sarek/pull/18), [#20](https://github.com/nf-core/sarek/pull/20) - Update docs - [#4](https://github.com/nf-core/sarek/pull/4) - Update `cancerit-allelecount` from `2.1.2` to `4.0.2` - [#4](https://github.com/nf-core/sarek/pull/4) - Update `gatk4` from `4.1.1.0` to `4.1.2.0` - [#7](https://github.com/nf-core/sarek/pull/7) - `--sampleDir` is now deprecated, use `--sample` instead diff --git a/docs/containers.md b/docs/containers.md index fd5de52105..20d7ee30e0 100644 --- a/docs/containers.md +++ b/docs/containers.md @@ -32,6 +32,7 @@ For annotation, the main container can be used, but the cache has to be download - Contain **[samtools][samtools-link]** 1.9 - Contain **[snpEff][snpeff-link]** 4.3.1t - Contain **[Strelka2][strelka-link]** 2.9.10 +- Contain **[TIDDIT][tiddit-link]** 2.7.1 - Contain **[VCFanno][vcfanno-link]** 0.3.1 - Contain **[VCFtools][vcftools-link]** 0.1.16 - Contain **[VEP][vep-link]** 96.0 @@ -111,6 +112,7 @@ The `environment.yml` file can easilly be modified if particular versions of too [sareksnpeff-docker-badge]: https://img.shields.io/docker/automated/nfcore/sareksnpeff.svg [sareksnpeff-docker-link]: https://hub.docker.com/r/nfcore/sareksnpeff [strelka-link]: https://github.com/Illumina/strelka +[tiddit-link]: https://github.com/SciLifeLab/TIDDIT [vcfanno-link]: https://github.com/brentp/vcfanno [vcftools-link]: https://vcftools.github.io/index.html [vep-link]: https://github.com/Ensembl/ensembl-vep diff --git a/docs/output.md b/docs/output.md index 105010936c..3d8a44fd48 100644 --- a/docs/output.md +++ b/docs/output.md @@ -24,6 +24,7 @@ The pipeline processes data using the following steps: * [`Strelka2`](#Strelka2) * Structural variants * [`Manta`](#Manta) + * [`TIDDIT`](#TIDDIT) * Sample heterogeneity, ploidy and CNVs * `alleleCounter` * [`ConvertAlleleCounts`](#ConvertAlleleCounts) @@ -48,6 +49,7 @@ The pipeline processes data using the following steps: * [`MultiQC`](#MultiQC) ## Preprocessing + Sarek preprocesses raw FastQ files or unmapped BAM files, based on [GATK best practices](https://software.broadinstitute.org/gatk/best-practices/). BAM files with Recalibration tables can also be used as an input to start with the recalibration of said BAM files, for more information see [TSV files output information](#TSV-files) @@ -79,6 +81,7 @@ For all samples: * BAM file and index ### TSV files + The TSV files are autogenerated and can be used by Sarek for further processing and/or variant calling. For further reading and documentation see the [input documentation](https://github.com/nf-core/sarek/blob/master/docs/input.md). @@ -89,14 +92,16 @@ For all samples: * `duplicateMarked.tsv` and `recalibrated.tsv` * TSV files to start Sarek from `recalibration` or `variantcalling` steps. * `duplicateMarked_[SAMPLE].tsv` and `recalibrated_[SAMPLE].tsv` - * TSV files to start Sarek from `recalibration` or `variantcalling` steps for a specific sample. + * TSV files to start Sarek from `recalibration` or `variantcalling` steps for a specific sample. ## Variant Calling + All the results regarding variant-calling are collected in this directory. Recalibrated BAM files can also be used as an input to start the Variant Calling, for more information see [TSV files output information](#TSV-files) ### FreeBayes + [FreeBayes](https://github.com/ekg/freebayes) is a Bayesian genetic variant detector designed to find small polymorphisms, specifically SNPs, indels, MNPs, and complex events smaller than the length of a short-read sequencing alignment.. For further reading and documentation see the [FreeBayes manual](https://github.com/ekg/freebayes/blob/master/README.md#user-manual-and-guide). @@ -108,6 +113,7 @@ For a Tumor/Normal pair only: * VCF with Tabix index ### HaplotypeCaller + [GATK HaplotypeCaller](https://github.com/broadinstitute/gatk) calls germline SNPs and indels via local re-assembly of haplotypes. Germline calls are provided for all samples, to able comparison of both tumor and normal for possible mixup. @@ -121,6 +127,7 @@ For all samples: * VCF with Tabix index ### GenotypeGVCFs + [GATK GenotypeGVCFs](https://github.com/broadinstitute/gatk) performs joint genotyping on one or more samples pre-called with HaplotypeCaller. Germline calls are provided for all samples, to able comparison of both tumor and normal for possible mixup. @@ -134,6 +141,7 @@ For all samples: * VCF with Tabix index ### MuTect2 + [GATK MuTect2](https://github.com/broadinstitute/gatk) calls somatic SNVs and indels via local assembly of haplotypes. For further reading and documentation see the [MuTect2 manual](https://software.broadinstitute.org/gatk/documentation/tooldocs/4.1.2.0/org_broadinstitute_hellbender_tools_walkers_mutect_Mutect2.php). @@ -144,7 +152,33 @@ For a Tumor/Normal pair only: * `MuTect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz` and `MuTect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.tbi` * VCF with Tabix index +### TIDDIT + +[TIDDIT](https://github.com/SciLifeLab/TIDDIT)identifies intra and inter-chromosomal translocations, deletions, tandem-duplications and inversions. + +Germline calls are provided for all samples, to able comparison of both tumor and normal for possible mixup. +Low quality calls are removed internally, to simplify processing of variant calls but they are saved by Sarek. + +For further reading and documentation see the [TIDDIT manual](https://github.com/SciLifeLab/TIDDIT/blob/master/README.md). + +For all samples: +**Output directory: `results/VariantCalling/[SAMPLE]/TIDDIT`** + +* `TIDDIT_[SAMPLE].vcf.gz` and `TIDDIT_[SAMPLE].vcf.gz.tbi` + * VCF with Tabix index +* `TIDDIT_[SAMPLE].signals.tab` + * tab file describing coverage across the genome, binned per 50 bp +* `TIDDIT_[SAMPLE].ploidy.tab` + * tab file describing the estimated ploïdy and coverage across each contig +* `TIDDIT_[SAMPLE].old.vcf` + * VCF including the low qualiy calls +* `TIDDIT_[SAMPLE].wig` + * wiggle file containing coverage across the genome, binned per 50 bp +* `TIDDIT_[SAMPLE].gc.wig` + * wiggle file containing fraction of gc content, binned per 50 bp + ### Strelka2 + [Strelka2](https://github.com/Illumina/strelka) is a fast and accurate small variant caller optimized for analysis of germline variation in small cohorts and somatic variation in tumor/normal sample pairs. For further reading and documentation see the [Strelka2 user guide](https://github.com/Illumina/strelka/blob/v2.9.x/docs/userGuide/README.md). @@ -167,15 +201,17 @@ For a Tumor/Normal pair: Using [Strelka Best Practices](https://github.com/Illumina/strelka/blob/v2.9.x/docs/userGuide/README.md#somatic-configuration-example) with the `candidateSmallIndels` from `Manta`: **Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/Strelka`** + * `StrelkaBP_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_indels.vcf.gz` and `StrelkaBP_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_indels.vcf.gz.tbi` * VCF with Tabix index * `StrelkaBP_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_snvs.vcf.gz` and `StrelkaBP_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_snvs.vcf.gz.tbi` * VCF with Tabix index ### Manta + [Manta](https://github.com/Illumina/manta) calls structural variants (SVs) and indels from mapped paired-end sequencing reads. It is optimized for analysis of germline variation in small sets of individuals and somatic variation in tumor/normal sample pairs. -`Manta` provides a candidate list for small indels also that can be fed to `Strelka` following [Strelka Best Practices](https://github.com/Illumina/strelka/blob/v2.9.x/docs/userGuide/README.md#somatic-configuration-example. +`Manta` provides a candidate list for small indels also that can be fed to `Strelka` following [Strelka Best Practices](https://github.com/Illumina/strelka/blob/v2.9.x/docs/userGuide/README.md#somatic-configuration-example). For further reading and documentation see the [Manta user guide](https://github.com/Illumina/manta/blob/master/docs/userGuide/README.md). @@ -188,10 +224,12 @@ For all samples: * VCF with Tabix index For Normal sample only: + * `Manta_[NORMALSAMPLE].diploidSV.vcf.gz` and `Manta_[NORMALSAMPLE].diploidSV.vcf.gz.tbi` * VCF with Tabix index For a Tumor sample only: + * `Manta_[TUMORSAMPLE].tumorSV.vcf.gz` and `Manta_[TUMORSAMPLE].tumorSV.vcf.gz.tbi` * VCF with Tabix index @@ -208,6 +246,7 @@ For a Tumor/Normal pair only: * VCF with Tabix index ### ConvertAlleleCounts + [ConvertAlleleCounts](https://github.com/nf-core/sarek/blob/master/bin/convertAlleleCounts.r) is a R-script for converting output from AlleleCount to BAF and LogR values. For a Tumor/Normal pair only: diff --git a/environment.yml b/environment.yml index 891322f26e..2ef20b6310 100644 --- a/environment.yml +++ b/environment.yml @@ -26,5 +26,6 @@ dependencies: - samtools=1.9 - snpeff=4.3.1t - strelka=2.9.10 + - tiddit=2.7.1 - vcfanno=0.3.1 - vcftools=0.1.16 diff --git a/main.nf b/main.nf index d5f95a61db..5c2f6325d9 100644 --- a/main.nf +++ b/main.nf @@ -49,15 +49,17 @@ def helpMessage() { --step Specify starting step Available: Mapping, Recalibrate, VariantCalling, Annotate Default: Mapping - --tools Specify tools to use for variant calling, and annotation + --tools Specify tools to use for variant calling: Available: ASCAT, ControlFREEC, FreeBayes, HaplotypeCaller - Manta, mpileup, MuTect2, Strelka, snpEff, VEP, merge + Manta, mpileup, MuTect2, Strelka, TIDDIT + and/or for annotation: + snpEff, VEP, merge Default: None --skip Specify which QC tools to skip when running Sarek Available: bamQC, BCFtools, FastQC, MultiQC, samtools, vcftools, versions Default: None --annotateTools Specify from which tools Sarek will look for VCF files to annotate, only for step annotate - Available: HaplotypeCaller, Manta, MuTect2, Strelka + Available: HaplotypeCaller, Manta, MuTect2, Strelka, TIDDIT Default: None --annotation_cache Enable the use of cache for annotation, to be used with --snpEff_cache and/or --vep_cache --snpEff_cache Specity the path to snpEff cache, to be used with --annotation_cache @@ -810,7 +812,7 @@ bamRecal = bamRecal.dump(tag:'BAM') // Manta will be run in Germline mode, or in Tumor mode depending on status // HaplotypeCaller and Strelka will be run for Normal and Tumor samples -(bamMantaSingle, bamStrelkaSingle, bamRecalAllTemp, bamRecalAll) = bamRecal.into(4) +(bamMantaSingle, bamStrelkaSingle, bamTIDDIT, bamRecalAll, bamRecalAllTemp) = bamRecal.into(5) // To speed Variant Callers up we are chopping the reference into smaller pieces // Do variant calling by this intervals, and re-merge the VCFs @@ -965,7 +967,7 @@ process MantaSingle { ]) output: - set val("Manta"), idPatient, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into vcfMantaSingle + set val("Manta"), idPatient, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into vcfMantaSingle when: 'manta' in tools @@ -1002,6 +1004,48 @@ process MantaSingle { vcfMantaSingle = vcfMantaSingle.dump(tag:'Single Manta') +// STEP TIDDIT + +process TIDDIT { + tag {idSample} + + publishDir "${params.outdir}/VariantCalling/${idSample}/TIDDIT", mode: params.publishDirMode + + publishDir params.outdir, mode: params.publishDirMode, + saveAs: { + if (it == "TIDDIT_${idSample}.vcf") "VariantCalling/${idSample}/TIDDIT/${it}" + else "Reports/${idSample}/TIDDIT/${it}" + } + + input: + set idPatient, idSample, file(bam), file(bai) from bamTIDDIT + set file(genomeFile), file(genomeIndex) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex + ]) + + output: + set val("TIDDIT"), idPatient, idSample, file("*.vcf.gz"), file("*.tbi") into vcfTIDDIT + set file("TIDDIT_${idSample}.old.vcf"), file("TIDDIT_${idSample}.ploidy.tab"), file("TIDDIT_${idSample}.signals.tab"), file("TIDDIT_${idSample}.wig"), file("TIDDIT_${idSample}.gc.wig") into tidditOut + + when: 'tiddit' in tools + + script: + """ + tiddit --sv -o TIDDIT_${idSample} --bam ${bam} --ref ${genomeFile} + + mv TIDDIT_${idSample}.vcf TIDDIT_${idSample}.old.vcf + + grep -E "#|PASS" TIDDIT_${idSample}.old.vcf > TIDDIT_${idSample}.vcf + + bgzip --threads ${task.cpus} -c TIDDIT_${idSample}.vcf > TIDDIT_${idSample}.vcf.gz + + tabix TIDDIT_${idSample}.vcf.gz + """ +} + +vcfTIDDIT = vcfTIDDIT.dump(tag:'TIDDIT') + /* ================================================================================ SOMATIC VARIANT CALLING @@ -1133,7 +1177,7 @@ process ConcatVCF { // we have this funny *_* pattern to avoid copying the raw calls to publishdir set variantCaller, idPatient, idSample, file("*_*.vcf.gz"), file("*_*.vcf.gz.tbi") into vcfConcatenated - when: ('haplotypecaller' in tools || 'mutect2' in tools || 'freebayes' in tools) + when: 'haplotypecaller' in tools || 'mutect2' in tools || 'freebayes' in tools script: if (variantCaller == 'HaplotypeCallerGVCF') outputFile = "HaplotypeCaller_${idSample}.g.vcf" @@ -1226,7 +1270,7 @@ process Manta { options = params.targetBED ? "--exome --callRegions call_targets.bed.gz" : "" """ ${beforeScript} - configManta.py \ + configManta.py \ --normalBam ${bamNormal} \ --tumorBam ${bamTumor} \ --reference ${genomeFile} \ @@ -1360,7 +1404,7 @@ alleleCounterOut = alleleCountOutNormal.combine(alleleCountOutTumor) alleleCounterOut = alleleCounterOut.map { idPatientNormal, idSampleNormal, alleleCountOutNormal, - idPatientTumor, idSampleTumor, alleleCountOutTumor -> + idPatientTumor, idSampleTumor, alleleCountOutTumor -> [idPatientNormal, idSampleNormal, idSampleTumor, alleleCountOutNormal, alleleCountOutTumor] } @@ -1437,7 +1481,7 @@ process Mpileup { output: set idPatient, idSample, file("${intervalBed.baseName}_${idSample}.pileup.gz") into mpileupMerge - when: ('controlfreec' in tools || 'mpileup' in tools) + when: 'controlfreec' in tools || 'mpileup' in tools script: """ @@ -1463,7 +1507,7 @@ process MergeMpileup { output: set idPatient, idSample, file("${idSample}.pileup.gz") into mpileupOut - when: ('controlfreec' in tools || 'mpileup' in tools) + when: 'controlfreec' in tools || 'mpileup' in tools script: """ @@ -1489,7 +1533,7 @@ mpileupOut = mpileupOutNormal.combine(mpileupOutTumor) mpileupOut = mpileupOut.map { idPatientNormal, idSampleNormal, mpileupOutNormal, - idPatientTumor, idSampleTumor, mpileupOutTumor -> + idPatientTumor, idSampleTumor, mpileupOutTumor -> [idPatientNormal, idSampleNormal, idSampleTumor, mpileupOutNormal, mpileupOutTumor] } @@ -1630,6 +1674,10 @@ vcfKeep = Channel.empty().mix( vcfStrelkaBPSNVS.map { variantcaller, idPatient, idSample, vcf, tbi -> [variantcaller, idSample, vcf[1]] + }, + vcfTIDDIT.map { + variantcaller, idPatient, idSample, vcf, tbi -> + [variantcaller, idSample, vcf] }) (vcfBCFtools, vcfVCFtools, vcfAnnotation) = vcfKeep.into(3) @@ -1822,7 +1870,7 @@ process VEP { } input: - set variantCaller, idSample, file(vcf), file(idx) from vcfVep + set variantCaller, idSample, file(vcf), file(idx) from vcfVep file dataDir from Channel.value(params.vep_cache ? file(params.vep_cache) : "null") val cache_version from Channel.value(params.genomes[params.genome].vepCacheVersion) set file(cadd_WG_SNVs), file(cadd_WG_SNVs_tbi), file(cadd_InDels), file(cadd_InDels_tbi) from Channel.value([ @@ -1885,7 +1933,7 @@ process VEPmerge { } input: - set variantCaller, idSample, file(vcf), file(idx) from compressVCFsnpEffOut + set variantCaller, idSample, file(vcf), file(idx) from compressVCFsnpEffOut file dataDir from Channel.value(params.vep_cache ? file(params.vep_cache) : "null") val cache_version from Channel.value(params.genomes[params.genome].vepCacheVersion) set file(cadd_WG_SNVs), file(cadd_WG_SNVs_tbi), file(cadd_InDels), file(cadd_InDels_tbi) from Channel.value([ @@ -2316,6 +2364,7 @@ def defineToolList() { 'mutect2', 'snpeff', 'strelka', + 'tiddit', 'vep' ] } diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index 43661935ed..46d85d17f6 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -88,7 +88,7 @@ fi if [[ ALL,SOMATIC =~ $TEST ]] then - OPTIONS="--tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2" + OPTIONS="--tools FreeBayes,HaplotypeCaller,Manta,Strelka,TIDDIT,Mutect2" if [[ $OFFLINE == false ]] then run_sarek ${OPTIONS} @@ -100,7 +100,7 @@ fi if [[ ALL,TARGETED =~ $TEST ]] then - OPTIONS="--tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2" + OPTIONS="--tools FreeBayes,HaplotypeCaller,Manta,Strelka,TIDDIT,Mutect2" if [[ $OFFLINE == false ]] then run_sarek ${OPTIONS} --targetBED https://github.com/nf-core/test-datasets/raw/sarek/testdata/target.bed @@ -135,7 +135,7 @@ fi if [[ MULTIPLE =~ $TEST ]] then - OPTIONS="--tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2,snpEff,VEP,merge" + OPTIONS="--tools FreeBayes,HaplotypeCaller,Manta,Strelka,TIDDIT,Mutect2,snpEff,VEP,merge" if [[ $OFFLINE == false ]] then run_sarek ${OPTIONS} --sample https://github.com/nf-core/test-datasets/raw/sarek/testdata/tsv/tiny-multiple-https.tsv From ca2a0b0e41128f86d24ab683074592ca26b81df8 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Mon, 12 Aug 2019 14:49:55 +0200 Subject: [PATCH 026/854] More improvments (#21) * feat: merge markdownlint config files * fix: more linting on md files * feat: add md linting to travisCI tests * feat: sort tests * feat: improve travis testing * feat: improve Travis tests * feat: sort tests * feat: use YAML anchors to improve/simplify circle ci docker deployment * fix: remove with stroke over aple core in nf-core logo * feat: use direct link to slack sarek channel * fix: code spacing * feat: remove ALL from tests and simplify/improve script * feat: use kraken profile to run tests * feat: remove unnecessary Channel.create() * fix: removed links to deleted files * feat: moved smallGRCh37 to new genomes.config * feat: update CHANGELOG --- .circleci/config.yml | 89 +++----------- .github/CONTRIBUTING.md | 2 +- .github/PULL_REQUEST_TEMPLATE.md | 7 +- .github/markdownlint.yml | 3 + .markdownlint.json | 4 - .travis.yml | 33 ++++-- CHANGELOG.md | 9 +- Jenkinsfile | 10 +- README.md | 2 +- conf/genomes.config | 58 +++++++++ conf/igenomes.config | 15 --- conf/test.config | 3 +- docs/README.md | 2 - docs/abstracts/2017-05-ESHG.md | 2 +- docs/abstracts/2018-06-EACR25.md | 21 ++-- .../nf-core_sarek_dark_color.svg | 10 +- main.nf | 3 - nextflow.config | 6 +- scripts/run_tests.sh | 111 ++++++++---------- 19 files changed, 186 insertions(+), 204 deletions(-) delete mode 100644 .markdownlint.json create mode 100644 conf/genomes.config diff --git a/.circleci/config.yml b/.circleci/config.yml index 2a805a0ea4..0af952fcb0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,11 +1,11 @@ version: 2.0 jobs: - snpeffgrch37: + snpeffgrch37: &buildsnpeff docker: - image: circleci/buildpack-deps:stretch environment: GENOME: GRCh37 - SNPEFF_CACHE_VERSION: 75 + SNPEFF_CACHE_VERSION: "75" steps: - checkout - setup_remote_docker @@ -17,60 +17,30 @@ jobs: docker push nfcore/sareksnpeff:dev.${GENOME} snpeffgrch38: - docker: - - image: circleci/buildpack-deps:stretch + << : *buildsnpeff environment: GENOME: GRCh38 - SNPEFF_CACHE_VERSION: 86 - steps: - - checkout - - setup_remote_docker - - run: - command: docker build -t nfcore/sareksnpeff:dev.${GENOME} containers/snpeff/. --build-arg GENOME=${GENOME} --build-arg SNPEFF_CACHE_VERSION=${SNPEFF_CACHE_VERSION} - - run: - command: | - echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin - docker push nfcore/sareksnpeff:dev.${GENOME} + SNPEFF_CACHE_VERSION: "86" snpeffgrcm38: - docker: - - image: circleci/buildpack-deps:stretch + << : *buildsnpeff environment: GENOME: GRCm38 - SNPEFF_CACHE_VERSION: 86 - steps: - - checkout - - setup_remote_docker - - run: - command: docker build -t nfcore/sareksnpeff:dev.${GENOME} containers/snpeff/. --build-arg GENOME=${GENOME} --build-arg SNPEFF_CACHE_VERSION=${SNPEFF_CACHE_VERSION} - - run: - command: | - echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin - docker push nfcore/sareksnpeff:dev.${GENOME} + SNPEFF_CACHE_VERSION: "86" snpeffcanfam3_1: - docker: - - image: circleci/buildpack-deps:stretch + << : *buildsnpeff environment: GENOME: CanFam3.1 - SNPEFF_CACHE_VERSION: 86 - steps: - - checkout - - setup_remote_docker - - run: - command: docker build -t nfcore/sareksnpeff:dev.${GENOME} containers/snpeff/. --build-arg GENOME=${GENOME} --build-arg SNPEFF_CACHE_VERSION=${SNPEFF_CACHE_VERSION} - - run: - command: | - echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin - docker push nfcore/sareksnpeff:dev.${GENOME} + SNPEFF_CACHE_VERSION: "86" - vepgrch37: + vepgrch37: &buildvep docker: - image: circleci/buildpack-deps:stretch environment: GENOME: GRCh37 SPECIES: homo_sapiens - VEP_VERSION: 95 + VEP_VERSION: "95" steps: - checkout - setup_remote_docker @@ -81,52 +51,25 @@ jobs: command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:dev.${GENOME} vepgrch38: - docker: - - image: circleci/buildpack-deps:stretch + << : *buildvep environment: GENOME: GRCh38 SPECIES: homo_sapiens - VEP_VERSION: 95 - steps: - - checkout - - setup_remote_docker - - run: - command: docker build -t nfcore/sarekvep:dev.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} - no_output_timeout: 3h - - run: - command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:dev.${GENOME} + VEP_VERSION: "95" vepgrcm38: - docker: - - image: circleci/buildpack-deps:stretch + << : *buildvep environment: GENOME: GRCm38 SPECIES: mus_musculus - VEP_VERSION: 95 - steps: - - checkout - - setup_remote_docker - - run: - command: docker build -t nfcore/sarekvep:dev.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} - no_output_timeout: 1h - - run: - command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:dev.${GENOME} + VEP_VERSION: "95" vepcanfam3_1: - docker: - - image: circleci/buildpack-deps:stretch + << : *buildvep environment: GENOME: CanFam3.1 SPECIES: canis_familiaris - VEP_VERSION: 95 - steps: - - checkout - - setup_remote_docker - - run: - command: docker build -t nfcore/sarekvep:dev.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} - no_output_timeout: 1h - - run: - command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:dev.${GENOME} + VEP_VERSION: "95" workflows: version: 2 diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index aa11820ab2..c8210fcedb 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -44,4 +44,4 @@ If there are any failures then the automated tests fail. These tests are run both with the latest available version of Nextflow and also the minimum required version that is stated in the pipeline code. ## Getting help -For further information/help, please consult the [nf-core/sarek documentation](https://github.com/nf-core/sarek#documentation) and don't hesitate to get in touch on the pipeline channel on [Slack](https://nf-core-invite.herokuapp.com/). +For further information/help, please consult the [nf-core/sarek documentation](https://github.com/nf-core/sarek#documentation) and don't hesitate to get in touch on the [sarek pipeline channel](https://nfcore.slack.com/channels/sarek) on [Slack](https://nf-co.re/join/slack). diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f9fe1f9ffa..15c9a1b1df 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,15 +1,16 @@ Many thanks to contributing to nf-core/sarek! -Please fill in the appropriate checklist below (delete whatever is not relevant). These are the most common things requested on pull requests (PRs). +Please fill in the appropriate checklist below (delete whatever is not relevant). +These are the most common things requested on pull requests (PRs). ## PR checklist - [ ] This comment contains a description of changes (with reason) - [ ] If you've fixed a bug or added code that should be tested, add tests! - - [ ] If necessary, also make a PR on the [nf-core/sarek branch on the nf-core/test-datasets repo]( https://github.com/nf-core/test-datasets/pull/new/nf-core/sarek) + - [ ] If necessary, also make a PR on the [nf-core/sarek branch on the nf-core/test-datasets repo](https://github.com/nf-core/test-datasets/pull/new/nf-core/sarek) - [ ] Ensure the test suite passes (`nextflow run . -profile test,docker`). - [ ] Make sure your code lints (`nf-core lint .`). - [ ] Documentation in `docs` is updated - [ ] `CHANGELOG.md` is updated - [ ] `README.md` is updated -**Learn more about contributing:** https://github.com/nf-core/sarek/tree/master/.github/CONTRIBUTING.md +**Learn more about contributing:** [guidelines](https://github.com/nf-core/sarek/tree/master/.github/CONTRIBUTING.md) \ No newline at end of file diff --git a/.github/markdownlint.yml b/.github/markdownlint.yml index e052a635aa..8f97a170e8 100644 --- a/.github/markdownlint.yml +++ b/.github/markdownlint.yml @@ -7,3 +7,6 @@ blanks-around-lists: false header-increment: false no-duplicate-header: siblings_only: true +no-inline-html: + allowed_elements: + - img \ No newline at end of file diff --git a/.markdownlint.json b/.markdownlint.json deleted file mode 100644 index 7ca973f0c2..0000000000 --- a/.markdownlint.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "MD013": false, - "MD024": { "siblings_only": true } -} diff --git a/.travis.yml b/.travis.yml index cb01d2c317..cbb65a0da6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,14 +14,17 @@ matrix: fast_finish: true env: - global: - - NXF_VER=19.04.0 matrix: - - TEST=SOMATIC - - TEST=GERMLINE - - TEST=TARGETED - - TEST=ANNOTATEVEP - - TEST=ANNOTATESNPEFF + - TEST=ANNOTATEVEP NXF_VER=19.04.0 + - TEST=ANNOTATEVEP NXF_VER='' + - TEST=SOMATIC NXF_VER=19.04.0 + - TEST=SOMATIC NXF_VER='' + - TEST=TARGETED NXF_VER=19.04.0 + - TEST=TARGETED NXF_VER='' + - TEST=GERMLINE NXF_VER=19.04.0 + - TEST=GERMLINE NXF_VER='' + - TEST=ANNOTATESNPEFF NXF_VER=19.04.0 + - TEST=ANNOTATESNPEFF NXF_VER='' before_install: # PRs to master are only ok if coming from dev branch @@ -34,13 +37,27 @@ install: - mkdir /tmp/nextflow && cd /tmp/nextflow - wget -qO- get.nextflow.io | bash - sudo ln -s /tmp/nextflow/nextflow /usr/local/bin/nextflow + # # Install nf-core/tools + # - pip install --upgrade pip + # - pip install nf-core # Reset - mkdir ${TRAVIS_BUILD_DIR}/tests && cd ${TRAVIS_BUILD_DIR}/tests + # Install markdownlint-cli + - sudo apt-get install npm && npm install -g markdownlint-cli # Build references if needed before_script: - - "${TRAVIS_BUILD_DIR}/scripts/build_reference.sh --test $TEST --verbose" + - ${TRAVIS_BUILD_DIR}/scripts/build_reference.sh --test $TEST --verbose # Actual tests script: - "${TRAVIS_BUILD_DIR}/scripts/run_tests.sh --test $TEST --verbose --no-reports" + +# Linting +jobs: + include: + - stage: "Linting" + name: "Markdown" + env: TEST=GERMLINE NXF_VER=19.04.0 + script: + - markdownlint ${TRAVIS_BUILD_DIR} -c ${TRAVIS_BUILD_DIR}/.github/markdownlint.yml \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index a5cf4380c2..22993ea81c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#7](https://github.com/nf-core/sarek/pull/7) - Add MultiQC - [#7](https://github.com/nf-core/sarek/pull/7) - Add annotation - [#7](https://github.com/nf-core/sarek/pull/7) - Add social preview image in `png` and `svg` format -- [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#11](https://github.com/nf-core/sarek/pull/11) - Add helper script `run_tests.sh` to run different tests +- [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#11](https://github.com/nf-core/sarek/pull/11), [#21](https://github.com/nf-core/sarek/pull/21) - Add helper script `run_tests.sh` to run different tests - [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9) - Add automatic build of specific containers for annotation for `GRCh37`, `GRCh38` and `GRCm38` using `CircleCI` - [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11) - Add helper script `build_reference.sh` to build small reference from [nf-core/test-datasets:sarek](https://github.com/nf-core/test-datasets/tree/sarek) - [#7](https://github.com/nf-core/sarek/pull/7), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Add helper script `download_image.sh` to download containers for testing @@ -40,10 +40,12 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#18](https://github.com/nf-core/sarek/pull/18) - Add params `--skip` to skip specified QC tools - [#18](https://github.com/nf-core/sarek/pull/18) - Add possibility to download other genome for `sareksnpeff` and `sarekvep` containers - [#20](https://github.com/nf-core/sarek/pull/20) - Add `markdownlint` config file +- [#21](https://github.com/nf-core/sarek/pull/21) - Add tests for latest Nextflow version as well +- [#21](https://github.com/nf-core/sarek/pull/21) - Add `genomes.config` for genomes without AWS iGenomes ### `Changed` -- [#1](https://github.com/nf-core/sarek/pull/1), [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#6](https://github.com/nf-core/sarek/pull/6), [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9), [#10](https://github.com/nf-core/sarek/pull/10), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12), [#18](https://github.com/nf-core/sarek/pull/18), [#20](https://github.com/nf-core/sarek/pull/20) - Update docs +- [#1](https://github.com/nf-core/sarek/pull/1), [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#6](https://github.com/nf-core/sarek/pull/6), [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9), [#10](https://github.com/nf-core/sarek/pull/10), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12), [#18](https://github.com/nf-core/sarek/pull/18), [#20](https://github.com/nf-core/sarek/pull/20), [#21](https://github.com/nf-core/sarek/pull/21) - Update docs - [#4](https://github.com/nf-core/sarek/pull/4) - Update `cancerit-allelecount` from `2.1.2` to `4.0.2` - [#4](https://github.com/nf-core/sarek/pull/4) - Update `gatk4` from `4.1.1.0` to `4.1.2.0` - [#7](https://github.com/nf-core/sarek/pull/7) - `--sampleDir` is now deprecated, use `--sample` instead @@ -65,7 +67,8 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#18](https://github.com/nf-core/sarek/pull/18) - Use `--no-reports` for TravisCI testing - [#18](https://github.com/nf-core/sarek/pull/18) - Add `--no-reports` for all tests but MULTIPLE in Jenkins - [#18](https://github.com/nf-core/sarek/pull/18) - `--noReports` is now `--skip all` -- [#18](https://github.com/nf-core/sarek/pull/18) - Update logo +- [#18](https://github.com/nf-core/sarek/pull/18), [#21](https://github.com/nf-core/sarek/pull/21) - Update logo +- [#21](https://github.com/nf-core/sarek/pull/21) - Moved smallGRCh37 path to `genomes.config` ### `Removed` diff --git a/Jenkinsfile b/Jenkinsfile index a6a974eb67..14c62c7b2c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -21,28 +21,28 @@ pipeline { steps { sh "rm -rf data/" sh "git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data" - sh "./scripts/run_tests.sh --test GERMLINE --no-reports" + sh "./scripts/run_tests.sh --profile kraken --test GERMLINE --no-reports" sh "rm -rf data/" } } stage('Somatic') { steps { - sh "./scripts/run_tests.sh --test SOMATIC --no-reports" + sh "./scripts/run_tests.sh --profile kraken --test SOMATIC --no-reports" } } stage('Targeted') { steps { - sh "./scripts/run_tests.sh --test TARGETED --no-reports" + sh "./scripts/run_tests.sh --profile kraken --test TARGETED --no-reports" } } stage('Annotation') { steps { - sh "./scripts/run_tests.sh --test ANNOTATEBOTH --no-reports" + sh "./scripts/run_tests.sh --profile kraken --test ANNOTATEBOTH --no-reports" } } stage('Multiple') { steps { - sh "./scripts/run_tests.sh --test MULTIPLE" + sh "./scripts/run_tests.sh --profile kraken --test MULTIPLE" } } } diff --git a/README.md b/README.md index d5ffd4f7dd..058a01b5ba 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ Helpful contributors: If you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md). -For further information or help, don't hesitate to get in touch on [Slack](https://nfcore.slack.com/messages/CGFUX04HZ/) or contact us: maxime.garcia@scilifelab.se, szilveszter.juhos@scilifelab.se +For further information or help, don't hesitate to get in touch on [Slack](https://nfcore.slack.com/channels/sarek) (you can join with [this invite](https://nf-co.re/join/slack)) or contact us: maxime.garcia@scilifelab.se, szilveszter.juhos@scilifelab.se ## CHANGELOG diff --git a/conf/genomes.config b/conf/genomes.config new file mode 100644 index 0000000000..8e26207a99 --- /dev/null +++ b/conf/genomes.config @@ -0,0 +1,58 @@ +/* + * ------------------------------------------------- + * Nextflow config file for reference genome + * ------------------------------------------------- + * Defines reference genomes, without using iGenome paths + * Can be used by any config that customises the base + * path using $params.genomes_base / --genomes_base + */ + +params { + genomes { + 'GRCh37' { + acLoci = "${params.genomes_base}/1000G_phase3_20130502_SNP_maf0.3.loci" + acLociGC = "${params.genomes_base}/1000G_phase3_20130502_SNP_maf0.3.loci.gc" + bwaIndex = "${params.genomes_base}/human_g1k_v37_decoy.fasta.{amb,ann,bwt,pac,sa}" + dbsnp = "${params.genomes_base}/dbsnp_138.b37.vcf" + dbsnpIndex = "${params.genomes_base}/dbsnp_138.b37.vcf.idx" + genomeDict = "${params.genomes_base}/human_g1k_v37_decoy.dict" + genomeFile = "${params.genomes_base}/human_g1k_v37_decoy.fasta" + genomeIndex = "${params.genomes_base}/human_g1k_v37_decoy.fasta.fai" + intervals = "${params.genomes_base}/wgs_calling_regions_CAW.list" + knownIndels = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf" + knownIndelsIndex = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" + snpeffDb = "GRCh37.75" + vepCacheVersion = "95" + } + 'GRCh38' { + acLoci = "${params.genomes_base}/1000G_phase3_GRCh38_maf0.3.loci" + acLociGC = "${params.genomes_base}/1000G_phase3_GRCh38_maf0.3.loci.gc" + bwaIndex = "${params.genomes_base}/Homo_sapiens_assembly38.fasta.64.{alt,amb,ann,bwt,pac,sa}" + dbsnp = "${params.genomes_base}/dbsnp_146.hg38.vcf.gz" + dbsnpIndex = "${params.genomes_base}/dbsnp_146.hg38.vcf.gz.tbi" + genomeDict = "${params.genomes_base}/Homo_sapiens_assembly38.dict" + genomeFile = "${params.genomes_base}/Homo_sapiens_assembly38.fasta" + genomeIndex = "${params.genomes_base}/Homo_sapiens_assembly38.fasta.fai" + intervals = "${params.genomes_base}/wgs_calling_regions.hg38.bed" + knownIndels = "${params.genomes_base}/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" + knownIndelsIndex = "${params.genomes_base}/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" + snpeffDb = "GRCh38.86" + vepCacheVersion = "95" + } + 'smallGRCh37' { + acLoci = "${params.genomes_base}/1000G_phase3_20130502_SNP_maf0.3.small.loci" + acLociGC = "${params.genomes_base}/1000G_phase3_20130502_SNP_maf0.3.small.loci.gc" + bwaIndex = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta.{amb,ann,bwt,pac,sa}" + dbsnp = "${params.genomes_base}/dbsnp_138.b37.small.vcf" + dbsnpIndex = "${params.genomes_base}/dbsnp_138.b37.small.vcf.idx" + genomeDict = "${params.genomes_base}/human_g1k_v37_decoy.small.dict" + genomeFile = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" + genomeIndex = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta.fai" + intervals = "${params.genomes_base}/small.intervals" + knownIndels = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf" + knownIndelsIndex = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf.idx" + snpeffDb = "GRCh37.75" + vepCacheVersion = "95" + } + } +} \ No newline at end of file diff --git a/conf/igenomes.config b/conf/igenomes.config index f35979bc3d..2c936e7a59 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -39,20 +39,5 @@ snpeffDb = "GRCh38.86" vepCacheVersion = "95" } - 'smallGRCh37' { - acLoci = "${params.igenomes_base}/1000G_phase3_20130502_SNP_maf0.3.small.loci" - acLociGC = "${params.igenomes_base}/1000G_phase3_20130502_SNP_maf0.3.small.loci.gc" - bwaIndex = "${params.igenomes_base}/human_g1k_v37_decoy.small.fasta.{amb,ann,bwt,pac,sa}" - dbsnp = "${params.igenomes_base}/dbsnp_138.b37.small.vcf" - dbsnpIndex = "${params.igenomes_base}/dbsnp_138.b37.small.vcf.idx" - genomeDict = "${params.igenomes_base}/human_g1k_v37_decoy.small.dict" - genomeFile = "${params.igenomes_base}/human_g1k_v37_decoy.small.fasta" - genomeIndex = "${params.igenomes_base}/human_g1k_v37_decoy.small.fasta.fai" - intervals = "${params.igenomes_base}/small.intervals" - knownIndels = "${params.igenomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf" - knownIndelsIndex = "${params.igenomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf.idx" - snpeffDb = "GRCh37.75" - vepCacheVersion = "95" - } } } diff --git a/conf/test.config b/conf/test.config index ddffd07edb..8e4eaff3d8 100644 --- a/conf/test.config +++ b/conf/test.config @@ -18,8 +18,9 @@ params { sample = 'https://github.com/nf-core/test-datasets/raw/sarek/testdata/tsv/tiny-manta-https.tsv' // Small reference genome // To be build with: `nextflow run build.nf --build -profile docker --outdir references` + igenomesIgnore = true genome = 'smallGRCh37' - igenomes_base = 'references' + genomes_base = 'references' // Use publishDir mode link so that work can be removed publishDirMode = 'link' } diff --git a/docs/README.md b/docs/README.md index 879c20f793..43e1c60051 100644 --- a/docs/README.md +++ b/docs/README.md @@ -12,9 +12,7 @@ The nf-core/sarek documentation is split into the following files: 3. [Running the pipeline](usage.md) * [Examples](use_cases.md) * [Input files documentation](input.md) - * [Extra documentation on variant calling](variantcalling.md) * [Documentation about containers](containers.md) - * [Extra documentation for targeted sequencing](targetseq.md) 4. [Output and how to interpret the results](output.md) * [Complementary information about ASCAT](ascat.md) * [Extra documentation on annotation](annotation.md) diff --git a/docs/abstracts/2017-05-ESHG.md b/docs/abstracts/2017-05-ESHG.md index d87f473a96..76e86db02f 100644 --- a/docs/abstracts/2017-05-ESHG.md +++ b/docs/abstracts/2017-05-ESHG.md @@ -28,4 +28,4 @@ We are presenting CAW (Cancer Analysis Workflow) a complete open source pipeline The software can start the analysis from raw FASTQ files, from the realignment step, or directly with any subset of variant callers. At the end of the analysis the resulting VCF files are merged to facilitate further downstream processing, though the individual results are also retained. The flow is capable of accommodating further variant calling software or CNV callers. It is also prepared to process normal - tumor - and several relapse samples. -Besides variant calls, the workflow provides quality controls presented by MultiQC. A docker image is also available, the open source software can be downloaded from https://github.com/SciLifeLab/CAW . +Besides variant calls, the workflow provides quality controls presented by MultiQC. A docker image is also available, the open source software can be downloaded from . diff --git a/docs/abstracts/2018-06-EACR25.md b/docs/abstracts/2018-06-EACR25.md index ca86f2e658..57af817151 100644 --- a/docs/abstracts/2018-06-EACR25.md +++ b/docs/abstracts/2018-06-EACR25.md @@ -2,14 +2,13 @@ ## Somatic and germline calls from tumour/normal whole genome data: bioinformatics workflow for reproducible research - -Szilveszter Juhos 1, -Maxime Garcia 2, -Teresita Díaz de Ståhl 3, -Johanna Sandgren 3, -Markus Mayrhofer 4, -Max Käller 5, -Björn Nystedt 6, +Szilveszter Juhos 1, +Maxime Garcia 2, +Teresita Díaz de Ståhl 3, +Johanna Sandgren 3, +Markus Mayrhofer 4, +Max Käller 5, +Björn Nystedt 6, Monica Nistér 3 1. Karolinska Institutet, Department of Oncology Pathology, Stockholm, Sweden. @@ -49,11 +48,9 @@ aggregated by MultiQC. Sarek was validated on a real dataset with known golden set of somatic mutations. In a real settings, whole-genome sequencing (WGS, 45-60x coverage) of patient-matched tumor and blood derived-DNA is being performed on a set of 80 pediatric brain tumor samples of the Swedish Childhood Tumor Biobank. The workflow helps to produce, filter, prioritise -and characterise both germline and somatic variations. +and characterise both germline and somatic variations. ### Conclusion Sarek is a portable bioinformatics pipeline for WGS normal/tumour matched samples, aiding precision medicine by improved -subtyping and to gain novel functional insights in a reproducible framework. - - +subtyping and to gain novel functional insights in a reproducible framework. diff --git a/docs/images/logos/nf-core_sarek/nf-core_sarek_dark_color.svg b/docs/images/logos/nf-core_sarek/nf-core_sarek_dark_color.svg index 7892026424..e22ded4fac 100644 --- a/docs/images/logos/nf-core_sarek/nf-core_sarek_dark_color.svg +++ b/docs/images/logos/nf-core_sarek/nf-core_sarek_dark_color.svg @@ -153,9 +153,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="2" - inkscape:cx="260.83537" - inkscape:cy="102.45087" + inkscape:zoom="5.6568542" + inkscape:cx="350.51581" + inkscape:cy="127.1652" inkscape:document-units="px" inkscape:current-layer="layer4" showgrid="false" @@ -178,7 +178,7 @@ image/svg+xml - + @@ -189,7 +189,7 @@ style="display:inline" transform="translate(-15.436598,82.468416)"> Date: Wed, 28 Aug 2019 09:43:36 +0200 Subject: [PATCH 027/854] Update docs (#29) * feat: update docs * feat: replace skip params by skipQC --- CHANGELOG.md | 6 +++--- docs/usage.md | 10 ++++++---- main.nf | 36 ++++++++++++++++++------------------ scripts/run_tests.sh | 2 +- 4 files changed, 28 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22993ea81c..9dfc3f6f62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#13](https://github.com/nf-core/sarek/pull/13) - Add `CompressVCFsnpEff` and `CompressVCFvep` processes - [#18](https://github.com/nf-core/sarek/pull/18) - Add `--no-reports` option for tests + add snpEff,VEP,merge to MULTIPLE test - [#18](https://github.com/nf-core/sarek/pull/18) - Add logo to MultiQC report -- [#18](https://github.com/nf-core/sarek/pull/18) - Add params `--skip` to skip specified QC tools +- [#18](https://github.com/nf-core/sarek/pull/18), [#29](https://github.com/nf-core/sarek/pull/29) - Add params `--skipQC` to skip specified QC tools - [#18](https://github.com/nf-core/sarek/pull/18) - Add possibility to download other genome for `sareksnpeff` and `sarekvep` containers - [#20](https://github.com/nf-core/sarek/pull/20) - Add `markdownlint` config file - [#21](https://github.com/nf-core/sarek/pull/21) - Add tests for latest Nextflow version as well @@ -45,7 +45,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) ### `Changed` -- [#1](https://github.com/nf-core/sarek/pull/1), [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#6](https://github.com/nf-core/sarek/pull/6), [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9), [#10](https://github.com/nf-core/sarek/pull/10), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12), [#18](https://github.com/nf-core/sarek/pull/18), [#20](https://github.com/nf-core/sarek/pull/20), [#21](https://github.com/nf-core/sarek/pull/21) - Update docs +- [#1](https://github.com/nf-core/sarek/pull/1), [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#6](https://github.com/nf-core/sarek/pull/6), [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9), [#10](https://github.com/nf-core/sarek/pull/10), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12), [#18](https://github.com/nf-core/sarek/pull/18), [#20](https://github.com/nf-core/sarek/pull/20), [#21](https://github.com/nf-core/sarek/pull/21), [#29](https://github.com/nf-core/sarek/pull/29) - Update docs - [#4](https://github.com/nf-core/sarek/pull/4) - Update `cancerit-allelecount` from `2.1.2` to `4.0.2` - [#4](https://github.com/nf-core/sarek/pull/4) - Update `gatk4` from `4.1.1.0` to `4.1.2.0` - [#7](https://github.com/nf-core/sarek/pull/7) - `--sampleDir` is now deprecated, use `--sample` instead @@ -66,7 +66,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#16](https://github.com/nf-core/sarek/pull/16) - Make scripts in `bin/` and `scripts/` executable - [#18](https://github.com/nf-core/sarek/pull/18) - Use `--no-reports` for TravisCI testing - [#18](https://github.com/nf-core/sarek/pull/18) - Add `--no-reports` for all tests but MULTIPLE in Jenkins -- [#18](https://github.com/nf-core/sarek/pull/18) - `--noReports` is now `--skip all` +- [#18](https://github.com/nf-core/sarek/pull/18), [#29](https://github.com/nf-core/sarek/pull/29) - `--noReports` is now `--skipQC all` - [#18](https://github.com/nf-core/sarek/pull/18), [#21](https://github.com/nf-core/sarek/pull/21) - Update logo - [#21](https://github.com/nf-core/sarek/pull/21) - Moved smallGRCh37 path to `genomes.config` diff --git a/docs/usage.md b/docs/usage.md index 29b239294c..bdf9de13f0 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -13,8 +13,8 @@ * [`-profile`](#-profile) * [`--sample`](#--sample) * [`--noGVCF`](#--nogvcf) - * [`--noReports`](#--noreports) * [`--nucleotidesPerSecond`](#--nucleotidespersecond) + * [`--skipQC`](#--skipQC) * [`--step`](#--step) * [`--tools`](#--tools) * [`--noStrelkaBP`](#--nostrelkabp) @@ -173,9 +173,11 @@ Multiple VCF files can be specified if the path must be enclosed in quotes Use this to disable g.vcf from `HaplotypeCaller`. -### `--noReports` +### `--skipQC` -Use this to disable all QC an Reporting tools. +Use this to disable specific QC and Reporting tools. +Available: `all`, `bamQC`, `BCFtools`, `FastQC`, `MultiQC`, `samtools`, `vcftools`, `versions` +Default: `None` ### `--nucleotidesPerSecond` @@ -190,7 +192,7 @@ Available: `mapping`, `recalibrate`, `variantcalling` and `annotate` ### `--tools` Use this to specify the tools to run: -Available: `ASCAT`, `ControlFREEC`, `FreeBayes`, `HaplotypeCaller`, `Manta`, `mpileup`, `MuTect2`, `Strelka` +Available: `ASCAT`, `ControlFREEC`, `FreeBayes`, `HaplotypeCaller`, `Manta`, `mpileup`, `MuTect2`, `Strelka`, `TIDDIT` ### `--noStrelkaBP` diff --git a/main.nf b/main.nf index b379084268..c1cd79fd15 100644 --- a/main.nf +++ b/main.nf @@ -55,8 +55,8 @@ def helpMessage() { and/or for annotation: snpEff, VEP, merge Default: None - --skip Specify which QC tools to skip when running Sarek - Available: bamQC, BCFtools, FastQC, MultiQC, samtools, vcftools, versions + --skipQC Specify which QC tools to skip when running Sarek + Available: all, bamQC, BCFtools, FastQC, MultiQC, samtools, vcftools, versions Default: None --annotateTools Specify from which tools Sarek will look for VCF files to annotate, only for step annotate Available: HaplotypeCaller, Manta, MuTect2, Strelka, TIDDIT @@ -123,7 +123,7 @@ params.noStrelkaBP = null params.nucleotidesPerSecond = 1000.0 params.sample = null params.sequencing_center = null -params.skip = null +params.skipQC = null params.snpEff_cache = null params.step = 'mapping' params.targetBED = null @@ -140,9 +140,9 @@ toolList = defineToolList() tools = params.tools ? params.tools.split(',').collect{it.trim().toLowerCase()} : [] if (!checkParameterList(tools,toolList)) exit 1, 'Unknown tool(s), see --help for more information' -skipList = defineSkipList() -skip = params.skip ? params.skip == 'all' ? skipList : params.skip.split(',').collect{it.trim().toLowerCase()} : [] -if (!checkParameterList(skip,skipList)) exit 1, 'Unknown QC tool(s), see --help for more information' +skipQClist = defineSkipQClist() +skipQC = params.skipQC ? params.skipQC == 'all' ? skipQClist : params.skipQC.split(',').collect{it.trim().toLowerCase()} : [] +if (!checkParameterList(skipQC,skipQClist)) exit 1, 'Unknown QC tool(s), see --help for more information' annoList = defineAnnoList() annotateTools = params.annotateTools ? params.annotateTools.split(',').collect{it.trim().toLowerCase()} : [] @@ -216,7 +216,7 @@ if (params.sample) summary['Sample'] = params.sample if (params.targetBED) summary['Target BED'] = params.targetBED if (params.step) summary['Step'] = params.step if (params.tools) summary['Tools'] = tools.join(', ') -if (params.skip) summary['QC tools skip'] = skip.join(', ') +if (params.skipQC) summary['QC tools skip'] = skipQC.join(', ') if (params.noGVCF) summary['No GVCF'] = params.noGVCF if (params.noStrelkaBP) summary['No Strelka BP'] = params.noStrelkaBP if (params.sequencing_center) summary['Sequenced by '] = params.sequencing_center @@ -254,7 +254,7 @@ process GetSoftwareVersions { output: file 'software_versions_mqc.yaml' into yamlSoftwareVersion - when: !('versions' in skip) + when: !('versions' in skipQC) script: """ @@ -391,7 +391,7 @@ process FastQCFQ { output: file "*_fastqc.{zip,html}" into fastQCFQReport - when: step == 'mapping' && !('fastqc' in skip) + when: step == 'mapping' && !('fastqc' in skipQC) script: @@ -413,7 +413,7 @@ process FastQCBAM { output: file "*_fastqc.{zip,html}" into fastQCBAMReport - when: step == 'mapping' && !('fastqc' in skip) + when: step == 'mapping' && !('fastqc' in skipQC) script: """ @@ -523,7 +523,7 @@ process MarkDuplicates { publishDir params.outdir, mode: params.publishDirMode, saveAs: { - if (it == "${idSample}.bam.metrics" && 'markduplicates' in skip) "Reports/${idSample}/MarkDuplicates/${it}" + if (it == "${idSample}.bam.metrics" && 'markduplicates' in skipQC) "Reports/${idSample}/MarkDuplicates/${it}" else "Preprocessing/${idSample}/DuplicateMarked/${it}" } @@ -551,7 +551,7 @@ process MarkDuplicates { """ } -if ('markduplicates' in skip) markDuplicatesReport.close() +if ('markduplicates' in skipQC) markDuplicatesReport.close() duplicateMarkedBams = duplicateMarkedBams.dump(tag:'MD BAM') markDuplicatesReport = markDuplicatesReport.dump(tag:'MD Report') @@ -747,7 +747,7 @@ process SamtoolsStats { output: file ("${bam}.samtools.stats.out") into samtoolsStatsReport - when: !('samtools' in skip) + when: !('samtools' in skipQC) script: """ @@ -776,7 +776,7 @@ process BamQC { output: file("${bam.baseName}") into bamQCReport - when: !('bamqc' in skip) + when: !('bamqc' in skipQC) script: use_bed = params.targetBED ? "-gff ${targetBED}" : '' @@ -1694,7 +1694,7 @@ process BcftoolsStats { output: file ("*.bcf.tools.stats.out") into bcftoolsReport - when: !('bcftools' in skip) + when: !('bcftools' in skipQC) script: """ @@ -1717,7 +1717,7 @@ process Vcftools { output: file ("${reduceVCF(vcf.fileName)}.*") into vcftoolsReport - when: !('vcftools' in skip) + when: !('vcftools' in skipQC) script: """ @@ -2035,7 +2035,7 @@ process MultiQC { output: set file("*multiqc_report.html"), file("*multiqc_data") into multiQCOut - when: !('multiqc' in skip) + when: !('multiqc' in skipQC) script: """ @@ -2325,7 +2325,7 @@ def defineAnnoList() { } // Define list of skipable QC tools -def defineSkipList() { +def defineSkipQClist() { return [ 'bamqc', 'bcftools', diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index 2e947e8a24..86e26ed777 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -30,7 +30,7 @@ do shift # past value ;; --no-reports) - REPORTS="--skip all" + REPORTS="--skipQC all" shift # past value ;; --offline) From c0d69e10944762794b2cd1661a099076b74a2bd4 Mon Sep 17 00:00:00 2001 From: Johannes Alneberg Date: Mon, 2 Sep 2019 16:31:04 +0200 Subject: [PATCH 028/854] Memory parameter singleCPUMem is now possible to use (#22) * Memory parameter singleCPUMem is now possible to use * Updated CHANGELOG * No import, but in a new place --- CHANGELOG.md | 1 + conf/base.config | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dfc3f6f62..d7f781d6dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -88,6 +88,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#18](https://github.com/nf-core/sarek/pull/18) - Use same font for nf-core and sarek in ascii art - [#20](https://github.com/nf-core/sarek/pull/20) - Use new logo in README - [#20](https://github.com/nf-core/sarek/pull/20) - Fix path to references genomes +- [#22](https://github.com/nf-core/sarek/pull/22) - Fix --singleCPUMem issue ## [2.3.FIX1] - 2019-03-04 diff --git a/conf/base.config b/conf/base.config index 942acc7a91..1d7ff02e52 100644 --- a/conf/base.config +++ b/conf/base.config @@ -22,7 +22,7 @@ params { process { cpus = {check_resource(params.cpus * task.attempt)} - memory = {check_resource(params.singleCPUMem * task.attempt)} + memory = {check_resource((params.singleCPUMem as nextflow.util.MemoryUnit) * task.attempt)} time = {check_resource(24.h * task.attempt)} shell = ['/bin/bash', '-euo', 'pipefail'] @@ -50,10 +50,10 @@ process { } withLabel:memory_singleCPU_2_task { - memory = {check_resource(params.singleCPUMem * 2 * task.attempt)} + memory = {check_resource((params.singleCPUMem as nextflow.util.MemoryUnit) * 2 * task.attempt)} } withLabel:memory_singleCPU_task_sq { - memory = {check_resource(params.singleCPUMem * task.attempt * task.attempt)} + memory = {check_resource((params.singleCPUMem as nextflow.util.MemoryUnit) * task.attempt * task.attempt)} } withLabel:memory_max { From 2647ec1b81d9f6103b845d17ad9548a37a6ecab8 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Tue, 3 Sep 2019 15:29:34 +0200 Subject: [PATCH 029/854] Add GitHubActions (#27) * feat: Add GitHubActions * feat: reduce linting time * feat: add --memory for script * feat: use --max_memory to limit memory usage to 6.GB on GitHub actions * install nextflow directly * try matrix * use export to get correct nextflow version * add linting tests * fix with node version indent * rename jobs * code polish * feat: add badges for GitHub Actions * test branch protection --- .github/workflows/branch.yml | 14 ++++++++++++++ .github/workflows/ci.yml | 27 +++++++++++++++++++++++++++ .github/workflows/linting.yml | 18 ++++++++++++++++++ .travis.yml | 2 +- CHANGELOG.md | 1 + README.md | 2 ++ scripts/build_reference.sh | 14 ++++++++++---- scripts/download_image.sh | 2 +- scripts/run_tests.sh | 12 +++++++++--- 9 files changed, 83 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/branch.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/linting.yml diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml new file mode 100644 index 0000000000..05b94b0daa --- /dev/null +++ b/.github/workflows/branch.yml @@ -0,0 +1,14 @@ +name: nf-core branch protection +# This workflow is triggered on PRs to master branch on the repository +on: + pull_request: + branches: + - master + +jobs: + test: + runs-on: ubuntu-latest + steps: + # PRs are only ok if coming from an nf-core dev branch + - name: Check PRs + run: [ ${GITHUB_ACTOR} = "nf-core" ] && [ ${GITHUB_HEAD_REF} = "dev" ] \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..a42622b711 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,27 @@ +name: nf-core CI +# This workflow is triggered on pushes and PRs to the repository. +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + test: [ANNOTATESNPEFF, ANNOTATEVEP, GERMLINE, SOMATIC, TARGETED] + nxf_ver: ['19.04.0', ''] + steps: + - uses: actions/checkout@v1 + - name: Install Nextflow + run: | + export NXF_VER=${{ matrix.nxf_ver }} + wget -qO- get.nextflow.io | bash + sudo mv nextflow /usr/local/bin/ + - name: Download image + run: | + ${GITHUB_WORKSPACE}/scripts/download_image.sh -n docker --test ${{ matrix.test }} + - name: Build References + run: | + ${GITHUB_WORKSPACE}/scripts/build_reference.sh --test ${{ matrix.test }} --verbose --memory 6.GB + - name: Run test + run: | + ${GITHUB_WORKSPACE}/scripts/run_tests.sh --test ${{ matrix.test }} --verbose --memory 6.GB \ No newline at end of file diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml new file mode 100644 index 0000000000..0bb9aadd17 --- /dev/null +++ b/.github/workflows/linting.yml @@ -0,0 +1,18 @@ +name: nf-core linting +# This workflow is triggered on pushes and PRs to the repository. +on: [push, pull_request] + +jobs: + Markdown: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-node@v1 + with: + node-version: '10' + - name: Install markdownlint + run: | + npm install -g markdownlint-cli + - name: Run Markdownlint + run: | + markdownlint ${GITHUB_WORKSPACE} -c ${GITHUB_WORKSPACE}/.github/markdownlint.yml \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index cbb65a0da6..7fb126f18c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,6 +58,6 @@ jobs: include: - stage: "Linting" name: "Markdown" - env: TEST=GERMLINE NXF_VER=19.04.0 + env: TEST=LINT NXF_VER=19.04.0 script: - markdownlint ${TRAVIS_BUILD_DIR} -c ${TRAVIS_BUILD_DIR}/.github/markdownlint.yml \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index d7f781d6dd..f26fa7ff0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#20](https://github.com/nf-core/sarek/pull/20) - Add `markdownlint` config file - [#21](https://github.com/nf-core/sarek/pull/21) - Add tests for latest Nextflow version as well - [#21](https://github.com/nf-core/sarek/pull/21) - Add `genomes.config` for genomes without AWS iGenomes +- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Use Github actions for CI ### `Changed` diff --git a/README.md b/README.md index 058a01b5ba..dd52d8cea4 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ [![nf-core][nf-core-badge]](https://nf-co.re/) [![Travis build status][travis-badge]](https://travis-ci.com/nf-core/sarek/) +[![GitHub Actions CI Status](https://github.com/nf-core/sarek/workflows/nf-core%20CI/badge.svg)](https://github.com/nf-core/sarek/actions) +[![GitHub Actions Linting Status](https://github.com/nf-core/sarek/workflows/nf-core%20linting/badge.svg)](https://github.com/nf-core/sarek/actions) [![CircleCi build status][circleci-badge]](https://circleci.com/gh/nf-core/sarek/) [![Install with bioconda][bioconda-badge]](https://bioconda.github.io/) diff --git a/scripts/build_reference.sh b/scripts/build_reference.sh index 2e34a04d0d..636b161628 100755 --- a/scripts/build_reference.sh +++ b/scripts/build_reference.sh @@ -4,14 +4,15 @@ set -xeuo pipefail # This script build small reference for sarek tests # https://github.com/nf-core/test-datasets/raw/sarek -usage() { echo "Usage: $0 <-p profile> <-t test> <-v>" 1>&2; exit 1; } +usage() { echo "Usage: $0 <-p profile> <-t test> <-v> <-m memory>" 1>&2; exit 1; } +MEMORY='7.GB' NXF_SINGULARITY_CACHEDIR=${NXF_SINGULARITY_CACHEDIR:-work/singularity/.} OFFLINE='' PROFILE=docker TEST=ALL -TRAVIS_BUILD_DIR=${TRAVIS_BUILD_DIR:-.} TRAVIS=${TRAVIS:-false} +TRAVIS_BUILD_DIR=${TRAVIS_BUILD_DIR:-.} VERBOSE='' while [[ $# -gt 0 ]] @@ -23,6 +24,11 @@ do shift # past argument shift # past value ;; + -m|--memory) + MEMORY=$2 + shift # past argument + shift # past value + ;; --offline) OFFLINE="--offline" shift # past value @@ -44,9 +50,9 @@ do done # Build references for smallGRCh37 -if ! [[ ANNOTATESNPEFF,ANNOTATEVEP =~ $TEST ]] +if ! [[ ANNOTATEBOTH,ANNOTATESNPEFF,ANNOTATEVEP,LINT =~ $TEST ]] then rm -rf references - nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile test,${PROFILE} --build --outdir references ${VERBOSE} ${OFFLINE} + nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile test,${PROFILE} --build --outdir references ${VERBOSE} ${OFFLINE} --max_memory ${MEMORY} rm -rf .nextflow* references/pipeline_info work fi diff --git a/scripts/download_image.sh b/scripts/download_image.sh index 862f265033..959e8fb843 100755 --- a/scripts/download_image.sh +++ b/scripts/download_image.sh @@ -74,7 +74,7 @@ then get_image sarekvep ${VERSION}.${SOURCEGENOME} ${VERSION}.${GENOME} fi -if ! [[ ANNOTATEBOTH,ANNOTATESNPEFF,ANNOTATEVEP,SNPEFF,VEP =~ $TEST ]] +if ! [[ ANNOTATEBOTH,ANNOTATESNPEFF,ANNOTATEVEP,LINT,SNPEFF,VEP =~ $TEST ]] then get_image sarek ${VERSION} ${VERSION} fi diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index 86e26ed777..a37958ea35 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -4,14 +4,15 @@ set -xeuo pipefail # This script run sarek tests # https://github.com/nf-core/test-datasets/raw/sarek -usage() { echo "Usage: $0 <-p profile> <-t test> <-c cpus> <-n> <-v>" 1>&2; exit 1; } +usage() { echo "Usage: $0 <-p profile> <-t test> <-c cpus> <-n> <-v> <-m memory>" 1>&2; exit 1; } CPUS=2 LOGS='' -REPORTS='' +MEMORY='7.GB' NXF_SINGULARITY_CACHEDIR=${NXF_SINGULARITY_CACHEDIR:-work/singularity/.} OFFLINE=false PROFILE=docker +REPORTS='' TEST=MULTIPLE TRAVIS=${TRAVIS:-false} TRAVIS_BUILD_DIR=${TRAVIS_BUILD_DIR:-.} @@ -25,6 +26,11 @@ do CPUS=$2 shift # past value ;; + -m|--memory) + MEMORY=$2 + shift # past argument + shift # past value + ;; -n|--no-logs) LOGS=true shift # past value @@ -66,7 +72,7 @@ function manage_logs() { } function run_sarek() { - nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile test,${PROFILE} ${VERBOSE} --monochrome_logs ${REPORTS} $@ + nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile test,${PROFILE} ${VERBOSE} --monochrome_logs ${REPORTS} --max_memory ${MEMORY} $@ } if [[ $OFFLINE == false ]] From 1547a3186414696f5ae9c1c0e33b8302c7e789c7 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Tue, 3 Sep 2019 18:41:11 +0200 Subject: [PATCH 030/854] small refactoring (#30) * Simplify code of MapReads process * Fix launching of FastQCBAM process * Add TIDDIT version to reports --- .github/workflows/branch.yml | 3 +- bin/scrape_software_versions.py | 2 + main.nf | 75 ++++++++++++++------------------- 3 files changed, 36 insertions(+), 44 deletions(-) diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 05b94b0daa..e3c557ce13 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -11,4 +11,5 @@ jobs: steps: # PRs are only ok if coming from an nf-core dev branch - name: Check PRs - run: [ ${GITHUB_ACTOR} = "nf-core" ] && [ ${GITHUB_HEAD_REF} = "dev" ] \ No newline at end of file + run: | + [ ${GITHUB_ACTOR} = "nf-core" ] && [ ${GITHUB_HEAD_REF} = "dev" ] \ No newline at end of file diff --git a/bin/scrape_software_versions.py b/bin/scrape_software_versions.py index 96281d68c5..92793a45b9 100755 --- a/bin/scrape_software_versions.py +++ b/bin/scrape_software_versions.py @@ -22,6 +22,7 @@ 'samtools': ['v_samtools.txt', r"samtools (\S+)"], 'SnpEff': ['v_snpeff.txt', r"version SnpEff (\S+)"], 'Strelka': ['v_strelka.txt', r"([0-9.]+)"], + 'TIDDIT': ['v_tiddit.txt', r"TIDDIT-(\S+)"], 'vcftools': ['v_vcftools.txt', r"([0-9.]+)"], 'VEP': ['v_vep.txt', r"ensembl-vep : (\S+)"], } @@ -43,6 +44,7 @@ results['samtools'] = 'N/A' results['SnpEff'] = 'N/A' results['Strelka'] = 'N/A' +results['TIDDIT'] = 'N/A' results['vcftools'] = 'N/A' results['VEP'] = 'N/A' diff --git a/main.nf b/main.nf index c1cd79fd15..172b31e267 100644 --- a/main.nf +++ b/main.nf @@ -138,11 +138,11 @@ if (!checkParameterExistence(step, stepList)) exit 1, "Unknown step ${step}, see toolList = defineToolList() tools = params.tools ? params.tools.split(',').collect{it.trim().toLowerCase()} : [] -if (!checkParameterList(tools,toolList)) exit 1, 'Unknown tool(s), see --help for more information' +if (!checkParameterList(tools, toolList)) exit 1, 'Unknown tool(s), see --help for more information' skipQClist = defineSkipQClist() skipQC = params.skipQC ? params.skipQC == 'all' ? skipQClist : params.skipQC.split(',').collect{it.trim().toLowerCase()} : [] -if (!checkParameterList(skipQC,skipQClist)) exit 1, 'Unknown QC tool(s), see --help for more information' +if (!checkParameterList(skipQC, skipQClist)) exit 1, 'Unknown QC tool(s), see --help for more information' annoList = defineAnnoList() annotateTools = params.annotateTools ? params.annotateTools.split(',').collect{it.trim().toLowerCase()} : [] @@ -170,8 +170,8 @@ if (workflow.profile == 'awsbatch') { ch_output_docs = Channel.fromPath("${baseDir}/docs/output.md") tsvPath = null -if (params.sample) if (hasExtension(params.sample,"tsv") || hasExtension(params.sample,"vcf") || hasExtension(params.sample,"vcf.gz")) tsvPath = params.sample -if (params.sample) if (hasExtension(params.sample,"vcf") || hasExtension(params.sample,"vcf.gz")) step = "annotate" +if (params.sample) if (hasExtension(params.sample, "tsv") || hasExtension(params.sample, "vcf") || hasExtension(params.sample, "vcf.gz")) tsvPath = params.sample +if (params.sample) if (hasExtension(params.sample, "vcf") || hasExtension(params.sample, "vcf.gz")) step = "annotate" // If no input file specified, trying to get TSV files corresponding to step in the TSV directory // only for steps recalibrate and variantCalling @@ -189,7 +189,7 @@ if (tsvPath) { case 'annotate': break default: exit 1, "Unknown step ${step}" } -} else if (params.sample) if (!hasExtension(params.sample,"tsv")) { +} else if (params.sample) if (!hasExtension(params.sample, "tsv")) { println "No TSV file" if (step != 'mapping') exit 1, 'No other step than "mapping" support a dir as an input' println "Reading ${params.sample} directory" @@ -238,7 +238,7 @@ if (params.email) { summary['E-mail Address'] = params.email summary['MultiQC maxsize'] = params.maxMultiqcEmailFileSize } -log.info summary.collect { k,v -> "${k.padRight(18)}: $v" }.join("\n") +log.info summary.collect { k, v -> "${k.padRight(18)}: $v" }.join("\n") if (params.monochrome_logs) log.info "----------------------------------------------------" else log.info "\033[2m----------------------------------------------------\033[0m" @@ -274,6 +274,7 @@ process GetSoftwareVersions { qualimap --version &> v_qualimap.txt 2>&1 || true R --version &> v_r.txt || true samtools --version &> v_samtools.txt 2>&1 || true + tiddit &> v_tiddit.txt 2>&1 || true vcftools --version &> v_vcftools.txt 2>&1 || true vep --help &> v_vep.txt 2>&1 || true @@ -305,7 +306,7 @@ process CreateIntervalBeds { script: // If the interval file is BED format, the fifth column is interpreted to // contain runtime estimates, which is then used to combine short-running jobs - if (hasExtension(intervals,"bed")) + if (hasExtension(intervals, "bed")) """ awk -vFS="\t" '{ t = \$5 # runtime estimate @@ -363,7 +364,7 @@ else (inputReads, inputReadsFastQC) = Channel.empty().into(2) inputPairReadsFastQC = Channel.create() inputBAMFastQC = Channel.create() -inputReadsFastQC.choice(inputPairReadsFastQC, inputBAMFastQC) {hasExtension(it[4],"bam")? 1 : 0} +inputReadsFastQC.choice(inputPairReadsFastQC, inputBAMFastQC) {hasExtension(it[3], "bam") ? 1 : 0} // Removing inputFile2 wich is null in case of uBAM inputBAMFastQC = inputBAMFastQC.map { @@ -453,24 +454,12 @@ process MapReads { // adjust mismatch penalty for tumor samples status = statusMap[idPatient, idSample] extra = status == 1 ? "-B 3" : "" - if (hasExtension(inputFile1,"fastq.gz") || hasExtension(inputFile1,"fq.gz")) + convertToFastq = hasExtension(inputFile1, "bam") ? "gatk --java-options -Xmx${task.memory.toGiga()}g SamToFastq --INPUT=${inputFile1} --FASTQ=/dev/stdout --INTERLEAVE=true --NON_PF=true | \\" : "" + input = hasExtension(inputFile1, "bam") ? "-p /dev/stdin - 2> >(tee ${inputFile1}.bwa.stderr.log >&2)" : "${inputFile1} ${inputFile2}" """ - bwa mem -K 100000000 -R \"${readGroup}\" ${extra} -t ${task.cpus} -M \ - ${genomeFile} ${inputFile1} ${inputFile2} | \ - samtools sort --threads ${task.cpus} -m 2G - > ${idRun}.bam - """ - else if (hasExtension(inputFile1,"bam")) - """ - gatk --java-options -Xmx${task.memory.toGiga()}g \ - SamToFastq \ - --INPUT=${inputFile1} \ - --FASTQ=/dev/stdout \ - --INTERLEAVE=true \ - --NON_PF=true \ - | \ - bwa mem -K 100000000 -p -R \"${readGroup}\" ${extra} -t ${task.cpus} -M ${genomeFile} \ - /dev/stdin - 2> >(tee ${inputFile1}.bwa.stderr.log >&2) \ - | \ + ${convertToFastq} + bwa mem -K 100000000 -R \"${readGroup}\" ${extra} -t ${task.cpus} -M ${genomeFile} \ + ${input} | \ samtools sort --threads ${task.cpus} -m 2G - > ${idRun}.bam """ } @@ -481,7 +470,7 @@ bamMapped = bamMapped.dump(tag:'Mapped BAM') singleBam = Channel.create() multipleBam = Channel.create() -bamMapped.groupTuple(by:[0,1]) +bamMapped.groupTuple(by:[0, 1]) .choice(singleBam, multipleBam) {it[2].size() > 1 ? 1 : 0} singleBam = singleBam.map { idPatient, idSample, idRun, bam -> @@ -601,7 +590,7 @@ process BaseRecalibrator { """ } -tableGatherBQSRReports = tableGatherBQSRReports.groupTuple(by:[0,1]) +tableGatherBQSRReports = tableGatherBQSRReports.groupTuple(by:[0, 1]) // STEP 3.5: MERGING RECALIBRATION TABLES @@ -688,7 +677,7 @@ process ApplyBQSR { """ } -bamMergeBamRecal = bamMergeBamRecal.groupTuple(by:[0,1]) +bamMergeBamRecal = bamMergeBamRecal.groupTuple(by:[0, 1]) // STEP 4.5: MERGING THE RECALIBRATED BAM FILES @@ -856,7 +845,7 @@ process HaplotypeCaller { """ } -gvcfHaplotypeCaller = gvcfHaplotypeCaller.groupTuple(by:[0,1,2]) +gvcfHaplotypeCaller = gvcfHaplotypeCaller.groupTuple(by:[0, 1, 2]) if (params.noGVCF) gvcfHaplotypeCaller.close() else gvcfHaplotypeCaller = gvcfHaplotypeCaller.dump(tag:'GVCF HaplotypeCaller') @@ -897,7 +886,7 @@ process GenotypeGVCFs { """ } -vcfGenotypeGVCFs = vcfGenotypeGVCFs.groupTuple(by:[0,1,2]) +vcfGenotypeGVCFs = vcfGenotypeGVCFs.groupTuple(by:[0, 1, 2]) // STEP STRELKA.1 - SINGLE MODE @@ -1112,7 +1101,7 @@ process Mutect2 { """ } -vcfMuTect2 = vcfMuTect2.groupTuple(by:[0,1,2]) +vcfMuTect2 = vcfMuTect2.groupTuple(by:[0, 1, 2]) // STEP FREEBAYES @@ -1150,7 +1139,7 @@ process FreeBayes { // we are merging the VCFs that are called separatelly for different intervals // so we can have a single sorted VCF containing all the calls for a given caller -vcfFreeBayes = vcfFreeBayes.groupTuple(by:[0,1,2]) +vcfFreeBayes = vcfFreeBayes.groupTuple(by:[0, 1, 2]) // STEP MERGING VCF - FREEBAYES, GATK HAPLOTYPECALLER & GATK MUTECT2 @@ -1489,7 +1478,7 @@ process Mpileup { """ } -mpileupMerge = mpileupMerge.groupTuple(by:[0,1]) +mpileupMerge = mpileupMerge.groupTuple(by:[0, 1]) // STEP CONTROLFREEC.2 - MERGE MPILEUP @@ -2165,7 +2154,7 @@ def create_workflow_summary(summary) { plot_type: 'html' data: |
-${summary.collect { k,v -> "
$k
${v ?: 'N/A'}
" }.join("\n")} +${summary.collect { k, v -> "
$k
${v ?: 'N/A'}
" }.join("\n")}
""".stripIndent() @@ -2380,8 +2369,8 @@ def extractBam(tsvFile) { def bamFile = returnFile(row[4]) def baiFile = returnFile(row[5]) - if (!hasExtension(bamFile,"bam")) exit 1, "File: ${bamFile} has the wrong extension. See --help for more information" - if (!hasExtension(baiFile,"bai")) exit 1, "File: ${baiFile} has the wrong extension. See --help for more information" + if (!hasExtension(bamFile, "bam")) exit 1, "File: ${bamFile} has the wrong extension. See --help for more information" + if (!hasExtension(baiFile, "bai")) exit 1, "File: ${baiFile} has the wrong extension. See --help for more information" return [idPatient, gender, status, idSample, bamFile, baiFile] } @@ -2445,13 +2434,13 @@ def extractFastq(tsvFile) { def idSample = row[3] def idRun = row[4] def file1 = returnFile(row[5]) - def file2 = file("null") - if (hasExtension(file1,"fastq.gz") || hasExtension(file1,"fq.gz")) { + def file2 = "null" + if (hasExtension(file1, "fastq.gz") || hasExtension(file1, "fq.gz")) { checkNumberOfItem(row, 7) file2 = returnFile(row[6]) - if (!hasExtension(file2,"fastq.gz") && !hasExtension(file2,"fq.gz")) exit 1, "File: ${file2} has the wrong extension. See --help for more information" + if (!hasExtension(file2, "fastq.gz") && !hasExtension(file2, "fq.gz")) exit 1, "File: ${file2} has the wrong extension. See --help for more information" } - else if (hasExtension(file1,"bam")) checkNumberOfItem(row, 6) + else if (hasExtension(file1, "bam")) checkNumberOfItem(row, 6) else "No recognisable extention for input file: ${file1}" [idPatient, gender, status, idSample, idRun, file1, file2] @@ -2473,9 +2462,9 @@ def extractRecal(tsvFile) { def baiFile = returnFile(row[5]) def recalTable = returnFile(row[6]) - if (!hasExtension(bamFile,"bam")) exit 1, "File: ${bamFile} has the wrong extension. See --help for more information" - if (!hasExtension(baiFile,"bai")) exit 1, "File: ${baiFile} has the wrong extension. See --help for more information" - if (!hasExtension(recalTable,"recal.table")) exit 1, "File: ${recalTable} has the wrong extension. See --help for more information" + if (!hasExtension(bamFile, "bam")) exit 1, "File: ${bamFile} has the wrong extension. See --help for more information" + if (!hasExtension(baiFile, "bai")) exit 1, "File: ${baiFile} has the wrong extension. See --help for more information" + if (!hasExtension(recalTable, "recal.table")) exit 1, "File: ${recalTable} has the wrong extension. See --help for more information" [idPatient, gender, status, idSample, bamFile, baiFile, recalTable] } From f4a9dbf5d79fa0a429e85563c592b48ef0d3df87 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 3 Sep 2019 20:36:50 +0200 Subject: [PATCH 031/854] print more info for branch protection github actions --- .github/workflows/branch.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index e3c557ce13..69170e93f0 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -12,4 +12,16 @@ jobs: # PRs are only ok if coming from an nf-core dev branch - name: Check PRs run: | + echo "HOME: ${HOME}" + echo "GITHUB_WORKFLOW: ${GITHUB_WORKFLOW}" + echo "GITHUB_ACTION: ${GITHUB_ACTION}" + echo "GITHUB_ACTOR: ${GITHUB_ACTOR}" + echo "GITHUB_REPOSITORY: ${GITHUB_REPOSITORY}" + echo "GITHUB_EVENT_NAME: ${GITHUB_EVENT_NAME}" + echo "GITHUB_EVENT_PATH: ${GITHUB_EVENT_PATH}" + echo "GITHUB_WORKSPACE: ${GITHUB_WORKSPACE}" + echo "GITHUB_SHA: ${GITHUB_SHA}" + echo "GITHUB_REF: ${GITHUB_REF}" + echo "GITHUB_HEAD_REF: ${GITHUB_HEAD_REF}" + echo "GITHUB_BASE_REF: ${GITHUB_BASE_REF}" [ ${GITHUB_ACTOR} = "nf-core" ] && [ ${GITHUB_HEAD_REF} = "dev" ] \ No newline at end of file From 70fb0268421619f7e7e0c99964a99aeee743fb8d Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Wed, 4 Sep 2019 15:36:57 +0200 Subject: [PATCH 032/854] adding nf-core lint (#31) * Fix nf-core lint on sarek * Remove extra CI from .travis.yml and GitHub Actions nf-core CI * Add new nf-core extra CI * remove fancy badges * Remove TODO nf-core comments in code * Use 1.1_2 version for rcolorbrewer, according to nf-core lint --- .github/workflows/ci-extra.yml | 27 +++++++++++++++++ .github/workflows/ci.yml | 10 ++---- .github/workflows/linting.yml | 24 ++++++++++++++- .travis.yml | 54 +++++++++++---------------------- CHANGELOG.md | 6 ++++ Dockerfile | 2 +- README.md | 33 ++++++-------------- bin/scrape_software_versions.py | 1 - build.nf | 2 -- environment.yml | 2 +- main.nf | 2 -- nextflow.config | 2 +- 12 files changed, 88 insertions(+), 77 deletions(-) create mode 100644 .github/workflows/ci-extra.yml diff --git a/.github/workflows/ci-extra.yml b/.github/workflows/ci-extra.yml new file mode 100644 index 0000000000..7992bfb2ce --- /dev/null +++ b/.github/workflows/ci-extra.yml @@ -0,0 +1,27 @@ +name: nf-core extra CI +# This workflow is triggered on pushes and PRs to the repository. +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + test: [ANNOTATESNPEFF, ANNOTATEVEP, GERMLINE, SOMATIC, TARGETED] + nxf_ver: ['19.04.0', ''] + steps: + - uses: actions/checkout@v1 + - name: Install Nextflow + run: | + export NXF_VER=${{ matrix.nxf_ver }} + wget -qO- get.nextflow.io | bash + sudo mv nextflow /usr/local/bin/ + - name: Download image + run: | + ${GITHUB_WORKSPACE}/scripts/download_image.sh -n docker --test ${{ matrix.test }} + - name: Build References + run: | + ${GITHUB_WORKSPACE}/scripts/build_reference.sh --test ${{ matrix.test }} --verbose --memory 6.GB + - name: Run test + run: | + ${GITHUB_WORKSPACE}/scripts/run_tests.sh --test ${{ matrix.test }} --verbose --memory 6.GB \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a42622b711..bc697f2f1c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,6 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - test: [ANNOTATESNPEFF, ANNOTATEVEP, GERMLINE, SOMATIC, TARGETED] nxf_ver: ['19.04.0', ''] steps: - uses: actions/checkout@v1 @@ -16,12 +15,9 @@ jobs: export NXF_VER=${{ matrix.nxf_ver }} wget -qO- get.nextflow.io | bash sudo mv nextflow /usr/local/bin/ - - name: Download image + - name: Build references run: | - ${GITHUB_WORKSPACE}/scripts/download_image.sh -n docker --test ${{ matrix.test }} - - name: Build References - run: | - ${GITHUB_WORKSPACE}/scripts/build_reference.sh --test ${{ matrix.test }} --verbose --memory 6.GB + nextflow run ${GITHUB_WORKSPACE}/build.nf -profile test,docker --build --outdir references - name: Run test run: | - ${GITHUB_WORKSPACE}/scripts/run_tests.sh --test ${{ matrix.test }} --verbose --memory 6.GB \ No newline at end of file + nextflow run ${GITHUB_WORKSPACE} -profile test,docker \ No newline at end of file diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 0bb9aadd17..8c1e97c073 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -15,4 +15,26 @@ jobs: npm install -g markdownlint-cli - name: Run Markdownlint run: | - markdownlint ${GITHUB_WORKSPACE} -c ${GITHUB_WORKSPACE}/.github/markdownlint.yml \ No newline at end of file + markdownlint ${GITHUB_WORKSPACE} -c ${GITHUB_WORKSPACE}/.github/markdownlint.yml + nf-core: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Install Nextflow + run: | + wget -qO- get.nextflow.io | bash + sudo mv nextflow /usr/local/bin/ + - uses: actions/setup-python@v1 + with: + python-version: '3.6' + architecture: 'x64' + - name: Install pip + run: | + sudo apt install python3-pip + pip install --upgrade pip + - name: Install nf-core tools + run: | + pip install nf-core + - name: Run nf-core lint + run: | + nf-core lint ${GITHUB_WORKSPACE} \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 7fb126f18c..d098cba819 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,62 +2,42 @@ sudo: required language: python jdk: openjdk8 services: docker - -addons: - apt: - update: true - python: '3.6' cache: pip - matrix: fast_finish: true -env: - matrix: - - TEST=ANNOTATEVEP NXF_VER=19.04.0 - - TEST=ANNOTATEVEP NXF_VER='' - - TEST=SOMATIC NXF_VER=19.04.0 - - TEST=SOMATIC NXF_VER='' - - TEST=TARGETED NXF_VER=19.04.0 - - TEST=TARGETED NXF_VER='' - - TEST=GERMLINE NXF_VER=19.04.0 - - TEST=GERMLINE NXF_VER='' - - TEST=ANNOTATESNPEFF NXF_VER=19.04.0 - - TEST=ANNOTATESNPEFF NXF_VER='' - before_install: # PRs to master are only ok if coming from dev branch - '[ $TRAVIS_PULL_REQUEST = "false" ] || [ $TRAVIS_BRANCH != "master" ] || ([ $TRAVIS_PULL_REQUEST_SLUG = $TRAVIS_REPO_SLUG ] && [ $TRAVIS_PULL_REQUEST_BRANCH = "dev" ])' # Pull the docker image first so the test doesn't wait for this - - "travis_retry ./scripts/download_image.sh -n docker --test $TEST" + - docker pull nfcore/sarek:dev + # Fake the tag locally so that the pipeline runs properly + # Looks weird when this is :dev to :dev, but makes sense when testing code for a release (:dev to :1.0.1) + - docker tag nfcore/sarek:dev nfcore/sarek:dev install: # Install Nextflow - mkdir /tmp/nextflow && cd /tmp/nextflow - wget -qO- get.nextflow.io | bash - sudo ln -s /tmp/nextflow/nextflow /usr/local/bin/nextflow - # # Install nf-core/tools - # - pip install --upgrade pip - # - pip install nf-core + # Install nf-core/tools + - pip install --upgrade pip + - pip install nf-core # Reset - mkdir ${TRAVIS_BUILD_DIR}/tests && cd ${TRAVIS_BUILD_DIR}/tests # Install markdownlint-cli - sudo apt-get install npm && npm install -g markdownlint-cli -# Build references if needed -before_script: - - ${TRAVIS_BUILD_DIR}/scripts/build_reference.sh --test $TEST --verbose +env: + - NXF_VER='19.04.0' # Specify a minimum NF version that should be tested and work + - NXF_VER='' # Plus: get the latest NF version and check that it works -# Actual tests script: - - "${TRAVIS_BUILD_DIR}/scripts/run_tests.sh --test $TEST --verbose --no-reports" - -# Linting -jobs: - include: - - stage: "Linting" - name: "Markdown" - env: TEST=LINT NXF_VER=19.04.0 - script: - - markdownlint ${TRAVIS_BUILD_DIR} -c ${TRAVIS_BUILD_DIR}/.github/markdownlint.yml \ No newline at end of file + # Lint the pipeline code + - nf-core lint ${TRAVIS_BUILD_DIR} + # Lint the documentation + - markdownlint ${TRAVIS_BUILD_DIR} -c ${TRAVIS_BUILD_DIR}/.github/markdownlint.yml + # Run the pipeline with the test profile + - nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile test,docker --build --outdir references + - nextflow run ${TRAVIS_BUILD_DIR} -profile test,docker \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index f26fa7ff0c..137b11519a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,8 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#21](https://github.com/nf-core/sarek/pull/21) - Add tests for latest Nextflow version as well - [#21](https://github.com/nf-core/sarek/pull/21) - Add `genomes.config` for genomes without AWS iGenomes - [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Use Github actions for CI +- [#31](https://github.com/nf-core/sarek/pull/31) - Add nf-core lint +- [#31](https://github.com/nf-core/sarek/pull/31) - Add extra CI to GitHub Actions nf-core extra CI ### `Changed` @@ -70,6 +72,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#18](https://github.com/nf-core/sarek/pull/18), [#29](https://github.com/nf-core/sarek/pull/29) - `--noReports` is now `--skipQC all` - [#18](https://github.com/nf-core/sarek/pull/18), [#21](https://github.com/nf-core/sarek/pull/21) - Update logo - [#21](https://github.com/nf-core/sarek/pull/21) - Moved smallGRCh37 path to `genomes.config` +- [#31](https://github.com/nf-core/sarek/pull/31) - Move extra CI to GitHub Actions nf-core extra CI ### `Removed` @@ -77,6 +80,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#13](https://github.com/nf-core/sarek/pull/13) - Removed `BamQCmapped` and `BamQCrecalibrated` processes - [#13](https://github.com/nf-core/sarek/pull/13) - Removed `CompressVCF` - [#18](https://github.com/nf-core/sarek/pull/18) - Removed params `--noReports` +- [#31](https://github.com/nf-core/sarek/pull/31) - Remove extra CI from Travis CI and GitHub Actions nf-core CI ### `Fixed` @@ -90,6 +94,8 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#20](https://github.com/nf-core/sarek/pull/20) - Use new logo in README - [#20](https://github.com/nf-core/sarek/pull/20) - Fix path to references genomes - [#22](https://github.com/nf-core/sarek/pull/22) - Fix --singleCPUMem issue +- [#31](https://github.com/nf-core/sarek/pull/31) - Fix badges according to nf-core lint +- [#31](https://github.com/nf-core/sarek/pull/31) - Fix rcolorbrewer version according to nf-core lint ## [2.3.FIX1] - 2019-03-04 diff --git a/Dockerfile b/Dockerfile index eb660ac656..8cb51fe468 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM nfcore/base:1.6 +FROM nfcore/base LABEL authors="Maxime Garcia" \ description="Docker image containing all requirements for nf-core/sarek pipeline" diff --git a/README.md b/README.md index dd52d8cea4..1140da3e36 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,19 @@ > **An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing** -[![Nextflow version][nextflow-badge]](https://www.nextflow.io/) -[![nf-core][nf-core-badge]](https://nf-co.re/) +[![Nextflow](https://img.shields.io/badge/nextflow-%E2%89%A519.04.0-brightgreen.svg)](https://www.nextflow.io/) +[![nf-core](https://img.shields.io/badge/nf--core-pipeline-brightgreen.svg)](https://nf-co.re/) -[![Travis build status][travis-badge]](https://travis-ci.com/nf-core/sarek/) +[![Travis build status](https://img.shields.io/travis/nf-core/sarek.svg)](https://travis-ci.com/nf-core/sarek/) [![GitHub Actions CI Status](https://github.com/nf-core/sarek/workflows/nf-core%20CI/badge.svg)](https://github.com/nf-core/sarek/actions) [![GitHub Actions Linting Status](https://github.com/nf-core/sarek/workflows/nf-core%20linting/badge.svg)](https://github.com/nf-core/sarek/actions) -[![CircleCi build status][circleci-badge]](https://circleci.com/gh/nf-core/sarek/) +[![CircleCi build status](https://img.shields.io/circleci/project/github/nf-core/sarek.svg)](https://circleci.com/gh/nf-core/sarek/) -[![Install with bioconda][bioconda-badge]](https://bioconda.github.io/) -[![Docker Container available][docker-sarek-badge]](https://hub.docker.com/r/nfcore/sarek/) -[![Install with Singularity][singularity-badge]](https://www.sylabs.io/docs/) +[![install with bioconda](https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg)](http://bioconda.github.io/) +[![Docker Container available](https://img.shields.io/docker/automated/nfcore/sarek.svg)](https://hub.docker.com/r/nfcore/sarek/) +[![Install with Singularity](https://img.shields.io/badge/use%20with-singularity-purple.svg)](https://www.sylabs.io/docs/) -[![Join us on Slack][slack-badge]](https://nfcore.slack.com/messages/CGFUX04HZ/) +[![Join us on Slack](https://img.shields.io/badge/slack-nfcore/sarek-blue.svg)](https://nfcore.slack.com/messages/CGFUX04HZ/) > :warning: This pipeline is a work in progress being ported to nf-core from [SciLifeLab/Sarek](https://github/SciLifeLab/Sarek/) @@ -57,7 +57,7 @@ The nf-core/sarek pipeline comes with documentation about the pipeline, found in ## Credits -Sarek was developed at the [National Genomics Infastructure][ngi-link] and [National Bioinformatics Infastructure Sweden][nbis-link] which are both platforms at [SciLifeLab][scilifelab-link], with the support of [The Swedish Childhood Tumor Biobank (Barntumörbanken)][btb-link]. +Sarek was developed at the [National Genomics Infa Main authors: @@ -106,18 +106,3 @@ You can cite the sarek zenodo record for a specific version using the following You can cite the `nf-core` pre-print as follows: > Ewels PA, Peltzer A, Fillinger S, Alneberg JA, Patel H, Wilm A, Garcia MU, Di Tommaso P, Nahnsen S. **nf-core: Community curated bioinformatics pipelines**. *bioRxiv*. 2019. p. 610741. [doi: 10.1101/610741](https://www.biorxiv.org/content/10.1101/610741v3). - -[bioconda-badge]: https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg?logo=data:image/png;base64,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 -[btb-link]: https://ki.se/forskning/barntumorbanken-0 -[circleci-badge]: https://img.shields.io/circleci/project/github/nf-core/sarek.svg?logo=circleci -[docker-sarek-badge]: https://img.shields.io/docker/automated/nfcore/sarek.svg?logo=docker -[docker-snpeff-badge]: https://img.shields.io/docker/automated/nfcore/sareksnpeff.svg?logo=docker -[docker-vep-badge]: https://img.shields.io/docker/automated/nfcore/sarekvep.svg?logo=docker -[nbis-link]: https://nbis.se -[nextflow-badge]: https://img.shields.io/badge/nextflow-%E2%89%A519.04.0-brightgreen.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAABnlBMVEUkrWIlr2Qlr2Mlr2MlrmMkq2EjqmAlrWMkrGIlr2Mlr2Mlr2Mlr2QlrmMlrmMlr2Mlr2Mlr2MlrmMlrmMlrWMjqV8lrmMlrWIlrmMlrmMkq2Elr2MlrmMlr2MlrmMkrGElrmMlr2Mlr2Qlr2Qlr2MlrmMlr2MlrmMlr2MlrmMblVAlrmMlr2QlrmMlrmMlrmMlrmMlr2Qlr2Qlr2Qlr2MlrmIlr2MdmVMkrWIbllEVhEQNbjQhpFwSeT0YjEoenVYhpFwblVEakU4SfD4blVEak04VhUUZjksZj0wdm1ULaTAho1sipl0enFYUg0MIYisRez4NbzQYi0oIYisMbDMJZS0GXSgholscllETfkAQdjoHXykEWSQEWCQlrmMmr2Qlr2QmrmMmr2Mlr2MlrmQmrmQkrGEYjEoXikgZjkwfnlcdmVMVhEQfoFgcl1IjqV8dm1UakU0akk8blVAUgEEhpVwWhkYUgkMlrWISfkAgoVoWiEcho1sipl0Rez4jqmAenFYPdTkip14ReTwMbTMNcTYKaC8JZCwEWCMFWybkfA15AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfjBQkMMhOJOO+9AAAEWklEQVRYw+1XS28bNxBePS6WBPiWwAcZBizAERQEcRO7PhhpgRQBDARogxwK9EByl1xJ1vu5Xlkv24ph9F93OOQ+ZL12nWvnsEtq+VHkcL5vhobxvxn7Fz85AaFm8vjNi+EfDItaYInEYXzw0WEiYRnUM2s/Jj4HGEoNYQtbWyYG+hWMF4AUwQqkFSLC3zA5msGTaR/AWvB1HgW+l1LjObcs0yCCoOkX+bgDfVJSw4VGGJxx5hm0CcltDxvOESE3IBvEIDZMhT40CbSlnW3xPCGmKRABD2GaMAEn3DO1CU6yG+CnOIJ7CNmCCTzjJLD1IZEia8zIHh94cSCEfgk7tQo/VOcu/HE6DgzjImMumdym275chhdK6gPBEf7A+Ve9OHAq9TfGuTufTn4L4z9SCj73jXHZT+WDAVmMLHm0QnBByg+TZueP0O7h2AQjjMP2BJwdHuMzHUjjkrRn2tPbWr0f/mbhkqWpraT3Vr1U4JaexJX4Vrf6BX/Pc2LJgKcEBsB3i5MNx5w1bXSOO5/UOq3e9bjxGX59Z+pAg9AxbQJj0ptZgpS0yw/Nu3q/W3EGo7+MPH1u2S2RXgQ4ddtDXEC1MZp9u1zBn26XuCQh84fbu3rvujIejBbjNiEWIRSPDYP1dAdbL5Jue9KUG4AFLJzps8gr5XfLxe/DZgfw48ZgVglCXkj27aC6p7W4gapzM7pmKjB9/iejCd7VXQsX0Ajz1LIIz0VV3Kt+ZewMbmph1kIUpGKINmzAmRDBmHQcZQKZUowxwedG16VaKCk2aC5e1um4vjoo+mfj4feITFtIOxP036KTmGlPJh5Jew7yILV78vRnrKyrWR/Y/dPT9+j498h/Kk+eIP/LjR9g3yLCX6fQ8yp5ctgIpYPHx8f7+/t/ok2wQl/aA/BisZjNosCLJSl/OlsrJayNADsbDQaDmwjHx5WwytIDNFB2po7ENhqO44yrO4sWP08rF4DNKzeAHY+rlUrl+vrTVvhS6hMq+9cqCOz2ev1+q1Wvd37dCM8IpmoGIYMHeASPxL7xqduV2Dpg72q1ZvP27w2KTiweSs+yeOEkfQJf6i3EAvR2MpxOH9rp12tKrpJp28tZ2+f/lcROhkOAzstl113V1e9fSjpwqKBSP5lA/if098sQ1Fb68Dac1/51ytSPvEADjgshoRa+Kvj6ENDbmZurtqzev+SCwsGvEfz0WqYmxIyNxa5J9biVE8bAAtdSrQ/Yz51/wGpdeOxR9YHN2Yqfz1R9AKWB0gfm9Q+ShqoJTDMQgHV1+9GyPoT0AlYAaV+XukAecrIp0g6toD7w9AL6oF7MJy6n2wr2glw4Z+q0vGKbL/N/+5UhQ9eYAZ7HxcOSdt4XihaqtF/dy5pI+oAR6LNElBtLhgT1AsWmoaIrlz2KpnjFXIIpH+igxftCJlbSOFeU9+4LB6lXsa9r7xL4/7LqFC+8LubfH8u6QZb7L7azPF5+fu7au3f+9j/k5Jp1oAO4eQAAAABJRU5ErkJggg== -[nf-core-badge]: https://img.shields.io/badge/nf--core-pipeline-brightgreen.svg?logo=data:image/png;base64,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 -[ngi-link]: https://ngisweden.scilifelab.se/ -[scilifelab-link]: https://scilifelab.se -[singularity-badge]: https://img.shields.io/badge/use%20with-singularity-purple.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAB3RJTUUH4wUJDScoDkSKugAACjxJREFUWMOlmGt0XNV1x3/73NeMRho9LFvWy/JDGEcEXCBg0xpqIKFgCAmNnUUMpg2Q8AhxV9MAK6kTWC2w2pAVAkmgzipxWA1ZLEMDFFoeduiqwdiODTHBtmwsy9bLsvUaaazRzNy595x+GGnQ2JITJ+fLPO4+e//v3v999t5HOINljIkAMwczYWOgzafToVkWaNPih6a6pUoxMNYzYIm917EiWwW1OeZWdQH9IpL5Q23IdA8CbbAERGQCzJreVHDDa52jS48kc7VtIz69qYBENqQ9GZD8SpTH372TqBMn7tVQVdJEZbS+d9HM5dvKvFkvisgvxvVgjEYp68wAGWMQEYwxtcbw1r/tGV6wfu+Qk8oZAmMwBkTyCnrHQtJ3RHn07VswmIJiERtXRflUw6rcJU1rOgR1uYh0n85Daiog48vSxty6rTd9dMWrnYvW7TjuJH1N+PFzQp0HNvn9jAkxRo/rCsmGo7x16EfOhl1fbu4cfr/LGP0VY4x1kq2pPTThlfHvTz61J3HXD3YPkgkMriWEGnLaUOYoLpwV5bxql5qojWcpvrTQpbVvKwNj7ZzIDnJw4G3SuWFEBEscQp3DtjyWNd3Kkjk3PQV8TUTMZJvThswY8/y67f0rN7QO41qCAKmcZnbM5s5PVnLd3FKqIzZRW6YJtyYbjtI2+C47un5JT/JDonb5ODd9zq+7gasX3vufIrJyWg9N4szDD+0c+PaPP0wQswVNnivXzinl0b+YRcRWnFFmYtjSvp6dPRvRJkRQ5HSapY2ruWLB2odFZN1kL8lJYK56vi35xjfeOY6rhJw2eJbi3guq+Oo5lfwpa1/fJja3/ZCUn8BWHtr4rDj7Hzl39oqrRGTTBIYin3eN5nqve6Vz9oivC4x/+spaltfHpjW0e187Xd0DDAwl8RyL8vIYZy9ooHle3SmyvSf28/zv/oFMOIoAnl3GLRf8tLcyWl8QtieF7Hvferdvdn86xLPyOO8+r5K/PAnMaCrN9vcO8NhPX+LN/32fiOdi2xZKCcaANppcLiQIQhafM59rP3MRN1yzlJaFc6gtW8Sl825jc9sTAKT8IbZ3/qLWGPOIiHx7csjmH076H/z5Cx2lUVsItKGlyuPlaxsL4AD2H+zmvod+xtYd+7Ati0jEBTNx8kwipgBGyAUBY5ksi1vm8/Iz36GiPP9yL3x4HwcH38ZWHjmd4c4lG0eronPOE5HDEwxdtW57f8xWeePpwPD0lXVFYFJjGVbf9Sjv/+4QsZIInufkT90iIIIIGJMns21bxEtLuOyScygrjRbkrvvEdwv5pLDZdPAHMWAlgDLGlBxK+pe+358RV4EfGr7QXEZ9zC5662c2/prBRBIlU6e6CJREXTzXRQCt81BtS3Hx+QuxrI+zM2KX8qmGVQQ6i6UcjiZbZSB1+DJjTIkCyrf0jLUEBsy44pUL4kXGsn6OfR91obWeEkw64/P12z9H6zvr+c0bj/HoA7cxv6mGIAiJRj2uvvzCU/acW3MNSmzAEJqAI4ldLUBcjQW6+vhYMDfUeffHHYtzZ3hFm3WoGRkZnTbTLKU40nkMgIp4jC9+7lJeeuY7nLOoieuvWoLj2KfsiUdqKHEq8ieVCRn1B+f6YbpaJbI6PuxrMeRjf3alQ6lTfPiJElzXmRaQ69q8+D/bWHzFPTz34haGEieoqijjmSe+wbf+7otT7vHsMpoqL0QbDRjSwYhK54bLlUBTIhMWBBtKHVyrmCee67CoueF0zQGWpRgcSnLHvT/ikuu+ybp/+Q96+4aIl5VMLS82Zd6swu9MLomIalTamOru0YCjqYCeVIAGJrJtcvZ8dc3VOI41ZYUutA5KUR6PMTaW4efPbeLmu7/PXff9hOl7rizJbB/JbB8jmV6M0TPFGL0WEzwO44QVa/J5WbSGhkf57M0P0nNsiFwuKMqcaY0GIX9746f55/vXnCrvp8EfbyZtB7zYWklnMqs/+qjt2f7+AYyBpqZGzmqeP62BTNbnpde288qbv+G/N+/Ec2280/DLGENVRRmvPvsgjXXVxdn7zsPkfrseRGEvuBpv2Xe/pDCmw7HtQm3OZjLThuXamx4g4rnc+PnLePqxtex64zGWXdxy2jCKCB09ffQPDBc/0DnMaDcYnc8mN44xuks5jpt0XMdMbB5KDJPLBaco3vXBQfYd6GLlbY9wrC9BxHNpnlfHc+vvZ35T7WlB+X6A74fFnssmCbu3gbJABFVSpVVJ9YhtWarfc70jIjLPGIPv+2QymVPSfNvO/Wit2bqzlevX/BOrv7Cci84/i4HBJMkTqaKu7+QVK/GIRt1iQMluzNhgHpCykVjNEezIgA0kq6qq9om0z8tPBIbe3mPE42VFvPntnkNoY3Bsi96+Ib7/5K9wHAutzWm9Y4xhXmMNNTMriv7PtW4EnQNlg1hYcy7fBySViIzFYtEtFeXlRmuNUoqOzm6CICjKrj37O4p4oZQQhvr3gMl/Xv9XS5k5o3xSuEbI7f53sCMQ+tj1S42qmLtFRMYm8vCFsxc2pyYXyj17WwsKjvclONDWzWgqQxCECPmqPl2RNQZOjKaxLMXqv17O12//bFHKZ16/h4ICE+Je9mAKeL7QoIlIuzHmJ/UNdff3dB9FKcXg4BBd3T00NtSz6KwG/u+lf+WVN3bw6qad7N7bjm1bOI6FEkFEgdGE2pD1A2IlHnd/eQW3rLqS+XNrceyPh8LcBxsIu94GKwJBFmfxraiKeU+IyJFTpo50JnN0x45dtRPhsmyLC/5scRGfJtbhzuPsP9hFMpUmlcrguS6zquOc+4m5zJ41df8dHt9N+uWbwM8XavHKid74Wq8Vb6grmjomNfmf6e099ubeffsREbTWuK7LwoXN1M6u+ZOa/ODAr8hueQA9NoBYEdA+kasex160sqjJVxMkHf9jU23t7Ieb5jQShiFKKYIgoLX1AG1t7X8cEqPxtz5CZvO9mGwSsSKYIIVz/h3Yi1Y+NBnM6QbFjfv3f7Sqq7sHpfJkzOUCKsrjNM1tpHrGDGzbnv7sMSEme4Lg8CZy7z1FeOw9JFKZ731CH3fxbXjLH3pBRFadySj9446Orq8daj9c8JY2BozBcR1mzazG8zxiJSW4rktVPEJw6HV0og09eozg0OuQSYAosFwIs2BH8ZZ+E+eCO5/EpO8RVfL7R+lJfFLA3yQSwz872HaIRGIY27ZPuZQQEXw/xzXLFjD68ytA+/mJTqmCepNNYtUvwbv0Aaz6pbcDG0REnwyGqfqMSQJaRDYYY/7r4osufOtIR2dLR0eXHYYhJyvSRheKc759odDKiBvDXfL3OfeitQdBLheRvilsTQ9osgfGDQ8Ci40xN9fOrrnheF//0nQ6XZdKjZHJZAmCAD+XAwTxypFIBVJWj6psRpXPOWo1r9imSuteFJFnC541GjnTC6vTXen5fq7BGH1lqM0yo/UnjdEzSks89EjHAMreK3b0HZT9a4nO6AIGzuRK7/8B0oTdpdA3RMwAAAAASUVORK5CYII= -[slack-badge]: https://img.shields.io/badge/slack-nfcore/sarek-blue.svg?logo=slack -[travis-badge]: https://img.shields.io/travis/nf-core/sarek.svg?logo=travis diff --git a/bin/scrape_software_versions.py b/bin/scrape_software_versions.py index 92793a45b9..148f0fbe82 100755 --- a/bin/scrape_software_versions.py +++ b/bin/scrape_software_versions.py @@ -3,7 +3,6 @@ from collections import OrderedDict import re -# TODO nf-core: Add additional regexes for new tools in process get_software_versions regexes = { 'AlleleCount': ['v_allelecount.txt', r"(\S+)"], 'ASCAT': ['v_ascat.txt', r"(\d\.\d+)"], diff --git a/build.nf b/build.nf index 9c828f6f36..3f23f8a1da 100644 --- a/build.nf +++ b/build.nf @@ -12,7 +12,6 @@ */ def helpMessage() { - // TODO nf-core: Add to this help message with new command line parameters log.info nfcoreHeader() log.info""" @@ -114,7 +113,6 @@ log.info nfcoreHeader() def summary = [:] if (workflow.revision) summary['Pipeline Release'] = workflow.revision summary['Run Name'] = custom_runName ?: workflow.runName -// TODO nf-core: Report custom parameters here summary['Max Resources'] = "$params.max_memory memory, $params.max_cpus cpus, $params.max_time time per job" if (workflow.containerEngine) summary['Container'] = "$workflow.containerEngine - $workflow.container" summary['Output dir'] = params.outdir diff --git a/environment.yml b/environment.yml index 2ef20b6310..968f8d3d8f 100644 --- a/environment.yml +++ b/environment.yml @@ -6,7 +6,7 @@ channels: - bioconda - defaults dependencies: - - r-rcolorbrewer=1.1 + - r-rcolorbrewer=1.1_2 - r-base=3.5.1 - bcftools=1.9 - bioconductor-rtracklayer=1.42.1 diff --git a/main.nf b/main.nf index 172b31e267..bed1254246 100644 --- a/main.nf +++ b/main.nf @@ -20,7 +20,6 @@ nf-core/sarek: */ def helpMessage() { - // TODO nf-core: Add to this help message with new command line parameters log.info nfcoreHeader() log.info""" @@ -2066,7 +2065,6 @@ workflow.onComplete { email_fields['summary']['Nextflow Build'] = workflow.nextflow.build email_fields['summary']['Nextflow Compile Timestamp'] = workflow.nextflow.timestamp - // TODO nf-core: If not using MultiQC, strip out this code (including params.maxMultiqcEmailFileSize) // On success try attach the multiqc report def mqc_report = null try { diff --git a/nextflow.config b/nextflow.config index 01540b9ffe..686593b934 100644 --- a/nextflow.config +++ b/nextflow.config @@ -104,7 +104,7 @@ manifest { homePage = 'https://github.com/nf-core/sarek' description = 'An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing' mainScript = 'main.nf' - nextflowVersion = '>=0.32.0' + nextflowVersion = '>=19.04.0' version = '2.5dev' } From 23d6d7015aad3f3b714f02b01c060861c348cdfb Mon Sep 17 00:00:00 2001 From: Malin Larsson Date: Thu, 5 Sep 2019 09:42:08 +0200 Subject: [PATCH 033/854] first step in updating Ascat --- bin/convertAlleleCounts.r | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/convertAlleleCounts.r b/bin/convertAlleleCounts.r index 302e45384c..7ad4a49d46 100755 --- a/bin/convertAlleleCounts.r +++ b/bin/convertAlleleCounts.r @@ -2,6 +2,8 @@ # Description: # R-script for converting output from AlleleCount to BAF and LogR values. # +# Testing new version of the script +# # Input: # AlleleCounter output file for tumor and normal samples # The first line should contain a header describing the data @@ -27,6 +29,8 @@ if(length(args)<5){ gender = args[5] } + + tumorcounts = read.table(tumorac, header=F, sep="\t") normalcounts = read.table(normalac, header=F, sep="\t") From 8c175a8406bd7bf24cd6bff7df10b61ac967bee2 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Thu, 5 Sep 2019 12:45:34 +0200 Subject: [PATCH 034/854] fix ci --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc697f2f1c..6f7e5b4683 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,9 @@ jobs: export NXF_VER=${{ matrix.nxf_ver }} wget -qO- get.nextflow.io | bash sudo mv nextflow /usr/local/bin/ + - name: Download image + run: | + docker pull nfcore/sarek:dev - name: Build references run: | nextflow run ${GITHUB_WORKSPACE}/build.nf -profile test,docker --build --outdir references From 747f8cdb7c0be1b9c9fedc4e54ffe96440c46cb5 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Thu, 5 Sep 2019 14:08:19 +0200 Subject: [PATCH 035/854] Install Ascat with bioconda (#32) * install ASCAT in the main container * update docs * clean up environment.yml --- CHANGELOG.md | 2 + docs/containers.md | 92 ++++++++++++++++------------------------------ environment.yml | 4 +- 3 files changed, 34 insertions(+), 64 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 137b11519a..f0b9106c89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#18](https://github.com/nf-core/sarek/pull/18), [#21](https://github.com/nf-core/sarek/pull/21) - Update logo - [#21](https://github.com/nf-core/sarek/pull/21) - Moved smallGRCh37 path to `genomes.config` - [#31](https://github.com/nf-core/sarek/pull/31) - Move extra CI to GitHub Actions nf-core extra CI +- [#32](https://github.com/nf-core/sarek/pull/32) - Install `ASCAT` with `conda` in the `environment.yml` file ### `Removed` @@ -81,6 +82,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#13](https://github.com/nf-core/sarek/pull/13) - Removed `CompressVCF` - [#18](https://github.com/nf-core/sarek/pull/18) - Removed params `--noReports` - [#31](https://github.com/nf-core/sarek/pull/31) - Remove extra CI from Travis CI and GitHub Actions nf-core CI +- [#32](https://github.com/nf-core/sarek/pull/32) - Clean up `environment.yml` file ### `Fixed` diff --git a/docs/containers.md b/docs/containers.md index 20d7ee30e0..9f31f477a0 100644 --- a/docs/containers.md +++ b/docs/containers.md @@ -11,44 +11,43 @@ For annotation, the main container can be used, but the cache has to be download ## What is actually inside the containers -### sarek [![sarek-docker status][sarek-docker-badge]][sarek-docker-link] +### sarek [![sarek-docker status](https://img.shields.io/docker/automated/nfcore/sarek.svg)](https://hub.docker.com/r/nfcore/sarek) - Based on `nfcore/base:latest` -- Contain **[AlleleCount][allelecount-link]** 4.0.2 -- Contain **[BCFTools][bcftools-link]** 1.9 -- Contain **[BWA][bwa-link]** 0.7.17 -- Contain **[FastQC][fastqc-link]** 0.11.8 -- Contain **[FreeBayes][freebayes-link]** 1.2.0 -- Contain **[GATK4][gatk4-link]** 4.1.2.0 -- Contain **[GeneSplicer][genesplicer-link]** 1.0 -- Contain **[HTSlib][htslib-link]** 1.9 -- Contain **[IGVtools][igvtools-link]** 2.3.93 -- Contain **[Manta][manta-link]** 1.5.0 -- Contain **[MultiQC][multiqc-link]** 1.7 -- Contain **[Qualimap][qualimap-link]** 2.2.2b -- Contain **[R][r-link]** 3.5.1 -- Contain **[RColorBrewer][rcolorbrewer-link]** 1.1 -- Contain **[Rtracklayer][rtracklayer-link]** 1.42.1 -- Contain **[samtools][samtools-link]** 1.9 -- Contain **[snpEff][snpeff-link]** 4.3.1t -- Contain **[Strelka2][strelka-link]** 2.9.10 -- Contain **[TIDDIT][tiddit-link]** 2.7.1 -- Contain **[VCFanno][vcfanno-link]** 0.3.1 -- Contain **[VCFtools][vcftools-link]** 0.1.16 -- Contain **[VEP][vep-link]** 96.0 - -### sareksnpeff [![sareksnpeff-docker status][sareksnpeff-docker-badge]][sareksnpeff-docker-link] +- Contain **[ASCAT](https://github.com/Crick-CancerGenomics/ascat)** 2.5.2 +- Contain **[AlleleCount](https://github.com/cancerit/alleleCount)** 4.0.2 +- Contain **[BCFTools](https://github.com/samtools/bcftools)** 1.9 +- Contain **[BWA](https://github.com/lh3/bwa)** 0.7.17 +- Contain **[Control-FREEC](https://github.com/BoevaLab/FREEC)** 11.4 +- Contain **[FastQC](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/)** 0.11.8 +- Contain **[FreeBayes](https://github.com/ekg/freebayes)** 1.2.0 +- Contain **[GATK4](https://github.com/broadinstitute/gatk)** 4.1.2.0 +- Contain **[GeneSplicer](https://ccb.jhu.edu/software/genesplicer/)** 1.0 +- Contain **[HTSlib](https://github.com/samtools/htslib)** 1.9 +- Contain **[IGVtools](http://software.broadinstitute.org/software/igv/)** 2.3.93 +- Contain **[Manta](https://github.com/Illumina/manta)** 1.5.0 +- Contain **[MultiQC](https://github.com/ewels/MultiQC/)** 1.7 +- Contain **[Qualimap](http://qualimap.bioinfo.cipf.es)** 2.2.2b +- Contain **[samtools](https://github.com/samtools/samtools)** 1.9 +- Contain **[snpEff](http://snpeff.sourceforge.net/)** 4.3.1t +- Contain **[Strelka2](https://github.com/Illumina/strelka)** 2.9.10 +- Contain **[TIDDIT](https://github.com/SciLifeLab/TIDDIT)** 2.7.1 +- Contain **[VCFanno](https://github.com/brentp/vcfanno)** 0.3.1 +- Contain **[VCFtools](https://vcftools.github.io/index.html)** 0.1.16 +- Contain **[VEP](https://github.com/Ensembl/ensembl-vep)** 95.2 + +### sareksnpeff [![sareksnpeff-docker status](https://img.shields.io/docker/automated/nfcore/sareksnpeff.svg)](https://hub.docker.com/r/nfcore/sareksnpeff) - Based on `nfcore/base:latest` -- Contain **[snpEff][snpeff-link]** 4.3.1t -- Contain cache for `GRCh37`, `GRCh38`, or `GRCm38` +- Contain **[snpEff](http://snpeff.sourceforge.net/)** 4.3.1t +- Contain cache for `GRCh37`, `GRCh38`, `GRCm38` or `CanFam3.1` -### sarekvep [![sarekvep-docker status][sarekvep-docker-badge]][sarekvep-docker-link] +### sarekvep [![sarekvep-docker status](https://img.shields.io/docker/automated/nfcore/sarekvep.svg)](https://hub.docker.com/r/nfcore/sarekvep) - Based on `nfcore/base:latest` -- Contain **[GeneSplicer][genesplicer-link]** 1.0 -- Contain **[VEP][vep-link]** 96.0 -- Contain cache for `GRCh37`, `GRCh38`, or `GRCm38` +- Contain **[GeneSplicer](https://ccb.jhu.edu/software/genesplicer/)** 1.0 +- Contain **[VEP](https://github.com/Ensembl/ensembl-vep)** 95.2 +- Contain cache for `GRCh37`, `GRCh38`, `GRCm38` or `CanFam3.1` ## Using helper script @@ -72,7 +71,7 @@ Default:`dev` ### Genome: -g -Specify which release genome to use for annotation containers (`sareksnpeff`, `sarekvep`): `GRCh37`, `GRCh38`, `smallGRCh37`, `CanFan3.1`, `GRCm38`. +Specify which release genome to use for annotation containers (`sareksnpeff`, `sarekvep`): `smallGRCh37`, `GRCh37`, `GRCh38`, `GRCm38` or `CanFam3.1`. Default:`smallGRCh37` ### Singularity @@ -89,32 +88,3 @@ That will build the main container, plus the annotation containers (`sareksnpeff Our containers are designed using [Conda](https://conda.io/). The `environment.yml` file can easilly be modified if particular versions of tools are more suited to your needs. - -[allelecount-link]: https://github.com/cancerit/alleleCount -[bcftools-link]: https://github.com/samtools/bcftools -[bwa-link]: https://github.com/lh3/bwa -[fastqc-link]: http://www.bioinformatics.babraham.ac.uk/projects/fastqc/ -[freebayes-link]: https://github.com/ekg/freebayes -[gatk4-link]: https://github.com/broadinstitute/gatk -[genesplicer-link]: https://ccb.jhu.edu/software/genesplicer/ -[htslib-link]: https://github.com/samtools/htslib -[igvtools-link]: http://software.broadinstitute.org/software/igv/ -[manta-link]: https://github.com/Illumina/manta -[multiqc-link]: https://github.com/ewels/MultiQC/ -[qualimap-link]: http://qualimap.bioinfo.cipf.es -[r-link]: https://www.r-project.org/ -[rcolorbrewer-link]: https://CRAN.R-project.org/package=RColorBrewer -[rtracklayer-link]: https://www.bioconductor.org/packages/release/bioc/html/rtracklayer.html -[samtools-link]: https://github.com/samtools/samtools -[sarek-docker-badge]: https://img.shields.io/docker/automated/nfcore/sarek.svg -[sarek-docker-link]: https://hub.docker.com/r/nfcore/sarek -[snpeff-link]: http://snpeff.sourceforge.net/ -[sareksnpeff-docker-badge]: https://img.shields.io/docker/automated/nfcore/sareksnpeff.svg -[sareksnpeff-docker-link]: https://hub.docker.com/r/nfcore/sareksnpeff -[strelka-link]: https://github.com/Illumina/strelka -[tiddit-link]: https://github.com/SciLifeLab/TIDDIT -[vcfanno-link]: https://github.com/brentp/vcfanno -[vcftools-link]: https://vcftools.github.io/index.html -[vep-link]: https://github.com/Ensembl/ensembl-vep -[sarekvep-docker-badge]: https://img.shields.io/docker/automated/nfcore/sarekvep.svg -[sarekvep-docker-link]: https://hub.docker.com/r/nfcore/sarekvep diff --git a/environment.yml b/environment.yml index 968f8d3d8f..761004c21c 100644 --- a/environment.yml +++ b/environment.yml @@ -6,10 +6,8 @@ channels: - bioconda - defaults dependencies: - - r-rcolorbrewer=1.1_2 - - r-base=3.5.1 + - ascat=2.5.2 - bcftools=1.9 - - bioconductor-rtracklayer=1.42.1 - bwa=0.7.17 - cancerit-allelecount=4.0.2 - control-freec=11.4 From 641dda2103cc5fbf983d00d31b07aaa034b859f3 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 6 Sep 2019 10:25:24 +0200 Subject: [PATCH 036/854] fix GitHub Actions CI --- .github/workflows/ci-extra.yml | 4 ++-- .github/workflows/ci.yml | 3 ++- .github/workflows/linting.yml | 13 +++++++++++++ conf/test.config | 2 +- scripts/run_tests.sh | 2 +- 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-extra.yml b/.github/workflows/ci-extra.yml index 7992bfb2ce..1b70a86079 100644 --- a/.github/workflows/ci-extra.yml +++ b/.github/workflows/ci-extra.yml @@ -21,7 +21,7 @@ jobs: ${GITHUB_WORKSPACE}/scripts/download_image.sh -n docker --test ${{ matrix.test }} - name: Build References run: | - ${GITHUB_WORKSPACE}/scripts/build_reference.sh --test ${{ matrix.test }} --verbose --memory 6.GB + ${GITHUB_WORKSPACE}/scripts/build_reference.sh --test ${{ matrix.test }} --verbose - name: Run test run: | - ${GITHUB_WORKSPACE}/scripts/run_tests.sh --test ${{ matrix.test }} --verbose --memory 6.GB \ No newline at end of file + ${GITHUB_WORKSPACE}/scripts/run_tests.sh --test ${{ matrix.test }} --verbose \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6f7e5b4683..1fe215c9f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,9 +15,10 @@ jobs: export NXF_VER=${{ matrix.nxf_ver }} wget -qO- get.nextflow.io | bash sudo mv nextflow /usr/local/bin/ - - name: Download image + - name: Download and tag image run: | docker pull nfcore/sarek:dev + docker tag nfcore/sarek:dev nfcore/sarek:dev - name: Build references run: | nextflow run ${GITHUB_WORKSPACE}/build.nf -profile test,docker --build --outdir references diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 8c1e97c073..d7d426cef6 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -16,6 +16,19 @@ jobs: - name: Run Markdownlint run: | markdownlint ${GITHUB_WORKSPACE} -c ${GITHUB_WORKSPACE}/.github/markdownlint.yml + YAML: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-node@v1 + with: + node-version: '10' + - name: Install yamllint + run: | + npm install -g yaml-lint + - name: Run yamllint + run: | + yamllint $(find ${GITHUB_WORKSPACE} -type f -name "*.yml") nf-core: runs-on: ubuntu-latest steps: diff --git a/conf/test.config b/conf/test.config index 8e4eaff3d8..b0fd3b6fab 100644 --- a/conf/test.config +++ b/conf/test.config @@ -12,7 +12,7 @@ params { config_profile_name = 'Test profile' // Limit resources so that this can run on Travis max_cpus = 2 - max_memory = 7.GB + max_memory = 6.GB max_time = 48.h // Input data sample = 'https://github.com/nf-core/test-datasets/raw/sarek/testdata/tsv/tiny-manta-https.tsv' diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index a37958ea35..6e125e3c9a 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -8,7 +8,7 @@ usage() { echo "Usage: $0 <-p profile> <-t test> <-c cpus> <-n> <-v> <-m memory> CPUS=2 LOGS='' -MEMORY='7.GB' +MEMORY='6.GB' NXF_SINGULARITY_CACHEDIR=${NXF_SINGULARITY_CACHEDIR:-work/singularity/.} OFFLINE=false PROFILE=docker From 2afd38351cfe8080bd27f4f3c449cba0797fbcc3 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Fri, 6 Sep 2019 13:03:50 +0200 Subject: [PATCH 037/854] Panel of Normals (#24) * changed MuTect2 to Mutect2 * copied Mutect2 processes * horrible mess right now * fixed merge mixup * looks Mutect2 works without PON * added germline resource to igenomes * we do know there are bugs around, but it is working * MuTect2 -> Mutect2 * Looks PON works with both GRCh37 and 38 * added DOCS * typo * renamed GRCh37 intervals to wgs_calling_regions_Sarek.list * PON in help and summary * extended Mutect2 output * even more extended Mutect2 output * Commits for comments * added contamination table to documents * Update main.nf Co-Authored-By: Maxime Garcia --- CHANGELOG.md | 3 + conf/genomes.config | 60 ++++----- conf/igenomes.config | 56 +++++---- docs/output.md | 26 ++-- docs/usage.md | 31 +++++ main.nf | 289 ++++++++++++++++++++++++++++++++++++------- 6 files changed, 358 insertions(+), 107 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0b9106c89..4ef5099419 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#20](https://github.com/nf-core/sarek/pull/20) - Add `markdownlint` config file - [#21](https://github.com/nf-core/sarek/pull/21) - Add tests for latest Nextflow version as well - [#21](https://github.com/nf-core/sarek/pull/21) - Add `genomes.config` for genomes without AWS iGenomes +- [#24](https://github.com/nf-core/sarek/pull/24) - Added GATK4 Mutect2 calling and filtering - [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Use Github actions for CI - [#31](https://github.com/nf-core/sarek/pull/31) - Add nf-core lint - [#31](https://github.com/nf-core/sarek/pull/31) - Add extra CI to GitHub Actions nf-core extra CI @@ -72,6 +73,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#18](https://github.com/nf-core/sarek/pull/18), [#29](https://github.com/nf-core/sarek/pull/29) - `--noReports` is now `--skipQC all` - [#18](https://github.com/nf-core/sarek/pull/18), [#21](https://github.com/nf-core/sarek/pull/21) - Update logo - [#21](https://github.com/nf-core/sarek/pull/21) - Moved smallGRCh37 path to `genomes.config` +- [#24](https://github.com/nf-core/sarek/pull/24) - iGenomes config now contains germline resource for GATK4 Mutect2 - [#31](https://github.com/nf-core/sarek/pull/31) - Move extra CI to GitHub Actions nf-core extra CI - [#32](https://github.com/nf-core/sarek/pull/32) - Install `ASCAT` with `conda` in the `environment.yml` file @@ -81,6 +83,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#13](https://github.com/nf-core/sarek/pull/13) - Removed `BamQCmapped` and `BamQCrecalibrated` processes - [#13](https://github.com/nf-core/sarek/pull/13) - Removed `CompressVCF` - [#18](https://github.com/nf-core/sarek/pull/18) - Removed params `--noReports` +- [#24](https://github.com/nf-core/sarek/pull/18) - Removed GATK3.X MuTect2 - [#31](https://github.com/nf-core/sarek/pull/31) - Remove extra CI from Travis CI and GitHub Actions nf-core CI - [#32](https://github.com/nf-core/sarek/pull/32) - Clean up `environment.yml` file diff --git a/conf/genomes.config b/conf/genomes.config index 8e26207a99..78ec23c8e6 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -18,41 +18,45 @@ params { genomeDict = "${params.genomes_base}/human_g1k_v37_decoy.dict" genomeFile = "${params.genomes_base}/human_g1k_v37_decoy.fasta" genomeIndex = "${params.genomes_base}/human_g1k_v37_decoy.fasta.fai" - intervals = "${params.genomes_base}/wgs_calling_regions_CAW.list" + intervals = "${params.genomes_base}/wgs_calling_regions_Sarek.list" knownIndels = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf" knownIndelsIndex = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" snpeffDb = "GRCh37.75" vepCacheVersion = "95" } 'GRCh38' { - acLoci = "${params.genomes_base}/1000G_phase3_GRCh38_maf0.3.loci" - acLociGC = "${params.genomes_base}/1000G_phase3_GRCh38_maf0.3.loci.gc" - bwaIndex = "${params.genomes_base}/Homo_sapiens_assembly38.fasta.64.{alt,amb,ann,bwt,pac,sa}" - dbsnp = "${params.genomes_base}/dbsnp_146.hg38.vcf.gz" - dbsnpIndex = "${params.genomes_base}/dbsnp_146.hg38.vcf.gz.tbi" - genomeDict = "${params.genomes_base}/Homo_sapiens_assembly38.dict" - genomeFile = "${params.genomes_base}/Homo_sapiens_assembly38.fasta" - genomeIndex = "${params.genomes_base}/Homo_sapiens_assembly38.fasta.fai" - intervals = "${params.genomes_base}/wgs_calling_regions.hg38.bed" - knownIndels = "${params.genomes_base}/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" - knownIndelsIndex = "${params.genomes_base}/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" - snpeffDb = "GRCh38.86" - vepCacheVersion = "95" + acLoci = "${params.genomes_base}/1000G_phase3_GRCh38_maf0.3.loci" + acLociGC = "${params.genomes_base}/1000G_phase3_GRCh38_maf0.3.loci.gc" + bwaIndex = "${params.genomes_base}/Homo_sapiens_assembly38.fasta.64.{alt,amb,ann,bwt,pac,sa}" + dbsnp = "${params.genomes_base}/dbsnp_146.hg38.vcf.gz" + dbsnpIndex = "${params.genomes_base}/dbsnp_146.hg38.vcf.gz.tbi" + germlineResource = "${params.genomes_base}/GCF_000001405.38.AUTOSOMESXY.COMMON.BIALLELIC.SNPs.with.AF.vcf.gz" + germlineResourceIndex = "${params.genomes_base}/GCF_000001405.38.AUTOSOMESXY.COMMON.BIALLELIC.SNPs.with.AF.vcf.gz.tbi" + genomeDict = "${params.genomes_base}/Homo_sapiens_assembly38.dict" + genomeFile = "${params.genomes_base}/Homo_sapiens_assembly38.fasta" + genomeIndex = "${params.genomes_base}/Homo_sapiens_assembly38.fasta.fai" + intervals = "${params.genomes_base}/wgs_calling_regions.hg38.bed" + knownIndels = "${params.genomes_base}/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" + knownIndelsIndex = "${params.genomes_base}/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" + snpeffDb = "GRCh38.86" + vepCacheVersion = "95" } 'smallGRCh37' { - acLoci = "${params.genomes_base}/1000G_phase3_20130502_SNP_maf0.3.small.loci" - acLociGC = "${params.genomes_base}/1000G_phase3_20130502_SNP_maf0.3.small.loci.gc" - bwaIndex = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta.{amb,ann,bwt,pac,sa}" - dbsnp = "${params.genomes_base}/dbsnp_138.b37.small.vcf" - dbsnpIndex = "${params.genomes_base}/dbsnp_138.b37.small.vcf.idx" - genomeDict = "${params.genomes_base}/human_g1k_v37_decoy.small.dict" - genomeFile = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" - genomeIndex = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta.fai" - intervals = "${params.genomes_base}/small.intervals" - knownIndels = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf" - knownIndelsIndex = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf.idx" - snpeffDb = "GRCh37.75" - vepCacheVersion = "95" + acLoci = "${params.genomes_base}/1000G_phase3_20130502_SNP_maf0.3.small.loci" + acLociGC = "${params.genomes_base}/1000G_phase3_20130502_SNP_maf0.3.small.loci.gc" + bwaIndex = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta.{amb,ann,bwt,pac,sa}" + dbsnp = "${params.genomes_base}/dbsnp_138.b37.small.vcf" + dbsnpIndex = "${params.genomes_base}/dbsnp_138.b37.small.vcf.idx" + germlineResource = "${params.genomes_base}/dbsnp_138.b37.small.vcf" + germlineResourceIndex = "${params.genomes_base}/dbsnp_138.b37.small.vcf.idx" + genomeDict = "${params.genomes_base}/human_g1k_v37_decoy.small.dict" + genomeFile = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" + genomeIndex = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta.fai" + intervals = "${params.genomes_base}/small.intervals" + knownIndels = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf" + knownIndelsIndex = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf.idx" + snpeffDb = "GRCh37.75" + vepCacheVersion = "95" } } -} \ No newline at end of file +} diff --git a/conf/igenomes.config b/conf/igenomes.config index 2c936e7a59..95fa91e27c 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -10,34 +10,38 @@ params { genomes { 'GRCh37' { - acLoci = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/ASCAT/1000G_phase3_20130502_SNP_maf0.3.loci" - acLociGC = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/ASCAT/1000G_phase3_20130502_SNP_maf0.3.loci.gc" - bwaIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/BWAIndex/human_g1k_v37_decoy.fasta.{amb,ann,bwt,pac,sa}" - dbsnp = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/dbsnp_138.b37.vcf" - dbsnpIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/dbsnp_138.b37.vcf.idx" - genomeDict = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.dict" - genomeFile = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta" - genomeIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta.fai" - intervals = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/intervals/wgs_calling_regions_CAW.list" - knownIndels = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf" - knownIndelsIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" - snpeffDb = "GRCh37.75" - vepCacheVersion = "95" + acLoci = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/ASCAT/1000G_phase3_20130502_SNP_maf0.3.loci" + acLociGC = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/ASCAT/1000G_phase3_20130502_SNP_maf0.3.loci.gc" + bwaIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/BWAIndex/human_g1k_v37_decoy.fasta.{amb,ann,bwt,pac,sa}" + dbsnp = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/dbsnp_138.b37.vcf" + dbsnpIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/dbsnp_138.b37.vcf.idx" + germlineResource = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh37.PASS.AC.AF.only.vcf.gz" + germlineResourceIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh37.PASS.AC.AF.only.vcf.gz.tbi" + genomeDict = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.dict" + genomeFile = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta" + genomeIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta.fai" + intervals = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/intervals/wgs_calling_regions_Sarek.list" + knownIndels = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf" + knownIndelsIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" + snpeffDb = "GRCh37.75" + vepCacheVersion = "95" } 'GRCh38' { - acLoci = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/ASCAT/1000G_phase3_GRCh38_maf0.3.loci" - acLociGC = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/ASCAT/1000G_phase3_GRCh38_maf0.3.loci.gc" - bwaIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/BWAIndex/Homo_sapiens_assembly38.fasta.64.{alt,amb,ann,bwt,pac,sa}" - dbsnp = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz" - dbsnpIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz.tbi" - genomeDict = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.dict" - genomeFile = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta" - genomeIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta.fai" - intervals = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/intervals/wgs_calling_regions.hg38.bed" - knownIndels = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" - knownIndelsIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" - snpeffDb = "GRCh38.86" - vepCacheVersion = "95" + acLoci = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/ASCAT/1000G_phase3_GRCh38_maf0.3.loci" + acLociGC = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/ASCAT/1000G_phase3_GRCh38_maf0.3.loci.gc" + bwaIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/BWAIndex/Homo_sapiens_assembly38.fasta.64.{alt,amb,ann,bwt,pac,sa}" + dbsnp = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz" + dbsnpIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz.tbi" + germlineResource = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh38.PASS.AC.AF.only.vcf.gz" + germlineResourceIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh38.PASS.AC.AF.only.vcf.gz.tbi" + genomeDict = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.dict" + genomeFile = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta" + genomeIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta.fai" + intervals = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/intervals/wgs_calling_regions.hg38.bed" + knownIndels = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" + knownIndelsIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" + snpeffDb = "GRCh38.86" + vepCacheVersion = "95" } } } diff --git a/docs/output.md b/docs/output.md index 3d8a44fd48..ace686f6e3 100644 --- a/docs/output.md +++ b/docs/output.md @@ -20,7 +20,7 @@ The pipeline processes data using the following steps: * [`FreeBayes`](#FreeBayes) * [`GATK HaplotypeCaller`](#HaplotypeCaller) * [`GATK GenotypeGVCFs`](#GenotypeGVCFs) - * [`GATK MuTect2`](#MuTect2) + * [`GATK Mutect2`](#Mutect2) * [`Strelka2`](#Strelka2) * Structural variants * [`Manta`](#Manta) @@ -140,21 +140,31 @@ For all samples: * `HaplotypeCaller_[SAMPLE].g.vcf.gz` and `HaplotypeCaller_[SAMPLE].g.vcf.gz.tbi` * VCF with Tabix index -### MuTect2 +### Mutect2 -[GATK MuTect2](https://github.com/broadinstitute/gatk) calls somatic SNVs and indels via local assembly of haplotypes. +[GATK Mutect2](https://github.com/broadinstitute/gatk) calls somatic SNVs and indels via local assembly of haplotypes. -For further reading and documentation see the [MuTect2 manual](https://software.broadinstitute.org/gatk/documentation/tooldocs/4.1.2.0/org_broadinstitute_hellbender_tools_walkers_mutect_Mutect2.php). +For further reading and documentation see the [Mutect2 manual](https://software.broadinstitute.org/gatk/documentation/tooldocs/current/org_broadinstitute_hellbender_tools_walkers_mutect_Mutect2.php). +It is recommended to have panel of normals [PON](https://gatkforums.broadinstitute.org/gatk/discussion/11136/how-to-call-somatic-mutations-using-gatk4-mutect2) for this version of Mutect2 using at +least 40 normal samples, and you can add your PON file to get filtered somatic calls. For a Tumor/Normal pair only: -**Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/MuTect2`** +**Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/Mutect2`** -* `MuTect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz` and `MuTect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.tbi` - * VCF with Tabix index +Files created: + +* `unfiltered_Mutect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz` and `unfiltered_Mutect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.tbi` + * unfiltered (raw) Mutect2 calls VCF with Tabix index +* `filtered_Mutect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz` and `filtered_Mutect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.tbi` + * filtered Mutect2 calls VCF with Tabix index: these entries has a PASS filter, you can get these when supplying a panel of normals using the `--pon` option +* `[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.stats` + * a stats file generated during calling raw variants (needed for filtering) +* `[TUMORSAMPLE]_contamination.table` + * a text file exported when panel-of-normals provided about sample contamination ### TIDDIT -[TIDDIT](https://github.com/SciLifeLab/TIDDIT)identifies intra and inter-chromosomal translocations, deletions, tandem-duplications and inversions. +[TIDDIT](https://github.com/SciLifeLab/TIDDIT) identifies intra and inter-chromosomal translocations, deletions, tandem-duplications and inversions. Germline calls are provided for all samples, to able comparison of both tumor and normal for possible mixup. Low quality calls are removed internally, to simplify processing of variant calls but they are saved by Sarek. diff --git a/docs/usage.md b/docs/usage.md index bdf9de13f0..97b325f265 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -29,10 +29,13 @@ * [`--genomeDict`](#--genomedict) * [`--genomeFile`](#--genomefile) * [`--genomeIndex`](#--genomeindex) + * [`--germlineResource`](#--germlineResource) + * [`--germlineResourceIndex`](#--germlineResourceIndex) * [`--intervals`](#--intervals) * [`--knownIndels`](#--knownindels) * [`--knownIndelsIndex`](#--knownindelsindex) * [`--snpeffDb`](#--snpeffdb) + * [`--pon`](#--pon) * [`--vepCacheVersion`](#--vepcacheversion) * [`--igenomesIgnore`](#--igenomesignore) * [Job resources](#job-resources) @@ -311,6 +314,19 @@ If you prefer, you can specify the full path to your reference genome when you r --genomeIndex '[path to the genome Index]' ``` + +### `--germlineResource` +### `--germlineResourceIndex` + +The [germline resource VCF file](https://software.broadinstitute.org/gatk/documentation/tooldocs/current/org_broadinstitute_hellbender_tools_walkers_mutect_Mutect2.php#--germline-resource) (bgzipped and tabixed) needed +by GATK4 Mutect2 is a collection of calls that are likely present in the sample, with allele frequencies. The AF info field must be present. +You can find a smaller, stripped gnomAD VCF file (most of the annotation is removed and only calls signed by PASS are stored) in the iGenomes Annotation/GermlineResource folder. To add your own +germline resource supply + +```bash +--germlineResource '[path to my resource.vcf.gz]' --germlineResourceIndex '[path to my resource.vcf.gz.idx]' +``` + ### `--intervals` If you prefer, you can specify the full path to your reference genome when you run the pipeline: @@ -335,6 +351,21 @@ If you prefer, you can specify the full path to your reference genome when you r --knownIndelsIndex '[path to the knownIndels index]' ``` +### `--pon` + +When a panel of normals [PON](https://gatkforums.broadinstitute.org/gatk/discussion/24057/how-to-call-somatic-mutations-using-gatk4-mutect2#latest) is defined, you will get filtered +somatic calls as a result. Without PON, there will be no calls with PASS in the INFO field, only an _unfiltered_ VCF is written. It is recommended to make your own panel-of-normals, +as it depends on sequencer and library preparation. For tests in iGenomes there is a dummy PON file in the Annotation/GermlineResource directory, but it _should not be used_ as a +real panel-of-normals file. Provide your PON by: + + +```bash +--pon '[path to the PON VCF]' +``` + +If the PON file is bgzipped, there have to be a tabixed index file at the same directory. + + ### `--snpeffDb` If you prefer, you can specify the DB version when you run the pipeline: diff --git a/main.nf b/main.nf index bed1254246..a3390d7a4d 100644 --- a/main.nf +++ b/main.nf @@ -50,7 +50,7 @@ def helpMessage() { Default: Mapping --tools Specify tools to use for variant calling: Available: ASCAT, ControlFREEC, FreeBayes, HaplotypeCaller - Manta, mpileup, MuTect2, Strelka, TIDDIT + Manta, mpileup, Mutect2, Strelka, TIDDIT and/or for annotation: snpEff, VEP, merge Default: None @@ -58,7 +58,7 @@ def helpMessage() { Available: all, bamQC, BCFtools, FastQC, MultiQC, samtools, vcftools, versions Default: None --annotateTools Specify from which tools Sarek will look for VCF files to annotate, only for step annotate - Available: HaplotypeCaller, Manta, MuTect2, Strelka, TIDDIT + Available: HaplotypeCaller, Manta, Mutect2, Strelka, TIDDIT Default: None --annotation_cache Enable the use of cache for annotation, to be used with --snpEff_cache and/or --vep_cache --snpEff_cache Specity the path to snpEff cache, to be used with --annotation_cache @@ -86,6 +86,7 @@ def helpMessage() { --monochrome_logs Logs will be without colors --email 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 --maxMultiqcEmailFileSize Theshold size for MultiQC report to be attached in notification email. If file generated by pipeline exceeds the threshold, it will not be attached (Default: 25MB) + --pon panel-of-normals VCF (bgzipped, indexed). See: https://software.broadinstitute.org/gatk/documentation/tooldocs/current/org_broadinstitute_hellbender_tools_walkers_mutect_CreateSomaticPanelOfNormals.php -name Name for the pipeline run. If not specified, Nextflow will automatically generate a random mnemonic AWSBatch options: @@ -120,6 +121,7 @@ params.multiqc_config = null params.noGVCF = null params.noStrelkaBP = null params.nucleotidesPerSecond = 1000.0 +params.pon = null params.sample = null params.sequencing_center = null params.skipQC = null @@ -207,18 +209,19 @@ if (tsvPath) { // Header log info log.info nfcoreHeader() def summary = [:] -if (workflow.revision) summary['Pipeline Release'] = workflow.revision +if (workflow.revision) summary['Pipeline Release'] = workflow.revision summary['Run Name'] = custom_runName ?: workflow.runName summary['Max Resources'] = "${params.max_memory} memory, ${params.max_cpus} cpus, ${params.max_time} time per job" -if (workflow.containerEngine) summary['Container'] = "${workflow.containerEngine} - ${workflow.container}" -if (params.sample) summary['Sample'] = params.sample -if (params.targetBED) summary['Target BED'] = params.targetBED -if (params.step) summary['Step'] = params.step -if (params.tools) summary['Tools'] = tools.join(', ') -if (params.skipQC) summary['QC tools skip'] = skipQC.join(', ') -if (params.noGVCF) summary['No GVCF'] = params.noGVCF -if (params.noStrelkaBP) summary['No Strelka BP'] = params.noStrelkaBP -if (params.sequencing_center) summary['Sequenced by '] = params.sequencing_center +if (workflow.containerEngine) summary['Container'] = "${workflow.containerEngine} - ${workflow.container}" +if (params.sample) summary['Sample'] = params.sample +if (params.targetBED) summary['Target BED'] = params.targetBED +if (params.step) summary['Step'] = params.step +if (params.tools) summary['Tools'] = tools.join(', ') +if (params.skipQC) summary['QC tools skip'] = skipQC.join(', ') +if (params.noGVCF) summary['No GVCF'] = params.noGVCF +if (params.noStrelkaBP) summary['No Strelka BP'] = params.noStrelkaBP +if (params.sequencing_center) summary['Sequenced by '] = params.sequencing_center +if (params.pon) summary['Panel of normals '] = params.pon summary['Nucleotides/s'] = params.nucleotidesPerSecond summary['Output dir'] = params.outdir summary['Launch dir'] = workflow.launchDir @@ -1060,52 +1063,111 @@ pairBam = bamNormal.cross(bamTumor).map { pairBam = pairBam.dump(tag:'BAM Somatic Pair') // Manta and Strelka -(pairBamManta, pairBamStrelka, pairBamStrelkaBP, pairBam) = pairBam.into(4) +(pairBamManta, pairBamStrelka, pairBamStrelkaBP, pairBamCalculateContamination, pairBamFilterMutect2, pairBam) = pairBam.into(6) + +intervalPairBam = pairBam.spread(bedIntervals) -intPairBam = pairBam.spread(bedIntervals) bamMpileup = bamMpileup.spread(intMpileup) -// MuTect2, FreeBayes -(pairBamMuTect2, pairBamFreeBayes) = intPairBam.into(3) +// intervals for Mutect2 calls, FreeBayes and pileups for Mutect2 filtering +(pairBamMutect2, pairBamFreeBayes, pairBamPileupSummaries) = intervalPairBam.into(3) // STEP GATK MUTECT2 process Mutect2 { tag {idSampleTumor + "_vs_" + idSampleNormal + "-" + intervalBed.baseName} + label 'cpus_1' input: - set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from pairBamMuTect2 - set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex) from Channel.value([ + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from pairBamMutect2 + set file(genomeFile), file(genomeIndex), file(genomeDict), file(intervals), file(germlineResource), file(germlineResourceIndex) from Channel.value([ referenceMap.genomeFile, referenceMap.genomeIndex, referenceMap.genomeDict, - referenceMap.dbsnp, - referenceMap.dbsnpIndex + referenceMap.intervals, + referenceMap.germlineResource, + referenceMap.germlineResourceIndex ]) output: - set val("MuTect2"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf") into vcfMuTect2 + set val("Mutect2"), + idPatient, + val("${idSampleTumor}_vs_${idSampleNormal}"), + file("${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf") into mutect2Output + set idPatient, + idSampleTumor, + idSampleNormal, + file("${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf.stats") optional true into mutect2Stats when: 'mutect2' in tools script: + // please make a panel-of-normals, using at least 40 samples + // https://gatkforums.broadinstitute.org/gatk/discussion/11136/how-to-call-somatic-mutations-using-gatk4-mutect2 + PON = params.pon ? "--panel-of-normals $params.pon" : "" + """ + # Get raw calls + # this case we are getting raw calls only for the intervals, we also have to concatenate them gatk --java-options "-Xmx${task.memory.toGiga()}g" \ - Mutect2 \ - -R ${genomeFile}\ - -I ${bamTumor} -tumor ${idSampleTumor} \ - -I ${bamNormal} -normal ${idSampleNormal} \ - -L ${intervalBed} \ - -O ${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf + Mutect2 \ + -R ${genomeFile}\ + -I ${bamTumor} -tumor ${idSampleTumor} \ + -I ${bamNormal} -normal ${idSampleNormal} \ + -L ${intervalBed} \ + --germline-resource ${germlineResource} \ + ${PON} \ + -O ${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf """ } -vcfMuTect2 = vcfMuTect2.groupTuple(by:[0, 1, 2]) +mutect2Output = mutect2Output.groupTuple(by:[0,1,2]) +(mutect2Output, mutect2OutForStats) = mutect2Output.into(2) + +(mutect2Stats,intervalStatsFiles) = mutect2Stats.into(2) +mutect2Stats = mutect2Stats.groupTuple(by:[0,1,2]) + +process MergeMutect2Stats { + tag {idSampleTumor + "_vs_" + idSampleNormal} + + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/Mutect2", mode: params.publishDirMode -// STEP FREEBAYES + input: + set caller, + idPatient, + idSampleTumor_vs_idSampleNormal, + file(vcfFiles) from mutect2OutForStats // corresponding small VCF chunks + set idPatient, + idSampleTumor, + idSampleNormal, + file(statsFiles) from mutect2Stats // the actual stats files + set file(genomeFile), file(genomeIndex), file(genomeDict), file(intervals), file(germlineResource), file(germlineResourceIndex) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.genomeDict, + referenceMap.intervals, + referenceMap.germlineResource, + referenceMap.germlineResourceIndex + ]) + + output: + file("${idSampleTumor_vs_idSampleNormal}.vcf.gz.stats") into mergedStatsFile + + when: 'mutect2' in tools + + script: + stats = statsFiles.collect{ "-stats ${it} " }.join(' ') + """ + gatk --java-options "-Xmx${task.memory.toGiga()}g" \ + MergeMutectStats \ + ${stats} \ + -O ${idSampleTumor}_vs_${idSampleNormal}.vcf.gz.stats + """ +} process FreeBayes { tag {idSampleTumor + "_vs_" + idSampleNormal + "-" + intervalBed.baseName} + label 'cpus_1' input: set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from pairBamFreeBayes @@ -1135,15 +1197,13 @@ process FreeBayes { """ } +vcfFreeBayes = vcfFreeBayes.groupTuple(by:[0,1,2]) + // we are merging the VCFs that are called separatelly for different intervals // so we can have a single sorted VCF containing all the calls for a given caller +// STEP MERGING VCF - FREEBAYES, GATK HAPLOTYPECALLER & GATK MUTECT2 (unfiltered) -vcfFreeBayes = vcfFreeBayes.groupTuple(by:[0, 1, 2]) - -// STEP MERGING VCF - FREEBAYES, GATK HAPLOTYPECALLER & GATK MUTECT2 - -vcfConcatenateVCFs = vcfMuTect2.mix(vcfFreeBayes, vcfGenotypeGVCFs, gvcfHaplotypeCaller) - +vcfConcatenateVCFs = mutect2Output.mix( vcfFreeBayes, vcfGenotypeGVCFs, gvcfHaplotypeCaller) vcfConcatenateVCFs = vcfConcatenateVCFs.dump(tag:'VCF to merge') process ConcatVCF { @@ -1162,19 +1222,156 @@ process ConcatVCF { // we have this funny *_* pattern to avoid copying the raw calls to publishdir set variantCaller, idPatient, idSample, file("*_*.vcf.gz"), file("*_*.vcf.gz.tbi") into vcfConcatenated - when: 'haplotypecaller' in tools || 'mutect2' in tools || 'freebayes' in tools + when: ('haplotypecaller' in tools || 'mutect2' in tools || 'freebayes' in tools) script: - if (variantCaller == 'HaplotypeCallerGVCF') outputFile = "HaplotypeCaller_${idSample}.g.vcf" - else outputFile = "${variantCaller}_${idSample}.vcf" + if (variantCaller == 'HaplotypeCallerGVCF') + outputFile = "HaplotypeCaller_${idSample}.g.vcf" + else if (variantCaller == "Mutect2") + outputFile = "unfiltered_${variantCaller}_${idSample}.vcf" + else + outputFile = "${variantCaller}_${idSample}.vcf" options = params.targetBED ? "-t ${targetBED}" : "" """ concatenateVCFs.sh -i ${genomeIndex} -c ${task.cpus} -o ${outputFile} ${options} """ } +(vcfConcatenated, vcfConcatenatedForFilter) = vcfConcatenated.into(2) vcfConcatenated = vcfConcatenated.dump(tag:'VCF') +process PileupSummariesForMutect2 { + tag {idSampleTumor + "_vs_" + idSampleNormal + "_" + intervalBed.baseName } + label 'cpus_1' + + input: + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from pairBamPileupSummaries + set file(germlineResource), file(germlineResourceIndex) from Channel.value([ + referenceMap.germlineResource, + referenceMap.germlineResourceIndex + ]) + set idPatient, + idSampleNormal, + idSampleTumor, + file(statsFile) from intervalStatsFiles + + output: + set idPatient, + idSampleTumor, + file("${intervalBed.baseName}_${idSampleTumor}_pileupsummaries.table") into pileupSummaries + + when: 'mutect2' in tools && params.pon + + script: + """ + # pileup summaries + gatk --java-options "-Xmx${task.memory.toGiga()}g" \ + GetPileupSummaries \ + -I ${bamTumor} \ + -V ${germlineResource} \ + -L ${intervalBed} \ + -O ${intervalBed.baseName}_${idSampleTumor}_pileupsummaries.table + """ +} + +pileupSummaries = pileupSummaries.groupTuple(by:[0,1]) + +process MergePileupSummaries { + tag {idPatient + "_" + idSampleTumor} + label 'cpus_1' + + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}/Mutect2", mode: params.publishDirMode + + input: + file(genomeDict) from Channel.value([referenceMap.genomeDict]) + set idPatient, idSampleTumor, file(pileupSums) from pileupSummaries + + output: + file("${idSampleTumor}_pileupsummaries.table.tsv") into mergedPileupFile + + when: 'mutect2' in tools + script: + allPileups = pileupSums.collect{ "-I ${it} " }.join(' ') + """ + gatk --java-options "-Xmx${task.memory.toGiga()}g" \ + GatherPileupSummaries \ + --sequence-dictionary ${genomeDict} \ + ${allPileups} \ + -O ${idSampleTumor}_pileupsummaries.table.tsv + """ +} + +process CalculateContamination { + tag {idSampleTumor + "_vs_" + idSampleNormal} + label 'cpus_1' + + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}/Mutect2", mode: params.publishDirMode + + input: + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor) from pairBamCalculateContamination + file("${idSampleTumor}_pileupsummaries.table") from mergedPileupFile + + output: + file("${idSampleTumor}_contamination.table") into contaminationTable + + when: 'mutect2' in tools && params.pon + + script: + """ + # calculate contamination + gatk --java-options "-Xmx${task.memory.toGiga()}g" \ + CalculateContamination \ + -I ${idSampleTumor}_pileupsummaries.table \ + -O ${idSampleTumor}_contamination.table + """ +} + +process FilterMutect2Calls { + tag {idSampleTN} + label 'cpus_1' + + publishDir "${params.outdir}/VariantCalling/${idSampleTN}/${"$variantCaller"}", mode: params.publishDirMode + + input: + set variantCaller, + idPatient, + idSampleTN, + file(unfiltered), + file(unfilteredIndex) from vcfConcatenatedForFilter + set file(genomeFile), file(genomeIndex), file(genomeDict), file(intervals), file(germlineResource), file(germlineResourceIndex) from Channel.value([ + referenceMap.genomeFile, + referenceMap.genomeIndex, + referenceMap.genomeDict, + referenceMap.intervals, + referenceMap.germlineResource, + referenceMap.germlineResourceIndex + ]) + file("${idSampleTN}.vcf.gz.stats") from mergedStatsFile + file("${idSampleTN}_contamination.table") from contaminationTable + + output: + set val("Mutect2"), + idPatient, + idSampleTN, + file("filtered_${variantCaller}_${idSampleTN}.vcf.gz"), + file("filtered_${variantCaller}_${idSampleTN}.vcf.gz.tbi"), + file("filtered_${variantCaller}_${idSampleTN}.vcf.gz.filteringStats.tsv") into filteredMutect2Output + + when: 'mutect2' in tools && params.pon + + script: + """ + # do the actual filtering + gatk --java-options "-Xmx${task.memory.toGiga()}g" \ + FilterMutectCalls \ + -V $unfiltered \ + --contamination-table ${idSampleTN}_contamination.table \ + --stats ${idSampleTN}.vcf.gz.stats \ + -R ${genomeFile} \ + -O filtered_${variantCaller}_${idSampleTN}.vcf.gz + """ +} + // STEP STRELKA.2 - SOMATIC PAIR process Strelka { @@ -1624,10 +1821,6 @@ controlFreecVizOut.dump(tag:'ControlFreecViz') (vcfMantaSomaticSV, vcfMantaDiploidSV) = vcfManta.into(2) vcfKeep = Channel.empty().mix( - vcfConcatenated.map { - variantcaller, idPatient, idSample, vcf, tbi -> - [variantcaller, idSample, vcf] - }, vcfStrelkaSingle.map { variantcaller, idPatient, idSample, vcf, tbi -> [variantcaller, idSample, vcf[1]] @@ -1741,7 +1934,7 @@ if (step == 'annotate') { if (tsvPath == []) { // Sarek, by default, annotates all available vcfs that it can find in the VariantCalling directory // Excluding vcfs from FreeBayes, and g.vcf from HaplotypeCaller - // Basically it's: VariantCalling/*/{HaplotypeCaller,Manta,MuTect2,Strelka}/*.vcf.gz + // Basically it's: VariantCalling/*/{HaplotypeCaller,Manta,Mutect2,Strelka}/*.vcf.gz // Without *SmallIndels.vcf.gz from Manta, and *.genome.vcf.gz from Strelka // The small snippet `vcf.minus(vcf.fileName)[-2]` catches idSample // This field is used to output final annotated VCFs in the correct directory @@ -1750,7 +1943,7 @@ if (step == 'annotate') { .flatten().map{vcf -> ['haplotypecaller', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, Channel.fromPath("${params.outdir}/VariantCalling/*/Manta/*[!candidate]SV.vcf.gz") .flatten().map{vcf -> ['manta', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, - Channel.fromPath("${params.outdir}/VariantCalling/*/MuTect2/*.vcf.gz") + Channel.fromPath("${params.outdir}/VariantCalling/*/Mutect2/*.vcf.gz") .flatten().map{vcf -> ['mutect2', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, Channel.fromPath("${params.outdir}/VariantCalling/*/Strelka/*{somatic,variant}*.vcf.gz") .flatten().map{vcf -> ['strelka', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, @@ -2297,6 +2490,12 @@ def defineReferenceMap(step, tools) { 'dbsnpIndex' : checkParamReturnFile("dbsnpIndex") ) } + if('mutect2' in tools ) { + referenceMap.putAll( + 'germlineResource' : checkParamReturnFile("germlineResource"), + 'germlineResourceIndex' : checkParamReturnFile("germlineResourceIndex") + ) + } if ('annotate' in step) return [] return referenceMap } @@ -2306,7 +2505,7 @@ def defineAnnoList() { return [ 'HaplotypeCaller', 'Manta', - 'MuTect2', + 'Mutect2', 'Strelka' ] } From 29e12f048f5cbe6e1a0a2f4fa106b0b6d156eb70 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 6 Sep 2019 13:39:59 +0200 Subject: [PATCH 038/854] fix MD lint --- CHANGELOG.md | 2 +- docs/output.md | 5 ++--- docs/usage.md | 30 ++++++++++++++++++------------ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ef5099419..bb317fae9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,7 +42,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#20](https://github.com/nf-core/sarek/pull/20) - Add `markdownlint` config file - [#21](https://github.com/nf-core/sarek/pull/21) - Add tests for latest Nextflow version as well - [#21](https://github.com/nf-core/sarek/pull/21) - Add `genomes.config` for genomes without AWS iGenomes -- [#24](https://github.com/nf-core/sarek/pull/24) - Added GATK4 Mutect2 calling and filtering +- [#24](https://github.com/nf-core/sarek/pull/24) - Added GATK4 Mutect2 calling and filtering - [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Use Github actions for CI - [#31](https://github.com/nf-core/sarek/pull/31) - Add nf-core lint - [#31](https://github.com/nf-core/sarek/pull/31) - Add extra CI to GitHub Actions nf-core extra CI diff --git a/docs/output.md b/docs/output.md index ace686f6e3..58f9af63a2 100644 --- a/docs/output.md +++ b/docs/output.md @@ -144,9 +144,8 @@ For all samples: [GATK Mutect2](https://github.com/broadinstitute/gatk) calls somatic SNVs and indels via local assembly of haplotypes. -For further reading and documentation see the [Mutect2 manual](https://software.broadinstitute.org/gatk/documentation/tooldocs/current/org_broadinstitute_hellbender_tools_walkers_mutect_Mutect2.php). -It is recommended to have panel of normals [PON](https://gatkforums.broadinstitute.org/gatk/discussion/11136/how-to-call-somatic-mutations-using-gatk4-mutect2) for this version of Mutect2 using at -least 40 normal samples, and you can add your PON file to get filtered somatic calls. +For further reading and documentation see the [Mutect2 manual](https://software.broadinstitute.org/gatk/documentation/tooldocs/current/org_broadinstitute_hellbender_tools_walkers_mutect_Mutect2.php). +It is recommended to have panel of normals [PON](https://gatkforums.broadinstitute.org/gatk/discussion/11136/how-to-call-somatic-mutations-using-gatk4-mutect2) for this version of Mutect2 using at least 40 normal samples, and you can add your PON file to get filtered somatic calls. For a Tumor/Normal pair only: **Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/Mutect2`** diff --git a/docs/usage.md b/docs/usage.md index 97b325f265..c737e92688 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -314,17 +314,24 @@ If you prefer, you can specify the full path to your reference genome when you r --genomeIndex '[path to the genome Index]' ``` - ### `--germlineResource` + +The [germline resource VCF file](https://software.broadinstitute.org/gatk/documentation/tooldocs/current/org_broadinstitute_hellbender_tools_walkers_mutect_Mutect2.php#--germline-resource) (bgzipped and tabixed) needed by GATK4 Mutect2 is a collection of calls that are likely present in the sample, with allele frequencies. +The AF info field must be present. +You can find a smaller, stripped gnomAD VCF file (most of the annotation is removed and only calls signed by PASS are stored) in the iGenomes Annotation/GermlineResource folder. +To add your own germline resource supply + +```bash +--germlineResource '[path to my resource.vcf.gz]' +``` + ### `--germlineResourceIndex` -The [germline resource VCF file](https://software.broadinstitute.org/gatk/documentation/tooldocs/current/org_broadinstitute_hellbender_tools_walkers_mutect_Mutect2.php#--germline-resource) (bgzipped and tabixed) needed -by GATK4 Mutect2 is a collection of calls that are likely present in the sample, with allele frequencies. The AF info field must be present. -You can find a smaller, stripped gnomAD VCF file (most of the annotation is removed and only calls signed by PASS are stored) in the iGenomes Annotation/GermlineResource folder. To add your own -germline resource supply +Tabix index of the germline resource specified at [`--germlineResource`](#--germlineResource). +To add your own germline resource supply ```bash ---germlineResource '[path to my resource.vcf.gz]' --germlineResourceIndex '[path to my resource.vcf.gz.idx]' +--germlineResourceIndex '[path to my resource.vcf.gz.idx]' ``` ### `--intervals` @@ -353,11 +360,11 @@ If you prefer, you can specify the full path to your reference genome when you r ### `--pon` -When a panel of normals [PON](https://gatkforums.broadinstitute.org/gatk/discussion/24057/how-to-call-somatic-mutations-using-gatk4-mutect2#latest) is defined, you will get filtered -somatic calls as a result. Without PON, there will be no calls with PASS in the INFO field, only an _unfiltered_ VCF is written. It is recommended to make your own panel-of-normals, -as it depends on sequencer and library preparation. For tests in iGenomes there is a dummy PON file in the Annotation/GermlineResource directory, but it _should not be used_ as a -real panel-of-normals file. Provide your PON by: - +When a panel of normals [PON](https://gatkforums.broadinstitute.org/gatk/discussion/24057/how-to-call-somatic-mutations-using-gatk4-mutect2#latest) is defined, you will get filtered somatic calls as a result. +Without PON, there will be no calls with PASS in the INFO field, only an _unfiltered_ VCF is written. +It is recommended to make your own panel-of-normals, as it depends on sequencer and library preparation. +For tests in iGenomes there is a dummy PON file in the Annotation/GermlineResource directory, but it _should not be used_ as a real panel-of-normals file. +Provide your PON by: ```bash --pon '[path to the PON VCF]' @@ -365,7 +372,6 @@ real panel-of-normals file. Provide your PON by: If the PON file is bgzipped, there have to be a tabixed index file at the same directory. - ### `--snpeffDb` If you prefer, you can specify the DB version when you run the pipeline: From 22670b6909d4d211dc8aabcabe867cd1b6dce606 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 6 Sep 2019 13:42:31 +0200 Subject: [PATCH 039/854] got ascat version using R library(ASCAT) + use workflow.manifest.version to specify workflow version in path to R scripts for control-FREEC and VEP --- bin/scrape_software_versions.py | 2 +- main.nf | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/bin/scrape_software_versions.py b/bin/scrape_software_versions.py index 148f0fbe82..617740e595 100755 --- a/bin/scrape_software_versions.py +++ b/bin/scrape_software_versions.py @@ -5,7 +5,7 @@ regexes = { 'AlleleCount': ['v_allelecount.txt', r"(\S+)"], - 'ASCAT': ['v_ascat.txt', r"(\d\.\d+)"], + 'ASCAT': ['v_ascat.txt', r"Version: (\S+)"], 'bcftools': ['v_bcftools.txt', r"bcftools (\S+)"], 'BWA': ['v_bwa.txt', r"Version: (\S+)"], 'FastQC': ['v_fastqc.txt', r"FastQC v(\S+)"], diff --git a/main.nf b/main.nf index a3390d7a4d..72a8cabf5d 100644 --- a/main.nf +++ b/main.nf @@ -263,7 +263,6 @@ process GetSoftwareVersions { alleleCounter --version &> v_allelecount.txt || true bcftools version > v_bcftools.txt 2>&1 || true bwa &> v_bwa.txt 2>&1 || true - cat ${baseDir}/scripts/ascat.R | grep "ASCAT version" &> v_ascat.txt || true configManta.py --version > v_manta.txt 2>&1 || true configureStrelkaGermlineWorkflow.py --version > v_strelka.txt 2>&1 || true echo "${workflow.manifest.version}" &> v_pipeline.txt 2>&1 || true @@ -275,6 +274,7 @@ process GetSoftwareVersions { multiqc --version &> v_multiqc.txt 2>&1 || true qualimap --version &> v_qualimap.txt 2>&1 || true R --version &> v_r.txt || true + R -e "library(ASCAT); help(package='ASCAT')" &> v_ascat.txt samtools --version &> v_samtools.txt 2>&1 || true tiddit &> v_tiddit.txt 2>&1 || true vcftools --version &> v_vcftools.txt 2>&1 || true @@ -1803,12 +1803,12 @@ process ControlFreecViz { when: 'controlfreec' in tools """ - cat /opt/conda/envs/sarek-2.5dev/bin/assess_significance.R | R --slave --args ${cnvTumor} ${ratioTumor} - cat /opt/conda/envs/sarek-2.5dev/bin/assess_significance.R | R --slave --args ${cnvNormal} ${ratioNormal} - cat /opt/conda/envs/sarek-2.5dev/bin/makeGraph.R | R --slave --args 2 ${ratioTumor} ${bafTumor} - cat /opt/conda/envs/sarek-2.5dev/bin/makeGraph.R | R --slave --args 2 ${ratioNormal} ${bafNormal} - perl /opt/conda/envs/sarek-2.5dev/bin/freec2bed.pl -f ${ratioTumor} > ${idSampleTumor}.bed - perl /opt/conda/envs/sarek-2.5dev/bin/freec2bed.pl -f ${ratioNormal} > ${idSampleNormal}.bed + cat /opt/conda/envs/sarek-${workflow.manifest.version}/bin/assess_significance.R | R --slave --args ${cnvTumor} ${ratioTumor} + cat /opt/conda/envs/sarek-${workflow.manifest.version}/bin/assess_significance.R | R --slave --args ${cnvNormal} ${ratioNormal} + cat /opt/conda/envs/sarek-${workflow.manifest.version}/bin/makeGraph.R | R --slave --args 2 ${ratioTumor} ${bafTumor} + cat /opt/conda/envs/sarek-${workflow.manifest.version}/bin/makeGraph.R | R --slave --args 2 ${ratioNormal} ${bafNormal} + perl /opt/conda/envs/sarek-${workflow.manifest.version}/bin/freec2bed.pl -f ${ratioTumor} > ${idSampleTumor}.bed + perl /opt/conda/envs/sarek-${workflow.manifest.version}/bin/freec2bed.pl -f ${ratioNormal} > ${idSampleNormal}.bed """ } @@ -2069,7 +2069,7 @@ process VEP { genome = params.genome == 'smallGRCh37' ? 'GRCh37' : params.genome dir_cache = (params.vep_cache && params.annotation_cache) ? " \${PWD}/${dataDir}" : "/.vep" cadd = (params.cadd_cache && params.cadd_WG_SNVs && params.cadd_InDels) ? "--plugin CADD,whole_genome_SNVs.tsv.gz,InDels.tsv.gz" : "" - genesplicer = params.genesplicer ? "--plugin GeneSplicer,/opt/conda/envs/sarek-2.5dev/bin/genesplicer,/opt/conda/envs/sarek-2.5dev/share/genesplicer-1.0-1/human,context=200,tmpdir=\$PWD/${reducedVCF}" : "--offline" + genesplicer = params.genesplicer ? "--plugin GeneSplicer,/opt/conda/envs/sarek-${workflow.manifest.version}/bin/genesplicer,/opt/conda/envs/sarek-${workflow.manifest.version}/share/genesplicer-1.0-1/human,context=200,tmpdir=\$PWD/${reducedVCF}" : "--offline" """ mkdir ${reducedVCF} @@ -2132,7 +2132,7 @@ process VEPmerge { genome = params.genome == 'smallGRCh37' ? 'GRCh37' : params.genome dir_cache = (params.vep_cache && params.annotation_cache) ? " \${PWD}/${dataDir}" : "/.vep" cadd = (params.cadd_cache && params.cadd_WG_SNVs && params.cadd_InDels) ? "--plugin CADD,whole_genome_SNVs.tsv.gz,InDels.tsv.gz" : "" - genesplicer = params.genesplicer ? "--plugin GeneSplicer,/opt/conda/envs/sarek-2.5dev/bin/genesplicer,/opt/conda/envs/sarek-2.5dev/share/genesplicer-1.0-1/human,context=200,tmpdir=\$PWD/${reducedVCF}" : "--offline" + genesplicer = params.genesplicer ? "--plugin GeneSplicer,/opt/conda/envs/sarek-${workflow.manifest.version}/bin/genesplicer,/opt/conda/envs/sarek-${workflow.manifest.version}/share/genesplicer-1.0-1/human,context=200,tmpdir=\$PWD/${reducedVCF}" : "--offline" """ mkdir ${reducedVCF} From cf682f4fc8ff923cc0bdc34f6f106642896adf73 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 6 Sep 2019 13:44:46 +0200 Subject: [PATCH 040/854] update CHANGELOG --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb317fae9e..0e8c8b9603 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,7 +75,8 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#21](https://github.com/nf-core/sarek/pull/21) - Moved smallGRCh37 path to `genomes.config` - [#24](https://github.com/nf-core/sarek/pull/24) - iGenomes config now contains germline resource for GATK4 Mutect2 - [#31](https://github.com/nf-core/sarek/pull/31) - Move extra CI to GitHub Actions nf-core extra CI -- [#32](https://github.com/nf-core/sarek/pull/32) - Install `ASCAT` with `conda` in the `environment.yml` file +- [#32](https://github.com/nf-core/sarek/pull/32), [#33](https://github.com/nf-core/sarek/pull/33) - Install `ASCAT` with `conda` in the `environment.yml` file +- [#33](https://github.com/nf-core/sarek/pull/33) - use workflow.manifest.version to specify workflow version in path to R scripts for control-FREEC and VEP processes ### `Removed` @@ -101,6 +102,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#22](https://github.com/nf-core/sarek/pull/22) - Fix --singleCPUMem issue - [#31](https://github.com/nf-core/sarek/pull/31) - Fix badges according to nf-core lint - [#31](https://github.com/nf-core/sarek/pull/31) - Fix rcolorbrewer version according to nf-core lint +- [#33](https://github.com/nf-core/sarek/pull/33) - Fix MD Linting ## [2.3.FIX1] - 2019-03-04 From 1ed4e5cf96c34c14a0f4238707356912c567e746 Mon Sep 17 00:00:00 2001 From: Malin Larsson Date: Fri, 6 Sep 2019 13:46:09 +0200 Subject: [PATCH 041/854] Update install_bianca.md --- docs/install_bianca.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/install_bianca.md b/docs/install_bianca.md index 5bb8c176c8..4ad2642316 100644 --- a/docs/install_bianca.md +++ b/docs/install_bianca.md @@ -146,6 +146,15 @@ So every member of the project who wants to use nf-core/sarek will need to do: > ln -s /castor/project/proj_nobackup/sarek/default sarek ``` +Singularity images for Sarek are available on Uppmax in /sw/data/uppnex/ToolBox/sarek. Sometimes nextflow needs write access to the image folder, and if so the images needs to be copied to a location with write permission, for example in a subfolder of your project folder. +```bash +mkdir sarek_simg +cd sarek_simg +cp /sw/data/uppnex/ToolBox/sarek/nfcore-sarek-dev.img . +#Update the ENV parameter NXF_SINGULARITY_CACHEDIR +export NXF_SINGULARITY_CACHEDIR=/path/to/your/local/sarek_simg +``` + And then nf-core/sarek can be used with: ```bash From c2b283b2aa5cd388ec7f935106a64159c56370e4 Mon Sep 17 00:00:00 2001 From: Malin Larsson Date: Fri, 6 Sep 2019 13:49:17 +0200 Subject: [PATCH 042/854] Update install_bianca.md --- docs/install_bianca.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/install_bianca.md b/docs/install_bianca.md index 4ad2642316..480c61dba7 100644 --- a/docs/install_bianca.md +++ b/docs/install_bianca.md @@ -148,9 +148,12 @@ So every member of the project who wants to use nf-core/sarek will need to do: Singularity images for Sarek are available on Uppmax in /sw/data/uppnex/ToolBox/sarek. Sometimes nextflow needs write access to the image folder, and if so the images needs to be copied to a location with write permission, for example in a subfolder of your project folder. ```bash +#Create a folder for the singularity images somewhere in your project: mkdir sarek_simg -cd sarek_simg -cp /sw/data/uppnex/ToolBox/sarek/nfcore-sarek-dev.img . + +#Copy the relevant singularity image from the write protected folder on Uppmax to the fodler where you have write permission: +cp /sw/data/uppnex/ToolBox/sarek/nfcore-sarek-dev.img /path/to/sarek_simg/. + #Update the ENV parameter NXF_SINGULARITY_CACHEDIR export NXF_SINGULARITY_CACHEDIR=/path/to/your/local/sarek_simg ``` From 403a3e02422b54818dd8b8e7f91a3db86550e72b Mon Sep 17 00:00:00 2001 From: Malin Larsson Date: Fri, 6 Sep 2019 13:50:28 +0200 Subject: [PATCH 043/854] Update install_bianca.md --- docs/install_bianca.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/install_bianca.md b/docs/install_bianca.md index 480c61dba7..f0adb03b9a 100644 --- a/docs/install_bianca.md +++ b/docs/install_bianca.md @@ -152,10 +152,10 @@ Singularity images for Sarek are available on Uppmax in /sw/data/uppnex/ToolBox/ mkdir sarek_simg #Copy the relevant singularity image from the write protected folder on Uppmax to the fodler where you have write permission: -cp /sw/data/uppnex/ToolBox/sarek/nfcore-sarek-dev.img /path/to/sarek_simg/. +cp /sw/data/uppnex/ToolBox/sarek/nfcore-sarek-dev.img /path/to/your/sarek_simg/. #Update the ENV parameter NXF_SINGULARITY_CACHEDIR -export NXF_SINGULARITY_CACHEDIR=/path/to/your/local/sarek_simg +export NXF_SINGULARITY_CACHEDIR=/path/to/your/sarek_simg ``` And then nf-core/sarek can be used with: From ee2dbd98341758c6996919a3c5740b8fb0c9f4f3 Mon Sep 17 00:00:00 2001 From: Malin Larsson Date: Fri, 6 Sep 2019 14:04:10 +0200 Subject: [PATCH 044/854] Update install_bianca.md --- docs/install_bianca.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/install_bianca.md b/docs/install_bianca.md index f0adb03b9a..dfbf9aa96a 100644 --- a/docs/install_bianca.md +++ b/docs/install_bianca.md @@ -164,6 +164,14 @@ And then nf-core/sarek can be used with: > nextflow run ~/sarek/main.nf -profile uppmax --custom_config_base ~/sarek/configs --project [PROJECT] --genome [GENOME ASSEMBLY] ... ``` +This command worked on Bianca 20190906: +``` +>screen -S SAMPLE /path/to/nextflow run /path/to/sarek/main.nf -profile uppmax --project PROJID --sample SAMPLE.tsv --genome GRCh37 --genomes_base /sw/data/uppnex/ToolBox/ReferenceAssemblies/hg38make/bundle/2.8/b37 --step variantcalling --tools ASCAT --igenomesIgnore + +#To detach screen: +ctrl-A-D +``` + This is an example of how to run sarek with the tool Manta and the genome assembly version GRCh38: ```bash From 6dd387f750e414c973c25e7aec732d0e55b7c351 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 6 Sep 2019 15:29:32 +0200 Subject: [PATCH 045/854] code polishing --- main.nf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.nf b/main.nf index 72a8cabf5d..a3f83e7a28 100644 --- a/main.nf +++ b/main.nf @@ -1133,7 +1133,7 @@ process MergeMutect2Stats { publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/Mutect2", mode: params.publishDirMode input: - set caller, + set caller, idPatient, idSampleTumor_vs_idSampleNormal, file(vcfFiles) from mutect2OutForStats // corresponding small VCF chunks @@ -1283,8 +1283,8 @@ process MergePileupSummaries { publishDir "${params.outdir}/VariantCalling/${idSampleTumor}/Mutect2", mode: params.publishDirMode input: - file(genomeDict) from Channel.value([referenceMap.genomeDict]) set idPatient, idSampleTumor, file(pileupSums) from pileupSummaries + file(genomeDict) from Channel.value([referenceMap.genomeDict]) output: file("${idSampleTumor}_pileupsummaries.table.tsv") into mergedPileupFile From ab0e8725c98693a61e56fccb15770c0b8c84c0bf Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 9 Sep 2019 09:55:44 +0200 Subject: [PATCH 046/854] code polishing --- main.nf | 70 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/main.nf b/main.nf index a3f83e7a28..62f73b9474 100644 --- a/main.nf +++ b/main.nf @@ -1072,6 +1072,42 @@ bamMpileup = bamMpileup.spread(intMpileup) // intervals for Mutect2 calls, FreeBayes and pileups for Mutect2 filtering (pairBamMutect2, pairBamFreeBayes, pairBamPileupSummaries) = intervalPairBam.into(3) +// STEP FREEBAYES + +process FreeBayes { + tag {idSampleTumor + "_vs_" + idSampleNormal + "-" + intervalBed.baseName} + label 'cpus_1' + + input: + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from pairBamFreeBayes + file(genomeFile) from Channel.value(referenceMap.genomeFile) + file(genomeIndex) from Channel.value(referenceMap.genomeIndex) + + output: + set val("FreeBayes"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf") into vcfFreeBayes + + when: 'freebayes' in tools + + script: + """ + freebayes \ + -f ${genomeFile} \ + --pooled-continuous \ + --pooled-discrete \ + --genotype-qualities \ + --report-genotype-likelihood-max \ + --allele-balance-priors-off \ + --min-alternate-fraction 0.03 \ + --min-repeat-entropy 1 \ + --min-alternate-count 2 \ + -t ${intervalBed} \ + ${bamTumor} \ + ${bamNormal} > ${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf + """ +} + +vcfFreeBayes = vcfFreeBayes.groupTuple(by:[0,1,2]) + // STEP GATK MUTECT2 process Mutect2 { @@ -1165,40 +1201,6 @@ process MergeMutect2Stats { """ } -process FreeBayes { - tag {idSampleTumor + "_vs_" + idSampleNormal + "-" + intervalBed.baseName} - label 'cpus_1' - - input: - set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from pairBamFreeBayes - file(genomeFile) from Channel.value(referenceMap.genomeFile) - file(genomeIndex) from Channel.value(referenceMap.genomeIndex) - - output: - set val("FreeBayes"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf") into vcfFreeBayes - - when: 'freebayes' in tools - - script: - """ - freebayes \ - -f ${genomeFile} \ - --pooled-continuous \ - --pooled-discrete \ - --genotype-qualities \ - --report-genotype-likelihood-max \ - --allele-balance-priors-off \ - --min-alternate-fraction 0.03 \ - --min-repeat-entropy 1 \ - --min-alternate-count 2 \ - -t ${intervalBed} \ - ${bamTumor} \ - ${bamNormal} > ${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf - """ -} - -vcfFreeBayes = vcfFreeBayes.groupTuple(by:[0,1,2]) - // we are merging the VCFs that are called separatelly for different intervals // so we can have a single sorted VCF containing all the calls for a given caller // STEP MERGING VCF - FREEBAYES, GATK HAPLOTYPECALLER & GATK MUTECT2 (unfiltered) From 5f8d2a7659b267fbd918a7dd312e821d66070cda Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 9 Sep 2019 10:04:15 +0200 Subject: [PATCH 047/854] fix memory usage --- scripts/build_reference.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build_reference.sh b/scripts/build_reference.sh index 636b161628..fb121ea335 100755 --- a/scripts/build_reference.sh +++ b/scripts/build_reference.sh @@ -6,7 +6,7 @@ set -xeuo pipefail usage() { echo "Usage: $0 <-p profile> <-t test> <-v> <-m memory>" 1>&2; exit 1; } -MEMORY='7.GB' +MEMORY='6.GB' NXF_SINGULARITY_CACHEDIR=${NXF_SINGULARITY_CACHEDIR:-work/singularity/.} OFFLINE='' PROFILE=docker From 1c48f2a767ceb8d6251587e01f20788057ce00a8 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 9 Sep 2019 15:53:13 +0200 Subject: [PATCH 048/854] update reference files --- CHANGELOG.md | 6 ++-- conf/genomes.config | 44 +++++++++++++----------- conf/igenomes.config | 80 +++++++++++++++++++++++--------------------- docs/usage.md | 26 +++++++++++--- 4 files changed, 92 insertions(+), 64 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e8c8b9603..3c8992909c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#7](https://github.com/nf-core/sarek/pull/7), [#9](https://github.com/nf-core/sarek/pull/9), [#10](https://github.com/nf-core/sarek/pull/10), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Add CI for `nf-core/sarek` - [#3](https://github.com/nf-core/sarek/pull/3) - Add preprocessing to `nf-core/sarek` - [#4](https://github.com/nf-core/sarek/pull/4) - Add variant calling to `nf-core/sarek` with `HaplotypeCaller`, and single mode `Manta` and `Strelka` -- [#5](https://github.com/nf-core/sarek/pull/5) - Add variant calling to `nf-core/sarek` with `Manta`, `Strelka`, `Strelka Best Practices`, `MuTecT2`, `FreeBayes`, `ASCAT`, `ControlFREEC` +- [#5](https://github.com/nf-core/sarek/pull/5), [#34](https://github.com/nf-core/sarek/pull/34) - Add variant calling to `nf-core/sarek` with `Manta`, `Strelka`, `Strelka Best Practices`, `MuTecT2`, `FreeBayes`, `ASCAT`, `ControlFREEC` - [#6](https://github.com/nf-core/sarek/pull/6) - Add default containers for annotation to `nf-core/sarek` - [#7](https://github.com/nf-core/sarek/pull/7) - Add MultiQC - [#7](https://github.com/nf-core/sarek/pull/7) - Add annotation @@ -73,10 +73,10 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#18](https://github.com/nf-core/sarek/pull/18), [#29](https://github.com/nf-core/sarek/pull/29) - `--noReports` is now `--skipQC all` - [#18](https://github.com/nf-core/sarek/pull/18), [#21](https://github.com/nf-core/sarek/pull/21) - Update logo - [#21](https://github.com/nf-core/sarek/pull/21) - Moved smallGRCh37 path to `genomes.config` -- [#24](https://github.com/nf-core/sarek/pull/24) - iGenomes config now contains germline resource for GATK4 Mutect2 +- [#24](https://github.com/nf-core/sarek/pull/24) - iGenomes config now contains germline resource for `GATK4 Mutect2` - [#31](https://github.com/nf-core/sarek/pull/31) - Move extra CI to GitHub Actions nf-core extra CI - [#32](https://github.com/nf-core/sarek/pull/32), [#33](https://github.com/nf-core/sarek/pull/33) - Install `ASCAT` with `conda` in the `environment.yml` file -- [#33](https://github.com/nf-core/sarek/pull/33) - use workflow.manifest.version to specify workflow version in path to R scripts for control-FREEC and VEP processes +- [#33](https://github.com/nf-core/sarek/pull/33) - use `workflow.manifest.version` to specify workflow version in path to scripts for `ControlFREEC` and `VEP` processes ### `Removed` diff --git a/conf/genomes.config b/conf/genomes.config index 78ec23c8e6..7a4800220e 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -10,31 +10,37 @@ params { genomes { 'GRCh37' { - acLoci = "${params.genomes_base}/1000G_phase3_20130502_SNP_maf0.3.loci" - acLociGC = "${params.genomes_base}/1000G_phase3_20130502_SNP_maf0.3.loci.gc" - bwaIndex = "${params.genomes_base}/human_g1k_v37_decoy.fasta.{amb,ann,bwt,pac,sa}" - dbsnp = "${params.genomes_base}/dbsnp_138.b37.vcf" - dbsnpIndex = "${params.genomes_base}/dbsnp_138.b37.vcf.idx" - genomeDict = "${params.genomes_base}/human_g1k_v37_decoy.dict" - genomeFile = "${params.genomes_base}/human_g1k_v37_decoy.fasta" - genomeIndex = "${params.genomes_base}/human_g1k_v37_decoy.fasta.fai" - intervals = "${params.genomes_base}/wgs_calling_regions_Sarek.list" - knownIndels = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf" - knownIndelsIndex = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" - snpeffDb = "GRCh37.75" - vepCacheVersion = "95" + acLoci = "${params.genomes_base}/1000G_phase3_20130502_SNP_maf0.3.loci" + acLociGC = "${params.genomes_base}/1000G_phase3_20130502_SNP_maf0.3.loci.gc" + bwaIndex = "${params.genomes_base}/human_g1k_v37_decoy.fasta.{amb,ann,bwt,pac,sa}" + chrDir = "${params.genomes_base}/Chromosomes" + chrLength = "${params.genomes_base}/human_g1k_v37_decoy.len" + dbsnp = "${params.genomes_base}/dbsnp_138.b37.vcf" + dbsnpIndex = "${params.genomes_base}/dbsnp_138.b37.vcf.idx" + dict = "${params.genomes_base}/human_g1k_v37_decoy.dict" + fasta = "${params.genomes_base}/human_g1k_v37_decoy.fasta" + fastaFai = "${params.genomes_base}/human_g1k_v37_decoy.fasta.fai" + germlineResource = "${params.genomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh37.PASS.AC.AF.only.vcf.gz" + germlineResourceIndex = "${params.genomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh37.PASS.AC.AF.only.vcf.gz.tbi" + intervals = "${params.genomes_base}/wgs_calling_regions_Sarek.list" + knownIndels = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf" + knownIndelsIndex = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" + snpeffDb = "GRCh37.75" + vepCacheVersion = "95" } 'GRCh38' { acLoci = "${params.genomes_base}/1000G_phase3_GRCh38_maf0.3.loci" acLociGC = "${params.genomes_base}/1000G_phase3_GRCh38_maf0.3.loci.gc" bwaIndex = "${params.genomes_base}/Homo_sapiens_assembly38.fasta.64.{alt,amb,ann,bwt,pac,sa}" + chrDir = "${params.genomes_base}/Chromosomes" + chrLength = "${params.genomes_base}/Homo_sapiens_assembly38.len" dbsnp = "${params.genomes_base}/dbsnp_146.hg38.vcf.gz" dbsnpIndex = "${params.genomes_base}/dbsnp_146.hg38.vcf.gz.tbi" + dict = "${params.genomes_base}/Homo_sapiens_assembly38.dict" + fasta = "${params.genomes_base}/Homo_sapiens_assembly38.fasta" + fastaFai = "${params.genomes_base}/Homo_sapiens_assembly38.fasta.fai" germlineResource = "${params.genomes_base}/GCF_000001405.38.AUTOSOMESXY.COMMON.BIALLELIC.SNPs.with.AF.vcf.gz" germlineResourceIndex = "${params.genomes_base}/GCF_000001405.38.AUTOSOMESXY.COMMON.BIALLELIC.SNPs.with.AF.vcf.gz.tbi" - genomeDict = "${params.genomes_base}/Homo_sapiens_assembly38.dict" - genomeFile = "${params.genomes_base}/Homo_sapiens_assembly38.fasta" - genomeIndex = "${params.genomes_base}/Homo_sapiens_assembly38.fasta.fai" intervals = "${params.genomes_base}/wgs_calling_regions.hg38.bed" knownIndels = "${params.genomes_base}/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" knownIndelsIndex = "${params.genomes_base}/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" @@ -49,9 +55,9 @@ params { dbsnpIndex = "${params.genomes_base}/dbsnp_138.b37.small.vcf.idx" germlineResource = "${params.genomes_base}/dbsnp_138.b37.small.vcf" germlineResourceIndex = "${params.genomes_base}/dbsnp_138.b37.small.vcf.idx" - genomeDict = "${params.genomes_base}/human_g1k_v37_decoy.small.dict" - genomeFile = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" - genomeIndex = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta.fai" + dict = "${params.genomes_base}/human_g1k_v37_decoy.small.dict" + fasta = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" + fastaFai = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta.fai" intervals = "${params.genomes_base}/small.intervals" knownIndels = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf" knownIndelsIndex = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf.idx" diff --git a/conf/igenomes.config b/conf/igenomes.config index 95fa91e27c..79f7b85484 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -7,41 +7,45 @@ * path using $params.igenomes_base / --igenomes_base */ - params { - genomes { - 'GRCh37' { - acLoci = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/ASCAT/1000G_phase3_20130502_SNP_maf0.3.loci" - acLociGC = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/ASCAT/1000G_phase3_20130502_SNP_maf0.3.loci.gc" - bwaIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/BWAIndex/human_g1k_v37_decoy.fasta.{amb,ann,bwt,pac,sa}" - dbsnp = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/dbsnp_138.b37.vcf" - dbsnpIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/dbsnp_138.b37.vcf.idx" - germlineResource = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh37.PASS.AC.AF.only.vcf.gz" - germlineResourceIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh37.PASS.AC.AF.only.vcf.gz.tbi" - genomeDict = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.dict" - genomeFile = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta" - genomeIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta.fai" - intervals = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/intervals/wgs_calling_regions_Sarek.list" - knownIndels = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf" - knownIndelsIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" - snpeffDb = "GRCh37.75" - vepCacheVersion = "95" - } - 'GRCh38' { - acLoci = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/ASCAT/1000G_phase3_GRCh38_maf0.3.loci" - acLociGC = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/ASCAT/1000G_phase3_GRCh38_maf0.3.loci.gc" - bwaIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/BWAIndex/Homo_sapiens_assembly38.fasta.64.{alt,amb,ann,bwt,pac,sa}" - dbsnp = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz" - dbsnpIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz.tbi" - germlineResource = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh38.PASS.AC.AF.only.vcf.gz" - germlineResourceIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh38.PASS.AC.AF.only.vcf.gz.tbi" - genomeDict = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.dict" - genomeFile = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta" - genomeIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta.fai" - intervals = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/intervals/wgs_calling_regions.hg38.bed" - knownIndels = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" - knownIndelsIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" - snpeffDb = "GRCh38.86" - vepCacheVersion = "95" - } - } - } +params { + genomes { + 'GRCh37' { + acLoci = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/ASCAT/1000G_phase3_20130502_SNP_maf0.3.loci" + acLociGC = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/ASCAT/1000G_phase3_20130502_SNP_maf0.3.loci.gc" + bwaIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/BWAIndex/human_g1k_v37_decoy.fasta.{amb,ann,bwt,pac,sa}" + chrDir = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/Chromosomes" + chrLength = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/Length/human_g1k_v37_decoy.len" + dbsnp = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/dbsnp_138.b37.vcf" + dbsnpIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/dbsnp_138.b37.vcf.idx" + dict = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.dict" + fasta = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta" + fastaFai = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta.fai" + germlineResource = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh37.PASS.AC.AF.only.vcf.gz" + germlineResourceIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh37.PASS.AC.AF.only.vcf.gz.tbi" + intervals = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/intervals/wgs_calling_regions_Sarek.list" + knownIndels = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf" + knownIndelsIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" + snpeffDb = "GRCh37.75" + vepCacheVersion = "95" + } + 'GRCh38' { + acLoci = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/ASCAT/1000G_phase3_GRCh38_maf0.3.loci" + acLociGC = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/ASCAT/1000G_phase3_GRCh38_maf0.3.loci.gc" + bwaIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/BWAIndex/Homo_sapiens_assembly38.fasta.64.{alt,amb,ann,bwt,pac,sa}" + chrDir = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/Chromosomes" + chrLength = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/Length/Homo_sapiens_assembly38.len" + dbsnp = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz" + dbsnpIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz.tbi" + dict = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.dict" + fasta = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta" + fastaFai = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta.fai" + germlineResource = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh38.PASS.AC.AF.only.vcf.gz" + germlineResourceIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh38.PASS.AC.AF.only.vcf.gz.tbi" + intervals = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/intervals/wgs_calling_regions.hg38.bed" + knownIndels = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" + knownIndelsIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" + snpeffDb = "GRCh38.86" + vepCacheVersion = "95" + } + } +} diff --git a/docs/usage.md b/docs/usage.md index c737e92688..c60dbd2256 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -13,8 +13,8 @@ * [`-profile`](#-profile) * [`--sample`](#--sample) * [`--noGVCF`](#--nogvcf) + * [`--skipQC`](#--skipqc) * [`--nucleotidesPerSecond`](#--nucleotidespersecond) - * [`--skipQC`](#--skipQC) * [`--step`](#--step) * [`--tools`](#--tools) * [`--noStrelkaBP`](#--nostrelkabp) @@ -24,18 +24,20 @@ * [`--acLoci`](#--acloci) * [`--acLociGC`](#--aclocigc) * [`--bwaIndex`](#--bwaindex) + * [`--chrDir`](#--chrdir) + * [`--chrLength`](#--chrlength) * [`--dbsnp`](#--dbsnp) * [`--dbsnpIndex`](#--dbsnpindex) * [`--genomeDict`](#--genomedict) * [`--genomeFile`](#--genomefile) * [`--genomeIndex`](#--genomeindex) - * [`--germlineResource`](#--germlineResource) - * [`--germlineResourceIndex`](#--germlineResourceIndex) + * [`--germlineResource`](#--germlineresource) + * [`--germlineResourceIndex`](#--germlineresourceindex) * [`--intervals`](#--intervals) * [`--knownIndels`](#--knownindels) * [`--knownIndelsIndex`](#--knownindelsindex) - * [`--snpeffDb`](#--snpeffdb) * [`--pon`](#--pon) + * [`--snpeffDb`](#--snpeffdb) * [`--vepCacheVersion`](#--vepcacheversion) * [`--igenomesIgnore`](#--igenomesignore) * [Job resources](#job-resources) @@ -274,6 +276,22 @@ If you prefer, you can specify the full path to your reference genome when you r --bwaIndex '[path to the bwa indexes]' ``` +### `--chrDir` + +If you prefer, you can specify the full path to your reference genome when you run the pipeline: + +```bash +--chrDir '[path to the Chromosomes folder]' +``` + +### `--chrLength` + +If you prefer, you can specify the full path to your reference genome when you run the pipeline: + +```bash +--chrLength '[path to the Chromosomes length file]' +``` + ### `--dbsnp` If you prefer, you can specify the full path to your reference genome when you run the pipeline: From c8bc0e828bd94bc5b09a037e2bd3b1e1af4a8953 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 9 Sep 2019 16:04:15 +0200 Subject: [PATCH 049/854] fix params name --- conf/genomes.config | 18 +++++++++--------- conf/igenomes.config | 12 ++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/conf/genomes.config b/conf/genomes.config index 7a4800220e..9c24651acf 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -17,9 +17,9 @@ params { chrLength = "${params.genomes_base}/human_g1k_v37_decoy.len" dbsnp = "${params.genomes_base}/dbsnp_138.b37.vcf" dbsnpIndex = "${params.genomes_base}/dbsnp_138.b37.vcf.idx" - dict = "${params.genomes_base}/human_g1k_v37_decoy.dict" - fasta = "${params.genomes_base}/human_g1k_v37_decoy.fasta" - fastaFai = "${params.genomes_base}/human_g1k_v37_decoy.fasta.fai" + genomeDict = "${params.genomes_base}/human_g1k_v37_decoy.dict" + genomeFile = "${params.genomes_base}/human_g1k_v37_decoy.fasta" + genomeIndex = "${params.genomes_base}/human_g1k_v37_decoy.fasta.fai" germlineResource = "${params.genomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh37.PASS.AC.AF.only.vcf.gz" germlineResourceIndex = "${params.genomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh37.PASS.AC.AF.only.vcf.gz.tbi" intervals = "${params.genomes_base}/wgs_calling_regions_Sarek.list" @@ -36,9 +36,9 @@ params { chrLength = "${params.genomes_base}/Homo_sapiens_assembly38.len" dbsnp = "${params.genomes_base}/dbsnp_146.hg38.vcf.gz" dbsnpIndex = "${params.genomes_base}/dbsnp_146.hg38.vcf.gz.tbi" - dict = "${params.genomes_base}/Homo_sapiens_assembly38.dict" - fasta = "${params.genomes_base}/Homo_sapiens_assembly38.fasta" - fastaFai = "${params.genomes_base}/Homo_sapiens_assembly38.fasta.fai" + genomeDict = "${params.genomes_base}/Homo_sapiens_assembly38.dict" + genomeFile = "${params.genomes_base}/Homo_sapiens_assembly38.fasta" + genomeIndex = "${params.genomes_base}/Homo_sapiens_assembly38.fasta.fai" germlineResource = "${params.genomes_base}/GCF_000001405.38.AUTOSOMESXY.COMMON.BIALLELIC.SNPs.with.AF.vcf.gz" germlineResourceIndex = "${params.genomes_base}/GCF_000001405.38.AUTOSOMESXY.COMMON.BIALLELIC.SNPs.with.AF.vcf.gz.tbi" intervals = "${params.genomes_base}/wgs_calling_regions.hg38.bed" @@ -55,9 +55,9 @@ params { dbsnpIndex = "${params.genomes_base}/dbsnp_138.b37.small.vcf.idx" germlineResource = "${params.genomes_base}/dbsnp_138.b37.small.vcf" germlineResourceIndex = "${params.genomes_base}/dbsnp_138.b37.small.vcf.idx" - dict = "${params.genomes_base}/human_g1k_v37_decoy.small.dict" - fasta = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" - fastaFai = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta.fai" + genomeDict = "${params.genomes_base}/human_g1k_v37_decoy.small.dict" + genomeFile = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" + genomeIndex = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta.fai" intervals = "${params.genomes_base}/small.intervals" knownIndels = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf" knownIndelsIndex = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf.idx" diff --git a/conf/igenomes.config b/conf/igenomes.config index 79f7b85484..8982b98a0c 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -17,9 +17,9 @@ params { chrLength = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/Length/human_g1k_v37_decoy.len" dbsnp = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/dbsnp_138.b37.vcf" dbsnpIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/dbsnp_138.b37.vcf.idx" - dict = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.dict" - fasta = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta" - fastaFai = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta.fai" + genomeDict = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.dict" + genomeFile = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta" + genomeIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta.fai" germlineResource = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh37.PASS.AC.AF.only.vcf.gz" germlineResourceIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh37.PASS.AC.AF.only.vcf.gz.tbi" intervals = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/intervals/wgs_calling_regions_Sarek.list" @@ -36,9 +36,9 @@ params { chrLength = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/Length/Homo_sapiens_assembly38.len" dbsnp = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz" dbsnpIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz.tbi" - dict = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.dict" - fasta = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta" - fastaFai = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta.fai" + genomeDict = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.dict" + genomeFile = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta" + genomeIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta.fai" germlineResource = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh38.PASS.AC.AF.only.vcf.gz" germlineResourceIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh38.PASS.AC.AF.only.vcf.gz.tbi" intervals = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/intervals/wgs_calling_regions.hg38.bed" From c66ca68c6342c3b6238200e4dd0771fd34d74cbb Mon Sep 17 00:00:00 2001 From: Malin Larsson Date: Tue, 10 Sep 2019 13:40:53 +0200 Subject: [PATCH 050/854] updated ASCAT: Now using version 2.5.2 and the most recent instructions on how to convert AlleleCounts to LogR values and run Ascat from https://github.com/cancerit/ascatNgs/blob/dev/perl/share/ascat/runASCAT.R (updated june 2016) --- .gitmodules | 7 +++++++ bin/convertAlleleCounts.r | 18 +++++++++--------- bin/run_ascat.r | 6 ++++-- configs | 1 + data | 1 + main.nf | 5 +++-- 6 files changed, 25 insertions(+), 13 deletions(-) create mode 100644 .gitmodules create mode 160000 configs create mode 160000 data diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..4944a7aa47 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,7 @@ +[submodule "configs"] + path = configs + url = https://github.com/nf-core/configs.git +[submodule "data"] + path = data + url = https://github.com/nf-core/test-datasets.git + branch = sarek diff --git a/bin/convertAlleleCounts.r b/bin/convertAlleleCounts.r index 7ad4a49d46..9798b79cc8 100755 --- a/bin/convertAlleleCounts.r +++ b/bin/convertAlleleCounts.r @@ -37,17 +37,11 @@ normalcounts = read.table(normalac, header=F, sep="\t") SNPpos = matrix(nrow = dim(normalcounts)[1],ncol = 2) rownames(SNPpos) = paste("snp",1:dim(SNPpos)[1],sep="") - -#Change rownames to "chr_pos" instead, such as 1_44552 -#This does not exactly work: -#rownames(SNPpos) = apply(cbind(tumorcounts[,1], tumorcounts[,2]), 1, paste, collapse="_") -#This is for compatibility with gc correction file - colnames(SNPpos) = c("Chr","Position") SNPpos[,1] = as.vector(normalcounts[,1]) SNPpos[,2] = normalcounts[,2] -#Caclulate BAF + Tumor_BAF = matrix(nrow = dim(normalcounts)[1],ncol = 1) rownames(Tumor_BAF) = rownames(SNPpos) colnames(Tumor_BAF) = c(tumorid) @@ -75,14 +69,20 @@ rownames(Germline_LogR) = rownames(SNPpos) colnames(Germline_LogR) = c(normalid) Tumor_LogR[,1] = log(tumorcounts[,7]/normalcounts[,7],2) Germline_LogR[,1] = 0 -Tumor_LogR[is.infinite(Tumor_LogR)]=NA + +Tumor_LogR[! is.finite(Tumor_LogR)]=NA # infinite = coverage in normal only, NaN = no coverage in tumour or normal + if(gender=="XY") { Tumor_LogR[SNPpos[,1]=="X",1] = Tumor_LogR[SNPpos[,1]=="X",1]-1 Germline_LogR[SNPpos[,1]=="X",1] = Germline_LogR[SNPpos[,1]=="X",1]-1 + Tumor_LogR[SNPpos[,1]=="Y",1] = Tumor_LogR[SNPpos[,1]=="Y",1]-1 + Germline_LogR[SNPpos[,1]=="Y",1] = Germline_LogR[SNPpos[,1]=="Y",1]-1 } + Tumor_LogR[,1] = Tumor_LogR[,1] - median(Tumor_LogR[,1],na.rm=T) + # set regions with 0 reads in tumor and normal to a LogR of 0. -Tumor_LogR[is.na(Tumor_LogR[,1]),1] = 0 +#Tumor_LogR[is.na(Tumor_LogR[,1]),1] = 0 removed in updated version 20190910! # limit the number of digits: Tumor_LogR = round(Tumor_LogR,4) diff --git a/bin/run_ascat.r b/bin/run_ascat.r index 6921f98c82..1957d06847 100755 --- a/bin/run_ascat.r +++ b/bin/run_ascat.r @@ -10,9 +10,11 @@ if(length(args)<6){ tumorname = args[5] baseDir = args[6] gcfile = args[7] + gender = args[8] } -source(paste(baseDir,"/scripts/ascat.R", sep="")) +#source(paste(baseDir,"/scripts/ascat.R", sep="")) +library(ASCAT) if(!require(RColorBrewer)){ source("http://bioconductor.org/biocLite.R") @@ -22,7 +24,7 @@ if(!require(RColorBrewer)){ options(bitmapType='cairo') #Load the data -ascat.bc <- ascat.loadData(Tumor_LogR_file=tumorlogr, Tumor_BAF_file=tumorbaf, Germline_LogR_file=normallogr, Germline_BAF_file=normalbaf) +ascat.bc <- ascat.loadData(Tumor_LogR_file=tumorlogr, Tumor_BAF_file=tumorbaf, Germline_LogR_file=normallogr, Germline_BAF_file=normalbaf, chrs = c(1:22,"X","Y"), gender = gender, sexchromosomes = c("X", "Y")) #GC wave correction ascat.bc = ascat.GCcorrect(ascat.bc, gcfile) diff --git a/configs b/configs new file mode 160000 index 0000000000..836da97efd --- /dev/null +++ b/configs @@ -0,0 +1 @@ +Subproject commit 836da97efdd3b9be3a0715c57ae58ee5d85e3c98 diff --git a/data b/data new file mode 160000 index 0000000000..e868cb311b --- /dev/null +++ b/data @@ -0,0 +1 @@ +Subproject commit e868cb311bc8be4e0d8181ae2dc783ed88810ddd diff --git a/main.nf b/main.nf index bed1254246..b06ec618ad 100644 --- a/main.nf +++ b/main.nf @@ -1440,10 +1440,11 @@ process Ascat { when: 'ascat' in tools script: + gender = genderMap[idPatient] """ # get rid of "chr" string if there is any - for f in *BAF *LogR; do sed 's/chr//g' \$f > tmpFile; mv tmpFile \$f;done - Rscript ${workflow.projectDir}/bin/run_ascat.r ${bafTumor} ${logrTumor} ${bafNormal} ${logrNormal} ${idSampleTumor} ${baseDir} ${acLociGC} + #for f in *BAF *LogR; do sed 's/chr//g' \$f > tmpFile; mv tmpFile \$f;done + Rscript ${workflow.projectDir}/bin/run_ascat.r ${bafTumor} ${logrTumor} ${bafNormal} ${logrNormal} ${idSampleTumor} ${baseDir} ${acLociGC} ${gender} """ } From f6e000361dc1e1e0e5f085d08361d60f3fb447d0 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 10 Sep 2019 14:21:53 +0200 Subject: [PATCH 051/854] fix branch protection GitHub actions --- .github/workflows/branch.yml | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 69170e93f0..8c377efb09 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -12,16 +12,4 @@ jobs: # PRs are only ok if coming from an nf-core dev branch - name: Check PRs run: | - echo "HOME: ${HOME}" - echo "GITHUB_WORKFLOW: ${GITHUB_WORKFLOW}" - echo "GITHUB_ACTION: ${GITHUB_ACTION}" - echo "GITHUB_ACTOR: ${GITHUB_ACTOR}" - echo "GITHUB_REPOSITORY: ${GITHUB_REPOSITORY}" - echo "GITHUB_EVENT_NAME: ${GITHUB_EVENT_NAME}" - echo "GITHUB_EVENT_PATH: ${GITHUB_EVENT_PATH}" - echo "GITHUB_WORKSPACE: ${GITHUB_WORKSPACE}" - echo "GITHUB_SHA: ${GITHUB_SHA}" - echo "GITHUB_REF: ${GITHUB_REF}" - echo "GITHUB_HEAD_REF: ${GITHUB_HEAD_REF}" - echo "GITHUB_BASE_REF: ${GITHUB_BASE_REF}" - [ ${GITHUB_ACTOR} = "nf-core" ] && [ ${GITHUB_HEAD_REF} = "dev" ] \ No newline at end of file + [[ $(git remote get-url origin) == *nf-core/sarek ]] && [ ${GITHUB_BASE_REF} = "master" ] && [ ${GITHUB_HEAD_REF} = "dev" ] From e01cbfb9aa83540c295a032f199d49c6bdbb9bbf Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 10 Sep 2019 14:23:55 +0200 Subject: [PATCH 052/854] fix branch protection GitHub actions --- .github/workflows/branch.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 8c377efb09..7c5fbfdc80 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -10,6 +10,7 @@ jobs: runs-on: ubuntu-latest steps: # PRs are only ok if coming from an nf-core dev branch + - uses: actions/checkout@v1 - name: Check PRs run: | [[ $(git remote get-url origin) == *nf-core/sarek ]] && [ ${GITHUB_BASE_REF} = "master" ] && [ ${GITHUB_HEAD_REF} = "dev" ] From c0c08ae144dd9c539acd268430467b25b9bc9b61 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 10 Sep 2019 16:43:53 +0200 Subject: [PATCH 053/854] fixing badges --- .github/workflows/branch.yml | 2 +- .github/workflows/ci-extra.yml | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/linting.yml | 2 +- README.md | 5 +++-- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 7c5fbfdc80..58a41ff689 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -1,4 +1,4 @@ -name: nf-core branch protection +name: sarek branch protection # This workflow is triggered on PRs to master branch on the repository on: pull_request: diff --git a/.github/workflows/ci-extra.yml b/.github/workflows/ci-extra.yml index 1b70a86079..2b2b593c72 100644 --- a/.github/workflows/ci-extra.yml +++ b/.github/workflows/ci-extra.yml @@ -1,4 +1,4 @@ -name: nf-core extra CI +name: sarek extra CI # This workflow is triggered on pushes and PRs to the repository. on: [push, pull_request] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1fe215c9f4..829b4764bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: nf-core CI +name: sarek CI # This workflow is triggered on pushes and PRs to the repository. on: [push, pull_request] diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index d7d426cef6..3892e41f2f 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -1,4 +1,4 @@ -name: nf-core linting +name: sarek linting # This workflow is triggered on pushes and PRs to the repository. on: [push, pull_request] diff --git a/README.md b/README.md index 1140da3e36..e054e6bbf6 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,9 @@ [![nf-core](https://img.shields.io/badge/nf--core-pipeline-brightgreen.svg)](https://nf-co.re/) [![Travis build status](https://img.shields.io/travis/nf-core/sarek.svg)](https://travis-ci.com/nf-core/sarek/) -[![GitHub Actions CI Status](https://github.com/nf-core/sarek/workflows/nf-core%20CI/badge.svg)](https://github.com/nf-core/sarek/actions) -[![GitHub Actions Linting Status](https://github.com/nf-core/sarek/workflows/nf-core%20linting/badge.svg)](https://github.com/nf-core/sarek/actions) +[![GitHub Actions CI Status](https://github.com/nf-core/sarek/workflows/sarek%20CI/badge.svg)](https://github.com/nf-core/sarek/actions) +[![GitHub Actions extra CI Status](https://github.com/nf-core/sarek/workflows/sarek%20extra%20CI/badge.svg)](https://github.com/nf-core/sarek/actions) +[![GitHub Actions Linting Status](https://github.com/nf-core/sarek/workflows/sarek%20linting/badge.svg)](https://github.com/nf-core/sarek/actions) [![CircleCi build status](https://img.shields.io/circleci/project/github/nf-core/sarek.svg)](https://circleci.com/gh/nf-core/sarek/) [![install with bioconda](https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg)](http://bioconda.github.io/) From 5ea919f484b44705f5b64e9ea1c7b0b546adc7f5 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Tue, 10 Sep 2019 20:51:06 +0200 Subject: [PATCH 054/854] Change --sample by --input (#23) * feat: remove unnecessary Channel.create() * feat: replace --sample with --input, genomeFile with fasta... * feat: update comments * feat: update docs * add deprecation message for --sample, --sampleDir, --anotateVCF, --noReports, --genomeDict, --genomeFile, --genomeIndex - Add message when deprecated params are used - Deprecated params are still working - Fix usage of deprecated params * Fix --input for germline sample directory * tsvPath is now defined as null by default * add deprecation info in docs about --noReports --- CHANGELOG.md | 19 +++- build.nf | 3 - conf/genomes.config | 18 +-- conf/igenomes.config | 12 +- conf/test.config | 2 +- docs/input.md | 10 +- docs/usage.md | 125 +++++++++++++++++++-- docs/use_cases.md | 20 ++-- main.nf | 253 +++++++++++++++++++++++++------------------ nextflow.config | 2 +- scripts/run_tests.sh | 14 +-- 11 files changed, 312 insertions(+), 166 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e8c8b9603..313e89c4ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,17 +43,17 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#21](https://github.com/nf-core/sarek/pull/21) - Add tests for latest Nextflow version as well - [#21](https://github.com/nf-core/sarek/pull/21) - Add `genomes.config` for genomes without AWS iGenomes - [#24](https://github.com/nf-core/sarek/pull/24) - Added GATK4 Mutect2 calling and filtering -- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Use Github actions for CI +- [#27](https://github.com/nf-core/sarek/pull/27), [#30](https://github.com/nf-core/sarek/pull/30) - Use Github actions for CI, linting and branch protection - [#31](https://github.com/nf-core/sarek/pull/31) - Add nf-core lint - [#31](https://github.com/nf-core/sarek/pull/31) - Add extra CI to GitHub Actions nf-core extra CI ### `Changed` -- [#1](https://github.com/nf-core/sarek/pull/1), [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#6](https://github.com/nf-core/sarek/pull/6), [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9), [#10](https://github.com/nf-core/sarek/pull/10), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12), [#18](https://github.com/nf-core/sarek/pull/18), [#20](https://github.com/nf-core/sarek/pull/20), [#21](https://github.com/nf-core/sarek/pull/21), [#29](https://github.com/nf-core/sarek/pull/29) - Update docs +- [#1](https://github.com/nf-core/sarek/pull/1), [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#6](https://github.com/nf-core/sarek/pull/6), [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9), [#10](https://github.com/nf-core/sarek/pull/10), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12), [#18](https://github.com/nf-core/sarek/pull/18), [#20](https://github.com/nf-core/sarek/pull/20), [#21](https://github.com/nf-core/sarek/pull/21), [#23](https://github.com/nf-core/sarek/pull/23), [#29](https://github.com/nf-core/sarek/pull/29) - Update docs - [#4](https://github.com/nf-core/sarek/pull/4) - Update `cancerit-allelecount` from `2.1.2` to `4.0.2` - [#4](https://github.com/nf-core/sarek/pull/4) - Update `gatk4` from `4.1.1.0` to `4.1.2.0` -- [#7](https://github.com/nf-core/sarek/pull/7) - `--sampleDir` is now deprecated, use `--sample` instead -- [#7](https://github.com/nf-core/sarek/pull/8) - `--annotateVCF` is now deprecated, use `--sample` instead +- [#7](https://github.com/nf-core/sarek/pull/7), [#23](https://github.com/nf-core/sarek/pull/23) - `--sampleDir` is now deprecated, use `--input` instead +- [#7](https://github.com/nf-core/sarek/pull/8), [#23](https://github.com/nf-core/sarek/pull/23) - `--annotateVCF` is now deprecated, use `--input` instead - [#8](https://github.com/nf-core/sarek/pull/8), [#12](https://github.com/nf-core/sarek/pull/12) - Improve helper script `build.nf` for downloading and building reference files - [#9](https://github.com/nf-core/sarek/pull/9) - ApplyBQSR is now parallelized - [#9](https://github.com/nf-core/sarek/pull/9) - Fastq files are named following "${idRun}_R1.fastq.gz" in the FastQC output for easier reporting @@ -73,7 +73,13 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#18](https://github.com/nf-core/sarek/pull/18), [#29](https://github.com/nf-core/sarek/pull/29) - `--noReports` is now `--skipQC all` - [#18](https://github.com/nf-core/sarek/pull/18), [#21](https://github.com/nf-core/sarek/pull/21) - Update logo - [#21](https://github.com/nf-core/sarek/pull/21) - Moved smallGRCh37 path to `genomes.config` +- [#23](https://github.com/nf-core/sarek/pull/23) - Rename `genomeFile`, `genomeIndex` and `genomeDict` by `fasta`, `fastaFai` and `dict` +- [#23](https://github.com/nf-core/sarek/pull/23) - `--sample` is now deprecated, use `--input` instead +- [#23](https://github.com/nf-core/sarek/pull/23) - `--genomeFile` is now deprecated, use `--fasta` instead +- [#23](https://github.com/nf-core/sarek/pull/23) - `--genomeIndex` is now deprecated, use `--fastaFai` instead +- [#23](https://github.com/nf-core/sarek/pull/23) - `--genomeDict` is now deprecated, use `--dict` instead - [#24](https://github.com/nf-core/sarek/pull/24) - iGenomes config now contains germline resource for GATK4 Mutect2 +- [#30](https://github.com/nf-core/sarek/pull/30) - Simplify code for `MapReads` process - [#31](https://github.com/nf-core/sarek/pull/31) - Move extra CI to GitHub Actions nf-core extra CI - [#32](https://github.com/nf-core/sarek/pull/32), [#33](https://github.com/nf-core/sarek/pull/33) - Install `ASCAT` with `conda` in the `environment.yml` file - [#33](https://github.com/nf-core/sarek/pull/33) - use workflow.manifest.version to specify workflow version in path to R scripts for control-FREEC and VEP processes @@ -91,7 +97,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) ### `Fixed` - [#3](https://github.com/nf-core/sarek/pull/3) - Fix Docker ownership -- [#11](https://github.com/nf-core/sarek/pull/11) - Fix MergeMpileup PublishDir +- [#11](https://github.com/nf-core/sarek/pull/11) - Fix `MergeMpileup` PublishDir - [#13](https://github.com/nf-core/sarek/pull/13) - Fix merge in annotation - [#14](https://github.com/nf-core/sarek/pull/14) - Fix output name for vcf files - [#16](https://github.com/nf-core/sarek/pull/16) - Fix path to Rscript @@ -99,7 +105,8 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#18](https://github.com/nf-core/sarek/pull/18) - Use same font for nf-core and sarek in ascii art - [#20](https://github.com/nf-core/sarek/pull/20) - Use new logo in README - [#20](https://github.com/nf-core/sarek/pull/20) - Fix path to references genomes -- [#22](https://github.com/nf-core/sarek/pull/22) - Fix --singleCPUMem issue +- [#22](https://github.com/nf-core/sarek/pull/22) - Fix `--singleCPUMem` issue +- [#30](https://github.com/nf-core/sarek/pull/30) - fix choice between `inputPairReadsFastQC` and `inputBAMFastQC` channels - [#31](https://github.com/nf-core/sarek/pull/31) - Fix badges according to nf-core lint - [#31](https://github.com/nf-core/sarek/pull/31) - Fix rcolorbrewer version according to nf-core lint - [#33](https://github.com/nf-core/sarek/pull/33) - Fix MD Linting diff --git a/build.nf b/build.nf index 3f23f8a1da..b70e1530f1 100644 --- a/build.nf +++ b/build.nf @@ -186,9 +186,6 @@ process DecompressFile { ch_decompressedFiles = ch_decompressedFiles.dump(tag:'DecompressedFile') ch_fastaFile = Channel.create() -ch_fastaForBWA = Channel.create() -ch_fastaReference = Channel.create() -ch_fastaForSAMTools = Channel.create() ch_otherFile = Channel.create() ch_vcfFile = Channel.create() diff --git a/conf/genomes.config b/conf/genomes.config index 78ec23c8e6..c22824a932 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -15,9 +15,9 @@ params { bwaIndex = "${params.genomes_base}/human_g1k_v37_decoy.fasta.{amb,ann,bwt,pac,sa}" dbsnp = "${params.genomes_base}/dbsnp_138.b37.vcf" dbsnpIndex = "${params.genomes_base}/dbsnp_138.b37.vcf.idx" - genomeDict = "${params.genomes_base}/human_g1k_v37_decoy.dict" - genomeFile = "${params.genomes_base}/human_g1k_v37_decoy.fasta" - genomeIndex = "${params.genomes_base}/human_g1k_v37_decoy.fasta.fai" + dict = "${params.genomes_base}/human_g1k_v37_decoy.dict" + fasta = "${params.genomes_base}/human_g1k_v37_decoy.fasta" + fastaFai = "${params.genomes_base}/human_g1k_v37_decoy.fasta.fai" intervals = "${params.genomes_base}/wgs_calling_regions_Sarek.list" knownIndels = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf" knownIndelsIndex = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" @@ -32,9 +32,9 @@ params { dbsnpIndex = "${params.genomes_base}/dbsnp_146.hg38.vcf.gz.tbi" germlineResource = "${params.genomes_base}/GCF_000001405.38.AUTOSOMESXY.COMMON.BIALLELIC.SNPs.with.AF.vcf.gz" germlineResourceIndex = "${params.genomes_base}/GCF_000001405.38.AUTOSOMESXY.COMMON.BIALLELIC.SNPs.with.AF.vcf.gz.tbi" - genomeDict = "${params.genomes_base}/Homo_sapiens_assembly38.dict" - genomeFile = "${params.genomes_base}/Homo_sapiens_assembly38.fasta" - genomeIndex = "${params.genomes_base}/Homo_sapiens_assembly38.fasta.fai" + dict = "${params.genomes_base}/Homo_sapiens_assembly38.dict" + fasta = "${params.genomes_base}/Homo_sapiens_assembly38.fasta" + fastaFai = "${params.genomes_base}/Homo_sapiens_assembly38.fasta.fai" intervals = "${params.genomes_base}/wgs_calling_regions.hg38.bed" knownIndels = "${params.genomes_base}/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" knownIndelsIndex = "${params.genomes_base}/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" @@ -49,9 +49,9 @@ params { dbsnpIndex = "${params.genomes_base}/dbsnp_138.b37.small.vcf.idx" germlineResource = "${params.genomes_base}/dbsnp_138.b37.small.vcf" germlineResourceIndex = "${params.genomes_base}/dbsnp_138.b37.small.vcf.idx" - genomeDict = "${params.genomes_base}/human_g1k_v37_decoy.small.dict" - genomeFile = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" - genomeIndex = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta.fai" + dict = "${params.genomes_base}/human_g1k_v37_decoy.small.dict" + fasta = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" + fastaFai = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta.fai" intervals = "${params.genomes_base}/small.intervals" knownIndels = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf" knownIndelsIndex = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf.idx" diff --git a/conf/igenomes.config b/conf/igenomes.config index 95fa91e27c..fd12e8200a 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -17,9 +17,9 @@ dbsnpIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/dbsnp_138.b37.vcf.idx" germlineResource = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh37.PASS.AC.AF.only.vcf.gz" germlineResourceIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh37.PASS.AC.AF.only.vcf.gz.tbi" - genomeDict = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.dict" - genomeFile = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta" - genomeIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta.fai" + dict = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.dict" + fasta = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta" + fastaFai = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Sequence/WholeGenomeFasta/human_g1k_v37_decoy.fasta.fai" intervals = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/intervals/wgs_calling_regions_Sarek.list" knownIndels = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf" knownIndelsIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" @@ -34,9 +34,9 @@ dbsnpIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz.tbi" germlineResource = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh38.PASS.AC.AF.only.vcf.gz" germlineResourceIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh38.PASS.AC.AF.only.vcf.gz.tbi" - genomeDict = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.dict" - genomeFile = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta" - genomeIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta.fai" + dict = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.dict" + fasta = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta" + fastaFai = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Sequence/WholeGenomeFasta/Homo_sapiens_assembly38.fasta.fai" intervals = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/intervals/wgs_calling_regions.hg38.bed" knownIndels = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" knownIndelsIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" diff --git a/conf/test.config b/conf/test.config index b0fd3b6fab..fb92b47f10 100644 --- a/conf/test.config +++ b/conf/test.config @@ -15,7 +15,7 @@ params { max_memory = 6.GB max_time = 48.h // Input data - sample = 'https://github.com/nf-core/test-datasets/raw/sarek/testdata/tsv/tiny-manta-https.tsv' + input = 'https://github.com/nf-core/test-datasets/raw/sarek/testdata/tsv/tiny-manta-https.tsv' // Small reference genome // To be build with: `nextflow run build.nf --build -profile docker --outdir references` igenomesIgnore = true diff --git a/docs/input.md b/docs/input.md index 094ca38169..18e6695855 100644 --- a/docs/input.md +++ b/docs/input.md @@ -2,7 +2,7 @@ ## Information about the TSV files -Input files for Sarek can be specified using a TSV file given to the `--sample` command. +Input files for Sarek can be specified using a TSV file given to the `--input` command. The TSV file is a Tab Separated Value file with columns: - `subject gender status sample lane fastq1 fastq2` for step `mapping` with paired-end FASTQs @@ -49,10 +49,10 @@ G15511 XX 1 D0ENMT D0ENM_2 pathToFiles/D0ENMACXX111207.2_1.fastq. ## Path to a FASTQ directory for a single normal sample (step mapping) -Input files for Sarek can be specified using the path to a FASTQ directory given to the `--sample` command only with the `mapping` step. +Input files for Sarek can be specified using the path to a FASTQ directory given to the `--input` command only with the `mapping` step. ```bash -nextflow run nf-core/sarek --sample pathToDirectory ... +nextflow run nf-core/sarek --input pathToDirectory ... ``` ### Input FASTQ file name best practices @@ -128,9 +128,9 @@ G15511 XX 1 D0ENMT pathToFiles/G15511.D0ENMT.md.recal.bam pathToF ## VCF files for annotation -Input files for Sarek can be specified using the path to a VCF directory given to the `--sample` command only with the `annotate` step. +Input files for Sarek can be specified using the path to a VCF directory given to the `--input` command only with the `annotate` step. Multiple VCF files can be specified if the path is enclosed in quotes. ```bash -nextflow run nf-core/sarek --step annotate --sample "results/VariantCalling/*/.vcf.gz" ... +nextflow run nf-core/sarek --step annotate --input "results/VariantCalling/*/.vcf.gz" ... ``` diff --git a/docs/usage.md b/docs/usage.md index c737e92688..6d179111e4 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -11,10 +11,14 @@ * [Reproducibility](#reproducibility) * [Main arguments](#main-arguments) * [`-profile`](#-profile) + * [`--input`](#--input) * [`--sample`](#--sample) + * [`--sampleDir`](#--sampledir) + * [`--annotateVCF`](#--annotatevcf) * [`--noGVCF`](#--nogvcf) + * [`--skipQC`](#--skipqc) + * [`--noReports`](#--noreports) * [`--nucleotidesPerSecond`](#--nucleotidespersecond) - * [`--skipQC`](#--skipQC) * [`--step`](#--step) * [`--tools`](#--tools) * [`--noStrelkaBP`](#--nostrelkabp) @@ -26,16 +30,19 @@ * [`--bwaIndex`](#--bwaindex) * [`--dbsnp`](#--dbsnp) * [`--dbsnpIndex`](#--dbsnpindex) + * [`--dict`](#--dict) + * [`--fasta`](#--fasta) + * [`--fastaFai`](#--fastafai) * [`--genomeDict`](#--genomedict) * [`--genomeFile`](#--genomefile) * [`--genomeIndex`](#--genomeindex) - * [`--germlineResource`](#--germlineResource) - * [`--germlineResourceIndex`](#--germlineResourceIndex) + * [`--germlineResource`](#--germlineresource) + * [`--germlineResourceIndex`](#--germlineresourceindex) * [`--intervals`](#--intervals) * [`--knownIndels`](#--knownindels) * [`--knownIndelsIndex`](#--knownindelsindex) - * [`--snpeffDb`](#--snpeffdb) * [`--pon`](#--pon) + * [`--snpeffDb`](#--snpeffdb) * [`--vepCacheVersion`](#--vepcacheversion) * [`--igenomesIgnore`](#--igenomesignore) * [Job resources](#job-resources) @@ -80,7 +87,7 @@ NXF_OPTS='-Xms1g -Xmx4g' The typical command for running the pipeline is as follows: ```bash -nextflow run nf-core/sarek --sample sample.tsv -profile docker +nextflow run nf-core/sarek --input sample.tsv -profile docker ``` This will launch the pipeline with the `docker` configuration profile. @@ -145,8 +152,38 @@ If `-profile` is not specified at all the pipeline will be run locally and expec * A profile with a complete configuration for automated testing * Includes links to test data so needs no other parameters +### `--input` + +Use this to specify the location of your input TSV file, on `mapping`, `recalibrate` and `variantcalling` steps. +For example: + +```bash +--input sample.tsv +``` + +Multiple TSV files can be specified if the path must be enclosed in quotes + +Use this to specify the location to a directory on `mapping` step with a single germline sample only. +For example: + +```bash +--input PathToDirectory +``` + +Use this to specify the location of your VCF input file on `annotate` step. +For example: + +```bash +--input sample.vcf +``` + +Multiple VCF files can be specified if the path must be enclosed in quotes + ### `--sample` +> :warning: This params is deprecated -- it will be removed in a future release. +> Please check: [`--input`](#--input) + Use this to specify the location of your input TSV file, on `mapping`, `recalibrate` and `variantcalling` steps. For example: @@ -172,6 +209,32 @@ For example: Multiple VCF files can be specified if the path must be enclosed in quotes +### `--sampleDir` + +> :warning: This params is deprecated -- it will be removed in a future release. +> Please check: [`--input`](#--input) + +Use this to specify the location to a directory on `mapping` step with a single germline sample only. +For example: + +```bash +--sampleDir PathToDirectory +``` + +### `--annotateVCF` + +> :warning: This params is deprecated -- it will be removed in a future release. +> Please check: [`--input`](#--input) + +Use this to specify the location of your VCF input file on `annotate` step. +For example: + +```bash +--annotateVCF sample.vcf +``` + +Multiple VCF files can be specified if the path must be enclosed in quotes + ### `--noGVCF` Use this to disable g.vcf from `HaplotypeCaller`. @@ -182,6 +245,13 @@ Use this to disable specific QC and Reporting tools. Available: `all`, `bamQC`, `BCFtools`, `FastQC`, `MultiQC`, `samtools`, `vcftools`, `versions` Default: `None` +### `--noReports` + +> :warning: This params is deprecated -- it will be removed in a future release. +> Please check: [`--skipQC`](#--skipQC) + +Use this to disable all QC and Reporting tools. + ### `--nucleotidesPerSecond` Use this to estimate of how many seconds it will take to call variants on any interval, the default value is `1000` is it's not specified in the `.bed` file. @@ -236,9 +306,9 @@ params { bwaIndex = '' dbsnp = '' dbsnpIndex = '' - genomeDict = '' - genomeFile = '' - genomeIndex = '' + dict = '' + fasta = '' + fastaFai = '' intervals = '' knownIndels = '' knownIndelsIndex = '' @@ -290,28 +360,61 @@ If you prefer, you can specify the full path to your reference genome when you r --dbsnpIndex '[path to the dbsnp index]' ``` +### `--dict` + +If you prefer, you can specify the full path to your reference genome when you run the pipeline: + +```bash +--dict '[path to the dict file]' +``` + +### `--fasta` + +If you prefer, you can specify the full path to your reference genome when you run the pipeline: + +```bash +--fasta '[path to the reference fasta file]' +``` + +### `--fastaFai` + +If you prefer, you can specify the full path to your reference genome when you run the pipeline: + +```bash +--fastaFai '[path to the reference index]' +``` + ### `--genomeDict` +> :warning: This params is deprecated -- it will be removed in a future release. +> Please check: [`--dict`](#--dict) + If you prefer, you can specify the full path to your reference genome when you run the pipeline: ```bash ---genomeDict '[path to the genomeDict file]' +--dict '[path to the dict file]' ``` ### `--genomeFile` +> :warning: This params is deprecated -- it will be removed in a future release. +> Please check: [`--fasta`](#--fasta) + If you prefer, you can specify the full path to your reference genome when you run the pipeline: ```bash ---genomeFile '[path to the genome file]' +--fasta '[path to the reference fasta file]' ``` ### `--genomeIndex` +> :warning: This params is deprecated -- it will be removed in a future release. +> Please check: [`--fastaFai`](#--fastaFai) + If you prefer, you can specify the full path to your reference genome when you run the pipeline: ```bash ---genomeIndex '[path to the genome Index]' +--fastaFai '[path to the reference index]' ``` ### `--germlineResource` diff --git a/docs/use_cases.md b/docs/use_cases.md index c47ad93387..2491ad69e6 100644 --- a/docs/use_cases.md +++ b/docs/use_cases.md @@ -5,7 +5,7 @@ Using the `mapping` directive one will have a pair of mapped, deduplicated and r This is the usual option you have to give when you are starting from raw FASTQ data: ```bash -nextflow run nf-core/sarek/main.nf --sample mysample.tsv --tools +nextflow run nf-core/sarek/main.nf --input mysample.tsv --tools ``` `mapping` will start by default, you do not have to give any additional parameters, only the TSV file describing the sample (see below). @@ -20,7 +20,7 @@ Also, older version are renamed with incremented numbers. The workflow should be started in this case with the smallest set of options as written above: ```bash -nextflow run nf-core/sarek/main.nf --sample mysample.tsv --tools +nextflow run nf-core/sarek/main.nf --input mysample.tsv --tools ``` The TSV file should look like: @@ -33,22 +33,22 @@ See the [input files documentation](docs/input.md) for more information. ## Starting from raw FASTQ - a directory with normal sample only -The `--sample` option can be also used to point Sarek to a directory with FASTQ files: +The `--input` option can be also used to point Sarek to a directory with FASTQ files: ```bash -nextflow run nf-core/sarek/main.nf --sample path/to/FASTQ/files --tools +nextflow run nf-core/sarek/main.nf --input path/to/FASTQ/files --tools ``` The given directory is searched recursively for FASTQ files that are named `*_R1_*.fastq.gz`, and a matching pair with the same name except `_R2_` instead of `_R1_` is expected to exist alongside. All of the found FASTQ files are considered to belong to the sample. Each FASTQ file pair gets its own read group (`@RG`) in the resulting BAM file. -### Metadata when using `--sample` with a directory +### Metadata when using `--input` with a directory -When using `--sample` with a directory, the metadata about the sample that are written to the BAM header in the `@RG` tag are determined in the following way. +When using `--input` with a directory, the metadata about the sample that are written to the BAM header in the `@RG` tag are determined in the following way. -- The sample name (`SM`) is derived from the the last component of the path given to `--sample`. -That is, you should make sure that that directory has a meaningful name! For example, with `--sample=/my/fastqs/sample123`, the sample name will be `sample123`. +- The sample name (`SM`) is derived from the the last component of the path given to `--input`. +That is, you should make sure that that directory has a meaningful name! For example, with `--input=/my/fastqs/sample123`, the sample name will be `sample123`. - The read group id is set to *flowcell.samplename.lane*. The flowcell id and lane number are auto-detected from the name of the first read in the FASTQ file. @@ -78,7 +78,7 @@ See the [input files documentation](docs/input.md) for more information. ## Starting from recalibration ```bash -nextflow run nf-core/sarek/main.nf --sample mysample.tsv --step recalibrate --tools +nextflow run nf-core/sarek/main.nf --input mysample.tsv --step recalibrate --tools ``` And the corresponding TSV file should be like: @@ -121,5 +121,5 @@ It is adviced to pad the variant calling regions (exons or the target) to some e To add the target BED file configure the flow like: ```bash -nextflow run nf-core/sarek/main.nf --tools haplotypecaller,strelka,mutect2 --targetBED targets.bed --sample my_panel.tsv +nextflow run nf-core/sarek/main.nf --tools haplotypecaller,strelka,mutect2 --targetBED targets.bed --input my_panel.tsv ``` diff --git a/main.nf b/main.nf index 62f73b9474..d54965cf63 100644 --- a/main.nf +++ b/main.nf @@ -27,10 +27,10 @@ def helpMessage() { The typical command for running the pipeline is as follows: - nextflow run nf-core/sarek --sample sample.tsv -profile docker + nextflow run nf-core/sarek --input sample.tsv -profile docker Mandatory arguments: - --sample Path to input TSV file on mapping, recalibrate and variantcalling steps + --input Path to input TSV file on mapping, recalibrate and variantcalling steps Multiple TSV files can be specified with quotes Works also with the path to a directory on mapping step with a single germline sample only Alternatively, path to VCF input file on annotate step @@ -70,9 +70,9 @@ def helpMessage() { --bwaIndex bwa indexes --dbsnp dbsnp file --dbsnpIndex dbsnp index - --genomeDict genome dict - --genomeFile genome file - --genomeIndex genome index + --dict dict from the fasta reference + --fasta fasta reference + --fastafai reference index --intervals intervals --knownIndels knownIndels file --knownIndelsIndex knownIndels index @@ -102,6 +102,22 @@ def helpMessage() { // Show help message if (params.help) exit 0, helpMessage() +// Handle deprecation +params.noReports = null +if (params.noReports) log.warn "The params `--noReports` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--skipQC" +params.annotateVCF = null +if (params.annotateVCF) log.warn "The params `--annotateVCF` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--input" +params.genomeDict = null +if (params.genomeDict) log.warn "The params `--genomeDict` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--dict" +params.genomeFile = null +if (params.genomeFile) log.warn "The params `--genomeFile` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--fasta" +params.genomeIndex = null +if (params.genomeIndex) log.warn "The params `--genomeIndex` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--fastaFai" +params.sample = null +if (params.sample) log.warn "The params `--sample` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--input" +params.sampleDir = null +if (params.sampleDir) log.warn "The params `--sampleDir` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--input" + // Check if genome exists in the config file if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { exit 1, "The provided genome '${params.genome}' is not available in the iGenomes file. Currently the available genomes are ${params.genomes.keySet().join(", ")}" @@ -116,13 +132,13 @@ params.cadd_WG_SNVs = null params.cadd_WG_SNVs_tbi = null params.cadd_cache = null params.genesplicer = null +params.input = null params.monochrome_logs = null params.multiqc_config = null params.noGVCF = null params.noStrelkaBP = null params.nucleotidesPerSecond = 1000.0 params.pon = null -params.sample = null params.sequencing_center = null params.skipQC = null params.snpEff_cache = null @@ -145,6 +161,9 @@ skipQClist = defineSkipQClist() skipQC = params.skipQC ? params.skipQC == 'all' ? skipQClist : params.skipQC.split(',').collect{it.trim().toLowerCase()} : [] if (!checkParameterList(skipQC, skipQClist)) exit 1, 'Unknown QC tool(s), see --help for more information' +// Handle deprecation +if (params.noReports) skipQC = skipQClist + annoList = defineAnnoList() annotateTools = params.annotateTools ? params.annotateTools.split(',').collect{it.trim().toLowerCase()} : [] if (!checkParameterList(annotateTools,annoList)) exit 1, 'Unknown tool(s) to annotate, see --help for more information' @@ -171,12 +190,17 @@ if (workflow.profile == 'awsbatch') { ch_output_docs = Channel.fromPath("${baseDir}/docs/output.md") tsvPath = null -if (params.sample) if (hasExtension(params.sample, "tsv") || hasExtension(params.sample, "vcf") || hasExtension(params.sample, "vcf.gz")) tsvPath = params.sample -if (params.sample) if (hasExtension(params.sample, "vcf") || hasExtension(params.sample, "vcf.gz")) step = "annotate" +if (params.input && (hasExtension(params.input, "tsv") || hasExtension(params.input, "vcf") || hasExtension(params.input, "vcf.gz"))) tsvPath = params.input +if (params.input && (hasExtension(params.input, "vcf") || hasExtension(params.input, "vcf.gz"))) step = "annotate" + +// Handle deprecation +if (params.annotateVCF) tsvPath = params.annotateVCF +if (params.sample) tsvPath = params.sample +if (params.sampleDir) tsvPath = params.sampleDir // If no input file specified, trying to get TSV files corresponding to step in the TSV directory // only for steps recalibrate and variantCalling -if (!params.sample && step != 'mapping' && step != 'annotate') { +if (!params.input && step != 'mapping' && step != 'annotate') { tsvPath = step == 'recalibrate' ? "${params.outdir}/Preprocessing/TSV/duplicateMarked.tsv": "${params.outdir}/Preprocessing/TSV/recalibrated.tsv" } @@ -190,16 +214,16 @@ if (tsvPath) { case 'annotate': break default: exit 1, "Unknown step ${step}" } -} else if (params.sample) if (!hasExtension(params.sample, "tsv")) { +} else if (params.input && !hasExtension(params.input, "tsv")) { println "No TSV file" if (step != 'mapping') exit 1, 'No other step than "mapping" support a dir as an input' - println "Reading ${params.sample} directory" - inputSample = extractFastqFromDir(params.sample) + println "Reading ${params.input} directory" + inputSample = extractFastqFromDir(params.input) (inputSample, fastqTMP) = inputSample.into(2) fastqTMP.toList().subscribe onNext: { - if (it.size() == 0) exit 1, "No FASTQ files found in --sample directory '${params.sample}'" + if (it.size() == 0) exit 1, "No FASTQ files found in --input directory '${params.input}'" } - tsvFile = params.sample // used in the reports + tsvFile = params.input // used in the reports } else if (step == 'annotate') { println "Annotating ${tsvFile}" } else exit 1, 'No sample were defined, see --help' @@ -212,15 +236,15 @@ def summary = [:] if (workflow.revision) summary['Pipeline Release'] = workflow.revision summary['Run Name'] = custom_runName ?: workflow.runName summary['Max Resources'] = "${params.max_memory} memory, ${params.max_cpus} cpus, ${params.max_time} time per job" -if (workflow.containerEngine) summary['Container'] = "${workflow.containerEngine} - ${workflow.container}" -if (params.sample) summary['Sample'] = params.sample -if (params.targetBED) summary['Target BED'] = params.targetBED -if (params.step) summary['Step'] = params.step -if (params.tools) summary['Tools'] = tools.join(', ') -if (params.skipQC) summary['QC tools skip'] = skipQC.join(', ') -if (params.noGVCF) summary['No GVCF'] = params.noGVCF -if (params.noStrelkaBP) summary['No Strelka BP'] = params.noStrelkaBP -if (params.sequencing_center) summary['Sequenced by '] = params.sequencing_center +if (workflow.containerEngine) summary['Container'] = "${workflow.containerEngine} - ${workflow.container}" +if (params.input) summary['Input'] = params.input +if (params.targetBED) summary['Target BED'] = params.targetBED +if (params.step) summary['Step'] = params.step +if (params.tools) summary['Tools'] = tools.join(', ') +if (params.skipQC) summary['QC tools skip'] = skipQC.join(', ') +if (params.noGVCF) summary['No GVCF'] = params.noGVCF +if (params.noStrelkaBP) summary['No Strelka BP'] = params.noStrelkaBP +if (params.sequencing_center) summary['Sequenced by '] = params.sequencing_center if (params.pon) summary['Panel of normals '] = params.pon summary['Nucleotides/s'] = params.nucleotidesPerSecond summary['Output dir'] = params.outdir @@ -437,7 +461,7 @@ process MapReads { input: set idPatient, idSample, idRun, file(inputFile1), file(inputFile2) from inputReads - set file(genomeFile), file(bwaIndex) from Channel.value([referenceMap.genomeFile, referenceMap.bwaIndex]) + set file(fasta), file(bwaIndex) from Channel.value([referenceMap.fasta, referenceMap.bwaIndex]) output: set idPatient, idSample, idRun, file("${idRun}.bam") into bamMapped @@ -460,7 +484,7 @@ process MapReads { input = hasExtension(inputFile1, "bam") ? "-p /dev/stdin - 2> >(tee ${inputFile1}.bwa.stderr.log >&2)" : "${inputFile1} ${inputFile2}" """ ${convertToFastq} - bwa mem -K 100000000 -R \"${readGroup}\" ${extra} -t ${task.cpus} -M ${genomeFile} \ + bwa mem -K 100000000 -R \"${readGroup}\" ${extra} -t ${task.cpus} -M ${fasta} \ ${input} | \ samtools sort --threads ${task.cpus} -m 2G - > ${idRun}.bam """ @@ -560,10 +584,10 @@ process BaseRecalibrator { input: set idPatient, idSample, file(bam), file(bai), file(intervalBed) from bamBaseRecalibrator - set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex), file(knownIndels), file(knownIndelsIndex) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex, - referenceMap.genomeDict, + set file(fasta), file(fastaFai), file(dict), file(dbsnp), file(dbsnpIndex), file(knownIndels), file(knownIndelsIndex) from Channel.value([ + referenceMap.fasta, + referenceMap.fastaFai, + referenceMap.dict, referenceMap.dbsnp, referenceMap.dbsnpIndex, referenceMap.knownIndels, @@ -584,7 +608,7 @@ process BaseRecalibrator { -I ${bam} \ -O ${intervalBed.baseName}_${idSample}.recal.table \ --tmp-dir /tmp \ - -R ${genomeFile} \ + -R ${fasta} \ -L ${intervalBed} \ --known-sites ${dbsnp} \ ${known} \ @@ -658,10 +682,10 @@ process ApplyBQSR { input: set idPatient, idSample, file(bam), file(bai), file(recalibrationReport), file(intervalBed) from bamApplyBQSR - set file(genomeFile), file(genomeIndex), file(genomeDict)from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex, - referenceMap.genomeDict + set file(fasta), file(fastaFai), file(dict)from Channel.value([ + referenceMap.fasta, + referenceMap.fastaFai, + referenceMap.dict ]) output: @@ -671,7 +695,7 @@ process ApplyBQSR { """ gatk --java-options -Xmx${task.memory.toGiga()}g \ ApplyBQSR \ - -R ${genomeFile} \ + -R ${fasta} \ --input ${bam} \ --output ${intervalBed.baseName}_${idSample}.recal.bam \ -L ${intervalBed} \ @@ -820,10 +844,10 @@ process HaplotypeCaller { input: set idPatient, idSample, file(bam), file(bai), file(intervalBed) from bamHaplotypeCaller - set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex, - referenceMap.genomeDict, + set file(fasta), file(fastaFai), file(dict), file(dbsnp), file(dbsnpIndex) from Channel.value([ + referenceMap.fasta, + referenceMap.fastaFai, + referenceMap.dict, referenceMap.dbsnp, referenceMap.dbsnpIndex ]) @@ -838,7 +862,7 @@ process HaplotypeCaller { """ gatk --java-options "-Xmx${task.memory.toGiga()}g -Xms6000m -XX:GCTimeLimit=50 -XX:GCHeapFreeLimit=10" \ HaplotypeCaller \ - -R ${genomeFile} \ + -R ${fasta} \ -I ${bam} \ -L ${intervalBed} \ -D ${dbsnp} \ @@ -859,10 +883,10 @@ process GenotypeGVCFs { input: set idPatient, idSample, file(intervalBed), file(gvcf) from gvcfGenotypeGVCFs - set file(genomeFile), file(genomeIndex), file(genomeDict), file(dbsnp), file(dbsnpIndex) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex, - referenceMap.genomeDict, + set file(fasta), file(fastaFai), file(dict), file(dbsnp), file(dbsnpIndex) from Channel.value([ + referenceMap.fasta, + referenceMap.fastaFai, + referenceMap.dict, referenceMap.dbsnp, referenceMap.dbsnpIndex ]) @@ -880,7 +904,7 @@ process GenotypeGVCFs { gatk --java-options -Xmx${task.memory.toGiga()}g \ GenotypeGVCFs \ - -R ${genomeFile} \ + -R ${fasta} \ -L ${intervalBed} \ -D ${dbsnp} \ -V ${gvcf} \ @@ -903,9 +927,9 @@ process StrelkaSingle { input: set idPatient, idSample, file(bam), file(bai) from bamStrelkaSingle file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") - set file(genomeFile), file(genomeIndex) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex + set file(fasta), file(fastaFai) from Channel.value([ + referenceMap.fasta, + referenceMap.fastaFai ]) output: @@ -920,7 +944,7 @@ process StrelkaSingle { ${beforeScript} configureStrelkaGermlineWorkflow.py \ --bam ${bam} \ - --referenceFasta ${genomeFile} \ + --referenceFasta ${fasta} \ ${options} \ --runDir Strelka @@ -952,9 +976,9 @@ process MantaSingle { input: set idPatient, idSample, file(bam), file(bai) from bamMantaSingle file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") - set file(genomeFile), file(genomeIndex) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex + set file(fasta), file(fastaFai) from Channel.value([ + referenceMap.fasta, + referenceMap.fastaFai ]) output: @@ -972,7 +996,7 @@ process MantaSingle { ${beforeScript} configManta.py \ ${inputbam} ${bam} \ - --reference ${genomeFile} \ + --reference ${fasta} \ ${options} \ --runDir Manta @@ -1010,9 +1034,9 @@ process TIDDIT { input: set idPatient, idSample, file(bam), file(bai) from bamTIDDIT - set file(genomeFile), file(genomeIndex) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex + set file(fasta), file(fastaFai) from Channel.value([ + referenceMap.fasta, + referenceMap.fastaFai ]) output: @@ -1023,7 +1047,7 @@ process TIDDIT { script: """ - tiddit --sv -o TIDDIT_${idSample} --bam ${bam} --ref ${genomeFile} + tiddit --sv -o TIDDIT_${idSample} --bam ${bam} --ref ${fasta} mv TIDDIT_${idSample}.vcf TIDDIT_${idSample}.old.vcf @@ -1080,8 +1104,10 @@ process FreeBayes { input: set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from pairBamFreeBayes - file(genomeFile) from Channel.value(referenceMap.genomeFile) - file(genomeIndex) from Channel.value(referenceMap.genomeIndex) + set file(fasta), file(fastaFai) from Channel.value([ + referenceMap.fasta, + referenceMap.fastaFai + ]) output: set val("FreeBayes"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf") into vcfFreeBayes @@ -1091,7 +1117,7 @@ process FreeBayes { script: """ freebayes \ - -f ${genomeFile} \ + -f ${fasta} \ --pooled-continuous \ --pooled-discrete \ --genotype-qualities \ @@ -1116,10 +1142,10 @@ process Mutect2 { input: set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from pairBamMutect2 - set file(genomeFile), file(genomeIndex), file(genomeDict), file(intervals), file(germlineResource), file(germlineResourceIndex) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex, - referenceMap.genomeDict, + set file(fasta), file(fastaFai), file(dict), file(intervals), file(germlineResource), file(germlineResourceIndex) from Channel.value([ + referenceMap.fasta, + referenceMap.fastaFai, + referenceMap.dict, referenceMap.intervals, referenceMap.germlineResource, referenceMap.germlineResourceIndex @@ -1147,7 +1173,7 @@ process Mutect2 { # this case we are getting raw calls only for the intervals, we also have to concatenate them gatk --java-options "-Xmx${task.memory.toGiga()}g" \ Mutect2 \ - -R ${genomeFile}\ + -R ${fasta}\ -I ${bamTumor} -tumor ${idSampleTumor} \ -I ${bamNormal} -normal ${idSampleNormal} \ -L ${intervalBed} \ @@ -1177,10 +1203,10 @@ process MergeMutect2Stats { idSampleTumor, idSampleNormal, file(statsFiles) from mutect2Stats // the actual stats files - set file(genomeFile), file(genomeIndex), file(genomeDict), file(intervals), file(germlineResource), file(germlineResourceIndex) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex, - referenceMap.genomeDict, + set file(fasta), file(fastaFai), file(dict), file(intervals), file(germlineResource), file(germlineResourceIndex) from Channel.value([ + referenceMap.fasta, + referenceMap.fastaFai, + referenceMap.dict, referenceMap.intervals, referenceMap.germlineResource, referenceMap.germlineResourceIndex @@ -1217,7 +1243,7 @@ process ConcatVCF { input: set variantCaller, idPatient, idSample, file(vcFiles) from vcfConcatenateVCFs - file(genomeIndex) from Channel.value(referenceMap.genomeIndex) + file(fastaFai) from Channel.value(referenceMap.fastaFai) file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") output: @@ -1235,13 +1261,15 @@ process ConcatVCF { outputFile = "${variantCaller}_${idSample}.vcf" options = params.targetBED ? "-t ${targetBED}" : "" """ - concatenateVCFs.sh -i ${genomeIndex} -c ${task.cpus} -o ${outputFile} ${options} + concatenateVCFs.sh -i ${fastaFai} -c ${task.cpus} -o ${outputFile} ${options} """ } (vcfConcatenated, vcfConcatenatedForFilter) = vcfConcatenated.into(2) vcfConcatenated = vcfConcatenated.dump(tag:'VCF') +// STEP GATK MUTECT2 + process PileupSummariesForMutect2 { tag {idSampleTumor + "_vs_" + idSampleNormal + "_" + intervalBed.baseName } label 'cpus_1' @@ -1286,7 +1314,7 @@ process MergePileupSummaries { input: set idPatient, idSampleTumor, file(pileupSums) from pileupSummaries - file(genomeDict) from Channel.value([referenceMap.genomeDict]) + file(dict) from Channel.value([referenceMap.dict]) output: file("${idSampleTumor}_pileupsummaries.table.tsv") into mergedPileupFile @@ -1297,7 +1325,7 @@ process MergePileupSummaries { """ gatk --java-options "-Xmx${task.memory.toGiga()}g" \ GatherPileupSummaries \ - --sequence-dictionary ${genomeDict} \ + --sequence-dictionary ${dict} \ ${allPileups} \ -O ${idSampleTumor}_pileupsummaries.table.tsv """ @@ -1340,10 +1368,10 @@ process FilterMutect2Calls { idSampleTN, file(unfiltered), file(unfilteredIndex) from vcfConcatenatedForFilter - set file(genomeFile), file(genomeIndex), file(genomeDict), file(intervals), file(germlineResource), file(germlineResourceIndex) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex, - referenceMap.genomeDict, + set file(fasta), file(fastaFai), file(dict), file(intervals), file(germlineResource), file(germlineResourceIndex) from Channel.value([ + referenceMap.fasta, + referenceMap.fastaFai, + referenceMap.dict, referenceMap.intervals, referenceMap.germlineResource, referenceMap.germlineResourceIndex @@ -1369,7 +1397,7 @@ process FilterMutect2Calls { -V $unfiltered \ --contamination-table ${idSampleTN}_contamination.table \ --stats ${idSampleTN}.vcf.gz.stats \ - -R ${genomeFile} \ + -R ${fasta} \ -O filtered_${variantCaller}_${idSampleTN}.vcf.gz """ } @@ -1387,10 +1415,10 @@ process Strelka { input: set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor) from pairBamStrelka file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") - set file(genomeFile), file(genomeIndex), file(genomeDict) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex, - referenceMap.genomeDict + set file(fasta), file(fastaFai), file(dict) from Channel.value([ + referenceMap.fasta, + referenceMap.fastaFai, + referenceMap.dict ]) output: @@ -1406,7 +1434,7 @@ process Strelka { configureStrelkaSomaticWorkflow.py \ --tumor ${bamTumor} \ --normal ${bamNormal} \ - --referenceFasta ${genomeFile} \ + --referenceFasta ${fasta} \ ${options} \ --runDir Strelka @@ -1438,9 +1466,9 @@ process Manta { input: set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor) from pairBamManta file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") - set file(genomeFile), file(genomeIndex) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex + set file(fasta), file(fastaFai) from Channel.value([ + referenceMap.fasta, + referenceMap.fastaFai ]) output: @@ -1457,7 +1485,7 @@ process Manta { configManta.py \ --normalBam ${bamNormal} \ --tumorBam ${bamTumor} \ - --reference ${genomeFile} \ + --reference ${fasta} \ ${options} \ --runDir Manta @@ -1506,10 +1534,10 @@ process StrelkaBP { input: set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(mantaCSI), file(mantaCSIi) from pairBamStrelkaBP file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") - set file(genomeFile), file(genomeIndex), file(genomeDict) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex, - referenceMap.genomeDict + set file(fasta), file(fastaFai), file(dict) from Channel.value([ + referenceMap.fasta, + referenceMap.fastaFai, + referenceMap.dict ]) output: @@ -1525,7 +1553,7 @@ process StrelkaBP { configureStrelkaSomaticWorkflow.py \ --tumor ${bamTumor} \ --normal ${bamNormal} \ - --referenceFasta ${genomeFile} \ + --referenceFasta ${fasta} \ --indelCandidates ${mantaCSI} \ ${options} \ --runDir Strelka @@ -1556,11 +1584,11 @@ process AlleleCounter { input: set idPatient, idSample, file(bam), file(bai) from bamAscat - set file(acLoci), file(genomeFile), file(genomeIndex), file(genomeDict) from Channel.value([ + set file(acLoci), file(fasta), file(fastaFai), file(dict) from Channel.value([ referenceMap.acLoci, - referenceMap.genomeFile, - referenceMap.genomeIndex, - referenceMap.genomeDict + referenceMap.fasta, + referenceMap.fastaFai, + referenceMap.dict ]) output: @@ -1572,7 +1600,7 @@ process AlleleCounter { """ alleleCounter \ -l ${acLoci} \ - -r ${genomeFile} \ + -r ${fasta} \ -b ${bam} \ -o ${idSample}.alleleCount; """ @@ -1657,9 +1685,9 @@ process Mpileup { input: set idPatient, idSample, file(bam), file(bai), file(intervalBed) from bamMpileup - set file(genomeFile), file(genomeIndex) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex + set file(fasta), file(fastaFai) from Channel.value([ + referenceMap.fasta, + referenceMap.fastaFai ]) output: @@ -1670,7 +1698,7 @@ process Mpileup { script: """ samtools mpileup \ - -f ${genomeFile} ${bam} \ + -f ${fasta} ${bam} \ -l ${intervalBed} \ | bgzip --threads ${task.cpus} -c > ${intervalBed.baseName}_${idSample}.pileup.gz """ @@ -1732,9 +1760,9 @@ process ControlFREEC { input: set idPatient, idSampleNormal, idSampleTumor, file(mpileupNormal), file(mpileupTumor) from mpileupOut - set file(genomeFile), file(genomeIndex), file(dbsnp), file(dbsnpIndex), file(chrDir), file(chrLength) from Channel.value([ - referenceMap.genomeFile, - referenceMap.genomeIndex, + set file(fasta), file(fastaFai), file(dbsnp), file(dbsnpIndex), file(chrDir), file(chrLength) from Channel.value([ + referenceMap.fasta, + referenceMap.fastaFai, referenceMap.dbsnp, referenceMap.dbsnpIndex, referenceMap.chrDir, @@ -2434,6 +2462,11 @@ def checkParameterList(list, realList) { // Check if params.item exists and return params.genomes[params.genome].item otherwise def checkParamReturnFile(item) { + // Handle deprecation + if (params.genomeDict && item == "dict") return file(params.genomeDict) + if (params.genomeFile && item == "fasta") return file(params.genomeFile) + if (params.genomeIndex && item == "fastaFai") return file(params.genomeIndex) + params."${item}" = params.genomes[params.genome]."${item}" return file(params."${item}") } @@ -2462,9 +2495,9 @@ def checkReferenceMap(referenceMap) { // Define map of reference depending of tools and step def defineReferenceMap(step, tools) { def referenceMap = [ - 'genomeDict' : checkParamReturnFile("genomeDict"), - 'genomeFile' : checkParamReturnFile("genomeFile"), - 'genomeIndex' : checkParamReturnFile("genomeIndex"), + 'dict' : checkParamReturnFile("dict"), + 'fasta' : checkParamReturnFile("fasta"), + 'fastaFai' : checkParamReturnFile("fastaFai"), 'intervals' : checkParamReturnFile("intervals") ] if ('mapping' in step) { @@ -2554,6 +2587,12 @@ def defineToolList() { ] } +// Print deprecation message +def deprecationMessage(oldItem, newItem = null) { + extra = newItem == null ? "": ", please use `${newItem}` instead" + log.warn "The ${oldItem} is deprecated${extra} -- it will be removed in a future release" +} + // Channeling the TSV file containing BAM. // Format is: "subject gender status sample bam bai" def extractBam(tsvFile) { diff --git a/nextflow.config b/nextflow.config index 686593b934..ec1ca9b05c 100644 --- a/nextflow.config +++ b/nextflow.config @@ -100,7 +100,7 @@ dag { manifest { name = 'nf-core/sarek' - author = 'Maxime Garcia' + author = 'Maxime Garcia, Szilveszter Juhos' homePage = 'https://github.com/nf-core/sarek' description = 'An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing' mainScript = 'main.nf' diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index 6e125e3c9a..2f852a6655 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -109,21 +109,21 @@ esac case $TEST in ANNOTATE) - run_sarek --step annotate --tools ${ANNOTATOR} --sample ${PATHTOSAMPLE}/vcf/Strelka_1234N_variants.vcf.gz + run_sarek --step annotate --tools ${ANNOTATOR} --input ${PATHTOSAMPLE}/vcf/Strelka_1234N_variants.vcf.gz ;; GERMLINE) - run_sarek --tools=false --sample data/testdata/tiny/normal - run_sarek --tools=false --sample results/Preprocessing/TSV/duplicateMarked.tsv --step recalibrate - run_sarek --tools HaplotypeCaller --sample results/Preprocessing/TSV/recalibrated.tsv --step variantCalling + run_sarek --tools=false --input data/testdata/tiny/normal + run_sarek --tools=false --input results/Preprocessing/TSV/duplicateMarked.tsv --step recalibrate + run_sarek --tools HaplotypeCaller --input results/Preprocessing/TSV/recalibrated.tsv --step variantCalling ;; MULTIPLE) - run_sarek ${OPTIONS},snpEff,VEP,merge --sample ${PATHTOSAMPLE}/tsv/tiny-multiple${SUFFIX}.tsv + run_sarek ${OPTIONS},snpEff,VEP,merge --input ${PATHTOSAMPLE}/tsv/tiny-multiple${SUFFIX}.tsv ;; SOMATIC) - run_sarek ${OPTIONS} --sample ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv + run_sarek ${OPTIONS} --input ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv ;; TARGETED) - run_sarek ${OPTIONS} --sample ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv --targetBED ${PATHTOSAMPLE}/target.bed + run_sarek ${OPTIONS} --input ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv --targetBED ${PATHTOSAMPLE}/target.bed ;; esac From f22f1639fedf0bac788be46985dec5cc5454dfde Mon Sep 17 00:00:00 2001 From: Malin Larsson Date: Wed, 11 Sep 2019 11:18:09 +0200 Subject: [PATCH 055/854] taking back step where regions with 0 reads in tumor and normal is set to a tumor LogR of 0 --- bin/convertAlleleCounts.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/convertAlleleCounts.r b/bin/convertAlleleCounts.r index 9798b79cc8..ee1ab2551e 100755 --- a/bin/convertAlleleCounts.r +++ b/bin/convertAlleleCounts.r @@ -82,7 +82,7 @@ if(gender=="XY") { Tumor_LogR[,1] = Tumor_LogR[,1] - median(Tumor_LogR[,1],na.rm=T) # set regions with 0 reads in tumor and normal to a LogR of 0. -#Tumor_LogR[is.na(Tumor_LogR[,1]),1] = 0 removed in updated version 20190910! +Tumor_LogR[is.na(Tumor_LogR[,1]),1] = 0 # limit the number of digits: Tumor_LogR = round(Tumor_LogR,4) From 107a0f3dcd9b34d1acb2425250440a819401cf3c Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Thu, 12 Sep 2019 09:58:50 +0200 Subject: [PATCH 056/854] Update tools - `control-freec` from `11.4` to `11.5` - `ensembl-vep` from `95.2` to `97.3` - `freebayes` from `1.2.0` to `1.3.1` - `gatk4` from `4.1.2.0` to `4.1.3.0` - `igvtools` from `2.3.93` to `2.5.3` - `manta` from `1.5.0` to `1.6.0` - `qualimap` from `2.2.2b` to `2.2.2c` - `vcfanno` from `0.3.1` to `0.3.2` --- CHANGELOG.md | 8 ++++++++ containers/vep/environment.yml | 2 +- docs/containers.md | 18 +++++++++--------- environment.yml | 16 ++++++++-------- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 313e89c4ac..c55d67caa0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -83,6 +83,14 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#31](https://github.com/nf-core/sarek/pull/31) - Move extra CI to GitHub Actions nf-core extra CI - [#32](https://github.com/nf-core/sarek/pull/32), [#33](https://github.com/nf-core/sarek/pull/33) - Install `ASCAT` with `conda` in the `environment.yml` file - [#33](https://github.com/nf-core/sarek/pull/33) - use workflow.manifest.version to specify workflow version in path to R scripts for control-FREEC and VEP processes +- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Update `control-freec` from `11.4` to `11.5` +- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Update `ensembl-vep` from `95.2` to `97.3` +- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Update `freebayes` from `1.2.0` to `1.3.1` +- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Update `gatk4` from `4.1.2.0` to `4.1.3.0` +- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Update `igvtools` from `2.3.93` to `2.5.3` +- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Update `manta` from `1.5.0` to `1.6.0` +- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Update `qualimap` from `2.2.2b` to `2.2.2c` +- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Update `vcfanno` from `0.3.1` to `0.3.2` ### `Removed` diff --git a/containers/vep/environment.yml b/containers/vep/environment.yml index 5fd86c3cdc..b29c9e6ca1 100644 --- a/containers/vep/environment.yml +++ b/containers/vep/environment.yml @@ -7,5 +7,5 @@ channels: - defaults dependencies: - - ensembl-vep=95.2 + - ensembl-vep=97.3 - genesplicer=1.0 diff --git a/docs/containers.md b/docs/containers.md index 9f31f477a0..1c05c5efcb 100644 --- a/docs/containers.md +++ b/docs/containers.md @@ -18,23 +18,23 @@ For annotation, the main container can be used, but the cache has to be download - Contain **[AlleleCount](https://github.com/cancerit/alleleCount)** 4.0.2 - Contain **[BCFTools](https://github.com/samtools/bcftools)** 1.9 - Contain **[BWA](https://github.com/lh3/bwa)** 0.7.17 -- Contain **[Control-FREEC](https://github.com/BoevaLab/FREEC)** 11.4 +- Contain **[Control-FREEC](https://github.com/BoevaLab/FREEC)** 11.5 - Contain **[FastQC](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/)** 0.11.8 -- Contain **[FreeBayes](https://github.com/ekg/freebayes)** 1.2.0 -- Contain **[GATK4](https://github.com/broadinstitute/gatk)** 4.1.2.0 +- Contain **[FreeBayes](https://github.com/ekg/freebayes)** 1.3.1 +- Contain **[GATK4](https://github.com/broadinstitute/gatk)** 4.1.3.0 - Contain **[GeneSplicer](https://ccb.jhu.edu/software/genesplicer/)** 1.0 - Contain **[HTSlib](https://github.com/samtools/htslib)** 1.9 -- Contain **[IGVtools](http://software.broadinstitute.org/software/igv/)** 2.3.93 -- Contain **[Manta](https://github.com/Illumina/manta)** 1.5.0 +- Contain **[IGVtools](http://software.broadinstitute.org/software/igv/)** 2.5.3 +- Contain **[Manta](https://github.com/Illumina/manta)** 1.6.0 - Contain **[MultiQC](https://github.com/ewels/MultiQC/)** 1.7 -- Contain **[Qualimap](http://qualimap.bioinfo.cipf.es)** 2.2.2b +- Contain **[Qualimap](http://qualimap.bioinfo.cipf.es)** 2.2.2c - Contain **[samtools](https://github.com/samtools/samtools)** 1.9 - Contain **[snpEff](http://snpeff.sourceforge.net/)** 4.3.1t - Contain **[Strelka2](https://github.com/Illumina/strelka)** 2.9.10 - Contain **[TIDDIT](https://github.com/SciLifeLab/TIDDIT)** 2.7.1 -- Contain **[VCFanno](https://github.com/brentp/vcfanno)** 0.3.1 +- Contain **[VCFanno](https://github.com/brentp/vcfanno)** 0.3.2 - Contain **[VCFtools](https://vcftools.github.io/index.html)** 0.1.16 -- Contain **[VEP](https://github.com/Ensembl/ensembl-vep)** 95.2 +- Contain **[VEP](https://github.com/Ensembl/ensembl-vep)** 97.3 ### sareksnpeff [![sareksnpeff-docker status](https://img.shields.io/docker/automated/nfcore/sareksnpeff.svg)](https://hub.docker.com/r/nfcore/sareksnpeff) @@ -46,7 +46,7 @@ For annotation, the main container can be used, but the cache has to be download - Based on `nfcore/base:latest` - Contain **[GeneSplicer](https://ccb.jhu.edu/software/genesplicer/)** 1.0 -- Contain **[VEP](https://github.com/Ensembl/ensembl-vep)** 95.2 +- Contain **[VEP](https://github.com/Ensembl/ensembl-vep)** 97.3 - Contain cache for `GRCh37`, `GRCh38`, `GRCm38` or `CanFam3.1` ## Using helper script diff --git a/environment.yml b/environment.yml index 761004c21c..3c4b04b263 100644 --- a/environment.yml +++ b/environment.yml @@ -10,20 +10,20 @@ dependencies: - bcftools=1.9 - bwa=0.7.17 - cancerit-allelecount=4.0.2 - - control-freec=11.4 - - ensembl-vep=95.2 + - control-freec=11.5 + - ensembl-vep=97.3 - fastqc=0.11.8 - - freebayes=1.2.0 - - gatk4=4.1.2.0 + - freebayes=1.3.1 + - gatk4=4.1.3.0 - genesplicer=1.0 - htslib=1.9 - - igvtools=2.3.93 - - manta=1.5.0 + - igvtools=2.5.3 + - manta=1.6.0 - multiqc=1.7 - - qualimap=2.2.2b + - qualimap=2.2.2c - samtools=1.9 - snpeff=4.3.1t - strelka=2.9.10 - tiddit=2.7.1 - - vcfanno=0.3.1 + - vcfanno=0.3.2 - vcftools=0.1.16 From 4f6cc2201fe42f1444f8c0ca676ed677b22a5ea5 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Thu, 12 Sep 2019 10:02:02 +0200 Subject: [PATCH 057/854] fix path to files --- conf/genomes.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/genomes.config b/conf/genomes.config index 7a4800220e..fe8398493c 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -20,8 +20,8 @@ params { dict = "${params.genomes_base}/human_g1k_v37_decoy.dict" fasta = "${params.genomes_base}/human_g1k_v37_decoy.fasta" fastaFai = "${params.genomes_base}/human_g1k_v37_decoy.fasta.fai" - germlineResource = "${params.genomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh37.PASS.AC.AF.only.vcf.gz" - germlineResourceIndex = "${params.genomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh37.PASS.AC.AF.only.vcf.gz.tbi" + germlineResource = "${params.genomes_base}/gnomAD.r2.1.1.GRCh37.PASS.AC.AF.only.vcf.gz" + germlineResourceIndex = "${params.genomes_base}/gnomAD.r2.1.1.GRCh37.PASS.AC.AF.only.vcf.gz.tbi" intervals = "${params.genomes_base}/wgs_calling_regions_Sarek.list" knownIndels = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf" knownIndelsIndex = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" From 27f1e09e8c27cc82bc33c80e501f45ecfc9fdf54 Mon Sep 17 00:00:00 2001 From: Malin Larsson Date: Fri, 13 Sep 2019 10:11:55 +0200 Subject: [PATCH 058/854] small edit in run_ascat.r, fix likely typo --- bin/run_ascat.r | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/bin/run_ascat.r b/bin/run_ascat.r index 1957d06847..beefb76cfb 100755 --- a/bin/run_ascat.r +++ b/bin/run_ascat.r @@ -20,11 +20,20 @@ if(!require(RColorBrewer)){ source("http://bioconductor.org/biocLite.R") biocLite("RColorBrewer", suppressUpdates=TRUE, lib="$baseDir/scripts") library(RColorBrewer) -} +}ls options(bitmapType='cairo') #Load the data -ascat.bc <- ascat.loadData(Tumor_LogR_file=tumorlogr, Tumor_BAF_file=tumorbaf, Germline_LogR_file=normallogr, Germline_BAF_file=normalbaf, chrs = c(1:22,"X","Y"), gender = gender, sexchromosomes = c("X", "Y")) +#ascat.bc <- ascat.loadData(Tumor_LogR_file=tumorlogr, Tumor_BAF_file=tumorbaf, Germline_LogR_file=normallogr, Germline_BAF_file=normalbaf, chrs = c(1:22,"X","Y"), gender = gender, sexchromosomes = c("X", "Y")) + +if(gender=="XY"){ + ascat.bc = ascat.loadData(Tumor_LogR_file = tumorlogr, Tumor_BAF_file = tumorbaf, Germline_LogR_file = normallogr, Germline_BAF_file = normalbaf, gender = gender, chrs = c(1:22,"X","Y"), sexchromosomes = c("X","Y")) +} else { + ascat.bc = ascat.loadData(Tumor_LogR_file = tumorlogr, Tumor_BAF_file = tumorbaf, Germline_LogR_file = normallogr, Germline_BAF_file = normalbaf, gender = gender, chrs = c(1:22,"X"), sexchromosomes = c("X")) + +} + + #GC wave correction ascat.bc = ascat.GCcorrect(ascat.bc, gcfile) From 2c71f7c925a291375fa721b79d609271c7a65180 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 13 Sep 2019 13:50:52 +0200 Subject: [PATCH 059/854] update CHANGELOG --- CHANGELOG.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c55d67caa0..ffcfa46995 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -83,14 +83,6 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#31](https://github.com/nf-core/sarek/pull/31) - Move extra CI to GitHub Actions nf-core extra CI - [#32](https://github.com/nf-core/sarek/pull/32), [#33](https://github.com/nf-core/sarek/pull/33) - Install `ASCAT` with `conda` in the `environment.yml` file - [#33](https://github.com/nf-core/sarek/pull/33) - use workflow.manifest.version to specify workflow version in path to R scripts for control-FREEC and VEP processes -- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Update `control-freec` from `11.4` to `11.5` -- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Update `ensembl-vep` from `95.2` to `97.3` -- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Update `freebayes` from `1.2.0` to `1.3.1` -- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Update `gatk4` from `4.1.2.0` to `4.1.3.0` -- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Update `igvtools` from `2.3.93` to `2.5.3` -- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Update `manta` from `1.5.0` to `1.6.0` -- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Update `qualimap` from `2.2.2b` to `2.2.2c` -- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Update `vcfanno` from `0.3.1` to `0.3.2` ### `Removed` @@ -100,7 +92,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#18](https://github.com/nf-core/sarek/pull/18) - Removed params `--noReports` - [#24](https://github.com/nf-core/sarek/pull/18) - Removed GATK3.X MuTect2 - [#31](https://github.com/nf-core/sarek/pull/31) - Remove extra CI from Travis CI and GitHub Actions nf-core CI -- [#32](https://github.com/nf-core/sarek/pull/32) - Clean up `environment.yml` file +- [#32](https://github.com/nf-core/sarek/pull/32), [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Clean up `environment.yml` file ### `Fixed` From 497c00efa6d62bc8b569cfb253eb528fb88a742e Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 13 Sep 2019 13:52:20 +0200 Subject: [PATCH 060/854] update files --- conf/genomes.config | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/conf/genomes.config b/conf/genomes.config index c22824a932..b9fbafb058 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -45,16 +45,11 @@ params { acLoci = "${params.genomes_base}/1000G_phase3_20130502_SNP_maf0.3.small.loci" acLociGC = "${params.genomes_base}/1000G_phase3_20130502_SNP_maf0.3.small.loci.gc" bwaIndex = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta.{amb,ann,bwt,pac,sa}" - dbsnp = "${params.genomes_base}/dbsnp_138.b37.small.vcf" - dbsnpIndex = "${params.genomes_base}/dbsnp_138.b37.small.vcf.idx" - germlineResource = "${params.genomes_base}/dbsnp_138.b37.small.vcf" - germlineResourceIndex = "${params.genomes_base}/dbsnp_138.b37.small.vcf.idx" - dict = "${params.genomes_base}/human_g1k_v37_decoy.small.dict" + dbsnp = "${params.genomes_base}/dbsnp_138.b37.small.vcf.gz" fasta = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" - fastaFai = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta.fai" + germlineResource = "${params.genomes_base}/dbsnp_138.b37.small.vcf.gz" intervals = "${params.genomes_base}/small.intervals" - knownIndels = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf" - knownIndelsIndex = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf.idx" + knownIndels = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf.gz" snpeffDb = "GRCh37.75" vepCacheVersion = "95" } From a1a56f6852aa9dedcced7a516f9bc56f40a6676a Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 13 Sep 2019 13:52:46 +0200 Subject: [PATCH 061/854] rename script --- build.nf => downloadcache.nf | 137 ----------------------------------- 1 file changed, 137 deletions(-) rename build.nf => downloadcache.nf (79%) diff --git a/build.nf b/downloadcache.nf similarity index 79% rename from build.nf rename to downloadcache.nf index b70e1530f1..8e758391d5 100644 --- a/build.nf +++ b/downloadcache.nf @@ -19,19 +19,6 @@ Usage: --help you're reading it -BUILD REFERENCES: - nextflow run build.nf --build --outdir [--offline] - --build - Will build reference files for smallGRCh37 - --outdir - Specify an output directory - - --offline - Will use data as the source for the reference files - Need to do: - `git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data` - Before transfering the repo to an offline location - DOWNLOAD CACHE: nextflow run build.nf --download_cache [--snpEff_cache ] [--vep_cache ] [--cadd_cache --cadd_version ] @@ -156,130 +143,6 @@ ${summary.collect { k,v -> "
$k
${v ?: ' ${f_reference.baseName} - """ -} - -ch_decompressedFiles = ch_decompressedFiles.dump(tag:'DecompressedFile') - -ch_fastaFile = Channel.create() -ch_otherFile = Channel.create() -ch_vcfFile = Channel.create() - -ch_decompressedFiles - .choice(ch_fastaFile, ch_vcfFile, ch_otherFile) { - it =~ ".fasta" ? 0 : - it =~ ".vcf" ? 1 : 2} - -(ch_fastaForBWA, ch_fastaReference, ch_fastaForSAMTools, ch_fastaFileToKeep) = ch_fastaFile.into(4) -(ch_vcfFile, ch_vcfFileToKeep) = ch_vcfFile.into(2) - -ch_notCompressedfiles - .mix(ch_fastaFileToKeep, ch_vcfFileToKeep, ch_otherFile) - .collectFile(storeDir: params.outdir) - -process BuildBWAindexes { - tag {f_reference} - - publishDir params.outdir, mode: params.publishDirMode - - input: - file(f_reference) from ch_fastaForBWA - - output: - file("*.{amb,ann,bwt,pac,sa}") into bwaIndexes - - script: - """ - bwa index ${f_reference} - """ -} - -bwaIndexes.dump(tag:'bwaIndexes') - -process BuildReferenceIndex { - tag {f_reference} - - publishDir params.outdir, mode: params.publishDirMode - - input: - file(f_reference) from ch_fastaReference - - output: - file("*.dict") into ch_referenceIndex - - script: - """ - gatk --java-options "-Xmx${task.memory.toGiga()}g" \ - CreateSequenceDictionary \ - --REFERENCE ${f_reference} \ - --OUTPUT ${f_reference.baseName}.dict - """ -} - -ch_referenceIndex.dump(tag:'dict') - -process BuildSAMToolsIndex { - tag {f_reference} - - publishDir params.outdir, mode: params.publishDirMode - - input: - file(f_reference) from ch_fastaForSAMTools - - output: - file("*.fai") into ch_samtoolsIndex - - script: - """ - samtools faidx ${f_reference} - """ -} - -ch_samtoolsIndex.dump(tag:'fai') - -process BuildVCFIndex { - tag {f_reference} - - publishDir params.outdir, mode: params.publishDirMode - - input: - file(f_reference) from ch_vcfFile - - output: - file("${f_reference}.idx") into ch_vcfIndex - - script: - """ - igvtools index ${f_reference} - """ -} - -ch_vcfIndex.dump(tag:'idx') - /* ================================================================================ = D O W N L O A D C A C H E = From f8d78f361ca0f58ab6460f7971e8628c08d35b8e Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 13 Sep 2019 16:54:56 +0200 Subject: [PATCH 062/854] code polishing --- .github/workflows/ci-extra.yml | 3 - .github/workflows/ci.yml | 3 - .travis.yml | 1 - Jenkinsfile | 6 - conf/genomes.config | 2 +- conf/test.config | 3 +- docs/containers.md | 1 - environment.yml | 1 - main.nf | 606 ++++++++++++++++++--------------- scripts/build_reference.sh | 58 ---- 10 files changed, 343 insertions(+), 341 deletions(-) delete mode 100755 scripts/build_reference.sh diff --git a/.github/workflows/ci-extra.yml b/.github/workflows/ci-extra.yml index 2b2b593c72..cfd23ca890 100644 --- a/.github/workflows/ci-extra.yml +++ b/.github/workflows/ci-extra.yml @@ -19,9 +19,6 @@ jobs: - name: Download image run: | ${GITHUB_WORKSPACE}/scripts/download_image.sh -n docker --test ${{ matrix.test }} - - name: Build References - run: | - ${GITHUB_WORKSPACE}/scripts/build_reference.sh --test ${{ matrix.test }} --verbose - name: Run test run: | ${GITHUB_WORKSPACE}/scripts/run_tests.sh --test ${{ matrix.test }} --verbose \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 829b4764bb..22c1031208 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,9 +19,6 @@ jobs: run: | docker pull nfcore/sarek:dev docker tag nfcore/sarek:dev nfcore/sarek:dev - - name: Build references - run: | - nextflow run ${GITHUB_WORKSPACE}/build.nf -profile test,docker --build --outdir references - name: Run test run: | nextflow run ${GITHUB_WORKSPACE} -profile test,docker \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index d098cba819..e2d4b23d67 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,5 +39,4 @@ script: # Lint the documentation - markdownlint ${TRAVIS_BUILD_DIR} -c ${TRAVIS_BUILD_DIR}/.github/markdownlint.yml # Run the pipeline with the test profile - - nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile test,docker --build --outdir references - nextflow run ${TRAVIS_BUILD_DIR} -profile test,docker \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile index 14c62c7b2c..a48cedb877 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -11,12 +11,6 @@ pipeline { sh "./scripts/download_image.sh -n docker -t ALL -T dev -g smallGRCh37" } } - stage('Build references') { - steps { - sh "rm -rf references/" - sh "./scripts/build_reference.sh" - } - } stage('Germline') { steps { sh "rm -rf data/" diff --git a/conf/genomes.config b/conf/genomes.config index eddc89331e..c117266a7f 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -55,7 +55,7 @@ params { fasta = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" germlineResource = "${params.genomes_base}/dbsnp_138.b37.small.vcf.gz" intervals = "${params.genomes_base}/small.intervals" - knownIndels = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.small.vcf.gz" + knownIndels = ["${params.genomes_base}/1000G_phase1.indels.b37.small.vcf.gz", "${params.genomes_base}/Mills_and_1000G_gold_standard.indels.b37.small.vcf.gz"] snpeffDb = "GRCh37.75" vepCacheVersion = "95" } diff --git a/conf/test.config b/conf/test.config index fb92b47f10..d3d4ad0073 100644 --- a/conf/test.config +++ b/conf/test.config @@ -20,7 +20,8 @@ params { // To be build with: `nextflow run build.nf --build -profile docker --outdir references` igenomesIgnore = true genome = 'smallGRCh37' - genomes_base = 'references' + genomes_base = "https://github.com/MaxUlysse/nf-core_test-datasets/raw/sarek/reference" + // Use publishDir mode link so that work can be removed publishDirMode = 'link' } diff --git a/docs/containers.md b/docs/containers.md index 1c05c5efcb..182588c52c 100644 --- a/docs/containers.md +++ b/docs/containers.md @@ -24,7 +24,6 @@ For annotation, the main container can be used, but the cache has to be download - Contain **[GATK4](https://github.com/broadinstitute/gatk)** 4.1.3.0 - Contain **[GeneSplicer](https://ccb.jhu.edu/software/genesplicer/)** 1.0 - Contain **[HTSlib](https://github.com/samtools/htslib)** 1.9 -- Contain **[IGVtools](http://software.broadinstitute.org/software/igv/)** 2.5.3 - Contain **[Manta](https://github.com/Illumina/manta)** 1.6.0 - Contain **[MultiQC](https://github.com/ewels/MultiQC/)** 1.7 - Contain **[Qualimap](http://qualimap.bioinfo.cipf.es)** 2.2.2c diff --git a/environment.yml b/environment.yml index 3c4b04b263..00bf97b2cb 100644 --- a/environment.yml +++ b/environment.yml @@ -17,7 +17,6 @@ dependencies: - gatk4=4.1.3.0 - genesplicer=1.0 - htslib=1.9 - - igvtools=2.5.3 - manta=1.6.0 - multiqc=1.7 - qualimap=2.2.2c diff --git a/main.nf b/main.nf index d54965cf63..92069bb487 100644 --- a/main.nf +++ b/main.nf @@ -126,10 +126,6 @@ if (params.genomes && params.genome && !params.genomes.containsKey(params.genome // Default value for params params.annotateTools = null params.annotation_cache = null -params.cadd_InDels = null -params.cadd_InDels_tbi = null -params.cadd_WG_SNVs = null -params.cadd_WG_SNVs_tbi = null params.cadd_cache = null params.genesplicer = null params.input = null @@ -138,13 +134,25 @@ params.multiqc_config = null params.noGVCF = null params.noStrelkaBP = null params.nucleotidesPerSecond = 1000.0 -params.pon = null params.sequencing_center = null params.skipQC = null -params.snpEff_cache = null params.step = 'mapping' -params.targetBED = null params.tools = null + +// PON optionnal file for GATK Mutect2 Panel of Normal +params.pon = false + +// TargetBED optionnal file for targeted sequencing +params.targetBED = false + +// Optionnal CADD files +params.cadd_InDels = false +params.cadd_InDels_tbi = false +params.cadd_WG_SNVs = false +params.cadd_WG_SNVs_tbi = false + +// Optionnal directories for cache +params.snpEff_cache = null params.vep_cache = null stepList = defineStepList() @@ -168,9 +176,6 @@ annoList = defineAnnoList() annotateTools = params.annotateTools ? params.annotateTools.split(',').collect{it.trim().toLowerCase()} : [] if (!checkParameterList(annotateTools,annoList)) exit 1, 'Unknown tool(s) to annotate, see --help for more information' -referenceMap = defineReferenceMap(step, tools) -if (!checkReferenceMap(referenceMap)) exit 1, 'Missing Reference file(s), see --help for more information' - // Has the run name been specified by the user? // This has the bonus effect of catching both -name and --name custom_runName = params.name @@ -230,39 +235,225 @@ if (tsvPath) { (genderMap, statusMap, inputSample) = extractInfos(inputSample) +/* +================================================================================ + CHECKING REFERENCES +================================================================================ +*/ + +// Initialize params, in case they were not define on the command line +params.acLoci = params.genome ? params.genomes[params.genome].acLoci ?: null : null +params.acLociGC = params.genome ? params.genomes[params.genome].acLociGC ?: null : null +params.bwaIndex = params.genome && 'mapping' in step ? params.genomes[params.genome].bwa ?: null : null +params.chrDir = params.genome ? params.genomes[params.genome].chrDir ?: null : null +params.chrLength = params.genome ? params.genomes[params.genome].chrLength ?: null : null +params.dbsnp = params.genome && ('mapping' in step || 'controlfreec' in tools || 'haplotypecaller' in tools || 'mutect2' in tools) ? params.genomes[params.genome].dbsnp ?: null : null +params.dbsnpIndex = params.genome ? params.genomes[params.genome].dbsnpIndex ?: null : null +params.dict = params.genome ? params.genomes[params.genome].dict ?: null : null +params.fasta = params.genome && !('annotate' in step) ? params.genomes[params.genome].fasta ?: null : null +params.fastaFai = params.genome ? params.genomes[params.genome].fastaFai ?: null : null +params.germlineResource = params.genome && 'mutect2' in tools ? params.genomes[params.genome].germlineResource ?: null : null +params.germlineResourceIndex = params.genome ? params.genomes[params.genome].germlineResourceIndex ?: null : null +params.intervals = params.genome && !('annotate' in step) ? params.genomes[params.genome].intervals ?: null : null +params.knownIndels = params.genome && 'mapping' in step ? params.genomes[params.genome].knownIndels ?: null : null +params.knownIndelsIndex = params.genome ? params.genomes[params.genome].knownIndelsIndex ?: null : null +params.snpeffDb = params.genome ? params.genomes[params.genome].snpeffDb ?: null : null +params.vepCacheVersion = params.genome ? params.genomes[params.genome].vepCacheVersion ?: null : null + +// Initialize channels based on these params +ch_acLoci = params.acLoci ? Channel.value(file(params.acLoci)) : "null" +ch_acLociGC = params.acLociGC ? Channel.value(file(params.acLociGC)) : "null" +ch_chrDir = params.chrDir ? Channel.value(file(params.chrDir)) : "null" +ch_chrLength = params.chrLength ? Channel.value(file(params.chrLength)) : "null" +ch_dbsnp = params.dbsnp ? Channel.value(file(params.dbsnp)) : "null" +ch_fasta = params.fasta ? Channel.value(file(params.fasta)) : "null" +ch_fastaFai = params.fastaFai ? Channel.value(file(params.fastaFai)) : "null" +ch_germlineResource = params.germlineResource ? Channel.value(file(params.germlineResource)) : "null" +ch_intervals = params.intervals ? Channel.value(file(params.intervals)) : "null" + +// knownIndels is a list of file, so transform it in a channel +li_knownIndels = [] +if (params.knownIndels && ('mapping' in step)) params.knownIndels.each { li_knownIndels.add(file(it)) } +ch_knownIndels = params.knownIndels ? Channel.value(li_knownIndels.collect()) : "null" + +ch_snpEff_cache = params.snpEff_cache ? Channel.value(file(params.snpEff_cache)) : "null" +ch_snpeffDb = params.snpeffDb ? Channel.value(params.snpeffDb) : "null" +ch_vepCacheVersion = params.vepCacheVersion ? Channel.value(params.vepCacheVersion) : "null" +ch_vep_cache = params.vep_cache ? Channel.value(file(params.vep_cache)) : "null" + +// Optionnal files, not defined within the params.genomes[params.genome] scope +ch_cadd_InDels = params.cadd_InDels ? Channel.value(file(params.cadd_InDels)) : "null" +ch_cadd_InDels_tbi = params.cadd_InDels_tbi ? Channel.value(file(params.cadd_InDels_tbi)) : "null" +ch_cadd_WG_SNVs = params.cadd_WG_SNVs ? Channel.value(file(params.cadd_WG_SNVs)) : "null" +ch_cadd_WG_SNVs_tbi = params.cadd_WG_SNVs_tbi ? Channel.value(file(params.cadd_WG_SNVs_tbi)) : "null" +ch_pon = params.pon ? Channel.value(file(params.pon)) : "null" +ch_targetBED = params.targetBED ? Channel.value(file(params.targetBED)) : "null" + +process BuildBWAindexes { + tag {fasta} + + publishDir params.outdir, mode: params.publishDirMode, + saveAs: {params.saveGenomeIndex ? "reference_genome/BWAIndex/${it}" : null } + + input: + file(fasta) from ch_fasta + + output: + file("${fasta}.*") into bwaIndexes + + when: !(params.bwaIndex) && params.fasta && 'mapping' in step + script: + """ + bwa index ${fasta} + """ +} + +process BuildDict { + tag {fasta} + + publishDir params.outdir, mode: params.publishDirMode, + saveAs: {params.saveGenomeIndex ? "reference_genome/${it}" : null } + + input: + file(fasta) from ch_fasta + + output: + file("${fasta.baseName}.dict") into dictBuilt + + when: !(params.dict) && params.fasta && !('annotate' in step) + script: + """ + gatk --java-options "-Xmx${task.memory.toGiga()}g" \ + CreateSequenceDictionary \ + --REFERENCE ${fasta} \ + --OUTPUT ${fasta.baseName}.dict + """ +} + +process BuildFastaFai { + tag {fasta} + + publishDir params.outdir, mode: params.publishDirMode, + saveAs: {params.saveGenomeIndex ? "reference_genome/${it}" : null } + + input: + file(fasta) from ch_fasta + + output: + file("${fasta}.fai") into fastaFaiBuilt + + when: !(params.fastaFai) && params.fasta && !('annotate' in step) + script: + """ + samtools faidx ${fasta} + """ +} + +process BuildDbsnpIndex { + tag {dbsnp} + + publishDir params.outdir, mode: params.publishDirMode, + saveAs: {params.saveGenomeIndex ? "reference_genome/${it}" : null } + + input: + file(dbsnp) from ch_dbsnp + + output: + file("${dbsnp}.tbi") into dbsnpIndexBuilt + + when: !(params.dbsnpIndex) && params.dbsnp && ('mapping' in step || 'controlfreec' in tools || 'haplotypecaller' in tools || 'mutect2' in tools) + script: + """ + tabix -p vcf ${dbsnp} + """ +} + +process BuildGermlineResourceIndex { + tag {germlineResource} + + publishDir params.outdir, mode: params.publishDirMode, + saveAs: {params.saveGenomeIndex ? "reference_genome/${it}" : null } + + input: + file(germlineResource) from ch_germlineResource + + output: + file("${germlineResource}.tbi") into germlineResourceIndexBuilt + + when: !(params.germlineResourceIndex) && params.germlineResource && 'mutect2' in tools + script: + """ + tabix -p vcf ${germlineResource} + """ +} + +process BuildKnownIndelsIndex { + tag {knownIndels} + + publishDir params.outdir, mode: params.publishDirMode, + saveAs: {params.saveGenomeIndex ? "reference_genome/${it}" : null } + + input: + each file(knownIndels) from ch_knownIndels + + output: + file("${knownIndels}.tbi") into knownIndelsIndexBuilt + + when: !(params.knownIndelsIndex) && params.knownIndels && 'mapping' in step + script: + """ + tabix -p vcf ${knownIndels} + """ +} + +// Initialize channels based on params or indexes that were just built +ch_bwaIndex = params.bwaIndex ? Channel.value(file(params.bwaIndex)) : bwaIndexes +ch_dbsnpIndex = params.dbsnpIndex ? Channel.value(file(params.dbsnpIndex)) : dbsnpIndexBuilt +ch_dict = params.dict ? Channel.value(file(params.dict)) : dictBuilt +ch_fastaFai = params.fastaFai ? Channel.value(file(params.fastaFai)) : fastaFaiBuilt +ch_germlineResourceIndex = params.germlineResourceIndex ? Channel.value(file(params.germlineResourceIndex)) : germlineResourceIndexBuilt +ch_knownIndelsIndex = params.knownIndelsIndex ? Channel.value(file(params.knownIndelsIndex)) : knownIndelsIndexBuilt.collect() + +/* +================================================================================ + PRINTING SUMMARY +================================================================================ +*/ + // Header log info log.info nfcoreHeader() def summary = [:] -if (workflow.revision) summary['Pipeline Release'] = workflow.revision -summary['Run Name'] = custom_runName ?: workflow.runName -summary['Max Resources'] = "${params.max_memory} memory, ${params.max_cpus} cpus, ${params.max_time} time per job" -if (workflow.containerEngine) summary['Container'] = "${workflow.containerEngine} - ${workflow.container}" -if (params.input) summary['Input'] = params.input -if (params.targetBED) summary['Target BED'] = params.targetBED -if (params.step) summary['Step'] = params.step -if (params.tools) summary['Tools'] = tools.join(', ') -if (params.skipQC) summary['QC tools skip'] = skipQC.join(', ') -if (params.noGVCF) summary['No GVCF'] = params.noGVCF -if (params.noStrelkaBP) summary['No Strelka BP'] = params.noStrelkaBP -if (params.sequencing_center) summary['Sequenced by '] = params.sequencing_center -if (params.pon) summary['Panel of normals '] = params.pon -summary['Nucleotides/s'] = params.nucleotidesPerSecond -summary['Output dir'] = params.outdir -summary['Launch dir'] = workflow.launchDir -summary['Working dir'] = workflow.workDir -summary['Script dir'] = workflow.projectDir -summary['User'] = workflow.userName +if (workflow.revision) summary['Pipeline Release'] = workflow.revision +summary['Run Name'] = custom_runName ?: workflow.runName +summary['Max Resources'] = "${params.max_memory} memory, ${params.max_cpus} cpus, ${params.max_time} time per job" +if (workflow.containerEngine) summary['Container'] = "${workflow.containerEngine} - ${workflow.container}" +if (params.input) summary['Input'] = params.input +if (params.targetBED) summary['Target BED'] = params.targetBED +if (params.step) summary['Step'] = params.step +if (params.tools) summary['Tools'] = tools.join(', ') +if (params.skipQC) summary['QC tools skip'] = skipQC.join(', ') +if (params.noGVCF) summary['No GVCF'] = params.noGVCF +if (params.noStrelkaBP) summary['No Strelka BP'] = params.noStrelkaBP +if (params.sequencing_center) summary['Sequenced by '] = params.sequencing_center +if (params.pon) summary['Panel of normals '] = params.pon +summary['Save Genome Index'] = params.saveGenomeIndex ? 'Yes' : 'No' +summary['Nucleotides/s'] = params.nucleotidesPerSecond +summary['Output dir'] = params.outdir +summary['Launch dir'] = workflow.launchDir +summary['Working dir'] = workflow.workDir +summary['Script dir'] = workflow.projectDir +summary['User'] = workflow.userName if (workflow.profile == 'awsbatch') { - summary['AWS Region'] = params.awsregion - summary['AWS Queue'] = params.awsqueue + summary['AWS Region'] = params.awsregion + summary['AWS Queue'] = params.awsqueue } summary['Config Profile'] = workflow.profile -if (params.config_profile_description) summary['Config Description'] = params.config_profile_description -if (params.config_profile_contact) summary['Config Contact'] = params.config_profile_contact -if (params.config_profile_url) summary['Config URL'] = params.config_profile_url +if (params.config_profile_description) summary['Config Description'] = params.config_profile_description +if (params.config_profile_contact) summary['Config Contact'] = params.config_profile_contact +if (params.config_profile_url) summary['Config URL'] = params.config_profile_url if (params.email) { - summary['E-mail Address'] = params.email - summary['MultiQC maxsize'] = params.maxMultiqcEmailFileSize + summary['E-mail Address'] = params.email + summary['MultiQC maxsize'] = params.maxMultiqcEmailFileSize } log.info summary.collect { k, v -> "${k.padRight(18)}: $v" }.join("\n") if (params.monochrome_logs) log.info "----------------------------------------------------" @@ -322,7 +513,7 @@ process CreateIntervalBeds { tag {intervals.fileName} input: - file(intervals) from Channel.value(referenceMap.intervals) + file(intervals) from ch_intervals output: file '*.bed' into bedIntervals mode flatten @@ -461,7 +652,8 @@ process MapReads { input: set idPatient, idSample, idRun, file(inputFile1), file(inputFile2) from inputReads - set file(fasta), file(bwaIndex) from Channel.value([referenceMap.fasta, referenceMap.bwaIndex]) + file(bwaIndex) from ch_bwaIndex + file(fasta) from ch_fasta output: set idPatient, idSample, idRun, file("${idRun}.bam") into bamMapped @@ -584,15 +776,13 @@ process BaseRecalibrator { input: set idPatient, idSample, file(bam), file(bai), file(intervalBed) from bamBaseRecalibrator - set file(fasta), file(fastaFai), file(dict), file(dbsnp), file(dbsnpIndex), file(knownIndels), file(knownIndelsIndex) from Channel.value([ - referenceMap.fasta, - referenceMap.fastaFai, - referenceMap.dict, - referenceMap.dbsnp, - referenceMap.dbsnpIndex, - referenceMap.knownIndels, - referenceMap.knownIndelsIndex - ]) + file(dbsnp) from ch_dbsnp + file(dbsnpIndex) from ch_dbsnpIndex + file(dict) from ch_dict + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai + file(knownIndels) from ch_knownIndels + file(knownIndelsIndex) from ch_knownIndelsIndex output: set idPatient, idSample, file("${intervalBed.baseName}_${idSample}.recal.table") into tableGatherBQSRReports @@ -629,11 +819,11 @@ process GatherBQSRReports { publishDir "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked", mode: params.publishDirMode, overwrite: false input: - set idPatient, idSample, file(recal) from tableGatherBQSRReports + set idPatient, idSample, file(recal) from tableGatherBQSRReports output: - set idPatient, idSample, file("${idSample}.recal.table") into recalTable - set idPatient, idSample, val("${idSample}.md.bam"), val("${idSample}.md.bai"), val("${idSample}.recal.table") into (recalTableTSV, recalTableSampleTSV) + set idPatient, idSample, file("${idSample}.recal.table") into recalTable + set idPatient, idSample, val("${idSample}.md.bam"), val("${idSample}.md.bai"), val("${idSample}.recal.table") into (recalTableTSV, recalTableSampleTSV) when: step == 'mapping' @@ -682,11 +872,9 @@ process ApplyBQSR { input: set idPatient, idSample, file(bam), file(bai), file(recalibrationReport), file(intervalBed) from bamApplyBQSR - set file(fasta), file(fastaFai), file(dict)from Channel.value([ - referenceMap.fasta, - referenceMap.fastaFai, - referenceMap.dict - ]) + file(dict) from ch_dict + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai output: set idPatient, idSample, file("${intervalBed.baseName}_${idSample}.recal.bam") into bamMergeBamRecal @@ -757,10 +945,10 @@ process SamtoolsStats { publishDir "${params.outdir}/Reports/${idSample}/SamToolsStats", mode: params.publishDirMode input: - set idPatient, idSample, file(bam), file(bai) from bamRecalSamToolsStats + set idPatient, idSample, file(bam), file(bai) from bamRecalSamToolsStats output: - file ("${bam}.samtools.stats.out") into samtoolsStatsReport + file ("${bam}.samtools.stats.out") into samtoolsStatsReport when: !('samtools' in skipQC) @@ -786,7 +974,7 @@ process BamQC { input: set idPatient, idSample, file(bam) from bamBamQC - file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") + file(targetBED) from ch_targetBED output: file("${bam.baseName}") into bamQCReport @@ -844,13 +1032,11 @@ process HaplotypeCaller { input: set idPatient, idSample, file(bam), file(bai), file(intervalBed) from bamHaplotypeCaller - set file(fasta), file(fastaFai), file(dict), file(dbsnp), file(dbsnpIndex) from Channel.value([ - referenceMap.fasta, - referenceMap.fastaFai, - referenceMap.dict, - referenceMap.dbsnp, - referenceMap.dbsnpIndex - ]) + file(dbsnp) from ch_dbsnp + file(dbsnpIndex) from ch_dbsnpIndex + file(dict) from ch_dict + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai output: set val("HaplotypeCallerGVCF"), idPatient, idSample, file("${intervalBed.baseName}_${idSample}.g.vcf") into gvcfHaplotypeCaller @@ -883,13 +1069,11 @@ process GenotypeGVCFs { input: set idPatient, idSample, file(intervalBed), file(gvcf) from gvcfGenotypeGVCFs - set file(fasta), file(fastaFai), file(dict), file(dbsnp), file(dbsnpIndex) from Channel.value([ - referenceMap.fasta, - referenceMap.fastaFai, - referenceMap.dict, - referenceMap.dbsnp, - referenceMap.dbsnpIndex - ]) + file(dbsnp) from ch_dbsnp + file(dbsnpIndex) from ch_dbsnpIndex + file(dict) from ch_dict + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai output: set val("HaplotypeCaller"), idPatient, idSample, file("${intervalBed.baseName}_${idSample}.vcf") into vcfGenotypeGVCFs @@ -926,11 +1110,9 @@ process StrelkaSingle { input: set idPatient, idSample, file(bam), file(bai) from bamStrelkaSingle - file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") - set file(fasta), file(fastaFai) from Channel.value([ - referenceMap.fasta, - referenceMap.fastaFai - ]) + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai + file(targetBED) from ch_targetBED output: set val("Strelka"), idPatient, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into vcfStrelkaSingle @@ -975,11 +1157,9 @@ process MantaSingle { input: set idPatient, idSample, file(bam), file(bai) from bamMantaSingle - file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") - set file(fasta), file(fastaFai) from Channel.value([ - referenceMap.fasta, - referenceMap.fastaFai - ]) + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai + file(targetBED) from ch_targetBED output: set val("Manta"), idPatient, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into vcfMantaSingle @@ -1034,10 +1214,8 @@ process TIDDIT { input: set idPatient, idSample, file(bam), file(bai) from bamTIDDIT - set file(fasta), file(fastaFai) from Channel.value([ - referenceMap.fasta, - referenceMap.fastaFai - ]) + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai output: set val("TIDDIT"), idPatient, idSample, file("*.vcf.gz"), file("*.tbi") into vcfTIDDIT @@ -1104,10 +1282,8 @@ process FreeBayes { input: set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from pairBamFreeBayes - set file(fasta), file(fastaFai) from Channel.value([ - referenceMap.fasta, - referenceMap.fastaFai - ]) + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai output: set val("FreeBayes"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf") into vcfFreeBayes @@ -1142,14 +1318,13 @@ process Mutect2 { input: set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from pairBamMutect2 - set file(fasta), file(fastaFai), file(dict), file(intervals), file(germlineResource), file(germlineResourceIndex) from Channel.value([ - referenceMap.fasta, - referenceMap.fastaFai, - referenceMap.dict, - referenceMap.intervals, - referenceMap.germlineResource, - referenceMap.germlineResourceIndex - ]) + file(dict) from ch_dict + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai + file(germlineResource) from ch_germlineResource + file(germlineResourceIndex) from ch_germlineResourceIndex + file(intervals) from ch_intervals + file(pon) from ch_pon output: set val("Mutect2"), @@ -1166,7 +1341,7 @@ process Mutect2 { script: // please make a panel-of-normals, using at least 40 samples // https://gatkforums.broadinstitute.org/gatk/discussion/11136/how-to-call-somatic-mutations-using-gatk4-mutect2 - PON = params.pon ? "--panel-of-normals $params.pon" : "" + PON = params.pon ? "--panel-of-normals ${pon}" : "" """ # Get raw calls @@ -1195,22 +1370,14 @@ process MergeMutect2Stats { publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/Mutect2", mode: params.publishDirMode input: - set caller, - idPatient, - idSampleTumor_vs_idSampleNormal, - file(vcfFiles) from mutect2OutForStats // corresponding small VCF chunks - set idPatient, - idSampleTumor, - idSampleNormal, - file(statsFiles) from mutect2Stats // the actual stats files - set file(fasta), file(fastaFai), file(dict), file(intervals), file(germlineResource), file(germlineResourceIndex) from Channel.value([ - referenceMap.fasta, - referenceMap.fastaFai, - referenceMap.dict, - referenceMap.intervals, - referenceMap.germlineResource, - referenceMap.germlineResourceIndex - ]) + set caller, idPatient, idSampleTumor_vs_idSampleNormal, file(vcfFiles) from mutect2OutForStats // corresponding small VCF chunks + set idPatient, idSampleTumor, idSampleNormal, file(statsFiles) from mutect2Stats // the actual stats files + file(dict) from ch_dict + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai + file(germlineResource) from ch_germlineResource + file(germlineResourceIndex) from ch_germlineResourceIndex + file(intervals) from ch_intervals output: file("${idSampleTumor_vs_idSampleNormal}.vcf.gz.stats") into mergedStatsFile @@ -1243,8 +1410,8 @@ process ConcatVCF { input: set variantCaller, idPatient, idSample, file(vcFiles) from vcfConcatenateVCFs - file(fastaFai) from Channel.value(referenceMap.fastaFai) - file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") + file(fastaFai) from ch_fastaFai + file(targetBED) from ch_targetBED output: // we have this funny *_* pattern to avoid copying the raw calls to publishdir @@ -1276,14 +1443,9 @@ process PileupSummariesForMutect2 { input: set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from pairBamPileupSummaries - set file(germlineResource), file(germlineResourceIndex) from Channel.value([ - referenceMap.germlineResource, - referenceMap.germlineResourceIndex - ]) - set idPatient, - idSampleNormal, - idSampleTumor, - file(statsFile) from intervalStatsFiles + set idPatient, idSampleNormal, idSampleTumor, file(statsFile) from intervalStatsFiles + file(germlineResource) from ch_germlineResource + file(germlineResourceIndex) from ch_germlineResourceIndex output: set idPatient, @@ -1314,7 +1476,7 @@ process MergePileupSummaries { input: set idPatient, idSampleTumor, file(pileupSums) from pileupSummaries - file(dict) from Channel.value([referenceMap.dict]) + file(dict) from ch_dict output: file("${idSampleTumor}_pileupsummaries.table.tsv") into mergedPileupFile @@ -1363,26 +1525,18 @@ process FilterMutect2Calls { publishDir "${params.outdir}/VariantCalling/${idSampleTN}/${"$variantCaller"}", mode: params.publishDirMode input: - set variantCaller, - idPatient, - idSampleTN, - file(unfiltered), - file(unfilteredIndex) from vcfConcatenatedForFilter - set file(fasta), file(fastaFai), file(dict), file(intervals), file(germlineResource), file(germlineResourceIndex) from Channel.value([ - referenceMap.fasta, - referenceMap.fastaFai, - referenceMap.dict, - referenceMap.intervals, - referenceMap.germlineResource, - referenceMap.germlineResourceIndex - ]) + set variantCaller, idPatient, idSampleTN, file(unfiltered), file(unfilteredIndex) from vcfConcatenatedForFilter file("${idSampleTN}.vcf.gz.stats") from mergedStatsFile file("${idSampleTN}_contamination.table") from contaminationTable - + file(dict) from ch_dict + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai + file(germlineResource) from ch_germlineResource + file(germlineResourceIndex) from ch_germlineResourceIndex + file(intervals) from ch_intervals + output: - set val("Mutect2"), - idPatient, - idSampleTN, + set val("Mutect2"), idPatient, idSampleTN, file("filtered_${variantCaller}_${idSampleTN}.vcf.gz"), file("filtered_${variantCaller}_${idSampleTN}.vcf.gz.tbi"), file("filtered_${variantCaller}_${idSampleTN}.vcf.gz.filteringStats.tsv") into filteredMutect2Output @@ -1414,12 +1568,10 @@ process Strelka { input: set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor) from pairBamStrelka - file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") - set file(fasta), file(fastaFai), file(dict) from Channel.value([ - referenceMap.fasta, - referenceMap.fastaFai, - referenceMap.dict - ]) + file(dict) from ch_dict + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai + file(targetBED) from ch_targetBED output: set val("Strelka"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into vcfStrelka @@ -1465,11 +1617,9 @@ process Manta { input: set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor) from pairBamManta - file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") - set file(fasta), file(fastaFai) from Channel.value([ - referenceMap.fasta, - referenceMap.fastaFai - ]) + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai + file(targetBED) from ch_targetBED output: set val("Manta"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into vcfManta @@ -1533,12 +1683,10 @@ process StrelkaBP { input: set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(mantaCSI), file(mantaCSIi) from pairBamStrelkaBP - file(targetBED) from Channel.value(params.targetBED ? file(params.targetBED) : "null") - set file(fasta), file(fastaFai), file(dict) from Channel.value([ - referenceMap.fasta, - referenceMap.fastaFai, - referenceMap.dict - ]) + file(dict) from ch_dict + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai + file(targetBED) from ch_targetBED output: set val("Strelka"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into vcfStrelkaBP @@ -1584,12 +1732,10 @@ process AlleleCounter { input: set idPatient, idSample, file(bam), file(bai) from bamAscat - set file(acLoci), file(fasta), file(fastaFai), file(dict) from Channel.value([ - referenceMap.acLoci, - referenceMap.fasta, - referenceMap.fastaFai, - referenceMap.dict - ]) + file(acLoci) from ch_acLoci + file(dict) from ch_dict + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai output: set idPatient, idSample, file("${idSample}.alleleCount") into alleleCounterOut @@ -1659,7 +1805,7 @@ process Ascat { input: set idPatient, idSampleNormal, idSampleTumor, file(bafNormal), file(logrNormal), file(bafTumor), file(logrTumor) from convertAlleleCountsOut - file(acLociGC) from Channel.value([referenceMap.acLociGC]) + file(acLociGC) from ch_acLociGC output: set val("ASCAT"), idPatient, idSampleNormal, idSampleTumor, file("${idSampleTumor}.*.{png,txt}") into ascatOut @@ -1685,10 +1831,8 @@ process Mpileup { input: set idPatient, idSample, file(bam), file(bai), file(intervalBed) from bamMpileup - set file(fasta), file(fastaFai) from Channel.value([ - referenceMap.fasta, - referenceMap.fastaFai - ]) + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai output: set idPatient, idSample, file("${intervalBed.baseName}_${idSample}.pileup.gz") into mpileupMerge @@ -1760,14 +1904,12 @@ process ControlFREEC { input: set idPatient, idSampleNormal, idSampleTumor, file(mpileupNormal), file(mpileupTumor) from mpileupOut - set file(fasta), file(fastaFai), file(dbsnp), file(dbsnpIndex), file(chrDir), file(chrLength) from Channel.value([ - referenceMap.fasta, - referenceMap.fastaFai, - referenceMap.dbsnp, - referenceMap.dbsnpIndex, - referenceMap.chrDir, - referenceMap.chrLength - ]) + file(chrDir) from ch_chrDir + file(chrLength) from ch_chrLength + file(dbsnp) from ch_dbsnp + file(dbsnpIndex) from ch_dbsnpIndex + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai output: set idPatient, idSampleNormal, idSampleTumor, file("${idSampleTumor}.pileup.gz_CNVs"), file("${idSampleTumor}.pileup.gz_ratio.txt"), file("${idSampleTumor}.pileup.gz_normal_CNVs"), file("${idSampleTumor}.pileup.gz_normal_ratio.txt"), file("${idSampleTumor}.pileup.gz_BAF.txt"), file("${idSampleNormal}.pileup.gz_BAF.txt") into controlFreecViz @@ -1782,8 +1924,8 @@ process ControlFREEC { touch ${config} echo "[general]" >> ${config} echo "BedGraphOutput = TRUE" >> ${config} - echo "chrFiles = \${PWD}/${referenceMap.chrDir.fileName}" >> ${config} - echo "chrLenFile = \${PWD}/${referenceMap.chrLength.fileName}" >> ${config} + echo "chrFiles = \${PWD}/${chrDir.fileName}" >> ${config} + echo "chrLenFile = \${PWD}/${chrLength.fileName}" >> ${config} echo "coefficientOfVariation = 0.05" >> ${config} echo "contaminationAdjustment = TRUE" >> ${config} echo "forceGCcontentNormalization = 0" >> ${config} @@ -1807,7 +1949,7 @@ process ControlFREEC { echo "" >> ${config} echo "[BAF]" >> ${config} - echo "SNPfile = ${referenceMap.dbsnp.fileName}" >> ${config} + echo "SNPfile = ${dbsnp.fileName}" >> ${config} freec -conf ${config} """ @@ -1825,10 +1967,10 @@ process ControlFreecViz { publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/controlFREEC", mode: params.publishDirMode input: - set idPatient, idSampleNormal, idSampleTumor, file(cnvTumor), file(ratioTumor), file(cnvNormal), file(ratioNormal), file(bafTumor), file(bafNormal) from controlFreecViz + set idPatient, idSampleNormal, idSampleTumor, file(cnvTumor), file(ratioTumor), file(cnvNormal), file(ratioNormal), file(bafTumor), file(bafNormal) from controlFreecViz output: - set file("*.txt"), file("*.png"), file("*.bed") into controlFreecVizOut + set file("*.txt"), file("*.png"), file("*.bed") into controlFreecVizOut when: 'controlfreec' in tools @@ -2012,8 +2154,8 @@ process Snpeff { input: set variantCaller, idSample, file(vcf) from vcfSnpeff - file dataDir from Channel.value(params.snpEff_cache ? file(params.snpEff_cache) : "null") - val snpeffDb from Channel.value(params.genomes[params.genome].snpeffDb) + file(dataDir) from ch_snpEff_cache + val snpeffDb from ch_snpeffDb output: set file("${reducedVCF}_snpEff.txt"), file("${reducedVCF}_snpEff.html"), file("${reducedVCF}_snpEff.csv") into snpeffReport @@ -2079,14 +2221,12 @@ process VEP { input: set variantCaller, idSample, file(vcf), file(idx) from vcfVep - file dataDir from Channel.value(params.vep_cache ? file(params.vep_cache) : "null") - val cache_version from Channel.value(params.genomes[params.genome].vepCacheVersion) - set file(cadd_WG_SNVs), file(cadd_WG_SNVs_tbi), file(cadd_InDels), file(cadd_InDels_tbi) from Channel.value([ - params.cadd_WG_SNVs ? file(params.cadd_WG_SNVs) : "null", - params.cadd_WG_SNVs_tbi ? file(params.cadd_WG_SNVs_tbi) : "null", - params.cadd_InDels ? file(params.cadd_InDels) : "null", - params.cadd_InDels_tbi ? file(params.cadd_InDels_tbi) : "null" - ]) + file(dataDir) from ch_vep_cache + val cache_version from ch_vepCacheVersion + file(cadd_InDels) from ch_cadd_InDels + file(cadd_InDels_tbi) from ch_cadd_InDels_tbi + file(cadd_WG_SNVs) from ch_cadd_WG_SNVs + file(cadd_WG_SNVs_tbi) from ch_cadd_WG_SNVs_tbi output: set variantCaller, idSample, file("${reducedVCF}_VEP.ann.vcf") into vepVCF @@ -2142,14 +2282,12 @@ process VEPmerge { input: set variantCaller, idSample, file(vcf), file(idx) from compressVCFsnpEffOut - file dataDir from Channel.value(params.vep_cache ? file(params.vep_cache) : "null") - val cache_version from Channel.value(params.genomes[params.genome].vepCacheVersion) - set file(cadd_WG_SNVs), file(cadd_WG_SNVs_tbi), file(cadd_InDels), file(cadd_InDels_tbi) from Channel.value([ - params.cadd_WG_SNVs ? file(params.cadd_WG_SNVs) : "null", - params.cadd_WG_SNVs_tbi ? file(params.cadd_WG_SNVs_tbi) : "null", - params.cadd_InDels ? file(params.cadd_InDels) : "null", - params.cadd_InDels_tbi ? file(params.cadd_InDels_tbi) : "null" - ]) + file(dataDir) from ch_vep_cache + val cache_version from ch_vepCacheVersion + file(cadd_InDels) from ch_cadd_InDels + file(cadd_InDels_tbi) from ch_cadd_InDels_tbi + file(cadd_WG_SNVs) from ch_cadd_WG_SNVs + file(cadd_WG_SNVs_tbi) from ch_cadd_WG_SNVs_tbi output: set variantCaller, idSample, file("${reducedVCF}_VEP.ann.vcf") into vepVCFmerge @@ -2471,70 +2609,6 @@ def checkParamReturnFile(item) { return file(params."${item}") } -// Loop through all the references files to check their existence -def checkRefExistence(referenceFile, fileToCheck) { - if (fileToCheck instanceof List) return fileToCheck.every{ checkRefExistence(referenceFile, it) } - def f = file(fileToCheck) - // this is an expanded wildcard: we can assume all files exist - if (f instanceof List && f.size() > 0) return true - else if (!f.exists()) { - println "Missing references: ${referenceFile} ${fileToCheck}" - return false - } - return true -} - -// Loop through all the references files to check their existence -def checkReferenceMap(referenceMap) { - referenceMap.every { - referenceFile, fileToCheck -> - checkRefExistence(referenceFile, fileToCheck) - } -} - -// Define map of reference depending of tools and step -def defineReferenceMap(step, tools) { - def referenceMap = [ - 'dict' : checkParamReturnFile("dict"), - 'fasta' : checkParamReturnFile("fasta"), - 'fastaFai' : checkParamReturnFile("fastaFai"), - 'intervals' : checkParamReturnFile("intervals") - ] - if ('mapping' in step) { - referenceMap.putAll( - 'bwaIndex' : checkParamReturnFile("bwaIndex"), - 'knownIndels' : checkParamReturnFile("knownIndels"), - 'knownIndelsIndex' : checkParamReturnFile("knownIndelsIndex") - ) - } - if ('controlfreec' in tools) { - referenceMap.putAll( - 'chrDir' : checkParamReturnFile("chrDir"), - 'chrLength' : checkParamReturnFile("chrLength") - ) - } - if ('ascat' in tools) { - referenceMap.putAll( - 'acLoci' : checkParamReturnFile("acLoci"), - 'acLociGC' : checkParamReturnFile("acLociGC") - ) - } - if ('mapping' in step || 'haplotypecaller' in tools || 'mutect2' in tools || 'controlfreec' in tools) { - referenceMap.putAll( - 'dbsnp' : checkParamReturnFile("dbsnp"), - 'dbsnpIndex' : checkParamReturnFile("dbsnpIndex") - ) - } - if('mutect2' in tools ) { - referenceMap.putAll( - 'germlineResource' : checkParamReturnFile("germlineResource"), - 'germlineResourceIndex' : checkParamReturnFile("germlineResourceIndex") - ) - } - if ('annotate' in step) return [] - return referenceMap -} - // Define list of available tools to annotate def defineAnnoList() { return [ diff --git a/scripts/build_reference.sh b/scripts/build_reference.sh deleted file mode 100755 index fb121ea335..0000000000 --- a/scripts/build_reference.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash -set -xeuo pipefail - -# This script build small reference for sarek tests -# https://github.com/nf-core/test-datasets/raw/sarek - -usage() { echo "Usage: $0 <-p profile> <-t test> <-v> <-m memory>" 1>&2; exit 1; } - -MEMORY='6.GB' -NXF_SINGULARITY_CACHEDIR=${NXF_SINGULARITY_CACHEDIR:-work/singularity/.} -OFFLINE='' -PROFILE=docker -TEST=ALL -TRAVIS=${TRAVIS:-false} -TRAVIS_BUILD_DIR=${TRAVIS_BUILD_DIR:-.} -VERBOSE='' - -while [[ $# -gt 0 ]] -do - key=$1 - case $key in - -t|--test) - TEST=$2 - shift # past argument - shift # past value - ;; - -m|--memory) - MEMORY=$2 - shift # past argument - shift # past value - ;; - --offline) - OFFLINE="--offline" - shift # past value - ;; - -p|--profile) - PROFILE=$2 - shift # past argument - shift # past value - ;; - -v|--verbose) - VERBOSE="-ansi-log false -dump-channels" - shift # past value - ;; - *) # unknown option - usage - shift # past argument - ;; - esac -done - -# Build references for smallGRCh37 -if ! [[ ANNOTATEBOTH,ANNOTATESNPEFF,ANNOTATEVEP,LINT =~ $TEST ]] - then - rm -rf references - nextflow run ${TRAVIS_BUILD_DIR}/build.nf -profile test,${PROFILE} --build --outdir references ${VERBOSE} ${OFFLINE} --max_memory ${MEMORY} - rm -rf .nextflow* references/pipeline_info work -fi From 55ffad39972ddb09cf734087db3954b82cfee310 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 13 Sep 2019 16:57:22 +0200 Subject: [PATCH 063/854] revert updates --- environment.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/environment.yml b/environment.yml index 00bf97b2cb..7e6f2d0f81 100644 --- a/environment.yml +++ b/environment.yml @@ -10,19 +10,19 @@ dependencies: - bcftools=1.9 - bwa=0.7.17 - cancerit-allelecount=4.0.2 - - control-freec=11.5 - - ensembl-vep=97.3 + - control-freec=11.4 + - ensembl-vep=95.2 - fastqc=0.11.8 - freebayes=1.3.1 - - gatk4=4.1.3.0 + - gatk4=4.1.2.0 - genesplicer=1.0 - htslib=1.9 - - manta=1.6.0 + - manta=1.5.0 - multiqc=1.7 - - qualimap=2.2.2c + - qualimap=2.2.2b - samtools=1.9 - snpeff=4.3.1t - strelka=2.9.10 - tiddit=2.7.1 - - vcfanno=0.3.2 - - vcftools=0.1.16 + - vcfanno=0.3.1 + - vcftools=0.1.16 \ No newline at end of file From 993068182a540a4567fe15aeca339fadc3df1b6a Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 13 Sep 2019 16:59:27 +0200 Subject: [PATCH 064/854] revert updates --- containers/vep/environment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/containers/vep/environment.yml b/containers/vep/environment.yml index b29c9e6ca1..5fd86c3cdc 100644 --- a/containers/vep/environment.yml +++ b/containers/vep/environment.yml @@ -7,5 +7,5 @@ channels: - defaults dependencies: - - ensembl-vep=97.3 + - ensembl-vep=95.2 - genesplicer=1.0 From ae2f03ef7be112e0e8458d4ca43ec7fa2a4ee2a5 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 13 Sep 2019 17:38:36 +0200 Subject: [PATCH 065/854] update docs --- docs/containers.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/containers.md b/docs/containers.md index 182588c52c..7cb9094b17 100644 --- a/docs/containers.md +++ b/docs/containers.md @@ -18,22 +18,22 @@ For annotation, the main container can be used, but the cache has to be download - Contain **[AlleleCount](https://github.com/cancerit/alleleCount)** 4.0.2 - Contain **[BCFTools](https://github.com/samtools/bcftools)** 1.9 - Contain **[BWA](https://github.com/lh3/bwa)** 0.7.17 -- Contain **[Control-FREEC](https://github.com/BoevaLab/FREEC)** 11.5 +- Contain **[Control-FREEC](https://github.com/BoevaLab/FREEC)** 11.4 - Contain **[FastQC](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/)** 0.11.8 -- Contain **[FreeBayes](https://github.com/ekg/freebayes)** 1.3.1 -- Contain **[GATK4](https://github.com/broadinstitute/gatk)** 4.1.3.0 +- Contain **[FreeBayes](https://github.com/ekg/freebayes)** 1.2.0 +- Contain **[GATK4](https://github.com/broadinstitute/gatk)** 4.1.2.0 - Contain **[GeneSplicer](https://ccb.jhu.edu/software/genesplicer/)** 1.0 - Contain **[HTSlib](https://github.com/samtools/htslib)** 1.9 -- Contain **[Manta](https://github.com/Illumina/manta)** 1.6.0 +- Contain **[Manta](https://github.com/Illumina/manta)** 1.5.0 - Contain **[MultiQC](https://github.com/ewels/MultiQC/)** 1.7 -- Contain **[Qualimap](http://qualimap.bioinfo.cipf.es)** 2.2.2c +- Contain **[Qualimap](http://qualimap.bioinfo.cipf.es)** 2.2.2b - Contain **[samtools](https://github.com/samtools/samtools)** 1.9 - Contain **[snpEff](http://snpeff.sourceforge.net/)** 4.3.1t - Contain **[Strelka2](https://github.com/Illumina/strelka)** 2.9.10 - Contain **[TIDDIT](https://github.com/SciLifeLab/TIDDIT)** 2.7.1 -- Contain **[VCFanno](https://github.com/brentp/vcfanno)** 0.3.2 +- Contain **[VCFanno](https://github.com/brentp/vcfanno)** 0.3.1 - Contain **[VCFtools](https://vcftools.github.io/index.html)** 0.1.16 -- Contain **[VEP](https://github.com/Ensembl/ensembl-vep)** 97.3 +- Contain **[VEP](https://github.com/Ensembl/ensembl-vep)** 95.2 ### sareksnpeff [![sareksnpeff-docker status](https://img.shields.io/docker/automated/nfcore/sareksnpeff.svg)](https://hub.docker.com/r/nfcore/sareksnpeff) @@ -45,7 +45,7 @@ For annotation, the main container can be used, but the cache has to be download - Based on `nfcore/base:latest` - Contain **[GeneSplicer](https://ccb.jhu.edu/software/genesplicer/)** 1.0 -- Contain **[VEP](https://github.com/Ensembl/ensembl-vep)** 97.3 +- Contain **[VEP](https://github.com/Ensembl/ensembl-vep)** 95.2 - Contain cache for `GRCh37`, `GRCh38`, `GRCm38` or `CanFam3.1` ## Using helper script From 2eb4f6e8b07cc0f3c9848d9f84ba341c28a5b6fe Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 13 Sep 2019 17:38:55 +0200 Subject: [PATCH 066/854] add comments to params --- main.nf | 110 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 72 insertions(+), 38 deletions(-) diff --git a/main.nf b/main.nf index 92069bb487..fa5b477287 100644 --- a/main.nf +++ b/main.nf @@ -43,7 +43,8 @@ def helpMessage() { --genome Name of iGenomes reference --noGVCF No g.vcf output from HaplotypeCaller --noStrelkaBP Will not use Manta candidateSmallIndels for Strelka as Best Practice - --nucleotidesPerSecond To estimate interval size by default 1000.0 + --nucleotidesPerSecond To estimate interval size + Default: 1000.0 --targetBED Target BED file for targeted or whole exome sequencing --step Specify starting step Available: Mapping, Recalibrate, VariantCalling, Annotate @@ -102,20 +103,24 @@ def helpMessage() { // Show help message if (params.help) exit 0, helpMessage() -// Handle deprecation +// Default value for params + +// Set deprecated params to null params.noReports = null -if (params.noReports) log.warn "The params `--noReports` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--skipQC" params.annotateVCF = null -if (params.annotateVCF) log.warn "The params `--annotateVCF` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--input" params.genomeDict = null -if (params.genomeDict) log.warn "The params `--genomeDict` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--dict" params.genomeFile = null -if (params.genomeFile) log.warn "The params `--genomeFile` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--fasta" params.genomeIndex = null -if (params.genomeIndex) log.warn "The params `--genomeIndex` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--fastaFai" params.sample = null -if (params.sample) log.warn "The params `--sample` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--input" params.sampleDir = null + +// Print warning message +if (params.noReports) log.warn "The params `--noReports` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--skipQC" +if (params.annotateVCF) log.warn "The params `--annotateVCF` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--input" +if (params.genomeDict) log.warn "The params `--genomeDict` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--dict" +if (params.genomeFile) log.warn "The params `--genomeFile` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--fasta" +if (params.genomeIndex) log.warn "The params `--genomeIndex` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--fastaFai" +if (params.sample) log.warn "The params `--sample` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--input" if (params.sampleDir) log.warn "The params `--sampleDir` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--input" // Check if genome exists in the config file @@ -123,21 +128,71 @@ if (params.genomes && params.genome && !params.genomes.containsKey(params.genome exit 1, "The provided genome '${params.genome}' is not available in the iGenomes file. Currently the available genomes are ${params.genomes.keySet().join(", ")}" } -// Default value for params +// Should be set up in the configs? +// params.email = null +// params.hostnames = null +// params.markdup_java_options = null +// params.max_cpus = null +// params.max_memory = null +// params.maxMultiqcEmailFileSize = null +// params.max_time = null +// params.monochrome_logs = null +// params.name = null +// params.outdir = null +// params.plaintext_email = null +// params.monochrome_logs = null + +// Decide what will happen in sarek +// Which tools to annotate with --step annotate params.annotateTools = null +// No g.vcf produced +params.noGVCF = null +// Strelka will not use Manta candidateSmallIndels +params.noStrelkaBP = null +// Which QC tools not to use +params.skipQC = null +// Which step to begin with +params.step = 'mapping' +// Which tools to use +params.tools = null +// What is the input +params.input = null + +// Use annotation cache params.annotation_cache = null +// Use cadd cache params.cadd_cache = null +// Use genesplicer params.genesplicer = null -params.input = null -params.monochrome_logs = null +// Specify a multiqc config params.multiqc_config = null -params.noGVCF = null -params.noStrelkaBP = null +// Estimate interval size params.nucleotidesPerSecond = 1000.0 +// Specify PublishDirMode +params.publishDirMode = 'copy' +// Enable Saving Indexes +params.saveGenomeIndex = null +// Specify a sequencing center to be writen in BAM header in MapReads process params.sequencing_center = null -params.skipQC = null -params.step = 'mapping' -params.tools = null + +// Initialize each params in params.genomes, catch the command line first if it was defined +params.acLoci = params.genome ? params.genomes[params.genome].acLoci ?: null : null +params.acLociGC = params.genome ? params.genomes[params.genome].acLociGC ?: null : null +params.bwaIndex = params.genome && 'mapping' in step ? params.genomes[params.genome].bwa ?: null : null +params.chrDir = params.genome ? params.genomes[params.genome].chrDir ?: null : null +params.chrLength = params.genome ? params.genomes[params.genome].chrLength ?: null : null +params.dbsnp = params.genome && ('mapping' in step || 'controlfreec' in tools || 'haplotypecaller' in tools || 'mutect2' in tools) ? params.genomes[params.genome].dbsnp ?: null : null +params.dbsnpIndex = params.genome ? params.genomes[params.genome].dbsnpIndex ?: null : null +params.dict = params.genome ? params.genomes[params.genome].dict ?: null : null +params.fasta = params.genome && !('annotate' in step) ? params.genomes[params.genome].fasta ?: null : null +params.fastaFai = params.genome ? params.genomes[params.genome].fastaFai ?: null : null +params.germlineResource = params.genome && 'mutect2' in tools ? params.genomes[params.genome].germlineResource ?: null : null +params.germlineResourceIndex = params.genome ? params.genomes[params.genome].germlineResourceIndex ?: null : null +params.intervals = params.genome && !('annotate' in step) ? params.genomes[params.genome].intervals ?: null : null +params.knownIndels = params.genome && 'mapping' in step ? params.genomes[params.genome].knownIndels ?: null : null +params.knownIndelsIndex = params.genome ? params.genomes[params.genome].knownIndelsIndex ?: null : null +params.snpeffDb = params.genome ? params.genomes[params.genome].snpeffDb ?: null : null +params.vepCacheVersion = params.genome ? params.genomes[params.genome].vepCacheVersion ?: null : null // PON optionnal file for GATK Mutect2 Panel of Normal params.pon = false @@ -241,26 +296,7 @@ if (tsvPath) { ================================================================================ */ -// Initialize params, in case they were not define on the command line -params.acLoci = params.genome ? params.genomes[params.genome].acLoci ?: null : null -params.acLociGC = params.genome ? params.genomes[params.genome].acLociGC ?: null : null -params.bwaIndex = params.genome && 'mapping' in step ? params.genomes[params.genome].bwa ?: null : null -params.chrDir = params.genome ? params.genomes[params.genome].chrDir ?: null : null -params.chrLength = params.genome ? params.genomes[params.genome].chrLength ?: null : null -params.dbsnp = params.genome && ('mapping' in step || 'controlfreec' in tools || 'haplotypecaller' in tools || 'mutect2' in tools) ? params.genomes[params.genome].dbsnp ?: null : null -params.dbsnpIndex = params.genome ? params.genomes[params.genome].dbsnpIndex ?: null : null -params.dict = params.genome ? params.genomes[params.genome].dict ?: null : null -params.fasta = params.genome && !('annotate' in step) ? params.genomes[params.genome].fasta ?: null : null -params.fastaFai = params.genome ? params.genomes[params.genome].fastaFai ?: null : null -params.germlineResource = params.genome && 'mutect2' in tools ? params.genomes[params.genome].germlineResource ?: null : null -params.germlineResourceIndex = params.genome ? params.genomes[params.genome].germlineResourceIndex ?: null : null -params.intervals = params.genome && !('annotate' in step) ? params.genomes[params.genome].intervals ?: null : null -params.knownIndels = params.genome && 'mapping' in step ? params.genomes[params.genome].knownIndels ?: null : null -params.knownIndelsIndex = params.genome ? params.genomes[params.genome].knownIndelsIndex ?: null : null -params.snpeffDb = params.genome ? params.genomes[params.genome].snpeffDb ?: null : null -params.vepCacheVersion = params.genome ? params.genomes[params.genome].vepCacheVersion ?: null : null - -// Initialize channels based on these params +// Initialize channels based on params ch_acLoci = params.acLoci ? Channel.value(file(params.acLoci)) : "null" ch_acLociGC = params.acLociGC ? Channel.value(file(params.acLociGC)) : "null" ch_chrDir = params.chrDir ? Channel.value(file(params.chrDir)) : "null" @@ -2371,8 +2407,6 @@ multiQCReport = Channel.empty() vcftoolsReport ).collect() -Channel.fromPath(params.multiqc_config) - process MultiQC { publishDir "${params.outdir}/Reports/MultiQC", mode: params.publishDirMode From 574790adeeb077b0bfb4edaa51304f31e1b28703 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Sun, 15 Sep 2019 19:53:30 +0200 Subject: [PATCH 067/854] remove Mutect2 from MULTIPLE --- scripts/run_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index 2f852a6655..d79a821913 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -117,7 +117,7 @@ case $TEST in run_sarek --tools HaplotypeCaller --input results/Preprocessing/TSV/recalibrated.tsv --step variantCalling ;; MULTIPLE) - run_sarek ${OPTIONS},snpEff,VEP,merge --input ${PATHTOSAMPLE}/tsv/tiny-multiple${SUFFIX}.tsv + run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,TIDDIT,snpEff,VEP,merge --input ${PATHTOSAMPLE}/tsv/tiny-multiple${SUFFIX}.tsv ;; SOMATIC) run_sarek ${OPTIONS} --input ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv From 9d780dabe9875d7574263e45a737b514b5997b7c Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Sun, 15 Sep 2019 19:53:42 +0200 Subject: [PATCH 068/854] more code polishing --- main.nf | 251 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 137 insertions(+), 114 deletions(-) diff --git a/main.nf b/main.nf index fa5b477287..7fabf2c9e1 100644 --- a/main.nf +++ b/main.nf @@ -158,6 +158,27 @@ params.tools = null // What is the input params.input = null +stepList = defineStepList() +step = params.step ? params.step.toLowerCase() : '' + +// Handle deprecation +if (step == 'preprocessing') step = 'mapping' + +if (step.contains(',')) exit 1, 'You can choose only one step, see --help for more information' +if (!checkParameterExistence(step, stepList)) exit 1, "Unknown step ${step}, see --help for more information" + +toolList = defineToolList() +tools = params.tools ? params.tools.split(',').collect{it.trim().toLowerCase()} : [] +if (!checkParameterList(tools, toolList)) exit 1, 'Unknown tool(s), see --help for more information' + +skipQClist = defineSkipQClist() +skipQC = params.skipQC ? params.skipQC == 'all' ? skipQClist : params.skipQC.split(',').collect{it.trim().toLowerCase()} : [] +if (!checkParameterList(skipQC, skipQClist)) exit 1, 'Unknown QC tool(s), see --help for more information' + +annoList = defineAnnoList() +annotateTools = params.annotateTools ? params.annotateTools.split(',').collect{it.trim().toLowerCase()} : [] +if (!checkParameterList(annotateTools,annoList)) exit 1, 'Unknown tool(s) to annotate, see --help for more information' + // Use annotation cache params.annotation_cache = null // Use cadd cache @@ -210,27 +231,9 @@ params.cadd_WG_SNVs_tbi = false params.snpEff_cache = null params.vep_cache = null -stepList = defineStepList() -step = params.step ? params.step.toLowerCase() : '' -if (step == 'preprocessing') step = 'mapping' -if (step.contains(',')) exit 1, 'You can choose only one step, see --help for more information' -if (!checkParameterExistence(step, stepList)) exit 1, "Unknown step ${step}, see --help for more information" - -toolList = defineToolList() -tools = params.tools ? params.tools.split(',').collect{it.trim().toLowerCase()} : [] -if (!checkParameterList(tools, toolList)) exit 1, 'Unknown tool(s), see --help for more information' - -skipQClist = defineSkipQClist() -skipQC = params.skipQC ? params.skipQC == 'all' ? skipQClist : params.skipQC.split(',').collect{it.trim().toLowerCase()} : [] -if (!checkParameterList(skipQC, skipQClist)) exit 1, 'Unknown QC tool(s), see --help for more information' - // Handle deprecation if (params.noReports) skipQC = skipQClist -annoList = defineAnnoList() -annotateTools = params.annotateTools ? params.annotateTools.split(',').collect{it.trim().toLowerCase()} : [] -if (!checkParameterList(annotateTools,annoList)) exit 1, 'Unknown tool(s) to annotate, see --help for more information' - // Has the run name been specified by the user? // This has the bonus effect of catching both -name and --name custom_runName = params.name @@ -297,15 +300,15 @@ if (tsvPath) { */ // Initialize channels based on params -ch_acLoci = params.acLoci ? Channel.value(file(params.acLoci)) : "null" -ch_acLociGC = params.acLociGC ? Channel.value(file(params.acLociGC)) : "null" -ch_chrDir = params.chrDir ? Channel.value(file(params.chrDir)) : "null" -ch_chrLength = params.chrLength ? Channel.value(file(params.chrLength)) : "null" -ch_dbsnp = params.dbsnp ? Channel.value(file(params.dbsnp)) : "null" -ch_fasta = params.fasta ? Channel.value(file(params.fasta)) : "null" -ch_fastaFai = params.fastaFai ? Channel.value(file(params.fastaFai)) : "null" -ch_germlineResource = params.germlineResource ? Channel.value(file(params.germlineResource)) : "null" -ch_intervals = params.intervals ? Channel.value(file(params.intervals)) : "null" +ch_acLoci = params.acLoci && 'ascat' in tools ? Channel.value(file(params.acLoci)) : "null" +ch_acLociGC = params.acLociGC && 'ascat' in tools ? Channel.value(file(params.acLociGC)) : "null" +ch_chrDir = params.chrDir && 'controlfreec' in tools ? Channel.value(file(params.chrDir)) : "null" +ch_chrLength = params.chrLength && 'controlfreec' in tools ? Channel.value(file(params.chrLength)) : "null" +ch_dbsnp = params.dbsnp && ('mapping' in step || 'controlfreec' in tools || 'haplotypecaller' in tools || 'mutect2' in tools) ? Channel.value(file(params.dbsnp)) : "null" +ch_fasta = params.fasta && !('annotate' in step) ? Channel.value(file(params.fasta)) : "null" +ch_fastaFai = params.fastaFai && !('annotate' in step) ? Channel.value(file(params.fastaFai)) : "null" +ch_germlineResource = params.germlineResource && 'mutect2' in tools ? Channel.value(file(params.germlineResource)) : "null" +ch_intervals = params.intervals && !('annotate' in step) ? Channel.value(file(params.intervals)) : "null" // knownIndels is a list of file, so transform it in a channel li_knownIndels = [] @@ -325,6 +328,113 @@ ch_cadd_WG_SNVs_tbi = params.cadd_WG_SNVs_tbi ? Channel.value(file(params.cadd_W ch_pon = params.pon ? Channel.value(file(params.pon)) : "null" ch_targetBED = params.targetBED ? Channel.value(file(params.targetBED)) : "null" +/* +================================================================================ + PRINTING SUMMARY +================================================================================ +*/ + +// Header log info +log.info nfcoreHeader() +def summary = [:] +if (workflow.revision) summary['Pipeline Release'] = workflow.revision +summary['Run Name'] = custom_runName ?: workflow.runName +summary['Max Resources'] = "${params.max_memory} memory, ${params.max_cpus} cpus, ${params.max_time} time per job" +if (workflow.containerEngine) summary['Container'] = "${workflow.containerEngine} - ${workflow.container}" +if (params.input) summary['Input'] = params.input +if (params.targetBED) summary['Target BED'] = params.targetBED +if (params.step) summary['Step'] = params.step +if (params.tools) summary['Tools'] = tools.join(', ') +if (params.skipQC) summary['QC tools skip'] = skipQC.join(', ') +summary['GVCF'] = params.noGVCF ? 'No' : 'Yes' +summary['Strelka BP'] = params.noStrelkaBP ? 'No' : 'Yes' +if (params.sequencing_center) summary['Sequenced by'] = params.sequencing_center +if (params.pon) summary['Panel of normals'] = params.pon +summary['Save Genome Index'] = params.saveGenomeIndex ? 'Yes' : 'No' +summary['Nucleotides/s'] = params.nucleotidesPerSecond +summary['Output dir'] = params.outdir +summary['Launch dir'] = workflow.launchDir +summary['Working dir'] = workflow.workDir +summary['Script dir'] = workflow.projectDir +summary['User'] = workflow.userName + +if (params.acLoci) summary['acLoci'] = params.acLoci +if (params.acLociGC) summary['acLociGC'] = params.acLociGC +if (params.chrDir) summary['chrDir'] = params.chrDir +if (params.chrLength) summary['chrLength'] = params.chrLength +if (params.dbsnp) summary['dbsnp'] = params.dbsnp +if (params.fasta) summary['fasta'] = params.fasta +if (params.germlineResource) summary['germlineResource'] = params.germlineResource +if (params.intervals) summary['intervals'] = params.intervals +if (params.knownIndels) summary['knownIndels'] = params.knownIndels.join(', ') +if (params.snpeffDb) summary['snpeffDb'] = params.snpeffDb +if (params.vepCacheVersion) summary['vepCacheVersion'] = params.vepCacheVersion + +if (workflow.profile == 'awsbatch') { + summary['AWS Region'] = params.awsregion + summary['AWS Queue'] = params.awsqueue +} +summary['Config Profile'] = workflow.profile +if (params.config_profile_description) summary['Config Description'] = params.config_profile_description +if (params.config_profile_contact) summary['Config Contact'] = params.config_profile_contact +if (params.config_profile_url) summary['Config URL'] = params.config_profile_url +if (params.email) { + summary['E-mail Address'] = params.email + summary['MultiQC maxsize'] = params.maxMultiqcEmailFileSize +} +log.info summary.collect { k, v -> "${k.padRight(18)}: $v" }.join("\n") +if (params.monochrome_logs) log.info "----------------------------------------------------" +else log.info "\033[2m----------------------------------------------------\033[0m" + +// Check the hostnames against configured profiles +checkHostname() + +/* + * Parse software version numbers + */ +process GetSoftwareVersions { + publishDir path:"${params.outdir}/pipeline_info", mode: params.publishDirMode + + output: + file 'software_versions_mqc.yaml' into yamlSoftwareVersion + + when: !('versions' in skipQC) + + script: + """ + alleleCounter --version &> v_allelecount.txt || true + bcftools version > v_bcftools.txt 2>&1 || true + bwa &> v_bwa.txt 2>&1 || true + configManta.py --version > v_manta.txt 2>&1 || true + configureStrelkaGermlineWorkflow.py --version > v_strelka.txt 2>&1 || true + echo "${workflow.manifest.version}" &> v_pipeline.txt 2>&1 || true + echo "${workflow.nextflow.version}" &> v_nextflow.txt 2>&1 || true + echo "SNPEFF version"\$(snpEff -h 2>&1) > v_snpeff.txt + fastqc --version > v_fastqc.txt 2>&1 || true + freebayes --version > v_freebayes.txt 2>&1 || true + gatk ApplyBQSR --help 2>&1 | grep Version: > v_gatk.txt 2>&1 || true + multiqc --version &> v_multiqc.txt 2>&1 || true + qualimap --version &> v_qualimap.txt 2>&1 || true + R --version &> v_r.txt || true + R -e "library(ASCAT); help(package='ASCAT')" &> v_ascat.txt + samtools --version &> v_samtools.txt 2>&1 || true + tiddit &> v_tiddit.txt 2>&1 || true + vcftools --version &> v_vcftools.txt 2>&1 || true + vep --help &> v_vep.txt 2>&1 || true + + scrape_software_versions.py &> software_versions_mqc.yaml + """ +} + +yamlSoftwareVersion = yamlSoftwareVersion.dump(tag:'SOFTWARE VERSIONS') + +/* +================================================================================ + BUILDING INDEXES +================================================================================ +*/ + + process BuildBWAindexes { tag {fasta} @@ -450,93 +560,6 @@ ch_fastaFai = params.fastaFai ? Channel.value(file(params.fastaFai)) : fastaFaiB ch_germlineResourceIndex = params.germlineResourceIndex ? Channel.value(file(params.germlineResourceIndex)) : germlineResourceIndexBuilt ch_knownIndelsIndex = params.knownIndelsIndex ? Channel.value(file(params.knownIndelsIndex)) : knownIndelsIndexBuilt.collect() -/* -================================================================================ - PRINTING SUMMARY -================================================================================ -*/ - -// Header log info -log.info nfcoreHeader() -def summary = [:] -if (workflow.revision) summary['Pipeline Release'] = workflow.revision -summary['Run Name'] = custom_runName ?: workflow.runName -summary['Max Resources'] = "${params.max_memory} memory, ${params.max_cpus} cpus, ${params.max_time} time per job" -if (workflow.containerEngine) summary['Container'] = "${workflow.containerEngine} - ${workflow.container}" -if (params.input) summary['Input'] = params.input -if (params.targetBED) summary['Target BED'] = params.targetBED -if (params.step) summary['Step'] = params.step -if (params.tools) summary['Tools'] = tools.join(', ') -if (params.skipQC) summary['QC tools skip'] = skipQC.join(', ') -if (params.noGVCF) summary['No GVCF'] = params.noGVCF -if (params.noStrelkaBP) summary['No Strelka BP'] = params.noStrelkaBP -if (params.sequencing_center) summary['Sequenced by '] = params.sequencing_center -if (params.pon) summary['Panel of normals '] = params.pon -summary['Save Genome Index'] = params.saveGenomeIndex ? 'Yes' : 'No' -summary['Nucleotides/s'] = params.nucleotidesPerSecond -summary['Output dir'] = params.outdir -summary['Launch dir'] = workflow.launchDir -summary['Working dir'] = workflow.workDir -summary['Script dir'] = workflow.projectDir -summary['User'] = workflow.userName -if (workflow.profile == 'awsbatch') { - summary['AWS Region'] = params.awsregion - summary['AWS Queue'] = params.awsqueue -} -summary['Config Profile'] = workflow.profile -if (params.config_profile_description) summary['Config Description'] = params.config_profile_description -if (params.config_profile_contact) summary['Config Contact'] = params.config_profile_contact -if (params.config_profile_url) summary['Config URL'] = params.config_profile_url -if (params.email) { - summary['E-mail Address'] = params.email - summary['MultiQC maxsize'] = params.maxMultiqcEmailFileSize -} -log.info summary.collect { k, v -> "${k.padRight(18)}: $v" }.join("\n") -if (params.monochrome_logs) log.info "----------------------------------------------------" -else log.info "\033[2m----------------------------------------------------\033[0m" - -// Check the hostnames against configured profiles -checkHostname() - -/* - * Parse software version numbers - */ -process GetSoftwareVersions { - publishDir path:"${params.outdir}/pipeline_info", mode: params.publishDirMode - - output: - file 'software_versions_mqc.yaml' into yamlSoftwareVersion - - when: !('versions' in skipQC) - - script: - """ - alleleCounter --version &> v_allelecount.txt || true - bcftools version > v_bcftools.txt 2>&1 || true - bwa &> v_bwa.txt 2>&1 || true - configManta.py --version > v_manta.txt 2>&1 || true - configureStrelkaGermlineWorkflow.py --version > v_strelka.txt 2>&1 || true - echo "${workflow.manifest.version}" &> v_pipeline.txt 2>&1 || true - echo "${workflow.nextflow.version}" &> v_nextflow.txt 2>&1 || true - echo "SNPEFF version"\$(snpEff -h 2>&1) > v_snpeff.txt - fastqc --version > v_fastqc.txt 2>&1 || true - freebayes --version > v_freebayes.txt 2>&1 || true - gatk ApplyBQSR --help 2>&1 | grep Version: > v_gatk.txt 2>&1 || true - multiqc --version &> v_multiqc.txt 2>&1 || true - qualimap --version &> v_qualimap.txt 2>&1 || true - R --version &> v_r.txt || true - R -e "library(ASCAT); help(package='ASCAT')" &> v_ascat.txt - samtools --version &> v_samtools.txt 2>&1 || true - tiddit &> v_tiddit.txt 2>&1 || true - vcftools --version &> v_vcftools.txt 2>&1 || true - vep --help &> v_vep.txt 2>&1 || true - - scrape_software_versions.py &> software_versions_mqc.yaml - """ -} - -yamlSoftwareVersion = yamlSoftwareVersion.dump(tag:'SOFTWARE VERSIONS') - /* ================================================================================ PREPROCESSING From 6c69699e0b0de4c5a139cb463f105eff305bf87d Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Sun, 15 Sep 2019 19:55:01 +0200 Subject: [PATCH 069/854] update CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2c0d2ca8c..05be2a7b79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -93,7 +93,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#18](https://github.com/nf-core/sarek/pull/18) - Removed params `--noReports` - [#24](https://github.com/nf-core/sarek/pull/18) - Removed GATK3.X MuTect2 - [#31](https://github.com/nf-core/sarek/pull/31) - Remove extra CI from Travis CI and GitHub Actions nf-core CI -- [#32](https://github.com/nf-core/sarek/pull/32), [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Clean up `environment.yml` file +- [#32](https://github.com/nf-core/sarek/pull/32), [#35](https://github.com/nf-core/sarek/pull/35) - Clean up `environment.yml` file ### `Fixed` From 87adf67577301ba8fb210da86ddc4afb2114038e Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 17 Sep 2019 13:00:54 +0200 Subject: [PATCH 070/854] more code polishing --- main.nf | 189 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 101 insertions(+), 88 deletions(-) diff --git a/main.nf b/main.nf index 7fabf2c9e1..95cc6d3759 100644 --- a/main.nf +++ b/main.nf @@ -310,7 +310,7 @@ ch_fastaFai = params.fastaFai && !('annotate' in step) ? Channel.value(file(para ch_germlineResource = params.germlineResource && 'mutect2' in tools ? Channel.value(file(params.germlineResource)) : "null" ch_intervals = params.intervals && !('annotate' in step) ? Channel.value(file(params.intervals)) : "null" -// knownIndels is a list of file, so transform it in a channel +// knownIndels is currently a list of file, so transform it in a channel li_knownIndels = [] if (params.knownIndels && ('mapping' in step)) params.knownIndels.each { li_knownIndels.add(file(it)) } ch_knownIndels = params.knownIndels ? Channel.value(li_knownIndels.collect()) : "null" @@ -434,7 +434,6 @@ yamlSoftwareVersion = yamlSoftwareVersion.dump(tag:'SOFTWARE VERSIONS') ================================================================================ */ - process BuildBWAindexes { tag {fasta} @@ -448,6 +447,7 @@ process BuildBWAindexes { file("${fasta}.*") into bwaIndexes when: !(params.bwaIndex) && params.fasta && 'mapping' in step + script: """ bwa index ${fasta} @@ -467,6 +467,7 @@ process BuildDict { file("${fasta.baseName}.dict") into dictBuilt when: !(params.dict) && params.fasta && !('annotate' in step) + script: """ gatk --java-options "-Xmx${task.memory.toGiga()}g" \ @@ -489,6 +490,7 @@ process BuildFastaFai { file("${fasta}.fai") into fastaFaiBuilt when: !(params.fastaFai) && params.fasta && !('annotate' in step) + script: """ samtools faidx ${fasta} @@ -527,6 +529,7 @@ process BuildGermlineResourceIndex { file("${germlineResource}.tbi") into germlineResourceIndexBuilt when: !(params.germlineResourceIndex) && params.germlineResource && 'mutect2' in tools + script: """ tabix -p vcf ${germlineResource} @@ -546,6 +549,7 @@ process BuildKnownIndelsIndex { file("${knownIndels}.tbi") into knownIndelsIndexBuilt when: !(params.knownIndelsIndex) && params.knownIndels && 'mapping' in step + script: """ tabix -p vcf ${knownIndels} @@ -669,8 +673,7 @@ process FastQCFQ { file "*_fastqc.{zip,html}" into fastQCFQReport when: step == 'mapping' && !('fastqc' in skipQC) - - + script: """ fastqc -t 2 -q ${idRun}_R1.fastq.gz ${idRun}_R2.fastq.gz @@ -850,7 +853,7 @@ process BaseRecalibrator { script: known = knownIndels.collect{"--known-sites ${it}"}.join(' ') - // --use-original-qualities ??? + // TODO: --use-original-qualities ??? """ gatk --java-options -Xmx${task.memory.toGiga()}g \ BaseRecalibrator \ @@ -965,8 +968,8 @@ process MergeBamRecal { set idPatient, idSample, file(bam) from bamMergeBamRecal output: - set idPatient, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bai") into (bamRecal, bamRecalSamToolsStats) - set idPatient, idSample, file("${idSample}.recal.bam") into bamRecalBamQC + set idPatient, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bai") into bamRecal + set idPatient, idSample, file("${idSample}.recal.bam") into (bamRecalBamQC, bamRecalSamToolsStats) set idPatient, idSample, val("${idSample}.recal.bam"), val("${idSample}.recal.bai") into (bamRecalTSV, bamRecalSampleTSV) script: @@ -1004,7 +1007,7 @@ process SamtoolsStats { publishDir "${params.outdir}/Reports/${idSample}/SamToolsStats", mode: params.publishDirMode input: - set idPatient, idSample, file(bam), file(bai) from bamRecalSamToolsStats + set idPatient, idSample, file(bam) from bamRecalSamToolsStats output: file ("${bam}.samtools.stats.out") into samtoolsStatsReport @@ -1019,8 +1022,6 @@ process SamtoolsStats { samtoolsStatsReport = samtoolsStatsReport.dump(tag:'SAMTools') -// QC - bamBamQC = bamMappedBamQC.mix(bamRecalBamQC) process BamQC { @@ -1072,7 +1073,7 @@ bamRecal = bamRecal.dump(tag:'BAM') // Here we have a recalibrated bam set // The TSV file is formatted like: "idPatient status idSample bamFile baiFile" // Manta will be run in Germline mode, or in Tumor mode depending on status -// HaplotypeCaller and Strelka will be run for Normal and Tumor samples +// HaplotypeCaller, TIDDIT and Strelka will be run for Normal and Tumor samples (bamMantaSingle, bamStrelkaSingle, bamTIDDIT, bamRecalAll, bamRecalAllTemp) = bamRecal.into(5) @@ -1369,7 +1370,7 @@ process FreeBayes { vcfFreeBayes = vcfFreeBayes.groupTuple(by:[0,1,2]) -// STEP GATK MUTECT2 +// STEP GATK MUTECT2.1 - RAW CALLS process Mutect2 { tag {idSampleTumor + "_vs_" + idSampleNormal + "-" + intervalBed.baseName} @@ -1401,10 +1402,8 @@ process Mutect2 { // please make a panel-of-normals, using at least 40 samples // https://gatkforums.broadinstitute.org/gatk/discussion/11136/how-to-call-somatic-mutations-using-gatk4-mutect2 PON = params.pon ? "--panel-of-normals ${pon}" : "" - """ # Get raw calls - # this case we are getting raw calls only for the intervals, we also have to concatenate them gatk --java-options "-Xmx${task.memory.toGiga()}g" \ Mutect2 \ -R ${fasta}\ @@ -1420,9 +1419,11 @@ process Mutect2 { mutect2Output = mutect2Output.groupTuple(by:[0,1,2]) (mutect2Output, mutect2OutForStats) = mutect2Output.into(2) -(mutect2Stats,intervalStatsFiles) = mutect2Stats.into(2) +(mutect2Stats, intervalStatsFiles) = mutect2Stats.into(2) mutect2Stats = mutect2Stats.groupTuple(by:[0,1,2]) +// STEP GATK MUTECT2.2 - MERGING STATS + process MergeMutect2Stats { tag {idSampleTumor + "_vs_" + idSampleNormal} @@ -1446,16 +1447,17 @@ process MergeMutect2Stats { script: stats = statsFiles.collect{ "-stats ${it} " }.join(' ') """ - gatk --java-options "-Xmx${task.memory.toGiga()}g" \ - MergeMutectStats \ - ${stats} \ - -O ${idSampleTumor}_vs_${idSampleNormal}.vcf.gz.stats + gatk --java-options "-Xmx${task.memory.toGiga()}g" \ + MergeMutectStats \ + ${stats} \ + -O ${idSampleTumor}_vs_${idSampleNormal}.vcf.gz.stats """ } // we are merging the VCFs that are called separatelly for different intervals // so we can have a single sorted VCF containing all the calls for a given caller -// STEP MERGING VCF - FREEBAYES, GATK HAPLOTYPECALLER & GATK MUTECT2 (unfiltered) + +// STEP MERGING VCF - FREEBAYES, GATK HAPLOTYPECALLER & GATK MUTECT2 (UNFILTERED) vcfConcatenateVCFs = mutect2Output.mix( vcfFreeBayes, vcfGenotypeGVCFs, gvcfHaplotypeCaller) vcfConcatenateVCFs = vcfConcatenateVCFs.dump(tag:'VCF to merge') @@ -1494,7 +1496,7 @@ process ConcatVCF { (vcfConcatenated, vcfConcatenatedForFilter) = vcfConcatenated.into(2) vcfConcatenated = vcfConcatenated.dump(tag:'VCF') -// STEP GATK MUTECT2 +// STEP GATK MUTECT2.3 - GENERATING PILEUP SUMMARIES process PileupSummariesForMutect2 { tag {idSampleTumor + "_vs_" + idSampleNormal + "_" + intervalBed.baseName } @@ -1515,22 +1517,24 @@ process PileupSummariesForMutect2 { script: """ - # pileup summaries - gatk --java-options "-Xmx${task.memory.toGiga()}g" \ - GetPileupSummaries \ - -I ${bamTumor} \ - -V ${germlineResource} \ - -L ${intervalBed} \ - -O ${intervalBed.baseName}_${idSampleTumor}_pileupsummaries.table + gatk --java-options "-Xmx${task.memory.toGiga()}g" \ + GetPileupSummaries \ + -I ${bamTumor} \ + -V ${germlineResource} \ + -L ${intervalBed} \ + -O ${intervalBed.baseName}_${idSampleTumor}_pileupsummaries.table """ } pileupSummaries = pileupSummaries.groupTuple(by:[0,1]) +// STEP GATK MUTECT2.4 - MERGING PILEUP SUMMARIES + process MergePileupSummaries { - tag {idPatient + "_" + idSampleTumor} label 'cpus_1' + tag {idPatient + "_" + idSampleTumor} + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}/Mutect2", mode: params.publishDirMode input: @@ -1544,18 +1548,21 @@ process MergePileupSummaries { script: allPileups = pileupSums.collect{ "-I ${it} " }.join(' ') """ - gatk --java-options "-Xmx${task.memory.toGiga()}g" \ - GatherPileupSummaries \ - --sequence-dictionary ${dict} \ - ${allPileups} \ - -O ${idSampleTumor}_pileupsummaries.table.tsv + gatk --java-options "-Xmx${task.memory.toGiga()}g" \ + GatherPileupSummaries \ + --sequence-dictionary ${dict} \ + ${allPileups} \ + -O ${idSampleTumor}_pileupsummaries.table.tsv """ } +// STEP GATK MUTECT2.5 - CALCULATING CONTAMINATION + process CalculateContamination { - tag {idSampleTumor + "_vs_" + idSampleNormal} label 'cpus_1' + tag {idSampleTumor + "_vs_" + idSampleNormal} + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}/Mutect2", mode: params.publishDirMode input: @@ -1569,18 +1576,21 @@ process CalculateContamination { script: """ - # calculate contamination - gatk --java-options "-Xmx${task.memory.toGiga()}g" \ - CalculateContamination \ - -I ${idSampleTumor}_pileupsummaries.table \ - -O ${idSampleTumor}_contamination.table + # calculate contamination + gatk --java-options "-Xmx${task.memory.toGiga()}g" \ + CalculateContamination \ + -I ${idSampleTumor}_pileupsummaries.table \ + -O ${idSampleTumor}_contamination.table """ } +// STEP GATK MUTECT2.6 - FILTERING CALLS + process FilterMutect2Calls { - tag {idSampleTN} label 'cpus_1' + tag {idSampleTN} + publishDir "${params.outdir}/VariantCalling/${idSampleTN}/${"$variantCaller"}", mode: params.publishDirMode input: @@ -1604,10 +1614,10 @@ process FilterMutect2Calls { script: """ - # do the actual filtering - gatk --java-options "-Xmx${task.memory.toGiga()}g" \ + # do the actual filtering + gatk --java-options "-Xmx${task.memory.toGiga()}g" \ FilterMutectCalls \ - -V $unfiltered \ + -V ${unfiltered} \ --contamination-table ${idSampleTN}_contamination.table \ --stats ${idSampleTN}.vcf.gz.stats \ -R ${fasta} \ @@ -2165,7 +2175,7 @@ if (step == 'annotate') { if (tsvPath == []) { // Sarek, by default, annotates all available vcfs that it can find in the VariantCalling directory // Excluding vcfs from FreeBayes, and g.vcf from HaplotypeCaller - // Basically it's: VariantCalling/*/{HaplotypeCaller,Manta,Mutect2,Strelka}/*.vcf.gz + // Basically it's: VariantCalling/*/{HaplotypeCaller,Manta,Mutect2,Strelka,TIDDIT}/*.vcf.gz // Without *SmallIndels.vcf.gz from Manta, and *.genome.vcf.gz from Strelka // The small snippet `vcf.minus(vcf.fileName)[-2]` catches idSample // This field is used to output final annotated VCFs in the correct directory @@ -2178,6 +2188,8 @@ if (step == 'annotate') { .flatten().map{vcf -> ['mutect2', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, Channel.fromPath("${params.outdir}/VariantCalling/*/Strelka/*{somatic,variant}*.vcf.gz") .flatten().map{vcf -> ['strelka', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, + Channel.fromPath("${params.outdir}/VariantCalling/*/TIDDIT/*.vcf.gz") + .flatten().map{vcf -> ['TIDDIT', vcf.minus(vcf.fileName)[-2].toString(), vcf]} ).choice(vcfToAnnotate, vcfNoAnnotate) { annotateTools == [] || (annotateTools != [] && it[0] in annotateTools) ? 0 : 1 } @@ -2227,14 +2239,14 @@ process Snpeff { cache = (params.snpEff_cache && params.annotation_cache) ? "-dataDir \${PWD}/${dataDir}" : "" """ snpEff -Xmx${task.memory.toGiga()}g \ - ${snpeffDb} \ - -csvStats ${reducedVCF}_snpEff.csv \ - -nodownload \ - ${cache} \ - -canon \ - -v \ - ${vcf} \ - > ${reducedVCF}_snpEff.ann.vcf + ${snpeffDb} \ + -csvStats ${reducedVCF}_snpEff.csv \ + -nodownload \ + ${cache} \ + -canon \ + -v \ + ${vcf} \ + > ${reducedVCF}_snpEff.ann.vcf mv snpEff_summary.html ${reducedVCF}_snpEff.html mv ${reducedVCF}_snpEff.genes.txt ${reducedVCF}_snpEff.txt @@ -2243,7 +2255,7 @@ process Snpeff { snpeffReport = snpeffReport.dump(tag:'snpEff report') -// STEP COMPRESS AND INDEX VCF.1 - snpEff +// STEP COMPRESS AND INDEX VCF.1 - SNPEFF process CompressVCFsnpEff { tag {"${idSample} - ${vcf}"} @@ -2303,22 +2315,22 @@ process VEP { mkdir ${reducedVCF} vep \ - -i ${vcf} \ - -o ${reducedVCF}_VEP.ann.vcf \ - --assembly ${genome} \ - ${cadd} \ - ${genesplicer} \ - --cache \ - --cache_version ${cache_version} \ - --dir_cache ${dir_cache} \ - --everything \ - --filter_common \ - --fork ${task.cpus} \ - --format vcf \ - --per_gene \ - --stats_file ${reducedVCF}_VEP.summary.html \ - --total_length \ - --vcf + -i ${vcf} \ + -o ${reducedVCF}_VEP.ann.vcf \ + --assembly ${genome} \ + ${cadd} \ + ${genesplicer} \ + --cache \ + --cache_version ${cache_version} \ + --dir_cache ${dir_cache} \ + --everything \ + --filter_common \ + --fork ${task.cpus} \ + --format vcf \ + --per_gene \ + --stats_file ${reducedVCF}_VEP.summary.html \ + --total_length \ + --vcf rm -rf ${reducedVCF} """ @@ -2326,7 +2338,7 @@ process VEP { vepReport = vepReport.dump(tag:'VEP') -// STEP VEP.2 - VEP after snpEff +// STEP VEP.2 - VEP AFTER SNPEFF process VEPmerge { label 'VEP' @@ -2364,22 +2376,22 @@ process VEPmerge { mkdir ${reducedVCF} vep \ - -i ${vcf} \ - -o ${reducedVCF}_VEP.ann.vcf \ - --assembly ${genome} \ - ${cadd} \ - ${genesplicer} \ - --cache \ - --cache_version ${cache_version} \ - --dir_cache ${dir_cache} \ - --everything \ - --filter_common \ - --fork ${task.cpus} \ - --format vcf \ - --per_gene \ - --stats_file ${reducedVCF}_VEP.summary.html \ - --total_length \ - --vcf + -i ${vcf} \ + -o ${reducedVCF}_VEP.ann.vcf \ + --assembly ${genome} \ + ${cadd} \ + ${genesplicer} \ + --cache \ + --cache_version ${cache_version} \ + --dir_cache ${dir_cache} \ + --everything \ + --filter_common \ + --fork ${task.cpus} \ + --format vcf \ + --per_gene \ + --stats_file ${reducedVCF}_VEP.summary.html \ + --total_length \ + --vcf rm -rf ${reducedVCF} """ @@ -2672,7 +2684,8 @@ def defineAnnoList() { 'HaplotypeCaller', 'Manta', 'Mutect2', - 'Strelka' + 'Strelka', + 'TIDDIT' ] } From 2fb0422ce454c16bb82dec70efaf403e6bbe8c6b Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 17 Sep 2019 16:04:56 +0200 Subject: [PATCH 071/854] code polish --- main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.nf b/main.nf index 95cc6d3759..c9fdcb87ee 100644 --- a/main.nf +++ b/main.nf @@ -128,7 +128,7 @@ if (params.genomes && params.genome && !params.genomes.containsKey(params.genome exit 1, "The provided genome '${params.genome}' is not available in the iGenomes file. Currently the available genomes are ${params.genomes.keySet().join(", ")}" } -// Should be set up in the configs? +// TODO: Should be set up? // params.email = null // params.hostnames = null // params.markdup_java_options = null From 1db0b94aeef0eab63c5af0bd2a67671097e17370 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 17 Sep 2019 16:05:08 +0200 Subject: [PATCH 072/854] revert changes --- environment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/environment.yml b/environment.yml index 7e6f2d0f81..683facbebb 100644 --- a/environment.yml +++ b/environment.yml @@ -13,7 +13,7 @@ dependencies: - control-freec=11.4 - ensembl-vep=95.2 - fastqc=0.11.8 - - freebayes=1.3.1 + - freebayes=1.2.0 - gatk4=4.1.2.0 - genesplicer=1.0 - htslib=1.9 From 97f2cb815970a18ee890252c75a73c2f227a5d94 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 17 Sep 2019 16:05:21 +0200 Subject: [PATCH 073/854] update CHANGELOG --- CHANGELOG.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05be2a7b79..ca2d3eb1fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#27](https://github.com/nf-core/sarek/pull/27), [#30](https://github.com/nf-core/sarek/pull/30) - Use Github actions for CI, linting and branch protection - [#31](https://github.com/nf-core/sarek/pull/31) - Add nf-core lint - [#31](https://github.com/nf-core/sarek/pull/31) - Add extra CI to GitHub Actions nf-core extra CI +- [#35](https://github.com/nf-core/sarek/pull/35) - Building indexes from [nf-core/test-datasets:sarek](https://github.com/nf-core/test-datasets/tree/sarek) for CI and small tests ### `Changed` @@ -55,7 +56,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#7](https://github.com/nf-core/sarek/pull/7), [#23](https://github.com/nf-core/sarek/pull/23) - `--sampleDir` is now deprecated, use `--input` instead - [#7](https://github.com/nf-core/sarek/pull/8), [#23](https://github.com/nf-core/sarek/pull/23) - `--annotateVCF` is now deprecated, use `--input` instead - [#8](https://github.com/nf-core/sarek/pull/8), [#12](https://github.com/nf-core/sarek/pull/12) - Improve helper script `build.nf` for downloading and building reference files -- [#9](https://github.com/nf-core/sarek/pull/9) - ApplyBQSR is now parallelized +- [#9](https://github.com/nf-core/sarek/pull/9) - `ApplyBQSR` is now parallelized - [#9](https://github.com/nf-core/sarek/pull/9) - Fastq files are named following "${idRun}_R1.fastq.gz" in the FastQC output for easier reporting - [#9](https://github.com/nf-core/sarek/pull/9) - Status is now a map with `idpatient`, `idsample` as keys (ie: `status = statusMap[idPatient, idSample]`) - [#9](https://github.com/nf-core/sarek/pull/9) - Use `ensembl-vep` `95.2` instead of `96.0` @@ -84,6 +85,11 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#31](https://github.com/nf-core/sarek/pull/31) - Move extra CI to GitHub Actions nf-core extra CI - [#32](https://github.com/nf-core/sarek/pull/32), [#33](https://github.com/nf-core/sarek/pull/33) - Install `ASCAT` with `conda` in the `environment.yml` file - [#33](https://github.com/nf-core/sarek/pull/33) - use `workflow.manifest.version` to specify workflow version in path to scripts for `ControlFREEC` and `VEP` processes +- [#35](https://github.com/nf-core/sarek/pull/35) - Building indexes is now done in `main.nf` +- [#35](https://github.com/nf-core/sarek/pull/35) - `build.nf` script now only download cache, so renamed to `downloadcache.nf` +- [#35](https://github.com/nf-core/sarek/pull/35) - Use `tabix` instead of `IGVtools` to build vcf indexes +- [#35](https://github.com/nf-core/sarek/pull/35) - Refactor references handling +- [#35](https://github.com/nf-core/sarek/pull/35) - use Channel values instead of `referenceMap` ### `Removed` @@ -94,6 +100,11 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#24](https://github.com/nf-core/sarek/pull/18) - Removed GATK3.X MuTect2 - [#31](https://github.com/nf-core/sarek/pull/31) - Remove extra CI from Travis CI and GitHub Actions nf-core CI - [#32](https://github.com/nf-core/sarek/pull/32), [#35](https://github.com/nf-core/sarek/pull/35) - Clean up `environment.yml` file +- [#35](https://github.com/nf-core/sarek/pull/35) - Remove building indexes from `build.nf` script +- [#35](https://github.com/nf-core/sarek/pull/35) - Remove helper script `build_reference.sh` +- [#35](https://github.com/nf-core/sarek/pull/35) - Remove `IGVtools` +- [#35](https://github.com/nf-core/sarek/pull/35) - Remove `Mutect2` from `MULTIPLE` test +- [#35](https://github.com/nf-core/sarek/pull/35) - Remove `referenceMap` and `defineReferenceMap()` and use Channel values instead ### `Fixed` From 938aac27bf3a046087e3f7a63225eb4853331dbf Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Tue, 17 Sep 2019 17:09:03 +0200 Subject: [PATCH 074/854] Update conf/test.config --- conf/test.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/test.config b/conf/test.config index d3d4ad0073..36aa57d4f8 100644 --- a/conf/test.config +++ b/conf/test.config @@ -20,7 +20,7 @@ params { // To be build with: `nextflow run build.nf --build -profile docker --outdir references` igenomesIgnore = true genome = 'smallGRCh37' - genomes_base = "https://github.com/MaxUlysse/nf-core_test-datasets/raw/sarek/reference" + genomes_base = "https://github.com/nf-core/test-datasets/raw/sarek/reference" // Use publishDir mode link so that work can be removed publishDirMode = 'link' From 04fa5b447d6c4acb57bdf1b812e7e598d716b496 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 18 Sep 2019 11:34:59 +0200 Subject: [PATCH 075/854] move params definition from main.nf to conf/base.config --- conf/base.config | 43 ++++++++++++++++++++++++++-- conf/test.config | 3 +- main.nf | 74 ------------------------------------------------ 3 files changed, 41 insertions(+), 79 deletions(-) diff --git a/conf/base.config b/conf/base.config index 1d7ff02e52..2eec883d18 100644 --- a/conf/base.config +++ b/conf/base.config @@ -11,13 +11,50 @@ params { // Defaults only, expecting to be overwritten - cpus = 8 + annotateTools = null // Only with --step annotate + annotateVCF = null // Deprecated params + annotation_cache = null // Annotation cache disabled + cadd_InDels = false // No CADD files + cadd_InDels_tbi = false // No CADD files + cadd_WG_SNVs = false // No CADD files + cadd_WG_SNVs_tbi = false // No CADD files + cadd_cache = null // CADD cache disabled + cpus = 8 // Base specifications + email = null // No default email + genesplicer = null // genesplicer disabled + genomeDict = null // Deprecated params + genomeFile = null // Deprecated params + genomeIndex = null // Deprecated params + hostnames = null // No default hostnames igenomes_base = 's3://ngi-igenomes/igenomes/' + input = null // No default input markdup_java_options = '"-Xms4000m -Xmx7g"' //Established values for markDuplicate memory consumption, see issue PR #689 for details + maxMultiqcEmailFileSize = null // No default max MultiQC email size max_cpus = 16 // Base specifications max_memory = 128.GB // Base specifications max_time = 240.h // Base specifications + monochrome_logs = null // Monochrome logs disabled + multiqc_config = "assets/multiqc_config" // Default multiqc config + name = null // No default name + noGVCF = null // g.vcf are produced by HaplotypeCaller + noReports = null // Deprecated params + noStrelkaBP = null // Strelka will use Manta candidateSmallIndels if available + nucleotidesPerSecond = 1000.0 // Default interval size + outdir = null // No default output dir + plaintext_email = null // Plaintext email disabled + pon = false // No default PON file for GATK Mutect2 Panel of Normal + publishDirMode = 'copy' // Default PublishDirMode (same as Nextflow) + sample = null // Deprecated params + sampleDir = null // Deprecated params + saveGenomeIndex = null // Built Indexes not saved + sequencing_center = null // No sequencing center to be writen in BAM header in MapReads process singleCPUMem = 7.GB // for processes that are using more memory but a single CPU only. Use the 'core' queue for these + skipQC = null // All QC tools are used + snpEff_cache = null // No directory for snpEff cache + step = 'mapping' // Starts with mapping + targetBED = false // No default TargetBED file for targeted sequencing + tools = null // No default Variant Calling or Annotation tools + vep_cache = null // No directory for VEP cache } process { @@ -46,7 +83,7 @@ process { cpus = {check_resource(16)} } withLabel:cpus_max { - cpus = {params.max_cpus} + cpus = {check_resource(params.max_cpus)} } withLabel:memory_singleCPU_2_task { @@ -72,7 +109,7 @@ process { errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} } withName:MapReads { - memory = {check_resource(check_resource(60.GB * task.attempt))} + memory = {check_resource(60.GB * task.attempt)} } withName:MultiQC { errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} diff --git a/conf/test.config b/conf/test.config index 36aa57d4f8..9c32937aca 100644 --- a/conf/test.config +++ b/conf/test.config @@ -10,14 +10,13 @@ params { config_profile_description = 'Minimal test dataset to check pipeline function' config_profile_name = 'Test profile' - // Limit resources so that this can run on Travis + // Limit resources so that this can run on GitHub Actions max_cpus = 2 max_memory = 6.GB max_time = 48.h // Input data input = 'https://github.com/nf-core/test-datasets/raw/sarek/testdata/tsv/tiny-manta-https.tsv' // Small reference genome - // To be build with: `nextflow run build.nf --build -profile docker --outdir references` igenomesIgnore = true genome = 'smallGRCh37' genomes_base = "https://github.com/nf-core/test-datasets/raw/sarek/reference" diff --git a/main.nf b/main.nf index c9fdcb87ee..0bdcf8a21a 100644 --- a/main.nf +++ b/main.nf @@ -103,17 +103,6 @@ def helpMessage() { // Show help message if (params.help) exit 0, helpMessage() -// Default value for params - -// Set deprecated params to null -params.noReports = null -params.annotateVCF = null -params.genomeDict = null -params.genomeFile = null -params.genomeIndex = null -params.sample = null -params.sampleDir = null - // Print warning message if (params.noReports) log.warn "The params `--noReports` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--skipQC" if (params.annotateVCF) log.warn "The params `--annotateVCF` is deprecated -- it will be removed in a future release.\n\tPlease check: https://github.com/nf-core/sarek/blob/master/docs/usage.md#--input" @@ -128,36 +117,6 @@ if (params.genomes && params.genome && !params.genomes.containsKey(params.genome exit 1, "The provided genome '${params.genome}' is not available in the iGenomes file. Currently the available genomes are ${params.genomes.keySet().join(", ")}" } -// TODO: Should be set up? -// params.email = null -// params.hostnames = null -// params.markdup_java_options = null -// params.max_cpus = null -// params.max_memory = null -// params.maxMultiqcEmailFileSize = null -// params.max_time = null -// params.monochrome_logs = null -// params.name = null -// params.outdir = null -// params.plaintext_email = null -// params.monochrome_logs = null - -// Decide what will happen in sarek -// Which tools to annotate with --step annotate -params.annotateTools = null -// No g.vcf produced -params.noGVCF = null -// Strelka will not use Manta candidateSmallIndels -params.noStrelkaBP = null -// Which QC tools not to use -params.skipQC = null -// Which step to begin with -params.step = 'mapping' -// Which tools to use -params.tools = null -// What is the input -params.input = null - stepList = defineStepList() step = params.step ? params.step.toLowerCase() : '' @@ -179,23 +138,6 @@ annoList = defineAnnoList() annotateTools = params.annotateTools ? params.annotateTools.split(',').collect{it.trim().toLowerCase()} : [] if (!checkParameterList(annotateTools,annoList)) exit 1, 'Unknown tool(s) to annotate, see --help for more information' -// Use annotation cache -params.annotation_cache = null -// Use cadd cache -params.cadd_cache = null -// Use genesplicer -params.genesplicer = null -// Specify a multiqc config -params.multiqc_config = null -// Estimate interval size -params.nucleotidesPerSecond = 1000.0 -// Specify PublishDirMode -params.publishDirMode = 'copy' -// Enable Saving Indexes -params.saveGenomeIndex = null -// Specify a sequencing center to be writen in BAM header in MapReads process -params.sequencing_center = null - // Initialize each params in params.genomes, catch the command line first if it was defined params.acLoci = params.genome ? params.genomes[params.genome].acLoci ?: null : null params.acLociGC = params.genome ? params.genomes[params.genome].acLociGC ?: null : null @@ -215,22 +157,6 @@ params.knownIndelsIndex = params.genome ? params.genomes[params.genome].knownInd params.snpeffDb = params.genome ? params.genomes[params.genome].snpeffDb ?: null : null params.vepCacheVersion = params.genome ? params.genomes[params.genome].vepCacheVersion ?: null : null -// PON optionnal file for GATK Mutect2 Panel of Normal -params.pon = false - -// TargetBED optionnal file for targeted sequencing -params.targetBED = false - -// Optionnal CADD files -params.cadd_InDels = false -params.cadd_InDels_tbi = false -params.cadd_WG_SNVs = false -params.cadd_WG_SNVs_tbi = false - -// Optionnal directories for cache -params.snpEff_cache = null -params.vep_cache = null - // Handle deprecation if (params.noReports) skipQC = skipQClist From 2dd6802b3956c00d84730c078270f7186b7beb83 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 18 Sep 2019 11:40:51 +0200 Subject: [PATCH 076/854] default params.outdir is results --- conf/base.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/base.config b/conf/base.config index 2eec883d18..da5ad3c394 100644 --- a/conf/base.config +++ b/conf/base.config @@ -40,7 +40,7 @@ params { noReports = null // Deprecated params noStrelkaBP = null // Strelka will use Manta candidateSmallIndels if available nucleotidesPerSecond = 1000.0 // Default interval size - outdir = null // No default output dir + outdir = 'results' // Default output dir is `results` plaintext_email = null // Plaintext email disabled pon = false // No default PON file for GATK Mutect2 Panel of Normal publishDirMode = 'copy' // Default PublishDirMode (same as Nextflow) From 968e80dd6077c3f77d4d84fcd928923b1daa40ce Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 18 Sep 2019 11:41:29 +0200 Subject: [PATCH 077/854] update docs --- docs/usage.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/usage.md b/docs/usage.md index 8b89e98f5e..5d497d27db 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -554,6 +554,7 @@ Please make sure to also set the `-w/--work-dir` and `--outdir` parameters to a ### `--outdir` The output directory where the results will be saved. +Default: `results/ ### `--sequencing_center` From 89dae9c1078d065e1768c357a5181bc75744b3c9 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 18 Sep 2019 12:11:03 +0200 Subject: [PATCH 078/854] move all params from conf/base.config to nextflow.config --- conf/base.config | 48 -------------------------------- nextflow.config | 72 ++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 57 insertions(+), 63 deletions(-) diff --git a/conf/base.config b/conf/base.config index da5ad3c394..b524b7c16e 100644 --- a/conf/base.config +++ b/conf/base.config @@ -9,54 +9,6 @@ * run on the logged in environment. */ -params { - // Defaults only, expecting to be overwritten - annotateTools = null // Only with --step annotate - annotateVCF = null // Deprecated params - annotation_cache = null // Annotation cache disabled - cadd_InDels = false // No CADD files - cadd_InDels_tbi = false // No CADD files - cadd_WG_SNVs = false // No CADD files - cadd_WG_SNVs_tbi = false // No CADD files - cadd_cache = null // CADD cache disabled - cpus = 8 // Base specifications - email = null // No default email - genesplicer = null // genesplicer disabled - genomeDict = null // Deprecated params - genomeFile = null // Deprecated params - genomeIndex = null // Deprecated params - hostnames = null // No default hostnames - igenomes_base = 's3://ngi-igenomes/igenomes/' - input = null // No default input - markdup_java_options = '"-Xms4000m -Xmx7g"' //Established values for markDuplicate memory consumption, see issue PR #689 for details - maxMultiqcEmailFileSize = null // No default max MultiQC email size - max_cpus = 16 // Base specifications - max_memory = 128.GB // Base specifications - max_time = 240.h // Base specifications - monochrome_logs = null // Monochrome logs disabled - multiqc_config = "assets/multiqc_config" // Default multiqc config - name = null // No default name - noGVCF = null // g.vcf are produced by HaplotypeCaller - noReports = null // Deprecated params - noStrelkaBP = null // Strelka will use Manta candidateSmallIndels if available - nucleotidesPerSecond = 1000.0 // Default interval size - outdir = 'results' // Default output dir is `results` - plaintext_email = null // Plaintext email disabled - pon = false // No default PON file for GATK Mutect2 Panel of Normal - publishDirMode = 'copy' // Default PublishDirMode (same as Nextflow) - sample = null // Deprecated params - sampleDir = null // Deprecated params - saveGenomeIndex = null // Built Indexes not saved - sequencing_center = null // No sequencing center to be writen in BAM header in MapReads process - singleCPUMem = 7.GB // for processes that are using more memory but a single CPU only. Use the 'core' queue for these - skipQC = null // All QC tools are used - snpEff_cache = null // No directory for snpEff cache - step = 'mapping' // Starts with mapping - targetBED = false // No default TargetBED file for targeted sequencing - tools = null // No default Variant Calling or Annotation tools - vep_cache = null // No directory for VEP cache -} - process { cpus = {check_resource(params.cpus * task.attempt)} memory = {check_resource((params.singleCPUMem as nextflow.util.MemoryUnit) * task.attempt)} diff --git a/nextflow.config b/nextflow.config index ec1ca9b05c..b31fea9538 100644 --- a/nextflow.config +++ b/nextflow.config @@ -9,29 +9,71 @@ params { // Workflow flags + annotateTools = null // Only with --step annotate genome = 'GRCh38' + input = null // No default input + noGVCF = null // g.vcf are produced by HaplotypeCaller + noStrelkaBP = null // Strelka will use Manta candidateSmallIndels if available + skipQC = null // All QC tools are used + step = 'mapping' // Starts with mapping + tools = null // No default Variant Calling or Annotation tools + + // Workflow settings + annotation_cache = null // Annotation cache disabled + cadd_cache = null // CADD cache disabled + genesplicer = null // genesplicer disabled + markdup_java_options = '"-Xms4000m -Xmx7g"' //Established values for markDuplicate memory consumption, see issue PR #689 for details + nucleotidesPerSecond = 1000.0 // Default interval size outdir = './results' - publishDirMode = 'symlink' + publishDirMode = 'symlink' // Default PublishDirMode (same as Nextflow) + saveGenomeIndex = null // Built Indexes not saved + sequencing_center = null // No sequencing center to be writen in BAM header in MapReads process + + // Optional files/directory + cadd_InDels = false // No CADD files + cadd_InDels_tbi = false // No CADD files + cadd_WG_SNVs = false // No CADD files + cadd_WG_SNVs_tbi = false // No CADD files + pon = false // No default PON file for GATK Mutect2 Panel of Normal + snpEff_cache = null // No directory for snpEff cache + targetBED = false // No default TargetBED file for targeted sequencing + vep_cache = null // No directory for VEP cache // Boilerplate options - name = false - multiqc_config = "${baseDir}/assets/multiqc_config.yaml" - email = false - maxMultiqcEmailFileSize = 25.MB - plaintext_email = false - monochrome_logs = false - help = false - igenomes_base = "./iGenomes" - tracedir = "${params.outdir}/pipeline_info" awsqueue = false awsregion = 'eu-west-1' - igenomesIgnore = false - custom_config_version = 'master' - custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" - hostnames = false - config_profile_description = false config_profile_contact = false + config_profile_description = false config_profile_url = false + custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" + custom_config_version = 'master' + email = false // No default email + help = false + hostnames = false + igenomesIgnore = false + igenomes_base = 's3://ngi-igenomes/igenomes/' + maxMultiqcEmailFileSize = 25.MB + monochrome_logs = false // Monochrome logs disabled + multiqc_config = "${baseDir}/assets/multiqc_config.yaml" // Default multiqc config + name = false // No default name + plaintext_email = false // Plaintext email disabled + tracedir = "${params.outdir}/pipeline_info" + + // Base specifications + cpus = 8 + max_cpus = 16 + max_memory = 128.GB + max_time = 240.h + singleCPUMem = 7.GB + + // Deprecated params + annotateVCF = null + genomeDict = null + genomeFile = null + genomeIndex = null + noReports = null + sample = null + sampleDir = null } // Container slug. Stable releases should specify release tag! From 511e1e89fb9c9a9447b31aa0f63ba20f16557465 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 18 Sep 2019 12:30:22 +0200 Subject: [PATCH 079/854] enhanced config --- main.nf | 28 +++++++++++++++------------- nextflow.config | 22 +++++++++++++++------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/main.nf b/main.nf index 0bdcf8a21a..9a7b6e8124 100644 --- a/main.nf +++ b/main.nf @@ -139,23 +139,25 @@ annotateTools = params.annotateTools ? params.annotateTools.split(',').collect{i if (!checkParameterList(annotateTools,annoList)) exit 1, 'Unknown tool(s) to annotate, see --help for more information' // Initialize each params in params.genomes, catch the command line first if it was defined -params.acLoci = params.genome ? params.genomes[params.genome].acLoci ?: null : null -params.acLociGC = params.genome ? params.genomes[params.genome].acLociGC ?: null : null -params.bwaIndex = params.genome && 'mapping' in step ? params.genomes[params.genome].bwa ?: null : null -params.chrDir = params.genome ? params.genomes[params.genome].chrDir ?: null : null -params.chrLength = params.genome ? params.genomes[params.genome].chrLength ?: null : null -params.dbsnp = params.genome && ('mapping' in step || 'controlfreec' in tools || 'haplotypecaller' in tools || 'mutect2' in tools) ? params.genomes[params.genome].dbsnp ?: null : null -params.dbsnpIndex = params.genome ? params.genomes[params.genome].dbsnpIndex ?: null : null -params.dict = params.genome ? params.genomes[params.genome].dict ?: null : null +// params.fasta has to be the first one params.fasta = params.genome && !('annotate' in step) ? params.genomes[params.genome].fasta ?: null : null -params.fastaFai = params.genome ? params.genomes[params.genome].fastaFai ?: null : null +// The rest can be sorted +params.acLoci = params.genome && 'ascat' in tools ? params.genomes[params.genome].acLoci ?: null : null +params.acLociGC = params.genome && 'ascat' in tools ? params.genomes[params.genome].acLociGC ?: null : null +params.bwaIndex = params.genome && params.fasta && 'mapping' in step ? params.genomes[params.genome].bwa ?: null : null +params.chrDir = params.genome && 'controlfreec' in tools ? params.genomes[params.genome].chrDir ?: null : null +params.chrLength = params.genome && 'controlfreec' in tools ? params.genomes[params.genome].chrLength ?: null : null +params.dbsnp = params.genome && ('mapping' in step || 'controlfreec' in tools || 'haplotypecaller' in tools || 'mutect2' in tools) ? params.genomes[params.genome].dbsnp ?: null : null +params.dbsnpIndex = params.genome && params.dbsnp ? params.genomes[params.genome].dbsnpIndex ?: null : null +params.dict = params.genome && params.fasta ? params.genomes[params.genome].dict ?: null : null +params.fastaFai = params.genome && params.fasta ? params.genomes[params.genome].fastaFai ?: null : null params.germlineResource = params.genome && 'mutect2' in tools ? params.genomes[params.genome].germlineResource ?: null : null -params.germlineResourceIndex = params.genome ? params.genomes[params.genome].germlineResourceIndex ?: null : null +params.germlineResourceIndex = params.genome && params.germlineResource ? params.genomes[params.genome].germlineResourceIndex ?: null : null params.intervals = params.genome && !('annotate' in step) ? params.genomes[params.genome].intervals ?: null : null params.knownIndels = params.genome && 'mapping' in step ? params.genomes[params.genome].knownIndels ?: null : null -params.knownIndelsIndex = params.genome ? params.genomes[params.genome].knownIndelsIndex ?: null : null -params.snpeffDb = params.genome ? params.genomes[params.genome].snpeffDb ?: null : null -params.vepCacheVersion = params.genome ? params.genomes[params.genome].vepCacheVersion ?: null : null +params.knownIndelsIndex = params.genome && params.knownIndels ? params.genomes[params.genome].knownIndelsIndex ?: null : null +params.snpeffDb = params.genome && 'snpeff' in tools ? params.genomes[params.genome].snpeffDb ?: null : null +params.vepCacheVersion = params.genome && 'vep' in tools ? params.genomes[params.genome].vepCacheVersion ?: null : null // Handle deprecation if (params.noReports) skipQC = skipQClist diff --git a/nextflow.config b/nextflow.config index b31fea9538..942f1be597 100644 --- a/nextflow.config +++ b/nextflow.config @@ -39,26 +39,34 @@ params { targetBED = false // No default TargetBED file for targeted sequencing vep_cache = null // No directory for VEP cache - // Boilerplate options + // AWSBatch awsqueue = false awsregion = 'eu-west-1' + + // Custom config config_profile_contact = false config_profile_description = false config_profile_url = false - custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" custom_config_version = 'master' - email = false // No default email - help = false - hostnames = false + custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" + + // Reference genomes igenomesIgnore = false igenomes_base = 's3://ngi-igenomes/igenomes/' - maxMultiqcEmailFileSize = 25.MB + + // Default + help = false + hostnames = false monochrome_logs = false // Monochrome logs disabled multiqc_config = "${baseDir}/assets/multiqc_config.yaml" // Default multiqc config name = false // No default name - plaintext_email = false // Plaintext email disabled tracedir = "${params.outdir}/pipeline_info" + // email + email = false // No default email + maxMultiqcEmailFileSize = 25.MB + plaintext_email = false // Plaintext email disabled + // Base specifications cpus = 8 max_cpus = 16 From 1cbdc307fd01a891d163369b3805b26fe1c2c4f8 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 18 Sep 2019 12:36:20 +0200 Subject: [PATCH 080/854] better logs --- main.nf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/main.nf b/main.nf index 9a7b6e8124..e073856a3f 100644 --- a/main.nf +++ b/main.nf @@ -274,10 +274,10 @@ if (params.targetBED) summary['Target BED'] = params.targetBED if (params.step) summary['Step'] = params.step if (params.tools) summary['Tools'] = tools.join(', ') if (params.skipQC) summary['QC tools skip'] = skipQC.join(', ') -summary['GVCF'] = params.noGVCF ? 'No' : 'Yes' -summary['Strelka BP'] = params.noStrelkaBP ? 'No' : 'Yes' -if (params.sequencing_center) summary['Sequenced by'] = params.sequencing_center -if (params.pon) summary['Panel of normals'] = params.pon +if ('haplotypecaller' in tools) summary['GVCF'] = params.noGVCF ? 'No' : 'Yes' +if ('strelka' in tools && 'manta' in tools ) summary['Strelka BP'] = params.noStrelkaBP ? 'No' : 'Yes' +if (params.sequencing_center) summary['Sequenced by'] = params.sequencing_center +if (params.pon && 'mutect2' in tools) summary['Panel of normals'] = params.pon summary['Save Genome Index'] = params.saveGenomeIndex ? 'Yes' : 'No' summary['Nucleotides/s'] = params.nucleotidesPerSecond summary['Output dir'] = params.outdir From 8610d7ecc09ad8b3068ffa5791ef9f82602dcea7 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 18 Sep 2019 12:37:41 +0200 Subject: [PATCH 081/854] code polishing --- main.nf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/main.nf b/main.nf index e073856a3f..bb6c2ba1bf 100644 --- a/main.nf +++ b/main.nf @@ -274,10 +274,12 @@ if (params.targetBED) summary['Target BED'] = params.targetBED if (params.step) summary['Step'] = params.step if (params.tools) summary['Tools'] = tools.join(', ') if (params.skipQC) summary['QC tools skip'] = skipQC.join(', ') -if ('haplotypecaller' in tools) summary['GVCF'] = params.noGVCF ? 'No' : 'Yes' + +if ('haplotypecaller' in tools) summary['GVCF'] = params.noGVCF ? 'No' : 'Yes' if ('strelka' in tools && 'manta' in tools ) summary['Strelka BP'] = params.noStrelkaBP ? 'No' : 'Yes' if (params.sequencing_center) summary['Sequenced by'] = params.sequencing_center if (params.pon && 'mutect2' in tools) summary['Panel of normals'] = params.pon + summary['Save Genome Index'] = params.saveGenomeIndex ? 'Yes' : 'No' summary['Nucleotides/s'] = params.nucleotidesPerSecond summary['Output dir'] = params.outdir From e04fdc3f03b88a0f29ad64687f63c8c596c4a728 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 18 Sep 2019 13:16:02 +0200 Subject: [PATCH 082/854] add comments --- main.nf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.nf b/main.nf index bb6c2ba1bf..0a7678aed7 100644 --- a/main.nf +++ b/main.nf @@ -269,6 +269,8 @@ if (workflow.revision) summary['Pipeline Release'] = workflow.revisi summary['Run Name'] = custom_runName ?: workflow.runName summary['Max Resources'] = "${params.max_memory} memory, ${params.max_cpus} cpus, ${params.max_time} time per job" if (workflow.containerEngine) summary['Container'] = "${workflow.containerEngine} - ${workflow.container}" +// TODO: if annotation print containers used for annotation +// Could be nfcore/sarek:dev or nfcore/sareksnpeff:dev.${params.genome}/nfcore/sarekvep:dev.${params.genome} if (params.input) summary['Input'] = params.input if (params.targetBED) summary['Target BED'] = params.targetBED if (params.step) summary['Step'] = params.step From 497e8e2c0b65267edc0c6063f206b4277e9d8702 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 18 Sep 2019 15:17:32 +0200 Subject: [PATCH 083/854] remove comments --- main.nf | 2 -- 1 file changed, 2 deletions(-) diff --git a/main.nf b/main.nf index 0a7678aed7..bb6c2ba1bf 100644 --- a/main.nf +++ b/main.nf @@ -269,8 +269,6 @@ if (workflow.revision) summary['Pipeline Release'] = workflow.revisi summary['Run Name'] = custom_runName ?: workflow.runName summary['Max Resources'] = "${params.max_memory} memory, ${params.max_cpus} cpus, ${params.max_time} time per job" if (workflow.containerEngine) summary['Container'] = "${workflow.containerEngine} - ${workflow.container}" -// TODO: if annotation print containers used for annotation -// Could be nfcore/sarek:dev or nfcore/sareksnpeff:dev.${params.genome}/nfcore/sarekvep:dev.${params.genome} if (params.input) summary['Input'] = params.input if (params.targetBED) summary['Target BED'] = params.targetBED if (params.step) summary['Step'] = params.step From 0b13966ae9cdde77f99bdafaccfdef6165dbe13e Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 18 Sep 2019 15:47:56 +0200 Subject: [PATCH 084/854] no need to use check_resource for cpus_max or memory_max --- conf/base.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/base.config b/conf/base.config index b524b7c16e..3b137eda52 100644 --- a/conf/base.config +++ b/conf/base.config @@ -35,7 +35,7 @@ process { cpus = {check_resource(16)} } withLabel:cpus_max { - cpus = {check_resource(params.max_cpus)} + cpus = {params.max_cpus} } withLabel:memory_singleCPU_2_task { @@ -46,7 +46,7 @@ process { } withLabel:memory_max { - memory = {check_resource(params.max_memory)} + memory = {params.max_memory} } withName:ConcatVCF { From 945bd3a28f69998f0c1db89cbc5d59b84e633a45 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 18 Sep 2019 17:18:28 +0200 Subject: [PATCH 085/854] fix markdownlint --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2bec860d9e..e6e67df597 100644 --- a/README.md +++ b/README.md @@ -106,4 +106,4 @@ If you use nf-core/sarek for your analysis, please cite the `Sarek` pre-print as You can cite the sarek zenodo record for a specific version using the following [doi: 10.5281/zenodo.2582812](https://doi.org/10.5281/zenodo.2582812) You can cite the `nf-core` pre-print as follows: -> Ewels PA, Peltzer A, Fillinger S, Alneberg JA, Patel H, Wilm A, Garcia MU, Di Tommaso P, Nahnsen S. **nf-core: Community curated bioinformatics pipelines**. *bioRxiv*. 2019. p. 610741. [doi: 10.1101/610741](https://www.biorxiv.org/content/10.1101/610741v3). \ No newline at end of file +> Ewels PA, Peltzer A, Fillinger S, Alneberg JA, Patel H, Wilm A, Garcia MU, Di Tommaso P, Nahnsen S. **nf-core: Community curated bioinformatics pipelines**. *bioRxiv*. 2019. p. 610741. [doi: 10.1101/610741](https://www.biorxiv.org/content/10.1101/610741v3). From e64c3a4d03935b3fee3334187a3314eb61fdf525 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Thu, 19 Sep 2019 08:59:25 +0200 Subject: [PATCH 086/854] default PublishDirMode is now copy --- nextflow.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextflow.config b/nextflow.config index 942f1be597..dd50b76c25 100644 --- a/nextflow.config +++ b/nextflow.config @@ -25,7 +25,7 @@ params { markdup_java_options = '"-Xms4000m -Xmx7g"' //Established values for markDuplicate memory consumption, see issue PR #689 for details nucleotidesPerSecond = 1000.0 // Default interval size outdir = './results' - publishDirMode = 'symlink' // Default PublishDirMode (same as Nextflow) + publishDirMode = 'copy' // Default PublishDirMode (same as other nf-core pipelines) saveGenomeIndex = null // Built Indexes not saved sequencing_center = null // No sequencing center to be writen in BAM header in MapReads process From 24e460155d57bedcbdd0382cdf750f30303af365 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Fri, 20 Sep 2019 10:34:05 +0200 Subject: [PATCH 087/854] Prepare release (#37) * nf-core bump-version . 2.5 * add --skipQC all to ANNOTATE test * update usage of download_image script * update CHANGELOG --- .circleci/config.yml | 8 ++++---- .github/workflows/ci-extra.yml | 2 +- .github/workflows/ci.yml | 2 +- .travis.yml | 2 +- CHANGELOG.md | 3 ++- Dockerfile | 2 +- Jenkinsfile | 2 +- containers/snpeff/Dockerfile | 2 +- containers/snpeff/environment.yml | 2 +- containers/vep/Dockerfile | 2 +- containers/vep/environment.yml | 2 +- environment.yml | 2 +- nextflow.config | 4 ++-- scripts/download_image.sh | 16 +++++++++++----- scripts/run_tests.sh | 2 +- 15 files changed, 30 insertions(+), 23 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0af952fcb0..1ede7ab8fe 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,11 +10,11 @@ jobs: - checkout - setup_remote_docker - run: - command: docker build -t nfcore/sareksnpeff:dev.${GENOME} containers/snpeff/. --build-arg GENOME=${GENOME} --build-arg SNPEFF_CACHE_VERSION=${SNPEFF_CACHE_VERSION} + command: docker build -t nfcore/sareksnpeff:2.5.${GENOME} containers/snpeff/. --build-arg GENOME=${GENOME} --build-arg SNPEFF_CACHE_VERSION=${SNPEFF_CACHE_VERSION} - run: command: | echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin - docker push nfcore/sareksnpeff:dev.${GENOME} + docker push nfcore/sareksnpeff:2.5.${GENOME} snpeffgrch38: << : *buildsnpeff @@ -45,10 +45,10 @@ jobs: - checkout - setup_remote_docker - run: - command: docker build -t nfcore/sarekvep:dev.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} + command: docker build -t nfcore/sarekvep:2.5.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} no_output_timeout: 3h - run: - command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:dev.${GENOME} + command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:2.5.${GENOME} vepgrch38: << : *buildvep diff --git a/.github/workflows/ci-extra.yml b/.github/workflows/ci-extra.yml index cfd23ca890..90543c7958 100644 --- a/.github/workflows/ci-extra.yml +++ b/.github/workflows/ci-extra.yml @@ -18,7 +18,7 @@ jobs: sudo mv nextflow /usr/local/bin/ - name: Download image run: | - ${GITHUB_WORKSPACE}/scripts/download_image.sh -n docker --test ${{ matrix.test }} + ${GITHUB_WORKSPACE}/scripts/download_image.sh -n docker --source-version dev --target-version 2.5 --test ${{ matrix.test }} - name: Run test run: | ${GITHUB_WORKSPACE}/scripts/run_tests.sh --test ${{ matrix.test }} --verbose \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 22c1031208..785fb9269c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: - name: Download and tag image run: | docker pull nfcore/sarek:dev - docker tag nfcore/sarek:dev nfcore/sarek:dev + docker tag nfcore/sarek:dev nfcore/sarek:2.5 - name: Run test run: | nextflow run ${GITHUB_WORKSPACE} -profile test,docker \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index e2d4b23d67..f34465aad6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ before_install: - docker pull nfcore/sarek:dev # Fake the tag locally so that the pipeline runs properly # Looks weird when this is :dev to :dev, but makes sense when testing code for a release (:dev to :1.0.1) - - docker tag nfcore/sarek:dev nfcore/sarek:dev + - docker tag nfcore/sarek:dev nfcore/sarek:2.5 install: # Install Nextflow diff --git a/CHANGELOG.md b/CHANGELOG.md index ca2d3eb1fb..8adbcab63a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## Unreleased +## [2.5] - Ålkatj Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) template. @@ -90,6 +90,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#35](https://github.com/nf-core/sarek/pull/35) - Use `tabix` instead of `IGVtools` to build vcf indexes - [#35](https://github.com/nf-core/sarek/pull/35) - Refactor references handling - [#35](https://github.com/nf-core/sarek/pull/35) - use Channel values instead of `referenceMap` +- [#37](https://github.com/nf-core/sarek/pull/37) - Bump version for Release ### `Removed` diff --git a/Dockerfile b/Dockerfile index e818c19845..33abcf89b7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,4 +4,4 @@ LABEL authors="Maxime Garcia, Szilveszter Juhos" \ COPY environment.yml / RUN conda env create -f /environment.yml && conda clean -a -ENV PATH /opt/conda/envs/nf-core-sarek-2.5dev/bin:$PATH +ENV PATH /opt/conda/envs/nf-core-sarek-2.5/bin:$PATH diff --git a/Jenkinsfile b/Jenkinsfile index a48cedb877..924e454f0d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -8,7 +8,7 @@ pipeline { stages { stage('Docker setup') { steps { - sh "./scripts/download_image.sh -n docker -t ALL -T dev -g smallGRCh37" + sh "./scripts/download_image.sh -n docker -t ALL --source-version dev --target-version 2.5 -g smallGRCh37" } } stage('Germline') { diff --git a/containers/snpeff/Dockerfile b/containers/snpeff/Dockerfile index 08b47c22b7..07ccb28152 100644 --- a/containers/snpeff/Dockerfile +++ b/containers/snpeff/Dockerfile @@ -7,7 +7,7 @@ LABEL \ COPY environment.yml / RUN conda env create -f /environment.yml && conda clean -a -ENV PATH /opt/conda/envs/sarek-snpeff-2.5dev/bin:$PATH +ENV PATH /opt/conda/envs/sarek-snpeff-2.5/bin:$PATH # Setup default ARG variables ARG GENOME=GRCh38 diff --git a/containers/snpeff/environment.yml b/containers/snpeff/environment.yml index 5e48bdb781..fd93bd1815 100644 --- a/containers/snpeff/environment.yml +++ b/containers/snpeff/environment.yml @@ -1,6 +1,6 @@ # You can use this file to create a conda environment for this pipeline: # conda env create -f environment.yml -name: sarek-snpeff-2.5dev +name: sarek-snpeff-2.5 channels: - conda-forge - bioconda diff --git a/containers/vep/Dockerfile b/containers/vep/Dockerfile index 06c12a7bb8..7969b5d1e7 100644 --- a/containers/vep/Dockerfile +++ b/containers/vep/Dockerfile @@ -7,7 +7,7 @@ LABEL \ COPY environment.yml / RUN conda env create -f /environment.yml && conda clean -a -ENV PATH /opt/conda/envs/sarek-vep-2.5dev/bin:$PATH +ENV PATH /opt/conda/envs/sarek-vep-2.5/bin:$PATH # Setup default ARG variables ARG GENOME=GRCh38 diff --git a/containers/vep/environment.yml b/containers/vep/environment.yml index 5fd86c3cdc..b5c73474a6 100644 --- a/containers/vep/environment.yml +++ b/containers/vep/environment.yml @@ -1,6 +1,6 @@ # You can use this file to create a conda environment for this pipeline: # conda env create -f environment.yml -name: sarek-vep-2.5dev +name: sarek-vep-2.5 channels: - conda-forge - bioconda diff --git a/environment.yml b/environment.yml index 683facbebb..2ae3303c97 100644 --- a/environment.yml +++ b/environment.yml @@ -1,6 +1,6 @@ # You can use this file to create a conda environment for this pipeline: # conda env create -f environment.yml -name: nf-core-sarek-2.5dev +name: nf-core-sarek-2.5 channels: - conda-forge - bioconda diff --git a/nextflow.config b/nextflow.config index dd50b76c25..88c33ebe31 100644 --- a/nextflow.config +++ b/nextflow.config @@ -86,7 +86,7 @@ params { // Container slug. Stable releases should specify release tag! // Developmental code should specify :dev -process.container = 'nfcore/sarek:dev' +process.container = 'nfcore/sarek:2.5' // Load base.config by default for all pipelines includeConfig 'conf/base.config' @@ -155,7 +155,7 @@ manifest { description = 'An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing' mainScript = 'main.nf' nextflowVersion = '>=19.04.0' - version = '2.5dev' + version = '2.5' } // Return the minimum between requirements and a maximum limit to ensure that resource requirements don't go over diff --git a/scripts/download_image.sh b/scripts/download_image.sh index 959e8fb843..00892c09b3 100755 --- a/scripts/download_image.sh +++ b/scripts/download_image.sh @@ -3,13 +3,14 @@ set -xeuo pipefail # This script download and tag image for sarek tests -usage() { echo "Usage: $0 <-t test|annotation tool> <-n engine> <-T version to pull/build> <-g genome>" 1>&2; exit 1; } +usage() { echo "Usage: $0 <-t test|annotation tool> <-n engine> <-S version to pull/build> <-T version to tag> <-g genome>" 1>&2; exit 1; } ENGINE=docker GENOME=smallGRCh37 NXF_SINGULARITY_CACHEDIR=${NXF_SINGULARITY_CACHEDIR:-work/singularity/.} TEST=ALL VERSION=dev +TARGETVERSION=${VERSION} while [[ $# -gt 0 ]] do @@ -25,7 +26,12 @@ do shift # past argument shift # past value ;; - -T|--tagged-version) + -T|--target-version) + TARGETVERSION=$2 + shift # past argument + shift # past value + ;; + -S|--source-version) VERSION=$2 shift # past argument shift # past value @@ -66,15 +72,15 @@ get_image(){ if [[ ALL,ANNOTATEBOTH,ANNOTATESNPEFF,SNPEFF =~ $TEST ]] then - get_image sareksnpeff ${VERSION}.${SOURCEGENOME} ${VERSION}.${GENOME} + get_image sareksnpeff ${VERSION}.${SOURCEGENOME} ${TARGETVERSION}.${GENOME} fi if [[ ALL,ANNOTATEBOTH,ANNOTATEVEP,VEP =~ $TEST ]] then - get_image sarekvep ${VERSION}.${SOURCEGENOME} ${VERSION}.${GENOME} + get_image sarekvep ${VERSION}.${SOURCEGENOME} ${TARGETVERSION}.${GENOME} fi if ! [[ ANNOTATEBOTH,ANNOTATESNPEFF,ANNOTATEVEP,LINT,SNPEFF,VEP =~ $TEST ]] then - get_image sarek ${VERSION} ${VERSION} + get_image sarek ${VERSION} ${TARGETVERSION} fi diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index d79a821913..cb6db88901 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -109,7 +109,7 @@ esac case $TEST in ANNOTATE) - run_sarek --step annotate --tools ${ANNOTATOR} --input ${PATHTOSAMPLE}/vcf/Strelka_1234N_variants.vcf.gz + run_sarek --step annotate --tools ${ANNOTATOR} --input ${PATHTOSAMPLE}/vcf/Strelka_1234N_variants.vcf.gz --skipQC all ;; GERMLINE) run_sarek --tools=false --input data/testdata/tiny/normal From af8650e358138593a45686f984e237690d0c8d68 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Tue, 24 Sep 2019 11:36:57 +0200 Subject: [PATCH 088/854] Update README.md Co-Authored-By: Alexander Peltzer --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index e6e67df597..436f43d3c2 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,6 @@ [![Join us on Slack](https://img.shields.io/badge/slack-nfcore/sarek-blue.svg)](https://nfcore.slack.com/messages/CGFUX04HZ/) -> :warning: This pipeline is a work in progress being ported to nf-core from [SciLifeLab/Sarek](https://github/SciLifeLab/Sarek/) ## Introduction From c60d99eebe66117c3adbc269e1f4122e8dc7c9a9 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Tue, 24 Sep 2019 11:38:24 +0200 Subject: [PATCH 089/854] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 436f43d3c2..dd2d2d5936 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ [![nf-core](https://img.shields.io/badge/nf--core-pipeline-brightgreen.svg)](https://nf-co.re/) [![Travis build status](https://img.shields.io/travis/nf-core/sarek.svg)](https://travis-ci.com/nf-core/sarek/) -[![GitHub Actions CI Status](https://github.com/nf-core/sarek/workflows/sarek%20CI/badge.svg)](https://github.com/nf-core/sarek/actions) [![GitHub Actions extra CI Status](https://github.com/nf-core/sarek/workflows/sarek%20extra%20CI/badge.svg)](https://github.com/nf-core/sarek/actions) [![GitHub Actions Linting Status](https://github.com/nf-core/sarek/workflows/sarek%20linting/badge.svg)](https://github.com/nf-core/sarek/actions) [![CircleCi build status](https://img.shields.io/circleci/project/github/nf-core/sarek.svg)](https://circleci.com/gh/nf-core/sarek/) From 584b3b2de9768328b00ed82b12b5da611916acec Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Tue, 24 Sep 2019 11:48:30 +0200 Subject: [PATCH 090/854] Apply suggestions from code review Co-Authored-By: Alexander Peltzer --- README.md | 4 ---- docs/containers.md | 4 ++-- docs/usage.md | 2 +- main.nf | 4 ++-- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index dd2d2d5936..73be27240e 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,6 @@ [![nf-core](https://img.shields.io/badge/nf--core-pipeline-brightgreen.svg)](https://nf-co.re/) [![Travis build status](https://img.shields.io/travis/nf-core/sarek.svg)](https://travis-ci.com/nf-core/sarek/) -[![GitHub Actions extra CI Status](https://github.com/nf-core/sarek/workflows/sarek%20extra%20CI/badge.svg)](https://github.com/nf-core/sarek/actions) -[![GitHub Actions Linting Status](https://github.com/nf-core/sarek/workflows/sarek%20linting/badge.svg)](https://github.com/nf-core/sarek/actions) [![CircleCi build status](https://img.shields.io/circleci/project/github/nf-core/sarek.svg)](https://circleci.com/gh/nf-core/sarek/) [![install with bioconda](https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg)](http://bioconda.github.io/) @@ -46,9 +44,7 @@ The nf-core/sarek pipeline comes with documentation about the pipeline, found in 3. [Running the pipeline](docs/usage.md) * [Examples](docs/use_cases.md) * [Input files documentation](docs/input.md) - * [Extra documentation on variant calling](docs/variantcalling.md) * [Documentation about containers](docs/containers.md) - * [Extra documentation for targeted sequencing](docs/targetseq.md) 4. [Output and how to interpret the results](docs/output.md) * [Complementary information about ASCAT](docs/ascat.md) * [Extra documentation on annotation](docs/annotation.md) diff --git a/docs/containers.md b/docs/containers.md index 7cb9094b17..87b7f05b87 100644 --- a/docs/containers.md +++ b/docs/containers.md @@ -39,7 +39,7 @@ For annotation, the main container can be used, but the cache has to be download - Based on `nfcore/base:latest` - Contain **[snpEff](http://snpeff.sourceforge.net/)** 4.3.1t -- Contain cache for `GRCh37`, `GRCh38`, `GRCm38` or `CanFam3.1` +- Contains cache for `GRCh37`, `GRCh38`, `GRCm38` or `CanFam3.1` ### sarekvep [![sarekvep-docker status](https://img.shields.io/docker/automated/nfcore/sarekvep.svg)](https://hub.docker.com/r/nfcore/sarekvep) @@ -50,7 +50,7 @@ For annotation, the main container can be used, but the cache has to be download ## Using helper script -An helper script, used for testing can also be used to help with pulling docker containers, or building singularity images. +A helper script, used for testing can also be used to help with pulling docker containers, or building singularity images. The following parameters can be used: ### Engine: -n diff --git a/docs/usage.md b/docs/usage.md index 5d497d27db..f1532af20b 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -491,7 +491,7 @@ Provide your PON by: --pon '[path to the PON VCF]' ``` -If the PON file is bgzipped, there have to be a tabixed index file at the same directory. +If the PON file is bgzipped, there has to be a tabixed index file at the same directory. ### `--snpeffDb` diff --git a/main.nf b/main.nf index bb6c2ba1bf..9a1f6a2c98 100644 --- a/main.nf +++ b/main.nf @@ -248,7 +248,7 @@ ch_snpeffDb = params.snpeffDb ? Channel.value(params.snpeffDb) : "null" ch_vepCacheVersion = params.vepCacheVersion ? Channel.value(params.vepCacheVersion) : "null" ch_vep_cache = params.vep_cache ? Channel.value(file(params.vep_cache)) : "null" -// Optionnal files, not defined within the params.genomes[params.genome] scope +// Optional files, not defined within the params.genomes[params.genome] scope ch_cadd_InDels = params.cadd_InDels ? Channel.value(file(params.cadd_InDels)) : "null" ch_cadd_InDels_tbi = params.cadd_InDels_tbi ? Channel.value(file(params.cadd_InDels_tbi)) : "null" ch_cadd_WG_SNVs = params.cadd_WG_SNVs ? Channel.value(file(params.cadd_WG_SNVs)) : "null" @@ -2483,7 +2483,7 @@ workflow.onComplete { c_green = params.monochrome_logs ? '' : "\033[0;32m"; c_purple = params.monochrome_logs ? '' : "\033[0;35m"; - if (workflow.stats.ignoredCountFmt > 0 && workflow.success) { + if (workflow.stats.ignoredCount > 0 && workflow.success) { log.info "${c_purple}Warning, pipeline completed, but with errored process(es)${c_reset}" log.info "${c_red}Number of ignored errored process(es) : ${workflow.stats.ignoredCountFmt}${c_reset}" log.info "${c_green}Number of successfully ran process(es) : ${workflow.stats.succeedCountFmt}${c_reset}" From 3b98c886061cf829a71a3901928d8ba5e21ff88a Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Wed, 25 Sep 2019 15:34:58 +0200 Subject: [PATCH 091/854] Apply suggestions from code review --- conf/genomes.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/genomes.config b/conf/genomes.config index c117266a7f..d1cea4fc74 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -39,8 +39,8 @@ params { dict = "${params.genomes_base}/Homo_sapiens_assembly38.dict" fasta = "${params.genomes_base}/Homo_sapiens_assembly38.fasta" fastaFai = "${params.genomes_base}/Homo_sapiens_assembly38.fasta.fai" - germlineResource = "${params.genomes_base}/GCF_000001405.38.AUTOSOMESXY.COMMON.BIALLELIC.SNPs.with.AF.vcf.gz" - germlineResourceIndex = "${params.genomes_base}/GCF_000001405.38.AUTOSOMESXY.COMMON.BIALLELIC.SNPs.with.AF.vcf.gz.tbi" + germlineResource = "${params.genomes_base}/gnomAD.r2.1.1.GRCh38.PASS.AC.AF.only.vcf.gz" + germlineResourceIndex = "${params.genomes_base}/gnomAD.r2.1.1.GRCh38.PASS.AC.AF.only.vcf.gz.tbi" intervals = "${params.genomes_base}/wgs_calling_regions.hg38.bed" knownIndels = "${params.genomes_base}/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" knownIndelsIndex = "${params.genomes_base}/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" From dc6cf30e4778a40e9c3c92927ab18c20daefc124 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Fri, 27 Sep 2019 11:32:04 +0200 Subject: [PATCH 092/854] Avoid collision in MultiQC (#38) * enforcing file names to be idsample_idRun pre merging to avoid collision * more consistency for fastqc and bamqc output * update CHANGELOG --- CHANGELOG.md | 2 ++ main.nf | 41 ++++++++++++++++++----------------------- nextflow.config | 1 + 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8adbcab63a..d19537ef98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -91,6 +91,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#35](https://github.com/nf-core/sarek/pull/35) - Refactor references handling - [#35](https://github.com/nf-core/sarek/pull/35) - use Channel values instead of `referenceMap` - [#37](https://github.com/nf-core/sarek/pull/37) - Bump version for Release +- [#38](https://github.com/nf-core/sarek/pull/38) - File names before merge is based on `${idSample}_${idRun}` instead of `${idRun}` ### `Removed` @@ -123,6 +124,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#31](https://github.com/nf-core/sarek/pull/31) - Fix badges according to nf-core lint - [#31](https://github.com/nf-core/sarek/pull/31) - Fix rcolorbrewer version according to nf-core lint - [#33](https://github.com/nf-core/sarek/pull/33) - Fix MD Linting +- [#38](https://github.com/nf-core/sarek/pull/38) - Avoid collision in MultiQC ### `Deprecated` diff --git a/main.nf b/main.nf index 9a1f6a2c98..ae9da92a4e 100644 --- a/main.nf +++ b/main.nf @@ -594,19 +594,19 @@ process FastQCFQ { tag {idPatient + "-" + idRun} - publishDir "${params.outdir}/Reports/${idSample}/FastQC/${idRun}", mode: params.publishDirMode + publishDir "${params.outdir}/Reports/${idSample}/FastQC/${idSample}_${idRun}", mode: params.publishDirMode input: - set idPatient, idSample, idRun, file("${idRun}_R1.fastq.gz"), file("${idRun}_R2.fastq.gz") from inputPairReadsFastQC + set idPatient, idSample, idRun, file("${idSample}_${idRun}_R1.fastq.gz"), file("${idSample}_${idRun}_R2.fastq.gz") from inputPairReadsFastQC output: - file "*_fastqc.{zip,html}" into fastQCFQReport + file("*.{html,zip}") into fastQCFQReport when: step == 'mapping' && !('fastqc' in skipQC) script: """ - fastqc -t 2 -q ${idRun}_R1.fastq.gz ${idRun}_R2.fastq.gz + fastqc -t 2 -q ${idSample}_${idRun}_R1.fastq.gz ${idSample}_${idRun}_R2.fastq.gz """ } @@ -615,19 +615,19 @@ process FastQCBAM { tag {idPatient + "-" + idRun} - publishDir "${params.outdir}/Reports/${idSample}/FastQC/${idRun}", mode: params.publishDirMode + publishDir "${params.outdir}/Reports/${idSample}/FastQC/${idSample}_${idRun}", mode: params.publishDirMode input: - set idPatient, idSample, idRun, file("${idRun}.bam") from inputBAMFastQC + set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam") from inputBAMFastQC output: - file "*_fastqc.{zip,html}" into fastQCBAMReport + file("*.{html,zip}") into fastQCBAMReport when: step == 'mapping' && !('fastqc' in skipQC) script: """ - fastqc -t 2 -q "${idRun}.bam" + fastqc -t 2 -q ${idSample}_${idRun}.bam """ } @@ -648,8 +648,8 @@ process MapReads { file(fasta) from ch_fasta output: - set idPatient, idSample, idRun, file("${idRun}.bam") into bamMapped - set idPatient, idSample, file("${idRun}.bam") into bamMappedBamQC + set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam") into bamMapped + set idPatient, idSample, file("${idSample}_${idRun}.bam") into bamMappedBamQC when: step == 'mapping' @@ -670,7 +670,7 @@ process MapReads { ${convertToFastq} bwa mem -K 100000000 -R \"${readGroup}\" ${extra} -t ${task.cpus} -M ${fasta} \ ${input} | \ - samtools sort --threads ${task.cpus} -m 2G - > ${idRun}.bam + samtools sort --threads ${task.cpus} -m 2G - > ${idSample}_${idRun}.bam """ } @@ -2361,24 +2361,19 @@ compressVCFOutVEP = compressVCFOutVEP.dump(tag:'VCF') // STEP MULTIQC -multiQCReport = Channel.empty() - .mix( - bamQCReport, - bcftoolsReport, - fastQCReport, - markDuplicatesReport, - samtoolsStatsReport, - snpeffReport, - vcftoolsReport - ).collect() - process MultiQC { publishDir "${params.outdir}/Reports/MultiQC", mode: params.publishDirMode input: file (multiqcConfig) from Channel.value(params.multiqc_config ? file(params.multiqc_config) : "") - file (reports) from multiQCReport file (versions) from yamlSoftwareVersion + file ('bamQC/*') from bamQCReport.collect().ifEmpty([]) + file ('BCFToolsStats/*') from bcftoolsReport.collect().ifEmpty([]) + file ('FastQC/*') from fastQCReport.collect().ifEmpty([]) + file ('MarkDuplicates/*') from markDuplicatesReport.collect().ifEmpty([]) + file ('SamToolsStats/*') from samtoolsStatsReport.collect().ifEmpty([]) + file ('snpEff/*') from snpeffReport.collect().ifEmpty([]) + file ('VCFTools/*') from vcftoolsReport.collect().ifEmpty([]) output: set file("*multiqc_report.html"), file("*multiqc_data") into multiQCOut diff --git a/nextflow.config b/nextflow.config index 88c33ebe31..71cead284b 100644 --- a/nextflow.config +++ b/nextflow.config @@ -115,6 +115,7 @@ profiles { singularity.enabled = false } singularity { + autoMounts = true docker.enabled = false singularity.enabled = true } From 64d9c10bcb1bcee3d2b41198ea8c7e59fe512b7a Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Fri, 27 Sep 2019 15:29:29 +0200 Subject: [PATCH 093/854] Fix ch_dbsnp channel (#39) * fix typo for bwaIndex in params.genomes[params.genome] * add more logs for reference Files * fix params.dbsnpIndex * remove bwaIndex from smallGRCh37 * fix ch_dbsnp * update CHANGELOG --- CHANGELOG.md | 1 + conf/genomes.config | 1 - main.nf | 41 +++++++++++++++++++++++++---------------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d19537ef98..080ba18d72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -125,6 +125,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#31](https://github.com/nf-core/sarek/pull/31) - Fix rcolorbrewer version according to nf-core lint - [#33](https://github.com/nf-core/sarek/pull/33) - Fix MD Linting - [#38](https://github.com/nf-core/sarek/pull/38) - Avoid collision in MultiQC +- [#39](https://github.com/nf-core/sarek/pull/39) - Fix `ch_dbsnp` channel ### `Deprecated` diff --git a/conf/genomes.config b/conf/genomes.config index d1cea4fc74..7d7527b21a 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -50,7 +50,6 @@ params { 'smallGRCh37' { acLoci = "${params.genomes_base}/1000G_phase3_20130502_SNP_maf0.3.small.loci" acLociGC = "${params.genomes_base}/1000G_phase3_20130502_SNP_maf0.3.small.loci.gc" - bwaIndex = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta.{amb,ann,bwt,pac,sa}" dbsnp = "${params.genomes_base}/dbsnp_138.b37.small.vcf.gz" fasta = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" germlineResource = "${params.genomes_base}/dbsnp_138.b37.small.vcf.gz" diff --git a/main.nf b/main.nf index ae9da92a4e..ffe3b12b7d 100644 --- a/main.nf +++ b/main.nf @@ -144,7 +144,7 @@ params.fasta = params.genome && !('annotate' in step) ? params.genomes[params.ge // The rest can be sorted params.acLoci = params.genome && 'ascat' in tools ? params.genomes[params.genome].acLoci ?: null : null params.acLociGC = params.genome && 'ascat' in tools ? params.genomes[params.genome].acLociGC ?: null : null -params.bwaIndex = params.genome && params.fasta && 'mapping' in step ? params.genomes[params.genome].bwa ?: null : null +params.bwaIndex = params.genome && params.fasta && 'mapping' in step ? params.genomes[params.genome].bwaIndex ?: null : null params.chrDir = params.genome && 'controlfreec' in tools ? params.genomes[params.genome].chrDir ?: null : null params.chrLength = params.genome && 'controlfreec' in tools ? params.genomes[params.genome].chrLength ?: null : null params.dbsnp = params.genome && ('mapping' in step || 'controlfreec' in tools || 'haplotypecaller' in tools || 'mutect2' in tools) ? params.genomes[params.genome].dbsnp ?: null : null @@ -238,10 +238,10 @@ ch_fastaFai = params.fastaFai && !('annotate' in step) ? Channel.value(file(para ch_germlineResource = params.germlineResource && 'mutect2' in tools ? Channel.value(file(params.germlineResource)) : "null" ch_intervals = params.intervals && !('annotate' in step) ? Channel.value(file(params.intervals)) : "null" -// knownIndels is currently a list of file, so transform it in a channel +// knownIndels is currently a list of file for smallGRCh37, so transform it in a channel li_knownIndels = [] if (params.knownIndels && ('mapping' in step)) params.knownIndels.each { li_knownIndels.add(file(it)) } -ch_knownIndels = params.knownIndels ? Channel.value(li_knownIndels.collect()) : "null" +ch_knownIndels = params.knownIndels && params.genome == 'smallGRCh37' ? Channel.value(li_knownIndels.collect()) : params.knownIndels ? Channel.value(file(params.knownIndels)) : "null" ch_snpEff_cache = params.snpEff_cache ? Channel.value(file(params.snpEff_cache)) : "null" ch_snpeffDb = params.snpeffDb ? Channel.value(params.snpeffDb) : "null" @@ -287,18 +287,25 @@ summary['Launch dir'] = workflow.launchDir summary['Working dir'] = workflow.workDir summary['Script dir'] = workflow.projectDir summary['User'] = workflow.userName - -if (params.acLoci) summary['acLoci'] = params.acLoci -if (params.acLociGC) summary['acLociGC'] = params.acLociGC -if (params.chrDir) summary['chrDir'] = params.chrDir -if (params.chrLength) summary['chrLength'] = params.chrLength -if (params.dbsnp) summary['dbsnp'] = params.dbsnp -if (params.fasta) summary['fasta'] = params.fasta -if (params.germlineResource) summary['germlineResource'] = params.germlineResource -if (params.intervals) summary['intervals'] = params.intervals -if (params.knownIndels) summary['knownIndels'] = params.knownIndels.join(', ') -if (params.snpeffDb) summary['snpeffDb'] = params.snpeffDb -if (params.vepCacheVersion) summary['vepCacheVersion'] = params.vepCacheVersion +summary['genome'] = params.genome + +if (params.fasta) summary['fasta'] = params.fasta +if (params.fastaFai) summary['fastaFai'] = params.fastaFai +if (params.dict) summary['dict'] = params.dict +if (params.bwaIndex) summary['bwaIndex'] = params.bwaIndex +if (params.germlineResource) summary['germlineResource'] = params.germlineResource +if (params.germlineResourceIndex) summary['germlineResourceIndex'] = params.germlineResourceIndex +if (params.intervals) summary['intervals'] = params.intervals +if (params.acLoci) summary['acLoci'] = params.acLoci +if (params.acLociGC) summary['acLociGC'] = params.acLociGC +if (params.chrDir) summary['chrDir'] = params.chrDir +if (params.chrLength) summary['chrLength'] = params.chrLength +if (params.dbsnp) summary['dbsnp'] = params.dbsnp +if (params.dbsnpIndex) summary['dbsnpIndex'] = params.dbsnpIndex +if (params.knownIndels) summary['knownIndels'] = params.knownIndels +if (params.knownIndelsIndex) summary['knownIndelsIndex'] = params.knownIndelsIndex +if (params.snpeffDb) summary['snpeffDb'] = params.snpeffDb +if (params.vepCacheVersion) summary['vepCacheVersion'] = params.vepCacheVersion if (workflow.profile == 'awsbatch') { summary['AWS Region'] = params.awsregion @@ -758,6 +765,8 @@ markDuplicatesReport = markDuplicatesReport.dump(tag:'MD Report') (bamMD, bamMDToJoin) = duplicateMarkedBams.into(2) bamBaseRecalibrator = bamMD.combine(intBaseRecalibrator) +bamBaseRecalibrator = bamBaseRecalibrator.dump(tag:'BAM FOR BASERECALIBRATOR') + // STEP 3: CREATING RECALIBRATION TABLES process BaseRecalibrator { @@ -770,8 +779,8 @@ process BaseRecalibrator { set idPatient, idSample, file(bam), file(bai), file(intervalBed) from bamBaseRecalibrator file(dbsnp) from ch_dbsnp file(dbsnpIndex) from ch_dbsnpIndex - file(dict) from ch_dict file(fasta) from ch_fasta + file(dict) from ch_dict file(fastaFai) from ch_fastaFai file(knownIndels) from ch_knownIndels file(knownIndelsIndex) from ch_knownIndelsIndex From 3acba3708f7da28c4a88fa187347f3102f3b342d Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Tue, 8 Oct 2019 09:41:02 +0200 Subject: [PATCH 094/854] Update nextflow.config --- nextflow.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextflow.config b/nextflow.config index 71cead284b..852831b8e4 100644 --- a/nextflow.config +++ b/nextflow.config @@ -22,7 +22,7 @@ params { annotation_cache = null // Annotation cache disabled cadd_cache = null // CADD cache disabled genesplicer = null // genesplicer disabled - markdup_java_options = '"-Xms4000m -Xmx7g"' //Established values for markDuplicate memory consumption, see issue PR #689 for details + markdup_java_options = '"-Xms4000m -Xmx7g"' //Established values for markDuplicate memory consumption, see https://github.com/SciLifeLab/Sarek/pull/689 for details nucleotidesPerSecond = 1000.0 // Default interval size outdir = './results' publishDirMode = 'copy' // Default PublishDirMode (same as other nf-core pipelines) From d11be86292d7cdccbe48d9d4745a99fae044e2d1 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 8 Oct 2019 10:23:07 +0200 Subject: [PATCH 095/854] use tagged image --- Dockerfile | 2 +- containers/snpeff/Dockerfile | 2 +- containers/vep/Dockerfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 33abcf89b7..c012a49d05 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM nfcore/base +FROM nfcore/base:1.7 LABEL authors="Maxime Garcia, Szilveszter Juhos" \ description="Docker image containing all requirements for nf-core/sarek pipeline" diff --git a/containers/snpeff/Dockerfile b/containers/snpeff/Dockerfile index 07ccb28152..3ac9b89dd7 100644 --- a/containers/snpeff/Dockerfile +++ b/containers/snpeff/Dockerfile @@ -1,4 +1,4 @@ -FROM nfcore/base:1.6 +FROM nfcore/base:1.7 LABEL \ author="Maxime Garcia" \ diff --git a/containers/vep/Dockerfile b/containers/vep/Dockerfile index 7969b5d1e7..cfe2d8eeb5 100644 --- a/containers/vep/Dockerfile +++ b/containers/vep/Dockerfile @@ -1,4 +1,4 @@ -FROM nfcore/base:1.6 +FROM nfcore/base:1.7 LABEL \ author="Maxime Garcia" \ From ff8807bc3df7cb6c6bd1a09762bcb39150c65b68 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 8 Oct 2019 10:23:17 +0200 Subject: [PATCH 096/854] add patch to branch protection --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f34465aad6..3598ccf284 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ matrix: before_install: # PRs to master are only ok if coming from dev branch - - '[ $TRAVIS_PULL_REQUEST = "false" ] || [ $TRAVIS_BRANCH != "master" ] || ([ $TRAVIS_PULL_REQUEST_SLUG = $TRAVIS_REPO_SLUG ] && [ $TRAVIS_PULL_REQUEST_BRANCH = "dev" ])' + - '[ $TRAVIS_PULL_REQUEST = "false" ] || [ $TRAVIS_BRANCH != "master" ] || ([ $TRAVIS_PULL_REQUEST_SLUG = $TRAVIS_REPO_SLUG ] && ([ $TRAVIS_PULL_REQUEST_BRANCH = "dev" ] || [ $TRAVIS_PULL_REQUEST_BRANCH = "patch" ]))' # Pull the docker image first so the test doesn't wait for this - docker pull nfcore/sarek:dev # Fake the tag locally so that the pipeline runs properly From 4bd1ae035331790351b63f48c6760800b54a646b Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 8 Oct 2019 10:38:16 +0200 Subject: [PATCH 097/854] remove VEP from CI as it's currently failing --- .github/workflows/ci-extra.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-extra.yml b/.github/workflows/ci-extra.yml index 90543c7958..040dc11ffe 100644 --- a/.github/workflows/ci-extra.yml +++ b/.github/workflows/ci-extra.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - test: [ANNOTATESNPEFF, ANNOTATEVEP, GERMLINE, SOMATIC, TARGETED] + test: [ANNOTATESNPEFF, GERMLINE, SOMATIC, TARGETED] nxf_ver: ['19.04.0', ''] steps: - uses: actions/checkout@v1 From 8d80be3f784763c0a4b9196b15d4445df76da7ca Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 8 Oct 2019 12:17:53 +0200 Subject: [PATCH 098/854] set time for MapReads process to 48.h --- conf/base.config | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/base.config b/conf/base.config index 3b137eda52..5c76d275e6 100644 --- a/conf/base.config +++ b/conf/base.config @@ -62,6 +62,7 @@ process { } withName:MapReads { memory = {check_resource(60.GB * task.attempt)} + time = {check_resource(48.h * task.attempt)} } withName:MultiQC { errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} From 508735eb09d2fe33e904516db8db128b0a808dd2 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Tue, 8 Oct 2019 15:30:44 +0200 Subject: [PATCH 099/854] Add Zenodo Badge --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 73be27240e..10e2544ca6 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ [![Nextflow](https://img.shields.io/badge/nextflow-%E2%89%A519.04.0-brightgreen.svg)](https://www.nextflow.io/) [![nf-core](https://img.shields.io/badge/nf--core-pipeline-brightgreen.svg)](https://nf-co.re/) +[![DOI](https://zenodo.org/badge/184289291.svg)](https://zenodo.org/badge/latestdoi/184289291) [![Travis build status](https://img.shields.io/travis/nf-core/sarek.svg)](https://travis-ci.com/nf-core/sarek/) [![CircleCi build status](https://img.shields.io/circleci/project/github/nf-core/sarek.svg)](https://circleci.com/gh/nf-core/sarek/) @@ -97,7 +98,7 @@ For further information or help, don't hesitate to get in touch on [Slack](https If you use nf-core/sarek for your analysis, please cite the `Sarek` pre-print as follows: > Garcia MU, Juhos S, Larsson M, Olason PI, Martin M, Eisfeldt J, DiLorenzo S, Sandgren J, de Ståhl TD, Wirta V, Nistér M, Nystedt B, Käller M. **Sarek: A portable workflow for whole-genome sequencing analysis of germline and somatic variants**. *bioRxiv*. 2018. p. 316976. [doi: 10.1101/316976](https://www.biorxiv.org/content/10.1101/316976v1). -You can cite the sarek zenodo record for a specific version using the following [doi: 10.5281/zenodo.2582812](https://doi.org/10.5281/zenodo.2582812) +You can cite the sarek zenodo record for a specific version using the following [DOI: 10.5281/zenodo.3476426 ](https://zenodo.org/badge/latestdoi/184289291) You can cite the `nf-core` pre-print as follows: > Ewels PA, Peltzer A, Fillinger S, Alneberg JA, Patel H, Wilm A, Garcia MU, Di Tommaso P, Nahnsen S. **nf-core: Community curated bioinformatics pipelines**. *bioRxiv*. 2019. p. 610741. [doi: 10.1101/610741](https://www.biorxiv.org/content/10.1101/610741v3). From e223831c37c1f2b6347e587683602348d7d950a0 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 8 Oct 2019 15:54:03 +0200 Subject: [PATCH 100/854] nf-core bump-version . 2.5.1dev --- .circleci/config.yml | 8 ++++---- .github/workflows/ci-extra.yml | 2 +- .github/workflows/ci.yml | 2 +- .travis.yml | 2 +- CHANGELOG.md | 2 ++ Dockerfile | 2 +- README.md | 4 ++-- containers/snpeff/Dockerfile | 2 +- containers/snpeff/environment.yml | 2 +- containers/vep/Dockerfile | 2 +- containers/vep/environment.yml | 2 +- environment.yml | 2 +- nextflow.config | 4 ++-- 13 files changed, 19 insertions(+), 17 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1ede7ab8fe..0af952fcb0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,11 +10,11 @@ jobs: - checkout - setup_remote_docker - run: - command: docker build -t nfcore/sareksnpeff:2.5.${GENOME} containers/snpeff/. --build-arg GENOME=${GENOME} --build-arg SNPEFF_CACHE_VERSION=${SNPEFF_CACHE_VERSION} + command: docker build -t nfcore/sareksnpeff:dev.${GENOME} containers/snpeff/. --build-arg GENOME=${GENOME} --build-arg SNPEFF_CACHE_VERSION=${SNPEFF_CACHE_VERSION} - run: command: | echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin - docker push nfcore/sareksnpeff:2.5.${GENOME} + docker push nfcore/sareksnpeff:dev.${GENOME} snpeffgrch38: << : *buildsnpeff @@ -45,10 +45,10 @@ jobs: - checkout - setup_remote_docker - run: - command: docker build -t nfcore/sarekvep:2.5.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} + command: docker build -t nfcore/sarekvep:dev.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} no_output_timeout: 3h - run: - command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:2.5.${GENOME} + command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:dev.${GENOME} vepgrch38: << : *buildvep diff --git a/.github/workflows/ci-extra.yml b/.github/workflows/ci-extra.yml index 040dc11ffe..d37a33aae0 100644 --- a/.github/workflows/ci-extra.yml +++ b/.github/workflows/ci-extra.yml @@ -18,7 +18,7 @@ jobs: sudo mv nextflow /usr/local/bin/ - name: Download image run: | - ${GITHUB_WORKSPACE}/scripts/download_image.sh -n docker --source-version dev --target-version 2.5 --test ${{ matrix.test }} + ${GITHUB_WORKSPACE}/scripts/download_image.sh -n docker --source-version dev --target-version dev --test ${{ matrix.test }} - name: Run test run: | ${GITHUB_WORKSPACE}/scripts/run_tests.sh --test ${{ matrix.test }} --verbose \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 785fb9269c..22c1031208 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: - name: Download and tag image run: | docker pull nfcore/sarek:dev - docker tag nfcore/sarek:dev nfcore/sarek:2.5 + docker tag nfcore/sarek:dev nfcore/sarek:dev - name: Run test run: | nextflow run ${GITHUB_WORKSPACE} -profile test,docker \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 3598ccf284..450539446e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ before_install: - docker pull nfcore/sarek:dev # Fake the tag locally so that the pipeline runs properly # Looks weird when this is :dev to :dev, but makes sense when testing code for a release (:dev to :1.0.1) - - docker tag nfcore/sarek:dev nfcore/sarek:2.5 + - docker tag nfcore/sarek:dev nfcore/sarek:dev install: # Install Nextflow diff --git a/CHANGELOG.md b/CHANGELOG.md index 080ba18d72..52ca85db3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## dev + ## [2.5] - Ålkatj Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) template. diff --git a/Dockerfile b/Dockerfile index c012a49d05..8b2563a995 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,4 +4,4 @@ LABEL authors="Maxime Garcia, Szilveszter Juhos" \ COPY environment.yml / RUN conda env create -f /environment.yml && conda clean -a -ENV PATH /opt/conda/envs/nf-core-sarek-2.5/bin:$PATH +ENV PATH /opt/conda/envs/nf-core-sarek-2.5.1dev/bin:$PATH diff --git a/README.md b/README.md index 10e2544ca6..8b4cfdff20 100644 --- a/README.md +++ b/README.md @@ -95,10 +95,10 @@ For further information or help, don't hesitate to get in touch on [Slack](https ## Citation -If you use nf-core/sarek for your analysis, please cite the `Sarek` pre-print as follows: +If you use `nf-core/sarek` for your analysis, please cite the `Sarek` pre-print as follows: > Garcia MU, Juhos S, Larsson M, Olason PI, Martin M, Eisfeldt J, DiLorenzo S, Sandgren J, de Ståhl TD, Wirta V, Nistér M, Nystedt B, Käller M. **Sarek: A portable workflow for whole-genome sequencing analysis of germline and somatic variants**. *bioRxiv*. 2018. p. 316976. [doi: 10.1101/316976](https://www.biorxiv.org/content/10.1101/316976v1). -You can cite the sarek zenodo record for a specific version using the following [DOI: 10.5281/zenodo.3476426 ](https://zenodo.org/badge/latestdoi/184289291) +You can cite the sarek zenodo record for a specific version using the following [DOI: 10.5281/zenodo.3476426](https://zenodo.org/badge/latestdoi/184289291) You can cite the `nf-core` pre-print as follows: > Ewels PA, Peltzer A, Fillinger S, Alneberg JA, Patel H, Wilm A, Garcia MU, Di Tommaso P, Nahnsen S. **nf-core: Community curated bioinformatics pipelines**. *bioRxiv*. 2019. p. 610741. [doi: 10.1101/610741](https://www.biorxiv.org/content/10.1101/610741v3). diff --git a/containers/snpeff/Dockerfile b/containers/snpeff/Dockerfile index 3ac9b89dd7..5c52720260 100644 --- a/containers/snpeff/Dockerfile +++ b/containers/snpeff/Dockerfile @@ -7,7 +7,7 @@ LABEL \ COPY environment.yml / RUN conda env create -f /environment.yml && conda clean -a -ENV PATH /opt/conda/envs/sarek-snpeff-2.5/bin:$PATH +ENV PATH /opt/conda/envs/sarek-snpeff-2.5.1dev/bin:$PATH # Setup default ARG variables ARG GENOME=GRCh38 diff --git a/containers/snpeff/environment.yml b/containers/snpeff/environment.yml index fd93bd1815..2dfdc6f3ff 100644 --- a/containers/snpeff/environment.yml +++ b/containers/snpeff/environment.yml @@ -1,6 +1,6 @@ # You can use this file to create a conda environment for this pipeline: # conda env create -f environment.yml -name: sarek-snpeff-2.5 +name: sarek-snpeff-2.5.1dev channels: - conda-forge - bioconda diff --git a/containers/vep/Dockerfile b/containers/vep/Dockerfile index cfe2d8eeb5..75a8497b3b 100644 --- a/containers/vep/Dockerfile +++ b/containers/vep/Dockerfile @@ -7,7 +7,7 @@ LABEL \ COPY environment.yml / RUN conda env create -f /environment.yml && conda clean -a -ENV PATH /opt/conda/envs/sarek-vep-2.5/bin:$PATH +ENV PATH /opt/conda/envs/sarek-vep-2.5.1dev/bin:$PATH # Setup default ARG variables ARG GENOME=GRCh38 diff --git a/containers/vep/environment.yml b/containers/vep/environment.yml index b5c73474a6..d426f78a68 100644 --- a/containers/vep/environment.yml +++ b/containers/vep/environment.yml @@ -1,6 +1,6 @@ # You can use this file to create a conda environment for this pipeline: # conda env create -f environment.yml -name: sarek-vep-2.5 +name: sarek-vep-2.5.1dev channels: - conda-forge - bioconda diff --git a/environment.yml b/environment.yml index 2ae3303c97..94ca2d5a19 100644 --- a/environment.yml +++ b/environment.yml @@ -1,6 +1,6 @@ # You can use this file to create a conda environment for this pipeline: # conda env create -f environment.yml -name: nf-core-sarek-2.5 +name: nf-core-sarek-2.5.1dev channels: - conda-forge - bioconda diff --git a/nextflow.config b/nextflow.config index 852831b8e4..6ddfb53847 100644 --- a/nextflow.config +++ b/nextflow.config @@ -86,7 +86,7 @@ params { // Container slug. Stable releases should specify release tag! // Developmental code should specify :dev -process.container = 'nfcore/sarek:2.5' +process.container = 'nfcore/sarek:dev' // Load base.config by default for all pipelines includeConfig 'conf/base.config' @@ -156,7 +156,7 @@ manifest { description = 'An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing' mainScript = 'main.nf' nextflowVersion = '>=19.04.0' - version = '2.5' + version = '2.5.1dev' } // Return the minimum between requirements and a maximum limit to ensure that resource requirements don't go over From 5a1c386844f93519247fb701e758af9468af8f1e Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Wed, 9 Oct 2019 13:44:02 +0200 Subject: [PATCH 101/854] Remove PublishDirMode from test profile (#40) * remove PublishDirMode from test profile --- CHANGELOG.md | 4 ++++ conf/test.config | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52ca85db3d..eb7262e651 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## dev +### `Fixed` + +- [#40](https://github.com/nf-core/sarek/pull/40) - Fix issue with `publishDirMode` within `test` profile + ## [2.5] - Ålkatj Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) template. diff --git a/conf/test.config b/conf/test.config index 9c32937aca..9652998f3b 100644 --- a/conf/test.config +++ b/conf/test.config @@ -20,9 +20,6 @@ params { igenomesIgnore = true genome = 'smallGRCh37' genomes_base = "https://github.com/nf-core/test-datasets/raw/sarek/reference" - - // Use publishDir mode link so that work can be removed - publishDirMode = 'link' } process { From 436af40c27cbad4cc951351430dc83610a70405d Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 9 Oct 2019 17:17:12 +0200 Subject: [PATCH 102/854] update all tools --- CHANGELOG.md | 11 +++++++++++ containers/vep/Dockerfile | 2 +- containers/vep/environment.yml | 2 +- docs/containers.md | 18 +++++++++--------- environment.yml | 16 ++++++++-------- 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb7262e651..417b6da2ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## dev +### `Added` + +- [#41](https://github.com/nf-core/sarek/pull/41) - Update `control-freec` from `11.4` to `11.5` +- [#41](https://github.com/nf-core/sarek/pull/41) - Update `ensembl-vep` from `95.2` to `98.2` +- [#41](https://github.com/nf-core/sarek/pull/41) - Update `freebayes` from `1.2.0` to `1.3.1` +- [#41](https://github.com/nf-core/sarek/pull/41) - Update `gatk4` from `4.1.2.0` to `4.1.4.0` +- [#41](https://github.com/nf-core/sarek/pull/41) - Update `manta` from `1.5.0` to `1.6.0` +- [#41](https://github.com/nf-core/sarek/pull/41) - Update `qualimap` from `2.2.2b` to `2.2.2c` +- [#41](https://github.com/nf-core/sarek/pull/41) - Update `tiddit` from `2.7.1` to `2.8.0` +- [#41](https://github.com/nf-core/sarek/pull/41) - Update `vcfanno` from `0.3.1` to `0.3.2` + ### `Fixed` - [#40](https://github.com/nf-core/sarek/pull/40) - Fix issue with `publishDirMode` within `test` profile diff --git a/containers/vep/Dockerfile b/containers/vep/Dockerfile index 75a8497b3b..ee617f9f98 100644 --- a/containers/vep/Dockerfile +++ b/containers/vep/Dockerfile @@ -12,7 +12,7 @@ ENV PATH /opt/conda/envs/sarek-vep-2.5.1dev/bin:$PATH # Setup default ARG variables ARG GENOME=GRCh38 ARG SPECIES=homo_sapiens -ARG VEP_VERSION=95 +ARG VEP_VERSION=98 # Download Genome RUN vep_install \ diff --git a/containers/vep/environment.yml b/containers/vep/environment.yml index d426f78a68..831df73abd 100644 --- a/containers/vep/environment.yml +++ b/containers/vep/environment.yml @@ -7,5 +7,5 @@ channels: - defaults dependencies: - - ensembl-vep=95.2 + - ensembl-vep=98.2 - genesplicer=1.0 diff --git a/docs/containers.md b/docs/containers.md index 87b7f05b87..b86347db11 100644 --- a/docs/containers.md +++ b/docs/containers.md @@ -18,22 +18,22 @@ For annotation, the main container can be used, but the cache has to be download - Contain **[AlleleCount](https://github.com/cancerit/alleleCount)** 4.0.2 - Contain **[BCFTools](https://github.com/samtools/bcftools)** 1.9 - Contain **[BWA](https://github.com/lh3/bwa)** 0.7.17 -- Contain **[Control-FREEC](https://github.com/BoevaLab/FREEC)** 11.4 +- Contain **[Control-FREEC](https://github.com/BoevaLab/FREEC)** 11.5 - Contain **[FastQC](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/)** 0.11.8 -- Contain **[FreeBayes](https://github.com/ekg/freebayes)** 1.2.0 -- Contain **[GATK4](https://github.com/broadinstitute/gatk)** 4.1.2.0 +- Contain **[FreeBayes](https://github.com/ekg/freebayes)** 1.3.1 +- Contain **[GATK4](https://github.com/broadinstitute/gatk)** 4.1.4.0 - Contain **[GeneSplicer](https://ccb.jhu.edu/software/genesplicer/)** 1.0 - Contain **[HTSlib](https://github.com/samtools/htslib)** 1.9 -- Contain **[Manta](https://github.com/Illumina/manta)** 1.5.0 +- Contain **[Manta](https://github.com/Illumina/manta)** 1.6.0 - Contain **[MultiQC](https://github.com/ewels/MultiQC/)** 1.7 -- Contain **[Qualimap](http://qualimap.bioinfo.cipf.es)** 2.2.2b +- Contain **[Qualimap](http://qualimap.bioinfo.cipf.es)** 2.2.2c - Contain **[samtools](https://github.com/samtools/samtools)** 1.9 - Contain **[snpEff](http://snpeff.sourceforge.net/)** 4.3.1t - Contain **[Strelka2](https://github.com/Illumina/strelka)** 2.9.10 -- Contain **[TIDDIT](https://github.com/SciLifeLab/TIDDIT)** 2.7.1 -- Contain **[VCFanno](https://github.com/brentp/vcfanno)** 0.3.1 +- Contain **[TIDDIT](https://github.com/SciLifeLab/TIDDIT)** 2.8.0 +- Contain **[VCFanno](https://github.com/brentp/vcfanno)** 0.3.2 - Contain **[VCFtools](https://vcftools.github.io/index.html)** 0.1.16 -- Contain **[VEP](https://github.com/Ensembl/ensembl-vep)** 95.2 +- Contain **[VEP](https://github.com/Ensembl/ensembl-vep)** 98.2 ### sareksnpeff [![sareksnpeff-docker status](https://img.shields.io/docker/automated/nfcore/sareksnpeff.svg)](https://hub.docker.com/r/nfcore/sareksnpeff) @@ -45,7 +45,7 @@ For annotation, the main container can be used, but the cache has to be download - Based on `nfcore/base:latest` - Contain **[GeneSplicer](https://ccb.jhu.edu/software/genesplicer/)** 1.0 -- Contain **[VEP](https://github.com/Ensembl/ensembl-vep)** 95.2 +- Contain **[VEP](https://github.com/Ensembl/ensembl-vep)** 98.2 - Contain cache for `GRCh37`, `GRCh38`, `GRCm38` or `CanFam3.1` ## Using helper script diff --git a/environment.yml b/environment.yml index 94ca2d5a19..797ba0c1ae 100644 --- a/environment.yml +++ b/environment.yml @@ -10,19 +10,19 @@ dependencies: - bcftools=1.9 - bwa=0.7.17 - cancerit-allelecount=4.0.2 - - control-freec=11.4 - - ensembl-vep=95.2 + - control-freec=11.5 + - ensembl-vep=98.2 - fastqc=0.11.8 - - freebayes=1.2.0 - - gatk4=4.1.2.0 + - freebayes=1.3.1 + - gatk4=4.1.4.0 - genesplicer=1.0 - htslib=1.9 - - manta=1.5.0 + - manta=1.6.0 - multiqc=1.7 - - qualimap=2.2.2b + - qualimap=2.2.2c - samtools=1.9 - snpeff=4.3.1t - strelka=2.9.10 - - tiddit=2.7.1 - - vcfanno=0.3.1 + - tiddit=2.8.0 + - vcfanno=0.3.2 - vcftools=0.1.16 \ No newline at end of file From 0dd946135d77c6051d2090b5b0531e158344cd5a Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Wed, 9 Oct 2019 17:59:01 +0200 Subject: [PATCH 103/854] minor updates + typo fix (#42) * minor updates + typo fix --- CHANGELOG.md | 1 + README.md | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb7262e651..bf85a9f1a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### `Fixed` - [#40](https://github.com/nf-core/sarek/pull/40) - Fix issue with `publishDirMode` within `test` profile +- [#42](https://github.com/nf-core/sarek/pull/42) - Fix typos, and minor updates in `README.md` ## [2.5] - Ålkatj diff --git a/README.md b/README.md index 8b4cfdff20..0de61ba17c 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ across multiple compute infrastructures in a very portable manner. Software dependencies are handled using [Conda](https://conda.io/), [Docker](https://www.docker.com) or [Singularity](https://www.sylabs.io/singularity/) - environment/container technologies that provide excellent reproducibility and ease of use. Thus making installation trivial and results highly reproducible. -It's listed on the [Elixir - Tools and Data Services Registry](https://bio.tools/Sarek), [Dockstore](https://dockstore.org/workflows/github.com/SciLifeLab/Sarek/) and [omicX - Bioinformatics tools](https://omictools.com/sarek-tool). +It's listed on the [Elixir - Tools and Data Services Registry](https://bio.tools/Sarek), [Dockstore](https://dockstore.org/workflows/github.com/nf-core/sarek) and [omicX - Bioinformatics tools](https://omictools.com/sarek-tool). ## Documentation @@ -98,7 +98,7 @@ For further information or help, don't hesitate to get in touch on [Slack](https If you use `nf-core/sarek` for your analysis, please cite the `Sarek` pre-print as follows: > Garcia MU, Juhos S, Larsson M, Olason PI, Martin M, Eisfeldt J, DiLorenzo S, Sandgren J, de Ståhl TD, Wirta V, Nistér M, Nystedt B, Käller M. **Sarek: A portable workflow for whole-genome sequencing analysis of germline and somatic variants**. *bioRxiv*. 2018. p. 316976. [doi: 10.1101/316976](https://www.biorxiv.org/content/10.1101/316976v1). -You can cite the sarek zenodo record for a specific version using the following [DOI: 10.5281/zenodo.3476426](https://zenodo.org/badge/latestdoi/184289291) +You can cite the sarek zenodo record for a specific version using the following [doi: 10.5281/zenodo.3476426](https://zenodo.org/badge/latestdoi/184289291) You can cite the `nf-core` pre-print as follows: > Ewels PA, Peltzer A, Fillinger S, Alneberg JA, Patel H, Wilm A, Garcia MU, Di Tommaso P, Nahnsen S. **nf-core: Community curated bioinformatics pipelines**. *bioRxiv*. 2019. p. 610741. [doi: 10.1101/610741](https://www.biorxiv.org/content/10.1101/610741v3). From 9c977def770a624aae189cfb67a4897f420be1e9 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Thu, 10 Oct 2019 09:38:49 +0200 Subject: [PATCH 104/854] fix VEP automated builds --- .circleci/config.yml | 8 ++++---- CHANGELOG.md | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0af952fcb0..582f2750a9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -40,7 +40,7 @@ jobs: environment: GENOME: GRCh37 SPECIES: homo_sapiens - VEP_VERSION: "95" + VEP_VERSION: "98" steps: - checkout - setup_remote_docker @@ -55,21 +55,21 @@ jobs: environment: GENOME: GRCh38 SPECIES: homo_sapiens - VEP_VERSION: "95" + VEP_VERSION: "98" vepgrcm38: << : *buildvep environment: GENOME: GRCm38 SPECIES: mus_musculus - VEP_VERSION: "95" + VEP_VERSION: "98" vepcanfam3_1: << : *buildvep environment: GENOME: CanFam3.1 SPECIES: canis_familiaris - VEP_VERSION: "95" + VEP_VERSION: "98" workflows: version: 2 diff --git a/CHANGELOG.md b/CHANGELOG.md index c9cf5a70a5..436428b1c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [#40](https://github.com/nf-core/sarek/pull/40) - Fix issue with `publishDirMode` within `test` profile - [#42](https://github.com/nf-core/sarek/pull/42) - Fix typos, and minor updates in `README.md` +- [#43](https://github.com/nf-core/sarek/pull/43) - Fix automated `VEP` builds with circleCI ## [2.5] - Ålkatj From 0bec6946ce11c429bce2a1a0bc01aefc657dcd29 Mon Sep 17 00:00:00 2001 From: Malin Larsson Date: Thu, 10 Oct 2019 10:25:49 +0200 Subject: [PATCH 105/854] Update ascat.md We have updated so that the Y-chromosome is treated like the X-chromosome in male samples. --- docs/ascat.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ascat.md b/docs/ascat.md index 1d30647a77..dd09587316 100644 --- a/docs/ascat.md +++ b/docs/ascat.md @@ -23,7 +23,7 @@ LogRi(tumor)=log2((countsAi(tumor)+countsBi(tumor))/(countsAi(normal)+countsBi(n LogRi(normal)=0 ``` -For male samples, the X chromosome markers have special treatment: +For male samples, the X and Y chromosome markers have special treatment: ```R LogRi(tumor)=log2((countsAi(tumor)+countsBi(tumor))/(countsAi(normal)+countsBi(normal))-1 - median(log2((countsA(tumor)+countsB(tumor))/(countsA(normal)+countsB(normal))-1) From 15f28509412a0c06839f8b8e6d43ade7979d59fc Mon Sep 17 00:00:00 2001 From: Malin Larsson Date: Thu, 10 Oct 2019 11:36:26 +0200 Subject: [PATCH 106/854] Update docs/install_bianca.md Co-Authored-By: Maxime Garcia --- docs/install_bianca.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/install_bianca.md b/docs/install_bianca.md index dfbf9aa96a..e395f9e387 100644 --- a/docs/install_bianca.md +++ b/docs/install_bianca.md @@ -146,7 +146,8 @@ So every member of the project who wants to use nf-core/sarek will need to do: > ln -s /castor/project/proj_nobackup/sarek/default sarek ``` -Singularity images for Sarek are available on Uppmax in /sw/data/uppnex/ToolBox/sarek. Sometimes nextflow needs write access to the image folder, and if so the images needs to be copied to a location with write permission, for example in a subfolder of your project folder. +Singularity images for Sarek are available on Uppmax in `/sw/data/uppnex/ToolBox/sarek`. +Sometimes Nextflow needs write access to the image folder, and if so the images needs to be copied to a location with write permission, for example in a subfolder of your project folder. ```bash #Create a folder for the singularity images somewhere in your project: mkdir sarek_simg From faf0ab6e0eed97b35501e50686862069ec9d95ae Mon Sep 17 00:00:00 2001 From: Malin Larsson Date: Thu, 10 Oct 2019 11:37:05 +0200 Subject: [PATCH 107/854] Update docs/install_bianca.md Co-Authored-By: Maxime Garcia --- docs/install_bianca.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/install_bianca.md b/docs/install_bianca.md index e395f9e387..57bb030a7f 100644 --- a/docs/install_bianca.md +++ b/docs/install_bianca.md @@ -148,6 +148,7 @@ So every member of the project who wants to use nf-core/sarek will need to do: Singularity images for Sarek are available on Uppmax in `/sw/data/uppnex/ToolBox/sarek`. Sometimes Nextflow needs write access to the image folder, and if so the images needs to be copied to a location with write permission, for example in a subfolder of your project folder. + ```bash #Create a folder for the singularity images somewhere in your project: mkdir sarek_simg From e5352e09408969b3a3d48c1405de0ca4ccd1ff9d Mon Sep 17 00:00:00 2001 From: Malin Larsson Date: Thu, 10 Oct 2019 11:37:22 +0200 Subject: [PATCH 108/854] Update docs/install_bianca.md Co-Authored-By: Maxime Garcia --- docs/install_bianca.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install_bianca.md b/docs/install_bianca.md index 57bb030a7f..abbacd22e7 100644 --- a/docs/install_bianca.md +++ b/docs/install_bianca.md @@ -153,7 +153,7 @@ Sometimes Nextflow needs write access to the image folder, and if so the images #Create a folder for the singularity images somewhere in your project: mkdir sarek_simg -#Copy the relevant singularity image from the write protected folder on Uppmax to the fodler where you have write permission: +#Copy the relevant singularity image from the write protected folder on Uppmax to the folder where you have write permission: cp /sw/data/uppnex/ToolBox/sarek/nfcore-sarek-dev.img /path/to/your/sarek_simg/. #Update the ENV parameter NXF_SINGULARITY_CACHEDIR From cf7a7488d097d872bd83db3d2ad4b5ea9a90b30b Mon Sep 17 00:00:00 2001 From: Malin Larsson Date: Thu, 10 Oct 2019 11:37:36 +0200 Subject: [PATCH 109/854] Update docs/install_bianca.md Co-Authored-By: Maxime Garcia --- docs/install_bianca.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/install_bianca.md b/docs/install_bianca.md index abbacd22e7..08df55d7f7 100644 --- a/docs/install_bianca.md +++ b/docs/install_bianca.md @@ -167,7 +167,8 @@ And then nf-core/sarek can be used with: ``` This command worked on Bianca 20190906: -``` + +```bash >screen -S SAMPLE /path/to/nextflow run /path/to/sarek/main.nf -profile uppmax --project PROJID --sample SAMPLE.tsv --genome GRCh37 --genomes_base /sw/data/uppnex/ToolBox/ReferenceAssemblies/hg38make/bundle/2.8/b37 --step variantcalling --tools ASCAT --igenomesIgnore #To detach screen: From 6a21836bc25add5ece810a5ad7bf22ef17b72462 Mon Sep 17 00:00:00 2001 From: Malin Larsson Date: Thu, 10 Oct 2019 11:38:07 +0200 Subject: [PATCH 110/854] Update bin/run_ascat.r Co-Authored-By: Maxime Garcia --- bin/run_ascat.r | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/run_ascat.r b/bin/run_ascat.r index beefb76cfb..ebb5f41a77 100755 --- a/bin/run_ascat.r +++ b/bin/run_ascat.r @@ -13,7 +13,6 @@ if(length(args)<6){ gender = args[8] } -#source(paste(baseDir,"/scripts/ascat.R", sep="")) library(ASCAT) if(!require(RColorBrewer)){ From e4ca71c530632a565083009d0602c978033d6f0a Mon Sep 17 00:00:00 2001 From: Malin Larsson Date: Thu, 10 Oct 2019 11:39:06 +0200 Subject: [PATCH 111/854] Update bin/run_ascat.r Co-Authored-By: Maxime Garcia --- bin/run_ascat.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/run_ascat.r b/bin/run_ascat.r index ebb5f41a77..991a64d7e6 100755 --- a/bin/run_ascat.r +++ b/bin/run_ascat.r @@ -19,7 +19,7 @@ if(!require(RColorBrewer)){ source("http://bioconductor.org/biocLite.R") biocLite("RColorBrewer", suppressUpdates=TRUE, lib="$baseDir/scripts") library(RColorBrewer) -}ls +} options(bitmapType='cairo') #Load the data From 5149780a1cf1275e99412cf966bbdfd7d0a54947 Mon Sep 17 00:00:00 2001 From: Malin Larsson Date: Thu, 10 Oct 2019 11:54:03 +0200 Subject: [PATCH 112/854] preparing branch for PR to nf-core --- .gitmodules | 7 - configs | 1 - scripts/ascat.R | 2181 ----------------------------------------------- 3 files changed, 2189 deletions(-) delete mode 100644 .gitmodules delete mode 160000 configs delete mode 100755 scripts/ascat.R diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 4944a7aa47..0000000000 --- a/.gitmodules +++ /dev/null @@ -1,7 +0,0 @@ -[submodule "configs"] - path = configs - url = https://github.com/nf-core/configs.git -[submodule "data"] - path = data - url = https://github.com/nf-core/test-datasets.git - branch = sarek diff --git a/configs b/configs deleted file mode 160000 index 836da97efd..0000000000 --- a/configs +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 836da97efdd3b9be3a0715c57ae58ee5d85e3c98 diff --git a/scripts/ascat.R b/scripts/ascat.R deleted file mode 100755 index 85ad6d9042..0000000000 --- a/scripts/ascat.R +++ /dev/null @@ -1,2181 +0,0 @@ -##########LICENCE########## -# Copyright (c) 2014 Genome Research Ltd. -# -# Author: Peter Van Loo -# -# This file is part of AscatNGS. -# -# AscatNGS is free software: you can redistribute it and/or modify it under -# the terms of the GNU Affero General Public License as published by the Free -# Software Foundation; either version 3 of the License, or (at your option) any -# later version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more -# details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -##########LICENCE########## - -# ASCAT version 2.3, 15/07/2014 -# author: Peter Van Loo -# PCF and ASPCF: Gro Nilsen -# GC correction: Jiqiu Cheng - -# function to read in SNP array data -# input: filenames of tumor LogR, tumor BAF, germline LogR and germline BAF data -# germline data files can be NULL - in that case these are not read in -# output: a data structure containing: -# 1. Tumor_LogR data matrix -# 2. Tumor_BAF data matrix -# 3. Tumor_LogR_segmented: placeholder, NULL -# 4. Tumor_BAF_segmented: placeholder, NULL -# 5. Germline_LogR data matrix -# 6. Germline_BAF data matrix -# 7. SNPpos: position of all SNPs -# 8. ch: a list containing vectors with the indices for each chromosome (e.g. Tumor_LogR[ch[[13]],] will output the Tumor_LogR data of chromosome 13 -# 9. chr: a list containing vectors with the indices for each distinct part that can be segmented separately (e.g. chromosome arm, stretch of DNA between gaps in the array design) -# 10. gender: a vector of gender for each cases ("XX" or "XY"). Default = NULL: all female ("XX") -ascat.loadData = function(Tumor_LogR_file, Tumor_BAF_file, Germline_LogR_file = NULL, Germline_BAF_file = NULL, chrs = c(1:22,"X","Y"), gender = NULL, sexchromosomes = c("X","Y")) { - - # read in SNP array data files - print.noquote("Reading Tumor LogR data...") - Tumor_LogR <- read.table(Tumor_LogR_file, header=T, row.names=1, comment.char="", sep = "\t", check.names=F) - print.noquote("Reading Tumor BAF data...") - Tumor_BAF <- read.table(Tumor_BAF_file, header=T, row.names=1, comment.char="", sep = "\t", check.names=F) - - #infinite values are a problem - change those - Tumor_LogR[Tumor_LogR==-Inf]=NA - Tumor_LogR[Tumor_LogR==Inf]=NA - - Germline_LogR = NULL - Germline_BAF = NULL - if(!is.null(Germline_LogR_file)) { - print.noquote("Reading Germline LogR data...") - Germline_LogR <- read.table(Germline_LogR_file, header=T, row.names=1, comment.char="", sep = "\t", check.names=F) - print.noquote("Reading Germline BAF data...") - Germline_BAF <- read.table(Germline_BAF_file, header=T, row.names=1, comment.char="", sep = "\t", check.names=F) - - #infinite values are a problem - change those - Germline_LogR[Germline_LogR==-Inf]=NA - Germline_LogR[Germline_LogR==Inf]=NA - } - - # make SNPpos vector that contains genomic position for all SNPs and remove all data not on chromosome 1-22,X,Y (or whatever is given in the input value of chrs) - print.noquote("Registering SNP locations...") - SNPpos <- Tumor_LogR[,1:2] - SNPpos = SNPpos[SNPpos[,1]%in%chrs,] - - # if some chromosomes have no data, just remove them - chrs = intersect(chrs,unique(SNPpos[,1])) - - Tumor_LogR = Tumor_LogR[rownames(SNPpos),c(-1,-2),drop=F] - Tumor_BAF = Tumor_BAF[rownames(SNPpos),c(-1,-2),drop=F] - # make sure it is all converted to numerical values - for (cc in 1:dim(Tumor_LogR)[2]) { - Tumor_LogR[,cc]=as.numeric(as.vector(Tumor_LogR[,cc])) - Tumor_BAF[,cc]=as.numeric(as.vector(Tumor_BAF[,cc])) - } - - if(!is.null(Germline_LogR_file)) { - Germline_LogR = Germline_LogR[rownames(SNPpos),c(-1,-2),drop=F] - Germline_BAF = Germline_BAF[rownames(SNPpos),c(-1,-2),drop=F] - for (cc in 1:dim(Germline_LogR)[2]) { - Germline_LogR[,cc]=as.numeric(as.vector(Germline_LogR[,cc])) - Germline_BAF[,cc]=as.numeric(as.vector(Germline_BAF[,cc])) - } - } - - # sort all data by genomic position - last = 0; - ch = list(); - SNPorder = vector(length=dim(SNPpos)[1]) - for (i in 1:length(chrs)) { - chrke = SNPpos[SNPpos[,1]==chrs[i],] - chrpos = chrke[,2] - names(chrpos) = rownames(chrke) - chrpos = sort(chrpos) - ch[[i]] = (last+1):(last+length(chrpos)) - SNPorder[ch[[i]]] = names(chrpos) - last = last+length(chrpos) - } - SNPpos = SNPpos[SNPorder,] - Tumor_LogR=Tumor_LogR[SNPorder,,drop=F] - Tumor_BAF=Tumor_BAF[SNPorder,,drop=F] - - if(!is.null(Germline_LogR_file)) { - Germline_LogR = Germline_LogR[SNPorder,,drop=F] - Germline_BAF = Germline_BAF[SNPorder,,drop=F] - } - - # split the genome into distinct parts to be used for segmentation (e.g. chromosome arms, parts of genome between gaps in array design) - print.noquote("Splitting genome in distinct chunks...") - chr = split_genome(SNPpos) - - if (is.null(gender)) { - gender = rep("XX",dim(Tumor_LogR)[2]) - } - return(list(Tumor_LogR = Tumor_LogR, Tumor_BAF = Tumor_BAF, - Tumor_LogR_segmented = NULL, Tumor_BAF_segmented = NULL, - Germline_LogR = Germline_LogR, Germline_BAF = Germline_BAF, - SNPpos = SNPpos, ch = ch, chr = chr, chrs = chrs, - samples = colnames(Tumor_LogR), gender = gender, - sexchromosomes = sexchromosomes, - failedarrays = NULL)) -} - - - - -# plots SNP array data -# input: an ASCAT object (e.g. from ASCAT.loaddata and plots the SNP array data -ascat.plotRawData = function(ASCATobj) { - print.noquote("Plotting tumor data") - for (i in 1:dim(ASCATobj$Tumor_LogR)[2]) { - png(filename = paste(ASCATobj$samples[i],".tumour.png",sep=""), width = 2000, height = 1000, res = 200) - par(mar = c(0.5,5,5,0.5), mfrow = c(2,1), cex = 0.4, cex.main=3, cex.axis = 2, pch = ifelse(dim(ASCATobj$Tumor_LogR)[1]>100000,".",20)) - plot(c(1,dim(ASCATobj$Tumor_LogR)[1]), c(-1,1), type = "n", xaxt = "n", main = paste(ASCATobj$samples[i], ", tumor data, LogR", sep = ""), xlab = "", ylab = "") - points(ASCATobj$Tumor_LogR[,i],col="red") - abline(v=0.5,lty=1,col="lightgrey") - chrk_tot_len = 0 - for (j in 1:length(ASCATobj$ch)) { - chrk = ASCATobj$ch[[j]]; - chrk_tot_len_prev = chrk_tot_len - chrk_tot_len = chrk_tot_len + length(chrk) - vpos = chrk_tot_len; - tpos = (chrk_tot_len+chrk_tot_len_prev)/2; - text(tpos,1,ASCATobj$chrs[j], pos = 1, cex = 2) - abline(v=vpos+0.5,lty=1,col="lightgrey") - } - plot(c(1,dim(ASCATobj$Tumor_BAF)[1]), c(0,1), type = "n", xaxt = "n", main = paste(ASCATobj$samples[i], ", tumor data, BAF", sep = ""), xlab = "", ylab = "") - points(ASCATobj$Tumor_BAF[,i],col="red") - abline(v=0.5,lty=1,col="lightgrey") - chrk_tot_len = 0 - for (j in 1:length(ASCATobj$ch)) { - chrk = ASCATobj$ch[[j]]; - chrk_tot_len_prev = chrk_tot_len - chrk_tot_len = chrk_tot_len + length(chrk) - vpos = chrk_tot_len; - tpos = (chrk_tot_len+chrk_tot_len_prev)/2; - text(tpos,1,ASCATobj$chrs[j], pos = 1, cex = 2) - abline(v=vpos+0.5,lty=1,col="lightgrey") - } - dev.off() - } - - if(!is.null(ASCATobj$Germline_LogR)) { - print.noquote("Plotting germline data") - for (i in 1:dim(ASCATobj$Germline_LogR)[2]) { - png(filename = paste(ASCATobj$samples[i],".germline.png",sep=""), width = 2000, height = 1000, res = 200) - par(mar = c(0.5,5,5,0.5), mfrow = c(2,1), cex = 0.4, cex.main=3, cex.axis = 2, pch = ifelse(dim(ASCATobj$Tumor_LogR)[1]>100000,".",20)) - plot(c(1,dim(ASCATobj$Germline_LogR)[1]), c(-1,1), type = "n", xaxt = "n", main = paste(ASCATobj$samples[i], ", germline data, LogR", sep = ""), xlab = "", ylab = "") - points(ASCATobj$Germline_LogR[,i],col="red") - abline(v=0.5,lty=1,col="lightgrey") - chrk_tot_len = 0 - for (j in 1:length(ASCATobj$ch)) { - chrk = ASCATobj$ch[[j]]; - chrk_tot_len_prev = chrk_tot_len - chrk_tot_len = chrk_tot_len + length(chrk) - vpos = chrk_tot_len; - tpos = (chrk_tot_len+chrk_tot_len_prev)/2; - text(tpos,1,ASCATobj$chrs[j], pos = 1, cex = 2) - abline(v=vpos+0.5,lty=1,col="lightgrey") - } - plot(c(1,dim(ASCATobj$Germline_BAF)[1]), c(0,1), type = "n", xaxt = "n", main = paste(ASCATobj$samples[i], ", germline data, BAF", sep = ""), xlab = "", ylab = "") - points(ASCATobj$Germline_BAF[,i],col="red") - abline(v=0.5,lty=1,col="lightgrey") - chrk_tot_len = 0 - for (j in 1:length(ASCATobj$ch)) { - chrk = ASCATobj$ch[[j]]; - chrk_tot_len_prev = chrk_tot_len - chrk_tot_len = chrk_tot_len + length(chrk) - vpos = chrk_tot_len; - tpos = (chrk_tot_len+chrk_tot_len_prev)/2; - text(tpos,1,ASCATobj$chrs[j], pos = 1, cex = 2) - abline(v=vpos+0.5,lty=1,col="lightgrey") - } - dev.off() - } - } -} - - -##################################################################################### -# -# This version of the GCcorrect funtion was debugged by Malin Larsson in July 2016 -# -##################################################################################### - -# note that probes not present in the GCcontentfile will be lost from the results -ascat.GCcorrect = function(ASCATobj, GCcontentfile = NULL) { - if(is.null(GCcontentfile)) { - print.noquote("Error: no GC content file given!") - } - else { - GC_newlist<-read.table(file=GCcontentfile,header=TRUE, row.names=1, as.is=TRUE) - #colnames(GC_newlist)[c(1,2)] = c("Chr","Position") - GC_newlist$Chr<-as.character(GC_newlist$Chr) - GC_newlist$Position<-as.numeric(as.character(GC_newlist$Position)) - - ovl = intersect(row.names(ASCATobj$Tumor_LogR),row.names(GC_newlist)) - - GC_newlist<-GC_newlist[ovl,] - - SNPpos = ASCATobj$SNPpos[ovl,] - Tumor_LogR = ASCATobj$Tumor_LogR[ovl,,drop=F] - Tumor_BAF = ASCATobj$Tumor_BAF[ovl,,drop=F] - - Germline_LogR = NULL - Germline_BAF = NULL - if(!is.null(ASCATobj$Germline_LogR)) { - Germline_LogR = ASCATobj$Germline_LogR[ovl,,drop=F] - Germline_BAF = ASCATobj$Germline_BAF[ovl,,drop=F] - } - - for (s in 1:length(ASCATobj$samples)) { - print.noquote(paste("Sample ", ASCATobj$samples[s], " (",s,"/",length(ASCATobj$samples),")",sep="")) - Tumordata = Tumor_LogR[,s] - names(Tumordata) = rownames(Tumor_LogR) - - # Calculate weighted correlation - length_tot<-NULL - corr_tot<-NULL - for(chrindex in unique(SNPpos[,1])) { - GC_newlist_chr<-GC_newlist[GC_newlist$Chr==chrindex,] - td_chr<-Tumordata[GC_newlist$Chr==chrindex] - - flag_nona<-(complete.cases(td_chr) & complete.cases(GC_newlist_chr)) - corr<-cor(GC_newlist_chr[flag_nona,3:ncol(GC_newlist_chr)],td_chr[flag_nona]) - corr_tot<-cbind(corr_tot,corr) - length_tot<-c(length_tot,length(td_chr)) - } - corr<-apply(corr_tot,1,function(x) sum(abs(x*length_tot))/sum(length_tot)) - - #old code: - #index_1M<-c(which(names(corr)=="X1M"),which(names(corr)=="X1Mb")) - #maxGCcol_short<-which(corr[1:(index_1M-1)]==max(corr[1:(index_1M-1)])) - #maxGCcol_long<-which(corr[index_1M:length(corr)]==max(corr[index_1M:length(corr)])) - #maxGCcol_long<-(maxGCcol_long+(index_1M-1)) - - #Updated by Malin: - index_1000bp<-which(names(corr)=="X1000bp") - maxGCcol_short<-which(corr[1:(index_1000bp-1)]==max(corr[1:(index_1000bp-1)])) - maxGCcol_long<-which(corr[index_1000bp:length(corr)]==max(corr[index_1000bp:length(corr)])) - maxGCcol_long<-(maxGCcol_long+(index_1000bp-1)) - - cat("weighted correlation: ",paste(names(corr),format(corr,digits=2), ";"),"\n") - cat("Short window size: ",names(GC_newlist)[maxGCcol_short+2],"\n") - cat("Long window size: ",names(GC_newlist)[maxGCcol_long+2],"\n") - - # Multiple regression - flag_NA<-(is.na(Tumordata))|(is.na(GC_newlist[,2+maxGCcol_short]))|(is.na(GC_newlist[,2+maxGCcol_long])) - td_select<-Tumordata[!flag_NA] - GC_newlist_select <- GC_newlist[!flag_NA,] - x1<-GC_newlist_select[,2+maxGCcol_short] - x2<-GC_newlist_select[,2+maxGCcol_long] - x3<-(x1)^2 - x4<-(x2)^2 - model<-lm(td_select~x1+x2+x3+x4,y=TRUE) - - GCcorrected<-Tumordata - GCcorrected[]<-NA - GCcorrected[!flag_NA] <- model$residuals - - Tumor_LogR[,s] = GCcorrected - } - - # add some plotting code for each sample while it is generated!!!! - - return(list(Tumor_LogR = Tumor_LogR, Tumor_BAF = Tumor_BAF, - Tumor_LogR_segmented = NULL, Tumor_BAF_segmented = NULL, - Germline_LogR = Germline_LogR, Germline_BAF = Germline_BAF, - SNPpos = SNPpos, ch = ASCATobj$ch, chr = ASCATobj$chr, chrs = ASCATobj$chrs, - samples = colnames(Tumor_LogR), gender = ASCATobj$gender, - sexchromosomes = ASCATobj$sexchromosomes)) - } -} - - - - -# run ASPCF segmentation -# input: (i) an ASCAT object from e.g. ASCAT.loaddata; -# (ii) selectsamples: a vector containing the sample(number)s to PCF otherwise -# (iii) germline genotypes (NULL if germline data is available) -# (iv) penalty: penalty of introducing an additional ASPCF breakpoint (expert parameter, don't adapt unless you know what you're doing) -# output: a data structure containing: -# 1. Tumor_LogR data matrix -# 2. Tumor_BAF data matrix -# 3. Tumor_LogR_segmented: matrix of LogR segmented values -# 4. Tumor_BAF_segmented: list of BAF segmented values; each element in the list is a matrix containing the segmented values for one sample (only for probes that are germline homozygous) -# 5. Germline_LogR data matrix -# 6. Germline_BAF data matrix -# 7. SNPpos: position of all SNPs -# 8. ch: a list containing vectors with the indices for each chromosome (e.g. Tumor_LogR[ch[[13]],] will output the Tumor_LogR data of chromosome 13 -# 9. chr: a list containing vectors with the indices for each distinct part that can be segmented separately (e.g. chromosome arm, stretch of DNA between gaps in the array design) -# note: this function can be easily parallelized by controlling the selectsamples parameter -# it saves the results in LogR_PCFed[sample]_[segment].txt and BAF_PCFed[sample]_[segment].txt -# if these files exist, the results are read from the files -# hence, after parallelization, copy all the files into the current directory, and run this function to read in the results -ascat.aspcf = function(ASCATobj, selectsamples = 1:length(ASCATobj$samples), ascat.gg = NULL, penalty = 25) { - #first, set germline genotypes - gg = NULL - if(!is.null(ascat.gg)) { - gg = ascat.gg$germlinegenotypes - } - else { - gg = ASCATobj$Germline_BAF < 0.3 | ASCATobj$Germline_BAF > 0.7 - } - # calculate germline homozygous stretches for later resegmentation - ghs = predictGermlineHomozygousStretches(ASCATobj$chr, gg) - - segmentlengths = unique(c(penalty,25,50,100,200,400,800)) - segmentlengths = segmentlengths[segmentlengths>=penalty] - - Tumor_LogR_segmented = matrix(nrow = dim(ASCATobj$Tumor_LogR)[1], ncol = dim(ASCATobj$Tumor_LogR)[2]) - rownames(Tumor_LogR_segmented) = rownames(ASCATobj$Tumor_LogR) - colnames(Tumor_LogR_segmented) = colnames(ASCATobj$Tumor_LogR) - Tumor_BAF_segmented = list(); - for (sample in selectsamples) { - print.noquote(paste("Sample ", ASCATobj$samples[sample], " (",sample,"/",length(ASCATobj$samples),")",sep="")) - logrfilename = paste(ASCATobj$samples[sample],".LogR.PCFed.txt",sep="") - baffilename = paste(ASCATobj$samples[sample],".BAF.PCFed.txt",sep="") - logRPCFed = numeric(0) - bafPCFed = numeric(0) - if(length(dir(pattern=logrfilename))==0 || length(dir(pattern=baffilename))==0) { - for (segmentlength in segmentlengths) { - logRPCFed = numeric(0) - bafPCFed = numeric(0) - tbsam = ASCATobj$Tumor_BAF[,sample] - names(tbsam) = rownames(ASCATobj$Tumor_BAF) - homosam = gg[,sample] - for (chrke in 1:length(ASCATobj$chr)) { - lr = ASCATobj$Tumor_LogR[ASCATobj$chr[[chrke]],sample] - #winsorize to remove outliers - #this has a problem with NAs - lrwins = vector(mode="numeric",length=length(lr)) - lrwins[is.na(lr)] = NA - lrwins[!is.na(lr)] = madWins(lr[!is.na(lr)],2.5,25)$ywin - baf = tbsam[ASCATobj$chr[[chrke]]] - homo = homosam[ASCATobj$chr[[chrke]]] - Select_het <- !homo & !is.na(homo) & !is.na(baf) & !is.na(lr) - bafsel = baf[Select_het] - # winsorize BAF as well (as a safeguard) - bafselwinsmirrored = madWins(ifelse(bafsel>0.5,bafsel,1-bafsel),2.5,25)$ywin - bafselwins = ifelse(bafsel>0.5,bafselwinsmirrored,1-bafselwinsmirrored) - indices = which(Select_het) - logRaveraged = NULL; - if(length(indices)!=0) { - averageIndices = c(1,(indices[1:(length(indices)-1)]+indices[2:length(indices)])/2,length(lr)+0.01) - startindices = ceiling(averageIndices[1:(length(averageIndices)-1)]) - endindices = floor(averageIndices[2:length(averageIndices)]-0.01) - if(length(indices)==1) { - startindices = 1 - endindices = length(lr) - } - nrIndices = endindices - startindices + 1 - logRaveraged = vector(mode="numeric",length=length(indices)) - for(i in 1:length(indices)) { - if(is.na(endindices[i])) { - endindices[i]=startindices[i] - } - logRaveraged[i]=mean(lrwins[startindices[i]:endindices[i]], na.rm=T) - } - } - # if there are no probes in the segment (after germline homozygous removal), don't do anything, except add a LogR segment - if(length(logRaveraged)>0) { - logRASPCF = NULL - bafASPCF = NULL - if(length(logRaveraged)<6) { - logRASPCF = rep(mean(logRaveraged),length(logRaveraged)) - bafASPCF = rep(mean(bafselwins),length(logRaveraged)) - } - else { - PCFed = fastAspcf(logRaveraged,bafselwins,6,segmentlength) - logRASPCF = PCFed$yhat1 - bafASPCF = PCFed$yhat2 - } - names(bafASPCF)=names(indices) - logRc = numeric(0) - for(probe in 1:length(logRASPCF)) { - if(probe == 1) { - logRc = rep(logRASPCF[probe],indices[probe]) - } - # if probe is 1, set the beginning, and let the loop go: - if(probe == length(logRASPCF)) { - logRc = c(logRc,rep(logRASPCF[probe],length(lr)-indices[probe])) - } - else if(logRASPCF[probe]==logRASPCF[probe+1]) { - logRc = c(logRc, rep(logRASPCF[probe],indices[probe+1]-indices[probe])) - } - else { - #find best breakpoint - d = numeric(0) - totall = indices[probe+1]-indices[probe] - for (bp in 0:(totall-1)) { - dis = sum(abs(lr[(1:bp)+indices[probe]]-logRASPCF[probe]), na.rm=T) - if(bp!=totall) { - dis = sum(dis, sum(abs(lr[((bp+1):totall)+indices[probe]]-logRASPCF[probe+1]), na.rm=T), na.rm=T) - } - d = c(d,dis) - } - breakpoint = which.min(d)-1 - logRc = c(logRc,rep(logRASPCF[probe],breakpoint),rep(logRASPCF[probe+1],totall-breakpoint)) - } - } - #2nd step: adapt levels! - logRd = numeric(0) - seg = make_seg_lr(logRc) - startprobe = 1 - endprobe = 0 - for (i in 1:length(seg)) { - endprobe = endprobe+seg[i] - level = mean(lr[startprobe:endprobe], na.rm=T) - logRd = c(logRd, rep(level,seg[i])) - startprobe = startprobe + seg[i] - } - logRPCFed = c(logRPCFed,logRd) - bafPCFed = c(bafPCFed,bafASPCF) - } - # add a LogR segment - else { - level = mean(lr,na.rm=T) - reps = length(lr) - logRPCFed = c(logRPCFed,rep(level,reps)) - } - # correct wrong segments in germline homozygous stretches: - homsegs = ghs[[sample]][ghs[[sample]][,1]==chrke,] - startchr = min(ASCATobj$chr[[chrke]]) - endchr = max(ASCATobj$chr[[chrke]]) - # to solve an annoying error when homsegs has length 1: - if(length(homsegs)==3) { - homsegs=t(as.matrix(homsegs)) - } - if(!is.null(homsegs)&&!is.na(homsegs)&&dim(homsegs)[1]!=0) { - for (i in 1:dim(homsegs)[1]) { - # note that only the germline homozygous segment is resegmented, plus a bit extra (but this is NOT replaced) - startpos = max(homsegs[i,2],startchr) - endpos = min(homsegs[i,3],endchr) - # PCF over a larger fragment - startpos2 = max(homsegs[i,2]-100,startchr) - endpos2 = min(homsegs[i,3]+100,endchr) - # take into account a little extra (difference between startpos2 and startpos3 is not changed) - startpos3 = max(homsegs[i,2]-5,startchr) - endpos3 = min(homsegs[i,3]+5,endchr) - # note that the parameters are arbitrary, but <100 seems to work on the ERBB2 example! - # segmentlength is lower here, as in the full data, noise on LogR is higher! - # do this on Winsorized data too! - towins = ASCATobj$Tumor_LogR[startpos2:endpos2,sample] - winsed = madWins(towins[!is.na(towins)],2.5,25)$ywin - pcfed = vector(mode="numeric",length=length(towins)) - pcfed[!is.na(towins)] = exactPcf(winsed,6,floor(segmentlength/4)) - pcfed2 = pcfed[(startpos3-startpos2+1):(endpos3-startpos2+1)] - dif = abs(pcfed2-logRPCFed[startpos3:endpos3]) - #0.3 is hardcoded here, in order not to have too many segments! - #only replace if enough probes differ (in order not to get singular probes with different breakpoints) - if(!is.na(dif)&&sum(dif>0.3)>5) { - #replace a bit more to make sure no 'lone' probes are left (startpos3 instead of startpos) - logRPCFed[startpos3:endpos3]=ifelse(dif>0.3,pcfed2,logRPCFed[startpos3:endpos3]) - } - } - } - } - #fill in NAs (otherwise they cause problems): - #some NA probes are filled in with zero, replace those too: - nakes = c(which(is.na(logRPCFed)),which(logRPCFed==0)) - nonnakes = which(!is.na(logRPCFed)&!(logRPCFed==0)) - if(length(nakes)>0) { - for (nake in 1:length(nakes)) { - pna = nakes[nake] - closestnonna = which.min(abs(nonnakes-pna)) - logRPCFed[pna] = logRPCFed[closestnonna] - } - } - #adapt levels again - seg = make_seg_lr(logRPCFed) - logRPCFed = numeric(0) - startprobe = 1 - endprobe = 0 - prevlevel = 0 - for (i in 1:length(seg)) { - endprobe = endprobe+seg[i] - level = mean(ASCATobj$Tumor_LogR[startprobe:endprobe,sample], na.rm=T) - #making sure no NA's get filled in... - if(is.nan(level)) { - level=prevlevel - } - else { - prevlevel=level - } - logRPCFed = c(logRPCFed, rep(level,seg[i])) - startprobe = startprobe + seg[i] - } - #put in names and write results to files - names(logRPCFed) = rownames(ASCATobj$Tumor_LogR) - - # if less than 800 segments: this segmentlength is ok, otherwise, rerun with higher segmentlength - if(length(unique(logRPCFed))<800) { - break - } - } - - write.table(logRPCFed,logrfilename,sep="\t",col.names=F) - write.table(bafPCFed,baffilename,sep="\t",col.names=F) - bafPCFed = as.matrix(bafPCFed) - } - else { - logRPCFed = read.table(logrfilename, sep="\t", header=F, row.names=1)[,1] - bafPCFed = read.table(baffilename, sep="\t", header=F, row.names=1) - } - Tumor_LogR_segmented[,sample] = logRPCFed - Tumor_BAF_segmented[[sample]] = 1-bafPCFed - } - - ASCATobj = list(Tumor_LogR = ASCATobj$Tumor_LogR, - Tumor_BAF = ASCATobj$Tumor_BAF, - Tumor_LogR_segmented = Tumor_LogR_segmented, - Tumor_BAF_segmented = Tumor_BAF_segmented, - Germline_LogR = ASCATobj$Germline_LogR, - Germline_BAF = ASCATobj$Germline_BAF, - SNPpos = ASCATobj$SNPpos, - ch = ASCATobj$ch, - chr = ASCATobj$chr, - chrs = ASCATobj$chrs, - samples = colnames(ASCATobj$Tumor_LogR), gender = ASCATobj$gender, - sexchromosomes = ASCATobj$sexchromosomes, failedarrays = ascat.gg$failedarrays) - return(ASCATobj) -} - - - -# plots SNP array data -# input: an ASCAT object (e.g. from ASCAT.ASPCF) and plots the SNP array data before and after segmentation -ascat.plotSegmentedData = function(ASCATobj) { - for (arraynr in 1:dim(ASCATobj$Tumor_LogR)[2]) { - Select_nonNAs = rownames(ASCATobj$Tumor_BAF_segmented[[arraynr]]) - AllIDs = 1:dim(ASCATobj$Tumor_LogR)[1] - names(AllIDs) = rownames(ASCATobj$Tumor_LogR) - HetIDs = AllIDs[Select_nonNAs] - png(filename = paste(ASCATobj$samples[arraynr],".ASPCF.png",sep=""), width = 2000, height = 1000, res = 200) - par(mar = c(0.5,5,5,0.5), mfrow = c(2,1), cex = 0.4, cex.main=3, cex.axis = 2) - r = ASCATobj$Tumor_LogR_segmented[rownames(ASCATobj$Tumor_BAF_segmented[[arraynr]]),arraynr] - beta = ASCATobj$Tumor_BAF_segmented[[arraynr]][,] - plot(c(1,length(r)), c(-1,1), type = "n", xaxt = "n", main = paste(colnames(ASCATobj$Tumor_BAF)[arraynr],", LogR",sep=""), xlab = "", ylab = "") - points(ASCATobj$Tumor_LogR[rownames(ASCATobj$Tumor_BAF_segmented[[arraynr]]),arraynr], col = "red", pch=ifelse(dim(ASCATobj$Tumor_LogR)[1]>100000,".",20)) - points(r,col="green") - abline(v=0.5,lty=1,col="lightgrey") - chrk_tot_len = 0 - for (j in 1:length(ASCATobj$ch)) { - chrk = intersect(ASCATobj$ch[[j]],HetIDs); - chrk_tot_len_prev = chrk_tot_len - chrk_tot_len = chrk_tot_len + length(chrk) - vpos = chrk_tot_len; - tpos = (chrk_tot_len+chrk_tot_len_prev)/2; - text(tpos,1,ASCATobj$chrs[j], pos = 1, cex = 2) - abline(v=vpos+0.5,lty=1,col="lightgrey") - } - plot(c(1,length(beta)), c(0,1), type = "n", xaxt = "n", main = paste(colnames(ASCATobj$Tumor_BAF)[arraynr],", BAF",sep=""), xlab = "", ylab = "") - points(ASCATobj$Tumor_BAF[rownames(ASCATobj$Tumor_BAF_segmented[[arraynr]]),arraynr], col = "red", pch=ifelse(dim(ASCATobj$Tumor_LogR)[1]>100000,".",20)) - points(beta, col = "green") - points(1-beta, col = "green") - abline(v=0.5,lty=1,col="lightgrey") - chrk_tot_len = 0 - for (j in 1:length(ASCATobj$ch)) { - chrk = intersect(ASCATobj$ch[[j]],HetIDs); - chrk_tot_len_prev = chrk_tot_len - chrk_tot_len = chrk_tot_len + length(chrk) - vpos = chrk_tot_len; - tpos = (chrk_tot_len+chrk_tot_len_prev)/2; - text(tpos,1,ASCATobj$chrs[j], pos = 1, cex = 2) - abline(v=vpos+0.5,lty=1,col="lightgrey") - } - dev.off() - } -} - - -# the ASCAT main function, calculating the allele-specific copy numbers -# input: (i) an ASCAT object from ascat.aspcf. -# (ii) gamma: technology parameter, compaction of Log R profiles (expected decrease in case of deletion in diploid sample, 100 % aberrant cells; 1 in ideal case, 0.55 of Illumina 109K arrays) -# (iii) rho_manual: optional argument to override ASCAT optimization and supply rho and psi parameters (not recommended) -# (iv) psi_manual: optional argument to override ASCAT optimization and supply rho and psi parameters (not recommended) -# output: an ASCAT output object, containing: -# 1. nA: copy number of the A allele -# 2. nB: copy number of the B allele -# 3. aberrantcellfraction: the aberrant cell fraction of all arrays -# 4. ploidy: the ploidy of all arrays -# 5. psi: ploidy parameter, an estimate of the tumour's ploidy for all arrays -# 6. goodnessOfFit: the goodness of fit for each copy number solution -# 7. failedarrays: arrays on which ASCAT analysis failed -# 8. nonaberrantarrays = arrays on which ASCAT analysis indicates that they so virtually no aberrations -# 9. segments: an array containing the copy number segments of each sample (not including failed arrays) -# 10. segments_raw: an array containing the copy number segments of each sample without any rounding applied -# note: for copy number only probes, nA contains the copy number value and nB = 0. -ascat.runAscat = function(ASCATobj, gamma = 0.55, rho_manual = NA, psi_manual = NA) { - goodarrays=NULL - res = vector("list",dim(ASCATobj$Tumor_LogR)[2]) - for (arraynr in 1:dim(ASCATobj$Tumor_LogR)[2]) { - print.noquote(paste("Sample ", ASCATobj$samples[arraynr], " (",arraynr,"/",length(ASCATobj$samples),")",sep="")) - lrr=ASCATobj$Tumor_LogR[,arraynr] - names(lrr)=rownames(ASCATobj$Tumor_LogR) - baf=ASCATobj$Tumor_BAF[,arraynr] - names(baf)=rownames(ASCATobj$Tumor_BAF) - lrrsegm = ASCATobj$Tumor_LogR_segmented[,arraynr] - names(lrrsegm) = rownames(ASCATobj$Tumor_LogR_segmented) - bafsegm = ASCATobj$Tumor_BAF_segmented[[arraynr]][,] - names(bafsegm) = rownames(ASCATobj$Tumor_BAF_segmented[[arraynr]]) - failedqualitycheck = F - if(ASCATobj$samples[arraynr]%in%ASCATobj$failedarrays) { - failedqualitycheck = T - } - if(is.na(rho_manual)) { - res[[arraynr]] = runASCAT(lrr,baf,lrrsegm,bafsegm,ASCATobj$gender[arraynr],ASCATobj$SNPpos,ASCATobj$ch,ASCATobj$chrs,ASCATobj$sexchromosomes, failedqualitycheck, - paste(ASCATobj$samples[arraynr],".sunrise.png",sep=""),paste(ASCATobj$samples[arraynr],".ASCATprofile.png",sep=""), - paste(ASCATobj$samples[arraynr],".rawprofile.png",sep=""),paste(ASCATobj$samples[arraynr],".aberrationreliability.png",sep=""), - gamma) - } else { - res[[arraynr]] = runASCAT(lrr,baf,lrrsegm,bafsegm,ASCATobj$gender[arraynr],ASCATobj$SNPpos,ASCATobj$ch,ASCATobj$chrs,ASCATobj$sexchromosomes, failedqualitycheck, - paste(ASCATobj$samples[arraynr],".sunrise.png",sep=""),paste(ASCATobj$samples[arraynr],".ASCATprofile.png",sep=""), - paste(ASCATobj$samples[arraynr],".rawprofile.png",sep=""),paste(ASCATobj$samples[arraynr],".aberrationreliability.png",sep=""), - gamma,rho_manual[arraynr],psi_manual[arraynr]) - } - if(!is.na(res[[arraynr]]$rho)) { - goodarrays[length(goodarrays)+1] = arraynr - } - } - - if(length(goodarrays)>0) { - n1 = matrix(nrow = dim(ASCATobj$Tumor_LogR)[1], ncol = length(goodarrays)) - n2 = matrix(nrow = dim(ASCATobj$Tumor_LogR)[1], ncol = length(goodarrays)) - rownames(n1) = rownames(ASCATobj$Tumor_LogR) - rownames(n2) = rownames(ASCATobj$Tumor_LogR) - colnames(n1) = colnames(ASCATobj$Tumor_LogR)[goodarrays] - colnames(n2) = colnames(ASCATobj$Tumor_LogR)[goodarrays] - for (i in 1:length(goodarrays)) { - n1[,i] = res[[goodarrays[i]]]$nA - n2[,i] = res[[goodarrays[i]]]$nB - } - - tp = vector(length=length(goodarrays)) - psi = vector(length=length(goodarrays)) - ploidy = vector(length=length(goodarrays)) - goodnessOfFit = vector(length=length(goodarrays)) - naarrays = NULL - for (i in 1:length(goodarrays)) { - tp[i] = res[[goodarrays[i]]]$rho - psi[i] = res[[goodarrays[i]]]$psi - ploidy[i] = mean(res[[goodarrays[i]]]$nA+res[[goodarrays[i]]]$nB,na.rm=T) - goodnessOfFit[i] = res[[goodarrays[i]]]$goodnessOfFit - if(res[[goodarrays[i]]]$nonaberrant) { - naarrays = c(naarrays,ASCATobj$samples[goodarrays[i]]) - } - } - fa = colnames(ASCATobj$Tumor_LogR)[-goodarrays] - names(tp) = colnames(n1) - names(ploidy) = colnames(n1) - names(psi) = colnames(n1) - names(goodnessOfFit) = colnames(n1) - - seg = NULL - for (i in 1:length(goodarrays)) { - segje = res[[goodarrays[i]]]$seg - seg = rbind(seg,cbind(ASCATobj$samples[goodarrays[i]],as.vector(ASCATobj$SNPpos[segje[,1],1]), - ASCATobj$SNPpos[segje[,1],2], - ASCATobj$SNPpos[segje[,2],2],segje[,3],segje[,4])) - } - colnames(seg) = c("sample","chr","startpos","endpos","nMajor","nMinor") - seg = data.frame(seg,stringsAsFactors=F) - seg[,3]=as.numeric(seg[,3]) - seg[,4]=as.numeric(seg[,4]) - seg[,5]=as.numeric(seg[,5]) - seg[,6]=as.numeric(seg[,6]) - - seg_raw = NULL - for (i in 1:length(goodarrays)) { - segje = res[[goodarrays[i]]]$seg_raw - seg_raw = rbind(seg_raw,cbind(ASCATobj$samples[goodarrays[i]],as.vector(ASCATobj$SNPpos[segje[,1],1]), - ASCATobj$SNPpos[segje[,1],2], - ASCATobj$SNPpos[segje[,2],2],segje[,3],segje[,4:ncol(segje)])) - - } - colnames(seg_raw) = c("sample","chr","startpos","endpos","nMajor","nMinor","nAraw","nBraw") - - seg_raw = data.frame(seg_raw,stringsAsFactors=F) - seg_raw[,3]=as.numeric(seg_raw[,3]) - seg_raw[,4]=as.numeric(seg_raw[,4]) - seg_raw[,5]=as.numeric(seg_raw[,5]) - seg_raw[,6]=as.numeric(seg_raw[,6]) - seg_raw[,7]=as.numeric(seg_raw[,7]) - seg_raw[,8]=as.numeric(seg_raw[,8]) - - } - else { - n1 = NULL - n2 = NULL - tp = NULL - ploidy = NULL - psi = NULL - goodnessOfFit = NULL - fa = colnames(ASCATobj$Tumor_LogR) - naarrays = NULL - seg = NULL - seg_raw = NULL - } - - return(list(nA = n1, nB = n2, aberrantcellfraction = tp, ploidy = ploidy, psi = psi, goodnessOfFit = goodnessOfFit, - failedarrays = fa, nonaberrantarrays = naarrays, segments = seg, segments_raw = seg_raw)) -} - - - - - -# helping function to read segments: -make_seg_lr = function(r) { - pcf_segments = numeric(0); - index = 0; - previousr = 1E10; - for (i in 1:length(r)) { - if (r[i] != previousr) { - index=index+1; - count=1; - } - else { - count = count + 1; - } - pcf_segments[index] = count; - previousr = r[i]; - } - return(pcf_segments); -} - - - -# helper function to split the genome into parts -split_genome = function(SNPpos) { - - # look for gaps of more than 5Mb (arbitrary treshold to account for big centremeres or other gaps) and chromosome borders - bigHoles = which(diff(SNPpos[,2])>=5000000)+1 - chrBorders = which(SNPpos[1:(dim(SNPpos)[1]-1),1]!=SNPpos[2:(dim(SNPpos)[1]),1])+1 - - holes = unique(sort(c(bigHoles,chrBorders))) - - # find which segments are too small - #joincandidates=which(diff(c(0,holes,dim(SNPpos)[1]))<200) - - # if it's the first or last segment, just join to the one next to it, irrespective of chromosome and positions - #while (1 %in% joincandidates) { - # holes=holes[-1] - # joincandidates=which(diff(c(0,holes,dim(SNPpos)[1]))<200) - #} - #while ((length(holes)+1) %in% joincandidates) { - # holes=holes[-length(holes)] - # joincandidates=which(diff(c(0,holes,dim(SNPpos)[1]))<200) - #} - - #while(length(joincandidates)!=0) { - # the while loop is because after joining, segments may still be too small.. - - #startseg = c(1,holes) - #endseg = c(holes-1,dim(SNPpos)[1]) - - # for each segment that is too short, see if it has the same chromosome as the segments before and after - # the next always works because neither the first or the last segment is in joincandidates now - #previoussamechr = SNPpos[endseg[joincandidates-1],1]==SNPpos[startseg[joincandidates],1] - #nextsamechr = SNPpos[endseg[joincandidates],1]==SNPpos[startseg[joincandidates+1],1] - - #distanceprevious = SNPpos[startseg[joincandidates],2]-SNPpos[endseg[joincandidates-1],2] - #distancenext = SNPpos[startseg[joincandidates+1],2]-SNPpos[endseg[joincandidates],2] - - # if both the same, decide based on distance, otherwise if one the same, take the other, if none, just take one. - #joins = ifelse(previoussamechr&nextsamechr, - # ifelse(distanceprevious>distancenext, joincandidates, joincandidates-1), - # ifelse(nextsamechr, joincandidates, joincandidates-1)) - - #holes=holes[-joins] - - #joincandidates=which(diff(c(0,holes,dim(SNPpos)[1]))<200) - #} - # if two neighboring segments are selected, this may make bigger segments then absolutely necessary, but I'm sure this is no problem. - - startseg = c(1,holes) - endseg = c(holes-1,dim(SNPpos)[1]) - - chr=list() - for (i in 1:length(startseg)) { - chr[[i]]=startseg[i]:endseg[i] - } - - return(chr) -} - - - -# helper function to predict germline homozygous segments for later resegmentation -predictGermlineHomozygousStretches = function(chr, hom) { - - # contains the result: a list of vectors of probe numbers in homozygous stretches for each sample - HomoStretches = list() - - for (sam in 1:dim(hom)[2]) { - homsam = hom[,sam] - - perchom = sum(homsam,na.rm=T)/sum(!is.na(homsam)) - - # NOTE THAT A P-VALUE THRESHOLD OF 0.001 IS HARDCODED HERE - homthres = ceiling(log(0.001,perchom)) - - allhprobes = NULL - for (chrke in 1:length(chr)) { - hschr = homsam[chr[[chrke]]] - - hprobes = vector(length=0) - for(probe in 1:length(hschr)) { - if(!is.na(hschr[probe])) { - if(hschr[probe]) { - hprobes = c(hprobes,probe) - } - else { - if(length(hprobes)>=homthres) { - allhprobes = rbind(allhprobes,c(chrke,chr[[chrke]][min(hprobes)],chr[[chrke]][max(hprobes)])) - } - hprobes = vector(length=0) - } - } - } - # if the last probe is homozygous, this is not yet accounted for - if(!is.na(hschr[probe]) & hschr[probe]) { - if(length(hprobes)>=homthres) { - allhprobes = rbind(allhprobes,c(chrke,chr[[chrke]][min(hprobes)],chr[[chrke]][max(hprobes)])) - } - } - - } - - HomoStretches[[sam]]=allhprobes - - } - - return(HomoStretches) -} - - - - - -# function to make segments of constant LRR and BAF -# this function is more general and does not depend on specifically ASPCF output -# it can also handle segmention performed on LRR and BAF separately -make_segments = function(r,b) { - m = matrix(ncol = 2, nrow = length(b)) - m[,1] = r - m[,2] = b - m = as.matrix(na.omit(m)) - pcf_segments = matrix(ncol = 3, nrow = dim(m)[1]) - colnames(pcf_segments) = c("r","b","length"); - index = 0; - previousb = -1; - previousr = 1E10; - for (i in 1:dim(m)[1]) { - if (m[i,2] != previousb || m[i,1] != previousr) { - index=index+1; - count=1; - pcf_segments[index, "r"] = m[i,1]; - pcf_segments[index, "b"] = m[i,2]; - } - else { - count = count + 1; - } - pcf_segments[index, "length"] = count; - previousb = m[i,2]; - previousr = m[i,1]; - } - pcf_segments = as.matrix(na.omit(pcf_segments))[,] - return(pcf_segments); -} - - - -# function to create the distance matrix (distance for a range of ploidy and tumor percentage values) -# input: segmented LRR and BAF and the value for gamma -create_distance_matrix = function(segments, gamma) { - s = segments - psi_pos = seq(1,6,0.05) - rho_pos = seq(0.1,1.05,0.01) - d = matrix(nrow = length(psi_pos), ncol = length(rho_pos)) - rownames(d) = psi_pos - colnames(d) = rho_pos - dmin = 1E20; - for(i in 1:length(psi_pos)) { - psi = psi_pos[i] - for(j in 1:length(rho_pos)) { - rho = rho_pos[j] - nA = (rho-1-(s[,"b"]-1)*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho - nB = (rho-1+s[,"b"]*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho - # choose the minor allele - nMinor = NULL - if (sum(nA,na.rm=T) < sum(nB,na.rm=T)) { - nMinor = nA - } - else { - nMinor = nB - } - d[i,j] = sum(abs(nMinor - pmax(round(nMinor),0))^2 * s[,"length"] * ifelse(s[,"b"]==0.5,0.05,1), na.rm=T) - } - } - return(d) -} - - - -# the ASCAT main function -# lrr: (unsegmented) log R, in genomic sequence (all probes), with probe IDs -# baf: (unsegmented) B Allele Frequency, in genomic sequence (all probes), with probe IDs -# lrrsegmented: log R, segmented, in genomic sequence (all probes), with probe IDs -# bafsegmented: B Allele Frequency, segmented, in genomic sequence (only probes heterozygous in germline), with probe IDs -# chromosomes: a list containing c vectors, where c is the number of chromosomes and every vector contains all probe numbers per chromosome -# chrnames: a vector containing the names for the chromosomes (e.g. c(1:22,"X")) -# sexchromosomes: a vector containing the names for the sex chromosomes -# failedqualitycheck: did the sample fail any previous quality check or not? -# distancepng: if NA: distance is plotted, if filename is given, the plot is written to a .png file -# copynumberprofilespng: if NA: possible copy number profiles are plotted, if filename is given, the plot is written to a .png file -# nonroundedprofilepng: if NA: copy number profile before rounding is plotted (total copy number as well as the copy number of the minor allele), if filename is given, the plot is written to a .png file -# aberrationreliabilitypng: if NA: aberration reliability score is plotted, if filename is given, the plot is written to a .png file -# gamma: technology parameter, compaction of Log R profiles (expected decrease in case of deletion in diploid sample, 100 % aberrant cells; 1 in ideal case, 0.55 of Illumina 109K arrays) -runASCAT = function(lrr, baf, lrrsegmented, bafsegmented, gender, SNPpos, chromosomes, chrnames, sexchromosomes, failedqualitycheck = F, - distancepng = NA, copynumberprofilespng = NA, nonroundedprofilepng = NA, aberrationreliabilitypng = NA, gamma = 0.55, - rho_manual = NA, psi_manual = NA) { - ch = chromosomes - chrs = chrnames - b = bafsegmented - r = lrrsegmented[names(bafsegmented)] - - library(RColorBrewer) - - SNPposhet = SNPpos[names(bafsegmented),] - autoprobes = !(SNPposhet[,1]%in%sexchromosomes) - - b2 = b[autoprobes] - r2 = r[autoprobes] - - s = make_segments(r2,b2) - d = create_distance_matrix(s, gamma) - - if (!is.na(distancepng)) { - png(filename = distancepng, width = 1000, height = 1000, res = 1000/7) - } - - par(mar = c(5,5,0.5,0.5), cex=0.75, cex.lab=2, cex.axis=2) - - hmcol = rev(colorRampPalette(brewer.pal(10, "RdBu"))(256)) - image(log(d), col = hmcol, axes = F, xlab = "Ploidy", ylab = "Aberrant cell fraction") - - axis(1, at = seq(0, 1, by = 1/5), label = seq(1, 6, by = 1)) - axis(2, at = seq(0, 1/1.05, by = 1/3/1.05), label = seq(0.1, 1, by = 3/10)) - - TheoretMaxdist = sum(rep(0.25,dim(s)[1]) * s[,"length"] * ifelse(s[,"b"]==0.5,0.05,1),na.rm=T) - - # flag the sample as non-aberrant if necessary - nonaberrant = F - MINABB = 0.03 - MINABBREGION = 0.005 - - percentAbb = sum(ifelse(s[,"b"]==0.5,0,1)*s[,"length"])/sum(s[,"length"]) - maxsegAbb = max(ifelse(s[,"b"]==0.5,0,s[,"length"]))/sum(s[,"length"]) - if(percentAbb <= MINABB & maxsegAbb <= MINABBREGION) { - nonaberrant = T - } - - - MINPLOIDY = 1.5 - MAXPLOIDY = 5.5 - MINRHO = 0.2 - MINGOODNESSOFFIT = 80 - MINPERCZERO = 0.02 - MINPERCZEROABB = 0.1 - MINPERCODDEVEN = 0.05 - MINPLOIDYSTRICT = 1.7 - MAXPLOIDYSTRICT = 2.3 - - nropt = 0 - localmin = NULL - optima = list() - - if(!failedqualitycheck && is.na(rho_manual)) { - - # first, try with all filters - for (i in 4:(dim(d)[1]-3)) { - for (j in 4:(dim(d)[2]-3)) { - m = d[i,j] - seld = d[(i-3):(i+3),(j-3):(j+3)] - seld[4,4] = max(seld) - if(min(seld) > m) { - psi = as.numeric(rownames(d)[i]) - rho = as.numeric(colnames(d)[j]) - nA = (rho-1-(s[,"b"]-1)*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho - nB = (rho-1+s[,"b"]*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho - - # ploidy is recalculated based on results, to avoid bias (due to differences in normalization of LogR) - ploidy = sum((nA+nB) * s[,"length"]) / sum(s[,"length"]); - - percentzero = (sum((round(nA)==0)*s[,"length"])+sum((round(nB)==0)*s[,"length"]))/sum(s[,"length"]) - - goodnessOfFit = (1-m/TheoretMaxdist) * 100 - - if (!nonaberrant & ploidy > MINPLOIDY & ploidy < MAXPLOIDY & rho >= MINRHO & goodnessOfFit > MINGOODNESSOFFIT & percentzero > MINPERCZERO) { - nropt = nropt + 1 - optima[[nropt]] = c(m,i,j,ploidy,goodnessOfFit) - localmin[nropt] = m - } - } - } - } - - # if no solution, drop the percentzero > MINPERCZERO filter (allow non-aberrant solutions - but limit the ploidy options) - if (nropt == 0) { - for (i in 4:(dim(d)[1]-3)) { - for (j in 4:(dim(d)[2]-3)) { - m = d[i,j] - seld = d[(i-3):(i+3),(j-3):(j+3)] - seld[4,4] = max(seld) - if(min(seld) > m) { - psi = as.numeric(rownames(d)[i]) - rho = as.numeric(colnames(d)[j]) - nA = (rho-1-(s[,"b"]-1)*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho - nB = (rho-1+s[,"b"]*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho - - # ploidy is recalculated based on results, to avoid bias (due to differences in normalization of LogR) - ploidy = sum((nA+nB) * s[,"length"]) / sum(s[,"length"]); - - perczeroAbb = (sum((round(nA)==0)*s[,"length"]*ifelse(s[,"b"]==0.5,0,1))+sum((round(nB)==0)*s[,"length"]*ifelse(s[,"b"]==0.5,0,1)))/sum(s[,"length"]*ifelse(s[,"b"]==0.5,0,1)) - # the next can happen if BAF is a flat line at 0.5 - if (is.na(perczeroAbb)) { - perczeroAbb = 0 - } - - goodnessOfFit = (1-m/TheoretMaxdist) * 100 - - if (ploidy > MINPLOIDYSTRICT & ploidy < MAXPLOIDYSTRICT & rho >= MINRHO & goodnessOfFit > MINGOODNESSOFFIT & perczeroAbb > MINPERCZEROABB) { - nropt = nropt + 1 - optima[[nropt]] = c(m,i,j,ploidy,goodnessOfFit) - localmin[nropt] = m - } - } - } - } - } - - # if still no solution, allow solutions with 100% aberrant cells (include the borders with rho = 1), but in first instance, keep the percentzero > 0.01 filter - if (nropt == 0) { - #first, include borders - cold = which(as.numeric(colnames(d))>1) - d[,cold]=1E20 - for (i in 4:(dim(d)[1]-3)) { - for (j in 4:(dim(d)[2]-3)) { - m = d[i,j] - seld = d[(i-3):(i+3),(j-3):(j+3)] - seld[4,4] = max(seld) - if(min(seld) > m) { - psi = as.numeric(rownames(d)[i]) - rho = as.numeric(colnames(d)[j]) - nA = (rho-1-(s[,"b"]-1)*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho - nB = (rho-1+s[,"b"]*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho - - # ploidy is recalculated based on results, to avoid bias (due to differences in normalization of LogR) - ploidy = sum((nA+nB) * s[,"length"]) / sum(s[,"length"]); - - percentzero = (sum((round(nA)==0)*s[,"length"])+sum((round(nB)==0)*s[,"length"]))/sum(s[,"length"]) - percOddEven = sum((round(nA)%%2==0&round(nB)%%2==1|round(nA)%%2==1&round(nB)%%2==0)*s[,"length"])/sum(s[,"length"]) - perczeroAbb = (sum((round(nA)==0)*s[,"length"]*ifelse(s[,"b"]==0.5,0,1))+sum((round(nB)==0)*s[,"length"]*ifelse(s[,"b"]==0.5,0,1)))/sum(s[,"length"]*ifelse(s[,"b"]==0.5,0,1)) - if (is.na(perczeroAbb)) { - perczeroAbb = 0 - } - - goodnessOfFit = (1-m/TheoretMaxdist) * 100 - - if (!nonaberrant & ploidy > MINPLOIDY & ploidy < MAXPLOIDY & rho >= MINRHO & goodnessOfFit > MINGOODNESSOFFIT & - (perczeroAbb > MINPERCZEROABB | percentzero > MINPERCZERO | percOddEven > MINPERCODDEVEN)) { - nropt = nropt + 1 - optima[[nropt]] = c(m,i,j,ploidy,goodnessOfFit) - localmin[nropt] = m - } - } - } - } - } - - # if still no solution, drop the percentzero > MINPERCENTZERO filter, but strict ploidy borders - if (nropt == 0) { - for (i in 4:(dim(d)[1]-3)) { - for (j in 4:(dim(d)[2]-3)) { - m = d[i,j] - seld = d[(i-3):(i+3),(j-3):(j+3)] - seld[4,4] = max(seld) - if(min(seld) > m) { - psi = as.numeric(rownames(d)[i]) - rho = as.numeric(colnames(d)[j]) - nA = (rho-1-(s[,"b"]-1)*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho - nB = (rho-1+s[,"b"]*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho - - # ploidy is recalculated based on results, to avoid bias (due to differences in normalization of LogR) - ploidy = sum((nA+nB) * s[,"length"]) / sum(s[,"length"]); - - perczeroAbb = (sum((round(nA)==0)*s[,"length"]*ifelse(s[,"b"]==0.5,0,1))+sum((round(nB)==0)*s[,"length"]*ifelse(s[,"b"]==0.5,0,1)))/sum(s[,"length"]*ifelse(s[,"b"]==0.5,0,1)) - # the next can happen if BAF is a flat line at 0.5 - if (is.na(perczeroAbb)) { - perczeroAbb = 0 - } - - goodnessOfFit = (1-m/TheoretMaxdist) * 100 - - if (ploidy > MINPLOIDYSTRICT & ploidy < MAXPLOIDYSTRICT & rho >= MINRHO & goodnessOfFit > MINGOODNESSOFFIT) { - nropt = nropt + 1 - optima[[nropt]] = c(m,i,j,ploidy,goodnessOfFit) - localmin[nropt] = m - } - } - } - } - } - } - - if (!is.na(rho_manual)) { - - rho = rho_manual - psi = psi_manual - - nA = (rho-1-(s[,"b"]-1)*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho - nB = (rho-1+s[,"b"]*2^(s[,"r"]/gamma)*((1-rho)*2+rho*psi))/rho - - # ploidy is recalculated based on results, to avoid bias (due to differences in normalization of LogR) - ploidy = sum((nA+nB) * s[,"length"]) / sum(s[,"length"]); - - nMinor = NULL - if (sum(nA,na.rm=T) < sum(nB,na.rm=T)) { - nMinor = nA - } - else { - nMinor = nB - } - m = sum(abs(nMinor - pmax(round(nMinor),0))^2 * s[,"length"] * ifelse(s[,"b"]==0.5,0.05,1), na.rm=T) - - goodnessOfFit = (1-m/TheoretMaxdist) * 100 - - nropt = 1 - optima[[1]] = c(m,rho,psi,ploidy,goodnessOfFit) - localmin[1] = m - - } - - - if (nropt>0) { - if (is.na(rho_manual)) { - optlim = sort(localmin)[1] - for (i in 1:length(optima)) { - if(optima[[i]][1] == optlim) { - psi_opt1 = as.numeric(rownames(d)[optima[[i]][2]]) - rho_opt1 = as.numeric(colnames(d)[optima[[i]][3]]) - if(rho_opt1 > 1) { - rho_opt1 = 1 - } - ploidy_opt1 = optima[[i]][4] - goodnessOfFit_opt1 = optima[[i]][5] - points((psi_opt1-1)/5,(rho_opt1-0.1)/0.95,col="green",pch="X", cex = 2) - } - } - } else { - rho_opt1 = optima[[1]][2] - psi_opt1 = optima[[1]][3] - ploidy_opt1 = optima[[1]][4] - goodnessOfFit_opt1 = optima[[1]][5] - points((psi_opt1-1)/5,(rho_opt1-0.1)/0.95,col="green",pch="X", cex = 2) - } - } - - if (!is.na(distancepng)) { - dev.off() - } - - - if(nropt>0) { - - if (!is.na(nonroundedprofilepng)) { - png(filename = nonroundedprofilepng, width = 2000, height = 500, res = 200) - } - else { - windows(10,5) - } - - par(mar = c(0.5,5,5,0.5), cex = 0.4, cex.main=3, cex.axis = 2.5) - - rho = rho_opt1 - psi = psi_opt1 - - SNPposhet = SNPpos[names(bafsegmented),] - haploidchrs = unique(c(substring(gender,1,1),substring(gender,2,2))) - if(substring(gender,1,1)==substring(gender,2,2)) { - haploidchrs = setdiff(haploidchrs,substring(gender,1,1)) - } - diploidprobes = !(SNPposhet[,1]%in%haploidchrs) - nullchrs = setdiff(sexchromosomes,unique(c(substring(gender,1,1),substring(gender,2,2)))) - nullprobes = SNPposhet[,1]%in%nullchrs - - nAfull = ifelse(diploidprobes, - (rho-1-(b-1)*2^(r/gamma)*((1-rho)*2+rho*psi))/rho, - ifelse(nullprobes,0, - ifelse(b<0.5,(rho-1+((1-rho)*2+rho*psi)*2^(r/gamma))/rho,0))) - nBfull = ifelse(diploidprobes, - (rho-1+b*2^(r/gamma)*((1-rho)*2+rho*psi))/rho, - ifelse(nullprobes,0, - ifelse(b<0.5,0,(rho-1+((1-rho)*2+rho*psi)*2^(r/gamma))/rho))) - nA = pmax(round(nAfull),0) - nB = pmax(round(nBfull),0) - - maintitle = paste("Ploidy: ",sprintf("%1.2f",ploidy_opt1),", aberrant cell fraction: ",sprintf("%2.0f",rho_opt1*100),"%, goodness of fit: ",sprintf("%2.1f",goodnessOfFit_opt1),"%", ifelse(nonaberrant,", non-aberrant",""),sep="") - plot(c(1,length(nAfull)), c(0,5), type = "n", xaxt = "n", main = maintitle, xlab = "", ylab = "") - points(nBfull,col="blue",pch = "|") - points(nAfull+nBfull,col="purple",pch = "|") -# don't ask me why, but the "|" sign is not centered, so the lines may need to be shifted.. - abline(v=0,lty=1,col="lightgrey") - chrk_tot_len = 0 - for (i in 1:length(ch)) { - chrk = ch[[i]]; - chrk_hetero = intersect(names(lrr)[chrk],names(bafsegmented)) - chrk_tot_len_prev = chrk_tot_len - chrk_tot_len = chrk_tot_len + length(chrk_hetero) - vpos = chrk_tot_len; - tpos = (chrk_tot_len+chrk_tot_len_prev)/2; - text(tpos,5,chrs[i], pos = 1, cex = 2) - abline(v=vpos,lty=1,col="lightgrey") - } - - if (!is.na(nonroundedprofilepng)) { - dev.off() - } - - rho = rho_opt1 - psi = psi_opt1 - - diploidprobes = !(SNPpos[,1]%in%haploidchrs) - nullprobes = SNPpos[,1]%in%nullchrs - - #this replaces an occurrence of unique that caused problems - tlr2 = rle(lrrsegmented) - tlr = tlr2$values - tlrstart = c(1,cumsum(tlr2$lengths)+1) - tlrstart = tlrstart[1:(length(tlrstart)-1)] - tlrend = cumsum(tlr2$lengths) - seg = NULL - for (i in 1:length(tlr)) { - logR = tlr[i] - #pr = which(lrrsegmented==logR) # this was a problem - pr = tlrstart[i]:tlrend[i] - start = min(pr) - end = max(pr) - bafke = bafsegmented[intersect(names(lrrsegmented)[pr],names(bafsegmented))][1] - #if bafke is NA, this means that we are dealing with a germline homozygous stretch with a copy number change within it. - #in this case, nA and nB are irrelevant, just their sum matters - if(is.na(bafke)) { - bafke=0 - } - - nAraw = ifelse(diploidprobes[start], - (rho-1-(bafke-1)*2^(logR/gamma)*((1-rho)*2+rho*psi))/rho, - ifelse(nullprobes[start],0, - (rho-1+((1-rho)*2+rho*psi)*2^(logR/gamma))/rho)) - nBraw = ifelse(diploidprobes[start],(rho-1+bafke*2^(logR/gamma)*((1-rho)*2+rho*psi))/rho,0) - # correct for negative values: - if (nAraw+nBraw<0) { - nAraw = 0 - nBraw = 0 - } - else if (nAraw<0) { - nBraw = nAraw+nBraw - nAraw = 0 - } - else if (nBraw<0) { - nAraw = nAraw+nBraw - nBraw = 0 - } - # when evidence for odd copy number in segments of BAF = 0.5, assume a deviation.. - limitround = 0.5 - nA = ifelse(bafke==0.5, - ifelse(nAraw+nBraw>round(nAraw)+round(nBraw)+limitround, - round(nAraw)+1, - ifelse(nAraw+nBrawround(nAraw)+round(nBraw)+limitround, - round(nBraw), - ifelse(nAraw+nBraw0.5,nMajor[heteroprobes], nMinor[heteroprobes]) - n1all[homoprobes] = ifelse(baf[homoprobes]<=0.5,nMajor[homoprobes]+nMinor[homoprobes],0) - n2all[homoprobes] = ifelse(baf[homoprobes]>0.5,nMajor[homoprobes]+nMinor[homoprobes],0) - - - # plot ASCAT profile - if (!is.na(copynumberprofilespng)) { - png(filename = copynumberprofilespng, width = 2000, height = 500, res = 200) - } - else { - windows(10,2.5) - } - - par(mar = c(0.5,5,5,0.5), cex = 0.4, cex.main=3, cex.axis = 2.5) - - nA2 = n1all[heteroprobes] - nB2 = n2all[heteroprobes] - nA = ifelse(nA2>nB2,nA2,nB2) - nB = ifelse(nA2>nB2,nB2,nA2) - maintitle = paste("Ploidy: ",sprintf("%1.2f",ploidy_opt1),", aberrant cell fraction: ",sprintf("%2.0f",rho_opt1*100),"%, goodness of fit: ",sprintf("%2.1f",goodnessOfFit_opt1),"%", ifelse(nonaberrant,", non-aberrant",""),sep="") - plot(c(1,length(nAfull)), c(0,5), type = "n", xaxt = "n", main = maintitle, xlab = "", ylab = "") - points(nA-0.1,col="red",pch = "|") - points(nB+0.1,col="green",pch = "|") - # don't ask me why, but the "|" sign is not centered, so the lines may need to be shifted.. - abline(v=0,lty=1,col="lightgrey") - chrk_tot_len = 0 - for (i in 1:length(ch)) { - chrk = ch[[i]]; - chrk_hetero = intersect(names(lrr)[chrk],names(bafsegmented)) - chrk_tot_len_prev = chrk_tot_len - chrk_tot_len = chrk_tot_len + length(chrk_hetero) - vpos = chrk_tot_len; - tpos = (chrk_tot_len+chrk_tot_len_prev)/2; - text(tpos,5,chrs[i], pos = 1, cex = 2) - abline(v=vpos,lty=1,col="lightgrey") - } - - - if (!is.na(copynumberprofilespng)) { - dev.off() - } - - - if (!is.na(aberrationreliabilitypng)) { - png(filename = aberrationreliabilitypng, width = 2000, height = 500, res = 200) - } - else { - windows(10,2.5) - } - - par(mar = c(0.5,5,5,0.5), cex = 0.4, cex.main=3, cex.axis = 2.5) - - diploidprobes = !(SNPposhet[,1]%in%haploidchrs) - nullprobes = SNPposhet[,1]%in%nullchrs - - rBacktransform = ifelse(diploidprobes, - gamma*log((rho*(nA+nB)+(1-rho)*2)/((1-rho)*2+rho*psi),2), - # the value for nullprobes is arbitrary (but doesn't matter, as these are not plotted anyway because BAF=0.5) - ifelse(nullprobes,-10,gamma*log((rho*(nA+nB)+(1-rho))/((1-rho)*2+rho*psi),2))) - - bBacktransform = ifelse(diploidprobes, - (1-rho+rho*nB)/(2-2*rho+rho*(nA+nB)), - ifelse(nullprobes,0.5,0)) - - rConf = ifelse(abs(rBacktransform)>0.15,pmin(100,pmax(0,100*(1-abs(rBacktransform-r)/abs(r)))),NA) - bConf = ifelse(diploidprobes & bBacktransform!=0.5, pmin(100,pmax(0,ifelse(b==0.5,100,100*(1-abs(bBacktransform-b)/abs(b-0.5))))), NA) - confidence = ifelse(is.na(rConf),bConf,ifelse(is.na(bConf),rConf,(rConf+bConf)/2)) - maintitle = paste("Aberration reliability score (%), average: ", sprintf("%2.0f",mean(confidence,na.rm=T)),"%",sep="") - plot(c(1,length(nAfull)), c(0,100), type = "n", xaxt = "n", main = maintitle, xlab = "", ylab = "") - points(confidence,col="blue",pch = "|") - abline(v=0,lty=1,col="lightgrey") - chrk_tot_len = 0 - for (i in 1:length(ch)) { - chrk = ch[[i]]; - chrk_hetero = intersect(names(lrr)[chrk],names(bafsegmented)) - chrk_tot_len_prev = chrk_tot_len - chrk_tot_len = chrk_tot_len + length(chrk_hetero) - vpos = chrk_tot_len; - tpos = (chrk_tot_len+chrk_tot_len_prev)/2; - text(tpos,5,chrs[i], pos = 1, cex = 2) - abline(v=vpos,lty=1,col="lightgrey") - } - - if (!is.na(aberrationreliabilitypng)) { - dev.off() - } - - return(list(rho = rho_opt1, psi = psi_opt1, goodnessOfFit = goodnessOfFit_opt1, nonaberrant = nonaberrant, nA = n1all, nB = n2all, seg = seg, seg_raw = seg_raw)) - - } - - else { - return(list(rho = NA, psi = NA, goodnessOfFit = NA, nonaberrant = F, nA = NA, nB = NA, seg = NA, seg_raw = NA)) - } - -} - - - - - - - - -# -# Enhanced bivariate PCF filter for aCGH data (v. 08.02.2010) -# Whole chromosomes/chromosome arms wrapper function -# - -fastAspcf <- function(logR, allB, kmin, gamma){ - - N <- length(logR) - w <- 1000 #w: windowsize - d <- 100 - - startw = -d - stopw = w-d - - nseg = 0 - var2 = 0 - breakpts = 0 - larger = TRUE - repeat{ - from <- max(c(1,startw)) - to <- min(c(stopw,N)) - logRpart <- logR[from:to] - allBpart <- allB[from:to] - allBflip <- allBpart - allBflip[allBpart > 0.5] <- 1 - allBpart[allBpart > 0.5] - - sd1 <- getMad(logRpart) - sd2 <- getMad(allBflip) - - #Must check that sd1 and sd2 are defined and != 0: - sd.valid <- c(!is.na(sd1),!is.na(sd2),sd1!=0,sd2!=0) - if(all(sd.valid)){ - #run aspcfpart: - #part.res <- aspcfpart(logRpart=logRpart, allBflip=allBflip, a=startw, b=stopw, d=d, sd1=sd1, sd2=sd2, N=N, kmin=kmin, gamma=gamma) - part.res <- aspcfpart(logRpart=logRpart, allBflip=allBflip, a=startw, b=stopw, d=d, sd1=sd1, sd2=sd2, N=N, kmin=kmin, gamma=gamma) - breakptspart <- part.res$breakpts - # the 'larger' is (occasionally) necessary in the last window of the segmentation! - larger = breakptspart>breakpts[length(breakpts)] - breakpts <- c(breakpts, breakptspart[larger]) - var2 <- var2 + sd2^2 - nseg = nseg+1 - } - - if(stopw < N+d){ - startw <- min(stopw-2*d + 1,N-2*d) - stopw <- startw + w - }else{ - break - } - - }#end repeat - breakpts <- unique(c(breakpts, N)) - if(nseg==0){nseg=1} #just in case the sd-test never passes. - sd2 <- sqrt(var2/nseg) - - # On each segment calculate mean of unflipped B allele data - frst <- breakpts[1:length(breakpts)-1] + 1 - last <- breakpts[2:length(breakpts)] - nseg <- length(frst) - - yhat1 <- rep(NA,N) - yhat2 <- rep(NA,N) - - for(i in 1:nseg){ - yhat1[frst[i]:last[i]] <- rep(mean(logR[frst[i]:last[i]]), last[i]-frst[i]+1) - yi2 <- allB[frst[i]:last[i]] - # Center data around zero (by subtracting 0.5) and estimate mean - if(length(yi2)== 0){ - mu <- 0 - }else{ - mu <- mean(abs(yi2-0.5)) - } - - # Make a (slightly arbitrary) decision concerning branches - # This may be improved by a test of equal variances - if(sqrt(sd2^2+mu^2) < 2*sd2){ - mu <- 0 - } - yhat2[frst[i]:last[i]] <- rep(mu+0.5,last[i]-frst[i]+1) - } - - return(list(yhat1=yhat1,yhat2=yhat2)) - -}#end fastAspcf - - - -aspcfpart <- function(logRpart, allBflip, a, b, d, sd1, sd2, N, kmin, gamma){ - - from <- max(c(1,a)) - usefrom <- max(c(1,a+d)) - useto <- min(c(N,b-d)) - - N <- length(logRpart) - y1 <- logRpart - y2 <- allBflip - - #Check that vectors are long enough to run algorithm: - if(N < 2*kmin){ - breakpts <- 0 - return(list(breakpts=breakpts)) - } - - # Find initSum, initKvad, initAve for segment y[1..kmin] - initSum1 <- sum(y1[1:kmin]) - initKvad1 <- sum(y1[1:kmin]^2) - initAve1 <- initSum1/kmin - initSum2 <- sum(y2[1:kmin]) - initKvad2 <- sum(y2[1:kmin]^2) - initAve2 <- initSum2/kmin - - # Define vector of best costs - bestCost <- rep(0,N) - cost1 <- (initKvad1 - initSum1*initAve1)/sd1^2 - cost2 <- (initKvad2 - initSum2*initAve2)/sd2^2 - bestCost[kmin] <- cost1 + cost2 - - # Define vector of best splits - bestSplit <- rep(0,N) - - # Define vector of best averages - bestAver1 <- rep(0,N) - bestAver2 <- rep(0,N) - bestAver1[kmin] <- initAve1 - bestAver2[kmin] <- initAve2 - - - #Initialize - Sum1 <- rep(0,N) - Sum2 <- rep(0,N) - Kvad1 <- rep(0,N) - Kvad2 <- rep(0,N) - Aver1 <- rep(0,N) - Aver2 <- rep(0,N) - Cost <- rep(0,N) - - # We have to treat the region y(1..2*kmin-1) separately, as it - # cannot be split into two full segments - kminP1 <- kmin+1 - for (k in (kminP1):(2*kmin-1)) { - Sum1[kminP1:k] <- Sum1[kminP1:k]+y1[k] - Aver1[kminP1:k] <- Sum1[kminP1:k]/((k-kmin):1) - Kvad1[kminP1:k] <- Kvad1[kminP1:k]+y1[k]^2 - Sum2[kminP1:k] <- Sum2[kminP1:k]+y2[k] - Aver2[kminP1:k] <- Sum2[kminP1:k]/((k-kmin):1) - Kvad2[kminP1:k] <- Kvad2[kminP1:k]+y2[k]^2 - - - bestAver1[k] <- (initSum1+Sum1[kminP1])/k - bestAver2[k] <- (initSum2+Sum2[kminP1])/k - cost1 <- ((initKvad1+Kvad1[kminP1])-k*bestAver1[k]^2)/sd1^2 - cost2 <- ((initKvad2+Kvad2[kminP1])-k*bestAver2[k]^2)/sd2^2 - - bestCost[k] <- cost1 + cost2 - - } - - - for (n in (2*kmin):N) { - - nMkminP1=n-kmin+1 - - Sum1[kminP1:n] <- Sum1[kminP1:n]+ y1[n] - Aver1[kminP1:n] <- Sum1[kminP1:n]/((n-kmin):1) - Kvad1[kminP1:n] <- Kvad1[kminP1:n]+ (y1[n])^2 - - cost1 <- (Kvad1[kminP1:nMkminP1]-Sum1[kminP1:nMkminP1]*Aver1[kminP1:nMkminP1])/sd1^2 - - Sum2[kminP1:n] <- Sum2[kminP1:n]+ y2[n] - Aver2[kminP1:n] <- Sum2[kminP1:n]/((n-kmin):1) - Kvad2[kminP1:n] <- Kvad2[kminP1:n]+ (y2[n])^2 - cost2 <- (Kvad2[kminP1:nMkminP1]-Sum2[kminP1:nMkminP1]*Aver2[kminP1:nMkminP1])/sd2^2 - - Cost[kminP1:nMkminP1] <- bestCost[kmin:(n-kmin)] + cost1 + cost2 - - Pos <- which.min(Cost[kminP1:nMkminP1])+kmin - cost <- Cost[Pos] + gamma - - aver1 <- Aver1[Pos] - aver2 <- Aver2[Pos] - totAver1 <- (Sum1[kminP1]+initSum1)/n - totCost1 <- ((Kvad1[kminP1]+initKvad1) - n*totAver1*totAver1)/sd1^2 - totAver2 <- (Sum2[kminP1]+initSum2)/n - totCost2 <- ((Kvad2[kminP1]+initKvad2) - n*totAver2*totAver2)/sd2^2 - totCost <- totCost1 + totCost2 - - if (totCost < cost) { - Pos <- 1 - cost <- totCost - aver1 <- totAver1 - aver2 <- totAver2 - } - bestCost[n] <- cost - bestAver1[n] <- aver1 - bestAver2[n] <- aver2 - bestSplit[n] <- Pos-1 - - - }#endfor - - - # Trace back - n <- N - breakpts <- n - while(n > 0){ - breakpts <- c(bestSplit[n], breakpts) - n <- bestSplit[n] - }#endwhile - - breakpts <- breakpts + from -1 - breakpts <- breakpts[breakpts>=usefrom & breakpts<=useto] - - return(list(breakpts=breakpts)) - -}#end aspcfpart - - - - - - -div <- function(a, b, c){ - - if(nargs() < 3){ - c <- 0 - }#endif - - if(b > 0){ - v <- a/b - }else{ - v <- c - }#endif - - return(v) -}#endfunction - - -#function v = div(a, b, c) -# if nargin < 3 -# c = 0; -# end -# if b > 0 -# v = a/b; -# else -# v = c; -# end -#end - - - -#Get mad SD (based on KL code) -getMad <- function(x,k=25){ - - #Remove observations that are equal to zero; are likely to be imputed, should not contribute to sd: - x <- x[x!=0] - - #Calculate runMedian - runMedian <- medianFilter(x,k) - - dif <- x-runMedian - SD <- mad(dif) - - return(SD) -} - - - - - -exactPcf <- function(y, kmin, gamma) { -## Implementaion of exact PCF by Potts-filtering - ## x: input array of (log2) copy numbers - ## kmin: Mininal length of plateaus - ## gamma: penalty for each discontinuity - N <- length(y) - yhat <- rep(0,N); - if (N < 2*kmin) { - yhat <- rep(mean(y),N) - return(yhat) - } - initSum <- sum(y[1:kmin]) - initKvad <- sum(y[1:kmin]^2) - initAve <- initSum/kmin; - bestCost <- rep(0,N) - bestCost[kmin] <- initKvad - initSum*initAve - bestSplit <- rep(0,N) - bestAver <- rep(0,N) - bestAver[kmin] <- initAve - Sum <- rep(0,N) - Kvad <- rep(0,N) - Aver <- rep(0,N) - Cost <- rep(0,N) - kminP1=kmin+1 - for (k in (kminP1):(2*kmin-1)) { - Sum[kminP1:k]<-Sum[kminP1:k]+y[k] - Aver[kminP1:k] <- Sum[kminP1:k]/((k-kmin):1) - Kvad[kminP1:k] <- Kvad[kminP1:k]+y[k]^2 - bestAver[k] <- (initSum+Sum[kminP1])/k - bestCost[k] <- (initKvad+Kvad[kminP1])-k*bestAver[k]^2 - } - for (n in (2*kmin):N) { - yn <- y[n] - yn2 <- yn^2 - Sum[kminP1:n] <- Sum[kminP1:n]+yn - Aver[kminP1:n] <- Sum[kminP1:n]/((n-kmin):1) - Kvad[kminP1:n] <- Kvad[kminP1:n]+yn2 - nMkminP1=n-kmin+1 - Cost[kminP1:nMkminP1] <- bestCost[kmin:(n-kmin)]+Kvad[kminP1:nMkminP1]-Sum[kminP1:nMkminP1]*Aver[kminP1:nMkminP1]+gamma - Pos <- which.min(Cost[kminP1:nMkminP1])+kmin - cost <- Cost[Pos] - aver <- Aver[Pos] - totAver <- (Sum[kminP1]+initSum)/n - totCost <- (Kvad[kminP1]+initKvad) - n*totAver*totAver - if (totCost < cost) { - Pos <- 1 - cost <- totCost - aver <- totAver - } - bestCost[n] <- cost - bestAver[n] <- aver - bestSplit[n] <- Pos-1 - } - n <- N - while (n > 0) { - yhat[(bestSplit[n]+1):n] <- bestAver[n] - n <- bestSplit[n] - } - return(yhat) -} - - -#Perform MAD winsorization: -madWins <- function(x,tau,k){ - xhat <- medianFilter(x,k) - d <- x-xhat - SD <- mad(d) - z <- tau*SD - xwin <- xhat + psi(d, z) - outliers <- rep(0, length(x)) - outliers[x > xwin] <- 1 - outliers[x < xwin] <- -1 - return(list(ywin=xwin,sdev=SD,outliers=outliers)) -} - - -######################################################################### -# Function to calculate running median for a given a window size -######################################################################### - -##Input: -### x: vector of numeric values -### k: window size to be used for the sliding window (actually half-window size) - -## Output: -### runMedian : the running median corresponding to each observation - -##Required by: -### getMad -### medianFilter - - -##Requires: -### none - -medianFilter <- function(x,k){ - n <- length(x) - filtWidth <- 2*k + 1 - - #Make sure filtWidth does not exceed n - if(filtWidth > n){ - if(n==0){ - filtWidth <- 1 - }else if(n%%2 == 0){ - #runmed requires filtWidth to be odd, ensure this: - filtWidth <- n - 1 - }else{ - filtWidth <- n - } - } - - runMedian <- runmed(x,k=filtWidth,endrule="median") - - return(runMedian) - -} - - - - - -psi <- function(x,z){ - xwin <- x - xwin[x < -z] <- -z - xwin[x > z] <- z - return(xwin) -} - - - - - - - -ascat.predictGermlineGenotypes = function(ASCATobj, platform = "AffySNP6") { - Homozygous = matrix(nrow = dim(ASCATobj$Tumor_LogR)[1], ncol = dim(ASCATobj$Tumor_LogR)[2]) - colnames(Homozygous) = colnames(ASCATobj$Tumor_LogR) - rownames(Homozygous) = rownames(ASCATobj$Tumor_LogR) - - if (platform=="Custom10k") { - maxHomozygous = 0.05 - proportionHetero = 0.59 - proportionHomo = 0.38 - proportionOpen = 0.02 - segmentLength = 20 - } - else if (platform=="Illumina109k") { - maxHomozygous = 0.05 - proportionHetero = 0.35 - proportionHomo = 0.60 - proportionOpen = 0.02 - segmentLength = 20 - } - else if (platform=="IlluminaCytoSNP") { - maxHomozygous = 0.05 - proportionHetero = 0.28 - proportionHomo = 0.62 - proportionOpen = 0.03 - segmentLength = 100 - } - else if (platform=="Illumina610k") { - maxHomozygous = 0.05 - proportionHetero = 0.295 - proportionHomo = 0.67 - proportionOpen = 0.015 - segmentLength = 30 - } - else if (platform=="Illumina660k") { - maxHomozygous = 0.05 - proportionHetero = 0.295 - proportionHomo = 0.67 - proportionOpen = 0.015 - segmentLength = 30 - } - else if (platform=="Illumina700k") { - maxHomozygous = 0.05 - proportionHetero = 0.295 - proportionHomo = 0.67 - proportionOpen = 0.015 - segmentLength = 30 - } - else if (platform=="Illumina1M") { - maxHomozygous = 0.05 - proportionHetero = 0.22 - proportionHomo = 0.74 - proportionOpen = 0.02 - segmentLength = 100 - #previousvalues: - #proportionHetero = 0.24 - #proportionOpen = 0.01 - #segmentLength = 60 - } - else if (platform=="Illumina2.5M") { - maxHomozygous = 0.05 - proportionHetero = 0.21 - proportionHomo = 0.745 - proportionOpen = 0.03 - segmentLength = 100 - } - else if (platform=="IlluminaOmni5") { - maxHomozygous = 0.05 - proportionHetero = 0.13 - proportionHomo = 0.855 - proportionOpen = 0.01 - segmentLength = 100 - } - else if (platform=="Affy10k") { - maxHomozygous = 0.04 - proportionHetero = 0.355 - proportionHomo = 0.605 - proportionOpen = 0.025 - segmentLength = 20 - } - else if (platform=="Affy100k") { - maxHomozygous = 0.05 - proportionHetero = 0.27 - proportionHomo = 0.62 - proportionOpen = 0.09 - segmentLength = 30 - } - else if (platform=="Affy250k_sty") { - maxHomozygous = 0.05 - proportionHetero = 0.26 - proportionHomo = 0.66 - proportionOpen = 0.05 - segmentLength = 50 - } - else if (platform=="Affy250k_nsp") { - maxHomozygous = 0.05 - proportionHetero = 0.26 - proportionHomo = 0.66 - proportionOpen = 0.05 - segmentLength = 50 - } - else if (platform=="AffySNP6") { - maxHomozygous = 0.05 - proportionHetero = 0.25 - proportionHomo = 0.67 - proportionOpen = 0.04 - segmentLength = 100 - } - else if (platform=="AffyOncoScan") { - maxHomozygous = 0.05 - proportionHetero = 0.24 - proportionHomo = 0.69 - proportionOpen = 0.04 - segmentLength = 30 - } - else if (platform=="AffyCytoScanHD") { - maxHomozygous = 0.05 - proportionHetero = 0.26 - proportionHomo = 0.69 - proportionOpen = 0.03 - segmentLength = 30 - } - else { - print("Error: platform unknown") - } - - failedarrays = NULL - - for (i in 1:dim(ASCATobj$Tumor_LogR)[2]) { - png(filename = paste("tumorSep",colnames(ASCATobj$Tumor_LogR)[i],".png",sep=""), width = 2000, height = 500, res = 200) - par(mar = c(0.5,5,5,0.5), cex = 0.4, cex.main=3, cex.axis = 2, pch = ifelse(dim(ASCATobj$Tumor_LogR)[1]>100000,".",20)) - - Tumor_BAF_noNA = ASCATobj$Tumor_BAF[!is.na(ASCATobj$Tumor_BAF[,i]),i] - names(Tumor_BAF_noNA) = rownames(ASCATobj$Tumor_BAF)[!is.na(ASCATobj$Tumor_BAF[,i])] - Tumor_LogR_noNA = ASCATobj$Tumor_LogR[names(Tumor_BAF_noNA),i] - names(Tumor_LogR_noNA) = names(Tumor_BAF_noNA) - - chr_noNA = list() - prev = 0 - for(j in 1:length(ASCATobj$chr)) { - chrke = ASCATobj$chr[[j]] - next2 = prev + sum(!is.na(ASCATobj$Tumor_BAF[chrke,i])) - chr_noNA[[j]] = (prev+1):next2 - prev = next2 - } - - ch_noNA = list() - prev = 0 - for(j in 1:length(ASCATobj$ch)) { - chrke = ASCATobj$ch[[j]] - next2 = prev + sum(!is.na(ASCATobj$Tumor_BAF[chrke,i])) - ch_noNA[[j]] = (prev+1):next2 - prev = next2 - } - - tbsam = Tumor_BAF_noNA - # sample, mirrored - bsm = ifelse(tbsam<0.5, tbsam, 1-tbsam) - - homoLimit = max(sort(bsm)[round(length(bsm)*proportionHomo)],maxHomozygous) - - if(homoLimit>0.25) { - failedarrays = c(failedarrays,ASCATobj$samples[i]) - } - - Hom = ifelse(bsm0) { - - allProbes=1:length(Tumor_BAF_noNA) - nonHomoProbes = allProbes[is.na(Hom)|Hom==F] - - lowestDist = NULL - - # bsm, with homozygous replaced by NA - bsmHNA=bsm - bsmHNA[!is.na(Hom)&Hom]=NA - - for (chrke in chr_noNA) { - - chrNonHomoProbes = intersect(nonHomoProbes,chrke) - - # there must be a minimum number of probes on the chromosome, otherwise these are called homozygous anyway - if (length(chrNonHomoProbes)>5) { - - #make sure we're not going over any borders.. - segmentLength2 = min(length(chrNonHomoProbes)-1,segmentLength) - - chrNonHomoProbesStartWindowLeft = c(rep(NA,segmentLength2),chrNonHomoProbes[1:(length(chrNonHomoProbes)-segmentLength2)]) - chrNonHomoProbesEndWindowLeft = c(NA,chrNonHomoProbes[1:(length(chrNonHomoProbes)-1)]) - chrNonHomoProbesStartWindowRight = c(chrNonHomoProbes[2:length(chrNonHomoProbes)],NA) - chrNonHomoProbesEndWindowRight = c(chrNonHomoProbes[(segmentLength2+1):length(chrNonHomoProbes)],rep(NA,segmentLength2)) - chrNonHomoProbesStartWindowMiddle = c(rep(NA,segmentLength2/2),chrNonHomoProbes[1:(length(chrNonHomoProbes)-segmentLength2/2)]) - chrNonHomoProbesEndWindowMiddle = c(chrNonHomoProbes[(segmentLength2/2+1):length(chrNonHomoProbes)],rep(NA,segmentLength2/2)) - - chrLowestDist = NULL - - for (probeNr in 1:length(chrNonHomoProbes)) { - probe = chrNonHomoProbes[probeNr] - if(!is.na(chrNonHomoProbesStartWindowLeft[probeNr])&!is.na(chrNonHomoProbesEndWindowLeft[probeNr])) { - medianLeft = median(bsmHNA[chrNonHomoProbesStartWindowLeft[probeNr]:chrNonHomoProbesEndWindowLeft[probeNr]], na.rm=T) - } - else { - medianLeft = NA - } - if(!is.na(chrNonHomoProbesStartWindowRight[probeNr])&!is.na(chrNonHomoProbesEndWindowRight[probeNr])) { - medianRight = median(bsmHNA[chrNonHomoProbesStartWindowRight[probeNr]:chrNonHomoProbesEndWindowRight[probeNr]], na.rm=T) - } - else { - medianRight = NA - } - - if(!is.na(chrNonHomoProbesStartWindowMiddle[probeNr])&!is.na(chrNonHomoProbesEndWindowMiddle[probeNr])) { - medianMiddle = median(c(bsmHNA[chrNonHomoProbesStartWindowMiddle[probeNr]:chrNonHomoProbesEndWindowLeft[probeNr]], - bsmHNA[chrNonHomoProbesStartWindowRight[probeNr]:chrNonHomoProbesEndWindowMiddle[probeNr]]), na.rm=T) - } - else { - medianMiddle = NA - } - - chrLowestDist[probeNr] = min(abs(medianLeft-bsm[probe]),abs(medianRight-bsm[probe]),abs(medianMiddle-bsm[probe]),Inf,na.rm=T) - } - } - - # if too few probes on the chromosome - else { - chrLowestDist = NULL - if (length(chrNonHomoProbes)>0) { - # 1 is higher than any practical distance - chrLowestDist[1:length(chrNonHomoProbes)] = 1 - } - } - - lowestDist = c(lowestDist,chrLowestDist) - } - - lowestDistUndecided = lowestDist[is.na(Hom[nonHomoProbes])] - names(lowestDistUndecided)=names(Tumor_LogR_noNA)[nonHomoProbes[is.na(Hom[nonHomoProbes])]] - - sorted = sort(lowestDistUndecided) - Hom[names(sorted[1:min(length(sorted),extraHetero)])] = F - - Hetero = sum(Hom==F, na.rm=T) - Homo = sum(Hom==T, na.rm=T) - Undecided = sum(is.na(Hom)) - - } - - title = paste(paste(colnames(ASCATobj$Tumor_BAF)[i], Hetero), Homo) - plot(c(1,length(Tumor_BAF_noNA)), c(0,1), type = "n", xaxt = "n", main = title, xlab = "", ylab = "") - points(Tumor_BAF_noNA,col=ifelse(is.na(Hom),"green",ifelse(Hom,"blue","red"))) - - abline(v=0.5,lty=1,col="lightgrey") - chrk_tot_len = 0 - for (j in 1:length(ch_noNA)) { - chrk = ch_noNA[[j]]; - chrk_tot_len_prev = chrk_tot_len - chrk_tot_len = chrk_tot_len + length(chrk) - vpos = chrk_tot_len; - tpos = (chrk_tot_len+chrk_tot_len_prev)/2; - text(tpos,1,ASCATobj$chrs[j], pos = 1, cex = 2) - abline(v=vpos+0.5,lty=1,col="lightgrey") - } - - # set all Undecided to homozygous - Hom[is.na(Hom)] = T - - dev.off() - - Homozygous[names(Hom),i] = Hom - } - - return(list(germlinegenotypes = Homozygous, failedarrays = failedarrays)) - -} From 338808ae1a6231122b50816d1babb11022e887d0 Mon Sep 17 00:00:00 2001 From: Malin Larsson Date: Thu, 10 Oct 2019 11:55:41 +0200 Subject: [PATCH 113/854] fixed typo --- bin/run_ascat.r | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bin/run_ascat.r b/bin/run_ascat.r index beefb76cfb..596130138e 100755 --- a/bin/run_ascat.r +++ b/bin/run_ascat.r @@ -1,4 +1,4 @@ -#!/bin/env Rscript +q#!/bin/env Rscript args = commandArgs(trailingOnly=TRUE) if(length(args)<6){ stop("No input files supplied\n\nUsage:\nRscript run_ascat.r tumor_baf tumor_logr normal_baf normal_logr tumor_sample_name baseDir gcfile\n\n") @@ -20,7 +20,7 @@ if(!require(RColorBrewer)){ source("http://bioconductor.org/biocLite.R") biocLite("RColorBrewer", suppressUpdates=TRUE, lib="$baseDir/scripts") library(RColorBrewer) -}ls +} options(bitmapType='cairo') #Load the data @@ -34,7 +34,6 @@ if(gender=="XY"){ } - #GC wave correction ascat.bc = ascat.GCcorrect(ascat.bc, gcfile) From 3a8e91b371b5f6455aab7293b0a47a9b8649cfb1 Mon Sep 17 00:00:00 2001 From: Malin Larsson Date: Thu, 10 Oct 2019 11:58:52 +0200 Subject: [PATCH 114/854] removed the data folder --- data | 1 - 1 file changed, 1 deletion(-) delete mode 160000 data diff --git a/data b/data deleted file mode 160000 index e868cb311b..0000000000 --- a/data +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e868cb311bc8be4e0d8181ae2dc783ed88810ddd From f0e822531d158042b755a9be42fb33c3e64e66d7 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 11 Oct 2019 14:25:51 +0200 Subject: [PATCH 115/854] add location for abstracts --- docs/abstracts/2016-09-KICR.md | 2 +- docs/abstracts/2017-05-ESHG.md | 2 +- docs/abstracts/2018-05-PMC.md | 2 +- docs/abstracts/2018-06-EACR25.md | 2 +- docs/abstracts/2018-06-NPMI.md | 2 +- docs/abstracts/2018-07-JOBIM.md | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/abstracts/2016-09-KICR.md b/docs/abstracts/2016-09-KICR.md index 3b3df35eec..a5758c5288 100644 --- a/docs/abstracts/2016-09-KICR.md +++ b/docs/abstracts/2016-09-KICR.md @@ -1,4 +1,4 @@ -# The XVth KICancer Retreat 2016 +# The XVth KICancer Retreat - Djurö, Sweden, 2016/09 ## Cancer Analysis Workflow Of Tumor/Normal Pairs At The National Genomics Infrastructure Of SciLifeLab diff --git a/docs/abstracts/2017-05-ESHG.md b/docs/abstracts/2017-05-ESHG.md index 76e86db02f..8098600c34 100644 --- a/docs/abstracts/2017-05-ESHG.md +++ b/docs/abstracts/2017-05-ESHG.md @@ -1,4 +1,4 @@ -# European Human Genetics Conference 2017 +# European Human Genetics Conference - Copenhagen, Denmark, 2017/05 ## CAW - Cancer Analysis Workflow to process normal/tumor WGS data diff --git a/docs/abstracts/2018-05-PMC.md b/docs/abstracts/2018-05-PMC.md index 7e25e269b4..6f4ab2a166 100644 --- a/docs/abstracts/2018-05-PMC.md +++ b/docs/abstracts/2018-05-PMC.md @@ -1,4 +1,4 @@ -# Keystone Symposia - Precision Medicine in Cancer +# Keystone Symposia - Precision Medicine in Cancer - Stockholm, Sweden, 2018/05 ## Sarek, a workflow for WGS analysis of germline and somatic mutations diff --git a/docs/abstracts/2018-06-EACR25.md b/docs/abstracts/2018-06-EACR25.md index 57af817151..6a4be1c8df 100644 --- a/docs/abstracts/2018-06-EACR25.md +++ b/docs/abstracts/2018-06-EACR25.md @@ -1,4 +1,4 @@ -# 25th Biennial Congress Of The European Association For Cancer Research 2018 +# 25th Biennial Congress Of The European Association For Cancer Research - Amsterdam, Netherlands, 2018/06-07 ## Somatic and germline calls from tumour/normal whole genome data: bioinformatics workflow for reproducible research diff --git a/docs/abstracts/2018-06-NPMI.md b/docs/abstracts/2018-06-NPMI.md index ef15cc035f..fbb3d97d8c 100644 --- a/docs/abstracts/2018-06-NPMI.md +++ b/docs/abstracts/2018-06-NPMI.md @@ -1,4 +1,4 @@ -# The Nordic Precision Medicine Initiative - Meeting No 5 +# The Nordic Precision Medicine Initiative - Meeting No 5 - Reykjavìk, Iceland, 2018/06 ## Sarek, a portable workflow for WGS analysis of germline and somatic mutations diff --git a/docs/abstracts/2018-07-JOBIM.md b/docs/abstracts/2018-07-JOBIM.md index 19e42d372c..9a6257cddb 100644 --- a/docs/abstracts/2018-07-JOBIM.md +++ b/docs/abstracts/2018-07-JOBIM.md @@ -1,4 +1,4 @@ -# Journées Ouvertes en Biologie, Informatique et Mathématiques 2018 +# Journées Ouvertes en Biologie, Informatique et Mathématiques - Marseille, France, 2018/07 ## Sarek, a portable workflow for WGS analysis of germline and somatic mutations From 2eef74344afd9e8e5af12121bfd583cd84d7025f Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 11 Oct 2019 14:26:06 +0200 Subject: [PATCH 116/854] remove reference to old buil.nf script --- docs/reference.md | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index 1d5d10c729..6240efe77f 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -12,8 +12,8 @@ Settings in `igenomes.config` can be tailored to your needs. To speed up some preprocessing and variant calling processes, the reference is chopped into smaller pieces. The intervals are chromosomes cut at their centromeres (so each chromosome arm processed separately) also additional unassigned contigs. -We are ignoring the hs37d5 contig that contains concatenated decoy sequences. -Parts of preprocessing and variant calling are done by this intervals, and the different resulting files are then merged. +We are ignoring the `hs37d5` contig that contains concatenated decoy sequences. +Parts of preprocessing and variant calling are done by these intervals, and the different resulting files are then merged. This can parallelize processes, and push down wall clock time significantly. The calling intervals can be defined using a `.list` or a `.bed` file. @@ -36,11 +36,3 @@ First, when there are multiple consecutive intervals in the file that take littl Second, the jobs with largest processing time are started first, which reduces wall-clock time. If no runtime is given, a time of 1000 nucleotides per second is assumed. Actual figures vary from 2 nucleotides/second to 30000 nucleotides/second. - -## build.nf - -The [`build.nf`](#buildnf) script is used to build reference needed for smallGRCh37. - -```bash -nextflow run build.nf -``` From 5df80a58a888e64c065ec19b90fb344461670799 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 11 Oct 2019 14:29:48 +0200 Subject: [PATCH 117/854] update CHANGELOG --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 436428b1c0..06ddb12e8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [#41](https://github.com/nf-core/sarek/pull/41) - Update `qualimap` from `2.2.2b` to `2.2.2c` - [#41](https://github.com/nf-core/sarek/pull/41) - Update `tiddit` from `2.7.1` to `2.8.0` - [#41](https://github.com/nf-core/sarek/pull/41) - Update `vcfanno` from `0.3.1` to `0.3.2` +- [#46](https://github.com/nf-core/sarek/pull/46) - Add location to abstacts. + +### `Removed` + +- [#46](https://github.com/nf-core/sarek/pull/46) - Remove mention of old `build.nf` script which was included in `main.nf` ### `Fixed` From 318a7abefc67b9bc0a7e9625b4e6e7c5f823cb8a Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Fri, 11 Oct 2019 15:25:04 +0200 Subject: [PATCH 118/854] Update docs/reference.md Co-Authored-By: Szilveszter Juhos --- docs/reference.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/reference.md b/docs/reference.md index 6240efe77f..7fe7b43ad1 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -35,4 +35,12 @@ The runtime estimate is used in two different ways. First, when there are multiple consecutive intervals in the file that take little time to compute, they are processed as a single job, thus reducing the number of processes that needs to be spawned. Second, the jobs with largest processing time are started first, which reduces wall-clock time. If no runtime is given, a time of 1000 nucleotides per second is assumed. -Actual figures vary from 2 nucleotides/second to 30000 nucleotides/second. + Actual figures vary from 2 nucleotides/second to 30000 nucleotides/second. + +### Working with whole exom (WES) or panel data + +The `--targetBED` parameter does _not_ imply that the workflow is running alignment or variant calling only for the supplied targets. +Instead, we are aligning for the whole genome, and selecting variants only at the very end by intersecting with the provided target file. +Adding every exon as an interval in case of WES can generate >200K processes or jobs, much more forks, and similar number of directories in the Nextflow work directory. +Furthermore, primers and/or baits are not 100% specific, (certainly not for MHC and KIR, etc.), quite likely there going to be reads mapping to multiple locations. +If you are certain that the target is unique for your genome (all the reads will certainly map to only one location), and aligning to the whole genome is an overkill, better to change the reference itself. From c8f748f83644321709e0e69bf843cfcec2d98c1d Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Fri, 11 Oct 2019 15:25:24 +0200 Subject: [PATCH 119/854] Update docs/reference.md --- docs/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference.md b/docs/reference.md index 7fe7b43ad1..071d9c385f 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -35,7 +35,7 @@ The runtime estimate is used in two different ways. First, when there are multiple consecutive intervals in the file that take little time to compute, they are processed as a single job, thus reducing the number of processes that needs to be spawned. Second, the jobs with largest processing time are started first, which reduces wall-clock time. If no runtime is given, a time of 1000 nucleotides per second is assumed. - Actual figures vary from 2 nucleotides/second to 30000 nucleotides/second. +Actual figures vary from 2 nucleotides/second to 30000 nucleotides/second. ### Working with whole exom (WES) or panel data From 444584714b45c638d3458ebb6c064e90e2c81906 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Fri, 11 Oct 2019 15:26:24 +0200 Subject: [PATCH 120/854] Update docs/reference.md --- docs/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference.md b/docs/reference.md index 071d9c385f..5c47b7dddb 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -37,7 +37,7 @@ Second, the jobs with largest processing time are started first, which reduces w If no runtime is given, a time of 1000 nucleotides per second is assumed. Actual figures vary from 2 nucleotides/second to 30000 nucleotides/second. -### Working with whole exom (WES) or panel data +### Working with whole exome (WES) or panel data The `--targetBED` parameter does _not_ imply that the workflow is running alignment or variant calling only for the supplied targets. Instead, we are aligning for the whole genome, and selecting variants only at the very end by intersecting with the provided target file. From f1483acfb02af4aa90ccf9d538b5283f36c0039b Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Fri, 11 Oct 2019 15:38:50 +0200 Subject: [PATCH 121/854] Worfklow (#45) * Add workflow figure * Include workflow figure in readme * Update CHANGELOG --- .github/markdownlint.yml | 3 +- CHANGELOG.md | 1 + README.md | 7 +- docs/images/sarek_workflow.png | Bin 0 -> 50856 bytes docs/images/sarek_workflow.svg | 3675 ++++++++++++++++++++++++++++++++ 5 files changed, 3683 insertions(+), 3 deletions(-) create mode 100644 docs/images/sarek_workflow.png create mode 100644 docs/images/sarek_workflow.svg diff --git a/.github/markdownlint.yml b/.github/markdownlint.yml index 8f97a170e8..9a0066d6f0 100644 --- a/.github/markdownlint.yml +++ b/.github/markdownlint.yml @@ -9,4 +9,5 @@ no-duplicate-header: siblings_only: true no-inline-html: allowed_elements: - - img \ No newline at end of file + - img + - p \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 436428b1c0..e39a31024d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [#41](https://github.com/nf-core/sarek/pull/41) - Update `qualimap` from `2.2.2b` to `2.2.2c` - [#41](https://github.com/nf-core/sarek/pull/41) - Update `tiddit` from `2.7.1` to `2.8.0` - [#41](https://github.com/nf-core/sarek/pull/41) - Update `vcfanno` from `0.3.1` to `0.3.2` +- [#45](https://github.com/nf-core/sarek/pull/45) - Include Workflow figure in `README.md` ### `Fixed` diff --git a/README.md b/README.md index 0de61ba17c..d689576f19 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,9 @@ [![Join us on Slack](https://img.shields.io/badge/slack-nfcore/sarek-blue.svg)](https://nfcore.slack.com/messages/CGFUX04HZ/) - ## Introduction - + Previously known as the Cancer Analysis Workflow (CAW), Sarek is a workflow designed to run analyses on whole genome or targeted sequencing data from regular samples or tumour / normal pairs and could include additional relapses. @@ -29,6 +28,10 @@ across multiple compute infrastructures in a very portable manner. Software dependencies are handled using [Conda](https://conda.io/), [Docker](https://www.docker.com) or [Singularity](https://www.sylabs.io/singularity/) - environment/container technologies that provide excellent reproducibility and ease of use. Thus making installation trivial and results highly reproducible. +

+ +

+ It's listed on the [Elixir - Tools and Data Services Registry](https://bio.tools/Sarek), [Dockstore](https://dockstore.org/workflows/github.com/nf-core/sarek) and [omicX - Bioinformatics tools](https://omictools.com/sarek-tool). ## Documentation diff --git a/docs/images/sarek_workflow.png b/docs/images/sarek_workflow.png new file mode 100644 index 0000000000000000000000000000000000000000..f7f019de0cd8cec8f39e17cfdc182eefb16a9160 GIT binary patch literal 50856 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 + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +r + + + + + + + + +fastqfastqfastqbambambamvcfvcfvcfBased on GATK Best PracticesPreprocessing + + +• HaplotypeCaller Strelka2• Manta, TIDDITVariant Calling• Freebayes, Mutect2 Strelka2• Manta• ASCAT, Control-FREECsnpEff, VEPsnpEff, VEPAnnotation + + +Reports + + +2.5 \ No newline at end of file From 2b2f7e8fdcb5651ea80f4de7c691ce29ae9a94b1 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 21 Oct 2019 10:07:13 +0200 Subject: [PATCH 122/854] add minimal genome and update some processes --- conf/genomes.config | 4 +++ main.nf | 78 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/conf/genomes.config b/conf/genomes.config index 7d7527b21a..d9ffcef42c 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -58,5 +58,9 @@ params { snpeffDb = "GRCh37.75" vepCacheVersion = "95" } + 'minimalGRCh37' { + fasta = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" + knownIndels = "${params.genomes_base}/dbsnp_138.b37.small.vcf.gz" + } } } diff --git a/main.nf b/main.nf index ffe3b12b7d..140c851af9 100644 --- a/main.nf +++ b/main.nf @@ -518,7 +518,7 @@ process CreateIntervalBeds { output: file '*.bed' into bedIntervals mode flatten - when: step != 'annotate' + when: params.intervals && step != 'annotate' script: // If the interval file is BED format, the fifth column is interpreted to @@ -762,7 +762,10 @@ if ('markduplicates' in skipQC) markDuplicatesReport.close() duplicateMarkedBams = duplicateMarkedBams.dump(tag:'MD BAM') markDuplicatesReport = markDuplicatesReport.dump(tag:'MD Report') -(bamMD, bamMDToJoin) = duplicateMarkedBams.into(2) +(bamMD, bamBaseRecalibratorNoInt, bamMDToJoin) = duplicateMarkedBams.into(3) + +// if (params.intervals) bamBaseRecalibratorNoInt.close() + bamBaseRecalibrator = bamMD.combine(intBaseRecalibrator) bamBaseRecalibrator = bamBaseRecalibrator.dump(tag:'BAM FOR BASERECALIBRATOR') @@ -791,7 +794,8 @@ process BaseRecalibrator { when: step == 'mapping' script: - known = knownIndels.collect{"--known-sites ${it}"}.join(' ') + dbsnpOptions = params.dbsnp ? "--known-sites ${dbsnp}" : "" + knownOptions = params.knownIndels ? knownIndels.collect{"--known-sites ${it}"}.join(' ') : "" // TODO: --use-original-qualities ??? """ gatk --java-options -Xmx${task.memory.toGiga()}g \ @@ -801,8 +805,44 @@ process BaseRecalibrator { --tmp-dir /tmp \ -R ${fasta} \ -L ${intervalBed} \ - --known-sites ${dbsnp} \ - ${known} \ + ${dbsnpOptions} \ + ${knownOptions} \ + --verbosity INFO + """ +} + +// STEP 3': CREATING RECALIBRATION TABLES WITHOUT INTERVALS + +process BaseRecalibratorNoIntervals { + label 'memory_max' + label 'cpus_1' + + tag {idPatient + "-" + idSample} + + input: + set idPatient, idSample, file(bam), file(bai) from bamBaseRecalibratorNoInt + file(fasta) from ch_fasta + file(dict) from ch_dict + file(fastaFai) from ch_fastaFai + file(knownIndels) from ch_knownIndels + file(knownIndelsIndex) from ch_knownIndelsIndex + + output: + set idPatient, idSample, file("${idSample}.recal.table") into bamMDnoInt + + when: step == 'mapping' + + script: + knownOptions = params.knownIndels ? knownIndels.collect{"--known-sites ${it}"}.join(' ') : "" + // TODO: --use-original-qualities ??? + """ + gatk --java-options -Xmx${task.memory.toGiga()}g \ + BaseRecalibrator \ + -I ${bam} \ + -O ${idSample}.recal.table \ + --tmp-dir /tmp \ + -R ${fasta} \ + ${knownOptions} \ --verbosity INFO """ } @@ -894,6 +934,34 @@ process ApplyBQSR { bamMergeBamRecal = bamMergeBamRecal.groupTuple(by:[0, 1]) +// STEP 4': RECALIBRATING WITHOUT INTERVALS + +process ApplyBQSRnoIntervals { + label 'memory_singleCPU_2_task' + label 'cpus_2' + + tag {idPatient + "-" + idSample} + + input: + set idPatient, idSample, file(bam), file(bai), file(recalibrationReport) from bamMDnoInt + file(dict) from ch_dict + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai + + output: + set idPatient, idSample, file("${idSample}.recal.bam") into bamRecalNoInt + + script: + """ + gatk --java-options -Xmx${task.memory.toGiga()}g \ + ApplyBQSR \ + -R ${fasta} \ + --input ${bam} \ + --output ${idSample}.recal.bam \ + --bqsr-recal-file ${recalibrationReport} + """ +} + // STEP 4.5: MERGING THE RECALIBRATED BAM FILES process MergeBamRecal { From 065ae5054c9cbefdc1d7900a3f64e473f8835011 Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Mon, 21 Oct 2019 12:10:45 +0200 Subject: [PATCH 123/854] Start adding mouse data --- conf/igenomes.config | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/conf/igenomes.config b/conf/igenomes.config index 79f7b85484..1f04ab3074 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -47,5 +47,24 @@ params { snpeffDb = "GRCh38.86" vepCacheVersion = "95" } + 'GRCm38' { + acLoci = "${params.igenomes_base}/Mus_musculus/Annotation/ASCAT/GRCm38.loci" + acLociGC = "${params.igenomes_base}/Mus_musculus/Annotation/ASCAT/GRCm38.loci.gc" + bwaIndex = "${params.igenomes_base}/Mus_musculus/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + chrDir = "${params.igenomes_base}/Mus_musculus/Sequence/Chromosomes" + chrLength = "${params.igenomes_base}/Mus_musculus/Sequence/Length/Homo_sapiens_assembly38.len" + dbsnp = "${params.igenomes_base}/Mus_musculus/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz" + dbsnpIndex = "${params.igenomes_base}/Mus_musculus/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz.tbi" + dict = "${params.igenomes_base}/Mus_musculus/Sequence/WholeGenomeFasta/genome.dict" + fasta = "${params.igenomes_base}/Mus_musculus/Sequence/WholeGenomeFasta/genome.fa" + fastaFai = "${params.igenomes_base}/Mus_musculus/Sequence/WholeGenomeFasta/genome.fai" + germlineResource = "${params.igenomes_base}/Mus_musculus/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh38.PASS.AC.AF.only.vcf.gz" + germlineResourceIndex = "${params.igenomes_base}/Mus_musculus/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh38.PASS.AC.AF.only.vcf.gz.tbi" + intervals = "${params.igenomes_base}/Mus_musculus/Annotation/intervals/wgs_calling_regions.hg38.bed" + knownIndels = "${params.igenomes_base}/Mus_musculus/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" + knownIndelsIndex = "${params.igenomes_base}/Mus_musculus/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" + snpeffDb = "GRCh38.86" + vepCacheVersion = "95" + } } } From 81485467b51a6616c86467284b813151046fcc45 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 21 Oct 2019 14:25:22 +0200 Subject: [PATCH 124/854] nf-core bump-version . 2.5.1 --- .travis.yml | 2 +- Dockerfile | 2 +- environment.yml | 2 +- nextflow.config | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3598ccf284..e08837e8fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ before_install: - docker pull nfcore/sarek:dev # Fake the tag locally so that the pipeline runs properly # Looks weird when this is :dev to :dev, but makes sense when testing code for a release (:dev to :1.0.1) - - docker tag nfcore/sarek:dev nfcore/sarek:2.5 + - docker tag nfcore/sarek:dev nfcore/sarek:2.5.1 install: # Install Nextflow diff --git a/Dockerfile b/Dockerfile index c012a49d05..c493eab98f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,4 +4,4 @@ LABEL authors="Maxime Garcia, Szilveszter Juhos" \ COPY environment.yml / RUN conda env create -f /environment.yml && conda clean -a -ENV PATH /opt/conda/envs/nf-core-sarek-2.5/bin:$PATH +ENV PATH /opt/conda/envs/nf-core-sarek-2.5.1/bin:$PATH diff --git a/environment.yml b/environment.yml index 2ae3303c97..c27f23966a 100644 --- a/environment.yml +++ b/environment.yml @@ -1,6 +1,6 @@ # You can use this file to create a conda environment for this pipeline: # conda env create -f environment.yml -name: nf-core-sarek-2.5 +name: nf-core-sarek-2.5.1 channels: - conda-forge - bioconda diff --git a/nextflow.config b/nextflow.config index 852831b8e4..d9aa514c8d 100644 --- a/nextflow.config +++ b/nextflow.config @@ -86,7 +86,7 @@ params { // Container slug. Stable releases should specify release tag! // Developmental code should specify :dev -process.container = 'nfcore/sarek:2.5' +process.container = 'nfcore/sarek:2.5.1' // Load base.config by default for all pipelines includeConfig 'conf/base.config' @@ -156,7 +156,7 @@ manifest { description = 'An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing' mainScript = 'main.nf' nextflowVersion = '>=19.04.0' - version = '2.5' + version = '2.5.1' } // Return the minimum between requirements and a maximum limit to ensure that resource requirements don't go over From e3453c686d83d0f0d8bd070e1b1ad07e53eb2e5c Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 21 Oct 2019 14:26:23 +0200 Subject: [PATCH 125/854] fix script name in docs --- docs/install_bianca.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/install_bianca.md b/docs/install_bianca.md index 5bb8c176c8..6cc0b51960 100644 --- a/docs/install_bianca.md +++ b/docs/install_bianca.md @@ -92,10 +92,10 @@ You can either download nf-core/sarek on your computer or on `rackham`, make an > pip install git-archive-all # If you used --user before, you might want to do that here too > pip install git-archive-all --user -> ./scripts/makeSnapshot.sh --include-test-data --include-configs +> ./scripts/make_snapshot.sh --include-test-data --include-configs # Or you can just include nf-core/sarek: -> ./scripts/makeSnapshot.sh +> ./scripts/make_snapshot.sh # You will get this message in your terminal Wrote sarek-[snapID].tar.gz From 6aa109130e72fd51b71c46f5ca6032366aab16ef Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 21 Oct 2019 14:27:49 +0200 Subject: [PATCH 126/854] fix markdownlint --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 10e2544ca6..8460be05c9 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ For further information or help, don't hesitate to get in touch on [Slack](https If you use nf-core/sarek for your analysis, please cite the `Sarek` pre-print as follows: > Garcia MU, Juhos S, Larsson M, Olason PI, Martin M, Eisfeldt J, DiLorenzo S, Sandgren J, de Ståhl TD, Wirta V, Nistér M, Nystedt B, Käller M. **Sarek: A portable workflow for whole-genome sequencing analysis of germline and somatic variants**. *bioRxiv*. 2018. p. 316976. [doi: 10.1101/316976](https://www.biorxiv.org/content/10.1101/316976v1). -You can cite the sarek zenodo record for a specific version using the following [DOI: 10.5281/zenodo.3476426 ](https://zenodo.org/badge/latestdoi/184289291) +You can cite the sarek zenodo record for a specific version using the following [doi: 10.5281/zenodo.3476426](https://zenodo.org/badge/latestdoi/184289291) You can cite the `nf-core` pre-print as follows: > Ewels PA, Peltzer A, Fillinger S, Alneberg JA, Patel H, Wilm A, Garcia MU, Di Tommaso P, Nahnsen S. **nf-core: Community curated bioinformatics pipelines**. *bioRxiv*. 2019. p. 610741. [doi: 10.1101/610741](https://www.biorxiv.org/content/10.1101/610741v3). From 33ff41fb77e66522ac20beb8eef0da7e467cc20a Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 21 Oct 2019 14:28:42 +0200 Subject: [PATCH 127/854] fix autoMounts in singularity profile, closes #48 --- nextflow.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextflow.config b/nextflow.config index d9aa514c8d..66b9397593 100644 --- a/nextflow.config +++ b/nextflow.config @@ -115,8 +115,8 @@ profiles { singularity.enabled = false } singularity { - autoMounts = true docker.enabled = false + singularity.autoMounts = true singularity.enabled = true } test { includeConfig 'conf/test.config' } From a7b0f0002d7136cac96d8b5740e475fd257d24fd Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 21 Oct 2019 14:30:23 +0200 Subject: [PATCH 128/854] fix path to script, close #50 --- main.nf | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/main.nf b/main.nf index ffe3b12b7d..204f315b4d 100644 --- a/main.nf +++ b/main.nf @@ -1983,12 +1983,12 @@ process ControlFreecViz { when: 'controlfreec' in tools """ - cat /opt/conda/envs/sarek-${workflow.manifest.version}/bin/assess_significance.R | R --slave --args ${cnvTumor} ${ratioTumor} - cat /opt/conda/envs/sarek-${workflow.manifest.version}/bin/assess_significance.R | R --slave --args ${cnvNormal} ${ratioNormal} - cat /opt/conda/envs/sarek-${workflow.manifest.version}/bin/makeGraph.R | R --slave --args 2 ${ratioTumor} ${bafTumor} - cat /opt/conda/envs/sarek-${workflow.manifest.version}/bin/makeGraph.R | R --slave --args 2 ${ratioNormal} ${bafNormal} - perl /opt/conda/envs/sarek-${workflow.manifest.version}/bin/freec2bed.pl -f ${ratioTumor} > ${idSampleTumor}.bed - perl /opt/conda/envs/sarek-${workflow.manifest.version}/bin/freec2bed.pl -f ${ratioNormal} > ${idSampleNormal}.bed + cat /opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/bin/assess_significance.R | R --slave --args ${cnvTumor} ${ratioTumor} + cat /opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/bin/assess_significance.R | R --slave --args ${cnvNormal} ${ratioNormal} + cat /opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/bin/makeGraph.R | R --slave --args 2 ${ratioTumor} ${bafTumor} + cat /opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/bin/makeGraph.R | R --slave --args 2 ${ratioNormal} ${bafNormal} + perl /opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/bin/freec2bed.pl -f ${ratioTumor} > ${idSampleTumor}.bed + perl /opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/bin/freec2bed.pl -f ${ratioNormal} > ${idSampleNormal}.bed """ } @@ -2249,7 +2249,7 @@ process VEP { genome = params.genome == 'smallGRCh37' ? 'GRCh37' : params.genome dir_cache = (params.vep_cache && params.annotation_cache) ? " \${PWD}/${dataDir}" : "/.vep" cadd = (params.cadd_cache && params.cadd_WG_SNVs && params.cadd_InDels) ? "--plugin CADD,whole_genome_SNVs.tsv.gz,InDels.tsv.gz" : "" - genesplicer = params.genesplicer ? "--plugin GeneSplicer,/opt/conda/envs/sarek-${workflow.manifest.version}/bin/genesplicer,/opt/conda/envs/sarek-${workflow.manifest.version}/share/genesplicer-1.0-1/human,context=200,tmpdir=\$PWD/${reducedVCF}" : "--offline" + genesplicer = params.genesplicer ? "--plugin GeneSplicer,/opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/bin/genesplicer,/opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/share/genesplicer-1.0-1/human,context=200,tmpdir=\$PWD/${reducedVCF}" : "--offline" """ mkdir ${reducedVCF} @@ -2310,7 +2310,7 @@ process VEPmerge { genome = params.genome == 'smallGRCh37' ? 'GRCh37' : params.genome dir_cache = (params.vep_cache && params.annotation_cache) ? " \${PWD}/${dataDir}" : "/.vep" cadd = (params.cadd_cache && params.cadd_WG_SNVs && params.cadd_InDels) ? "--plugin CADD,whole_genome_SNVs.tsv.gz,InDels.tsv.gz" : "" - genesplicer = params.genesplicer ? "--plugin GeneSplicer,/opt/conda/envs/sarek-${workflow.manifest.version}/bin/genesplicer,/opt/conda/envs/sarek-${workflow.manifest.version}/share/genesplicer-1.0-1/human,context=200,tmpdir=\$PWD/${reducedVCF}" : "--offline" + genesplicer = params.genesplicer ? "--plugin GeneSplicer,/opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/bin/genesplicer,/opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/share/genesplicer-1.0-1/human,context=200,tmpdir=\$PWD/${reducedVCF}" : "--offline" """ mkdir ${reducedVCF} From a3e45c6e046589b38e283c6bab1a30a20d9959d4 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 21 Oct 2019 15:33:01 +0200 Subject: [PATCH 129/854] build 2.5.1 version of annotation containers --- .circleci/config.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1ede7ab8fe..2da763cf15 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,11 +10,11 @@ jobs: - checkout - setup_remote_docker - run: - command: docker build -t nfcore/sareksnpeff:2.5.${GENOME} containers/snpeff/. --build-arg GENOME=${GENOME} --build-arg SNPEFF_CACHE_VERSION=${SNPEFF_CACHE_VERSION} + command: docker build -t nfcore/sareksnpeff:2.5.1.${GENOME} containers/snpeff/. --build-arg GENOME=${GENOME} --build-arg SNPEFF_CACHE_VERSION=${SNPEFF_CACHE_VERSION} - run: command: | echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin - docker push nfcore/sareksnpeff:2.5.${GENOME} + docker push nfcore/sareksnpeff:2.5.1.${GENOME} snpeffgrch38: << : *buildsnpeff @@ -45,10 +45,10 @@ jobs: - checkout - setup_remote_docker - run: - command: docker build -t nfcore/sarekvep:2.5.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} + command: docker build -t nfcore/sarekvep:2.5.1.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} no_output_timeout: 3h - run: - command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:2.5.${GENOME} + command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:2.5.1.${GENOME} vepgrch38: << : *buildvep From d00a8f7b531f8f22adbb4b84693571b880263997 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 21 Oct 2019 15:33:29 +0200 Subject: [PATCH 130/854] add patch to branch protection --- .github/workflows/branch.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 58a41ff689..054d2d78f2 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -13,4 +13,4 @@ jobs: - uses: actions/checkout@v1 - name: Check PRs run: | - [[ $(git remote get-url origin) == *nf-core/sarek ]] && [ ${GITHUB_BASE_REF} = "master" ] && [ ${GITHUB_HEAD_REF} = "dev" ] + [[ $(git remote get-url origin) == *nf-core/sarek ]] && [[ ${GITHUB_BASE_REF} = "master" ]] && { [[ ${GITHUB_HEAD_REF} = "dev" ]] || [[ ${GITHUB_BASE_REF} = "patch" ]]; } \ No newline at end of file From 8dfc48ace72a59e0c93bd4cf9367ef72912e90c4 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 21 Oct 2019 15:35:28 +0200 Subject: [PATCH 131/854] pull image 2.5,tag it as 2.5.1 --- .github/workflows/ci-extra.yml | 2 +- .github/workflows/ci.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-extra.yml b/.github/workflows/ci-extra.yml index 040dc11ffe..442be114bb 100644 --- a/.github/workflows/ci-extra.yml +++ b/.github/workflows/ci-extra.yml @@ -18,7 +18,7 @@ jobs: sudo mv nextflow /usr/local/bin/ - name: Download image run: | - ${GITHUB_WORKSPACE}/scripts/download_image.sh -n docker --source-version dev --target-version 2.5 --test ${{ matrix.test }} + ${GITHUB_WORKSPACE}/scripts/download_image.sh -n docker --source-version 2.5 --target-version 2.5.1 --test ${{ matrix.test }} - name: Run test run: | ${GITHUB_WORKSPACE}/scripts/run_tests.sh --test ${{ matrix.test }} --verbose \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 785fb9269c..16fc90d4d1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,8 +17,8 @@ jobs: sudo mv nextflow /usr/local/bin/ - name: Download and tag image run: | - docker pull nfcore/sarek:dev - docker tag nfcore/sarek:dev nfcore/sarek:2.5 + docker pull nfcore/sarek:2.5 + docker tag nfcore/sarek:2.5 nfcore/sarek:2.5.1 - name: Run test run: | nextflow run ${GITHUB_WORKSPACE} -profile test,docker \ No newline at end of file From 77ec187a3ecadce02f158a447775b007cda57ada Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Mon, 21 Oct 2019 15:47:37 +0200 Subject: [PATCH 132/854] Update iGenomes.config --- conf/igenomes.config | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/conf/igenomes.config b/conf/igenomes.config index 1f04ab3074..6acb25efd7 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -48,21 +48,21 @@ params { vepCacheVersion = "95" } 'GRCm38' { - acLoci = "${params.igenomes_base}/Mus_musculus/Annotation/ASCAT/GRCm38.loci" - acLociGC = "${params.igenomes_base}/Mus_musculus/Annotation/ASCAT/GRCm38.loci.gc" + acLoci = "${params.igenomes_base}/Mus_musculus/Annotation/ASCAT/fake.loci" + acLociGC = "${params.igenomes_base}/Mus_musculus/Annotation/ASCAT/fake.loci.gc" bwaIndex = "${params.igenomes_base}/Mus_musculus/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" chrDir = "${params.igenomes_base}/Mus_musculus/Sequence/Chromosomes" chrLength = "${params.igenomes_base}/Mus_musculus/Sequence/Length/Homo_sapiens_assembly38.len" - dbsnp = "${params.igenomes_base}/Mus_musculus/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz" - dbsnpIndex = "${params.igenomes_base}/Mus_musculus/Annotation/GATKBundle/dbsnp_146.hg38.vcf.gz.tbi" + dbsnp = "${params.igenomes_base}/Mus_musculus/Annotation/mgp.v6.merged.norm.snp.indels.sfiltered.vcf.gz" + dbsnpIndex = "${params.igenomes_base}/Mus_musculus/Annotation/mgp.v6.merged.norm.snp.indels.sfiltered.vcf.gz.tbi" dict = "${params.igenomes_base}/Mus_musculus/Sequence/WholeGenomeFasta/genome.dict" fasta = "${params.igenomes_base}/Mus_musculus/Sequence/WholeGenomeFasta/genome.fa" fastaFai = "${params.igenomes_base}/Mus_musculus/Sequence/WholeGenomeFasta/genome.fai" germlineResource = "${params.igenomes_base}/Mus_musculus/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh38.PASS.AC.AF.only.vcf.gz" germlineResourceIndex = "${params.igenomes_base}/Mus_musculus/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh38.PASS.AC.AF.only.vcf.gz.tbi" intervals = "${params.igenomes_base}/Mus_musculus/Annotation/intervals/wgs_calling_regions.hg38.bed" - knownIndels = "${params.igenomes_base}/Mus_musculus/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" - knownIndelsIndex = "${params.igenomes_base}/Mus_musculus/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" + knownIndels = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz" + knownIndelsIndex = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.snps_all.dbSNP142.vcf.gz" snpeffDb = "GRCh38.86" vepCacheVersion = "95" } From db69d295695a210537b25bfb355fab6d311e886a Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Mon, 21 Oct 2019 15:48:10 +0200 Subject: [PATCH 133/854] Add tbi --- conf/igenomes.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/igenomes.config b/conf/igenomes.config index 6acb25efd7..069ae30881 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -62,7 +62,7 @@ params { germlineResourceIndex = "${params.igenomes_base}/Mus_musculus/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh38.PASS.AC.AF.only.vcf.gz.tbi" intervals = "${params.igenomes_base}/Mus_musculus/Annotation/intervals/wgs_calling_regions.hg38.bed" knownIndels = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz" - knownIndelsIndex = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.snps_all.dbSNP142.vcf.gz" + knownIndelsIndex = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz.tbi" snpeffDb = "GRCh38.86" vepCacheVersion = "95" } From 8995981e88c8154684ea45393b8f3f3b7d47d1be Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Mon, 21 Oct 2019 16:00:48 +0200 Subject: [PATCH 134/854] Drop ASCAT files --- conf/igenomes.config | 2 -- 1 file changed, 2 deletions(-) diff --git a/conf/igenomes.config b/conf/igenomes.config index 069ae30881..a04e2e5397 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -48,8 +48,6 @@ params { vepCacheVersion = "95" } 'GRCm38' { - acLoci = "${params.igenomes_base}/Mus_musculus/Annotation/ASCAT/fake.loci" - acLociGC = "${params.igenomes_base}/Mus_musculus/Annotation/ASCAT/fake.loci.gc" bwaIndex = "${params.igenomes_base}/Mus_musculus/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" chrDir = "${params.igenomes_base}/Mus_musculus/Sequence/Chromosomes" chrLength = "${params.igenomes_base}/Mus_musculus/Sequence/Length/Homo_sapiens_assembly38.len" From db4775c2cd067a82745bae9f64d65bc7f2e8a98c Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 21 Oct 2019 16:29:34 +0200 Subject: [PATCH 135/854] pull image 2.5,tag it as 2.5.1 --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 924e454f0d..ffe06115b0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -8,7 +8,7 @@ pipeline { stages { stage('Docker setup') { steps { - sh "./scripts/download_image.sh -n docker -t ALL --source-version dev --target-version 2.5 -g smallGRCh37" + sh "./scripts/download_image.sh -n docker -t ALL --source-version 2.5 --target-version 2.5.1 -g smallGRCh37" } } stage('Germline') { From 642ddfb72eb28317f1a679f2e2eacb9ff68cc859 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 21 Oct 2019 16:30:21 +0200 Subject: [PATCH 136/854] use correct tag for containers close #49 --- conf/base.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/base.config b/conf/base.config index 5c76d275e6..4e46501b14 100644 --- a/conf/base.config +++ b/conf/base.config @@ -68,11 +68,11 @@ process { errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} } withName:Snpeff { - container = {(params.annotation_cache && params.snpEff_cache) ? 'nfcore/sarek:dev' : "nfcore/sareksnpeff:dev.${params.genome}"} + container = {(params.annotation_cache && params.snpEff_cache) ? 'nfcore/sarek:2.5.1' : "nfcore/sareksnpeff:2.5.1.${params.genome}"} errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} } withLabel:VEP { - container = {(params.annotation_cache && params.vep_cache) ? 'nfcore/sarek:dev' : "nfcore/sarekvep:dev.${params.genome}"} + container = {(params.annotation_cache && params.vep_cache) ? 'nfcore/sarek:2.5.1' : "nfcore/sarekvep:2.5.1.${params.genome}"} errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} } } From 94c82e221a3f21d6fd54cd0a643f482adc41b31f Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 21 Oct 2019 16:32:18 +0200 Subject: [PATCH 137/854] bump version to 2.5.1 --- containers/snpeff/Dockerfile | 2 +- containers/snpeff/environment.yml | 2 +- containers/vep/Dockerfile | 2 +- containers/vep/environment.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/containers/snpeff/Dockerfile b/containers/snpeff/Dockerfile index 3ac9b89dd7..769ef317e9 100644 --- a/containers/snpeff/Dockerfile +++ b/containers/snpeff/Dockerfile @@ -7,7 +7,7 @@ LABEL \ COPY environment.yml / RUN conda env create -f /environment.yml && conda clean -a -ENV PATH /opt/conda/envs/sarek-snpeff-2.5/bin:$PATH +ENV PATH /opt/conda/envs/sarek-snpeff-2.5.1/bin:$PATH # Setup default ARG variables ARG GENOME=GRCh38 diff --git a/containers/snpeff/environment.yml b/containers/snpeff/environment.yml index fd93bd1815..31428bb7a4 100644 --- a/containers/snpeff/environment.yml +++ b/containers/snpeff/environment.yml @@ -1,6 +1,6 @@ # You can use this file to create a conda environment for this pipeline: # conda env create -f environment.yml -name: sarek-snpeff-2.5 +name: sarek-snpeff-2.5.1 channels: - conda-forge - bioconda diff --git a/containers/vep/Dockerfile b/containers/vep/Dockerfile index cfe2d8eeb5..e140f8e77b 100644 --- a/containers/vep/Dockerfile +++ b/containers/vep/Dockerfile @@ -7,7 +7,7 @@ LABEL \ COPY environment.yml / RUN conda env create -f /environment.yml && conda clean -a -ENV PATH /opt/conda/envs/sarek-vep-2.5/bin:$PATH +ENV PATH /opt/conda/envs/sarek-vep-2.5.1/bin:$PATH # Setup default ARG variables ARG GENOME=GRCh38 diff --git a/containers/vep/environment.yml b/containers/vep/environment.yml index b5c73474a6..b1d32f1d02 100644 --- a/containers/vep/environment.yml +++ b/containers/vep/environment.yml @@ -1,6 +1,6 @@ # You can use this file to create a conda environment for this pipeline: # conda env create -f environment.yml -name: sarek-vep-2.5 +name: sarek-vep-2.5.1 channels: - conda-forge - bioconda From c650e080f69d0f77f820243233690cf2bbb8bcae Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 21 Oct 2019 16:32:39 +0200 Subject: [PATCH 138/854] update script name --- docs/annotation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/annotation.md b/docs/annotation.md index 8e426e2140..b7babedc7c 100644 --- a/docs/annotation.md +++ b/docs/annotation.md @@ -63,7 +63,7 @@ An helper script has been designed to help downloading CADD files. Such files are meant to be share between multiple users, so this script is mainly meant for people administrating servers, clusters and advanced users. ```bash -nextflow run build.nf --cadd_cache /Path/To/CADDcache --cadd_version --genome +nextflow run downloadcache.nf --cadd_cache /Path/To/CADDcache --cadd_version --genome ``` ## Using VEP GeneSplicer plugin From 424a4f534040caed2bad6c0d70eb09426f7b51bf Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 21 Oct 2019 16:33:42 +0200 Subject: [PATCH 139/854] update docs --- docs/reference.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index 1d5d10c729..9e69e2dcdd 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -36,11 +36,3 @@ First, when there are multiple consecutive intervals in the file that take littl Second, the jobs with largest processing time are started first, which reduces wall-clock time. If no runtime is given, a time of 1000 nucleotides per second is assumed. Actual figures vary from 2 nucleotides/second to 30000 nucleotides/second. - -## build.nf - -The [`build.nf`](#buildnf) script is used to build reference needed for smallGRCh37. - -```bash -nextflow run build.nf -``` From 8ba3e47d9c6f1044b8eb42de13240c073ff6941a Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 21 Oct 2019 16:53:46 +0200 Subject: [PATCH 140/854] update CHANGELOG --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 080ba18d72..e35bf7ad3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [2.5.1] - Årjep-Ålkatjjekna + +Årjep-Ålkatjjekna is one of the two glaciers of the Ålkatj Massif. + +### `Fixed` + +- [#48](https://github.com/nf-core/sarek/issues/48) - Fix `singularity.autoMounts` issue. +- [#49](https://github.com/nf-core/sarek/issues/49) - Use correct tag for annotation containers. +- [#50](https://github.com/nf-core/sarek/issues/50) - Fix paths for scripts. + ## [2.5] - Ålkatj Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) template. From 84f039c9658e3cc70be23b71a16a702be02b674e Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 21 Oct 2019 17:18:40 +0200 Subject: [PATCH 141/854] always download nfcore/sarek --- scripts/download_image.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/scripts/download_image.sh b/scripts/download_image.sh index 00892c09b3..730e8fe945 100755 --- a/scripts/download_image.sh +++ b/scripts/download_image.sh @@ -80,7 +80,4 @@ then get_image sarekvep ${VERSION}.${SOURCEGENOME} ${TARGETVERSION}.${GENOME} fi -if ! [[ ANNOTATEBOTH,ANNOTATESNPEFF,ANNOTATEVEP,LINT,SNPEFF,VEP =~ $TEST ]] -then - get_image sarek ${VERSION} ${TARGETVERSION} -fi +get_image sarek ${VERSION} ${TARGETVERSION} From b238dd6ed1f1b4ed47578c0c847fdba6bee8c615 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Tue, 22 Oct 2019 10:57:19 +0200 Subject: [PATCH 142/854] Try to fix branch protection --- .github/workflows/branch.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 054d2d78f2..8cbf3d1546 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -13,4 +13,4 @@ jobs: - uses: actions/checkout@v1 - name: Check PRs run: | - [[ $(git remote get-url origin) == *nf-core/sarek ]] && [[ ${GITHUB_BASE_REF} = "master" ]] && { [[ ${GITHUB_HEAD_REF} = "dev" ]] || [[ ${GITHUB_BASE_REF} = "patch" ]]; } \ No newline at end of file + [[ $(git remote get-url origin) == *nf-core/sarek ]] && [[ ${GITHUB_BASE_REF} = "master" ]] && [[ ${GITHUB_HEAD_REF} = "dev" ]] || [[ ${GITHUB_BASE_REF} = "patch" ]] From 83e5348934b9949c473a22ec7c9c9432ab075ec6 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Tue, 22 Oct 2019 10:59:47 +0200 Subject: [PATCH 143/854] Group checks --- .github/workflows/branch.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 8cbf3d1546..75836dd0a0 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -13,4 +13,4 @@ jobs: - uses: actions/checkout@v1 - name: Check PRs run: | - [[ $(git remote get-url origin) == *nf-core/sarek ]] && [[ ${GITHUB_BASE_REF} = "master" ]] && [[ ${GITHUB_HEAD_REF} = "dev" ]] || [[ ${GITHUB_BASE_REF} = "patch" ]] + { [[ $(git remote get-url origin) == *nf-core/sarek ]] && [[ ${GITHUB_BASE_REF} = "master" ]] && [[ ${GITHUB_HEAD_REF} = "dev" ]] ; } || [[ ${GITHUB_BASE_REF} = "patch" ]] From 114e2c0a0b58ac12162008a0e1ff6b258a23ce54 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Tue, 22 Oct 2019 11:12:36 +0200 Subject: [PATCH 144/854] rewrote test --- .github/workflows/branch.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 75836dd0a0..3247c86312 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -13,4 +13,4 @@ jobs: - uses: actions/checkout@v1 - name: Check PRs run: | - { [[ $(git remote get-url origin) == *nf-core/sarek ]] && [[ ${GITHUB_BASE_REF} = "master" ]] && [[ ${GITHUB_HEAD_REF} = "dev" ]] ; } || [[ ${GITHUB_BASE_REF} = "patch" ]] + [[ ${GITHUB_HEAD_REF} = "patch" ]] || [[ $(git remote get-url origin) == *nf-core/sarek ]] && [[ ${GITHUB_BASE_REF} = "master" ]] && [[ ${GITHUB_HEAD_REF} = "dev" ]] From b76f217ad2f504433252270420cd896ecdbdbedf Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Tue, 22 Oct 2019 11:23:39 +0200 Subject: [PATCH 145/854] This time it'll work --- .github/workflows/branch.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 3247c86312..5a51271ef7 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -13,4 +13,4 @@ jobs: - uses: actions/checkout@v1 - name: Check PRs run: | - [[ ${GITHUB_HEAD_REF} = "patch" ]] || [[ $(git remote get-url origin) == *nf-core/sarek ]] && [[ ${GITHUB_BASE_REF} = "master" ]] && [[ ${GITHUB_HEAD_REF} = "dev" ]] + [[ ${GITHUB_HEAD_REF} = "patch" ]] || { [[ $(git remote get-url origin) == *nf-core/sarek ]] && [[ ${GITHUB_BASE_REF} = "master" ]] && [[ ${GITHUB_HEAD_REF} = "dev" ]] }``` From 67bc3410974e1f18b20ca04d5aa03112c3e20aed Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Tue, 22 Oct 2019 11:25:30 +0200 Subject: [PATCH 146/854] Typo --- .github/workflows/branch.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 5a51271ef7..431dae2e52 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -13,4 +13,4 @@ jobs: - uses: actions/checkout@v1 - name: Check PRs run: | - [[ ${GITHUB_HEAD_REF} = "patch" ]] || { [[ $(git remote get-url origin) == *nf-core/sarek ]] && [[ ${GITHUB_BASE_REF} = "master" ]] && [[ ${GITHUB_HEAD_REF} = "dev" ]] }``` + [[ ${GITHUB_HEAD_REF} = "patch" ]] || { [[ $(git remote get-url origin) == *nf-core/sarek ]] && [[ ${GITHUB_BASE_REF} = "master" ]] && [[ ${GITHUB_HEAD_REF} = "dev" ]] } From 9019dc3bb14e7cb4d54738603eaa872c489b322d Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Tue, 22 Oct 2019 11:31:35 +0200 Subject: [PATCH 147/854] Update .github/workflows/branch.yml --- .github/workflows/branch.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 431dae2e52..5d12758d1c 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -13,4 +13,4 @@ jobs: - uses: actions/checkout@v1 - name: Check PRs run: | - [[ ${GITHUB_HEAD_REF} = "patch" ]] || { [[ $(git remote get-url origin) == *nf-core/sarek ]] && [[ ${GITHUB_BASE_REF} = "master" ]] && [[ ${GITHUB_HEAD_REF} = "dev" ]] } + [[ ${GITHUB_HEAD_REF} = "patch" ]] || { [[ $(git remote get-url origin) == *nf-core/sarek ]] && [[ ${GITHUB_BASE_REF} = "master" ]] && [[ ${GITHUB_HEAD_REF} = "dev" ]]; } From 6e7262faee3db3b937c5881fc1518dbdedaea037 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Tue, 22 Oct 2019 11:38:27 +0200 Subject: [PATCH 148/854] Update .github/workflows/branch.yml --- .github/workflows/branch.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 5d12758d1c..741af20632 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -13,4 +13,4 @@ jobs: - uses: actions/checkout@v1 - name: Check PRs run: | - [[ ${GITHUB_HEAD_REF} = "patch" ]] || { [[ $(git remote get-url origin) == *nf-core/sarek ]] && [[ ${GITHUB_BASE_REF} = "master" ]] && [[ ${GITHUB_HEAD_REF} = "dev" ]]; } + { [[ $(git remote get-url origin) == *nf-core/sarek ]] && [[ ${GITHUB_BASE_REF} = "master" ]] && [[ ${GITHUB_HEAD_REF} = "dev" ]]; } || [[ ${GITHUB_HEAD_REF} == patch* ]] From 9893a3b6a945fa7b2c73405a83792a7dafb2ec7d Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 22 Oct 2019 12:17:09 +0200 Subject: [PATCH 149/854] fix travis branch protection --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e08837e8fc..fdc9ffb066 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ matrix: before_install: # PRs to master are only ok if coming from dev branch - - '[ $TRAVIS_PULL_REQUEST = "false" ] || [ $TRAVIS_BRANCH != "master" ] || ([ $TRAVIS_PULL_REQUEST_SLUG = $TRAVIS_REPO_SLUG ] && ([ $TRAVIS_PULL_REQUEST_BRANCH = "dev" ] || [ $TRAVIS_PULL_REQUEST_BRANCH = "patch" ]))' + - '[ $TRAVIS_PULL_REQUEST = "false" ] || [ $TRAVIS_BRANCH != "master" ] || ([ $TRAVIS_PULL_REQUEST_SLUG = $TRAVIS_REPO_SLUG ] && [ $TRAVIS_PULL_REQUEST_BRANCH = "dev" ]) || [ $TRAVIS_PULL_REQUEST_BRANCH = "patch" ]' # Pull the docker image first so the test doesn't wait for this - docker pull nfcore/sarek:dev # Fake the tag locally so that the pipeline runs properly From d1a2e13ac7461e73defa53729772e91663693e5a Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 22 Oct 2019 15:48:02 +0200 Subject: [PATCH 150/854] apply changes from 2.5.1 to dev --- .github/workflows/branch.yml | 2 +- .travis.yml | 2 +- CHANGELOG.md | 10 ++++++++++ Dockerfile | 2 +- Jenkinsfile | 2 +- containers/snpeff/Dockerfile | 2 +- containers/snpeff/environment.yml | 2 +- containers/vep/Dockerfile | 2 +- containers/vep/environment.yml | 2 +- docs/annotation.md | 4 ++-- docs/install_bianca.md | 4 ++-- environment.yml | 2 +- main.nf | 16 ++++++++-------- nextflow.config | 2 +- scripts/download_image.sh | 5 +---- 15 files changed, 33 insertions(+), 26 deletions(-) diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 58a41ff689..174e995a05 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -13,4 +13,4 @@ jobs: - uses: actions/checkout@v1 - name: Check PRs run: | - [[ $(git remote get-url origin) == *nf-core/sarek ]] && [ ${GITHUB_BASE_REF} = "master" ] && [ ${GITHUB_HEAD_REF} = "dev" ] + { [[ $(git remote get-url origin) == *nf-core/sarek ]] && [[ ${GITHUB_BASE_REF} = "master" ]] && [[ ${GITHUB_HEAD_REF} = "dev" ]]; } || [[ ${GITHUB_HEAD_REF} == patch* ]] \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 450539446e..b270cdf879 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ matrix: before_install: # PRs to master are only ok if coming from dev branch - - '[ $TRAVIS_PULL_REQUEST = "false" ] || [ $TRAVIS_BRANCH != "master" ] || ([ $TRAVIS_PULL_REQUEST_SLUG = $TRAVIS_REPO_SLUG ] && ([ $TRAVIS_PULL_REQUEST_BRANCH = "dev" ] || [ $TRAVIS_PULL_REQUEST_BRANCH = "patch" ]))' + - '[ $TRAVIS_PULL_REQUEST = "false" ] || [ $TRAVIS_BRANCH != "master" ] || ([ $TRAVIS_PULL_REQUEST_SLUG = $TRAVIS_REPO_SLUG ] && [ $TRAVIS_PULL_REQUEST_BRANCH = "dev" ]) || [ $TRAVIS_PULL_REQUEST_BRANCH = "patch" ]' # Pull the docker image first so the test doesn't wait for this - docker pull nfcore/sarek:dev # Fake the tag locally so that the pipeline runs properly diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f1d71a6ea..61afc594d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [#42](https://github.com/nf-core/sarek/pull/42) - Fix typos, and minor updates in `README.md` - [#43](https://github.com/nf-core/sarek/pull/43) - Fix automated `VEP` builds with circleCI +## [2.5.1] - Årjep-Ålkatjjekna + +Årjep-Ålkatjjekna is one of the two glaciers of the Ålkatj Massif. + +### `Fixed` + +- [#48](https://github.com/nf-core/sarek/issues/48) - Fix `singularity.autoMounts` issue. +- [#49](https://github.com/nf-core/sarek/issues/49) - Use correct tag for annotation containers. +- [#50](https://github.com/nf-core/sarek/issues/50) - Fix paths for scripts. + ## [2.5] - Ålkatj Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) template. diff --git a/Dockerfile b/Dockerfile index 8b2563a995..2179ebbdda 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,4 +4,4 @@ LABEL authors="Maxime Garcia, Szilveszter Juhos" \ COPY environment.yml / RUN conda env create -f /environment.yml && conda clean -a -ENV PATH /opt/conda/envs/nf-core-sarek-2.5.1dev/bin:$PATH +ENV PATH /opt/conda/envs/nf-core-sarek-2.5.2dev/bin:$PATH diff --git a/Jenkinsfile b/Jenkinsfile index 924e454f0d..00c743cde2 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -8,7 +8,7 @@ pipeline { stages { stage('Docker setup') { steps { - sh "./scripts/download_image.sh -n docker -t ALL --source-version dev --target-version 2.5 -g smallGRCh37" + sh "./scripts/download_image.sh -n docker -t ALL --source-version dev --target-version dev -g smallGRCh37" } } stage('Germline') { diff --git a/containers/snpeff/Dockerfile b/containers/snpeff/Dockerfile index 5c52720260..cbd68c52d8 100644 --- a/containers/snpeff/Dockerfile +++ b/containers/snpeff/Dockerfile @@ -7,7 +7,7 @@ LABEL \ COPY environment.yml / RUN conda env create -f /environment.yml && conda clean -a -ENV PATH /opt/conda/envs/sarek-snpeff-2.5.1dev/bin:$PATH +ENV PATH /opt/conda/envs/sarek-snpeff-2.5.2dev/bin:$PATH # Setup default ARG variables ARG GENOME=GRCh38 diff --git a/containers/snpeff/environment.yml b/containers/snpeff/environment.yml index 2dfdc6f3ff..5e73063ece 100644 --- a/containers/snpeff/environment.yml +++ b/containers/snpeff/environment.yml @@ -1,6 +1,6 @@ # You can use this file to create a conda environment for this pipeline: # conda env create -f environment.yml -name: sarek-snpeff-2.5.1dev +name: sarek-snpeff-2.5.2dev channels: - conda-forge - bioconda diff --git a/containers/vep/Dockerfile b/containers/vep/Dockerfile index ee617f9f98..562b770bef 100644 --- a/containers/vep/Dockerfile +++ b/containers/vep/Dockerfile @@ -7,7 +7,7 @@ LABEL \ COPY environment.yml / RUN conda env create -f /environment.yml && conda clean -a -ENV PATH /opt/conda/envs/sarek-vep-2.5.1dev/bin:$PATH +ENV PATH /opt/conda/envs/sarek-vep-2.5.2dev/bin:$PATH # Setup default ARG variables ARG GENOME=GRCh38 diff --git a/containers/vep/environment.yml b/containers/vep/environment.yml index 831df73abd..993a963ab0 100644 --- a/containers/vep/environment.yml +++ b/containers/vep/environment.yml @@ -1,6 +1,6 @@ # You can use this file to create a conda environment for this pipeline: # conda env create -f environment.yml -name: sarek-vep-2.5.1dev +name: sarek-vep-2.5.2dev channels: - conda-forge - bioconda diff --git a/docs/annotation.md b/docs/annotation.md index 8e426e2140..bec92ff7d6 100644 --- a/docs/annotation.md +++ b/docs/annotation.md @@ -63,7 +63,7 @@ An helper script has been designed to help downloading CADD files. Such files are meant to be share between multiple users, so this script is mainly meant for people administrating servers, clusters and advanced users. ```bash -nextflow run build.nf --cadd_cache /Path/To/CADDcache --cadd_version --genome +nextflow run downloadcache.nf --cadd_cache /Path/To/CADDcache --cadd_version --genome ``` ## Using VEP GeneSplicer plugin @@ -75,5 +75,5 @@ To enable the use of the VEP GeneSplicer plugin: Example: ```bash -nextflow run annotate.nf --tools VEP --sample file.vcf.gz --genesplicer +nextflow run nf-core/sarek/main.nf --step annotate --tools VEP --sample file.vcf.gz --genesplicer ``` diff --git a/docs/install_bianca.md b/docs/install_bianca.md index 5bb8c176c8..6cc0b51960 100644 --- a/docs/install_bianca.md +++ b/docs/install_bianca.md @@ -92,10 +92,10 @@ You can either download nf-core/sarek on your computer or on `rackham`, make an > pip install git-archive-all # If you used --user before, you might want to do that here too > pip install git-archive-all --user -> ./scripts/makeSnapshot.sh --include-test-data --include-configs +> ./scripts/make_snapshot.sh --include-test-data --include-configs # Or you can just include nf-core/sarek: -> ./scripts/makeSnapshot.sh +> ./scripts/make_snapshot.sh # You will get this message in your terminal Wrote sarek-[snapID].tar.gz diff --git a/environment.yml b/environment.yml index 797ba0c1ae..f1858415aa 100644 --- a/environment.yml +++ b/environment.yml @@ -1,6 +1,6 @@ # You can use this file to create a conda environment for this pipeline: # conda env create -f environment.yml -name: nf-core-sarek-2.5.1dev +name: nf-core-sarek-2.5.2dev channels: - conda-forge - bioconda diff --git a/main.nf b/main.nf index ffe3b12b7d..204f315b4d 100644 --- a/main.nf +++ b/main.nf @@ -1983,12 +1983,12 @@ process ControlFreecViz { when: 'controlfreec' in tools """ - cat /opt/conda/envs/sarek-${workflow.manifest.version}/bin/assess_significance.R | R --slave --args ${cnvTumor} ${ratioTumor} - cat /opt/conda/envs/sarek-${workflow.manifest.version}/bin/assess_significance.R | R --slave --args ${cnvNormal} ${ratioNormal} - cat /opt/conda/envs/sarek-${workflow.manifest.version}/bin/makeGraph.R | R --slave --args 2 ${ratioTumor} ${bafTumor} - cat /opt/conda/envs/sarek-${workflow.manifest.version}/bin/makeGraph.R | R --slave --args 2 ${ratioNormal} ${bafNormal} - perl /opt/conda/envs/sarek-${workflow.manifest.version}/bin/freec2bed.pl -f ${ratioTumor} > ${idSampleTumor}.bed - perl /opt/conda/envs/sarek-${workflow.manifest.version}/bin/freec2bed.pl -f ${ratioNormal} > ${idSampleNormal}.bed + cat /opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/bin/assess_significance.R | R --slave --args ${cnvTumor} ${ratioTumor} + cat /opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/bin/assess_significance.R | R --slave --args ${cnvNormal} ${ratioNormal} + cat /opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/bin/makeGraph.R | R --slave --args 2 ${ratioTumor} ${bafTumor} + cat /opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/bin/makeGraph.R | R --slave --args 2 ${ratioNormal} ${bafNormal} + perl /opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/bin/freec2bed.pl -f ${ratioTumor} > ${idSampleTumor}.bed + perl /opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/bin/freec2bed.pl -f ${ratioNormal} > ${idSampleNormal}.bed """ } @@ -2249,7 +2249,7 @@ process VEP { genome = params.genome == 'smallGRCh37' ? 'GRCh37' : params.genome dir_cache = (params.vep_cache && params.annotation_cache) ? " \${PWD}/${dataDir}" : "/.vep" cadd = (params.cadd_cache && params.cadd_WG_SNVs && params.cadd_InDels) ? "--plugin CADD,whole_genome_SNVs.tsv.gz,InDels.tsv.gz" : "" - genesplicer = params.genesplicer ? "--plugin GeneSplicer,/opt/conda/envs/sarek-${workflow.manifest.version}/bin/genesplicer,/opt/conda/envs/sarek-${workflow.manifest.version}/share/genesplicer-1.0-1/human,context=200,tmpdir=\$PWD/${reducedVCF}" : "--offline" + genesplicer = params.genesplicer ? "--plugin GeneSplicer,/opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/bin/genesplicer,/opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/share/genesplicer-1.0-1/human,context=200,tmpdir=\$PWD/${reducedVCF}" : "--offline" """ mkdir ${reducedVCF} @@ -2310,7 +2310,7 @@ process VEPmerge { genome = params.genome == 'smallGRCh37' ? 'GRCh37' : params.genome dir_cache = (params.vep_cache && params.annotation_cache) ? " \${PWD}/${dataDir}" : "/.vep" cadd = (params.cadd_cache && params.cadd_WG_SNVs && params.cadd_InDels) ? "--plugin CADD,whole_genome_SNVs.tsv.gz,InDels.tsv.gz" : "" - genesplicer = params.genesplicer ? "--plugin GeneSplicer,/opt/conda/envs/sarek-${workflow.manifest.version}/bin/genesplicer,/opt/conda/envs/sarek-${workflow.manifest.version}/share/genesplicer-1.0-1/human,context=200,tmpdir=\$PWD/${reducedVCF}" : "--offline" + genesplicer = params.genesplicer ? "--plugin GeneSplicer,/opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/bin/genesplicer,/opt/conda/envs/nf-core-sarek-${workflow.manifest.version}/share/genesplicer-1.0-1/human,context=200,tmpdir=\$PWD/${reducedVCF}" : "--offline" """ mkdir ${reducedVCF} diff --git a/nextflow.config b/nextflow.config index 6ddfb53847..0f9dfeb01a 100644 --- a/nextflow.config +++ b/nextflow.config @@ -115,8 +115,8 @@ profiles { singularity.enabled = false } singularity { - autoMounts = true docker.enabled = false + singularity.autoMounts = true singularity.enabled = true } test { includeConfig 'conf/test.config' } diff --git a/scripts/download_image.sh b/scripts/download_image.sh index 00892c09b3..b4ce89205b 100755 --- a/scripts/download_image.sh +++ b/scripts/download_image.sh @@ -80,7 +80,4 @@ then get_image sarekvep ${VERSION}.${SOURCEGENOME} ${TARGETVERSION}.${GENOME} fi -if ! [[ ANNOTATEBOTH,ANNOTATESNPEFF,ANNOTATEVEP,LINT,SNPEFF,VEP =~ $TEST ]] -then - get_image sarek ${VERSION} ${TARGETVERSION} -fi +get_image sarek ${VERSION} ${TARGETVERSION} \ No newline at end of file From a0179d42e38653cde80ee0db9486bc4477840892 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 22 Oct 2019 15:52:32 +0200 Subject: [PATCH 151/854] bump version to 2.5.2dev --- .travis.yml | 2 +- nextflow.config | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b270cdf879..450539446e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ matrix: before_install: # PRs to master are only ok if coming from dev branch - - '[ $TRAVIS_PULL_REQUEST = "false" ] || [ $TRAVIS_BRANCH != "master" ] || ([ $TRAVIS_PULL_REQUEST_SLUG = $TRAVIS_REPO_SLUG ] && [ $TRAVIS_PULL_REQUEST_BRANCH = "dev" ]) || [ $TRAVIS_PULL_REQUEST_BRANCH = "patch" ]' + - '[ $TRAVIS_PULL_REQUEST = "false" ] || [ $TRAVIS_BRANCH != "master" ] || ([ $TRAVIS_PULL_REQUEST_SLUG = $TRAVIS_REPO_SLUG ] && ([ $TRAVIS_PULL_REQUEST_BRANCH = "dev" ] || [ $TRAVIS_PULL_REQUEST_BRANCH = "patch" ]))' # Pull the docker image first so the test doesn't wait for this - docker pull nfcore/sarek:dev # Fake the tag locally so that the pipeline runs properly diff --git a/nextflow.config b/nextflow.config index 0f9dfeb01a..4632a988a6 100644 --- a/nextflow.config +++ b/nextflow.config @@ -156,7 +156,7 @@ manifest { description = 'An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing' mainScript = 'main.nf' nextflowVersion = '>=19.04.0' - version = '2.5.1dev' + version = '2.5.2dev' } // Return the minimum between requirements and a maximum limit to ensure that resource requirements don't go over From 7a6650e3596cc282a4eca44dee2812991d74ece5 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 22 Oct 2019 15:57:02 +0200 Subject: [PATCH 152/854] update CHANGELOG --- CHANGELOG.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61afc594d8..c42715a89b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [#41](https://github.com/nf-core/sarek/pull/41) - Update `qualimap` from `2.2.2b` to `2.2.2c` - [#41](https://github.com/nf-core/sarek/pull/41) - Update `tiddit` from `2.7.1` to `2.8.0` - [#41](https://github.com/nf-core/sarek/pull/41) - Update `vcfanno` from `0.3.1` to `0.3.2` -- [#46](https://github.com/nf-core/sarek/pull/46) - Add location to abstacts. +- [#46](https://github.com/nf-core/sarek/pull/46) - Add location to abstacts + +### `Changed` + +- [#54](https://github.com/nf-core/sarek/pull/54) - Bump version to `2.5.2dev` ### `Removed` @@ -29,11 +33,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [#40](https://github.com/nf-core/sarek/pull/40) - Fix issue with `publishDirMode` within `test` profile - [#42](https://github.com/nf-core/sarek/pull/42) - Fix typos, and minor updates in `README.md` - [#43](https://github.com/nf-core/sarek/pull/43) - Fix automated `VEP` builds with circleCI +- [#54](https://github.com/nf-core/sarek/pull/54) - Apply fixes from release `2.5.1` ## [2.5.1] - Årjep-Ålkatjjekna Årjep-Ålkatjjekna is one of the two glaciers of the Ålkatj Massif. +### `Added` + +- [#53](https://github.com/nf-core/sarek/pull/53) - Release `2.5.1` + ### `Fixed` - [#48](https://github.com/nf-core/sarek/issues/48) - Fix `singularity.autoMounts` issue. From a7cb0f11712efa5541d8fee1de4d6f82034c532b Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 28 Oct 2019 13:12:43 +0100 Subject: [PATCH 153/854] update tiddit to 2.8.1 --- CHANGELOG.md | 10 +++++----- docs/containers.md | 2 +- environment.yml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c42715a89b..6a8e7c2d25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,18 +9,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### `Added` +- [#46](https://github.com/nf-core/sarek/pull/46) - Add location to abstacts + +### `Changed` + - [#41](https://github.com/nf-core/sarek/pull/41) - Update `control-freec` from `11.4` to `11.5` - [#41](https://github.com/nf-core/sarek/pull/41) - Update `ensembl-vep` from `95.2` to `98.2` - [#41](https://github.com/nf-core/sarek/pull/41) - Update `freebayes` from `1.2.0` to `1.3.1` - [#41](https://github.com/nf-core/sarek/pull/41) - Update `gatk4` from `4.1.2.0` to `4.1.4.0` - [#41](https://github.com/nf-core/sarek/pull/41) - Update `manta` from `1.5.0` to `1.6.0` - [#41](https://github.com/nf-core/sarek/pull/41) - Update `qualimap` from `2.2.2b` to `2.2.2c` -- [#41](https://github.com/nf-core/sarek/pull/41) - Update `tiddit` from `2.7.1` to `2.8.0` +- [#41](https://github.com/nf-core/sarek/pull/41), [#55](https://github.com/nf-core/sarek/pull/55) - Update `tiddit` from `2.7.1` to `2.8.1` - [#41](https://github.com/nf-core/sarek/pull/41) - Update `vcfanno` from `0.3.1` to `0.3.2` -- [#46](https://github.com/nf-core/sarek/pull/46) - Add location to abstacts - -### `Changed` - - [#54](https://github.com/nf-core/sarek/pull/54) - Bump version to `2.5.2dev` ### `Removed` diff --git a/docs/containers.md b/docs/containers.md index b86347db11..b75d74db9a 100644 --- a/docs/containers.md +++ b/docs/containers.md @@ -30,7 +30,7 @@ For annotation, the main container can be used, but the cache has to be download - Contain **[samtools](https://github.com/samtools/samtools)** 1.9 - Contain **[snpEff](http://snpeff.sourceforge.net/)** 4.3.1t - Contain **[Strelka2](https://github.com/Illumina/strelka)** 2.9.10 -- Contain **[TIDDIT](https://github.com/SciLifeLab/TIDDIT)** 2.8.0 +- Contain **[TIDDIT](https://github.com/SciLifeLab/TIDDIT)** 2.8.1 - Contain **[VCFanno](https://github.com/brentp/vcfanno)** 0.3.2 - Contain **[VCFtools](https://vcftools.github.io/index.html)** 0.1.16 - Contain **[VEP](https://github.com/Ensembl/ensembl-vep)** 98.2 diff --git a/environment.yml b/environment.yml index f1858415aa..56e57e8f0a 100644 --- a/environment.yml +++ b/environment.yml @@ -23,6 +23,6 @@ dependencies: - samtools=1.9 - snpeff=4.3.1t - strelka=2.9.10 - - tiddit=2.8.0 + - tiddit=2.8.1 - vcfanno=0.3.2 - vcftools=0.1.16 \ No newline at end of file From 0d1e56ca83091f46fa09c30eac4e8bee8b2e9662 Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Mon, 28 Oct 2019 16:28:00 +0100 Subject: [PATCH 154/854] Use Version 98 of Mouse --- conf/igenomes.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/igenomes.config b/conf/igenomes.config index a04e2e5397..c4e67148c2 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -62,7 +62,7 @@ params { knownIndels = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz" knownIndelsIndex = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz.tbi" snpeffDb = "GRCh38.86" - vepCacheVersion = "95" + vepCacheVersion = "98" } } } From 9195f0f0060f4a8bacb2e791e8ce73d17494f817 Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Mon, 28 Oct 2019 16:31:49 +0100 Subject: [PATCH 155/854] Add for grcm38 --- conf/igenomes.config | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/conf/igenomes.config b/conf/igenomes.config index c4e67148c2..a1ecc4cc22 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -56,9 +56,7 @@ params { dict = "${params.igenomes_base}/Mus_musculus/Sequence/WholeGenomeFasta/genome.dict" fasta = "${params.igenomes_base}/Mus_musculus/Sequence/WholeGenomeFasta/genome.fa" fastaFai = "${params.igenomes_base}/Mus_musculus/Sequence/WholeGenomeFasta/genome.fai" - germlineResource = "${params.igenomes_base}/Mus_musculus/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh38.PASS.AC.AF.only.vcf.gz" - germlineResourceIndex = "${params.igenomes_base}/Mus_musculus/Annotation/GermlineResource/gnomAD.r2.1.1.GRCh38.PASS.AC.AF.only.vcf.gz.tbi" - intervals = "${params.igenomes_base}/Mus_musculus/Annotation/intervals/wgs_calling_regions.hg38.bed" + intervals = "${params.igenomes_base}/Mus_musculus/Annotation/intervals/wgs_calling_regions.grcm38.bed" knownIndels = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz" knownIndelsIndex = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz.tbi" snpeffDb = "GRCh38.86" From 228592dc11901abc653090ba3c7fae5a7126ff30 Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Mon, 28 Oct 2019 16:34:09 +0100 Subject: [PATCH 156/854] Adjust mus musculus DB --- conf/igenomes.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/igenomes.config b/conf/igenomes.config index a1ecc4cc22..c27ea0fcff 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -59,7 +59,7 @@ params { intervals = "${params.igenomes_base}/Mus_musculus/Annotation/intervals/wgs_calling_regions.grcm38.bed" knownIndels = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz" knownIndelsIndex = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz.tbi" - snpeffDb = "GRCh38.86" + snpeffDb = "GRCm38.86" vepCacheVersion = "98" } } From e216b2489b8b301f8ac11b74423486b5dc2e6e58 Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Mon, 28 Oct 2019 16:38:11 +0100 Subject: [PATCH 157/854] Annotation --- conf/igenomes.config | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/conf/igenomes.config b/conf/igenomes.config index c27ea0fcff..5413cec2a2 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -48,15 +48,15 @@ params { vepCacheVersion = "95" } 'GRCm38' { - bwaIndex = "${params.igenomes_base}/Mus_musculus/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" - chrDir = "${params.igenomes_base}/Mus_musculus/Sequence/Chromosomes" - chrLength = "${params.igenomes_base}/Mus_musculus/Sequence/Length/Homo_sapiens_assembly38.len" - dbsnp = "${params.igenomes_base}/Mus_musculus/Annotation/mgp.v6.merged.norm.snp.indels.sfiltered.vcf.gz" - dbsnpIndex = "${params.igenomes_base}/Mus_musculus/Annotation/mgp.v6.merged.norm.snp.indels.sfiltered.vcf.gz.tbi" - dict = "${params.igenomes_base}/Mus_musculus/Sequence/WholeGenomeFasta/genome.dict" - fasta = "${params.igenomes_base}/Mus_musculus/Sequence/WholeGenomeFasta/genome.fa" - fastaFai = "${params.igenomes_base}/Mus_musculus/Sequence/WholeGenomeFasta/genome.fai" - intervals = "${params.igenomes_base}/Mus_musculus/Annotation/intervals/wgs_calling_regions.grcm38.bed" + bwaIndex = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + chrDir = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/Chromosomes" + chrLength = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/Length/Homo_sapiens_assembly38.len" + dbsnp = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/mgp.v6.merged.norm.snp.indels.sfiltered.vcf.gz" + dbsnpIndex = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/mgp.v6.merged.norm.snp.indels.sfiltered.vcf.gz.tbi" + dict = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.dict" + fasta = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa" + fastaFai = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fai" + intervals = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/intervals/wgs_calling_regions.grcm38.bed" knownIndels = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz" knownIndelsIndex = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz.tbi" snpeffDb = "GRCm38.86" From 5c13e435afa938a6c2223a4b095761818f51b33b Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 28 Oct 2019 17:08:08 +0100 Subject: [PATCH 158/854] add smallerGRCh37 and minimalGRCh37 --- conf/genomes.config | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/conf/genomes.config b/conf/genomes.config index d9ffcef42c..2b01bf7bd9 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -58,9 +58,12 @@ params { snpeffDb = "GRCh37.75" vepCacheVersion = "95" } - 'minimalGRCh37' { + 'smallerGRCh37' { fasta = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" knownIndels = "${params.genomes_base}/dbsnp_138.b37.small.vcf.gz" } + 'minimalGRCh37' { + fasta = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" + } } } From 05d174db38a06b03875048b942f1adaeeb112ea5 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 28 Oct 2019 17:08:58 +0100 Subject: [PATCH 159/854] use bwa aln when no knowIndels, otherwise use bwa mem, noIntervals currently in the process of being added everywhere --- main.nf | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 93 insertions(+), 11 deletions(-) diff --git a/main.nf b/main.nf index 140c851af9..eee29e19f1 100644 --- a/main.nf +++ b/main.nf @@ -575,8 +575,8 @@ bedIntervals = bedIntervals.dump(tag:'bedintervals') // PREPARING CHANNELS FOR PREPROCESSING AND QC -if (step == 'mapping') (inputReads, inputReadsFastQC) = inputSample.into(2) -else (inputReads, inputReadsFastQC) = Channel.empty().into(2) +if (step == 'mapping') (inputReads, inputReadsBWAaln, inputReadsFastQC) = inputSample.into(3) +else (inputReads, inputReadsBWAaln, inputReadsFastQC) = Channel.empty().into(3) inputPairReadsFastQC = Channel.create() inputBAMFastQC = Channel.create() @@ -658,7 +658,7 @@ process MapReads { set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam") into bamMapped set idPatient, idSample, file("${idSample}_${idRun}.bam") into bamMappedBamQC - when: step == 'mapping' + when: step == 'mapping' && params.knownIndels script: // -K is an hidden option, used to fix the number of reads processed by bwa mem @@ -683,10 +683,42 @@ process MapReads { bamMapped = bamMapped.dump(tag:'Mapped BAM') +process MapReadsBWAaln { + label 'cpus_max' + + tag {idPatient + "-" + idRun} + + input: + set idPatient, idSample, idRun, file(inputFile1), file(inputFile2) from inputReadsBWAaln + file(bwaIndex) from ch_bwaIndex + file(fasta) from ch_fasta + + output: + set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam") into bamMappedbwaaln + set idPatient, idSample, file("${idSample}_${idRun}.bam") into bamMappedBamQCbwaaln + + when: step == 'mapping' && !params.knownIndels + + script: + """ + bwa aln ${fasta} ${inputFile1} > ${idSample}_${idRun}_R1.sai + bwa aln ${fasta} ${inputFile2} > ${idSample}_${idRun}_R2.sai + + bwa sampe ${fasta} ${idSample}_${idRun}_R1.sai ${idSample}_${idRun}_R2.sai ${inputFile1} ${inputFile2} > ${idSample}_${idRun}.sam + + samtools view -S -b ${idSample}_${idRun}.sam > ${idSample}_${idRun}.unsorted.sam + + samtools sort ${idSample}_${idRun}.unsorted.sam -o ${idSample}_${idRun}.bam + """ +} + +bamMappedbwaaln = bamMappedbwaaln.dump(tag:'Mapped BAM bwa aln') + // Sort BAM whether they are standalone or should be merged singleBam = Channel.create() multipleBam = Channel.create() +bamMapped = bamMapped.mix(bamMappedbwaaln) bamMapped.groupTuple(by:[0, 1]) .choice(singleBam, multipleBam) {it[2].size() > 1 ? 1 : 0} singleBam = singleBam.map { @@ -720,6 +752,28 @@ mergedBam = mergedBam.dump(tag:'Merged BAM') mergedBam = mergedBam.mix(singleBam) mergedBam = mergedBam.dump(tag:'BAMs for MD') +(mergedBam, mergedBamBWAaln) = mergedBam.into(2) + +process IndexBamFile { + label 'cpus_8' + + tag {idPatient + "-" + idSample} + + input: + set idPatient, idSample, file(bam) from mergedBamBWAaln + + output: + set idPatient, idSample, file(bam), file("*.bai") into indexedBam + + when: !params.knownIndels + + script: + """ + samtools index ${bam} + mv ${bam}.bai ${bam.baseName}.bai + """ +} + // STEP 2: MARKING DUPLICATES process MarkDuplicates { @@ -740,7 +794,7 @@ process MarkDuplicates { set idPatient, idSample, file("${idSample}.md.bam"), file("${idSample}.md.bai") into duplicateMarkedBams file ("${idSample}.bam.metrics") into markDuplicatesReport - when: step == 'mapping' + when: step == 'mapping' && params.knownIndels script: markdup_java_options = task.memory.toGiga() > 8 ? params.markdup_java_options : "\"-Xms" + (task.memory.toGiga() / 2).trunc() + "g -Xmx" + (task.memory.toGiga() - 1) + "g\"" @@ -762,7 +816,7 @@ if ('markduplicates' in skipQC) markDuplicatesReport.close() duplicateMarkedBams = duplicateMarkedBams.dump(tag:'MD BAM') markDuplicatesReport = markDuplicatesReport.dump(tag:'MD Report') -(bamMD, bamBaseRecalibratorNoInt, bamMDToJoin) = duplicateMarkedBams.into(3) +(bamMD, bamBaseRecalibratorNoInt, bamMDToJoin, bamMDToJoinNoInt) = duplicateMarkedBams.into(4) // if (params.intervals) bamBaseRecalibratorNoInt.close() @@ -828,9 +882,9 @@ process BaseRecalibratorNoIntervals { file(knownIndelsIndex) from ch_knownIndelsIndex output: - set idPatient, idSample, file("${idSample}.recal.table") into bamMDnoInt + set idPatient, idSample, file("${idSample}.recal.table") into recalNoInt - when: step == 'mapping' + when: !params.intervals && step == 'mapping' script: knownOptions = params.knownIndels ? knownIndels.collect{"--known-sites ${it}"}.join(' ') : "" @@ -903,6 +957,8 @@ bamApplyBQSR = bamApplyBQSR.dump(tag:'recal.table') bamApplyBQSR = bamApplyBQSR.combine(intApplyBQSR) +bamApplyBQSRnoInt = bamMDToJoinNoInt.join(recalNoInt, by:[0,1]) + // STEP 4: RECALIBRATING process ApplyBQSR { @@ -943,13 +999,13 @@ process ApplyBQSRnoIntervals { tag {idPatient + "-" + idSample} input: - set idPatient, idSample, file(bam), file(bai), file(recalibrationReport) from bamMDnoInt + set idPatient, idSample, file(bam), file(bai), file(recalibrationReport) from bamApplyBQSRnoInt file(dict) from ch_dict file(fasta) from ch_fasta file(fastaFai) from ch_fastaFai output: - set idPatient, idSample, file("${idSample}.recal.bam") into bamRecalNoInt + set idPatient, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bai") into bamRecalNoInt script: """ @@ -959,6 +1015,9 @@ process ApplyBQSRnoIntervals { --input ${bam} \ --output ${idSample}.recal.bam \ --bqsr-recal-file ${recalibrationReport} + + samtools index ${idSample}.recal.bam + mv ${idSample}.recal.bam.bai ${idSample}.recal.bai """ } @@ -1073,6 +1132,8 @@ bamQCReport = bamQCReport.dump(tag:'BamQC') ================================================================================ */ +bamRecal = params.knownIndels ? bamRecal.mix(bamRecalNoInt) : indexedBam + if (step == 'variantcalling') bamRecal = inputSample bamRecal = bamRecal.dump(tag:'BAM') @@ -1313,7 +1374,7 @@ vcfTIDDIT = vcfTIDDIT.dump(tag:'TIDDIT') */ // Ascat, Control-FREEC -(bamAscat, bamMpileup, bamRecalAll) = bamRecalAll.into(3) +(bamAscat, bamMpileup, bamMpileupNoInt, bamRecalAll) = bamRecalAll.into(4) // separate BAM by status bamNormal = Channel.create() @@ -1924,7 +1985,28 @@ process Mpileup { """ } -mpileupMerge = mpileupMerge.groupTuple(by:[0, 1]) +process MpileupNoIntervals { + label 'memory_singleCPU_2_task' + + tag {idSample} + + input: + set idPatient, idSample, file(bam), file(bai) from bamMpileupNoInt + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai + + output: + set idPatient, idSample, file("${idSample}.pileup.gz") into mpileupNoIntOut + + when: !params.intervals && 'mpileup' in tools + + script: + """ + samtools mpileup \ + -f ${fasta} ${bam} \ + | bgzip --threads ${task.cpus} -c > ${idSample}.pileup.gz + """ +} // STEP CONTROLFREEC.2 - MERGE MPILEUP From c61768b2e0bac09ef07ed91cc2b1ad297aa7a50f Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 29 Oct 2019 09:43:49 +0100 Subject: [PATCH 160/854] don't use bwa aln --- main.nf | 38 ++++---------------------------------- 1 file changed, 4 insertions(+), 34 deletions(-) diff --git a/main.nf b/main.nf index eee29e19f1..f61dd3db3e 100644 --- a/main.nf +++ b/main.nf @@ -683,42 +683,10 @@ process MapReads { bamMapped = bamMapped.dump(tag:'Mapped BAM') -process MapReadsBWAaln { - label 'cpus_max' - - tag {idPatient + "-" + idRun} - - input: - set idPatient, idSample, idRun, file(inputFile1), file(inputFile2) from inputReadsBWAaln - file(bwaIndex) from ch_bwaIndex - file(fasta) from ch_fasta - - output: - set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam") into bamMappedbwaaln - set idPatient, idSample, file("${idSample}_${idRun}.bam") into bamMappedBamQCbwaaln - - when: step == 'mapping' && !params.knownIndels - - script: - """ - bwa aln ${fasta} ${inputFile1} > ${idSample}_${idRun}_R1.sai - bwa aln ${fasta} ${inputFile2} > ${idSample}_${idRun}_R2.sai - - bwa sampe ${fasta} ${idSample}_${idRun}_R1.sai ${idSample}_${idRun}_R2.sai ${inputFile1} ${inputFile2} > ${idSample}_${idRun}.sam - - samtools view -S -b ${idSample}_${idRun}.sam > ${idSample}_${idRun}.unsorted.sam - - samtools sort ${idSample}_${idRun}.unsorted.sam -o ${idSample}_${idRun}.bam - """ -} - -bamMappedbwaaln = bamMappedbwaaln.dump(tag:'Mapped BAM bwa aln') - // Sort BAM whether they are standalone or should be merged singleBam = Channel.create() multipleBam = Channel.create() -bamMapped = bamMapped.mix(bamMappedbwaaln) bamMapped.groupTuple(by:[0, 1]) .choice(singleBam, multipleBam) {it[2].size() > 1 ? 1 : 0} singleBam = singleBam.map { @@ -752,7 +720,7 @@ mergedBam = mergedBam.dump(tag:'Merged BAM') mergedBam = mergedBam.mix(singleBam) mergedBam = mergedBam.dump(tag:'BAMs for MD') -(mergedBam, mergedBamBWAaln) = mergedBam.into(2) +(mergedBam, mergedBamToIndex) = mergedBam.into(2) process IndexBamFile { label 'cpus_8' @@ -760,7 +728,7 @@ process IndexBamFile { tag {idPatient + "-" + idSample} input: - set idPatient, idSample, file(bam) from mergedBamBWAaln + set idPatient, idSample, file(bam) from mergedBamToIndex output: set idPatient, idSample, file(bam), file("*.bai") into indexedBam @@ -1985,6 +1953,8 @@ process Mpileup { """ } +mpileupMerge = mpileupMerge.groupTuple(by:[0, 1]) + process MpileupNoIntervals { label 'memory_singleCPU_2_task' From 044de7517690c730e8925f09e5d7dc72fed3dd5e Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 29 Oct 2019 16:22:30 +0100 Subject: [PATCH 161/854] add automatic generation of intervals file based on fastaFai file --- main.nf | 63 +++++++++++++++++++++++++++++++++++++------------ nextflow.config | 1 + 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/main.nf b/main.nf index f61dd3db3e..58abea6254 100644 --- a/main.nf +++ b/main.nf @@ -43,6 +43,7 @@ def helpMessage() { --genome Name of iGenomes reference --noGVCF No g.vcf output from HaplotypeCaller --noStrelkaBP Will not use Manta candidateSmallIndels for Strelka as Best Practice + --noIntervals Disable usage of intervals --nucleotidesPerSecond To estimate interval size Default: 1000.0 --targetBED Target BED file for targeted or whole exome sequencing @@ -69,14 +70,21 @@ def helpMessage() { --acLoci acLoci file --acLociGC acLoci GC file --bwaIndex bwa indexes + If none provided, will be generated automatically --dbsnp dbsnp file --dbsnpIndex dbsnp index + If none provided, will be generated automatically --dict dict from the fasta reference + If none provided, will be generated automatically --fasta fasta reference --fastafai reference index + If none provided, will be generated automatically --intervals intervals + If none provided, will be generated automatically + Use --noIntervals to disable automatic generation --knownIndels knownIndels file --knownIndelsIndex knownIndels index + If none provided, will be generated automatically --snpeffDb snpeffDb version --vepCacheVersion VEP Cache version @@ -236,7 +244,6 @@ ch_dbsnp = params.dbsnp && ('mapping' in step || 'controlfreec' in tools || 'hap ch_fasta = params.fasta && !('annotate' in step) ? Channel.value(file(params.fasta)) : "null" ch_fastaFai = params.fastaFai && !('annotate' in step) ? Channel.value(file(params.fastaFai)) : "null" ch_germlineResource = params.germlineResource && 'mutect2' in tools ? Channel.value(file(params.germlineResource)) : "null" -ch_intervals = params.intervals && !('annotate' in step) ? Channel.value(file(params.intervals)) : "null" // knownIndels is currently a list of file for smallGRCh37, so transform it in a channel li_knownIndels = [] @@ -371,6 +378,8 @@ yamlSoftwareVersion = yamlSoftwareVersion.dump(tag:'SOFTWARE VERSIONS') ================================================================================ */ +// And then initialize channels based on params or indexes that were just built + process BuildBWAindexes { tag {fasta} @@ -391,6 +400,8 @@ process BuildBWAindexes { """ } +ch_bwaIndex = params.bwaIndex ? Channel.value(file(params.bwaIndex)) : bwaIndexes + process BuildDict { tag {fasta} @@ -414,6 +425,8 @@ process BuildDict { """ } +ch_dict = params.dict ? Channel.value(file(params.dict)) : dictBuilt + process BuildFastaFai { tag {fasta} @@ -434,6 +447,8 @@ process BuildFastaFai { """ } +ch_fastaFai = params.fastaFai ? Channel.value(file(params.fastaFai)) : fastaFaiBuilt + process BuildDbsnpIndex { tag {dbsnp} @@ -453,6 +468,8 @@ process BuildDbsnpIndex { """ } +ch_dbsnpIndex = params.dbsnpIndex ? Channel.value(file(params.dbsnpIndex)) : dbsnpIndexBuilt + process BuildGermlineResourceIndex { tag {germlineResource} @@ -473,6 +490,8 @@ process BuildGermlineResourceIndex { """ } +ch_germlineResourceIndex = params.germlineResourceIndex ? Channel.value(file(params.germlineResourceIndex)) : germlineResourceIndexBuilt + process BuildKnownIndelsIndex { tag {knownIndels} @@ -493,14 +512,30 @@ process BuildKnownIndelsIndex { """ } -// Initialize channels based on params or indexes that were just built -ch_bwaIndex = params.bwaIndex ? Channel.value(file(params.bwaIndex)) : bwaIndexes -ch_dbsnpIndex = params.dbsnpIndex ? Channel.value(file(params.dbsnpIndex)) : dbsnpIndexBuilt -ch_dict = params.dict ? Channel.value(file(params.dict)) : dictBuilt -ch_fastaFai = params.fastaFai ? Channel.value(file(params.fastaFai)) : fastaFaiBuilt -ch_germlineResourceIndex = params.germlineResourceIndex ? Channel.value(file(params.germlineResourceIndex)) : germlineResourceIndexBuilt ch_knownIndelsIndex = params.knownIndelsIndex ? Channel.value(file(params.knownIndelsIndex)) : knownIndelsIndexBuilt.collect() +process BuildIntervals { + tag {fastaFai} + + publishDir params.outdir, mode: params.publishDirMode, + saveAs: {params.saveGenomeIndex ? "reference_genome/${it}" : null } + + input: + file(fastaFai) from ch_fastaFai + + output: + file("${fastaFai.baseName}.bed") into intervalBuilt + + when: !(params.intervals) && !('annotate' in step) && !(params.noIntervals) + + script: + """ + awk -v FS='\t' -v OFS='\t' '{ print \$1, \"0\", \$2 }' ${fastaFai} > ${fastaFai.baseName}.bed + """ +} + +ch_intervals = params.noIntervals ? "null" : params.intervals && !('annotate' in step) ? Channel.value(file(params.intervals)) : intervalBuilt + /* ================================================================================ PREPROCESSING @@ -518,7 +553,7 @@ process CreateIntervalBeds { output: file '*.bed' into bedIntervals mode flatten - when: params.intervals && step != 'annotate' + when: !(params.noIntervals) && step != 'annotate' script: // If the interval file is BED format, the fifth column is interpreted to @@ -575,8 +610,8 @@ bedIntervals = bedIntervals.dump(tag:'bedintervals') // PREPARING CHANNELS FOR PREPROCESSING AND QC -if (step == 'mapping') (inputReads, inputReadsBWAaln, inputReadsFastQC) = inputSample.into(3) -else (inputReads, inputReadsBWAaln, inputReadsFastQC) = Channel.empty().into(3) +if (step == 'mapping') (inputReads, inputReadsFastQC) = inputSample.into(2) +else (inputReads, inputReadsFastQC) = Channel.empty().into(2) inputPairReadsFastQC = Channel.create() inputBAMFastQC = Channel.create() @@ -658,7 +693,7 @@ process MapReads { set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam") into bamMapped set idPatient, idSample, file("${idSample}_${idRun}.bam") into bamMappedBamQC - when: step == 'mapping' && params.knownIndels + when: step == 'mapping' script: // -K is an hidden option, used to fix the number of reads processed by bwa mem @@ -786,8 +821,6 @@ markDuplicatesReport = markDuplicatesReport.dump(tag:'MD Report') (bamMD, bamBaseRecalibratorNoInt, bamMDToJoin, bamMDToJoinNoInt) = duplicateMarkedBams.into(4) -// if (params.intervals) bamBaseRecalibratorNoInt.close() - bamBaseRecalibrator = bamMD.combine(intBaseRecalibrator) bamBaseRecalibrator = bamBaseRecalibrator.dump(tag:'BAM FOR BASERECALIBRATOR') @@ -852,7 +885,7 @@ process BaseRecalibratorNoIntervals { output: set idPatient, idSample, file("${idSample}.recal.table") into recalNoInt - when: !params.intervals && step == 'mapping' + when: params.noIntervals && step == 'mapping' script: knownOptions = params.knownIndels ? knownIndels.collect{"--known-sites ${it}"}.join(' ') : "" @@ -1968,7 +2001,7 @@ process MpileupNoIntervals { output: set idPatient, idSample, file("${idSample}.pileup.gz") into mpileupNoIntOut - when: !params.intervals && 'mpileup' in tools + when: params.noIntervals && 'mpileup' in tools script: """ diff --git a/nextflow.config b/nextflow.config index 6ddfb53847..4cdead349e 100644 --- a/nextflow.config +++ b/nextflow.config @@ -14,6 +14,7 @@ params { input = null // No default input noGVCF = null // g.vcf are produced by HaplotypeCaller noStrelkaBP = null // Strelka will use Manta candidateSmallIndels if available + noIntervals = null // Intervals will be built from the fastaFai file skipQC = null // All QC tools are used step = 'mapping' // Starts with mapping tools = null // No default Variant Calling or Annotation tools From 0dacda143a5e71c7647e9c837f52d6b7b43ab028 Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Wed, 30 Oct 2019 10:52:28 +0100 Subject: [PATCH 162/854] Adjusted genomes.config --- conf/genomes.config | 15 +++++++++++++++ conf/igenomes.config | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/conf/genomes.config b/conf/genomes.config index 7d7527b21a..df2b0d9f79 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -58,5 +58,20 @@ params { snpeffDb = "GRCh37.75" vepCacheVersion = "95" } + 'GRCm38' { + bwaIndex = "${params.genomes_base}/genome.fa.{amb,ann,bwt,pac,sa}" + chrDir = "${params.genomes_base}/Chromosomes" + chrLength = "${params.genomes_base}/GRCm38.len" + dbsnp = "${params.genomes_base}/mgp.v6.merged.norm.snp.indels.sfiltered.vcf.gz" + dbsnpIndex = "${params.genomes_base}/mgp.v6.merged.norm.snp.indels.sfiltered.vcf.gz.tbi" + dict = "${params.genomes_base}/genome.dict" + fasta = "${params.genomes_base}/genome.fa" + fastaFai = "${params.genomes_base}/genome.fai" + intervals = "${params.genomes_base}/wgs_calling_regions.grcm38.bed" + knownIndels = "${params.genomes_base}/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz" + knownIndelsIndex = "${params.genomes_base}/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz.tbi" + snpeffDb = "GRCm38.86" + vepCacheVersion = "98" + } } } diff --git a/conf/igenomes.config b/conf/igenomes.config index 5413cec2a2..3637b731d6 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -50,7 +50,7 @@ params { 'GRCm38' { bwaIndex = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" chrDir = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/Chromosomes" - chrLength = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/Length/Homo_sapiens_assembly38.len" + chrLength = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/Length/GRCm38.len" dbsnp = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/mgp.v6.merged.norm.snp.indels.sfiltered.vcf.gz" dbsnpIndex = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/mgp.v6.merged.norm.snp.indels.sfiltered.vcf.gz.tbi" dict = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.dict" From 9a35195ae62af28cd3952ea793c101ae06ee21bc Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Wed, 30 Oct 2019 11:52:33 +0100 Subject: [PATCH 163/854] Should be list --- conf/genomes.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/genomes.config b/conf/genomes.config index df2b0d9f79..151562d5b7 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -67,7 +67,7 @@ params { dict = "${params.genomes_base}/genome.dict" fasta = "${params.genomes_base}/genome.fa" fastaFai = "${params.genomes_base}/genome.fai" - intervals = "${params.genomes_base}/wgs_calling_regions.grcm38.bed" + intervals = "${params.genomes_base}/wgs_calling_regions.grcm38.list" knownIndels = "${params.genomes_base}/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz" knownIndelsIndex = "${params.genomes_base}/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz.tbi" snpeffDb = "GRCm38.86" From e6c07a5051209b65dad5429c3c8ff91dee91378e Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Wed, 30 Oct 2019 11:59:45 +0100 Subject: [PATCH 164/854] Set genomes_base to something --- nextflow.config | 1 + 1 file changed, 1 insertion(+) diff --git a/nextflow.config b/nextflow.config index 6ddfb53847..af89c56254 100644 --- a/nextflow.config +++ b/nextflow.config @@ -53,6 +53,7 @@ params { // Reference genomes igenomesIgnore = false igenomes_base = 's3://ngi-igenomes/igenomes/' + genomes_base = false // Default help = false From 934622da52287d94a57dd5f1964d0c84963baf8d Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Wed, 30 Oct 2019 12:13:26 +0100 Subject: [PATCH 165/854] Revert back --- nextflow.config | 1 - 1 file changed, 1 deletion(-) diff --git a/nextflow.config b/nextflow.config index af89c56254..6ddfb53847 100644 --- a/nextflow.config +++ b/nextflow.config @@ -53,7 +53,6 @@ params { // Reference genomes igenomesIgnore = false igenomes_base = 's3://ngi-igenomes/igenomes/' - genomes_base = false // Default help = false From 1cde457dedb08e99be965653cb3372d5b6e9d609 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 30 Oct 2019 13:31:01 +0100 Subject: [PATCH 166/854] enable CreateIntervalsBed for intervals_list from GATK Bundle --- main.nf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/main.nf b/main.nf index 204f315b4d..d1acd29d57 100644 --- a/main.nf +++ b/main.nf @@ -543,6 +543,14 @@ process CreateIntervalBeds { print \$0 > name }' ${intervals} """ + else if (hasExtension(intervals, "interval_list")) + """ + cat ${intervals} | grep -v "@" > intervals.temp + awk -vFS="\t" '{ + name = sprintf("%s_%d-%d", \$1, \$2, \$3); + printf("%s\\t%d\\t%d\\n", \$1, \$2-1, \$3) > name ".bed" + }' intervals.temp + """ else """ awk -vFS="[:-]" '{ From 985af84438a224216850ffaff77351b5b23b2a7e Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Wed, 30 Oct 2019 14:04:54 +0100 Subject: [PATCH 167/854] Add proper calling list --- conf/genomes.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/genomes.config b/conf/genomes.config index 151562d5b7..16886883b6 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -67,7 +67,7 @@ params { dict = "${params.genomes_base}/genome.dict" fasta = "${params.genomes_base}/genome.fa" fastaFai = "${params.genomes_base}/genome.fai" - intervals = "${params.genomes_base}/wgs_calling_regions.grcm38.list" + intervals = "${params.genomes_base}/GRCm38_calling_list.list" knownIndels = "${params.genomes_base}/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz" knownIndelsIndex = "${params.genomes_base}/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz.tbi" snpeffDb = "GRCm38.86" From da5ea62a98deb9e82887361ac55501f8a88fb3b2 Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Wed, 30 Oct 2019 14:08:58 +0100 Subject: [PATCH 168/854] Use the bed file --- conf/genomes.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/genomes.config b/conf/genomes.config index 16886883b6..b2faba0ae0 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -67,7 +67,7 @@ params { dict = "${params.genomes_base}/genome.dict" fasta = "${params.genomes_base}/genome.fa" fastaFai = "${params.genomes_base}/genome.fai" - intervals = "${params.genomes_base}/GRCm38_calling_list.list" + intervals = "${params.genomes_base}/GRCm38_calling_list.bed" knownIndels = "${params.genomes_base}/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz" knownIndelsIndex = "${params.genomes_base}/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz.tbi" snpeffDb = "GRCm38.86" From 793ba99a0bbecc6e13411bda7421404196372831 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 30 Oct 2019 15:27:16 +0100 Subject: [PATCH 169/854] remove temp file --- main.nf | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/main.nf b/main.nf index d1acd29d57..2aec0d0e2c 100644 --- a/main.nf +++ b/main.nf @@ -545,11 +545,10 @@ process CreateIntervalBeds { """ else if (hasExtension(intervals, "interval_list")) """ - cat ${intervals} | grep -v "@" > intervals.temp - awk -vFS="\t" '{ + grep -v '^@' ${intervals} | awk -vFS="\t" '{ name = sprintf("%s_%d-%d", \$1, \$2, \$3); printf("%s\\t%d\\t%d\\n", \$1, \$2-1, \$3) > name ".bed" - }' intervals.temp + }' """ else """ From 962ebe68e3de9d2d12b35299a2d879b0d04229f6 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 30 Oct 2019 15:32:36 +0100 Subject: [PATCH 170/854] update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a8e7c2d25..70736a1d59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [#42](https://github.com/nf-core/sarek/pull/42) - Fix typos, and minor updates in `README.md` - [#43](https://github.com/nf-core/sarek/pull/43) - Fix automated `VEP` builds with circleCI - [#54](https://github.com/nf-core/sarek/pull/54) - Apply fixes from release `2.5.1` +- [#58](https://github.com/nf-core/sarek/pull/58) - Fix issue with `.interval_list` file from the GATK bundle [#56](https://github.com/nf-core/sarek/issues/56) that was not recognized in the `CreateIntervalsBed` process ## [2.5.1] - Årjep-Ålkatjjekna From 888a22050263de6541fdf4e7aa626fac35dc2187 Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Wed, 30 Oct 2019 15:36:14 +0100 Subject: [PATCH 171/854] Fix genome fa.fai --- conf/genomes.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/genomes.config b/conf/genomes.config index b2faba0ae0..d567b35772 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -66,7 +66,7 @@ params { dbsnpIndex = "${params.genomes_base}/mgp.v6.merged.norm.snp.indels.sfiltered.vcf.gz.tbi" dict = "${params.genomes_base}/genome.dict" fasta = "${params.genomes_base}/genome.fa" - fastaFai = "${params.genomes_base}/genome.fai" + fastaFai = "${params.genomes_base}/genome.fa.fai" intervals = "${params.genomes_base}/GRCm38_calling_list.bed" knownIndels = "${params.genomes_base}/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz" knownIndelsIndex = "${params.genomes_base}/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz.tbi" From 17e1f23de1f162d3f1a7c7336f2ae5a2736c205c Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Wed, 30 Oct 2019 23:57:43 +0100 Subject: [PATCH 172/854] Add in mgpv5 --- conf/genomes.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/genomes.config b/conf/genomes.config index d567b35772..be88bad126 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -62,8 +62,8 @@ params { bwaIndex = "${params.genomes_base}/genome.fa.{amb,ann,bwt,pac,sa}" chrDir = "${params.genomes_base}/Chromosomes" chrLength = "${params.genomes_base}/GRCm38.len" - dbsnp = "${params.genomes_base}/mgp.v6.merged.norm.snp.indels.sfiltered.vcf.gz" - dbsnpIndex = "${params.genomes_base}/mgp.v6.merged.norm.snp.indels.sfiltered.vcf.gz.tbi" + dbsnp = "${params.genomes_base}/mgp.v5.merged.snps_all.dbSNP142.vcf.gz" + dbsnpIndex = "${params.genomes_base}/mgp.v5.merged.snps_all.dbSNP142.vcf.gz.tbi" dict = "${params.genomes_base}/genome.dict" fasta = "${params.genomes_base}/genome.fa" fastaFai = "${params.genomes_base}/genome.fa.fai" From c3c6e93b61918414b179349d298f9a45e0a6463d Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Thu, 31 Oct 2019 10:24:22 +0100 Subject: [PATCH 173/854] Try short track --- main.nf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.nf b/main.nf index ffe3b12b7d..1570175677 100644 --- a/main.nf +++ b/main.nf @@ -2247,6 +2247,7 @@ process VEP { script: reducedVCF = reduceVCF(vcf.fileName) genome = params.genome == 'smallGRCh37' ? 'GRCh37' : params.genome + dir_cache = (params.vep_cache && params.annotation_cache) ? " \${PWD}/${dataDir}" : "/.vep" cadd = (params.cadd_cache && params.cadd_WG_SNVs && params.cadd_InDels) ? "--plugin CADD,whole_genome_SNVs.tsv.gz,InDels.tsv.gz" : "" genesplicer = params.genesplicer ? "--plugin GeneSplicer,/opt/conda/envs/sarek-${workflow.manifest.version}/bin/genesplicer,/opt/conda/envs/sarek-${workflow.manifest.version}/share/genesplicer-1.0-1/human,context=200,tmpdir=\$PWD/${reducedVCF}" : "--offline" @@ -2257,6 +2258,7 @@ process VEP { -i ${vcf} \ -o ${reducedVCF}_VEP.ann.vcf \ --assembly ${genome} \ + --species mus_musculus \ ${cadd} \ ${genesplicer} \ --cache \ From 7fa975687402322b44a7b6a2528b1b5852374deb Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Thu, 31 Oct 2019 10:48:17 +0100 Subject: [PATCH 174/854] Add in species handling --- conf/genomes.config | 4 ++++ conf/igenomes.config | 3 +++ main.nf | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/conf/genomes.config b/conf/genomes.config index be88bad126..64745178e2 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -27,6 +27,7 @@ params { knownIndelsIndex = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" snpeffDb = "GRCh37.75" vepCacheVersion = "95" + species = 'homo_sapiens' } 'GRCh38' { acLoci = "${params.genomes_base}/1000G_phase3_GRCh38_maf0.3.loci" @@ -46,6 +47,7 @@ params { knownIndelsIndex = "${params.genomes_base}/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" snpeffDb = "GRCh38.86" vepCacheVersion = "95" + species = 'homo_sapiens' } 'smallGRCh37' { acLoci = "${params.genomes_base}/1000G_phase3_20130502_SNP_maf0.3.small.loci" @@ -57,6 +59,7 @@ params { knownIndels = ["${params.genomes_base}/1000G_phase1.indels.b37.small.vcf.gz", "${params.genomes_base}/Mills_and_1000G_gold_standard.indels.b37.small.vcf.gz"] snpeffDb = "GRCh37.75" vepCacheVersion = "95" + species = 'homo_sapiens' } 'GRCm38' { bwaIndex = "${params.genomes_base}/genome.fa.{amb,ann,bwt,pac,sa}" @@ -72,6 +75,7 @@ params { knownIndelsIndex = "${params.genomes_base}/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz.tbi" snpeffDb = "GRCm38.86" vepCacheVersion = "98" + species = 'mus_musculus' } } } diff --git a/conf/igenomes.config b/conf/igenomes.config index 3637b731d6..d3adee8854 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -27,6 +27,7 @@ params { knownIndelsIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" snpeffDb = "GRCh37.75" vepCacheVersion = "95" + species = 'homo_sapiens' } 'GRCh38' { acLoci = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/ASCAT/1000G_phase3_GRCh38_maf0.3.loci" @@ -46,6 +47,7 @@ params { knownIndelsIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" snpeffDb = "GRCh38.86" vepCacheVersion = "95" + species = 'homo_sapiens' } 'GRCm38' { bwaIndex = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" @@ -61,6 +63,7 @@ params { knownIndelsIndex = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz.tbi" snpeffDb = "GRCm38.86" vepCacheVersion = "98" + species = 'mus_musculus' } } } diff --git a/main.nf b/main.nf index 1570175677..7fdeb24cc5 100644 --- a/main.nf +++ b/main.nf @@ -2258,7 +2258,7 @@ process VEP { -i ${vcf} \ -o ${reducedVCF}_VEP.ann.vcf \ --assembly ${genome} \ - --species mus_musculus \ + --species ${params.species} \ ${cadd} \ ${genesplicer} \ --cache \ @@ -2320,6 +2320,7 @@ process VEPmerge { -i ${vcf} \ -o ${reducedVCF}_VEP.ann.vcf \ --assembly ${genome} \ + --species ${params.species} \ ${cadd} \ ${genesplicer} \ --cache \ From 2f9530ffd7f22e701304bae291f47eb9768a481a Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Thu, 31 Oct 2019 10:48:24 +0100 Subject: [PATCH 175/854] Document new parameter species --- docs/usage.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/usage.md b/docs/usage.md index f1532af20b..ef4346006d 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -47,6 +47,7 @@ * [`--snpeffDb`](#--snpeffdb) * [`--vepCacheVersion`](#--vepcacheversion) * [`--igenomesIgnore`](#--igenomesignore) + * [`--species`](#--species) * [Job resources](#job-resources) * [Automatic resubmission](#automatic-resubmission) * [Custom resource requests](#custom-resource-requests) @@ -514,6 +515,10 @@ If you prefer, you can specify the cache version when you run the pipeline: Do not load `igenomes.config` when running the pipeline. You may choose this option if you observe clashes between custom parameters and those supplied in `igenomes.config`. +### `--species` + +This specifies the species used for running VEP annotation. For human data, this needs to be set to `homo_sapiens`, for mouse data `mus_musculus` as the annotation needs to know where to look for appropriate annotation references. If you use iGenomes or a local resource with `genomes.conf`, this has already been set for you appropriately. + ## Job resources ### Automatic resubmission From 30e6b4c9848a3e77602db0f630431681a32c9a6c Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Thu, 31 Oct 2019 10:53:50 +0100 Subject: [PATCH 176/854] Add changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f1d71a6ea..d516c37ebe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [#41](https://github.com/nf-core/sarek/pull/41) - Update `qualimap` from `2.2.2b` to `2.2.2c` - [#41](https://github.com/nf-core/sarek/pull/41) - Update `tiddit` from `2.7.1` to `2.8.0` - [#41](https://github.com/nf-core/sarek/pull/41) - Update `vcfanno` from `0.3.1` to `0.3.2` -- [#46](https://github.com/nf-core/sarek/pull/46) - Add location to abstacts. +- [#46](https://github.com/nf-core/sarek/pull/46) - Add location to abstracts. +- [#52](https://github.com/nf-core/sarek/pull/52) - Add support for mouse data `GRCm38` ### `Removed` From c86114ab6d98ce48ed0f841acf551c4672990ae1 Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Thu, 31 Oct 2019 10:56:33 +0100 Subject: [PATCH 177/854] Fix iGenomes stuff --- conf/igenomes.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/igenomes.config b/conf/igenomes.config index d3adee8854..f137b7f121 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -53,8 +53,8 @@ params { bwaIndex = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" chrDir = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/Chromosomes" chrLength = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/Length/GRCm38.len" - dbsnp = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/mgp.v6.merged.norm.snp.indels.sfiltered.vcf.gz" - dbsnpIndex = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/mgp.v6.merged.norm.snp.indels.sfiltered.vcf.gz.tbi" + dbsnp = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/mgp.v5.merged.snps_all.dbSNP142.vcf.gz" + dbsnpIndex = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/mgp.v5.merged.snps_all.dbSNP142.vcf.gz.tbi" dict = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.dict" fasta = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa" fastaFai = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fai" From 9ba7c6fb9ecc588272995c073940b05df302dfcd Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Thu, 31 Oct 2019 10:57:28 +0100 Subject: [PATCH 178/854] Add in note about GRCm38 --- docs/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference.md b/docs/reference.md index 5c47b7dddb..5fd89e59e7 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -5,7 +5,7 @@ Sarek is using [AWS iGenomes](https://ewels.github.io/AWS-iGenomes/), which facilitate storing and sharing references. Sarek currently uses `GRCh38` by default. Both `GRCh37` and `GRCh38` are available with `--genome GRCh37` or `--genome GRCh38` respectively with any profile using the `conf/igenomes.config` file, or you can specify it with `-c conf/igenomes.config`. -Use `--genome smallGRCh37` to map against a small reference genome based on GRCh37. +Use `--genome smallGRCh37` to map against a small reference genome based on GRCh37. Furthermore, mouse genome data can be analyzed using `--genome GRCm38`. Settings in `igenomes.config` can be tailored to your needs. ### Intervals From b33576bfb4bd5e767ecad67621ddf34a3ce00bd9 Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Thu, 31 Oct 2019 11:14:19 +0100 Subject: [PATCH 179/854] Fix small fai index issue --- conf/igenomes.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/igenomes.config b/conf/igenomes.config index f137b7f121..75f26a1ddd 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -57,7 +57,7 @@ params { dbsnpIndex = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/mgp.v5.merged.snps_all.dbSNP142.vcf.gz.tbi" dict = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.dict" fasta = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa" - fastaFai = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fai" + fastaFai = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa.fai" intervals = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/intervals/wgs_calling_regions.grcm38.bed" knownIndels = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz" knownIndelsIndex = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz.tbi" From c70dd719625d51419c16963f84b4fff22db2984e Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Thu, 31 Oct 2019 11:35:31 +0100 Subject: [PATCH 180/854] Adjusted quotes in genomes.config --- conf/genomes.config | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/conf/genomes.config b/conf/genomes.config index 64745178e2..b29d038e29 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -25,8 +25,8 @@ params { intervals = "${params.genomes_base}/wgs_calling_regions_Sarek.list" knownIndels = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf" knownIndelsIndex = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" - snpeffDb = "GRCh37.75" - vepCacheVersion = "95" + snpeffDb = 'GRCh37.75' + vepCacheVersion = '95' species = 'homo_sapiens' } 'GRCh38' { @@ -45,8 +45,8 @@ params { intervals = "${params.genomes_base}/wgs_calling_regions.hg38.bed" knownIndels = "${params.genomes_base}/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" knownIndelsIndex = "${params.genomes_base}/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" - snpeffDb = "GRCh38.86" - vepCacheVersion = "95" + snpeffDb = 'GRCh38.86' + vepCacheVersion = '95' species = 'homo_sapiens' } 'smallGRCh37' { @@ -57,8 +57,8 @@ params { germlineResource = "${params.genomes_base}/dbsnp_138.b37.small.vcf.gz" intervals = "${params.genomes_base}/small.intervals" knownIndels = ["${params.genomes_base}/1000G_phase1.indels.b37.small.vcf.gz", "${params.genomes_base}/Mills_and_1000G_gold_standard.indels.b37.small.vcf.gz"] - snpeffDb = "GRCh37.75" - vepCacheVersion = "95" + snpeffDb = 'GRCh37.75' + vepCacheVersion = '95' species = 'homo_sapiens' } 'GRCm38' { @@ -73,8 +73,8 @@ params { intervals = "${params.genomes_base}/GRCm38_calling_list.bed" knownIndels = "${params.genomes_base}/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz" knownIndelsIndex = "${params.genomes_base}/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz.tbi" - snpeffDb = "GRCm38.86" - vepCacheVersion = "98" + snpeffDb = 'GRCm38.86' + vepCacheVersion = '98' species = 'mus_musculus' } } From fffc46f3b03b663d62b137262e60886588999b4a Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Thu, 31 Oct 2019 11:36:01 +0100 Subject: [PATCH 181/854] And the same for igenomes --- conf/igenomes.config | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/conf/igenomes.config b/conf/igenomes.config index 75f26a1ddd..0b5e9dbde1 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -25,8 +25,8 @@ params { intervals = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/intervals/wgs_calling_regions_Sarek.list" knownIndels = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf" knownIndelsIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" - snpeffDb = "GRCh37.75" - vepCacheVersion = "95" + snpeffDb = 'GRCh37.75' + vepCacheVersion = '95' species = 'homo_sapiens' } 'GRCh38' { @@ -45,8 +45,8 @@ params { intervals = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/intervals/wgs_calling_regions.hg38.bed" knownIndels = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" knownIndelsIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" - snpeffDb = "GRCh38.86" - vepCacheVersion = "95" + snpeffDb = 'GRCh38.86' + vepCacheVersion = '95' species = 'homo_sapiens' } 'GRCm38' { @@ -61,8 +61,8 @@ params { intervals = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/intervals/wgs_calling_regions.grcm38.bed" knownIndels = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz" knownIndelsIndex = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz.tbi" - snpeffDb = "GRCm38.86" - vepCacheVersion = "98" + snpeffDb = 'GRCm38.86' + vepCacheVersion = '98' species = 'mus_musculus' } } From 2c821e437ce300daa9b2eb66a50899add2a01f2f Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Thu, 31 Oct 2019 11:54:14 +0100 Subject: [PATCH 182/854] Better folder structure for Mouse Genome Project data --- conf/igenomes.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/igenomes.config b/conf/igenomes.config index 0b5e9dbde1..e4ad3d9871 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -53,8 +53,8 @@ params { bwaIndex = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" chrDir = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/Chromosomes" chrLength = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/Length/GRCm38.len" - dbsnp = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/mgp.v5.merged.snps_all.dbSNP142.vcf.gz" - dbsnpIndex = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/mgp.v5.merged.snps_all.dbSNP142.vcf.gz.tbi" + dbsnp = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/MouseGenomeProject/Annotation/mgp.v5.merged.snps_all.dbSNP142.vcf.gz" + dbsnpIndex = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/MouseGenomeProject/Annotation/mgp.v5.merged.snps_all.dbSNP142.vcf.gz.tbi" dict = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.dict" fasta = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa" fastaFai = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa.fai" From 092518954b0a43b78d03cefacb71963a0f7bec2a Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Thu, 31 Oct 2019 12:07:17 +0100 Subject: [PATCH 183/854] Minor adjustment to propoer paths --- conf/igenomes.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/igenomes.config b/conf/igenomes.config index e4ad3d9871..b06dffac39 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -58,7 +58,7 @@ params { dict = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.dict" fasta = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa" fastaFai = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa.fai" - intervals = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/intervals/wgs_calling_regions.grcm38.bed" + intervals = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/intervals/GRCm38_calling_list.bed" knownIndels = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz" knownIndelsIndex = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz.tbi" snpeffDb = 'GRCm38.86' From 12a515293d93e2f7bdd0afd19bf655bd0688f24e Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Thu, 31 Oct 2019 12:50:48 +0100 Subject: [PATCH 184/854] Apply suggestions from code review Add changes by Maxime Co-Authored-By: Maxime Garcia --- docs/reference.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index 5fd89e59e7..f09702f939 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -4,8 +4,8 @@ Sarek is using [AWS iGenomes](https://ewels.github.io/AWS-iGenomes/), which facilitate storing and sharing references. Sarek currently uses `GRCh38` by default. -Both `GRCh37` and `GRCh38` are available with `--genome GRCh37` or `--genome GRCh38` respectively with any profile using the `conf/igenomes.config` file, or you can specify it with `-c conf/igenomes.config`. -Use `--genome smallGRCh37` to map against a small reference genome based on GRCh37. Furthermore, mouse genome data can be analyzed using `--genome GRCm38`. +`GRCh37`, `GRCh38` and `GRCm38 `are available with `--genome GRCh37`, `--genome GRCh38` or `--genome GRCm38` respectively with any profile using the `conf/igenomes.config` file, or you can specify it with `-c conf/igenomes.config`. +Use `--genome smallGRCh37` to map against a small reference genome based on GRCh37. Settings in `igenomes.config` can be tailored to your needs. ### Intervals From 92be499571770e15d20cda1ce366425a2cba11fa Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Thu, 31 Oct 2019 13:25:43 +0100 Subject: [PATCH 185/854] Remove space --- docs/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference.md b/docs/reference.md index f09702f939..65d96997e0 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -4,7 +4,7 @@ Sarek is using [AWS iGenomes](https://ewels.github.io/AWS-iGenomes/), which facilitate storing and sharing references. Sarek currently uses `GRCh38` by default. -`GRCh37`, `GRCh38` and `GRCm38 `are available with `--genome GRCh37`, `--genome GRCh38` or `--genome GRCm38` respectively with any profile using the `conf/igenomes.config` file, or you can specify it with `-c conf/igenomes.config`. +`GRCh37`, `GRCh38` and `GRCm38` are available with `--genome GRCh37`, `--genome GRCh38` or `--genome GRCm38` respectively with any profile using the `conf/igenomes.config` file, or you can specify it with `-c conf/igenomes.config`. Use `--genome smallGRCh37` to map against a small reference genome based on GRCh37. Settings in `igenomes.config` can be tailored to your needs. From 98ea8985710448492a85c65f65c96275e235bd5a Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Thu, 31 Oct 2019 13:52:51 +0100 Subject: [PATCH 186/854] Move it up --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fcfc6b8369..58b2ce302f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### `Added` - [#46](https://github.com/nf-core/sarek/pull/46) - Add location to abstacts +- [#52](https://github.com/nf-core/sarek/pull/52) - Add support for mouse data `GRCm38` ### `Changed` @@ -22,7 +23,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [#41](https://github.com/nf-core/sarek/pull/41), [#55](https://github.com/nf-core/sarek/pull/55) - Update `tiddit` from `2.7.1` to `2.8.1` - [#41](https://github.com/nf-core/sarek/pull/41) - Update `vcfanno` from `0.3.1` to `0.3.2` - [#46](https://github.com/nf-core/sarek/pull/46) - Add location to abstracts. -- [#52](https://github.com/nf-core/sarek/pull/52) - Add support for mouse data `GRCm38` - [#54](https://github.com/nf-core/sarek/pull/54) - Bump version to `2.5.2dev` ### `Removed` From bf3f262e622c8c76e906f14cc8d5a2685e3d2f3d Mon Sep 17 00:00:00 2001 From: Alexander Peltzer Date: Thu, 31 Oct 2019 13:57:26 +0100 Subject: [PATCH 187/854] Update CHANGELOG.md Co-Authored-By: Maxime Garcia --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58b2ce302f..036e279327 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [#41](https://github.com/nf-core/sarek/pull/41) - Update `qualimap` from `2.2.2b` to `2.2.2c` - [#41](https://github.com/nf-core/sarek/pull/41), [#55](https://github.com/nf-core/sarek/pull/55) - Update `tiddit` from `2.7.1` to `2.8.1` - [#41](https://github.com/nf-core/sarek/pull/41) - Update `vcfanno` from `0.3.1` to `0.3.2` -- [#46](https://github.com/nf-core/sarek/pull/46) - Add location to abstracts. - [#54](https://github.com/nf-core/sarek/pull/54) - Bump version to `2.5.2dev` ### `Removed` From 1bebb786ee11b5e39f190047d9864e097f3db2ca Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 4 Nov 2019 16:01:16 +0100 Subject: [PATCH 188/854] add minimal tests --- .github/workflows/ci-extra.yml | 2 +- scripts/run_tests.sh | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-extra.yml b/.github/workflows/ci-extra.yml index d37a33aae0..84d58bbde2 100644 --- a/.github/workflows/ci-extra.yml +++ b/.github/workflows/ci-extra.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - test: [ANNOTATESNPEFF, GERMLINE, SOMATIC, TARGETED] + test: [ANNOTATESNPEFF, GERMLINE, MINIMAL, SOMATIC, TARGETED] nxf_ver: ['19.04.0', ''] steps: - uses: actions/checkout@v1 diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index cb6db88901..eb02a84d18 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -84,7 +84,7 @@ else SUFFIX="" fi -OPTIONS="--tools FreeBayes,HaplotypeCaller,Manta,Mutect2,Strelka,TIDDIT" +OPTIONS="--tools FreeBayes,HaplotypeCaller,Manta,mpileup,Mutect2,Strelka" if [[ $TEST == "GERMLINE" ]] && [[ $OFFLINE == false ]] then @@ -113,11 +113,17 @@ case $TEST in ;; GERMLINE) run_sarek --tools=false --input data/testdata/tiny/normal - run_sarek --tools=false --input results/Preprocessing/TSV/duplicateMarked.tsv --step recalibrate + run_sarek --tools=false --input results/Preprocessing/TSV/duplicateMarked.tsv --step recalibrate -resume run_sarek --tools HaplotypeCaller --input results/Preprocessing/TSV/recalibrated.tsv --step variantCalling ;; + MINIMAL) + run_sarek --tools manta,mpileup,strelka --input ${PATHTOSAMPLE}/tsv/tiny-manta-normal${SUFFIX}.tsv --genome smallerGRCh37 + run_sarek --tools manta,mpileup,strelka --input ${PATHTOSAMPLE}/tsv/tiny-manta-normal${SUFFIX}.tsv --genome smallerGRCh37 --noIntervals -resume + run_sarek --tools manta,mpileup,strelka --input ${PATHTOSAMPLE}/tsv/tiny-manta-normal${SUFFIX}.tsv --genome minimalGRCh37 -resume + run_sarek --tools manta,mpileup,strelka --input ${PATHTOSAMPLE}/tsv/tiny-manta-normal${SUFFIX}.tsv --genome minimalGRCh37 --noIntervals -resume + ;; MULTIPLE) - run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,TIDDIT,snpEff,VEP,merge --input ${PATHTOSAMPLE}/tsv/tiny-multiple${SUFFIX}.tsv + run_sarek --tools FreeBayes,HaplotypeCaller,Manta,mpileup,Strelka,snpEff,VEP,merge --input ${PATHTOSAMPLE}/tsv/tiny-multiple${SUFFIX}.tsv ;; SOMATIC) run_sarek ${OPTIONS} --input ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv From 528cc1f293536ad944b666859d98333114c4fe81 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 4 Nov 2019 16:09:37 +0100 Subject: [PATCH 189/854] fix processes with no intervals --- main.nf | 216 ++++++++++++++++++++++++++------------------------------ 1 file changed, 101 insertions(+), 115 deletions(-) diff --git a/main.nf b/main.nf index 60b1e7c3d5..457b993b65 100644 --- a/main.nf +++ b/main.nf @@ -468,7 +468,7 @@ process BuildDbsnpIndex { """ } -ch_dbsnpIndex = params.dbsnpIndex ? Channel.value(file(params.dbsnpIndex)) : dbsnpIndexBuilt +ch_dbsnpIndex = params.dbsnp ? params.dbsnpIndex ? Channel.value(file(params.dbsnpIndex)) : dbsnpIndexBuilt : "null" process BuildGermlineResourceIndex { tag {germlineResource} @@ -490,7 +490,7 @@ process BuildGermlineResourceIndex { """ } -ch_germlineResourceIndex = params.germlineResourceIndex ? Channel.value(file(params.germlineResourceIndex)) : germlineResourceIndexBuilt +ch_germlineResourceIndex = params.germlineResource ? params.germlineResourceIndex ? Channel.value(file(params.germlineResourceIndex)) : germlineResourceIndexBuilt : "null" process BuildKnownIndelsIndex { tag {knownIndels} @@ -512,7 +512,7 @@ process BuildKnownIndelsIndex { """ } -ch_knownIndelsIndex = params.knownIndelsIndex ? Channel.value(file(params.knownIndelsIndex)) : knownIndelsIndexBuilt.collect() +ch_knownIndelsIndex = params.knownIndels ? params.knownIndelsIndex ? Channel.value(file(params.knownIndelsIndex)) : knownIndelsIndexBuilt.collect() : "null" process BuildIntervals { tag {fastaFai} @@ -553,7 +553,7 @@ process CreateIntervalBeds { output: file '*.bed' into bedIntervals mode flatten - when: !(params.noIntervals) && step != 'annotate' + when: (!params.noIntervals) && step != 'annotate' script: // If the interval file is BED format, the fifth column is interpreted to @@ -606,6 +606,8 @@ bedIntervals = bedIntervals bedIntervals = bedIntervals.dump(tag:'bedintervals') +if (params.noIntervals) bedIntervals = Channel.from(file("no_intervals.bed")) + (intBaseRecalibrator, intApplyBQSR, intHaplotypeCaller, intMpileup, bedIntervals) = bedIntervals.into(5) // PREPARING CHANNELS FOR PREPROCESSING AND QC @@ -786,7 +788,8 @@ process MarkDuplicates { publishDir params.outdir, mode: params.publishDirMode, saveAs: { - if (it == "${idSample}.bam.metrics" && 'markduplicates' in skipQC) "Reports/${idSample}/MarkDuplicates/${it}" + if (it == "${idSample}.bam.metrics" && 'markduplicates' in skipQC) null + else if (it == "${idSample}.bam.metrics") "Reports/${idSample}/MarkDuplicates/${it}" else "Preprocessing/${idSample}/DuplicateMarked/${it}" } @@ -819,7 +822,7 @@ if ('markduplicates' in skipQC) markDuplicatesReport.close() duplicateMarkedBams = duplicateMarkedBams.dump(tag:'MD BAM') markDuplicatesReport = markDuplicatesReport.dump(tag:'MD Report') -(bamMD, bamBaseRecalibratorNoInt, bamMDToJoin, bamMDToJoinNoInt) = duplicateMarkedBams.into(4) +(bamMD, bamMDToJoin) = duplicateMarkedBams.into(2) bamBaseRecalibrator = bamMD.combine(intBaseRecalibrator) @@ -831,7 +834,7 @@ process BaseRecalibrator { label 'memory_max' label 'cpus_1' - tag {idPatient + "-" + idSample + "-" + intervalBed} + tag {idPatient + "-" + idSample + "-" + intervalBed.baseName} input: set idPatient, idSample, file(bam), file(bai), file(intervalBed) from bamBaseRecalibrator @@ -844,65 +847,39 @@ process BaseRecalibrator { file(knownIndelsIndex) from ch_knownIndelsIndex output: - set idPatient, idSample, file("${intervalBed.baseName}_${idSample}.recal.table") into tableGatherBQSRReports + set idPatient, idSample, file("${prefix}${idSample}.recal.table") into tableGatherBQSRReports + set idPatient, idSample into recalTableTSVnoInt - when: step == 'mapping' + when: step == 'mapping' && params.knownIndels script: dbsnpOptions = params.dbsnp ? "--known-sites ${dbsnp}" : "" knownOptions = params.knownIndels ? knownIndels.collect{"--known-sites ${it}"}.join(' ') : "" + prefix = params.noIntervals ? "" : "${intervalBed.baseName}_" + intervalsOptions = params.noIntervals ? "" : "-L ${intervalBed}" // TODO: --use-original-qualities ??? """ gatk --java-options -Xmx${task.memory.toGiga()}g \ BaseRecalibrator \ -I ${bam} \ - -O ${intervalBed.baseName}_${idSample}.recal.table \ + -O ${prefix}${idSample}.recal.table \ --tmp-dir /tmp \ -R ${fasta} \ - -L ${intervalBed} \ + ${intervalsOptions} \ ${dbsnpOptions} \ ${knownOptions} \ --verbosity INFO """ } -// STEP 3': CREATING RECALIBRATION TABLES WITHOUT INTERVALS - -process BaseRecalibratorNoIntervals { - label 'memory_max' - label 'cpus_1' - - tag {idPatient + "-" + idSample} - - input: - set idPatient, idSample, file(bam), file(bai) from bamBaseRecalibratorNoInt - file(fasta) from ch_fasta - file(dict) from ch_dict - file(fastaFai) from ch_fastaFai - file(knownIndels) from ch_knownIndels - file(knownIndelsIndex) from ch_knownIndelsIndex +if (!params.noIntervals) tableGatherBQSRReports = tableGatherBQSRReports.groupTuple(by:[0, 1]) - output: - set idPatient, idSample, file("${idSample}.recal.table") into recalNoInt +tableGatherBQSRReports = tableGatherBQSRReports.dump(tag:'BQSR REPORTS') - when: params.noIntervals && step == 'mapping' - - script: - knownOptions = params.knownIndels ? knownIndels.collect{"--known-sites ${it}"}.join(' ') : "" - // TODO: --use-original-qualities ??? - """ - gatk --java-options -Xmx${task.memory.toGiga()}g \ - BaseRecalibrator \ - -I ${bam} \ - -O ${idSample}.recal.table \ - --tmp-dir /tmp \ - -R ${fasta} \ - ${knownOptions} \ - --verbosity INFO - """ -} - -tableGatherBQSRReports = tableGatherBQSRReports.groupTuple(by:[0, 1]) +if (params.noIntervals) { + (tableGatherBQSRReports, tableGatherBQSRReportsNoInt) = tableGatherBQSRReports.into(2) + recalTable = tableGatherBQSRReportsNoInt +} else recalTableTSVnoInt.close() // STEP 3.5: MERGING RECALIBRATION TABLES @@ -919,9 +896,9 @@ process GatherBQSRReports { output: set idPatient, idSample, file("${idSample}.recal.table") into recalTable - set idPatient, idSample, val("${idSample}.md.bam"), val("${idSample}.md.bai"), val("${idSample}.recal.table") into (recalTableTSV, recalTableSampleTSV) + set idPatient, idSample into recalTableTSV - when: step == 'mapping' + when: step == 'mapping' && !(params.noIntervals) script: input = recal.collect{"-I ${it}"}.join(' ') @@ -933,32 +910,44 @@ process GatherBQSRReports { """ } +recalTable = recalTable.dump(tag:'RECAL TABLE') + +(recalTableTSV, recalTableSampleTSV) = recalTableTSV.mix(recalTableTSVnoInt).into(2) + // Create TSV files to restart from this step -recalTableTSV.map { idPatient, idSample, bam, bai, recalTable -> +recalTableTSV.map { idPatient, idSample -> status = statusMap[idPatient, idSample] gender = genderMap[idPatient] - "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bam}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bai}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${recalTable}\n" + bam = "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${idSample}.md.bam" + bai = "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${idSample}.md.bai" + recalTable = "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${idSample}.recal.table" + "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\t${recalTable}\n" }.collectFile( name: 'duplicateMarked.tsv', sort: true, storeDir: "${params.outdir}/Preprocessing/TSV" ) recalTableSampleTSV .collectFile(storeDir: "${params.outdir}/Preprocessing/TSV/") { - idPatient, idSample, bam, bai, recalTable -> + idPatient, idSample -> status = statusMap[idPatient, idSample] gender = genderMap[idPatient] - ["duplicateMarked_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bam}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bai}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${recalTable}\n"] + bam = "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${idSample}.md.bam" + bai = "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${idSample}.md.bai" + recalTable = "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${idSample}.recal.table" + ["duplicateMarked_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\t${recalTable}\n"] } bamApplyBQSR = bamMDToJoin.join(recalTable, by:[0,1]) if (step == 'recalibrate') bamApplyBQSR = inputSample -bamApplyBQSR = bamApplyBQSR.dump(tag:'recal.table') +bamApplyBQSR = bamApplyBQSR.dump(tag:'BAM + BAI + RECAL TABLE') +// [DUMP: recal.table] ['normal', 'normal', normal.md.bam, normal.md.bai, normal.recal.table] bamApplyBQSR = bamApplyBQSR.combine(intApplyBQSR) -bamApplyBQSRnoInt = bamMDToJoinNoInt.join(recalNoInt, by:[0,1]) +bamApplyBQSR = bamApplyBQSR.dump(tag:'BAM + BAI + RECAL TABLE + INT') +// [DUMP: BAM + BAI + RECAL TABLE + INT] ['normal', 'normal', normal.md.bam, normal.md.bai, normal.recal.table, 1_1-200000.bed] // STEP 4: RECALIBRATING @@ -975,56 +964,55 @@ process ApplyBQSR { file(fastaFai) from ch_fastaFai output: - set idPatient, idSample, file("${intervalBed.baseName}_${idSample}.recal.bam") into bamMergeBamRecal + set idPatient, idSample, file("${prefix}${idSample}.recal.bam") into bamMergeBamRecal script: + prefix = params.noIntervals ? "" : "${intervalBed.baseName}_" + intervalsOptions = params.noIntervals ? "" : "-L ${intervalBed}" """ gatk --java-options -Xmx${task.memory.toGiga()}g \ ApplyBQSR \ -R ${fasta} \ --input ${bam} \ - --output ${intervalBed.baseName}_${idSample}.recal.bam \ - -L ${intervalBed} \ + --output ${prefix}${idSample}.recal.bam \ + ${intervalsOptions} \ --bqsr-recal-file ${recalibrationReport} """ } bamMergeBamRecal = bamMergeBamRecal.groupTuple(by:[0, 1]) +(bamMergeBamRecal, bamMergeBamRecalNoInt) = bamMergeBamRecal.into(2) -// STEP 4': RECALIBRATING WITHOUT INTERVALS +// STEP 4.5: MERGING THE RECALIBRATED BAM FILES -process ApplyBQSRnoIntervals { - label 'memory_singleCPU_2_task' - label 'cpus_2' +process MergeBamRecal { + label 'cpus_8' tag {idPatient + "-" + idSample} + publishDir "${params.outdir}/Preprocessing/${idSample}/Recalibrated", mode: params.publishDirMode + input: - set idPatient, idSample, file(bam), file(bai), file(recalibrationReport) from bamApplyBQSRnoInt - file(dict) from ch_dict - file(fasta) from ch_fasta - file(fastaFai) from ch_fastaFai + set idPatient, idSample, file(bam) from bamMergeBamRecal output: - set idPatient, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bai") into bamRecalNoInt + set idPatient, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bai") into bamRecal + set idPatient, idSample, file("${idSample}.recal.bam") into bamRecalQC + set idPatient, idSample into bamRecalTSV + + when: !(params.noIntervals) script: """ - gatk --java-options -Xmx${task.memory.toGiga()}g \ - ApplyBQSR \ - -R ${fasta} \ - --input ${bam} \ - --output ${idSample}.recal.bam \ - --bqsr-recal-file ${recalibrationReport} - + samtools merge --threads ${task.cpus} ${idSample}.recal.bam ${bam} samtools index ${idSample}.recal.bam mv ${idSample}.recal.bam.bai ${idSample}.recal.bai """ } -// STEP 4.5: MERGING THE RECALIBRATED BAM FILES +// STEP 4.5': INDEXING THE RECALIBRATED BAM FILES -process MergeBamRecal { +process IndexBamRecal { label 'cpus_8' tag {idPatient + "-" + idSample} @@ -1032,36 +1020,48 @@ process MergeBamRecal { publishDir "${params.outdir}/Preprocessing/${idSample}/Recalibrated", mode: params.publishDirMode input: - set idPatient, idSample, file(bam) from bamMergeBamRecal + set idPatient, idSample, file("${idSample}.recal.bam") from bamMergeBamRecalNoInt output: - set idPatient, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bai") into bamRecal - set idPatient, idSample, file("${idSample}.recal.bam") into (bamRecalBamQC, bamRecalSamToolsStats) - set idPatient, idSample, val("${idSample}.recal.bam"), val("${idSample}.recal.bai") into (bamRecalTSV, bamRecalSampleTSV) + set idPatient, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bai") into bamRecalNoInt + set idPatient, idSample, file("${idSample}.recal.bam") into bamRecalQCnoInt + set idPatient, idSample into bamRecalTSVnoInt + + when: params.noIntervals script: """ - samtools merge --threads ${task.cpus} ${idSample}.recal.bam ${bam} samtools index ${idSample}.recal.bam mv ${idSample}.recal.bam.bai ${idSample}.recal.bai """ } +bamRecal = bamRecal.mix(bamRecalNoInt) +bamRecalQC = bamRecalQC.mix(bamRecalQCnoInt) +bamRecalTSV = bamRecalTSV.mix(bamRecalTSVnoInt) + +(bamRecalBamQC, bamRecalSamToolsStats) = bamRecalQC.into(2) +(bamRecalTSV, bamRecalSampleTSV) = bamRecalTSV.into(2) + // Creating a TSV file to restart from this step -bamRecalTSV.map { idPatient, idSample, bam, bai -> +bamRecalTSV.map { idPatient, idSample -> gender = genderMap[idPatient] status = statusMap[idPatient, idSample] - "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bam}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bai}\n" + bam = "${params.outdir}/Preprocessing/${idSample}/Recalibrated/${idSample}.recal.bam" + bai = "${params.outdir}/Preprocessing/${idSample}/Recalibrated/${idSample}.recal.bai" + "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\n" }.collectFile( name: 'recalibrated.tsv', sort: true, storeDir: "${params.outdir}/Preprocessing/TSV" ) bamRecalSampleTSV .collectFile(storeDir: "${params.outdir}/Preprocessing/TSV") { - idPatient, idSample, bam, bai -> + idPatient, idSample -> status = statusMap[idPatient, idSample] gender = genderMap[idPatient] - ["recalibrated_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bam}\t${params.outdir}/Preprocessing/${idSample}/Recalibrated/${bai}\n"] + bam = "${params.outdir}/Preprocessing/${idSample}/Recalibrated/${idSample}.recal.bam" + bai = "${params.outdir}/Preprocessing/${idSample}/Recalibrated/${idSample}.recal.bai" + ["recalibrated_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\n"] } // STEP 5: QC @@ -1133,7 +1133,7 @@ bamQCReport = bamQCReport.dump(tag:'BamQC') ================================================================================ */ -bamRecal = params.knownIndels ? bamRecal.mix(bamRecalNoInt) : indexedBam +bamRecal = params.knownIndels ? bamRecal : indexedBam if (step == 'variantcalling') bamRecal = inputSample @@ -1960,7 +1960,7 @@ process Ascat { ascatOut.dump(tag:'ASCAT') -// STEP CONTROLFREEC.1 - MPILEUP +// STEP MPILEUP.1 process Mpileup { label 'memory_singleCPU_2_task' @@ -1973,45 +1973,30 @@ process Mpileup { file(fastaFai) from ch_fastaFai output: - set idPatient, idSample, file("${intervalBed.baseName}_${idSample}.pileup.gz") into mpileupMerge + set idPatient, idSample, file("${prefix}${idSample}.pileup.gz") into mpileupMerge when: 'controlfreec' in tools || 'mpileup' in tools script: + prefix = params.noIntervals ? "" : "${intervalBed.baseName}_" + intervalsOptions = params.noIntervals ? "" : "-l ${intervalBed}" """ samtools mpileup \ -f ${fasta} ${bam} \ - -l ${intervalBed} \ - | bgzip --threads ${task.cpus} -c > ${intervalBed.baseName}_${idSample}.pileup.gz + ${intervalsOptions} \ + | bgzip --threads ${task.cpus} -c > ${prefix}${idSample}.pileup.gz """ } -mpileupMerge = mpileupMerge.groupTuple(by:[0, 1]) - -process MpileupNoIntervals { - label 'memory_singleCPU_2_task' - - tag {idSample} - - input: - set idPatient, idSample, file(bam), file(bai) from bamMpileupNoInt - file(fasta) from ch_fasta - file(fastaFai) from ch_fastaFai - - output: - set idPatient, idSample, file("${idSample}.pileup.gz") into mpileupNoIntOut - - when: params.noIntervals && 'mpileup' in tools - - script: - """ - samtools mpileup \ - -f ${fasta} ${bam} \ - | bgzip --threads ${task.cpus} -c > ${idSample}.pileup.gz - """ +if (!params.noIntervals) { + mpileupMerge = mpileupMerge.groupTuple(by:[0, 1]) + mpileupNoInt = Channel.empty() +} else { + (mpileupMerge, mpileupNoInt) = mpileupMerge.into(2) + mpileupMerge.close() } -// STEP CONTROLFREEC.2 - MERGE MPILEUP +// STEP MPILEUP.2 - MERGE process MergeMpileup { tag {idSample} @@ -2024,7 +2009,7 @@ process MergeMpileup { output: set idPatient, idSample, file("${idSample}.pileup.gz") into mpileupOut - when: 'controlfreec' in tools || 'mpileup' in tools + when: !(params.noIntervals) && 'controlfreec' in tools || 'mpileup' in tools script: """ @@ -2038,6 +2023,7 @@ process MergeMpileup { """ } +mpileupOut = mpileupOut.mix(mpileupNoInt) mpileupOut = mpileupOut.dump(tag:'mpileup') mpileupOutNormal = Channel.create() @@ -2054,7 +2040,7 @@ mpileupOut = mpileupOut.map { [idPatientNormal, idSampleNormal, idSampleTumor, mpileupOutNormal, mpileupOutTumor] } -// STEP CONTROLFREEC.3 - CONTROLFREEC +// STEP CONTROLFREEC.1 - CONTROLFREEC process ControlFREEC { label 'memory_singleCPU_2_task' From 4b7d1ffef54688310512591264df136620abac1e Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 4 Nov 2019 16:14:11 +0100 Subject: [PATCH 190/854] add comments --- main.nf | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/main.nf b/main.nf index 457b993b65..b2345649af 100644 --- a/main.nf +++ b/main.nf @@ -73,18 +73,21 @@ def helpMessage() { If none provided, will be generated automatically --dbsnp dbsnp file --dbsnpIndex dbsnp index - If none provided, will be generated automatically + If none provided, will be generated automatically if a dbsnp file is provided --dict dict from the fasta reference If none provided, will be generated automatically --fasta fasta reference --fastafai reference index If none provided, will be generated automatically + --germlineResource Germline Resource File + --germlineResourceIndex Germline Resource Index + If none provided, will be generated automatically if a germlineResource file is provided --intervals intervals If none provided, will be generated automatically Use --noIntervals to disable automatic generation --knownIndels knownIndels file --knownIndelsIndex knownIndels index - If none provided, will be generated automatically + If none provided, will be generated automatically if a knownIndels file is provided --snpeffDb snpeffDb version --vepCacheVersion VEP Cache version From f1cdd93e75da91d04fecb96a4806e1e422c4dfa5 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 4 Nov 2019 16:25:31 +0100 Subject: [PATCH 191/854] params noIntervals -> no_intervals --- main.nf | 58 ++++++++++++++++++++++++++----------------------- nextflow.config | 2 +- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/main.nf b/main.nf index a9387c0b79..ba1afa1e84 100644 --- a/main.nf +++ b/main.nf @@ -43,7 +43,7 @@ def helpMessage() { --genome Name of iGenomes reference --noGVCF No g.vcf output from HaplotypeCaller --noStrelkaBP Will not use Manta candidateSmallIndels for Strelka as Best Practice - --noIntervals Disable usage of intervals + --no_intervals Disable usage of intervals --nucleotidesPerSecond To estimate interval size Default: 1000.0 --targetBED Target BED file for targeted or whole exome sequencing @@ -70,24 +70,25 @@ def helpMessage() { --acLoci acLoci file --acLociGC acLoci GC file --bwaIndex bwa indexes - If none provided, will be generated automatically + If none provided, will be generated automatically from the fasta reference --dbsnp dbsnp file --dbsnpIndex dbsnp index If none provided, will be generated automatically if a dbsnp file is provided --dict dict from the fasta reference - If none provided, will be generated automatically + If none provided, will be generated automatically from the fasta reference --fasta fasta reference --fastafai reference index - If none provided, will be generated automatically + If none provided, will be generated automatically from the fasta reference --germlineResource Germline Resource File --germlineResourceIndex Germline Resource Index If none provided, will be generated automatically if a germlineResource file is provided --intervals intervals - If none provided, will be generated automatically - Use --noIntervals to disable automatic generation + If none provided, will be generated automatically from the fasta reference + Use --no_intervals to disable automatic generation --knownIndels knownIndels file --knownIndelsIndex knownIndels index If none provided, will be generated automatically if a knownIndels file is provided + --species species for VEP --snpeffDb snpeffDb version --vepCacheVersion VEP Cache version @@ -168,6 +169,7 @@ params.intervals = params.genome && !('annotate' in step) ? params.genomes[param params.knownIndels = params.genome && 'mapping' in step ? params.genomes[params.genome].knownIndels ?: null : null params.knownIndelsIndex = params.genome && params.knownIndels ? params.genomes[params.genome].knownIndelsIndex ?: null : null params.snpeffDb = params.genome && 'snpeff' in tools ? params.genomes[params.genome].snpeffDb ?: null : null +params.species = params.genome && 'vep' in tools ? params.genomes[params.genome].species ?: null : null params.vepCacheVersion = params.genome && 'vep' in tools ? params.genomes[params.genome].vepCacheVersion ?: null : null // Handle deprecation @@ -285,10 +287,11 @@ if (params.step) summary['Step'] = params.step if (params.tools) summary['Tools'] = tools.join(', ') if (params.skipQC) summary['QC tools skip'] = skipQC.join(', ') -if ('haplotypecaller' in tools) summary['GVCF'] = params.noGVCF ? 'No' : 'Yes' -if ('strelka' in tools && 'manta' in tools ) summary['Strelka BP'] = params.noStrelkaBP ? 'No' : 'Yes' -if (params.sequencing_center) summary['Sequenced by'] = params.sequencing_center -if (params.pon && 'mutect2' in tools) summary['Panel of normals'] = params.pon +if (params.no_intervals && step != 'annotate') summary['Intervals'] = 'Do not use' +if ('haplotypecaller' in tools) summary['GVCF'] = params.noGVCF ? 'No' : 'Yes' +if ('strelka' in tools && 'manta' in tools ) summary['Strelka BP'] = params.noStrelkaBP ? 'No' : 'Yes' +if (params.sequencing_center) summary['Sequenced by'] = params.sequencing_center +if (params.pon && 'mutect2' in tools) summary['Panel of normals'] = params.pon summary['Save Genome Index'] = params.saveGenomeIndex ? 'Yes' : 'No' summary['Nucleotides/s'] = params.nucleotidesPerSecond @@ -315,6 +318,7 @@ if (params.dbsnpIndex) summary['dbsnpIndex'] = params.dbsn if (params.knownIndels) summary['knownIndels'] = params.knownIndels if (params.knownIndelsIndex) summary['knownIndelsIndex'] = params.knownIndelsIndex if (params.snpeffDb) summary['snpeffDb'] = params.snpeffDb +if (params.species) summary['species'] = params.species if (params.vepCacheVersion) summary['vepCacheVersion'] = params.vepCacheVersion if (workflow.profile == 'awsbatch') { @@ -529,7 +533,7 @@ process BuildIntervals { output: file("${fastaFai.baseName}.bed") into intervalBuilt - when: !(params.intervals) && !('annotate' in step) && !(params.noIntervals) + when: !(params.intervals) && !('annotate' in step) && !(params.no_intervals) script: """ @@ -537,7 +541,7 @@ process BuildIntervals { """ } -ch_intervals = params.noIntervals ? "null" : params.intervals && !('annotate' in step) ? Channel.value(file(params.intervals)) : intervalBuilt +ch_intervals = params.no_intervals ? "null" : params.intervals && !('annotate' in step) ? Channel.value(file(params.intervals)) : intervalBuilt /* ================================================================================ @@ -556,7 +560,7 @@ process CreateIntervalBeds { output: file '*.bed' into bedIntervals mode flatten - when: (!params.noIntervals) && step != 'annotate' + when: (!params.no_intervals) && step != 'annotate' script: // If the interval file is BED format, the fifth column is interpreted to @@ -616,7 +620,7 @@ bedIntervals = bedIntervals bedIntervals = bedIntervals.dump(tag:'bedintervals') -if (params.noIntervals) bedIntervals = Channel.from(file("no_intervals.bed")) +if (params.no_intervals && step != 'annotate') bedIntervals = Channel.from(file("no_intervals.bed")) (intBaseRecalibrator, intApplyBQSR, intHaplotypeCaller, intMpileup, bedIntervals) = bedIntervals.into(5) @@ -865,8 +869,8 @@ process BaseRecalibrator { script: dbsnpOptions = params.dbsnp ? "--known-sites ${dbsnp}" : "" knownOptions = params.knownIndels ? knownIndels.collect{"--known-sites ${it}"}.join(' ') : "" - prefix = params.noIntervals ? "" : "${intervalBed.baseName}_" - intervalsOptions = params.noIntervals ? "" : "-L ${intervalBed}" + prefix = params.no_intervals ? "" : "${intervalBed.baseName}_" + intervalsOptions = params.no_intervals ? "" : "-L ${intervalBed}" // TODO: --use-original-qualities ??? """ gatk --java-options -Xmx${task.memory.toGiga()}g \ @@ -882,11 +886,11 @@ process BaseRecalibrator { """ } -if (!params.noIntervals) tableGatherBQSRReports = tableGatherBQSRReports.groupTuple(by:[0, 1]) +if (!params.no_intervals) tableGatherBQSRReports = tableGatherBQSRReports.groupTuple(by:[0, 1]) tableGatherBQSRReports = tableGatherBQSRReports.dump(tag:'BQSR REPORTS') -if (params.noIntervals) { +if (params.no_intervals) { (tableGatherBQSRReports, tableGatherBQSRReportsNoInt) = tableGatherBQSRReports.into(2) recalTable = tableGatherBQSRReportsNoInt } else recalTableTSVnoInt.close() @@ -908,7 +912,7 @@ process GatherBQSRReports { set idPatient, idSample, file("${idSample}.recal.table") into recalTable set idPatient, idSample into recalTableTSV - when: step == 'mapping' && !(params.noIntervals) + when: step == 'mapping' && !(params.no_intervals) script: input = recal.collect{"-I ${it}"}.join(' ') @@ -977,8 +981,8 @@ process ApplyBQSR { set idPatient, idSample, file("${prefix}${idSample}.recal.bam") into bamMergeBamRecal script: - prefix = params.noIntervals ? "" : "${intervalBed.baseName}_" - intervalsOptions = params.noIntervals ? "" : "-L ${intervalBed}" + prefix = params.no_intervals ? "" : "${intervalBed.baseName}_" + intervalsOptions = params.no_intervals ? "" : "-L ${intervalBed}" """ gatk --java-options -Xmx${task.memory.toGiga()}g \ ApplyBQSR \ @@ -1010,7 +1014,7 @@ process MergeBamRecal { set idPatient, idSample, file("${idSample}.recal.bam") into bamRecalQC set idPatient, idSample into bamRecalTSV - when: !(params.noIntervals) + when: !(params.no_intervals) script: """ @@ -1037,7 +1041,7 @@ process IndexBamRecal { set idPatient, idSample, file("${idSample}.recal.bam") into bamRecalQCnoInt set idPatient, idSample into bamRecalTSVnoInt - when: params.noIntervals + when: params.no_intervals script: """ @@ -1988,8 +1992,8 @@ process Mpileup { when: 'controlfreec' in tools || 'mpileup' in tools script: - prefix = params.noIntervals ? "" : "${intervalBed.baseName}_" - intervalsOptions = params.noIntervals ? "" : "-l ${intervalBed}" + prefix = params.no_intervals ? "" : "${intervalBed.baseName}_" + intervalsOptions = params.no_intervals ? "" : "-l ${intervalBed}" """ samtools mpileup \ -f ${fasta} ${bam} \ @@ -1998,7 +2002,7 @@ process Mpileup { """ } -if (!params.noIntervals) { +if (!params.no_intervals) { mpileupMerge = mpileupMerge.groupTuple(by:[0, 1]) mpileupNoInt = Channel.empty() } else { @@ -2019,7 +2023,7 @@ process MergeMpileup { output: set idPatient, idSample, file("${idSample}.pileup.gz") into mpileupOut - when: !(params.noIntervals) && 'controlfreec' in tools || 'mpileup' in tools + when: !(params.no_intervals) && 'controlfreec' in tools || 'mpileup' in tools script: """ diff --git a/nextflow.config b/nextflow.config index d4d5355c9c..4c18796b63 100644 --- a/nextflow.config +++ b/nextflow.config @@ -14,7 +14,7 @@ params { input = null // No default input noGVCF = null // g.vcf are produced by HaplotypeCaller noStrelkaBP = null // Strelka will use Manta candidateSmallIndels if available - noIntervals = null // Intervals will be built from the fastaFai file + no_intervals = null // Intervals will be built from the fasta file skipQC = null // All QC tools are used step = 'mapping' // Starts with mapping tools = null // No default Variant Calling or Annotation tools From daca2ba7213f1eceeb05c1f9d35dd56a9159c792 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 4 Nov 2019 16:56:43 +0100 Subject: [PATCH 192/854] sort genomes + add news --- conf/genomes.config | 10 ++- conf/igenomes.config | 142 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 143 insertions(+), 9 deletions(-) diff --git a/conf/genomes.config b/conf/genomes.config index 12993d52e1..acc6137506 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -26,8 +26,8 @@ params { knownIndels = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf" knownIndelsIndex = "${params.genomes_base}/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" snpeffDb = 'GRCh37.75' - vepCacheVersion = '95' species = 'homo_sapiens' + vepCacheVersion = '95' } 'GRCh38' { acLoci = "${params.genomes_base}/1000G_phase3_GRCh38_maf0.3.loci" @@ -46,20 +46,18 @@ params { knownIndels = "${params.genomes_base}/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" knownIndelsIndex = "${params.genomes_base}/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" snpeffDb = 'GRCh38.86' - vepCacheVersion = '95' species = 'homo_sapiens' + vepCacheVersion = '95' } 'smallGRCh37' { - acLoci = "${params.genomes_base}/1000G_phase3_20130502_SNP_maf0.3.small.loci" - acLociGC = "${params.genomes_base}/1000G_phase3_20130502_SNP_maf0.3.small.loci.gc" dbsnp = "${params.genomes_base}/dbsnp_138.b37.small.vcf.gz" fasta = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" germlineResource = "${params.genomes_base}/dbsnp_138.b37.small.vcf.gz" intervals = "${params.genomes_base}/small.intervals" knownIndels = ["${params.genomes_base}/1000G_phase1.indels.b37.small.vcf.gz", "${params.genomes_base}/Mills_and_1000G_gold_standard.indels.b37.small.vcf.gz"] snpeffDb = 'GRCh37.75' - vepCacheVersion = '95' species = 'homo_sapiens' + vepCacheVersion = '95' } 'GRCm38' { bwaIndex = "${params.genomes_base}/genome.fa.{amb,ann,bwt,pac,sa}" @@ -74,8 +72,8 @@ params { knownIndels = "${params.genomes_base}/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz" knownIndelsIndex = "${params.genomes_base}/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz.tbi" snpeffDb = 'GRCm38.86' - vepCacheVersion = '98' species = 'mus_musculus' + vepCacheVersion = '98' } 'smallerGRCh37' { fasta = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" diff --git a/conf/igenomes.config b/conf/igenomes.config index b06dffac39..0dc0f857a0 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -26,8 +26,8 @@ params { knownIndels = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf" knownIndelsIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh37/Annotation/GATKBundle/{1000G_phase1,Mills_and_1000G_gold_standard}.indels.b37.vcf.idx" snpeffDb = 'GRCh37.75' - vepCacheVersion = '95' species = 'homo_sapiens' + vepCacheVersion = '95' } 'GRCh38' { acLoci = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/ASCAT/1000G_phase3_GRCh38_maf0.3.loci" @@ -46,8 +46,8 @@ params { knownIndels = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz" knownIndelsIndex = "${params.igenomes_base}/Homo_sapiens/GATK/GRCh38/Annotation/GATKBundle/{Mills_and_1000G_gold_standard.indels.hg38,beta/Homo_sapiens_assembly38.known_indels}.vcf.gz.tbi" snpeffDb = 'GRCh38.86' - vepCacheVersion = '95' species = 'homo_sapiens' + vepCacheVersion = '95' } 'GRCm38' { bwaIndex = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" @@ -62,8 +62,144 @@ params { knownIndels = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz" knownIndelsIndex = "${params.igenomes_base}/Mus_musculus/Annotation/MouseGenomeProject/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz.tbi" snpeffDb = 'GRCm38.86' - vepCacheVersion = '98' species = 'mus_musculus' + vepCacheVersion = '98' + } + 'TAIR10' { + bwaIndex = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/WholeGenomeFasta/genome.fa" + } + 'EB2' { + bwaIndex = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/WholeGenomeFasta/genome.fa" + } + 'UMD3.1' { + bwaIndex = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/WholeGenomeFasta/genome.fa" + } + 'WBcel235' { + bwaIndex = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/WholeGenomeFasta/genome.fa" + } + 'CanFam3.1' { + bwaIndex = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/WholeGenomeFasta/genome.fa" + } + 'GRCz10' { + bwaIndex = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/WholeGenomeFasta/genome.fa" + } + 'BDGP6' { + bwaIndex = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/WholeGenomeFasta/genome.fa" + } + 'EquCab2' { + bwaIndex = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/WholeGenomeFasta/genome.fa" + } + 'EB1' { + bwaIndex = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/WholeGenomeFasta/genome.fa" + } + 'Galgal4' { + bwaIndex = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/WholeGenomeFasta/genome.fa" + } + 'Gm01' { + bwaIndex = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/WholeGenomeFasta/genome.fa" + } + 'Mmul_1' { + bwaIndex = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/WholeGenomeFasta/genome.fa" + } + 'IRGSP-1.0' { + bwaIndex = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/WholeGenomeFasta/genome.fa" + } + 'CHIMP2.1.4' { + bwaIndex = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/WholeGenomeFasta/genome.fa" + } + 'Rnor_6.0' { + bwaIndex = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/WholeGenomeFasta/genome.fa" + } + 'R64-1-1' { + bwaIndex = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/WholeGenomeFasta/genome.fa" + } + 'EF2' { + bwaIndex = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/WholeGenomeFasta/genome.fa" + } + 'Sbi1' { + bwaIndex = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/WholeGenomeFasta/genome.fa" + } + 'Sscrofa10.2' { + bwaIndex = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/WholeGenomeFasta/genome.fa" + } + 'AGPv3' { + bwaIndex = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/WholeGenomeFasta/genome.fa" + } + 'hg38' { + bwaIndex = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/WholeGenomeFasta/genome.fa" + } + 'hg19' { + bwaIndex = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/WholeGenomeFasta/genome.fa" + } + 'mm10' { + bwaIndex = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/WholeGenomeFasta/genome.fa" + } + 'bosTau8' { + bwaIndex = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/WholeGenomeFasta/genome.fa" + } + 'ce10' { + bwaIndex = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/WholeGenomeFasta/genome.fa" + } + 'canFam3' { + bwaIndex = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/WholeGenomeFasta/genome.fa" + } + 'danRer10' { + bwaIndex = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/WholeGenomeFasta/genome.fa" + } + 'dm6' { + bwaIndex = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/WholeGenomeFasta/genome.fa" + } + 'equCab2' { + bwaIndex = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/WholeGenomeFasta/genome.fa" + } + 'galGal4' { + bwaIndex = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/WholeGenomeFasta/genome.fa" + } + 'panTro4' { + bwaIndex = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/WholeGenomeFasta/genome.fa" + } + 'rn6' { + bwaIndex = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/WholeGenomeFasta/genome.fa" + } + 'sacCer3' { + bwaIndex = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/WholeGenomeFasta/genome.fa" + } + 'susScr3' { + bwaIndex = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/WholeGenomeFasta/genome.fa" } } } From 3fce99c6b3b9081c646f3b464d5df9f79f119dff Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 4 Nov 2019 17:08:04 +0100 Subject: [PATCH 193/854] code polishing --- scripts/run_tests.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index eb02a84d18..1f61b81207 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -84,7 +84,7 @@ else SUFFIX="" fi -OPTIONS="--tools FreeBayes,HaplotypeCaller,Manta,mpileup,Mutect2,Strelka" +OPTIONS="--tools FreeBayes,HaplotypeCaller,Manta,Mpileup,Mutect2,Strelka" if [[ $TEST == "GERMLINE" ]] && [[ $OFFLINE == false ]] then @@ -117,13 +117,13 @@ case $TEST in run_sarek --tools HaplotypeCaller --input results/Preprocessing/TSV/recalibrated.tsv --step variantCalling ;; MINIMAL) - run_sarek --tools manta,mpileup,strelka --input ${PATHTOSAMPLE}/tsv/tiny-manta-normal${SUFFIX}.tsv --genome smallerGRCh37 - run_sarek --tools manta,mpileup,strelka --input ${PATHTOSAMPLE}/tsv/tiny-manta-normal${SUFFIX}.tsv --genome smallerGRCh37 --noIntervals -resume - run_sarek --tools manta,mpileup,strelka --input ${PATHTOSAMPLE}/tsv/tiny-manta-normal${SUFFIX}.tsv --genome minimalGRCh37 -resume - run_sarek --tools manta,mpileup,strelka --input ${PATHTOSAMPLE}/tsv/tiny-manta-normal${SUFFIX}.tsv --genome minimalGRCh37 --noIntervals -resume + run_sarek --tools manta,Mpileup,strelka --input ${PATHTOSAMPLE}/tsv/tiny-manta-normal${SUFFIX}.tsv --genome smallerGRCh37 + run_sarek --tools manta,Mpileup,strelka --input ${PATHTOSAMPLE}/tsv/tiny-manta-normal${SUFFIX}.tsv --genome smallerGRCh37 --noIntervals -resume + run_sarek --tools manta,Mpileup,strelka --input ${PATHTOSAMPLE}/tsv/tiny-manta-normal${SUFFIX}.tsv --genome minimalGRCh37 -resume + run_sarek --tools manta,Mpileup,strelka --input ${PATHTOSAMPLE}/tsv/tiny-manta-normal${SUFFIX}.tsv --genome minimalGRCh37 --noIntervals -resume ;; MULTIPLE) - run_sarek --tools FreeBayes,HaplotypeCaller,Manta,mpileup,Strelka,snpEff,VEP,merge --input ${PATHTOSAMPLE}/tsv/tiny-multiple${SUFFIX}.tsv + run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Mpileup,Strelka,snpEff,VEP,merge --input ${PATHTOSAMPLE}/tsv/tiny-multiple${SUFFIX}.tsv ;; SOMATIC) run_sarek ${OPTIONS} --input ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv From 7adfe02a64eda25f3b9b7774d525f2c11bc74784 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 4 Nov 2019 17:08:11 +0100 Subject: [PATCH 194/854] update CHANGELOG --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7238d184b1..037e85c3f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [#46](https://github.com/nf-core/sarek/pull/46) - Add location to abstacts - [#52](https://github.com/nf-core/sarek/pull/52) - Add support for mouse data `GRCm38` +- [#60](https://github.com/nf-core/sarek/pull/60) - Add `no_intervals` params +- [#60](https://github.com/nf-core/sarek/pull/60) - Add automatic generation of `intervals` file with `BuildIntervals` process +- [#60](https://github.com/nf-core/sarek/pull/60) - Add minimal support for minimal genome (only `fasta`, or `fasta` + `knownIndels`) +- [#60](https://github.com/nf-core/sarek/pull/60) - Add new processes (`IndexBamFile`, `IndexBamRecal`) to deal with optional usage of interval files and minimal genome +- [#60](https://github.com/nf-core/sarek/pull/60) - Add tests for minimal genome usage +- [#60](https://github.com/nf-core/sarek/pull/60) - Add new minimal genomes (`AGPv3`, `BDGP6`, `CHIMP2.1.4`, `CanFam3.1`, `EB1`, `EB2`, `EF2`, `EquCab2`, `GRCz10`, `Galgal4`, `Gm01`, `IRGSP-1.0`, `Mmul_1`, `R64-1-1`, `Rnor_6.0`, `Sbi1`, `Sscrofa10.2`, `TAIR10`, `UMD3.1`, `WBcel235`, `bosTau8`, `canFam3`, `ce10`, `danRer10`, `dm6`, `equCab2`, `galGal4`, `hg19`, `hg38`, `mm10`, `panTro4`, `rn6`, `sacCer3`, `susScr3`) to `igenomes.config` ### `Changed` @@ -23,6 +29,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [#41](https://github.com/nf-core/sarek/pull/41), [#55](https://github.com/nf-core/sarek/pull/55) - Update `tiddit` from `2.7.1` to `2.8.1` - [#41](https://github.com/nf-core/sarek/pull/41) - Update `vcfanno` from `0.3.1` to `0.3.2` - [#54](https://github.com/nf-core/sarek/pull/54) - Bump version to `2.5.2dev` +- [#60](https://github.com/nf-core/sarek/pull/60) - Some process (`BaseRecalibrator`, `ApplyBQSR`, `Mpileup`) have now optional usage of interval files +- [#60](https://github.com/nf-core/sarek/pull/60) - Update documentation ### `Removed` From 0401b894f459b873503ce6bf4d5c7550bf09f04f Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 14:08:49 +0100 Subject: [PATCH 195/854] add split_fastq params to split the fastq files with the splitFastq() nf method --- main.nf | 39 ++++++++++++++++++++++++++++++--------- nextflow.config | 1 + 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/main.nf b/main.nf index 204f315b4d..84fe76fe79 100644 --- a/main.nf +++ b/main.nf @@ -575,21 +575,40 @@ bedIntervals = bedIntervals.dump(tag:'bedintervals') // PREPARING CHANNELS FOR PREPROCESSING AND QC -if (step == 'mapping') (inputReads, inputReadsFastQC) = inputSample.into(2) -else (inputReads, inputReadsFastQC) = Channel.empty().into(2) +inputPairReads = Channel.create() +inputBam = Channel.create() -inputPairReadsFastQC = Channel.create() -inputBAMFastQC = Channel.create() +inputSample.choice(inputPairReads, inputBam) {hasExtension(it[3], "bam") ? 1 : 0} -inputReadsFastQC.choice(inputPairReadsFastQC, inputBAMFastQC) {hasExtension(it[3], "bam") ? 1 : 0} +(inputBam, inputBamFastQC) = inputBam.into(2) // Removing inputFile2 wich is null in case of uBAM -inputBAMFastQC = inputBAMFastQC.map { +inputBamFastQC = inputBamFastQC.map { idPatient, idSample, idRun, inputFile1, inputFile2 -> [idPatient, idSample, idRun, inputFile1] } -inputReads = inputReads.dump(tag:'INPUT') +if (params.split_fastq){ + inputPairReads = inputPairReads + // newly splitfastq are named based on split, so the name is easier to catch + .splitFastq(by: params.split_fastq, compress:true, file:"split", pe:true) + .map {idPatient, idSample, idRun, reads1, reads2 -> + // The split fastq read1 is the 4th element (indexed 3) its name is split_3 + // The split fastq read2's name is split_4 + // It's followed by which split it's acutally based on the mother fastq file + // Index start at 1 + // Extracting the index to get a new IdRun + splitIndex = reads1.fileName.toString().minus("split_3.").minus(".gz") + newIdRun = idRun + "_" + splitIndex + // Giving the files a new nice name + newReads1 = file("${idSample}_${newIdRun}_R1.fastq.gz") + newReads2 = file("${idSample}_${newIdRun}_R2.fastq.gz") + [idPatient, idSample, newIdRun, reads1, reads2]} +} + +inputPairReads = inputPairReads.dump(tag:'INPUT') + +(inputPairReads, inputPairReadsFastQC) = inputPairReads.into(2) // STEP 0.5: QC ON READS @@ -625,7 +644,7 @@ process FastQCBAM { publishDir "${params.outdir}/Reports/${idSample}/FastQC/${idSample}_${idRun}", mode: params.publishDirMode input: - set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam") from inputBAMFastQC + set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam") from inputBamFastQC output: file("*.{html,zip}") into fastQCBAMReport @@ -644,6 +663,8 @@ fastQCReport = fastQCReport.dump(tag:'FastQC') // STEP 1: MAPPING READS TO REFERENCE GENOME WITH BWA MEM +inputReads = inputPairReads.mix(inputBam) + process MapReads { label 'cpus_max' @@ -656,7 +677,7 @@ process MapReads { output: set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam") into bamMapped - set idPatient, idSample, file("${idSample}_${idRun}.bam") into bamMappedBamQC + set idPatient, val("${idSample}_${idRun}"), file("${idSample}_${idRun}.bam") into bamMappedBamQC when: step == 'mapping' diff --git a/nextflow.config b/nextflow.config index 4632a988a6..d5ef7098be 100644 --- a/nextflow.config +++ b/nextflow.config @@ -24,6 +24,7 @@ params { genesplicer = null // genesplicer disabled markdup_java_options = '"-Xms4000m -Xmx7g"' //Established values for markDuplicate memory consumption, see https://github.com/SciLifeLab/Sarek/pull/689 for details nucleotidesPerSecond = 1000.0 // Default interval size + split_fastq = null // Fastq files will not be split by default outdir = './results' publishDirMode = 'copy' // Default PublishDirMode (same as other nf-core pipelines) saveGenomeIndex = null // Built Indexes not saved From bab56042662f984e614bfec42a3811f4f8201bf0 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 14:33:47 +0100 Subject: [PATCH 196/854] add tests --- .github/workflows/ci-extra.yml | 2 +- scripts/run_tests.sh | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-extra.yml b/.github/workflows/ci-extra.yml index d37a33aae0..aae78639a2 100644 --- a/.github/workflows/ci-extra.yml +++ b/.github/workflows/ci-extra.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - test: [ANNOTATESNPEFF, GERMLINE, SOMATIC, TARGETED] + test: [ANNOTATESNPEFF, GERMLINE, SOMATIC, SPLITFASTQ, TARGETED] nxf_ver: ['19.04.0', ''] steps: - uses: actions/checkout@v1 diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index cb6db88901..1057692a41 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -122,6 +122,9 @@ case $TEST in SOMATIC) run_sarek ${OPTIONS} --input ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv ;; + SPLITFASTQ) + run_sarek ${OPTIONS} --input ${PATHTOSAMPLE}/tsv/tiny-manta-normal${SUFFIX}.tsv --split_fastq 500 + ;; TARGETED) run_sarek ${OPTIONS} --input ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv --targetBED ${PATHTOSAMPLE}/target.bed ;; From cbd81569a5e8dc0747ce7671eed7de14c8f21077 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 14:38:19 +0100 Subject: [PATCH 197/854] temporarely remove TIDDIT tests --- scripts/run_tests.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index 1057692a41..e350e7f60c 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -84,7 +84,7 @@ else SUFFIX="" fi -OPTIONS="--tools FreeBayes,HaplotypeCaller,Manta,Mutect2,Strelka,TIDDIT" +OPTIONS="--tools FreeBayes,HaplotypeCaller,Manta,Mutect2,Strelka" if [[ $TEST == "GERMLINE" ]] && [[ $OFFLINE == false ]] then @@ -117,7 +117,7 @@ case $TEST in run_sarek --tools HaplotypeCaller --input results/Preprocessing/TSV/recalibrated.tsv --step variantCalling ;; MULTIPLE) - run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,TIDDIT,snpEff,VEP,merge --input ${PATHTOSAMPLE}/tsv/tiny-multiple${SUFFIX}.tsv + run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,snpEff,VEP,merge --input ${PATHTOSAMPLE}/tsv/tiny-multiple${SUFFIX}.tsv ;; SOMATIC) run_sarek ${OPTIONS} --input ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv From f3312d95b0e89791560d34dfcfae14471ba1debf Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 14:58:23 +0100 Subject: [PATCH 198/854] add sention for bwa mem --- conf/base.config | 3 +++ main.nf | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/conf/base.config b/conf/base.config index 5c76d275e6..65190bff68 100644 --- a/conf/base.config +++ b/conf/base.config @@ -75,4 +75,7 @@ process { container = {(params.annotation_cache && params.vep_cache) ? 'nfcore/sarek:dev' : "nfcore/sarekvep:dev.${params.genome}"} errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} } + withLabel:sentieon { + beforeScript = {params.sentieon ? 'module load sentieon/201808.05 samtools/1.9' : ''} + } } diff --git a/main.nf b/main.nf index 052b7fb26b..778547fdc5 100644 --- a/main.nf +++ b/main.nf @@ -653,6 +653,7 @@ fastQCReport = fastQCReport.dump(tag:'FastQC') process MapReads { label 'cpus_max' + label 'sentieon' tag {idPatient + "-" + idRun} @@ -680,12 +681,19 @@ process MapReads { extra = status == 1 ? "-B 3" : "" convertToFastq = hasExtension(inputFile1, "bam") ? "gatk --java-options -Xmx${task.memory.toGiga()}g SamToFastq --INPUT=${inputFile1} --FASTQ=/dev/stdout --INTERLEAVE=true --NON_PF=true | \\" : "" input = hasExtension(inputFile1, "bam") ? "-p /dev/stdin - 2> >(tee ${inputFile1}.bwa.stderr.log >&2)" : "${inputFile1} ${inputFile2}" + if (!params.sentieon) """ ${convertToFastq} bwa mem -K 100000000 -R \"${readGroup}\" ${extra} -t ${task.cpus} -M ${fasta} \ ${input} | \ samtools sort --threads ${task.cpus} -m 2G - > ${idSample}_${idRun}.bam """ + else + """ + sentieon bwa mem -K 100000000 -R \"${readGroup}\" -t ${task.cpus} -M ${fasta} \ + ${input} | \ + sentieon util sort -r ${fasta} -o ${idSample}_${idRun}.sorted.bam -t ${task.cpus} --sam2bam -i - + """ } bamMapped = bamMapped.dump(tag:'Mapped BAM') From 9f085337c0c71bf43522f9fbacdb37142718a7e8 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 15:05:29 +0100 Subject: [PATCH 199/854] disable docker and singularity --- conf/base.config | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conf/base.config b/conf/base.config index 65190bff68..52c511593f 100644 --- a/conf/base.config +++ b/conf/base.config @@ -77,5 +77,7 @@ process { } withLabel:sentieon { beforeScript = {params.sentieon ? 'module load sentieon/201808.05 samtools/1.9' : ''} + docker.enabled = {params.sentieon ? false : false} + singularity.enabled = {params.sentieon ? false : false} } } From 477a99f6a5d1f03d7db4ee2322531e43cbeaabf7 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 15:07:58 +0100 Subject: [PATCH 200/854] disable container --- conf/base.config | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/conf/base.config b/conf/base.config index 52c511593f..443701a2f5 100644 --- a/conf/base.config +++ b/conf/base.config @@ -77,7 +77,6 @@ process { } withLabel:sentieon { beforeScript = {params.sentieon ? 'module load sentieon/201808.05 samtools/1.9' : ''} - docker.enabled = {params.sentieon ? false : false} - singularity.enabled = {params.sentieon ? false : false} + container = {params.sentieon ? '' : 'nfcore/sarek:dev'} } } From 0cf67cab1876182db12d5b6ae4174e1e703b09e4 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 15:18:39 +0100 Subject: [PATCH 201/854] add fastaFai for bwamem --- main.nf | 1 + 1 file changed, 1 insertion(+) diff --git a/main.nf b/main.nf index 778547fdc5..24627eec4a 100644 --- a/main.nf +++ b/main.nf @@ -661,6 +661,7 @@ process MapReads { set idPatient, idSample, idRun, file(inputFile1), file(inputFile2) from inputReads file(bwaIndex) from ch_bwaIndex file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai output: set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam") into bamMapped From c55c19f90efc50dee2a471cd1557df3f8d631611 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 15:23:24 +0100 Subject: [PATCH 202/854] remove module samtools from label sentieon --- conf/base.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/base.config b/conf/base.config index 443701a2f5..3eeac179f5 100644 --- a/conf/base.config +++ b/conf/base.config @@ -76,7 +76,7 @@ process { errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} } withLabel:sentieon { - beforeScript = {params.sentieon ? 'module load sentieon/201808.05 samtools/1.9' : ''} + beforeScript = {params.sentieon ? 'module load sentieon/201808.05' : ''} container = {params.sentieon ? '' : 'nfcore/sarek:dev'} } } From 6a06f02c3fc0fd8b0ff0dbc2c0265c11e6bf1378 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 15:23:38 +0100 Subject: [PATCH 203/854] fix output from bwa mem --- main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.nf b/main.nf index 24627eec4a..908b5b2d3d 100644 --- a/main.nf +++ b/main.nf @@ -693,7 +693,7 @@ process MapReads { """ sentieon bwa mem -K 100000000 -R \"${readGroup}\" -t ${task.cpus} -M ${fasta} \ ${input} | \ - sentieon util sort -r ${fasta} -o ${idSample}_${idRun}.sorted.bam -t ${task.cpus} --sam2bam -i - + sentieon util sort -r ${fasta} -o ${idSample}_${idRun}.bam -t ${task.cpus} --sam2bam -i - """ } From aea3512c1fb3499aa2956a9acc258bfb54070c83 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 15:52:28 +0100 Subject: [PATCH 204/854] fix output channel BamMapped from MapReads --- main.nf | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/main.nf b/main.nf index 908b5b2d3d..267ffc9c34 100644 --- a/main.nf +++ b/main.nf @@ -664,7 +664,7 @@ process MapReads { file(fastaFai) from ch_fastaFai output: - set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam") into bamMapped + set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam"), file("${idSample}_${idRun}.bam.bai") into bamMapped set idPatient, idSample, file("${idSample}_${idRun}.bam") into bamMappedBamQC when: step == 'mapping' @@ -688,6 +688,7 @@ process MapReads { bwa mem -K 100000000 -R \"${readGroup}\" ${extra} -t ${task.cpus} -M ${fasta} \ ${input} | \ samtools sort --threads ${task.cpus} -m 2G - > ${idSample}_${idRun}.bam + touch ${idSample}_${idRun}.bam.bai """ else """ @@ -697,8 +698,12 @@ process MapReads { """ } -bamMapped = bamMapped.dump(tag:'Mapped BAM') +if (!params.sentieon) { + bamMapped = bamMapped.map{idPatient, idSample, idRun, bam, bai -> + [idPatient, idSample, idRun, bam]} +} +bamMapped = bamMapped.dump(tag:'Mapped BAM') // Sort BAM whether they are standalone or should be merged singleBam = Channel.create() From b93b1f25214285f9ab49a7e9fb14b65a13c0961a Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 15:52:48 +0100 Subject: [PATCH 205/854] set params.sentieon to null by default --- nextflow.config | 1 + 1 file changed, 1 insertion(+) diff --git a/nextflow.config b/nextflow.config index 4632a988a6..a39be4f66a 100644 --- a/nextflow.config +++ b/nextflow.config @@ -28,6 +28,7 @@ params { publishDirMode = 'copy' // Default PublishDirMode (same as other nf-core pipelines) saveGenomeIndex = null // Built Indexes not saved sequencing_center = null // No sequencing center to be writen in BAM header in MapReads process + sentieon = null // Not using Sentieon by default // Optional files/directory cadd_InDels = false // No CADD files From 313fda0eb2b74b5ba20e386445a2ae086728f302 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 16:18:34 +0100 Subject: [PATCH 206/854] add SentieonDedup process --- main.nf | 56 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/main.nf b/main.nf index 267ffc9c34..6c4b77e157 100644 --- a/main.nf +++ b/main.nf @@ -664,7 +664,7 @@ process MapReads { file(fastaFai) from ch_fastaFai output: - set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam"), file("${idSample}_${idRun}.bam.bai") into bamMapped + set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam") into bamMapped set idPatient, idSample, file("${idSample}_${idRun}.bam") into bamMappedBamQC when: step == 'mapping' @@ -688,7 +688,6 @@ process MapReads { bwa mem -K 100000000 -R \"${readGroup}\" ${extra} -t ${task.cpus} -M ${fasta} \ ${input} | \ samtools sort --threads ${task.cpus} -m 2G - > ${idSample}_${idRun}.bam - touch ${idSample}_${idRun}.bam.bai """ else """ @@ -698,11 +697,6 @@ process MapReads { """ } -if (!params.sentieon) { - bamMapped = bamMapped.map{idPatient, idSample, idRun, bam, bai -> - [idPatient, idSample, idRun, bam]} -} - bamMapped = bamMapped.dump(tag:'Mapped BAM') // Sort BAM whether they are standalone or should be merged @@ -741,6 +735,11 @@ mergedBam = mergedBam.dump(tag:'Merged BAM') mergedBam = mergedBam.mix(singleBam) mergedBam = mergedBam.dump(tag:'BAMs for MD') +(mergedBam, mergedBamForSentieion) = mergedBam.into(2) + +if (params.sentieon) mergedBam.close() +else mergedBamForSentieion.close() + // STEP 2: MARKING DUPLICATES process MarkDuplicates { @@ -788,6 +787,49 @@ bamBaseRecalibrator = bamMD.combine(intBaseRecalibrator) bamBaseRecalibrator = bamBaseRecalibrator.dump(tag:'BAM FOR BASERECALIBRATOR') +// STEP 2': SENTIEON DEDUP + +process SentieonDedup { + label 'cpus_16' + label 'sentieon' + + tag {idPatient + "-" + idSample} + + publishDir params.outdir, mode: params.publishDirMode, + saveAs: { + if (it == "${idSample}_*.txt" && 'sentieon' in skipQC) "Reports/${idSample}/Sentieion/${it}" + else "Preprocessing/${idSample}/Deduped/${it}" + } + + input: + set idPatient, idSample, file("${idSample}.bam") from mergedBamForSentieion + file(fasta) from ch_fasta + + output: + set idPatient, idSample, file("${idSample}.deduped.bam") into dedupedSentieionBams + file("${idSample}_*.txt") into dedupedSentieionBamsQC + + when: step == 'mapping' && params.sentieon + + script: + markdup_java_options = task.memory.toGiga() > 8 ? params.markdup_java_options : "\"-Xms" + (task.memory.toGiga() / 2).trunc() + "g -Xmx" + (task.memory.toGiga() - 1) + "g\"" + """ + sentieon driver -t ${task.cpus} -r ${fasta} -i ${idSample}.bam \ + --algo GCBias --summary ${idSample}_gc_summary.txt ${idSample}_gc_metric.txt \ + --algo MeanQualityByCycle ${idSample}_mq_metric.txt \ + --algo QualDistribution ${idSample}_qd_metric.txt \ + --algo InsertSizeMetricAlgo ${idSample}_is_metric.txt \ + --algo AlignmentStat ${idSample}_aln_metric.txt + + sentieon driver -t $THREADS -i ${idSample}.bam \ + --algo LocusCollector --fun score_info ${idSample}_score.gz + + sentieon driver -t $THREADS -i ${idSample}.bam \ + --algo Dedup --rmdup --score_info ${idSample}_score.gz \ + --metrics ${idSample}_dedup_metric.txt ${idSample}.deduped.bam + """ +} + // STEP 3: CREATING RECALIBRATION TABLES process BaseRecalibrator { From 152016edd71d3e0ee45f0a800abab75ef2354fc7 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 16:19:55 +0100 Subject: [PATCH 207/854] fix typo --- main.nf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.nf b/main.nf index 6c4b77e157..46bd1be79d 100644 --- a/main.nf +++ b/main.nf @@ -821,10 +821,10 @@ process SentieonDedup { --algo InsertSizeMetricAlgo ${idSample}_is_metric.txt \ --algo AlignmentStat ${idSample}_aln_metric.txt - sentieon driver -t $THREADS -i ${idSample}.bam \ + sentieon driver -t ${task.cpus} -i ${idSample}.bam \ --algo LocusCollector --fun score_info ${idSample}_score.gz - sentieon driver -t $THREADS -i ${idSample}.bam \ + sentieon driver -t ${task.cpus} -i ${idSample}.bam \ --algo Dedup --rmdup --score_info ${idSample}_score.gz \ --metrics ${idSample}_dedup_metric.txt ${idSample}.deduped.bam """ From 962600e2687e3560c9bbba4347e49690ae722087 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 16:21:20 +0100 Subject: [PATCH 208/854] add fastaFai to SentieonDedup process --- main.nf | 1 + 1 file changed, 1 insertion(+) diff --git a/main.nf b/main.nf index 46bd1be79d..2790b4acad 100644 --- a/main.nf +++ b/main.nf @@ -804,6 +804,7 @@ process SentieonDedup { input: set idPatient, idSample, file("${idSample}.bam") from mergedBamForSentieion file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai output: set idPatient, idSample, file("${idSample}.deduped.bam") into dedupedSentieionBams From 22f545cbabf8673b3c30b05f7282bf0fd6e5f1ad Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 16:28:05 +0100 Subject: [PATCH 209/854] fix bam indexing --- main.nf | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/main.nf b/main.nf index 2790b4acad..05a5a85a39 100644 --- a/main.nf +++ b/main.nf @@ -664,7 +664,7 @@ process MapReads { file(fastaFai) from ch_fastaFai output: - set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam") into bamMapped + set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam"), file("${idSample}_${idRun}.bam.bai") into bamMapped set idPatient, idSample, file("${idSample}_${idRun}.bam") into bamMappedBamQC when: step == 'mapping' @@ -688,6 +688,7 @@ process MapReads { bwa mem -K 100000000 -R \"${readGroup}\" ${extra} -t ${task.cpus} -M ${fasta} \ ${input} | \ samtools sort --threads ${task.cpus} -m 2G - > ${idSample}_${idRun}.bam + samtools index ${idSample}_${idRun}.bam """ else """ @@ -721,22 +722,24 @@ process MergeBamMapped { set idPatient, idSample, idRun, file(bam) from multipleBam output: - set idPatient, idSample, file("${idSample}.bam") into mergedBam + set idPatient, idSample, file("${idSample}.bam"), file("${idSample}.bam.bai") into mergedBam when: step == 'mapping' script: """ samtools merge --threads ${task.cpus} ${idSample}.bam ${bam} + samtools index ${idSample}.bam """ } mergedBam = mergedBam.dump(tag:'Merged BAM') -mergedBam = mergedBam.mix(singleBam) -mergedBam = mergedBam.dump(tag:'BAMs for MD') (mergedBam, mergedBamForSentieion) = mergedBam.into(2) +mergedBam = mergedBam.mix(singleBam) +mergedBam = mergedBam.dump(tag:'BAMs for MD') + if (params.sentieon) mergedBam.close() else mergedBamForSentieion.close() @@ -971,15 +974,14 @@ process MergeBamRecal { set idPatient, idSample, file(bam) from bamMergeBamRecal output: - set idPatient, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bai") into bamRecal + set idPatient, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bam.bai") into bamRecal set idPatient, idSample, file("${idSample}.recal.bam") into (bamRecalBamQC, bamRecalSamToolsStats) - set idPatient, idSample, val("${idSample}.recal.bam"), val("${idSample}.recal.bai") into (bamRecalTSV, bamRecalSampleTSV) + set idPatient, idSample, val("${idSample}.recal.bam"), val("${idSample}.recal.bam.bai") into (bamRecalTSV, bamRecalSampleTSV) script: """ samtools merge --threads ${task.cpus} ${idSample}.recal.bam ${bam} samtools index ${idSample}.recal.bam - mv ${idSample}.recal.bam.bai ${idSample}.recal.bai """ } From ea839de82c3480ea6ec89c1b0b6b5065312079d8 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 16:30:49 +0100 Subject: [PATCH 210/854] fix bam indexing --- main.nf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.nf b/main.nf index 05a5a85a39..c8759c2d67 100644 --- a/main.nf +++ b/main.nf @@ -757,7 +757,7 @@ process MarkDuplicates { } input: - set idPatient, idSample, file("${idSample}.bam") from mergedBam + set idPatient, idSample, file("${idSample}.bam"), file("${idSample}.bam.bai") from mergedBam output: set idPatient, idSample, file("${idSample}.md.bam"), file("${idSample}.md.bai") into duplicateMarkedBams @@ -805,7 +805,7 @@ process SentieonDedup { } input: - set idPatient, idSample, file("${idSample}.bam") from mergedBamForSentieion + set idPatient, idSample, file("${idSample}.bam"), file("${idSample}.bam.bai") from mergedBamForSentieion file(fasta) from ch_fasta file(fastaFai) from ch_fastaFai From 3419fd94e2bcee255999476d9cb005802d2e99b8 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 16:32:11 +0100 Subject: [PATCH 211/854] fix bam indexing --- main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.nf b/main.nf index c8759c2d67..c3f59a6344 100644 --- a/main.nf +++ b/main.nf @@ -719,7 +719,7 @@ process MergeBamMapped { tag {idPatient + "-" + idSample} input: - set idPatient, idSample, idRun, file(bam) from multipleBam + set idPatient, idSample, idRun, file(bam), file(bai) from multipleBam output: set idPatient, idSample, file("${idSample}.bam"), file("${idSample}.bam.bai") into mergedBam From 4f6154e05db11628b5db4f687574c24d7ee8fb55 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 16:45:25 +0100 Subject: [PATCH 212/854] add SentieonBQSR --- main.nf | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/main.nf b/main.nf index c3f59a6344..becb979d8f 100644 --- a/main.nf +++ b/main.nf @@ -801,7 +801,7 @@ process SentieonDedup { publishDir params.outdir, mode: params.publishDirMode, saveAs: { if (it == "${idSample}_*.txt" && 'sentieon' in skipQC) "Reports/${idSample}/Sentieion/${it}" - else "Preprocessing/${idSample}/Deduped/${it}" + else "Preprocessing/${idSample}/DedupedSentieon/${it}" } input: @@ -810,8 +810,8 @@ process SentieonDedup { file(fastaFai) from ch_fastaFai output: - set idPatient, idSample, file("${idSample}.deduped.bam") into dedupedSentieionBams - file("${idSample}_*.txt") into dedupedSentieionBamsQC + set idPatient, idSample, file("${idSample}.deduped.bam"), file("${idSample}.deduped.bam.bai") into dedupedSentieionBam + file("${idSample}_*.txt") into dedupedSentieionBamQC when: step == 'mapping' && params.sentieon @@ -876,6 +876,67 @@ process BaseRecalibrator { tableGatherBQSRReports = tableGatherBQSRReports.groupTuple(by:[0, 1]) +// STEP 3': SENTIEON BQSR + +process SentieonBQSR { + label 'memory_max' + label 'cpus_1' + + tag {idPatient + "-" + idSample} + + publishDir params.outdir, mode: params.publishDirMode, + saveAs: { + if (it == "${idSample}_recal_result.csv" && 'sentieon' in skipQC) "Reports/${idSample}/Sentieion/${it}" + else "Preprocessing/${idSample}/RecalSentieon/${it}" + } + + input: + set idPatient, idSample, file(bam), file(bai) from dedupedSentieionBam + file(dbsnp) from ch_dbsnp + file(dbsnpIndex) from ch_dbsnpIndex + file(fasta) from ch_fasta + file(dict) from ch_dict + file(fastaFai) from ch_fastaFai + file(knownIndels) from ch_knownIndels + file(knownIndelsIndex) from ch_knownIndelsIndex + + output: + set idPatient, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bam.bai") into bamRecalSentieon + file("${idSample}_recal_result.CSV") into bamRecalSentieonQC + + when: step == 'mapping' && params.sentieon + + script: + known = knownIndels.collect{"--known-sites ${it}"}.join(' ') + """ + sentieon driver \ + -t ${task.cpus} \ + -r ${fasta} \ + -i ${idSample}.deduped.bam \ + --algo QualCal \ + -k ${dbsnp} \ + ${idSample}.recal.table + + sentieon driver \ + -t ${task.cpus} \ + -r ${fasta} \ + -i ${idSample}.deduped.bam \ + -q ${idSample}.recal.table \ + --algo QualCal \ + -k ${dbsnp} \ + ${idSample}.table.post \ + --algo ReadWriter ${idSample}.recal.bam + + sentieon driver \ + -t ${task.cpus} \ + --algo QualCal \ + --plot \ + --before ${idSample}.recal.table \ + --after ${idSample}.table.post \ + ${idSample}_recal_result.csv + """ +} + // STEP 3.5: MERGING RECALIBRATION TABLES process GatherBQSRReports { @@ -1071,6 +1132,8 @@ bamQCReport = bamQCReport.dump(tag:'BamQC') ================================================================================ */ +if (params.sentieon) bamRecal = bamRecalSentieon + if (step == 'variantcalling') bamRecal = inputSample bamRecal = bamRecal.dump(tag:'BAM') From 7e00bb22cb942226b2772b9e32537f7afecd2232 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 16:46:57 +0100 Subject: [PATCH 213/854] add label sentieon to SentieonBQSR --- main.nf | 1 + 1 file changed, 1 insertion(+) diff --git a/main.nf b/main.nf index becb979d8f..cc4de4e3f4 100644 --- a/main.nf +++ b/main.nf @@ -880,6 +880,7 @@ tableGatherBQSRReports = tableGatherBQSRReports.groupTuple(by:[0, 1]) process SentieonBQSR { label 'memory_max' + label 'sentieon' label 'cpus_1' tag {idPatient + "-" + idSample} From 04395c7b53dd6ca465790f27914e8e67a6172d65 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 5 Nov 2019 16:48:45 +0100 Subject: [PATCH 214/854] fix metrics output for SentieonBQSR --- main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.nf b/main.nf index cc4de4e3f4..4fad762a52 100644 --- a/main.nf +++ b/main.nf @@ -903,7 +903,7 @@ process SentieonBQSR { output: set idPatient, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bam.bai") into bamRecalSentieon - file("${idSample}_recal_result.CSV") into bamRecalSentieonQC + file("${idSample}_recal_result.csv") into bamRecalSentieonQC when: step == 'mapping' && params.sentieon From c31bf4ee4750e8f11651a51a79763462d65b53e8 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 8 Nov 2019 11:02:34 +0100 Subject: [PATCH 215/854] increase cpus for Sentieon BQSR --- main.nf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/main.nf b/main.nf index 4fad762a52..a317d8c012 100644 --- a/main.nf +++ b/main.nf @@ -692,7 +692,7 @@ process MapReads { """ else """ - sentieon bwa mem -K 100000000 -R \"${readGroup}\" -t ${task.cpus} -M ${fasta} \ + sentieon bwa mem -K 100000000 -R \"${readGroup}\" ${extra} -t ${task.cpus} -M ${fasta} \ ${input} | \ sentieon util sort -r ${fasta} -o ${idSample}_${idRun}.bam -t ${task.cpus} --sam2bam -i - """ @@ -881,7 +881,6 @@ tableGatherBQSRReports = tableGatherBQSRReports.groupTuple(by:[0, 1]) process SentieonBQSR { label 'memory_max' label 'sentieon' - label 'cpus_1' tag {idPatient + "-" + idSample} From 4bdff8eed3e4bf1a4393b226d2e87f09c2346d35 Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Fri, 8 Nov 2019 11:35:56 +0100 Subject: [PATCH 216/854] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8460be05c9..bbf9718ad7 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ For further information or help, don't hesitate to get in touch on [Slack](https ## Aknowledgements -[![Barntumörbanken](docs/images/BTB_logo.png)](https://ki.se/forskning/barntumorbanken-0) | [![SciLifeLab](docs/images/SciLifeLab_logo.png)](https://scilifelab.se) +[![Barntumörbanken](docs/images/BTB_logo.png)](https://ki.se/forskning/barntumorbanken) | [![SciLifeLab](docs/images/SciLifeLab_logo.png)](https://scilifelab.se) :-:|:-: [![National Genomics Infrastructure](docs/images/NGI_logo.png)](https://ngisweden.scilifelab.se/) | [![National Bioinformatics Infrastructure Sweden](docs/images/NBIS_logo.png)](https://nbis.se) From 2d5f759cb1068c31362b699f1e131f89c6f5cae0 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 8 Nov 2019 12:02:52 +0100 Subject: [PATCH 217/854] remove indexing --- main.nf | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/main.nf b/main.nf index a317d8c012..bb8f6d3c1f 100644 --- a/main.nf +++ b/main.nf @@ -664,7 +664,7 @@ process MapReads { file(fastaFai) from ch_fastaFai output: - set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam"), file("${idSample}_${idRun}.bam.bai") into bamMapped + set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam") into bamMapped set idPatient, idSample, file("${idSample}_${idRun}.bam") into bamMappedBamQC when: step == 'mapping' @@ -688,7 +688,6 @@ process MapReads { bwa mem -K 100000000 -R \"${readGroup}\" ${extra} -t ${task.cpus} -M ${fasta} \ ${input} | \ samtools sort --threads ${task.cpus} -m 2G - > ${idSample}_${idRun}.bam - samtools index ${idSample}_${idRun}.bam """ else """ @@ -719,17 +718,16 @@ process MergeBamMapped { tag {idPatient + "-" + idSample} input: - set idPatient, idSample, idRun, file(bam), file(bai) from multipleBam + set idPatient, idSample, idRun, file(bam) from multipleBam output: - set idPatient, idSample, file("${idSample}.bam"), file("${idSample}.bam.bai") into mergedBam + set idPatient, idSample, file("${idSample}.bam") into mergedBam when: step == 'mapping' script: """ samtools merge --threads ${task.cpus} ${idSample}.bam ${bam} - samtools index ${idSample}.bam """ } @@ -757,7 +755,7 @@ process MarkDuplicates { } input: - set idPatient, idSample, file("${idSample}.bam"), file("${idSample}.bam.bai") from mergedBam + set idPatient, idSample, file("${idSample}.bam") from mergedBam output: set idPatient, idSample, file("${idSample}.md.bam"), file("${idSample}.md.bai") into duplicateMarkedBams @@ -805,7 +803,7 @@ process SentieonDedup { } input: - set idPatient, idSample, file("${idSample}.bam"), file("${idSample}.bam.bai") from mergedBamForSentieion + set idPatient, idSample, file("${idSample}.bam") from mergedBamForSentieion file(fasta) from ch_fasta file(fastaFai) from ch_fastaFai From 23a88b3368be399480455f35a1f5a9d6544765e6 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 11 Nov 2019 10:33:27 +0100 Subject: [PATCH 218/854] add index for dedup --- main.nf | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/main.nf b/main.nf index bb8f6d3c1f..ece1cf0254 100644 --- a/main.nf +++ b/main.nf @@ -733,14 +733,34 @@ process MergeBamMapped { mergedBam = mergedBam.dump(tag:'Merged BAM') -(mergedBam, mergedBamForSentieion) = mergedBam.into(2) - mergedBam = mergedBam.mix(singleBam) mergedBam = mergedBam.dump(tag:'BAMs for MD') +(mergedBam, mergedBamForSentieion) = mergedBam.into(2) + if (params.sentieon) mergedBam.close() else mergedBamForSentieion.close() +process IndexBamMergedForSentieon { + label 'cpus_8' + + tag {idPatient + "-" + idSample} + + input: + set idPatient, idSample, file(bam) from mergedBamForSentieion + + output: + set idPatient, idSample, file(bam), file("${idSample}.bam.bai") into bamForSentieionDedup + + when: step == 'mapping' && params.sentieon + + script: + """ + samtools index ${bam} + """ +} + + // STEP 2: MARKING DUPLICATES process MarkDuplicates { @@ -798,12 +818,13 @@ process SentieonDedup { publishDir params.outdir, mode: params.publishDirMode, saveAs: { - if (it == "${idSample}_*.txt" && 'sentieon' in skipQC) "Reports/${idSample}/Sentieion/${it}" + if (it == "${idSample}_*.txt" && 'sentieon' in skipQC) null + else if (it == "${idSample}_*.txt") "Reports/${idSample}/Sentieion/${it}" else "Preprocessing/${idSample}/DedupedSentieon/${it}" } input: - set idPatient, idSample, file("${idSample}.bam") from mergedBamForSentieion + set idPatient, idSample, file(bam), file(bai) from bamForSentieionDedup file(fasta) from ch_fasta file(fastaFai) from ch_fastaFai @@ -814,19 +835,18 @@ process SentieonDedup { when: step == 'mapping' && params.sentieon script: - markdup_java_options = task.memory.toGiga() > 8 ? params.markdup_java_options : "\"-Xms" + (task.memory.toGiga() / 2).trunc() + "g -Xmx" + (task.memory.toGiga() - 1) + "g\"" """ - sentieon driver -t ${task.cpus} -r ${fasta} -i ${idSample}.bam \ + sentieon driver -t ${task.cpus} -r ${fasta} -i ${bam} \ --algo GCBias --summary ${idSample}_gc_summary.txt ${idSample}_gc_metric.txt \ --algo MeanQualityByCycle ${idSample}_mq_metric.txt \ --algo QualDistribution ${idSample}_qd_metric.txt \ --algo InsertSizeMetricAlgo ${idSample}_is_metric.txt \ --algo AlignmentStat ${idSample}_aln_metric.txt - sentieon driver -t ${task.cpus} -i ${idSample}.bam \ + sentieon driver -t ${task.cpus} -i ${bam} \ --algo LocusCollector --fun score_info ${idSample}_score.gz - sentieon driver -t ${task.cpus} -i ${idSample}.bam \ + sentieon driver -t ${task.cpus} -i ${bam} \ --algo Dedup --rmdup --score_info ${idSample}_score.gz \ --metrics ${idSample}_dedup_metric.txt ${idSample}.deduped.bam """ @@ -2762,6 +2782,7 @@ def defineSkipQClist() { 'markduplicates', 'multiqc', 'samtools', + 'senteion', 'vcftools', 'versions' ] @@ -2782,6 +2803,8 @@ def defineToolList() { return [ 'ascat', 'controlfreec', + 'dnascope', + 'dnaseq', 'freebayes', 'haplotypecaller', 'manta', @@ -2791,16 +2814,11 @@ def defineToolList() { 'snpeff', 'strelka', 'tiddit', + 'tnscope', 'vep' ] } -// Print deprecation message -def deprecationMessage(oldItem, newItem = null) { - extra = newItem == null ? "": ", please use `${newItem}` instead" - log.warn "The ${oldItem} is deprecated${extra} -- it will be removed in a future release" -} - // Channeling the TSV file containing BAM. // Format is: "subject gender status sample bam bai" def extractBam(tsvFile) { From bc5599796534702649d283df0f7f0370ce69bfed Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 12 Nov 2019 09:57:48 +0100 Subject: [PATCH 219/854] bwa mem sentieon specific process --- main.nf | 230 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 140 insertions(+), 90 deletions(-) diff --git a/main.nf b/main.nf index ece1cf0254..94fca70c3b 100644 --- a/main.nf +++ b/main.nf @@ -372,125 +372,126 @@ yamlSoftwareVersion = yamlSoftwareVersion.dump(tag:'SOFTWARE VERSIONS') */ process BuildBWAindexes { - tag {fasta} + tag {fasta} - publishDir params.outdir, mode: params.publishDirMode, - saveAs: {params.saveGenomeIndex ? "reference_genome/BWAIndex/${it}" : null } + publishDir params.outdir, mode: params.publishDirMode, + saveAs: {params.saveGenomeIndex ? "reference_genome/BWAIndex/${it}" : null } - input: - file(fasta) from ch_fasta + input: + file(fasta) from ch_fasta - output: - file("${fasta}.*") into bwaIndexes + output: + file("${fasta}.*") into bwaIndexes - when: !(params.bwaIndex) && params.fasta && 'mapping' in step + when: !(params.bwaIndex) && params.fasta && 'mapping' in step - script: - """ - bwa index ${fasta} - """ + script: + """ + bwa index ${fasta} + """ } process BuildDict { - tag {fasta} + tag {fasta} - publishDir params.outdir, mode: params.publishDirMode, - saveAs: {params.saveGenomeIndex ? "reference_genome/${it}" : null } + publishDir params.outdir, mode: params.publishDirMode, + saveAs: {params.saveGenomeIndex ? "reference_genome/${it}" : null } - input: - file(fasta) from ch_fasta + input: + file(fasta) from ch_fasta - output: - file("${fasta.baseName}.dict") into dictBuilt + output: + file("${fasta.baseName}.dict") into dictBuilt - when: !(params.dict) && params.fasta && !('annotate' in step) + when: !(params.dict) && params.fasta && !('annotate' in step) - script: - """ - gatk --java-options "-Xmx${task.memory.toGiga()}g" \ - CreateSequenceDictionary \ - --REFERENCE ${fasta} \ - --OUTPUT ${fasta.baseName}.dict - """ + script: + """ + gatk --java-options "-Xmx${task.memory.toGiga()}g" \ + CreateSequenceDictionary \ + --REFERENCE ${fasta} \ + --OUTPUT ${fasta.baseName}.dict + """ } process BuildFastaFai { - tag {fasta} + tag {fasta} - publishDir params.outdir, mode: params.publishDirMode, - saveAs: {params.saveGenomeIndex ? "reference_genome/${it}" : null } + publishDir params.outdir, mode: params.publishDirMode, + saveAs: {params.saveGenomeIndex ? "reference_genome/${it}" : null } - input: - file(fasta) from ch_fasta + input: + file(fasta) from ch_fasta - output: - file("${fasta}.fai") into fastaFaiBuilt + output: + file("${fasta}.fai") into fastaFaiBuilt - when: !(params.fastaFai) && params.fasta && !('annotate' in step) + when: !(params.fastaFai) && params.fasta && !('annotate' in step) - script: - """ - samtools faidx ${fasta} - """ + script: + """ + samtools faidx ${fasta} + """ } process BuildDbsnpIndex { - tag {dbsnp} + tag {dbsnp} + + publishDir params.outdir, mode: params.publishDirMode, + saveAs: {params.saveGenomeIndex ? "reference_genome/${it}" : null } - publishDir params.outdir, mode: params.publishDirMode, - saveAs: {params.saveGenomeIndex ? "reference_genome/${it}" : null } + input: + file(dbsnp) from ch_dbsnp - input: - file(dbsnp) from ch_dbsnp + output: + file("${dbsnp}.tbi") into dbsnpIndexBuilt - output: - file("${dbsnp}.tbi") into dbsnpIndexBuilt + when: !(params.dbsnpIndex) && params.dbsnp && ('mapping' in step || 'controlfreec' in tools || 'haplotypecaller' in tools || 'mutect2' in tools) - when: !(params.dbsnpIndex) && params.dbsnp && ('mapping' in step || 'controlfreec' in tools || 'haplotypecaller' in tools || 'mutect2' in tools) - script: - """ - tabix -p vcf ${dbsnp} - """ + script: + """ + tabix -p vcf ${dbsnp} + """ } process BuildGermlineResourceIndex { - tag {germlineResource} + tag {germlineResource} - publishDir params.outdir, mode: params.publishDirMode, - saveAs: {params.saveGenomeIndex ? "reference_genome/${it}" : null } + publishDir params.outdir, mode: params.publishDirMode, + saveAs: {params.saveGenomeIndex ? "reference_genome/${it}" : null } - input: - file(germlineResource) from ch_germlineResource + input: + file(germlineResource) from ch_germlineResource - output: - file("${germlineResource}.tbi") into germlineResourceIndexBuilt + output: + file("${germlineResource}.tbi") into germlineResourceIndexBuilt - when: !(params.germlineResourceIndex) && params.germlineResource && 'mutect2' in tools + when: !(params.germlineResourceIndex) && params.germlineResource && 'mutect2' in tools - script: - """ - tabix -p vcf ${germlineResource} - """ + script: + """ + tabix -p vcf ${germlineResource} + """ } process BuildKnownIndelsIndex { - tag {knownIndels} + tag {knownIndels} - publishDir params.outdir, mode: params.publishDirMode, - saveAs: {params.saveGenomeIndex ? "reference_genome/${it}" : null } + publishDir params.outdir, mode: params.publishDirMode, + saveAs: {params.saveGenomeIndex ? "reference_genome/${it}" : null } - input: - each file(knownIndels) from ch_knownIndels + input: + each file(knownIndels) from ch_knownIndels - output: - file("${knownIndels}.tbi") into knownIndelsIndexBuilt + output: + file("${knownIndels}.tbi") into knownIndelsIndexBuilt - when: !(params.knownIndelsIndex) && params.knownIndels && 'mapping' in step + when: !(params.knownIndelsIndex) && params.knownIndels && 'mapping' in step - script: - """ - tabix -p vcf ${knownIndels} - """ + script: + """ + tabix -p vcf ${knownIndels} + """ } // Initialize channels based on params or indexes that were just built @@ -596,8 +597,6 @@ inputBAMFastQC = inputBAMFastQC.map { [idPatient, idSample, idRun, inputFile1] } -inputReads = inputReads.dump(tag:'INPUT') - // STEP 0.5: QC ON READS // TODO: Use only one process for FastQC for FASTQ files and uBAM files @@ -651,9 +650,14 @@ fastQCReport = fastQCReport.dump(tag:'FastQC') // STEP 1: MAPPING READS TO REFERENCE GENOME WITH BWA MEM +inputReads = inputReads.dump(tag:'INPUT') + +(inputReads, inputReadsSentieon) = inputReads.into(2) +if (params.sentieon) inputReads.close() +else inputReadsSentieon.close() + process MapReads { label 'cpus_max' - label 'sentieon' tag {idPatient + "-" + idRun} @@ -682,19 +686,12 @@ process MapReads { extra = status == 1 ? "-B 3" : "" convertToFastq = hasExtension(inputFile1, "bam") ? "gatk --java-options -Xmx${task.memory.toGiga()}g SamToFastq --INPUT=${inputFile1} --FASTQ=/dev/stdout --INTERLEAVE=true --NON_PF=true | \\" : "" input = hasExtension(inputFile1, "bam") ? "-p /dev/stdin - 2> >(tee ${inputFile1}.bwa.stderr.log >&2)" : "${inputFile1} ${inputFile2}" - if (!params.sentieon) """ ${convertToFastq} bwa mem -K 100000000 -R \"${readGroup}\" ${extra} -t ${task.cpus} -M ${fasta} \ ${input} | \ samtools sort --threads ${task.cpus} -m 2G - > ${idSample}_${idRun}.bam """ - else - """ - sentieon bwa mem -K 100000000 -R \"${readGroup}\" ${extra} -t ${task.cpus} -M ${fasta} \ - ${input} | \ - sentieon util sort -r ${fasta} -o ${idSample}_${idRun}.bam -t ${task.cpus} --sam2bam -i - - """ } bamMapped = bamMapped.dump(tag:'Mapped BAM') @@ -710,8 +707,61 @@ singleBam = singleBam.map { } singleBam = singleBam.dump(tag:'Single BAM') +// STEP 1': MAPPING READS TO REFERENCE GENOME WITH SENTIEON BWA MEM + +process SentieonMapReads { + label 'cpus_max' + label 'sentieon' + + tag {idPatient + "-" + idRun} + + input: + set idPatient, idSample, idRun, file(inputFile1), file(inputFile2) from inputReadsSentieon + file(bwaIndex) from ch_bwaIndex + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai + + output: + set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam") into bamMappedSentieon + set idPatient, idSample, file("${idSample}_${idRun}.bam") into bamMappedSentieonBamQC + + when: step == 'mapping' && params.sentieon + + script: + // -K is an hidden option, used to fix the number of reads processed by bwa mem + // Chunk size can affect bwa results, if not specified, + // the number of threads can change which can give not deterministic result. + // cf https://github.com/CCDG/Pipeline-Standardization/blob/master/PipelineStandard.md + // and https://github.com/gatk-workflows/gatk4-data-processing/blob/8ffa26ff4580df4ac3a5aa9e272a4ff6bab44ba2/processing-for-variant-discovery-gatk4.b37.wgs.inputs.json#L29 + CN = params.sequencing_center ? "CN:${params.sequencing_center}\\t" : "" + readGroup = "@RG\\tID:${idRun}\\t${CN}PU:${idRun}\\tSM:${idSample}\\tLB:${idSample}\\tPL:illumina" + // adjust mismatch penalty for tumor samples + status = statusMap[idPatient, idSample] + extra = status == 1 ? "-B 3" : "" + """ + sentieon bwa mem -K 100000000 -R \"${readGroup}\" ${extra} -t ${task.cpus} -M ${fasta} \ + ${inputFile1} ${inputFile2} | \ + sentieon util sort -r ${fasta} -o ${idSample}_${idRun}.bam -t ${task.cpus} --sam2bam -i - + """ +} + +bamMappedSentieon = bamMappedSentieon.dump(tag:'Sentieon Mapped BAM') +// Sort BAM whether they are standalone or should be merged + +singleBamSentieon = Channel.create() +multipleBamSentieon = Channel.create() +bamMappedSentieon.groupTuple(by:[0, 1]) + .choice(singleBamSentieon, multipleBamSentieon) {it[2].size() > 1 ? 1 : 0} +singleBamSentieon = singleBamSentieon.map { + idPatient, idSample, idRun, bam -> + [idPatient, idSample, bam] +} +singleBamSentieon = singleBamSentieon.dump(tag:'Single BAM') + // STEP 1.5: MERGING BAM FROM MULTIPLE LANES +multipleBam = multipleBam.mix(multipleBamSentieon) + process MergeBamMapped { label 'cpus_8' @@ -733,7 +783,8 @@ process MergeBamMapped { mergedBam = mergedBam.dump(tag:'Merged BAM') -mergedBam = mergedBam.mix(singleBam) +mergedBam = mergedBam.mix(singleBam,singleBamSentieon) + mergedBam = mergedBam.dump(tag:'BAMs for MD') (mergedBam, mergedBamForSentieion) = mergedBam.into(2) @@ -760,7 +811,6 @@ process IndexBamMergedForSentieon { """ } - // STEP 2: MARKING DUPLICATES process MarkDuplicates { @@ -1286,7 +1336,7 @@ process StrelkaSingle { Strelka_${idSample}_variants.vcf.gz mv Strelka/results/variants/variants.vcf.gz.tbi \ Strelka_${idSample}_variants.vcf.gz.tbi - """ + """ } vcfStrelkaSingle = vcfStrelkaSingle.dump(tag:'Strelka - Single Mode') @@ -1755,7 +1805,7 @@ process Strelka { Strelka_${idSampleTumor}_vs_${idSampleNormal}_somatic_snvs.vcf.gz mv Strelka/results/variants/somatic.snvs.vcf.gz.tbi \ Strelka_${idSampleTumor}_vs_${idSampleNormal}_somatic_snvs.vcf.gz.tbi - """ + """ } vcfStrelka = vcfStrelka.dump(tag:'Strelka') @@ -1871,7 +1921,7 @@ process StrelkaBP { StrelkaBP_${idSampleTumor}_vs_${idSampleNormal}_somatic_snvs.vcf.gz mv Strelka/results/variants/somatic.snvs.vcf.gz.tbi \ StrelkaBP_${idSampleTumor}_vs_${idSampleNormal}_somatic_snvs.vcf.gz.tbi - """ + """ } vcfStrelkaBP = vcfStrelkaBP.dump(tag:'Strelka BP') From d874bd665f30308d3a5cec6df4bf20623043c87a Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 12 Nov 2019 10:21:39 +0100 Subject: [PATCH 220/854] TSV file for sentieon Dedup --- main.nf | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/main.nf b/main.nf index 94fca70c3b..8d8bc15059 100644 --- a/main.nf +++ b/main.nf @@ -192,7 +192,7 @@ if (params.sampleDir) tsvPath = params.sampleDir // If no input file specified, trying to get TSV files corresponding to step in the TSV directory // only for steps recalibrate and variantCalling if (!params.input && step != 'mapping' && step != 'annotate') { - tsvPath = step == 'recalibrate' ? "${params.outdir}/Preprocessing/TSV/duplicateMarked.tsv": "${params.outdir}/Preprocessing/TSV/recalibrated.tsv" + tsvPath = step == 'recalibrate' ? "${params.outdir}/Preprocessing/TSV/duplicateMarked.tsv": params.sention ? "${params.outdir}/Preprocessing/TSV/sentieon.tsv" : "${params.outdir}/Preprocessing/TSV/recalibrated.tsv" } inputSample = Channel.empty() @@ -970,6 +970,7 @@ process SentieonBQSR { output: set idPatient, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bam.bai") into bamRecalSentieon + set idPatient, idSample into bamRecalSentieonTSV file("${idSample}_recal_result.csv") into bamRecalSentieonQC when: step == 'mapping' && params.sentieon @@ -1005,6 +1006,28 @@ process SentieonBQSR { """ } +(bamRecalSentieonTSV, bamRecalSentieonSampleTSV) = bamRecalSentieonTSV.into(2) + +// Creating a TSV file to restart from this step +bamRecalSentieonTSV.map { idPatient, idSample -> + gender = genderMap[idPatient] + status = statusMap[idPatient, idSample] + bam = "${params.outdir}/Preprocessing/${idSample}/Sentieion/${idSample}.recal.bam" + bai = "${params.outdir}/Preprocessing/${idSample}/Sentieion/${idSample}.recal.bam.bai" + "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\n" +}.collectFile( + name: 'sentieion.tsv', sort: true, storeDir: "${params.outdir}/Preprocessing/TSV" +) + +bamRecalSentieonSampleTSV + .collectFile(storeDir: "${params.outdir}/Preprocessing/TSV") { + idPatient, idSample -> + status = statusMap[idPatient, idSample] + gender = genderMap[idPatient] + bam = "${params.outdir}/Preprocessing/${idSample}/Sentieion/${idSample}.recal.bam" + bai = "${params.outdir}/Preprocessing/${idSample}/Sentieion/${idSample}.recal.bam.bai" + ["sentieion_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\n"] +} // STEP 3.5: MERGING RECALIBRATION TABLES process GatherBQSRReports { From 2ce9735d5807e5a2f112559b63521ae647389a06 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 12 Nov 2019 10:45:01 +0100 Subject: [PATCH 221/854] TSV for every step for Sentieon --- main.nf | 71 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/main.nf b/main.nf index 8d8bc15059..2c49212393 100644 --- a/main.nf +++ b/main.nf @@ -192,7 +192,12 @@ if (params.sampleDir) tsvPath = params.sampleDir // If no input file specified, trying to get TSV files corresponding to step in the TSV directory // only for steps recalibrate and variantCalling if (!params.input && step != 'mapping' && step != 'annotate') { - tsvPath = step == 'recalibrate' ? "${params.outdir}/Preprocessing/TSV/duplicateMarked.tsv": params.sention ? "${params.outdir}/Preprocessing/TSV/sentieon.tsv" : "${params.outdir}/Preprocessing/TSV/recalibrated.tsv" + if (!params.sentieon) { + tsvPath = step == 'recalibrate' ? "${params.outdir}/Preprocessing/TSV/duplicateMarked.tsv" : "${params.outdir}/Preprocessing/TSV/recalibrated.tsv" + } + else { + tsvPath = step == 'recalibrate' ? "${params.outdir}/Preprocessing/TSV/deduped_sentieon.tsv" : "${params.outdir}/Preprocessing/TSV/recalibrated_sentieon.tsv" + } } inputSample = Channel.empty() @@ -200,7 +205,7 @@ if (tsvPath) { tsvFile = file(tsvPath) switch (step) { case 'mapping': inputSample = extractFastq(tsvFile); break - case 'recalibrate': inputSample = extractRecal(tsvFile); break + case 'recalibrate': inputSample = params.sentieon ? extractBam(tsvFile) : extractRecal(tsvFile) ; break case 'variantcalling': inputSample = extractBam(tsvFile); break case 'annotate': break default: exit 1, "Unknown step ${step}" @@ -711,6 +716,7 @@ singleBam = singleBam.dump(tag:'Single BAM') process SentieonMapReads { label 'cpus_max' + label 'memory_max' label 'sentieon' tag {idPatient + "-" + idRun} @@ -787,10 +793,10 @@ mergedBam = mergedBam.mix(singleBam,singleBamSentieon) mergedBam = mergedBam.dump(tag:'BAMs for MD') -(mergedBam, mergedBamForSentieion) = mergedBam.into(2) +(mergedBam, mergedBamForSentieon) = mergedBam.into(2) if (params.sentieon) mergedBam.close() -else mergedBamForSentieion.close() +else mergedBamForSentieon.close() process IndexBamMergedForSentieon { label 'cpus_8' @@ -798,10 +804,10 @@ process IndexBamMergedForSentieon { tag {idPatient + "-" + idSample} input: - set idPatient, idSample, file(bam) from mergedBamForSentieion + set idPatient, idSample, file(bam) from mergedBamForSentieon output: - set idPatient, idSample, file(bam), file("${idSample}.bam.bai") into bamForSentieionDedup + set idPatient, idSample, file(bam), file("${idSample}.bam.bai") into bamForSentieonDedup when: step == 'mapping' && params.sentieon @@ -861,7 +867,8 @@ bamBaseRecalibrator = bamBaseRecalibrator.dump(tag:'BAM FOR BASERECALIBRATOR') // STEP 2': SENTIEON DEDUP process SentieonDedup { - label 'cpus_16' + label 'cpus_max' + label 'memory_max' label 'sentieon' tag {idPatient + "-" + idSample} @@ -869,18 +876,19 @@ process SentieonDedup { publishDir params.outdir, mode: params.publishDirMode, saveAs: { if (it == "${idSample}_*.txt" && 'sentieon' in skipQC) null - else if (it == "${idSample}_*.txt") "Reports/${idSample}/Sentieion/${it}" + else if (it == "${idSample}_*.txt") "Reports/${idSample}/Sentieon/${it}" else "Preprocessing/${idSample}/DedupedSentieon/${it}" } input: - set idPatient, idSample, file(bam), file(bai) from bamForSentieionDedup + set idPatient, idSample, file(bam), file(bai) from bamForSentieonDedup file(fasta) from ch_fasta file(fastaFai) from ch_fastaFai output: - set idPatient, idSample, file("${idSample}.deduped.bam"), file("${idSample}.deduped.bam.bai") into dedupedSentieionBam - file("${idSample}_*.txt") into dedupedSentieionBamQC + set idPatient, idSample, file("${idSample}.deduped.bam"), file("${idSample}.deduped.bam.bai") into bamDedupedSentieon + set idPatient, idSample into bamDedupedSentieonTSV + file("${idSample}_*.txt") into bamDedupedSentieonQC when: step == 'mapping' && params.sentieon @@ -902,6 +910,29 @@ process SentieonDedup { """ } +(bamDedupedSentieonTSV, bamDedupedSentieonSampleTSV) = bamDedupedSentieonTSV.into(2) + +// Creating a TSV file to restart from this step +bamDedupedSentieonTSV.map { idPatient, idSample -> + gender = genderMap[idPatient] + status = statusMap[idPatient, idSample] + bam = "${params.outdir}/Preprocessing/${idSample}/DedupedSentieon/${idSample}.recal.bam" + bai = "${params.outdir}/Preprocessing/${idSample}/DedupedSentieon/${idSample}.recal.bam.bai" + "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\n" +}.collectFile( + name: 'deduped_sentieon.tsv', sort: true, storeDir: "${params.outdir}/Preprocessing/TSV" +) + +bamDedupedSentieonSampleTSV + .collectFile(storeDir: "${params.outdir}/Preprocessing/TSV") { + idPatient, idSample -> + status = statusMap[idPatient, idSample] + gender = genderMap[idPatient] + bam = "${params.outdir}/Preprocessing/${idSample}/DedupedSentieon/${idSample}.recal.bam" + bai = "${params.outdir}/Preprocessing/${idSample}/DedupedSentieon/${idSample}.recal.bam.bai" + ["deduped_sentieon_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\n"] +} + // STEP 3: CREATING RECALIBRATION TABLES process BaseRecalibrator { @@ -947,6 +978,7 @@ tableGatherBQSRReports = tableGatherBQSRReports.groupTuple(by:[0, 1]) // STEP 3': SENTIEON BQSR process SentieonBQSR { + label 'cpus_max' label 'memory_max' label 'sentieon' @@ -954,12 +986,12 @@ process SentieonBQSR { publishDir params.outdir, mode: params.publishDirMode, saveAs: { - if (it == "${idSample}_recal_result.csv" && 'sentieon' in skipQC) "Reports/${idSample}/Sentieion/${it}" + if (it == "${idSample}_recal_result.csv" && 'sentieon' in skipQC) "Reports/${idSample}/Sentieon/${it}" else "Preprocessing/${idSample}/RecalSentieon/${it}" } input: - set idPatient, idSample, file(bam), file(bai) from dedupedSentieionBam + set idPatient, idSample, file(bam), file(bai) from bamDedupedSentieon file(dbsnp) from ch_dbsnp file(dbsnpIndex) from ch_dbsnpIndex file(fasta) from ch_fasta @@ -1012,11 +1044,11 @@ process SentieonBQSR { bamRecalSentieonTSV.map { idPatient, idSample -> gender = genderMap[idPatient] status = statusMap[idPatient, idSample] - bam = "${params.outdir}/Preprocessing/${idSample}/Sentieion/${idSample}.recal.bam" - bai = "${params.outdir}/Preprocessing/${idSample}/Sentieion/${idSample}.recal.bam.bai" + bam = "${params.outdir}/Preprocessing/${idSample}/RecalSentieon/${idSample}.recal.bam" + bai = "${params.outdir}/Preprocessing/${idSample}/RecalSentieon/${idSample}.recal.bam.bai" "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\n" }.collectFile( - name: 'sentieion.tsv', sort: true, storeDir: "${params.outdir}/Preprocessing/TSV" + name: 'recalibrated_sentieon.tsv', sort: true, storeDir: "${params.outdir}/Preprocessing/TSV" ) bamRecalSentieonSampleTSV @@ -1024,10 +1056,11 @@ bamRecalSentieonSampleTSV idPatient, idSample -> status = statusMap[idPatient, idSample] gender = genderMap[idPatient] - bam = "${params.outdir}/Preprocessing/${idSample}/Sentieion/${idSample}.recal.bam" - bai = "${params.outdir}/Preprocessing/${idSample}/Sentieion/${idSample}.recal.bam.bai" - ["sentieion_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\n"] + bam = "${params.outdir}/Preprocessing/${idSample}/RecalSentieon/${idSample}.recal.bam" + bai = "${params.outdir}/Preprocessing/${idSample}/RecalSentieon/${idSample}.recal.bam.bai" + ["recalibrated_sentieon_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\n"] } + // STEP 3.5: MERGING RECALIBRATION TABLES process GatherBQSRReports { From babb391c9fdbcbd366923fd0cc602345067832a6 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 12 Nov 2019 10:54:44 +0100 Subject: [PATCH 222/854] recal -> deduped --- main.nf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/main.nf b/main.nf index 2c49212393..f079290c44 100644 --- a/main.nf +++ b/main.nf @@ -916,8 +916,8 @@ process SentieonDedup { bamDedupedSentieonTSV.map { idPatient, idSample -> gender = genderMap[idPatient] status = statusMap[idPatient, idSample] - bam = "${params.outdir}/Preprocessing/${idSample}/DedupedSentieon/${idSample}.recal.bam" - bai = "${params.outdir}/Preprocessing/${idSample}/DedupedSentieon/${idSample}.recal.bam.bai" + bam = "${params.outdir}/Preprocessing/${idSample}/DedupedSentieon/${idSample}.deduped.bam" + bai = "${params.outdir}/Preprocessing/${idSample}/DedupedSentieon/${idSample}.deduped.bam.bai" "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\n" }.collectFile( name: 'deduped_sentieon.tsv', sort: true, storeDir: "${params.outdir}/Preprocessing/TSV" @@ -928,8 +928,8 @@ bamDedupedSentieonSampleTSV idPatient, idSample -> status = statusMap[idPatient, idSample] gender = genderMap[idPatient] - bam = "${params.outdir}/Preprocessing/${idSample}/DedupedSentieon/${idSample}.recal.bam" - bai = "${params.outdir}/Preprocessing/${idSample}/DedupedSentieon/${idSample}.recal.bam.bai" + bam = "${params.outdir}/Preprocessing/${idSample}/DedupedSentieon/${idSample}.deduped.bam" + bai = "${params.outdir}/Preprocessing/${idSample}/DedupedSentieon/${idSample}.deduped.bam.bai" ["deduped_sentieon_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\n"] } From bea7238b14ffd9e0e07156ff4d0735ae046a6af2 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 12 Nov 2019 10:58:54 +0100 Subject: [PATCH 223/854] fix input for TSV recalibrate --- main.nf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/main.nf b/main.nf index f079290c44..8fab56b1f5 100644 --- a/main.nf +++ b/main.nf @@ -977,6 +977,8 @@ tableGatherBQSRReports = tableGatherBQSRReports.groupTuple(by:[0, 1]) // STEP 3': SENTIEON BQSR +if (step == 'recalibrate' && params.sentieon) bamDedupedSentieon = inputSample + process SentieonBQSR { label 'cpus_max' label 'memory_max' @@ -1109,7 +1111,7 @@ recalTableSampleTSV bamApplyBQSR = bamMDToJoin.join(recalTable, by:[0,1]) -if (step == 'recalibrate') bamApplyBQSR = inputSample +if (step == 'recalibrate' && (!params.sentieon)) bamApplyBQSR = inputSample bamApplyBQSR = bamApplyBQSR.dump(tag:'recal.table') From efaec9fa02379ef53a04f9e97efe69e3409729e0 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 12 Nov 2019 11:03:06 +0100 Subject: [PATCH 224/854] enable restart from recalibrate with TSV with Sentieon --- main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.nf b/main.nf index 8fab56b1f5..40038d8b89 100644 --- a/main.nf +++ b/main.nf @@ -1007,7 +1007,7 @@ process SentieonBQSR { set idPatient, idSample into bamRecalSentieonTSV file("${idSample}_recal_result.csv") into bamRecalSentieonQC - when: step == 'mapping' && params.sentieon + when: params.sentieon && (step == 'mapping' || step == 'recalibrate') script: known = knownIndels.collect{"--known-sites ${it}"}.join(' ') From f5744e440b75c1ec56ccbdc96d76e05115c595b3 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 12 Nov 2019 11:10:58 +0100 Subject: [PATCH 225/854] fix sention variant calling from mapping and recalibrate --- main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.nf b/main.nf index 40038d8b89..b01646fe00 100644 --- a/main.nf +++ b/main.nf @@ -1258,7 +1258,7 @@ bamQCReport = bamQCReport.dump(tag:'BamQC') ================================================================================ */ -if (params.sentieon) bamRecal = bamRecalSentieon +if (params.sentieon && (step == 'mapping' || step == 'recalibrate')) bamRecal = bamRecalSentieon if (step == 'variantcalling') bamRecal = inputSample From ee5beaf84bfb84d8340b4026edf9028530f617dd Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 12 Nov 2019 11:35:54 +0100 Subject: [PATCH 226/854] code polishing --- main.nf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.nf b/main.nf index b01646fe00..a9aeaf4c2c 100644 --- a/main.nf +++ b/main.nf @@ -1007,7 +1007,7 @@ process SentieonBQSR { set idPatient, idSample into bamRecalSentieonTSV file("${idSample}_recal_result.csv") into bamRecalSentieonQC - when: params.sentieon && (step == 'mapping' || step == 'recalibrate') + when: params.sentieon && step in ['mapping','recalibrate'] script: known = knownIndels.collect{"--known-sites ${it}"}.join(' ') @@ -1258,7 +1258,7 @@ bamQCReport = bamQCReport.dump(tag:'BamQC') ================================================================================ */ -if (params.sentieon && (step == 'mapping' || step == 'recalibrate')) bamRecal = bamRecalSentieon +if (params.sentieon && step in ['mapping', 'recalibrate']) bamRecal = bamRecalSentieon if (step == 'variantcalling') bamRecal = inputSample From 88f4af3cfc657e9edf6ccdde01bedce2e693303d Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 12 Nov 2019 12:29:35 +0100 Subject: [PATCH 227/854] add dump tag for imput sample --- main.nf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.nf b/main.nf index a9aeaf4c2c..919e7d137e 100644 --- a/main.nf +++ b/main.nf @@ -588,6 +588,8 @@ bedIntervals = bedIntervals.dump(tag:'bedintervals') // PREPARING CHANNELS FOR PREPROCESSING AND QC +inputSample = inputSample.dump(tag:'INPUT SAMPLE') + if (step == 'mapping') (inputReads, inputReadsFastQC) = inputSample.into(2) else (inputReads, inputReadsFastQC) = Channel.empty().into(2) From 2b6842fc0967360700e86ce4346e4f63c600f48c Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 12 Nov 2019 12:35:09 +0100 Subject: [PATCH 228/854] add dump tag for bamDedupedSentieon --- main.nf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.nf b/main.nf index 919e7d137e..649755e0da 100644 --- a/main.nf +++ b/main.nf @@ -981,6 +981,8 @@ tableGatherBQSRReports = tableGatherBQSRReports.groupTuple(by:[0, 1]) if (step == 'recalibrate' && params.sentieon) bamDedupedSentieon = inputSample +bamDedupedSentieon = bamDedupedSentieon.dump(tag:'deduped.bam') + process SentieonBQSR { label 'cpus_max' label 'memory_max' From 1b979e53548e4fafbb07aa80b2f27c8f06efb066 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 12 Nov 2019 13:10:36 +0100 Subject: [PATCH 229/854] code polishing --- main.nf | 59 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/main.nf b/main.nf index 649755e0da..65ccc0ab28 100644 --- a/main.nf +++ b/main.nf @@ -192,11 +192,11 @@ if (params.sampleDir) tsvPath = params.sampleDir // If no input file specified, trying to get TSV files corresponding to step in the TSV directory // only for steps recalibrate and variantCalling if (!params.input && step != 'mapping' && step != 'annotate') { - if (!params.sentieon) { - tsvPath = step == 'recalibrate' ? "${params.outdir}/Preprocessing/TSV/duplicateMarked.tsv" : "${params.outdir}/Preprocessing/TSV/recalibrated.tsv" + if (params.sentieon) { + tsvPath = step == 'recalibrate' ? "${params.outdir}/Preprocessing/TSV/deduped_sentieon.tsv" : "${params.outdir}/Preprocessing/TSV/recalibrated_sentieon.tsv" } else { - tsvPath = step == 'recalibrate' ? "${params.outdir}/Preprocessing/TSV/deduped_sentieon.tsv" : "${params.outdir}/Preprocessing/TSV/recalibrated_sentieon.tsv" + tsvPath = step == 'recalibrate' ? "${params.outdir}/Preprocessing/TSV/duplicateMarked.tsv" : "${params.outdir}/Preprocessing/TSV/recalibrated.tsv" } } @@ -793,12 +793,13 @@ mergedBam = mergedBam.dump(tag:'Merged BAM') mergedBam = mergedBam.mix(singleBam,singleBamSentieon) -mergedBam = mergedBam.dump(tag:'BAMs for MD') - (mergedBam, mergedBamForSentieon) = mergedBam.into(2) -if (params.sentieon) mergedBam.close() -else mergedBamForSentieon.close() +if (!params.sentieon) mergedBamForSentieon.close() +else mergedBam.close() + +mergedBam = mergedBam.dump(tag:'BAMs for MD') +mergedBamForSentieon = mergedBamForSentieon.dump(tag:'Sentieon BAMs to Index') process IndexBamMergedForSentieon { label 'cpus_8' @@ -811,7 +812,7 @@ process IndexBamMergedForSentieon { output: set idPatient, idSample, file(bam), file("${idSample}.bam.bai") into bamForSentieonDedup - when: step == 'mapping' && params.sentieon + when: step == 'mapping' script: """ @@ -1011,36 +1012,36 @@ process SentieonBQSR { set idPatient, idSample into bamRecalSentieonTSV file("${idSample}_recal_result.csv") into bamRecalSentieonQC - when: params.sentieon && step in ['mapping','recalibrate'] + when: params.sentieon && step in ['mapping', 'recalibrate'] script: known = knownIndels.collect{"--known-sites ${it}"}.join(' ') """ sentieon driver \ - -t ${task.cpus} \ - -r ${fasta} \ - -i ${idSample}.deduped.bam \ - --algo QualCal \ - -k ${dbsnp} \ - ${idSample}.recal.table + -t ${task.cpus} \ + -r ${fasta} \ + -i ${idSample}.deduped.bam \ + --algo QualCal \ + -k ${dbsnp} \ + ${idSample}.recal.table sentieon driver \ - -t ${task.cpus} \ - -r ${fasta} \ - -i ${idSample}.deduped.bam \ - -q ${idSample}.recal.table \ - --algo QualCal \ - -k ${dbsnp} \ - ${idSample}.table.post \ - --algo ReadWriter ${idSample}.recal.bam + -t ${task.cpus} \ + -r ${fasta} \ + -i ${idSample}.deduped.bam \ + -q ${idSample}.recal.table \ + --algo QualCal \ + -k ${dbsnp} \ + ${idSample}.table.post \ + --algo ReadWriter ${idSample}.recal.bam sentieon driver \ - -t ${task.cpus} \ - --algo QualCal \ - --plot \ - --before ${idSample}.recal.table \ - --after ${idSample}.table.post \ - ${idSample}_recal_result.csv + -t ${task.cpus} \ + --algo QualCal \ + --plot \ + --before ${idSample}.recal.table \ + --after ${idSample}.table.post \ + ${idSample}_recal_result.csv """ } From 60a9fb3a9a8b92531490073a48915744a3fd8109 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 12 Nov 2019 13:27:11 +0100 Subject: [PATCH 230/854] code polishing --- main.nf | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/main.nf b/main.nf index 65ccc0ab28..a0f0b3e550 100644 --- a/main.nf +++ b/main.nf @@ -211,9 +211,9 @@ if (tsvPath) { default: exit 1, "Unknown step ${step}" } } else if (params.input && !hasExtension(params.input, "tsv")) { - println "No TSV file" + log.info "No TSV file" if (step != 'mapping') exit 1, 'No other step than "mapping" support a dir as an input' - println "Reading ${params.input} directory" + log.info "Reading ${params.input} directory" inputSample = extractFastqFromDir(params.input) (inputSample, fastqTMP) = inputSample.into(2) fastqTMP.toList().subscribe onNext: { @@ -221,7 +221,7 @@ if (tsvPath) { } tsvFile = params.input // used in the reports } else if (step == 'annotate') { - println "Annotating ${tsvFile}" + log.info "Annotating ${tsvFile}" } else exit 1, 'No sample were defined, see --help' (genderMap, statusMap, inputSample) = extractInfos(inputSample) @@ -1012,7 +1012,7 @@ process SentieonBQSR { set idPatient, idSample into bamRecalSentieonTSV file("${idSample}_recal_result.csv") into bamRecalSentieonQC - when: params.sentieon && step in ['mapping', 'recalibrate'] + when: params.sentieon && (step in ['mapping', 'recalibrate']) script: known = knownIndels.collect{"--known-sites ${it}"}.join(' ') @@ -2853,7 +2853,7 @@ def checkNumberOfItem(row, number) { // Check parameter existence def checkParameterExistence(it, list) { if (!list.contains(it)) { - println("Unknown parameter: ${it}") + log.warn "Unknown parameter: ${it}" return false } return true From dc25d277ca56a0ac08d6ab6be06a3911f6a1d226 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 12 Nov 2019 13:44:47 +0100 Subject: [PATCH 231/854] code polishing --- main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.nf b/main.nf index a0f0b3e550..2124a0d340 100644 --- a/main.nf +++ b/main.nf @@ -1012,7 +1012,7 @@ process SentieonBQSR { set idPatient, idSample into bamRecalSentieonTSV file("${idSample}_recal_result.csv") into bamRecalSentieonQC - when: params.sentieon && (step in ['mapping', 'recalibrate']) + when: params.sentieon script: known = knownIndels.collect{"--known-sites ${it}"}.join(' ') From fba89d0cdb42ae84c569f000df171a6cd05fa334 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 12 Nov 2019 14:51:16 +0100 Subject: [PATCH 232/854] code polishing --- main.nf | 175 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 88 insertions(+), 87 deletions(-) diff --git a/main.nf b/main.nf index 2124a0d340..d3e0a1d9d4 100644 --- a/main.nf +++ b/main.nf @@ -978,9 +978,95 @@ process BaseRecalibrator { tableGatherBQSRReports = tableGatherBQSRReports.groupTuple(by:[0, 1]) -// STEP 3': SENTIEON BQSR +// STEP 3.5: MERGING RECALIBRATION TABLES + +process GatherBQSRReports { + label 'memory_singleCPU_2_task' + label 'cpus_2' + + tag {idPatient + "-" + idSample} + + publishDir "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked", mode: params.publishDirMode, overwrite: false + + input: + set idPatient, idSample, file(recal) from tableGatherBQSRReports + + output: + set idPatient, idSample, file("${idSample}.recal.table") into recalTable + set idPatient, idSample, val("${idSample}.md.bam"), val("${idSample}.md.bai"), val("${idSample}.recal.table") into (recalTableTSV, recalTableSampleTSV) + + when: step == 'mapping' + + script: + input = recal.collect{"-I ${it}"}.join(' ') + """ + gatk --java-options -Xmx${task.memory.toGiga()}g \ + GatherBQSRReports \ + ${input} \ + -O ${idSample}.recal.table \ + """ +} + +// Create TSV files to restart from this step +recalTableTSV.map { idPatient, idSample, bam, bai, recalTable -> + status = statusMap[idPatient, idSample] + gender = genderMap[idPatient] + "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bam}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bai}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${recalTable}\n" +}.collectFile( + name: 'duplicateMarked.tsv', sort: true, storeDir: "${params.outdir}/Preprocessing/TSV" +) + +recalTableSampleTSV + .collectFile(storeDir: "${params.outdir}/Preprocessing/TSV/") { + idPatient, idSample, bam, bai, recalTable -> + status = statusMap[idPatient, idSample] + gender = genderMap[idPatient] + ["duplicateMarked_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bam}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bai}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${recalTable}\n"] +} + +bamApplyBQSR = bamMDToJoin.join(recalTable, by:[0,1]) + +if (step == 'recalibrate') { + if (params.sentieon) bamDedupedSentieon = inputSample + else bamApplyBQSR = inputSample +} + +bamApplyBQSR = bamApplyBQSR.dump(tag:'recal.table') + +bamApplyBQSR = bamApplyBQSR.combine(intApplyBQSR) + +// STEP 4: RECALIBRATING + +process ApplyBQSR { + label 'memory_singleCPU_2_task' + label 'cpus_2' + + tag {idPatient + "-" + idSample + "-" + intervalBed.baseName} + + input: + set idPatient, idSample, file(bam), file(bai), file(recalibrationReport), file(intervalBed) from bamApplyBQSR + file(dict) from ch_dict + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai + + output: + set idPatient, idSample, file("${intervalBed.baseName}_${idSample}.recal.bam") into bamMergeBamRecal + + script: + """ + gatk --java-options -Xmx${task.memory.toGiga()}g \ + ApplyBQSR \ + -R ${fasta} \ + --input ${bam} \ + --output ${intervalBed.baseName}_${idSample}.recal.bam \ + -L ${intervalBed} \ + --bqsr-recal-file ${recalibrationReport} + """ +} + +bamMergeBamRecal = bamMergeBamRecal.groupTuple(by:[0, 1]) -if (step == 'recalibrate' && params.sentieon) bamDedupedSentieon = inputSample +// STEP 4': SENTIEON BQSR bamDedupedSentieon = bamDedupedSentieon.dump(tag:'deduped.bam') @@ -1068,91 +1154,6 @@ bamRecalSentieonSampleTSV ["recalibrated_sentieon_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\n"] } -// STEP 3.5: MERGING RECALIBRATION TABLES - -process GatherBQSRReports { - label 'memory_singleCPU_2_task' - label 'cpus_2' - - tag {idPatient + "-" + idSample} - - publishDir "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked", mode: params.publishDirMode, overwrite: false - - input: - set idPatient, idSample, file(recal) from tableGatherBQSRReports - - output: - set idPatient, idSample, file("${idSample}.recal.table") into recalTable - set idPatient, idSample, val("${idSample}.md.bam"), val("${idSample}.md.bai"), val("${idSample}.recal.table") into (recalTableTSV, recalTableSampleTSV) - - when: step == 'mapping' - - script: - input = recal.collect{"-I ${it}"}.join(' ') - """ - gatk --java-options -Xmx${task.memory.toGiga()}g \ - GatherBQSRReports \ - ${input} \ - -O ${idSample}.recal.table \ - """ -} - -// Create TSV files to restart from this step -recalTableTSV.map { idPatient, idSample, bam, bai, recalTable -> - status = statusMap[idPatient, idSample] - gender = genderMap[idPatient] - "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bam}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bai}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${recalTable}\n" -}.collectFile( - name: 'duplicateMarked.tsv', sort: true, storeDir: "${params.outdir}/Preprocessing/TSV" -) - -recalTableSampleTSV - .collectFile(storeDir: "${params.outdir}/Preprocessing/TSV/") { - idPatient, idSample, bam, bai, recalTable -> - status = statusMap[idPatient, idSample] - gender = genderMap[idPatient] - ["duplicateMarked_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bam}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${bai}\t${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${recalTable}\n"] -} - -bamApplyBQSR = bamMDToJoin.join(recalTable, by:[0,1]) - -if (step == 'recalibrate' && (!params.sentieon)) bamApplyBQSR = inputSample - -bamApplyBQSR = bamApplyBQSR.dump(tag:'recal.table') - -bamApplyBQSR = bamApplyBQSR.combine(intApplyBQSR) - -// STEP 4: RECALIBRATING - -process ApplyBQSR { - label 'memory_singleCPU_2_task' - label 'cpus_2' - - tag {idPatient + "-" + idSample + "-" + intervalBed.baseName} - - input: - set idPatient, idSample, file(bam), file(bai), file(recalibrationReport), file(intervalBed) from bamApplyBQSR - file(dict) from ch_dict - file(fasta) from ch_fasta - file(fastaFai) from ch_fastaFai - - output: - set idPatient, idSample, file("${intervalBed.baseName}_${idSample}.recal.bam") into bamMergeBamRecal - - script: - """ - gatk --java-options -Xmx${task.memory.toGiga()}g \ - ApplyBQSR \ - -R ${fasta} \ - --input ${bam} \ - --output ${intervalBed.baseName}_${idSample}.recal.bam \ - -L ${intervalBed} \ - --bqsr-recal-file ${recalibrationReport} - """ -} - -bamMergeBamRecal = bamMergeBamRecal.groupTuple(by:[0, 1]) - // STEP 4.5: MERGING THE RECALIBRATED BAM FILES process MergeBamRecal { From 6f73d832c2427a1ed373ea1768cb7ebb78781ad0 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 12 Nov 2019 15:01:48 +0100 Subject: [PATCH 233/854] remove when statement --- main.nf | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/main.nf b/main.nf index d3e0a1d9d4..d701674b19 100644 --- a/main.nf +++ b/main.nf @@ -622,7 +622,7 @@ process FastQCFQ { output: file("*.{html,zip}") into fastQCFQReport - when: step == 'mapping' && !('fastqc' in skipQC) + when: !('fastqc' in skipQC) script: """ @@ -643,7 +643,7 @@ process FastQCBAM { output: file("*.{html,zip}") into fastQCBAMReport - when: step == 'mapping' && !('fastqc' in skipQC) + when: !('fastqc' in skipQC) script: """ @@ -678,8 +678,6 @@ process MapReads { set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam") into bamMapped set idPatient, idSample, file("${idSample}_${idRun}.bam") into bamMappedBamQC - when: step == 'mapping' - script: // -K is an hidden option, used to fix the number of reads processed by bwa mem // Chunk size can affect bwa results, if not specified, @@ -733,8 +731,6 @@ process SentieonMapReads { set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam") into bamMappedSentieon set idPatient, idSample, file("${idSample}_${idRun}.bam") into bamMappedSentieonBamQC - when: step == 'mapping' && params.sentieon - script: // -K is an hidden option, used to fix the number of reads processed by bwa mem // Chunk size can affect bwa results, if not specified, @@ -781,8 +777,6 @@ process MergeBamMapped { output: set idPatient, idSample, file("${idSample}.bam") into mergedBam - when: step == 'mapping' - script: """ samtools merge --threads ${task.cpus} ${idSample}.bam ${bam} @@ -812,8 +806,6 @@ process IndexBamMergedForSentieon { output: set idPatient, idSample, file(bam), file("${idSample}.bam.bai") into bamForSentieonDedup - when: step == 'mapping' - script: """ samtools index ${bam} @@ -840,8 +832,6 @@ process MarkDuplicates { set idPatient, idSample, file("${idSample}.md.bam"), file("${idSample}.md.bai") into duplicateMarkedBams file ("${idSample}.bam.metrics") into markDuplicatesReport - when: step == 'mapping' - script: markdup_java_options = task.memory.toGiga() > 8 ? params.markdup_java_options : "\"-Xms" + (task.memory.toGiga() / 2).trunc() + "g -Xmx" + (task.memory.toGiga() - 1) + "g\"" """ @@ -893,8 +883,6 @@ process SentieonDedup { set idPatient, idSample into bamDedupedSentieonTSV file("${idSample}_*.txt") into bamDedupedSentieonQC - when: step == 'mapping' && params.sentieon - script: """ sentieon driver -t ${task.cpus} -r ${fasta} -i ${bam} \ @@ -957,8 +945,6 @@ process BaseRecalibrator { output: set idPatient, idSample, file("${intervalBed.baseName}_${idSample}.recal.table") into tableGatherBQSRReports - when: step == 'mapping' - script: known = knownIndels.collect{"--known-sites ${it}"}.join(' ') // TODO: --use-original-qualities ??? @@ -995,8 +981,6 @@ process GatherBQSRReports { set idPatient, idSample, file("${idSample}.recal.table") into recalTable set idPatient, idSample, val("${idSample}.md.bam"), val("${idSample}.md.bai"), val("${idSample}.recal.table") into (recalTableTSV, recalTableSampleTSV) - when: step == 'mapping' - script: input = recal.collect{"-I ${it}"}.join(' ') """ @@ -1098,8 +1082,6 @@ process SentieonBQSR { set idPatient, idSample into bamRecalSentieonTSV file("${idSample}_recal_result.csv") into bamRecalSentieonQC - when: params.sentieon - script: known = knownIndels.collect{"--known-sites ${it}"}.join(' ') """ From b0f091e2a1c1a1132edd0f095f59fcfb1c5b6a38 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 12 Nov 2019 16:23:41 +0100 Subject: [PATCH 234/854] fix typo --- main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.nf b/main.nf index d701674b19..bb5b625021 100644 --- a/main.nf +++ b/main.nf @@ -2878,7 +2878,7 @@ def defineSkipQClist() { 'markduplicates', 'multiqc', 'samtools', - 'senteion', + 'sentieon', 'vcftools', 'versions' ] From 1aa82a947f94318406f953ccbf8d80d1bcdff4ca Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 12 Nov 2019 16:31:33 +0100 Subject: [PATCH 235/854] remove tsv for recalibrate with sentieon --- main.nf | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/main.nf b/main.nf index bb5b625021..0f2360ba31 100644 --- a/main.nf +++ b/main.nf @@ -193,7 +193,8 @@ if (params.sampleDir) tsvPath = params.sampleDir // only for steps recalibrate and variantCalling if (!params.input && step != 'mapping' && step != 'annotate') { if (params.sentieon) { - tsvPath = step == 'recalibrate' ? "${params.outdir}/Preprocessing/TSV/deduped_sentieon.tsv" : "${params.outdir}/Preprocessing/TSV/recalibrated_sentieon.tsv" + if (step == 'variantcalling') tsvPath = "${params.outdir}/Preprocessing/TSV/recalibrated_sentieon.tsv" + else exit 1, "Not possible to restart from that step" } else { tsvPath = step == 'recalibrate' ? "${params.outdir}/Preprocessing/TSV/duplicateMarked.tsv" : "${params.outdir}/Preprocessing/TSV/recalibrated.tsv" @@ -880,7 +881,6 @@ process SentieonDedup { output: set idPatient, idSample, file("${idSample}.deduped.bam"), file("${idSample}.deduped.bam.bai") into bamDedupedSentieon - set idPatient, idSample into bamDedupedSentieonTSV file("${idSample}_*.txt") into bamDedupedSentieonQC script: @@ -901,29 +901,6 @@ process SentieonDedup { """ } -(bamDedupedSentieonTSV, bamDedupedSentieonSampleTSV) = bamDedupedSentieonTSV.into(2) - -// Creating a TSV file to restart from this step -bamDedupedSentieonTSV.map { idPatient, idSample -> - gender = genderMap[idPatient] - status = statusMap[idPatient, idSample] - bam = "${params.outdir}/Preprocessing/${idSample}/DedupedSentieon/${idSample}.deduped.bam" - bai = "${params.outdir}/Preprocessing/${idSample}/DedupedSentieon/${idSample}.deduped.bam.bai" - "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\n" -}.collectFile( - name: 'deduped_sentieon.tsv', sort: true, storeDir: "${params.outdir}/Preprocessing/TSV" -) - -bamDedupedSentieonSampleTSV - .collectFile(storeDir: "${params.outdir}/Preprocessing/TSV") { - idPatient, idSample -> - status = statusMap[idPatient, idSample] - gender = genderMap[idPatient] - bam = "${params.outdir}/Preprocessing/${idSample}/DedupedSentieon/${idSample}.deduped.bam" - bai = "${params.outdir}/Preprocessing/${idSample}/DedupedSentieon/${idSample}.deduped.bam.bai" - ["deduped_sentieon_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\n"] -} - // STEP 3: CREATING RECALIBRATION TABLES process BaseRecalibrator { @@ -1010,10 +987,7 @@ recalTableSampleTSV bamApplyBQSR = bamMDToJoin.join(recalTable, by:[0,1]) -if (step == 'recalibrate') { - if (params.sentieon) bamDedupedSentieon = inputSample - else bamApplyBQSR = inputSample -} +if (step == 'recalibrate') bamApplyBQSR = inputSample bamApplyBQSR = bamApplyBQSR.dump(tag:'recal.table') From bbe01fb1e1409187b45da20c37b09efb308bc1fc Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 12 Nov 2019 16:59:10 +0100 Subject: [PATCH 236/854] add dnascope dnaseq --- main.nf | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/main.nf b/main.nf index 0f2360ba31..7269cc8d54 100644 --- a/main.nf +++ b/main.nf @@ -1231,7 +1231,7 @@ bamRecal = bamRecal.dump(tag:'BAM') // Manta will be run in Germline mode, or in Tumor mode depending on status // HaplotypeCaller, TIDDIT and Strelka will be run for Normal and Tumor samples -(bamMantaSingle, bamStrelkaSingle, bamTIDDIT, bamRecalAll, bamRecalAllTemp) = bamRecal.into(5) +(bamSentieonDNAscope, bamSentieonDNAseq, bamMantaSingle, bamStrelkaSingle, bamTIDDIT, bamRecalAll, bamRecalAllTemp) = bamRecal.into(7) // To speed Variant Callers up we are chopping the reference into smaller pieces // Do variant calling by this intervals, and re-merge the VCFs @@ -1314,6 +1314,92 @@ process GenotypeGVCFs { vcfGenotypeGVCFs = vcfGenotypeGVCFs.groupTuple(by:[0, 1, 2]) +// STEP SENTIEON DNAseq + +process SentieonDNAseq { + label 'cpus_max' + label 'memory_max' + label 'sentieon' + + tag {idSample} + + input: + set idPatient, idSample, file(bam), file(bai) from bamSentieonDNAseq + file(dbsnp) from ch_dbsnp + file(dbsnpIndex) from ch_dbsnpIndex + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai + + output: + set val("SentieonDNAseq"), idPatient, idSample, file("DNAseq_${idSample}.vcf") into sentieonDNAseqVCF + + when: 'dnaseq' in tools && params.sentieon + + script: + """ + sentieon driver \ + -t ${task.cpus} \ + -r ${fasta} \ + -i ${bam} \ + --algo Genotyper \ + -d ${dbsnp} \ + DNAseq_${idSample}.vcf + """ +} + +sentieonDNAseqVCF = sentieonDNAseqVCF.dump(tag:'sentieon DNAseq') + +// STEP SENTIEON DNAscope + +process SentieonDNAscope { + label 'cpus_max' + label 'memory_max' + label 'sentieon' + + tag {idSample} + + input: + set idPatient, idSample, file(bam), file(bai) from bamSentieonDNAscope + file(dbsnp) from ch_dbsnp + file(dbsnpIndex) from ch_dbsnpIndex + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai + + output: + set val("SentieonDNAscope"), idPatient, idSample, file("DNAscope_${idSample}.vcf"), file("DNAscope_SV_${idSample}.vcf") into sentieonDNAscopeVCF + + when: 'dnascope' in tools && params.sentieon + + script: + """ + sentieon driver \ + -t ${task.cpus} \ + -r ${fasta} \ + -i ${bam} \ + --algo DNAscope \ + -d ${dbsnp} \ + DNAscope_${idSample}.vcf + + sentieon driver \ + -t ${task.cpus} \ + -r ${fasta}\ + -i ${bam} \ + --algo DNAscope + --var_type bnd \ + -d ${dbsnp} + DNAscope_${idSample}.temp.vcf + + sentieon driver \ + -t ${task.cpus} \ + -r ${fasta}\ + --algo SVSolver \ + -v DNAscope_${idSample}.temp.vcf \ + DNAscope_SV_${idSample}.vcf + """ +} + +sentieonDNAscopeVCF = sentieonDNAscopeVCF.dump(tag:'sentieon DNAscope') + // STEP STRELKA.1 - SINGLE MODE process StrelkaSingle { From 2d980d8d183d16014b9e34d870da94f54a8521a6 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 12 Nov 2019 17:06:37 +0100 Subject: [PATCH 237/854] fix dnascope --- main.nf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main.nf b/main.nf index 7269cc8d54..38d7e2b81a 100644 --- a/main.nf +++ b/main.nf @@ -1384,15 +1384,15 @@ process SentieonDNAscope { -t ${task.cpus} \ -r ${fasta}\ -i ${bam} \ - --algo DNAscope + --algo DNAscope \ --var_type bnd \ - -d ${dbsnp} + -d ${dbsnp} \ DNAscope_${idSample}.temp.vcf sentieon driver \ -t ${task.cpus} \ -r ${fasta}\ - --algo SVSolver \ + --algo SVSolver \ -v DNAscope_${idSample}.temp.vcf \ DNAscope_SV_${idSample}.vcf """ From f67f8f35851183357022989414614e75f7a8d4a0 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 13 Nov 2019 14:10:58 +0100 Subject: [PATCH 238/854] add TNscope process --- main.nf | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/main.nf b/main.nf index 38d7e2b81a..45b91c0d34 100644 --- a/main.nf +++ b/main.nf @@ -871,7 +871,7 @@ process SentieonDedup { saveAs: { if (it == "${idSample}_*.txt" && 'sentieon' in skipQC) null else if (it == "${idSample}_*.txt") "Reports/${idSample}/Sentieon/${it}" - else "Preprocessing/${idSample}/DedupedSentieon/${it}" + else null } input: @@ -885,18 +885,28 @@ process SentieonDedup { script: """ - sentieon driver -t ${task.cpus} -r ${fasta} -i ${bam} \ + sentieon driver \ + -t ${task.cpus} \ + -i ${bam} \ + -r ${fasta} \ --algo GCBias --summary ${idSample}_gc_summary.txt ${idSample}_gc_metric.txt \ --algo MeanQualityByCycle ${idSample}_mq_metric.txt \ --algo QualDistribution ${idSample}_qd_metric.txt \ --algo InsertSizeMetricAlgo ${idSample}_is_metric.txt \ --algo AlignmentStat ${idSample}_aln_metric.txt - sentieon driver -t ${task.cpus} -i ${bam} \ - --algo LocusCollector --fun score_info ${idSample}_score.gz + sentieon driver \ + -t ${task.cpus} \ + -i ${bam} \ + --algo LocusCollector \ + --fun score_info ${idSample}_score.gz - sentieon driver -t ${task.cpus} -i ${bam} \ - --algo Dedup --rmdup --score_info ${idSample}_score.gz \ + sentieon driver \ + -t ${task.cpus} \ + -i ${bam} \ + --algo Dedup \ + --rmdup \ + --score_info ${idSample}_score.gz \ --metrics ${idSample}_dedup_metric.txt ${idSample}.deduped.bam """ } @@ -1323,6 +1333,8 @@ process SentieonDNAseq { tag {idSample} + publishDir "${params.outdir}/VariantCalling/${idSample}/SentieonDNAseq", mode: params.publishDirMode + input: set idPatient, idSample, file(bam), file(bai) from bamSentieonDNAseq file(dbsnp) from ch_dbsnp @@ -1358,6 +1370,8 @@ process SentieonDNAscope { tag {idSample} + publishDir "${params.outdir}/VariantCalling/${idSample}/SentieonDNAscope", mode: params.publishDirMode + input: set idPatient, idSample, file(bam), file(bai) from bamSentieonDNAscope file(dbsnp) from ch_dbsnp @@ -1566,8 +1580,8 @@ pairBam = bamNormal.cross(bamTumor).map { pairBam = pairBam.dump(tag:'BAM Somatic Pair') -// Manta and Strelka -(pairBamManta, pairBamStrelka, pairBamStrelkaBP, pairBamCalculateContamination, pairBamFilterMutect2, pairBam) = pairBam.into(6) +// Manta, Strelka, Mutect2 +(pairBamManta, pairBamStrelka, pairBamStrelkaBP, pairBamCalculateContamination, pairBamFilterMutect2, pairBamTNscope, pairBam) = pairBam.into(7) intervalPairBam = pairBam.spread(bedIntervals) @@ -1867,6 +1881,47 @@ process FilterMutect2Calls { """ } +// STEP SENTIEON TNSCOPE + +process SentieonTNscope { + label 'cpus_max' + label 'memory_max' + label 'sentieon' + + tag {idSampleTumor + "_vs_" + idSampleNormal} + + publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/SentieonTNscope", mode: params.publishDirMode + + input: + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor) from pairBamTNscope + file(dict) from ch_dict + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai + file(dbsnp) from ch_dbsnp + file(dbsnpIndex) from ch_dbsnpIndex + + output: + set val("SentieonTNscope"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into vcfTNscope + + when: 'tnscope' in tools + + script: + """ + sentieon driver \ + -t ${task.cpus} \ + -r ${fasta} \ + -i ${bamTumor} \ + -i ${bamNormal} \ + --algo TNscope \ + --tumor_sample ${idSampleTumor} \ + --normal_sample ${idSampleNormal} \ + --dbsnp ${dbsnp} \ + SentieonTNscope_${idSampleTumor}_vs_${idSampleNormal}.vcf + """ +} + +vcfTNscope = vcfTNscope.dump(tag:'SentieonTNscope') + // STEP STRELKA.2 - SOMATIC PAIR process Strelka { From 9d6c76ee8d2a0da1ce62de6d3e70f52cae9a656b Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 13 Nov 2019 14:13:01 +0100 Subject: [PATCH 239/854] fix TNscope output --- main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.nf b/main.nf index 45b91c0d34..464f47605b 100644 --- a/main.nf +++ b/main.nf @@ -1901,7 +1901,7 @@ process SentieonTNscope { file(dbsnpIndex) from ch_dbsnpIndex output: - set val("SentieonTNscope"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf.gz"), file("*.vcf.gz.tbi") into vcfTNscope + set val("SentieonTNscope"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf") into vcfTNscope when: 'tnscope' in tools From 0aa8ebea42ff458e4de47bb32ac192e6b92a4970 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 13 Nov 2019 15:18:03 +0100 Subject: [PATCH 240/854] add pon for TNscope --- main.nf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/main.nf b/main.nf index 464f47605b..12289b6f57 100644 --- a/main.nf +++ b/main.nf @@ -1899,6 +1899,7 @@ process SentieonTNscope { file(fastaFai) from ch_fastaFai file(dbsnp) from ch_dbsnp file(dbsnpIndex) from ch_dbsnpIndex + file(pon) from ch_pon output: set val("SentieonTNscope"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf") into vcfTNscope @@ -1906,6 +1907,7 @@ process SentieonTNscope { when: 'tnscope' in tools script: + PON = params.pon ? "--pon ${pon}" : "" """ sentieon driver \ -t ${task.cpus} \ @@ -1916,6 +1918,7 @@ process SentieonTNscope { --tumor_sample ${idSampleTumor} \ --normal_sample ${idSampleNormal} \ --dbsnp ${dbsnp} \ + ${PON} \ SentieonTNscope_${idSampleTumor}_vs_${idSampleNormal}.vcf """ } From 10ad68729a0c9a2f7e75ff81d587114cbc38ba28 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 13 Nov 2019 15:29:54 +0100 Subject: [PATCH 241/854] add params.pon_index --- main.nf | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/main.nf b/main.nf index 12289b6f57..a7259085da 100644 --- a/main.nf +++ b/main.nf @@ -64,6 +64,8 @@ def helpMessage() { --annotation_cache Enable the use of cache for annotation, to be used with --snpEff_cache and/or --vep_cache --snpEff_cache Specity the path to snpEff cache, to be used with --annotation_cache --vep_cache Specity the path to VEP cache, to be used with --annotation_cache + --pon panel-of-normals VCF (bgzipped, indexed). See: https://software.broadinstitute.org/gatk/documentation/tooldocs/current/org_broadinstitute_hellbender_tools_walkers_mutect_CreateSomaticPanelOfNormals.php + --pon_index index of pon panel-of-normals VCF References If not specified in the configuration file or you wish to overwrite any of the references. --acLoci acLoci file @@ -87,7 +89,6 @@ def helpMessage() { --monochrome_logs Logs will be without colors --email 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 --maxMultiqcEmailFileSize Theshold size for MultiQC report to be attached in notification email. If file generated by pipeline exceeds the threshold, it will not be attached (Default: 25MB) - --pon panel-of-normals VCF (bgzipped, indexed). See: https://software.broadinstitute.org/gatk/documentation/tooldocs/current/org_broadinstitute_hellbender_tools_walkers_mutect_CreateSomaticPanelOfNormals.php -name Name for the pipeline run. If not specified, Nextflow will automatically generate a random mnemonic AWSBatch options: @@ -500,6 +501,26 @@ process BuildKnownIndelsIndex { """ } +process BuildPonIndex { + tag {pon} + + publishDir params.outdir, mode: params.publishDirMode, + saveAs: {params.saveGenomeIndex ? "reference_genome/${it}" : null } + + input: + file(pon) from ch_pon + + output: + file("${pon}.tbi") into ponIndexBuilt + + when: !(params.ponIndex) && params.pon && ('tnscope' in tools || 'mutect2' in tools) + + script: + """ + tabix -p vcf ${pon} + """ +} + // Initialize channels based on params or indexes that were just built ch_bwaIndex = params.bwaIndex ? Channel.value(file(params.bwaIndex)) : bwaIndexes ch_dbsnpIndex = params.dbsnpIndex ? Channel.value(file(params.dbsnpIndex)) : dbsnpIndexBuilt @@ -507,6 +528,7 @@ ch_dict = params.dict ? Channel.value(file(params.dict)) : dictBuilt ch_fastaFai = params.fastaFai ? Channel.value(file(params.fastaFai)) : fastaFaiBuilt ch_germlineResourceIndex = params.germlineResourceIndex ? Channel.value(file(params.germlineResourceIndex)) : germlineResourceIndexBuilt ch_knownIndelsIndex = params.knownIndelsIndex ? Channel.value(file(params.knownIndelsIndex)) : knownIndelsIndexBuilt.collect() +ch_ponIndex = params.ponIndex ? Channel.value(file(params.ponIndex)) : ponIndexBuilt /* ================================================================================ @@ -1641,6 +1663,8 @@ process Mutect2 { file(germlineResourceIndex) from ch_germlineResourceIndex file(intervals) from ch_intervals file(pon) from ch_pon + file(ponIndex) from ch_ponIndex + file(ponIndex) from ch_ponIndex output: set val("Mutect2"), @@ -1900,6 +1924,7 @@ process SentieonTNscope { file(dbsnp) from ch_dbsnp file(dbsnpIndex) from ch_dbsnpIndex file(pon) from ch_pon + file(ponIndex) from ch_ponIndex output: set val("SentieonTNscope"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf") into vcfTNscope From 03332fc6a5600c0e39781953729aa55ef882fc19 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 13 Nov 2019 16:23:45 +0100 Subject: [PATCH 242/854] add annotation for sention DNAseq, DNAscope, TNscope --- main.nf | 46 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/main.nf b/main.nf index a7259085da..28bb3adfdd 100644 --- a/main.nf +++ b/main.nf @@ -1402,7 +1402,8 @@ process SentieonDNAscope { file(fastaFai) from ch_fastaFai output: - set val("SentieonDNAscope"), idPatient, idSample, file("DNAscope_${idSample}.vcf"), file("DNAscope_SV_${idSample}.vcf") into sentieonDNAscopeVCF + set val("SentieonDNAscope"), idPatient, idSample, file("DNAscope_${idSample}.vcf") into sentieonDNAscopeVCF + set val("SentieonDNAscope"), idPatient, idSample, file("DNAscope_SV_${idSample}.vcf") into sentieonDNAscopeSVVCF when: 'dnascope' in tools && params.sentieon @@ -1435,6 +1436,7 @@ process SentieonDNAscope { } sentieonDNAscopeVCF = sentieonDNAscopeVCF.dump(tag:'sentieon DNAscope') +sentieonDNAscopeSVVCF = sentieonDNAscopeSVVCF.dump(tag:'sentieon DNAscope SV') // STEP STRELKA.1 - SINGLE MODE @@ -1948,7 +1950,29 @@ process SentieonTNscope { """ } -vcfTNscope = vcfTNscope.dump(tag:'SentieonTNscope') +vcfTNscope = vcfTNscope.dump(tag:'Sentieon TNscope') + +sentieonVCF = sentieonDNAseqVCF.mix(sentieonDNAscopeVCF, sentieonDNAscopeSVVCF, vcfTNscope) + +process CompressSentieonVCF { + tag {"${idSample} - ${vcf}"} + + publishDir "${params.outdir}/VariantCalling/${idSample}/${variantCaller}", mode: params.publishDirMode + + input: + set variantCaller, idPatient, idSample, file(vcf) from sentieonVCF + + output: + set variantCaller, idPatient, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into vcfSentieon + + script: + """ + bgzip < ${vcf} > ${vcf}.gz + tabix ${vcf}.gz + """ +} + +vcfSentieon = vcfSentieon.dump(tag:'Sentieon VCF indexed') // STEP STRELKA.2 - SOMATIC PAIR @@ -2387,6 +2411,10 @@ controlFreecVizOut.dump(tag:'ControlFreecViz') (vcfMantaSomaticSV, vcfMantaDiploidSV) = vcfManta.into(2) vcfKeep = Channel.empty().mix( + vcfSentieon.map { + variantcaller, idPatient, idSample, vcf, tbi -> + [variantcaller, idSample, vcf + }, vcfStrelkaSingle.map { variantcaller, idPatient, idSample, vcf, tbi -> [variantcaller, idSample, vcf[1]] @@ -2506,13 +2534,19 @@ if (step == 'annotate') { // This field is used to output final annotated VCFs in the correct directory Channel.empty().mix( Channel.fromPath("${params.outdir}/VariantCalling/*/HaplotypeCaller/*.vcf.gz") - .flatten().map{vcf -> ['haplotypecaller', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, + .flatten().map{vcf -> ['HaplotypeCaller', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, Channel.fromPath("${params.outdir}/VariantCalling/*/Manta/*[!candidate]SV.vcf.gz") - .flatten().map{vcf -> ['manta', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, + .flatten().map{vcf -> ['Manta', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, Channel.fromPath("${params.outdir}/VariantCalling/*/Mutect2/*.vcf.gz") - .flatten().map{vcf -> ['mutect2', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, + .flatten().map{vcf -> ['Mutect2', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, + Channel.fromPath("${params.outdir}/VariantCalling/*/SentieonDNAseq/*.vcf.gz") + .flatten().map{vcf -> ['SentieonDNAseq', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, + Channel.fromPath("${params.outdir}/VariantCalling/*/SentieonDNAscope/*.vcf.gz") + .flatten().map{vcf -> ['SentieonDNAscope', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, + Channel.fromPath("${params.outdir}/VariantCalling/*/SentieonTNscope/*.vcf.gz") + .flatten().map{vcf -> ['SentieonTNscope', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, Channel.fromPath("${params.outdir}/VariantCalling/*/Strelka/*{somatic,variant}*.vcf.gz") - .flatten().map{vcf -> ['strelka', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, + .flatten().map{vcf -> ['Strelka', vcf.minus(vcf.fileName)[-2].toString(), vcf]}, Channel.fromPath("${params.outdir}/VariantCalling/*/TIDDIT/*.vcf.gz") .flatten().map{vcf -> ['TIDDIT', vcf.minus(vcf.fileName)[-2].toString(), vcf]} ).choice(vcfToAnnotate, vcfNoAnnotate) { From afc5046f54c235ba013e94b8a76e7a838ea39313 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 13 Nov 2019 16:23:57 +0100 Subject: [PATCH 243/854] add default pon_index --- nextflow.config | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/nextflow.config b/nextflow.config index a39be4f66a..09b2ae03eb 100644 --- a/nextflow.config +++ b/nextflow.config @@ -31,11 +31,12 @@ params { sentieon = null // Not using Sentieon by default // Optional files/directory - cadd_InDels = false // No CADD files - cadd_InDels_tbi = false // No CADD files - cadd_WG_SNVs = false // No CADD files - cadd_WG_SNVs_tbi = false // No CADD files - pon = false // No default PON file for GATK Mutect2 Panel of Normal + cadd_InDels = false // No CADD InDels file + cadd_InDels_tbi = false // No CADD InDels index + cadd_WG_SNVs = false // No CADD SNVs file + cadd_WG_SNVs_tbi = false // No CADD SNVs index + pon = false // No default PON (Panel of Normals) file for GATK Mutect2 / Sentieon TNscope + pon_index = false // No default PON index for GATK Mutect2 / Sentieon TNscope snpEff_cache = null // No directory for snpEff cache targetBED = false // No default TargetBED file for targeted sequencing vep_cache = null // No directory for VEP cache From dd7c1f8a868b8eea4312f7ae21574b740344c9c5 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 13 Nov 2019 16:25:26 +0100 Subject: [PATCH 244/854] typo --- main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.nf b/main.nf index 28bb3adfdd..7a08e43082 100644 --- a/main.nf +++ b/main.nf @@ -2413,7 +2413,7 @@ controlFreecVizOut.dump(tag:'ControlFreecViz') vcfKeep = Channel.empty().mix( vcfSentieon.map { variantcaller, idPatient, idSample, vcf, tbi -> - [variantcaller, idSample, vcf + [variantcaller, idSample, vcf] }, vcfStrelkaSingle.map { variantcaller, idPatient, idSample, vcf, tbi -> From 0c29e692bc98508c3a639b072c83990dedb548fd Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 13 Nov 2019 16:36:53 +0100 Subject: [PATCH 245/854] fix typo --- main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.nf b/main.nf index 7a08e43082..4a4a994ce1 100644 --- a/main.nf +++ b/main.nf @@ -223,7 +223,7 @@ if (tsvPath) { } tsvFile = params.input // used in the reports } else if (step == 'annotate') { - log.info "Annotating ${tsvFile}" + log.info "Annotating ${tsvPath}" } else exit 1, 'No sample were defined, see --help' (genderMap, statusMap, inputSample) = extractInfos(inputSample) From 2fe67d5b0ff289896c0530e63a8baf079a27a116 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 13 Nov 2019 16:40:56 +0100 Subject: [PATCH 246/854] improve automatic annotation --- main.nf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/main.nf b/main.nf index 4a4a994ce1..ff169f7444 100644 --- a/main.nf +++ b/main.nf @@ -222,8 +222,10 @@ if (tsvPath) { if (it.size() == 0) exit 1, "No FASTQ files found in --input directory '${params.input}'" } tsvFile = params.input // used in the reports -} else if (step == 'annotate') { +} else if (tsvPath && step == 'annotate') { log.info "Annotating ${tsvPath}" +} else if (step == 'annotate') { + log.info "Trying automatic annotation on file in the VariantCalling directory" } else exit 1, 'No sample were defined, see --help' (genderMap, statusMap, inputSample) = extractInfos(inputSample) From 2bbc127db7e466980605b8a729f1154bd3f645e4 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 13 Nov 2019 17:28:32 +0100 Subject: [PATCH 247/854] typo --- main.nf | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/main.nf b/main.nf index ff169f7444..7b67208e09 100644 --- a/main.nf +++ b/main.nf @@ -315,6 +315,9 @@ if (params.knownIndels) summary['knownIndels'] = params.know if (params.knownIndelsIndex) summary['knownIndelsIndex'] = params.knownIndelsIndex if (params.snpeffDb) summary['snpeffDb'] = params.snpeffDb if (params.vepCacheVersion) summary['vepCacheVersion'] = params.vepCacheVersion +if (params.species) summary['species'] = params.species +if (params.snpEff_cache) summary['snpEff_cache'] = params.snpEff_cache +if (params.vep_cache) summary['vep_cache'] = params.vep_cache if (workflow.profile == 'awsbatch') { summary['AWS Region'] = params.awsregion @@ -515,7 +518,7 @@ process BuildPonIndex { output: file("${pon}.tbi") into ponIndexBuilt - when: !(params.ponIndex) && params.pon && ('tnscope' in tools || 'mutect2' in tools) + when: !(params.pon_index) && params.pon && ('tnscope' in tools || 'mutect2' in tools) script: """ @@ -530,7 +533,7 @@ ch_dict = params.dict ? Channel.value(file(params.dict)) : dictBuilt ch_fastaFai = params.fastaFai ? Channel.value(file(params.fastaFai)) : fastaFaiBuilt ch_germlineResourceIndex = params.germlineResourceIndex ? Channel.value(file(params.germlineResourceIndex)) : germlineResourceIndexBuilt ch_knownIndelsIndex = params.knownIndelsIndex ? Channel.value(file(params.knownIndelsIndex)) : knownIndelsIndexBuilt.collect() -ch_ponIndex = params.ponIndex ? Channel.value(file(params.ponIndex)) : ponIndexBuilt +ch_ponIndex = params.pon_index ? Channel.value(file(params.pon_index)) : ponIndexBuilt /* ================================================================================ @@ -2530,7 +2533,7 @@ if (step == 'annotate') { if (tsvPath == []) { // Sarek, by default, annotates all available vcfs that it can find in the VariantCalling directory // Excluding vcfs from FreeBayes, and g.vcf from HaplotypeCaller - // Basically it's: VariantCalling/*/{HaplotypeCaller,Manta,Mutect2,Strelka,TIDDIT}/*.vcf.gz + // Basically it's: results/VariantCalling/*/{HaplotypeCaller,Manta,Mutect2,SentieonDNAseq,SentieonDNAscope,SentieonTNscope,Strelka,TIDDIT}/*.vcf.gz // Without *SmallIndels.vcf.gz from Manta, and *.genome.vcf.gz from Strelka // The small snippet `vcf.minus(vcf.fileName)[-2]` catches idSample // This field is used to output final annotated VCFs in the correct directory From 66276c37b3b27864ca3a815b4ea54e29b58eede7 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 13 Nov 2019 17:30:38 +0100 Subject: [PATCH 248/854] typo --- main.nf | 1 - 1 file changed, 1 deletion(-) diff --git a/main.nf b/main.nf index 7b67208e09..117ccf171f 100644 --- a/main.nf +++ b/main.nf @@ -1671,7 +1671,6 @@ process Mutect2 { file(intervals) from ch_intervals file(pon) from ch_pon file(ponIndex) from ch_ponIndex - file(ponIndex) from ch_ponIndex output: set val("Mutect2"), From fc27dd064a0accb0d085642a65192a8445491568 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 13 Nov 2019 17:44:16 +0100 Subject: [PATCH 249/854] add condition on when statement on TNscope --- main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.nf b/main.nf index 117ccf171f..f54d4be675 100644 --- a/main.nf +++ b/main.nf @@ -1935,7 +1935,7 @@ process SentieonTNscope { output: set val("SentieonTNscope"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("*.vcf") into vcfTNscope - when: 'tnscope' in tools + when: 'tnscope' in tools && params.sentieon script: PON = params.pon ? "--pon ${pon}" : "" From 6d9124740ae798c8e94ff4506277586b6bcfde4a Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Thu, 14 Nov 2019 10:32:17 +0100 Subject: [PATCH 250/854] clean up --- main.nf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.nf b/main.nf index f54d4be675..908da73e68 100644 --- a/main.nf +++ b/main.nf @@ -207,7 +207,7 @@ if (tsvPath) { tsvFile = file(tsvPath) switch (step) { case 'mapping': inputSample = extractFastq(tsvFile); break - case 'recalibrate': inputSample = params.sentieon ? extractBam(tsvFile) : extractRecal(tsvFile) ; break + case 'recalibrate': inputSample = extractRecal(tsvFile) ; break case 'variantcalling': inputSample = extractBam(tsvFile); break case 'annotate': break default: exit 1, "Unknown step ${step}" @@ -1257,7 +1257,7 @@ bamQCReport = bamQCReport.dump(tag:'BamQC') ================================================================================ */ -if (params.sentieon && step in ['mapping', 'recalibrate']) bamRecal = bamRecalSentieon +if (params.sentieon && step == 'mapping') bamRecal = bamRecalSentieon if (step == 'variantcalling') bamRecal = inputSample From c23306bf55c1bd1ce370f498860866a371094d41 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Thu, 14 Nov 2019 10:34:05 +0100 Subject: [PATCH 251/854] code polish --- main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.nf b/main.nf index 908da73e68..3734b855a7 100644 --- a/main.nf +++ b/main.nf @@ -207,7 +207,7 @@ if (tsvPath) { tsvFile = file(tsvPath) switch (step) { case 'mapping': inputSample = extractFastq(tsvFile); break - case 'recalibrate': inputSample = extractRecal(tsvFile) ; break + case 'recalibrate': inputSample = extractRecal(tsvFile); break case 'variantcalling': inputSample = extractBam(tsvFile); break case 'annotate': break default: exit 1, "Unknown step ${step}" From 0003194e294463b255cab2551bfc3fcf6da5e21d Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Thu, 14 Nov 2019 11:15:13 +0100 Subject: [PATCH 252/854] enable filter Mutect2calls without pon --- main.nf | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/main.nf b/main.nf index 052b7fb26b..6253951691 100644 --- a/main.nf +++ b/main.nf @@ -323,6 +323,8 @@ log.info summary.collect { k, v -> "${k.padRight(18)}: $v" }.join("\n") if (params.monochrome_logs) log.info "----------------------------------------------------" else log.info "\033[2m----------------------------------------------------\033[0m" +if ('mutect2' in tools && !(params.pon)) log.warn "[nf-core/sarek] Mutect2 was requested, but as no panel of normals were given, results will not be optimal" + // Check the hostnames against configured profiles checkHostname() @@ -1430,7 +1432,7 @@ process ConcatVCF { if (variantCaller == 'HaplotypeCallerGVCF') outputFile = "HaplotypeCaller_${idSample}.g.vcf" else if (variantCaller == "Mutect2") - outputFile = "unfiltered_${variantCaller}_${idSample}.vcf" + outputFile = "Mutect2_unfiltered_${idSample}.vcf" else outputFile = "${variantCaller}_${idSample}.vcf" options = params.targetBED ? "-t ${targetBED}" : "" @@ -1459,7 +1461,7 @@ process PileupSummariesForMutect2 { idSampleTumor, file("${intervalBed.baseName}_${idSampleTumor}_pileupsummaries.table") into pileupSummaries - when: 'mutect2' in tools && params.pon + when: 'mutect2' in tools script: """ @@ -1518,7 +1520,7 @@ process CalculateContamination { output: file("${idSampleTumor}_contamination.table") into contaminationTable - when: 'mutect2' in tools && params.pon + when: 'mutect2' in tools script: """ @@ -1537,7 +1539,7 @@ process FilterMutect2Calls { tag {idSampleTN} - publishDir "${params.outdir}/VariantCalling/${idSampleTN}/${"$variantCaller"}", mode: params.publishDirMode + publishDir "${params.outdir}/VariantCalling/${idSampleTN}/Mutect2", mode: params.publishDirMode input: set variantCaller, idPatient, idSampleTN, file(unfiltered), file(unfilteredIndex) from vcfConcatenatedForFilter @@ -1552,11 +1554,11 @@ process FilterMutect2Calls { output: set val("Mutect2"), idPatient, idSampleTN, - file("filtered_${variantCaller}_${idSampleTN}.vcf.gz"), - file("filtered_${variantCaller}_${idSampleTN}.vcf.gz.tbi"), - file("filtered_${variantCaller}_${idSampleTN}.vcf.gz.filteringStats.tsv") into filteredMutect2Output + file("${variantCaller}_filtered_${idSampleTN}.vcf.gz"), + file("${variantCaller}_filtered_${idSampleTN}.vcf.gz.tbi"), + file("${variantCaller}_filtered_${idSampleTN}.vcf.gz.filteringStats.tsv") into filteredMutect2Output - when: 'mutect2' in tools && params.pon + when: 'mutect2' in tools script: """ @@ -1567,7 +1569,7 @@ process FilterMutect2Calls { --contamination-table ${idSampleTN}_contamination.table \ --stats ${idSampleTN}.vcf.gz.stats \ -R ${fasta} \ - -O filtered_${variantCaller}_${idSampleTN}.vcf.gz + -O ${variantCaller}_filtered_${idSampleTN}.vcf.gz """ } From 07e8502cb093cba1406f3ca73db847ff6eb6aa14 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 15 Nov 2019 10:45:23 +0100 Subject: [PATCH 253/854] add CODEOWNERS file --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000000..04c39ab2b5 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @MaxUlysse \ No newline at end of file From a85b9be8ba8d935d7d5203db6472377640c25c93 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 18 Nov 2019 17:00:56 +0100 Subject: [PATCH 254/854] add when statement on all sentieon processes with params.sentieon --- main.nf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/main.nf b/main.nf index 3734b855a7..dd03f8fadc 100644 --- a/main.nf +++ b/main.nf @@ -759,6 +759,8 @@ process SentieonMapReads { set idPatient, idSample, idRun, file("${idSample}_${idRun}.bam") into bamMappedSentieon set idPatient, idSample, file("${idSample}_${idRun}.bam") into bamMappedSentieonBamQC + when: params.sentieon + script: // -K is an hidden option, used to fix the number of reads processed by bwa mem // Chunk size can affect bwa results, if not specified, @@ -910,6 +912,8 @@ process SentieonDedup { set idPatient, idSample, file("${idSample}.deduped.bam"), file("${idSample}.deduped.bam.bai") into bamDedupedSentieon file("${idSample}_*.txt") into bamDedupedSentieonQC + when: params.sentieon + script: """ sentieon driver \ @@ -1093,6 +1097,8 @@ process SentieonBQSR { set idPatient, idSample into bamRecalSentieonTSV file("${idSample}_recal_result.csv") into bamRecalSentieonQC + when: params.sentieon + script: known = knownIndels.collect{"--known-sites ${it}"}.join(' ') """ @@ -1969,6 +1975,8 @@ process CompressSentieonVCF { output: set variantCaller, idPatient, idSample, file("*.vcf.gz"), file("*.vcf.gz.tbi") into vcfSentieon + when: params.sentieon + script: """ bgzip < ${vcf} > ${vcf}.gz From b84cbc4be780afdddaf4e6b1d16c2a55c4dc939a Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 20 Nov 2019 10:12:17 +0100 Subject: [PATCH 255/854] remove munin sentieon specific configs from config --- conf/base.config | 4 ---- 1 file changed, 4 deletions(-) diff --git a/conf/base.config b/conf/base.config index 3eeac179f5..5c76d275e6 100644 --- a/conf/base.config +++ b/conf/base.config @@ -75,8 +75,4 @@ process { container = {(params.annotation_cache && params.vep_cache) ? 'nfcore/sarek:dev' : "nfcore/sarekvep:dev.${params.genome}"} errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} } - withLabel:sentieon { - beforeScript = {params.sentieon ? 'module load sentieon/201808.05' : ''} - container = {params.sentieon ? '' : 'nfcore/sarek:dev'} - } } From 38d113e2d5de4750849ece63ec33e380abd94e31 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 20 Nov 2019 10:12:30 +0100 Subject: [PATCH 256/854] load sarek specific config --- nextflow.config | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/nextflow.config b/nextflow.config index 09b2ae03eb..49d37893cf 100644 --- a/nextflow.config +++ b/nextflow.config @@ -100,6 +100,13 @@ try { System.err.println("WARNING: Could not load nf-core/config profiles: ${params.custom_config_base}/nfcore_custom.config") } +// Load nf-core/sarek custom profiles from different Institutions +try { + includeConfig "${params.custom_config_base}/pipeline/nfcore_custom_sarek.config" +} catch (Exception e) { + System.err.println("WARNING: Could not load nf-core/config/sarek profiles: ${params.custom_config_base}/pipeline/nfcore_custom_sarek.config") +} + profiles { awsbatch { includeConfig 'conf/awsbatch.config' } conda { From daaf48f947f13ef31d2c2c215e3ecd62ca99e668 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 20 Nov 2019 14:03:34 +0100 Subject: [PATCH 257/854] update path to specific config --- nextflow.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nextflow.config b/nextflow.config index 49d37893cf..2789042979 100644 --- a/nextflow.config +++ b/nextflow.config @@ -102,9 +102,9 @@ try { // Load nf-core/sarek custom profiles from different Institutions try { - includeConfig "${params.custom_config_base}/pipeline/nfcore_custom_sarek.config" + includeConfig "${params.custom_config_base}/pipeline/sarek.config" } catch (Exception e) { - System.err.println("WARNING: Could not load nf-core/config/sarek profiles: ${params.custom_config_base}/pipeline/nfcore_custom_sarek.config") + System.err.println("WARNING: Could not load nf-core/config/sarek profiles: ${params.custom_config_base}/pipeline/sarek.config") } profiles { From 485ac145a9fd25a8bfd0e6fcc185af0d88fa50ab Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Thu, 28 Nov 2019 17:28:27 +0100 Subject: [PATCH 258/854] update docs --- .github/CONTRIBUTING.md | 48 +++-- .github/ISSUE_TEMPLATE/bug_report.md | 43 ++-- .github/ISSUE_TEMPLATE/feature_request.md | 18 +- .github/PULL_REQUEST_TEMPLATE.md | 23 ++- .github/workflows/branch.yml | 2 +- CHANGELOG.md | 241 ++++++++++++---------- README.md | 23 +-- 7 files changed, 219 insertions(+), 179 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index c8210fcedb..8c8447976d 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,47 +1,53 @@ # nf-core/sarek: Contributing Guidelines -Hi there! Many thanks for taking an interest in improving nf-core/sarek. +Hi there! +Many thanks for taking an interest in improving nf-core/sarek. -We try to manage the required tasks for nf-core/sarek using GitHub issues, you probably came to this page when creating one. Please use the pre-filled template to save time. - -However, don't be put off by this template - other more general issues and suggestions are welcome! Contributions to the code are even more welcome ;) - -> If you need help using or modifying nf-core/sarek then the best place to ask is on the pipeline channel on [Slack](https://nf-core-invite.herokuapp.com/). +We try to manage the required tasks for nf-core/sarek using GitHub issues, you probably came to this page when creating one. +Please use the pre-filled template to save time. +However, don't be put off by this template - other more general issues and suggestions are welcome! +Contributions to the code are even more welcome ;) +> If you need help using or modifying nf-core/sarek then the best place to ask is on the nf-core Slack [#sarek](https://nfcore.slack.com/channels/sarek) channel ([join our Slack here](https://nf-co.re/join/slack)). ## Contribution workflow -If you'd like to write some code for nf-core/sarek, the standard workflow -is as follows: -1. Check that there isn't already an issue about your idea in the - [nf-core/sarek issues](https://github.com/nf-core/sarek/issues) to avoid - duplicating work. +If you'd like to write some code for nf-core/sarek, the standard workflow is as follows: + +1. Check that there isn't already an issue about your idea in the [nf-core/sarek issues](https://github.com/nf-core/sarek/issues) to avoid duplicating work * If there isn't one already, please create one so that others know you're working on this -2. Fork the [nf-core/sarek repository](https://github.com/nf-core/sarek) to your GitHub account +2. [Fork](https://help.github.com/en/github/getting-started-with-github/fork-a-repo) the [nf-core/sarek repository](https://github.com/nf-core/sarek) to your GitHub account 3. Make the necessary changes / additions within your forked repository -4. Submit a Pull Request against the `dev` branch and wait for the code to be reviewed and merged. - -If you're not used to this workflow with git, you can start with some [basic docs from GitHub](https://help.github.com/articles/fork-a-repo/) or even their [excellent interactive tutorial](https://try.github.io/). +4. Submit a Pull Request against the `dev` branch and wait for the code to be reviewed and merged +If you're not used to this workflow with git, you can start with some [docs from GitHub](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests) or even their [excellent `git` resources](https://try.github.io/). ## Tests -When you create a pull request with changes, [Travis CI](https://travis-ci.org/) will run automatic tests. + +When you create a pull request with changes, [GitHub Actions](https://github.com/features/actions) will run automatic tests. Typically, pull-requests are only fully reviewed when these tests are passing, though of course we can help out before then. There are typically two types of tests that run: ### Lint Tests -The nf-core has a [set of guidelines](http://nf-co.re/guidelines) which all pipelines must adhere to. + +`nf-core` has a [set of guidelines](https://nf-co.re/developers/guidelines) which all pipelines must adhere to. To enforce these and ensure that all pipelines stay in sync, we have developed a helper tool which runs checks on the pipeline code. This is in the [nf-core/tools repository](https://github.com/nf-core/tools) and once installed can be run locally with the `nf-core lint ` command. If any failures or warnings are encountered, please follow the listed URL for more documentation. ### Pipeline Tests -Each nf-core pipeline should be set up with a minimal set of test-data. -Travis CI then runs the pipeline on this data to ensure that it exists successfully. + +Each `nf-core` pipeline should be set up with a minimal set of test-data. +`GitHub Actions` then runs the pipeline on this data to ensure that it exits successfully. If there are any failures then the automated tests fail. -These tests are run both with the latest available version of Nextflow and also the minimum required version that is stated in the pipeline code. +These tests are run both with the latest available version of `Nextflow` and also the minimum required version that is stated in the pipeline code. + +## Patch + +When patching a release, please work on your fork on a new branch named `patch` ## Getting help -For further information/help, please consult the [nf-core/sarek documentation](https://github.com/nf-core/sarek#documentation) and don't hesitate to get in touch on the [sarek pipeline channel](https://nfcore.slack.com/channels/sarek) on [Slack](https://nf-co.re/join/slack). + +For further information/help, please consult the [nf-core/sarek documentation](https://github.com/nf-core/sarek#documentation) and don't hesitate to get in touch on the nf-core Slack [#sarek](https://nfcore.slack.com/channels/sarek) channel ([join our Slack here](https://nf-co.re/join/slack)). diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 6df6c5052c..5e62bedd66 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,31 +1,42 @@ +# nf-core/sarek bug report + Hi there! -Thanks for telling us about a problem with the pipeline. Please delete this text and anything that's not relevant from the template below: +Thanks for telling us about a problem with the pipeline. +Please delete this text and anything that's not relevant from the template below: + +## Describe the bug -#### Describe the bug A clear and concise description of what the bug is. -#### Steps to reproduce +## Steps to reproduce + Steps to reproduce the behaviour: + 1. Command line: `nextflow run ...` 2. See error: _Please provide your error message_ -#### Expected behaviour +## Expected behaviour + A clear and concise description of what you expected to happen. -#### System: - - Hardware: [e.g. HPC, Desktop, Cloud...] - - Executor: [e.g. slurm, local, awsbatch...] - - OS: [e.g. CentOS Linux, macOS, Linux Mint...] - - Version [e.g. 7, 10.13.6, 18.3...] +## System + +- Hardware: [e.g. HPC, Desktop, Cloud...] +- Executor: [e.g. slurm, local, awsbatch...] +- OS: [e.g. CentOS Linux, macOS, Linux Mint...] +- Version [e.g. 7, 10.13.6, 18.3...] + +## Nextflow Installation + +- Version: [e.g. 0.31.0] + +## Container engine -#### Nextflow Installation: - - Version: [e.g. 0.31.0] +- Engine: [e.g. Conda, Docker or Singularity] +- version: [e.g. 1.0.0] +- Image tag: [e.g. nfcore/sarek:2.5.1] -#### Container engine: - - Engine: [e.g. Conda, Docker or Singularity] - - version: [e.g. 1.0.0] - - Image tag: [e.g. nfcore/sarek:1.0.0] +## Additional context -#### Additional context Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 1f025b779c..e3f009a723 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,16 +1,24 @@ +# nf-core/sarek feature request + Hi there! -Thanks for suggesting a new feature for the pipeline! Please delete this text and anything that's not relevant from the template below: +Thanks for suggesting a new feature for the pipeline! +Please delete this text and anything that's not relevant from the template below: + +## Is your feature request related to a problem? Please describe -#### Is your feature request related to a problem? Please describe. A clear and concise description of what the problem is. + Ex. I'm always frustrated when [...] -#### Describe the solution you'd like +## Describe the solution you'd like + A clear and concise description of what you want to happen. -#### Describe alternatives you've considered +## Describe alternatives you've considered + A clear and concise description of any alternative solutions or features you've considered. -#### Additional context +## Additional context + Add any other context about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 15c9a1b1df..913a3fa83c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,16 +1,19 @@ -Many thanks to contributing to nf-core/sarek! +# nf-core/sarek pull request + +Many thanks for contributing to nf-core/sarek! Please fill in the appropriate checklist below (delete whatever is not relevant). These are the most common things requested on pull requests (PRs). ## PR checklist - - [ ] This comment contains a description of changes (with reason) - - [ ] If you've fixed a bug or added code that should be tested, add tests! - - [ ] If necessary, also make a PR on the [nf-core/sarek branch on the nf-core/test-datasets repo](https://github.com/nf-core/test-datasets/pull/new/nf-core/sarek) - - [ ] Ensure the test suite passes (`nextflow run . -profile test,docker`). - - [ ] Make sure your code lints (`nf-core lint .`). - - [ ] Documentation in `docs` is updated - - [ ] `CHANGELOG.md` is updated - - [ ] `README.md` is updated -**Learn more about contributing:** [guidelines](https://github.com/nf-core/sarek/tree/master/.github/CONTRIBUTING.md) \ No newline at end of file +- [ ] This comment contains a description of changes (with reason) +- [ ] If you've fixed a bug or added code that should be tested, add tests! +- [ ] If necessary, also make a PR on the [nf-core/sarek branch on the nf-core/test-datasets repo](https://github.com/nf-core/test-datasets/pull/new/nf-core/sarek) +- [ ] Ensure the test suite passes (`nextflow run . -profile test,docker`). +- [ ] Make sure your code lints (`nf-core lint .`). +- [ ] Documentation in `docs` is updated +- [ ] `CHANGELOG.md` is updated +- [ ] `README.md` is updated + +**Learn more about contributing:** [CONTRIBUTING.md](https://github.com/nf-core/sarek/tree/master/.github/CONTRIBUTING.md) \ No newline at end of file diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 174e995a05..06824f2d77 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -13,4 +13,4 @@ jobs: - uses: actions/checkout@v1 - name: Check PRs run: | - { [[ $(git remote get-url origin) == *nf-core/sarek ]] && [[ ${GITHUB_BASE_REF} = "master" ]] && [[ ${GITHUB_HEAD_REF} = "dev" ]]; } || [[ ${GITHUB_HEAD_REF} == patch* ]] \ No newline at end of file + { [[ $(git remote get-url origin) == *nf-core/sarek ]] && [[ ${GITHUB_HEAD_REF} = "dev" ]]; } || [[ ${GITHUB_HEAD_REF} == "patch" ]] \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 7238d184b1..20f8b472e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,14 +2,14 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) -and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## dev ### `Added` -- [#46](https://github.com/nf-core/sarek/pull/46) - Add location to abstacts +- [#45](https://github.com/nf-core/sarek/pull/45) - Include Workflow figure in `README.md` +- [#46](https://github.com/nf-core/sarek/pull/46) - Add location to abstracts - [#52](https://github.com/nf-core/sarek/pull/52) - Add support for mouse data `GRCm38` ### `Changed` @@ -23,11 +23,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [#41](https://github.com/nf-core/sarek/pull/41), [#55](https://github.com/nf-core/sarek/pull/55) - Update `tiddit` from `2.7.1` to `2.8.1` - [#41](https://github.com/nf-core/sarek/pull/41) - Update `vcfanno` from `0.3.1` to `0.3.2` - [#54](https://github.com/nf-core/sarek/pull/54) - Bump version to `2.5.2dev` +- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Update `README` +- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Update `CHANGELOG` ### `Removed` -- [#45](https://github.com/nf-core/sarek/pull/45) - Include Workflow figure in `README.md` - [#46](https://github.com/nf-core/sarek/pull/46) - Remove mention of old `build.nf` script which was included in `main.nf` +- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Remove `Freebayes` ### `Fixed` @@ -35,7 +37,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [#42](https://github.com/nf-core/sarek/pull/42) - Fix typos, and minor updates in `README.md` - [#43](https://github.com/nf-core/sarek/pull/43) - Fix automated `VEP` builds with circleCI - [#54](https://github.com/nf-core/sarek/pull/54) - Apply fixes from release `2.5.1` -- [#58](https://github.com/nf-core/sarek/pull/58) - Fix issue with `.interval_list` file from the GATK bundle [#56](https://github.com/nf-core/sarek/issues/56) that was not recognized in the `CreateIntervalsBed` process +- [#58](https://github.com/nf-core/sarek/pull/58) - Fix issue with `.interval_list` file from the `GATK` bundle [#56](https://github.com/nf-core/sarek/issues/56) that was not recognized in the `CreateIntervalsBed` process +- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Fix typos in `CHANGELOG` ## [2.5.1] - Årjep-Ålkatjjekna @@ -53,6 +56,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [2.5] - Ålkatj +Ålkatj is one of the main massif in the Sarek National Park. + Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) template. ### `Added` @@ -61,37 +66,37 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#7](https://github.com/nf-core/sarek/pull/7), [#9](https://github.com/nf-core/sarek/pull/9), [#10](https://github.com/nf-core/sarek/pull/10), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Add CI for `nf-core/sarek` - [#3](https://github.com/nf-core/sarek/pull/3) - Add preprocessing to `nf-core/sarek` - [#4](https://github.com/nf-core/sarek/pull/4) - Add variant calling to `nf-core/sarek` with `HaplotypeCaller`, and single mode `Manta` and `Strelka` -- [#5](https://github.com/nf-core/sarek/pull/5), [#34](https://github.com/nf-core/sarek/pull/34) - Add variant calling to `nf-core/sarek` with `Manta`, `Strelka`, `Strelka Best Practices`, `MuTecT2`, `FreeBayes`, `ASCAT`, `ControlFREEC` +- [#5](https://github.com/nf-core/sarek/pull/5), [#34](https://github.com/nf-core/sarek/pull/34) - Add variant calling to `nf-core/sarek` with `Manta`, `Strelka`, `Strelka Best Practices`, `Mutect2`, `FreeBayes`, `ASCAT`, `ControlFREEC` - [#6](https://github.com/nf-core/sarek/pull/6) - Add default containers for annotation to `nf-core/sarek` -- [#7](https://github.com/nf-core/sarek/pull/7) - Add MultiQC +- [#7](https://github.com/nf-core/sarek/pull/7) - Add `MultiQC` - [#7](https://github.com/nf-core/sarek/pull/7) - Add annotation - [#7](https://github.com/nf-core/sarek/pull/7) - Add social preview image in `png` and `svg` format - [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#11](https://github.com/nf-core/sarek/pull/11), [#21](https://github.com/nf-core/sarek/pull/21) - Add helper script `run_tests.sh` to run different tests - [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9) - Add automatic build of specific containers for annotation for `GRCh37`, `GRCh38` and `GRCm38` using `CircleCI` - [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11) - Add helper script `build_reference.sh` to build small reference from [nf-core/test-datasets:sarek](https://github.com/nf-core/test-datasets/tree/sarek) - [#7](https://github.com/nf-core/sarek/pull/7), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Add helper script `download_image.sh` to download containers for testing -- [#8](https://github.com/nf-core/sarek/pull/8) - Add test configation for easier testing +- [#8](https://github.com/nf-core/sarek/pull/8) - Add test configuration for easier testing - [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11) - Add scripts for `ASCAT` - [#10](https://github.com/nf-core/sarek/pull/10) - Add `TIDDIT` to detect structural variants - [#11](https://github.com/nf-core/sarek/pull/11) - Add automatic build of specific containers for annotation for `CanFam3.1` using `CircleCI` - [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Add posters and abstracts - [#12](https://github.com/nf-core/sarek/pull/12) - Add helper script `make_snapshot.sh` to make an archive for usage on a secure cluster - [#12](https://github.com/nf-core/sarek/pull/12) - Add helper scripts `filter_locifile.py` and `selectROI.py` -- [#12](https://github.com/nf-core/sarek/pull/12) - Use `label` for processes configation +- [#12](https://github.com/nf-core/sarek/pull/12) - Use `label` for processes configuration - [#13](https://github.com/nf-core/sarek/pull/13) - Add Citation documentation - [#13](https://github.com/nf-core/sarek/pull/13) - Add `BamQC` process - [#13](https://github.com/nf-core/sarek/pull/13) - Add `CompressVCFsnpEff` and `CompressVCFvep` processes - [#18](https://github.com/nf-core/sarek/pull/18) - Add `--no-reports` option for tests + add snpEff,VEP,merge to MULTIPLE test -- [#18](https://github.com/nf-core/sarek/pull/18) - Add logo to MultiQC report +- [#18](https://github.com/nf-core/sarek/pull/18) - Add logo to `MultiQC` report - [#18](https://github.com/nf-core/sarek/pull/18), [#29](https://github.com/nf-core/sarek/pull/29) - Add params `--skipQC` to skip specified QC tools - [#18](https://github.com/nf-core/sarek/pull/18) - Add possibility to download other genome for `sareksnpeff` and `sarekvep` containers - [#20](https://github.com/nf-core/sarek/pull/20) - Add `markdownlint` config file -- [#21](https://github.com/nf-core/sarek/pull/21) - Add tests for latest Nextflow version as well -- [#21](https://github.com/nf-core/sarek/pull/21) - Add `genomes.config` for genomes without AWS iGenomes -- [#24](https://github.com/nf-core/sarek/pull/24) - Added GATK4 Mutect2 calling and filtering +- [#21](https://github.com/nf-core/sarek/pull/21) - Add tests for latest `Nextflow` version as well +- [#21](https://github.com/nf-core/sarek/pull/21) - Add `genomes.config` for genomes without `AWS iGenomes` +- [#24](https://github.com/nf-core/sarek/pull/24) - Added `GATK4 Mutect2` calling and filtering - [#27](https://github.com/nf-core/sarek/pull/27), [#30](https://github.com/nf-core/sarek/pull/30) - Use Github actions for CI, linting and branch protection -- [#31](https://github.com/nf-core/sarek/pull/31) - Add nf-core lint -- [#31](https://github.com/nf-core/sarek/pull/31) - Add extra CI to GitHub Actions nf-core extra CI +- [#31](https://github.com/nf-core/sarek/pull/31) - Add `nf-core lint` +- [#31](https://github.com/nf-core/sarek/pull/31) - Add extra CI to `GitHub Actions` nf-core extra CI - [#35](https://github.com/nf-core/sarek/pull/35) - Building indexes from [nf-core/test-datasets:sarek](https://github.com/nf-core/test-datasets/tree/sarek) for CI and small tests ### `Changed` @@ -103,10 +108,10 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#7](https://github.com/nf-core/sarek/pull/8), [#23](https://github.com/nf-core/sarek/pull/23) - `--annotateVCF` is now deprecated, use `--input` instead - [#8](https://github.com/nf-core/sarek/pull/8), [#12](https://github.com/nf-core/sarek/pull/12) - Improve helper script `build.nf` for downloading and building reference files - [#9](https://github.com/nf-core/sarek/pull/9) - `ApplyBQSR` is now parallelized -- [#9](https://github.com/nf-core/sarek/pull/9) - Fastq files are named following "${idRun}_R1.fastq.gz" in the FastQC output for easier reporting +- [#9](https://github.com/nf-core/sarek/pull/9) - Fastq files are named following "${idRun}_R1.fastq.gz" in the `FastQC` output for easier reporting - [#9](https://github.com/nf-core/sarek/pull/9) - Status is now a map with `idpatient`, `idsample` as keys (ie: `status = statusMap[idPatient, idSample]`) - [#9](https://github.com/nf-core/sarek/pull/9) - Use `ensembl-vep` `95.2` instead of `96.0` -- [#11](https://github.com/nf-core/sarek/pull/11) - Summary HTML from VWP is now in the `Reports` directory +- [#11](https://github.com/nf-core/sarek/pull/11) - Summary HTML from `VEP` is now in the `Reports` directory - [#12](https://github.com/nf-core/sarek/pull/12) - Update configuration files - [#12](https://github.com/nf-core/sarek/pull/12) - Disable `Docker` in `singularity` profile - [#12](https://github.com/nf-core/sarek/pull/12) - Disable `Singularity` in `docker` profile @@ -119,23 +124,23 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#18](https://github.com/nf-core/sarek/pull/18) - Add `--no-reports` for all tests but MULTIPLE in Jenkins - [#18](https://github.com/nf-core/sarek/pull/18), [#29](https://github.com/nf-core/sarek/pull/29) - `--noReports` is now `--skipQC all` - [#18](https://github.com/nf-core/sarek/pull/18), [#21](https://github.com/nf-core/sarek/pull/21) - Update logo -- [#21](https://github.com/nf-core/sarek/pull/21) - Moved smallGRCh37 path to `genomes.config` +- [#21](https://github.com/nf-core/sarek/pull/21) - Moved `smallGRCh37` path to `genomes.config` - [#23](https://github.com/nf-core/sarek/pull/23) - Rename `genomeFile`, `genomeIndex` and `genomeDict` by `fasta`, `fastaFai` and `dict` - [#23](https://github.com/nf-core/sarek/pull/23) - `--sample` is now deprecated, use `--input` instead - [#23](https://github.com/nf-core/sarek/pull/23) - `--genomeFile` is now deprecated, use `--fasta` instead - [#23](https://github.com/nf-core/sarek/pull/23) - `--genomeIndex` is now deprecated, use `--fastaFai` instead - [#23](https://github.com/nf-core/sarek/pull/23) - `--genomeDict` is now deprecated, use `--dict` instead -- [#24](https://github.com/nf-core/sarek/pull/24) - iGenomes config now contains germline resource for GATK4 Mutect2 +- [#24](https://github.com/nf-core/sarek/pull/24) - `AWS iGenomes` config now contains germline resource for `GATK4 Mutect2` - [#30](https://github.com/nf-core/sarek/pull/30) - Simplify code for `MapReads` process -- [#24](https://github.com/nf-core/sarek/pull/24) - iGenomes config now contains germline resource for `GATK4 Mutect2` -- [#31](https://github.com/nf-core/sarek/pull/31) - Move extra CI to GitHub Actions nf-core extra CI +- [#24](https://github.com/nf-core/sarek/pull/24) - `AWS iGenomes` config now contains germline resource for `GATK4 Mutect2` +- [#31](https://github.com/nf-core/sarek/pull/31) - Move extra CI to `GitHub Actions` nf-core extra CI - [#32](https://github.com/nf-core/sarek/pull/32), [#33](https://github.com/nf-core/sarek/pull/33) - Install `ASCAT` with `conda` in the `environment.yml` file -- [#33](https://github.com/nf-core/sarek/pull/33) - use `workflow.manifest.version` to specify workflow version in path to scripts for `ControlFREEC` and `VEP` processes +- [#33](https://github.com/nf-core/sarek/pull/33) - Use `workflow.manifest.version` to specify workflow version in path to scripts for `ControlFREEC` and `VEP` processes - [#35](https://github.com/nf-core/sarek/pull/35) - Building indexes is now done in `main.nf` - [#35](https://github.com/nf-core/sarek/pull/35) - `build.nf` script now only download cache, so renamed to `downloadcache.nf` - [#35](https://github.com/nf-core/sarek/pull/35) - Use `tabix` instead of `IGVtools` to build vcf indexes - [#35](https://github.com/nf-core/sarek/pull/35) - Refactor references handling -- [#35](https://github.com/nf-core/sarek/pull/35) - use Channel values instead of `referenceMap` +- [#35](https://github.com/nf-core/sarek/pull/35) - Use Channel values instead of `referenceMap` - [#37](https://github.com/nf-core/sarek/pull/37) - Bump version for Release - [#38](https://github.com/nf-core/sarek/pull/38) - File names before merge is based on `${idSample}_${idRun}` instead of `${idRun}` @@ -145,8 +150,8 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#13](https://github.com/nf-core/sarek/pull/13) - Removed `BamQCmapped` and `BamQCrecalibrated` processes - [#13](https://github.com/nf-core/sarek/pull/13) - Removed `CompressVCF` - [#18](https://github.com/nf-core/sarek/pull/18) - Removed params `--noReports` -- [#24](https://github.com/nf-core/sarek/pull/18) - Removed GATK3.X MuTect2 -- [#31](https://github.com/nf-core/sarek/pull/31) - Remove extra CI from Travis CI and GitHub Actions nf-core CI +- [#24](https://github.com/nf-core/sarek/pull/18) - Removed `GATK3.X Mutect2` +- [#31](https://github.com/nf-core/sarek/pull/31) - Remove extra CI from `Travis CI` and `GitHub Actions` nf-core CI - [#32](https://github.com/nf-core/sarek/pull/32), [#35](https://github.com/nf-core/sarek/pull/35) - Clean up `environment.yml` file - [#35](https://github.com/nf-core/sarek/pull/35) - Remove building indexes from `build.nf` script - [#35](https://github.com/nf-core/sarek/pull/35) - Remove helper script `build_reference.sh` @@ -156,21 +161,21 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) ### `Fixed` -- [#3](https://github.com/nf-core/sarek/pull/3) - Fix Docker ownership +- [#3](https://github.com/nf-core/sarek/pull/3) - Fix `Docker` ownership - [#11](https://github.com/nf-core/sarek/pull/11) - Fix `MergeMpileup` PublishDir - [#13](https://github.com/nf-core/sarek/pull/13) - Fix merge in annotation - [#14](https://github.com/nf-core/sarek/pull/14) - Fix output name for vcf files -- [#16](https://github.com/nf-core/sarek/pull/16) - Fix path to Rscript +- [#16](https://github.com/nf-core/sarek/pull/16) - Fix path to `Rscript` - [#18](https://github.com/nf-core/sarek/pull/18) - Improve cpu usage -- [#18](https://github.com/nf-core/sarek/pull/18) - Use same font for nf-core and sarek in ascii art +- [#18](https://github.com/nf-core/sarek/pull/18) - Use same font for `nf-core` and `sarek` in ascii art - [#20](https://github.com/nf-core/sarek/pull/20) - Use new logo in README - [#20](https://github.com/nf-core/sarek/pull/20) - Fix path to references genomes - [#22](https://github.com/nf-core/sarek/pull/22) - Fix `--singleCPUMem` issue -- [#30](https://github.com/nf-core/sarek/pull/30) - fix choice between `inputPairReadsFastQC` and `inputBAMFastQC` channels +- [#30](https://github.com/nf-core/sarek/pull/30) - Fix choice between `inputPairReadsFastQC` and `inputBAMFastQC` channels - [#31](https://github.com/nf-core/sarek/pull/31) - Fix badges according to nf-core lint -- [#31](https://github.com/nf-core/sarek/pull/31) - Fix rcolorbrewer version according to nf-core lint +- [#31](https://github.com/nf-core/sarek/pull/31) - Fix `rcolorbrewer` version according to nf-core lint - [#33](https://github.com/nf-core/sarek/pull/33) - Fix MD Linting -- [#38](https://github.com/nf-core/sarek/pull/38) - Avoid collision in MultiQC +- [#38](https://github.com/nf-core/sarek/pull/38) - Avoid collision in `MultiQC` - [#39](https://github.com/nf-core/sarek/pull/39) - Fix `ch_dbsnp` channel ### `Deprecated` @@ -185,10 +190,12 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) ### `Fixed` -- [#742](https://github.com/SciLifeLab/Sarek/pull/742) - Fix output dirs (HaplotypeCaller that was not recognized by annotate.nf introduced by [#728](https://github.com/SciLifeLab/Sarek/pull/728)) +- [#742](https://github.com/SciLifeLab/Sarek/pull/742) - Fix output dirs (`HaplotypeCaller` that was not recognized by `annotate.nf` introduced by [#728](https://github.com/SciLifeLab/Sarek/pull/728)) ## [2.3] - Äpar - 2019-02-27 +Äpar is one of the main massif in the Sarek National Park. + ### `Added` - [#628](https://github.com/SciLifeLab/Sarek/pull/628), [#722](https://github.com/SciLifeLab/Sarek/pull/722) - `ASCAT` now use `.gc` file @@ -200,50 +207,50 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#722](https://github.com/SciLifeLab/Sarek/pull/722) - Add path to ASCAT `.gc` file in `igenomes.config` - [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Update `Sarek-data` submodule with multiple patients TSV file - [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Add `cadd_WG_SNVs`, `cadd_WG_SNVs_tbi`, `cadd_InDels`, `cadd_InDels_tbi` and `cadd_cache` params -- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Add tabix indexed cache for VEP +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Add `tabix` indexed cache for `VEP` - [#732](https://github.com/SciLifeLab/Sarek/pull/732) - New `DownloadCADD` process to download CADD files - [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Specify values for `cadd_WG_SNVs`, `cadd_WG_SNVs_tbi`, `cadd_InDels`, `cadd_InDels_tbi` and `cadd_cache` params in `munin.conf` file - [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Use `cadd_cache` param for optional use of CADD VEP plugin in `annotate.nf` -- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - VEP cache has now fasta files for `--HGVS` -- [#735](https://github.com/SciLifeLab/Sarek/pull/735) - Added `--exome` for Manta, and for StrelkaBP -- [#735](https://github.com/SciLifeLab/Sarek/pull/735) - Added Travis CI test for targeted +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - `VEP` cache has now fasta files for `--HGVS` +- [#735](https://github.com/SciLifeLab/Sarek/pull/735) - Added `--exome` for `Manta`, and for `StrelkaBP` +- [#735](https://github.com/SciLifeLab/Sarek/pull/735) - Added `Travis CI` test for targeted ### `Changed` - [#710](https://github.com/SciLifeLab/Sarek/pull/710) - Improve release checklist and script - [#711](https://github.com/SciLifeLab/Sarek/pull/711) - Improve configuration priorities -- [#716](https://github.com/SciLifeLab/Sarek/pull/716) - Update paths to containers and iGenomes +- [#716](https://github.com/SciLifeLab/Sarek/pull/716) - Update paths to containers and `AWS iGenomes` - [#717](https://github.com/SciLifeLab/Sarek/pull/717) - `checkFileExtension` has changed to `hasExtension`, and now only verify if file has extension - [#717](https://github.com/SciLifeLab/Sarek/pull/717) - `fastqFiles` renamed to `inputFiles` - [#717](https://github.com/SciLifeLab/Sarek/pull/717) - `mapping` step can now map BAM files too - [#717](https://github.com/SciLifeLab/Sarek/pull/717) - `MapReads` can now convert BAM to FASTQ and feed it to BWA on the fly - [#717](https://github.com/SciLifeLab/Sarek/pull/717), [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Update documentation -- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - `snpeff` and `vep` containers are now built with conda +- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - `snpeff` and `vep` containers are now built with `conda` - [#719](https://github.com/SciLifeLab/Sarek/pull/719) - `vepCacheVersion` is now defined in `conf/genomes.config` or `conf/igenomes.config` - [#722](https://github.com/SciLifeLab/Sarek/pull/722) - Add path to ASCAT `.gc` file in `igenomes.config` - [#722](https://github.com/SciLifeLab/Sarek/pull/722) - Update `Sarek-data` submodule - [#723](https://github.com/SciLifeLab/Sarek/pull/723), [#725](https://github.com/SciLifeLab/Sarek/pull/725) - Update docs -- [#724](https://github.com/SciLifeLab/Sarek/pull/724) - Improved AwsBatch configuration +- [#724](https://github.com/SciLifeLab/Sarek/pull/724) - Improved `AWS batch` configuration - [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Improved usage of `targetBED` params -- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Strelka Best Practices output is now prefixed with `StrelkaBP_` +- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - `Strelka` Best Practices output is now prefixed with `StrelkaBP_` - [#728](https://github.com/SciLifeLab/Sarek/pull/728) - VCFs and Annotated VCFs are now ordered by Patient, then tools - [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Merge `buildContainers.nf` and `buildReferences.nf` in `build.nf` - [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Reduce number of CPUs for `RunVEP` to `4` cf: [VEP docs](https://www.ensembl.org/info/docs/tools/vep/script/vep_other.html) -- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Update VEP from `95.1` to `95.2` +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Update `VEP` from `95.1` to `95.2` ### `Removed` - [#715](https://github.com/SciLifeLab/Sarek/pull/715) - Remove `defReferencesFiles` function from `buildReferences.nf` - [#719](https://github.com/SciLifeLab/Sarek/pull/719) - `snpEff` base container is no longer used -- [#721](https://github.com/SciLifeLab/Sarek/pull/721) - Remove COSMIC docs +- [#721](https://github.com/SciLifeLab/Sarek/pull/721) - Remove `COSMIC` docs - [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Remove `defineDirectoryMap()` -- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Removed `--database` option for VEP cf: [VEP docs](https://www.ensembl.org/info/docs/tools/vep/script/vep_other.html) +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Remove `--database` option for VEP cf: [VEP docs](https://www.ensembl.org/info/docs/tools/vep/script/vep_other.html) ### `Fixed` -- [#720](https://github.com/SciLifeLab/Sarek/pull/720) - bamQC is now run on the recalibrated bams, and not after MarkDuplicates -- [#726](https://github.com/SciLifeLab/Sarek/pull/726) - Fix Ascat ref file input (one file can't be a set) -- [#727](https://github.com/SciLifeLab/Sarek/pull/727) - bamQC outputs are no longer overwritten (name of dir is now the file instead of sample) +- [#720](https://github.com/SciLifeLab/Sarek/pull/720) - `bamQC` is now run on the recalibrated bams, and not after `MarkDuplicates` +- [#726](https://github.com/SciLifeLab/Sarek/pull/726) - Fix `Ascat` ref file input (one file can't be a set) +- [#727](https://github.com/SciLifeLab/Sarek/pull/727) - `bamQC` outputs are no longer overwritten (name of dir is now the file instead of sample) - [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Fix issue with annotation that was consuming `cache` channels - [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Fix multi sample TSV file [#691](https://github.com/SciLifeLab/Sarek/issues/691) - [#733](https://github.com/SciLifeLab/Sarek/pull/733) - Fix the possibility to specify reference files on the command line @@ -255,31 +262,31 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#671](https://github.com/SciLifeLab/Sarek/pull/671) - New `publishDirMode` param and docs - [#673](https://github.com/SciLifeLab/Sarek/pull/673), [#675](https://github.com/SciLifeLab/Sarek/pull/675), [#676](https://github.com/SciLifeLab/Sarek/pull/676) - Profiles for BinAC and CFC clusters in Tübingen - [#679](https://github.com/SciLifeLab/Sarek/pull/679) - Add container for `CreateIntervalBeds` -- [#692](https://github.com/SciLifeLab/Sarek/pull/692), [#697](https://github.com/SciLifeLab/Sarek/pull/697) - Add AWS iGenomes possibilities (within `conf/igenomes.conf`) +- [#692](https://github.com/SciLifeLab/Sarek/pull/692), [#697](https://github.com/SciLifeLab/Sarek/pull/697) - Add `AWS iGenomes` possibilities (within `conf/igenomes.conf`) - [#694](https://github.com/SciLifeLab/Sarek/pull/694) - Add monochrome and grey logos for light or dark background - [#698](https://github.com/SciLifeLab/Sarek/pull/698) - Add btb profile for munin server -- [#702](https://github.com/SciLifeLab/Sarek/pull/702) - Add font-ttf-dejavu-sans-mono `2.37` and fontconfig `2.12.6` to container +- [#702](https://github.com/SciLifeLab/Sarek/pull/702) - Add `font-ttf-dejavu-sans-mono` `2.37` and `fontconfig` `2.12.6` to container ### `Changed` - [#663](https://github.com/SciLifeLab/Sarek/pull/663) - Update `do_release.sh` script -- [#671](https://github.com/SciLifeLab/Sarek/pull/671) - publishDir modes are now params +- [#671](https://github.com/SciLifeLab/Sarek/pull/671) - `publishDir` modes are now params - [#677](https://github.com/SciLifeLab/Sarek/pull/677), [#698](https://github.com/SciLifeLab/Sarek/pull/698), [#703](https://github.com/SciLifeLab/Sarek/pull/703) - Update docs -- [#678](https://github.com/SciLifeLab/Sarek/pull/678) - Changing VEP to v92 and adjusting CPUs for VEP -- [#679](https://github.com/SciLifeLab/Sarek/pull/679) - Update old awsbatch configuration -- [#682](https://github.com/SciLifeLab/Sarek/pull/682) - Specifications for memory and cpus for awsbatch -- [#693](https://github.com/SciLifeLab/Sarek/pull/693) - Qualimap bamQC is now ran after mapping and after recalibration for better QC -- [#700](https://github.com/SciLifeLab/Sarek/pull/700) - Update GATK to `4.0.9.0` -- [#702](https://github.com/SciLifeLab/Sarek/pull/702) - Update FastQC to `0.11.8` -- [#705](https://github.com/SciLifeLab/Sarek/pull/705) - Change `--TMP_DIR` by `--tmp-dir` for GATK `4.0.9.0` BaseRecalibrator -- [#706](https://github.com/SciLifeLab/Sarek/pull/706) - Update TravisCI testing +- [#678](https://github.com/SciLifeLab/Sarek/pull/678) - Changing `VEP` to `v92` and adjusting CPUs for `VEP` +- [#679](https://github.com/SciLifeLab/Sarek/pull/679) - Update old `awsbatch` configuration +- [#682](https://github.com/SciLifeLab/Sarek/pull/682) - Specifications for memory and cpus for `awsbatch` +- [#693](https://github.com/SciLifeLab/Sarek/pull/693) - `Qualimap bamQC` is now ran after mapping and after recalibration for better QC +- [#700](https://github.com/SciLifeLab/Sarek/pull/700) - Update `GATK` to `4.0.9.0` +- [#702](https://github.com/SciLifeLab/Sarek/pull/702) - Update `FastQC` to `0.11.8` +- [#705](https://github.com/SciLifeLab/Sarek/pull/705) - Change `--TMP_DIR` by `--tmp-dir` for `GATK` `4.0.9.0` `BaseRecalibrator` +- [#706](https://github.com/SciLifeLab/Sarek/pull/706) - Update `Travis CI` testing ### `Fixed` -- [#665](https://github.com/SciLifeLab/Sarek/pull/665) - Input bam file now has always the same name (whether it is from a single fastq pair or multiple) in the MarkDuplicates process, so metrics too -- [#672](https://github.com/SciLifeLab/Sarek/pull/672) - process `PullSingularityContainers` from `buildContainers.nf` now expect a file with the correct `.simg` extension for singularity images, and no longer the `.img` one. -- [#679](https://github.com/SciLifeLab/Sarek/pull/679) - Add publishDirMode for `germlineVC.nf` -- [#700](https://github.com/SciLifeLab/Sarek/pull/700) - Fix [#699](https://github.com/SciLifeLab/Sarek/issues/699) missing DP in the FORMAT column VCFs for MuTect2 +- [#665](https://github.com/SciLifeLab/Sarek/pull/665) - Input bam file now has always the same name (whether it is from a single fastq pair or multiple) in the `MarkDuplicates` process, so metrics too +- [#672](https://github.com/SciLifeLab/Sarek/pull/672) - Process `PullSingularityContainers` from `buildContainers.nf` now expect a file with the correct `.simg` extension for singularity images, and no longer the `.img` one. +- [#679](https://github.com/SciLifeLab/Sarek/pull/679) - Add `publishDirMode` for `germlineVC.nf` +- [#700](https://github.com/SciLifeLab/Sarek/pull/700) - Fix [#699](https://github.com/SciLifeLab/Sarek/issues/699) missing DP in the FORMAT column VCFs for Mutect2 - [#702](https://github.com/SciLifeLab/Sarek/pull/702) - Fix [#701](https://github.com/SciLifeLab/Sarek/issues/701) - [#705](https://github.com/SciLifeLab/Sarek/pull/705) - Fix [#704](https://github.com/SciLifeLab/Sarek/issues/704) @@ -288,16 +295,18 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) ### `Changed` - [#646](https://github.com/SciLifeLab/Sarek/pull/646) - Update [`pathfindr`](https://github.com/NBISweden/pathfindr) submodule -- [#659](https://github.com/SciLifeLab/Sarek/pull/659) - Update Nextflow to `0.32.0` +- [#659](https://github.com/SciLifeLab/Sarek/pull/659) - Update `Nextflow` to `0.32.0` - [#660](https://github.com/SciLifeLab/Sarek/pull/660) - Update docs ### `Fixed` - [#657](https://github.com/SciLifeLab/Sarek/pull/657) - Fix `RunMultiQC.nf` bug -- [#659](https://github.com/SciLifeLab/Sarek/pull/659) - Fix bugs due to updating Nextflow +- [#659](https://github.com/SciLifeLab/Sarek/pull/659) - Fix bugs due to updating `Nextflow` ## [2.2.0] - Skårki - 2018-09-21 +Skårki is one of the main massif in the Sarek National Park. + ### `Added` - [#613](https://github.com/SciLifeLab/Sarek/pull/613) - Add Issue Templates (bug report and feature request) @@ -312,23 +321,23 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) ### `Changed` -- [#608](https://github.com/SciLifeLab/Sarek/pull/608) - Update Nextflow required version +- [#608](https://github.com/SciLifeLab/Sarek/pull/608) - Update `Nextflow` required version - [#615](https://github.com/SciLifeLab/Sarek/pull/615) - Use `splitCsv` instead of `readlines` -- [#616](https://github.com/SciLifeLab/Sarek/pull/616) - Update CHANGELOG +- [#616](https://github.com/SciLifeLab/Sarek/pull/616) - Update `CHANGELOG` - [#621](https://github.com/SciLifeLab/Sarek/pull/621), [#638](https://github.com/SciLifeLab/Sarek/pull/638) - Improve install script - [#621](https://github.com/SciLifeLab/Sarek/pull/621), [#638](https://github.com/SciLifeLab/Sarek/pull/638) - Simplify tests - [#627](https://github.com/SciLifeLab/Sarek/pull/627), [#629](https://github.com/SciLifeLab/Sarek/pull/629), [#637](https://github.com/SciLifeLab/Sarek/pull/637) - Refactor docs - [#629](https://github.com/SciLifeLab/Sarek/pull/629) - Refactor config -- [#632](https://github.com/SciLifeLab/Sarek/pull/632) - Use 2 threads and 2 cpus FastQC processes +- [#632](https://github.com/SciLifeLab/Sarek/pull/632) - Use 2 threads and 2 cpus `FastQC` processes - [#637](https://github.com/SciLifeLab/Sarek/pull/637) - Update tool version gathering - [#638](https://github.com/SciLifeLab/Sarek/pull/638) - Use correct `.simg` extension for Singularity images - [#639](https://github.com/SciLifeLab/Sarek/pull/639) - Smaller refactoring of the docs - [#640](https://github.com/SciLifeLab/Sarek/pull/640) - Update RELEASE_CHECKLIST -- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - MultiQC 1.5 -> 1.6 -- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - Qualimap 2.2.2a -> 2.2.2b -- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - Update conda channel order priorities -- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - VCFanno 0.2.8 -> 0.3.0 -- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - VCFtools 0.1.15 -> 0.1.16 +- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - `MultiQC` 1.5 -> 1.6 +- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - `Qualimap` 2.2.2a -> 2.2.2b +- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - Update `conda` channel order priorities +- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - `VCFanno` 0.2.8 -> 0.3.0 +- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - `VCFtools` 0.1.15 -> 0.1.16 ### `Removed` @@ -338,34 +347,36 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) ### `Fixed` -- [#621](https://github.com/SciLifeLab/Sarek/pull/621) - Fix VEP tests +- [#621](https://github.com/SciLifeLab/Sarek/pull/621) - Fix `VEP` tests - [#637](https://github.com/SciLifeLab/Sarek/pull/637) - Fix links in MD files ## [2.1.0] - Ruotes - 2018-08-14 +Ruotes is one of the main massif in the Sarek National Park. + ### `Added` - [#555](https://github.com/SciLifeLab/Sarek/pull/555) - `snpEff` output into `VEP` - [#556](https://github.com/SciLifeLab/Sarek/pull/556) - `Strelka` Best Practices - [#563](https://github.com/SciLifeLab/Sarek/pull/563) - Use `SnpEFF` reports in `MultiQC` - [#568](https://github.com/SciLifeLab/Sarek/pull/568) - `VCFTools` process `RunVcftools` for QC -- [#574](https://github.com/SciLifeLab/Sarek/pull/574), [#580](https://github.com/SciLifeLab/Sarek/pull/580) - Abstracts for NPMI, JOBIM and EACR25 +- [#574](https://github.com/SciLifeLab/Sarek/pull/574), [#580](https://github.com/SciLifeLab/Sarek/pull/580) - Abstracts for `NPMI`, `JOBIM` and `EACR25` - [#577](https://github.com/SciLifeLab/Sarek/pull/577) - New repository for testing: [Sarek-data](https://github.com/SciLifeLab/Sarek-data) - [#595](https://github.com/SciLifeLab/Sarek/pull/595) - New library `QC` for functions `bamQC`, `bcftools`, `samtoolsStats`, `vcftools`, `getVersionBCFtools`, `getVersionGATK`, `getVersionManta`, `getVersionSnpEFF`, `getVersionStrelka`, `getVersionVCFtools`, `getVersionVEP` - [#595](https://github.com/SciLifeLab/Sarek/pull/595) - New Processes `GetVersionBCFtools`, `GetVersionGATK`, `GetVersionManta`, `GetVersionSnpEFF`, `GetVersionStrelka`, `GetVersionVCFtools`, `GetVersionVEP` -- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - new Python script `bin/scrape_tool_versions.py` inspired by @ewels and @apeltzer +- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - New `Python` script `bin/scrape_tool_versions.py` inspired by @ewels and @apeltzer - [#595](https://github.com/SciLifeLab/Sarek/pull/595) - New QC Process `RunVcftools` -- [#596](https://github.com/SciLifeLab/Sarek/pull/596) - New profile for BinAC cluster +- [#596](https://github.com/SciLifeLab/Sarek/pull/596) - New profile for `BinAC` cluster - [#597](https://github.com/SciLifeLab/Sarek/pull/597) - New function `sarek_ascii()` in `SarekUtils` - [#599](https://github.com/SciLifeLab/Sarek/pull/599), [#602](https://github.com/SciLifeLab/Sarek/pull/602) - New Process `CompressVCF` -- [#601](https://github.com/SciLifeLab/Sarek/pull/601), [#603](https://github.com/SciLifeLab/Sarek/pull/603) - Container for GATK4 +- [#601](https://github.com/SciLifeLab/Sarek/pull/601), [#603](https://github.com/SciLifeLab/Sarek/pull/603) - Container for `GATK4` - [#606](https://github.com/SciLifeLab/Sarek/pull/606) - Add test data as a submodule from [`Sarek-data`](https://github.com/SciLifeLab/Sarek-data) - [#608](https://github.com/SciLifeLab/Sarek/pull/608) - Add documentation on how to install Nextflow on `bianca` ### `Changed` - [#557](https://github.com/SciLifeLab/Sarek/pull/557), [#583](https://github.com/SciLifeLab/Sarek/pull/583), [#585](https://github.com/SciLifeLab/Sarek/pull/585), [#588](https://github.com/SciLifeLab/Sarek/pull/588) - Update help -- [#560](https://github.com/SciLifeLab/Sarek/pull/560) - GitHub langage for the repository is now `Nextflow` +- [#560](https://github.com/SciLifeLab/Sarek/pull/560) - `GitHub` langage for the repository is now `Nextflow` - [#561](https://github.com/SciLifeLab/Sarek/pull/561) - `do_all.sh` build only containers for one genome reference (default `GRCh38`) only - [#571](https://github.com/SciLifeLab/Sarek/pull/571) - Only one container for all QC tools - [#582](https://github.com/SciLifeLab/Sarek/pull/582), [#587](https://github.com/SciLifeLab/Sarek/pull/587) - Update figures @@ -378,10 +389,10 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#599](https://github.com/SciLifeLab/Sarek/pull/599) - Merge is tested with `ANNOTATEALL` - [#604](https://github.com/SciLifeLab/Sarek/pull/604) - Synching `GRCh38` `wgs_calling_regions` bedfiles - [#607](https://github.com/SciLifeLab/Sarek/pull/607) - One container approach -- [#607](https://github.com/SciLifeLab/Sarek/pull/607) - Update to GATK4 -- [#608](https://github.com/SciLifeLab/Sarek/pull/608) - Update Nextflow required version -- [#616](https://github.com/SciLifeLab/Sarek/pull/616) - Update CHANGELOG -- [#617](https://github.com/SciLifeLab/Sarek/pull/617) - Replace deprecated $name syntax with withName +- [#607](https://github.com/SciLifeLab/Sarek/pull/607) - Update to `GATK4` +- [#608](https://github.com/SciLifeLab/Sarek/pull/608) - Update `Nextflow` required version +- [#616](https://github.com/SciLifeLab/Sarek/pull/616) - Update `CHANGELOG` +- [#617](https://github.com/SciLifeLab/Sarek/pull/617) - Replace deprecated `Nextflow ``$name` syntax with `withName` ### `Fixed` @@ -389,24 +400,26 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - [#566](https://github.com/SciLifeLab/Sarek/pull/566) - `slurmDownload` profile - [#579](https://github.com/SciLifeLab/Sarek/pull/579), [#584](https://github.com/SciLifeLab/Sarek/pull/584) - `Manta` output reorganized after modification for `Strelka Best Practices` process - [#585](https://github.com/SciLifeLab/Sarek/pull/583) - Trace file is plain txt -- [#590](https://github.com/SciLifeLab/Sarek/pull/590), [#593](https://github.com/SciLifeLab/Sarek/pull/593) - Fix Singularity installation in Travis CI testing -- [#598](https://github.com/SciLifeLab/Sarek/pull/598), [#601](https://github.com/SciLifeLab/Sarek/pull/601) - Fixes for Python script `selectROI.py` to work with CLC viewer +- [#590](https://github.com/SciLifeLab/Sarek/pull/590), [#593](https://github.com/SciLifeLab/Sarek/pull/593) - Fix `Singularity` installation in `Travis CI` testing +- [#598](https://github.com/SciLifeLab/Sarek/pull/598), [#601](https://github.com/SciLifeLab/Sarek/pull/601) - Fixes for `Python` script `selectROI.py` to work with `CLC` viewer ### `Removed` -- [#607](https://github.com/SciLifeLab/Sarek/pull/607) - Remove Mutect1 +- [#607](https://github.com/SciLifeLab/Sarek/pull/607) - Remove `Mutect1` ## [2.0.0] - 2018-03-23 +First release under the `Sarek` name, from the National Park in Northern Sweden + ### `Added` -- basic wrapper script +- Basic wrapper script - Abstract, posters and figures -- ROI selector and FreeBayes sanitizer scripts +- ROI selector and `FreeBayes` sanitizer scripts - New logo and icon for the project -- check for existing tumor/normal channel +- Check for existing tumor/normal channel - `SarekUtils` with `checkParams()`, `checkParameterList()`, `checkParameterExistence()` and `isAllowedParams()` functions -- some `runOptions` for `docker` (prevent some user right problem) +- Some `runOptions` for `docker` (prevent some user right problem) - This `CHANGELOG` ### `Changed` @@ -415,22 +428,22 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - Dissect Workflow in 5 new scripts: `annotate.nf`, `main.nf`, `germlineVC.nf`, `runMultiQC.nf` and `somaticVC.nf` - `report.html`, `timeline.html` and `trace.html` are generated in `Reports/` - `--version` is now used to define the workflow version -- most params are now defined in the base.config file instead of in the scripts -- update RELEASE_CHECKLIST.md +- Most params are now defined in the `base.config` file instead of in the scripts +- Update `RELEASE_CHECKLIST.md` - `checkParams()`, `checkParameterList()`, `checkParameterExistence()` and `isAllowedParams()` in script functions are now called within `SarekUtils` - `nf_required_version` is now `params.nfRequiredVersion` -- in `buildReferences.nf` script, channels now begin by `ch_`, and files by `f_` -- use `PublishDir mode: 'link'` instead of `copy` +- In `buildReferences.nf` script, channels now begin by `ch_`, and files by `f_` +- Use `PublishDir mode: 'link'` instead of `copy` - `directoryMap` now contains `params.outDir` -- [#539](https://github.com/SciLifeLab/Sarek/issues/539) - use Nextflow support of scratch -- reordered Travis CI tests -- update documentation +- [#539](https://github.com/SciLifeLab/Sarek/issues/539) - Use Nextflow support of scratch +- Reordered `Travis CI` tests +- Update documentation - `MultiQC` version in container from v`1.4` to v`1.5` - `vepgrch37` container base image from `release_90.6` to `release_92` - `vepgrch38` container base image from `release_90.6` to `release_92` - `VEP` version in containers from v`90` to v`91` - `nucleotidesPerSecond` is now `params.nucleotidesPerSecond` -- default `params.tag` is now `latest` instead of current version, so --tag needs to be specified with the right version to be sure of using the `containers` corresponding +- Default `params.tag` is now `latest` instead of current version, so `--tag` needs to be specified with the right version to be sure of using the `containers` corresponding ### `Deprecated` @@ -440,22 +453,22 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) ### `Removed` - `scripts/skeleton_batch.sh` -- old data and tsv files -- UPPMAX directories from containers +- Old data and tsv files +- `UPPMAX` directories from containers - `--step` in `annotate.nf`, `germlineVC.nf` and `somatic.nf` -- some `runOptions` for Singularity (binding not needed anymore on UPPMAX) +- Some `runOptions` for `Singularity` (binding not needed anymore on `UPPMAX`) - `download` profile ### `Fixed` -- [#530](https://github.com/SciLifeLab/Sarek/issues/530) - use `$PWD` for default `outDir` +- [#530](https://github.com/SciLifeLab/Sarek/issues/530) - Use `$PWD` for default `outDir` - [#533](https://github.com/SciLifeLab/Sarek/issues/533) - Replace `VEP` `--pick` option by `--per_gene` ## [1.2.5] - 2018-01-18 ### `Added` -- Zenodo for DOI +- `Zenodo` for DOI - Delivery README - Document use of the `--sampleDir` option - Contributing Guidelines @@ -464,22 +477,22 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) - `--outDir` - `awsbatch` profile - `aws-batch.config` config file -- `--noBAMQC` params (failing sometimes on Bianca) +- `--noBAMQC` params (failing sometimes on `Bianca`) ### `Changed` -- Update `Nextflow` to `0.26.0` (new fancy report + AWS Batch) -- Extra time on Travis CI testing +- Update `Nextflow` to `0.26.0` (new fancy report + `AWS Batch`) +- Extra time on `Travis CI` testing - Replace `bundleDir` by `params.genome_base` -- Update `MultiQC` to `1.3` (MEGAQC FTW) +- Update `MultiQC` to `1.3` (`MEGAQC` FTW) - Move and rename some test files ### `Fixed` -- Version of COSMIC GRCh37 v83 +- Version of `COSMIC` `GRCh37` `v83` - Write an error message when `--sampleDir` does not find any FASTQ files -- `base.config` for ConcatVCF process -- File specification for recalibrationReport in RecalibrateBam process (got error on AWS Batch) +- `base.config` for `ConcatVCF` process +- File specification for `recalibrationReport` in `RecalibrateBam` process (got error on `AWS Batch`) ## [1.2.4] - 2017-10-27 @@ -493,7 +506,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) ### `Fixed` -- [#357](https://github.com/SciLifeLab/Sarek/issues/357) - `ASCAT` works for GRCh38 +- [#357](https://github.com/SciLifeLab/Sarek/issues/357) - `ASCAT` works for `GRCh38` - [#471](https://github.com/SciLifeLab/Sarek/issues/471) - Running `Singularity` on `/scratch` - [#475](https://github.com/SciLifeLab/Sarek/issues/475) - 16 cpus for local executor - [#480](https://github.com/SciLifeLab/Sarek/issues/480) - No `tsv` file needed for step `annotate` @@ -519,7 +532,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) ### `Fixed` - [#471](https://github.com/SciLifeLab/Sarek/issues/471) - Running `Singularity` on /scratch -- [#472](https://github.com/SciLifeLab/Sarek/issues/472) - Update function to check Nextflow version +- [#472](https://github.com/SciLifeLab/Sarek/issues/472) - Update function to check `Nextflow` version - [#473](https://github.com/SciLifeLab/Sarek/issues/473) - Remove `returnMin()` function ## [1.2.0] - 2017-10-02 @@ -532,14 +545,14 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) ### `Added` -- Singularity possibilities +- `Singularity` possibilities ### `Changed` - Reports made by default - Intervals file can be a bed file -- Normal sample preprocessing + HaplotypeCaller is possible -- Better Travis CI tests +- Normal sample preprocessing + `HaplotypeCaller` is possible +- Better `Travis CI` tests ### `Fixed` @@ -549,7 +562,7 @@ Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) ### `Added` -- Docker possibilities +- `Docker` possibilities ## [0.9] - 2016-11-16 diff --git a/README.md b/README.md index d689576f19..addec50a11 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,24 @@ -# [![Sarek](docs/images/nf-core_sarek_logo.png "Sarek")](https://sarek.scilifelab.se/) +# [![Sarek](docs/images/nf-core_sarek_logo.png "Sarek")](https://nf-co.re/sarek) > **An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing** -[![Nextflow](https://img.shields.io/badge/nextflow-%E2%89%A519.04.0-brightgreen.svg)](https://www.nextflow.io/) -[![nf-core](https://img.shields.io/badge/nf--core-pipeline-brightgreen.svg)](https://nf-co.re/) +[![Nextflow](https://img.shields.io/badge/nextflow-%E2%89%A519.04.0-brightgreen)](https://www.nextflow.io/) +[![nf-core](https://img.shields.io/badge/nf--core-pipeline-brightgreen)](https://nf-co.re/) [![DOI](https://zenodo.org/badge/184289291.svg)](https://zenodo.org/badge/latestdoi/184289291) -[![Travis build status](https://img.shields.io/travis/nf-core/sarek.svg)](https://travis-ci.com/nf-core/sarek/) -[![CircleCi build status](https://img.shields.io/circleci/project/github/nf-core/sarek.svg)](https://circleci.com/gh/nf-core/sarek/) +[![GitHub Actions CI status](https://github.com/nf-core/sarek/workflows/nf-core%20CI/badge.svg)](https://github.com/nf-core/sarek/actions?query=workflow%3A%22sarek+CI%22) +[![GitHub Actions extra-CI status](https://github.com/nf-core/sarek/workflows/nf-core%20extra%20CI/badge.svg)](https://github.com/nf-core/sarek/actions?query=workflow%3A%22sarek+extra+CI%22) +[![GitHub Actions Linting status](https://github.com/nf-core/sarek/workflows/nf-core%20linting/badge.svg)](https://github.com/nf-core/sarek/actions?query=workflow%3A%22sarek+linting%22) +[![CircleCi build status](https://img.shields.io/circleci/project/github/nf-core/sarek?logo=circleci)](https://circleci.com/gh/nf-core/sarek/) -[![install with bioconda](https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg)](http://bioconda.github.io/) -[![Docker Container available](https://img.shields.io/docker/automated/nfcore/sarek.svg)](https://hub.docker.com/r/nfcore/sarek/) -[![Install with Singularity](https://img.shields.io/badge/use%20with-singularity-purple.svg)](https://www.sylabs.io/docs/) +[![install with bioconda](https://img.shields.io/badge/install%20with-bioconda-brightgreen)](http://bioconda.github.io/) +[![Docker Container available](https://img.shields.io/docker/automated/nfcore/sarek)](https://hub.docker.com/r/nfcore/sarek/) +[![Install with Singularity](https://img.shields.io/badge/use%20with-singularity-purple)](https://www.sylabs.io/docs/) -[![Join us on Slack](https://img.shields.io/badge/slack-nfcore/sarek-blue.svg)](https://nfcore.slack.com/messages/CGFUX04HZ/) +[![Join us on Slack](https://img.shields.io/badge/slack-nfcore/sarek-blue)](https://nfcore.slack.com/channels/sarek) ## Introduction - - -Previously known as the Cancer Analysis Workflow (CAW), Sarek is a workflow designed to run analyses on whole genome or targeted sequencing data from regular samples or tumour / normal pairs and could include additional relapses. It's built using [Nextflow](https://www.nextflow.io), From e7d4428d68d50efea2a03ca0987f3c61d1a6168f Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Thu, 28 Nov 2019 17:28:48 +0100 Subject: [PATCH 259/854] remove Freebayes --- bin/scrape_software_versions.py | 2 -- docs/containers.md | 1 - docs/output.md | 14 --------- docs/usage.md | 9 +++--- environment.yml | 1 - main.nf | 52 +++++---------------------------- scripts/run_tests.sh | 4 +-- 7 files changed, 14 insertions(+), 69 deletions(-) diff --git a/bin/scrape_software_versions.py b/bin/scrape_software_versions.py index 617740e595..d85700a0e2 100755 --- a/bin/scrape_software_versions.py +++ b/bin/scrape_software_versions.py @@ -9,7 +9,6 @@ 'bcftools': ['v_bcftools.txt', r"bcftools (\S+)"], 'BWA': ['v_bwa.txt', r"Version: (\S+)"], 'FastQC': ['v_fastqc.txt', r"FastQC v(\S+)"], - 'FreeBayes': ['v_freebayes.txt', r"version: v(\d\.\d\.\d+)"], 'GATK': ['v_gatk.txt', r"Version:(\S+)"], 'htslib': ['v_samtools.txt', r"htslib (\S+)"], 'Manta': ['v_manta.txt', r"([0-9.]+)"], @@ -33,7 +32,6 @@ results['bcftools'] = 'N/A' results['BWA'] = 'N/A' results['FastQC'] = 'N/A' -results['FreeBayes'] = 'N/A' results['GATK'] = 'N/A' results['htslib'] = 'N/A' results['Manta'] = 'N/A' diff --git a/docs/containers.md b/docs/containers.md index b75d74db9a..d8a51fb637 100644 --- a/docs/containers.md +++ b/docs/containers.md @@ -20,7 +20,6 @@ For annotation, the main container can be used, but the cache has to be download - Contain **[BWA](https://github.com/lh3/bwa)** 0.7.17 - Contain **[Control-FREEC](https://github.com/BoevaLab/FREEC)** 11.5 - Contain **[FastQC](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/)** 0.11.8 -- Contain **[FreeBayes](https://github.com/ekg/freebayes)** 1.3.1 - Contain **[GATK4](https://github.com/broadinstitute/gatk)** 4.1.4.0 - Contain **[GeneSplicer](https://ccb.jhu.edu/software/genesplicer/)** 1.0 - Contain **[HTSlib](https://github.com/samtools/htslib)** 1.9 diff --git a/docs/output.md b/docs/output.md index 58f9af63a2..1f14fdf857 100644 --- a/docs/output.md +++ b/docs/output.md @@ -17,7 +17,6 @@ The pipeline processes data using the following steps: * `GATK ApplyBQSR` 2. [**Variant calling**](#Variant-Calling) * SNVs and small indels - * [`FreeBayes`](#FreeBayes) * [`GATK HaplotypeCaller`](#HaplotypeCaller) * [`GATK GenotypeGVCFs`](#GenotypeGVCFs) * [`GATK Mutect2`](#Mutect2) @@ -100,18 +99,6 @@ All the results regarding variant-calling are collected in this directory. Recalibrated BAM files can also be used as an input to start the Variant Calling, for more information see [TSV files output information](#TSV-files) -### FreeBayes - -[FreeBayes](https://github.com/ekg/freebayes) is a Bayesian genetic variant detector designed to find small polymorphisms, specifically SNPs, indels, MNPs, and complex events smaller than the length of a short-read sequencing alignment.. - -For further reading and documentation see the [FreeBayes manual](https://github.com/ekg/freebayes/blob/master/README.md#user-manual-and-guide). - -For a Tumor/Normal pair only: -**Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/FreeBayes`** - -* `FreeBayes_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz` and `FreeBayes_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.tbi` - * VCF with Tabix index - ### HaplotypeCaller [GATK HaplotypeCaller](https://github.com/broadinstitute/gatk) calls germline SNPs and indels via local re-assembly of haplotypes. @@ -331,7 +318,6 @@ For a Tumor/Normal pair only: This directory contains results from the final annotation steps: two software are used for annotation, [snpEff](http://snpeff.sourceforge.net/) and [VEP](https://www.ensembl.org/info/docs/tools/vep/index.html). Only a subset of the VCF files are annotated, and only variants that have a PASS filter. -FreeBayes results are not annotated in the moment yet as we are lacking a decent somatic filter. For HaplotypeCaller the germline variations are annotated for both the tumor and the normal sample. ### snpEff diff --git a/docs/usage.md b/docs/usage.md index ef4346006d..4ddc0ba79b 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -106,8 +106,9 @@ results # Finished results (configurable, see below) ``` The nf-core/sarek pipeline comes with more documentation about running the pipeline, found in the `docs/` directory: - * [Extra Documentation on variant calling](docs/variantcalling.md) - * [Extra Documentation on annotation](docs/annotation.md) + +* [Output and how to interpret the results](output.md) +* [Extra Documentation on annotation](annotation.md) ### Updating the pipeline @@ -268,7 +269,7 @@ Available: `mapping`, `recalibrate`, `variantcalling` and `annotate` ### `--tools` Use this to specify the tools to run: -Available: `ASCAT`, `ControlFREEC`, `FreeBayes`, `HaplotypeCaller`, `Manta`, `mpileup`, `MuTect2`, `Strelka`, `TIDDIT` +Available: `ASCAT`, `ControlFREEC`, `HaplotypeCaller`, `Manta`, `mpileup`, `Mutect2`, `Strelka`, `TIDDIT` ### `--noStrelkaBP` @@ -280,7 +281,7 @@ Use this to specify the target BED file for targeted or whole exome sequencing. ## Reference genomes -The pipeline config files come bundled with paths to the illumina iGenomes reference index files. +The pipeline config files come bundled with paths to the Illumina iGenomes reference index files. If running with docker or AWS, the configuration is set up to use the [AWS-iGenomes](https://ewels.github.io/AWS-iGenomes/) resource. ### `--genome` (using iGenomes) diff --git a/environment.yml b/environment.yml index 56e57e8f0a..bcaea91970 100644 --- a/environment.yml +++ b/environment.yml @@ -13,7 +13,6 @@ dependencies: - control-freec=11.5 - ensembl-vep=98.2 - fastqc=0.11.8 - - freebayes=1.3.1 - gatk4=4.1.4.0 - genesplicer=1.0 - htslib=1.9 diff --git a/main.nf b/main.nf index 052b7fb26b..fef6238812 100644 --- a/main.nf +++ b/main.nf @@ -50,7 +50,7 @@ def helpMessage() { Available: Mapping, Recalibrate, VariantCalling, Annotate Default: Mapping --tools Specify tools to use for variant calling: - Available: ASCAT, ControlFREEC, FreeBayes, HaplotypeCaller + Available: ASCAT, ControlFREEC, HaplotypeCaller Manta, mpileup, Mutect2, Strelka, TIDDIT and/or for annotation: snpEff, VEP, merge @@ -348,7 +348,6 @@ process GetSoftwareVersions { echo "${workflow.nextflow.version}" &> v_nextflow.txt 2>&1 || true echo "SNPEFF version"\$(snpEff -h 2>&1) > v_snpeff.txt fastqc --version > v_fastqc.txt 2>&1 || true - freebayes --version > v_freebayes.txt 2>&1 || true gatk ApplyBQSR --help 2>&1 | grep Version: > v_gatk.txt 2>&1 || true multiqc --version &> v_multiqc.txt 2>&1 || true qualimap --version &> v_qualimap.txt 2>&1 || true @@ -1277,44 +1276,8 @@ intervalPairBam = pairBam.spread(bedIntervals) bamMpileup = bamMpileup.spread(intMpileup) -// intervals for Mutect2 calls, FreeBayes and pileups for Mutect2 filtering -(pairBamMutect2, pairBamFreeBayes, pairBamPileupSummaries) = intervalPairBam.into(3) - -// STEP FREEBAYES - -process FreeBayes { - tag {idSampleTumor + "_vs_" + idSampleNormal + "-" + intervalBed.baseName} - label 'cpus_1' - - input: - set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from pairBamFreeBayes - file(fasta) from ch_fasta - file(fastaFai) from ch_fastaFai - - output: - set val("FreeBayes"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf") into vcfFreeBayes - - when: 'freebayes' in tools - - script: - """ - freebayes \ - -f ${fasta} \ - --pooled-continuous \ - --pooled-discrete \ - --genotype-qualities \ - --report-genotype-likelihood-max \ - --allele-balance-priors-off \ - --min-alternate-fraction 0.03 \ - --min-repeat-entropy 1 \ - --min-alternate-count 2 \ - -t ${intervalBed} \ - ${bamTumor} \ - ${bamNormal} > ${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf - """ -} - -vcfFreeBayes = vcfFreeBayes.groupTuple(by:[0,1,2]) +// intervals for Mutect2 calls and pileups for Mutect2 filtering +(pairBamMutect2, pairBamPileupSummaries) = intervalPairBam.into(2) // STEP GATK MUTECT2.1 - RAW CALLS @@ -1403,9 +1366,9 @@ process MergeMutect2Stats { // we are merging the VCFs that are called separatelly for different intervals // so we can have a single sorted VCF containing all the calls for a given caller -// STEP MERGING VCF - FREEBAYES, GATK HAPLOTYPECALLER & GATK MUTECT2 (UNFILTERED) +// STEP MERGING VCF - GATK HAPLOTYPECALLER & GATK MUTECT2 (UNFILTERED) -vcfConcatenateVCFs = mutect2Output.mix( vcfFreeBayes, vcfGenotypeGVCFs, gvcfHaplotypeCaller) +vcfConcatenateVCFs = mutect2Output.mix(vcfGenotypeGVCFs, gvcfHaplotypeCaller) vcfConcatenateVCFs = vcfConcatenateVCFs.dump(tag:'VCF to merge') process ConcatVCF { @@ -1424,7 +1387,7 @@ process ConcatVCF { // we have this funny *_* pattern to avoid copying the raw calls to publishdir set variantCaller, idPatient, idSample, file("*_*.vcf.gz"), file("*_*.vcf.gz.tbi") into vcfConcatenated - when: ('haplotypecaller' in tools || 'mutect2' in tools || 'freebayes' in tools) + when: ('haplotypecaller' in tools || 'mutect2' in tools) script: if (variantCaller == 'HaplotypeCallerGVCF') @@ -2120,7 +2083,7 @@ if (step == 'annotate') { if (tsvPath == []) { // Sarek, by default, annotates all available vcfs that it can find in the VariantCalling directory - // Excluding vcfs from FreeBayes, and g.vcf from HaplotypeCaller + // Excluding g.vcf from HaplotypeCaller // Basically it's: VariantCalling/*/{HaplotypeCaller,Manta,Mutect2,Strelka,TIDDIT}/*.vcf.gz // Without *SmallIndels.vcf.gz from Manta, and *.genome.vcf.gz from Strelka // The small snippet `vcf.minus(vcf.fileName)[-2]` catches idSample @@ -2662,7 +2625,6 @@ def defineToolList() { return [ 'ascat', 'controlfreec', - 'freebayes', 'haplotypecaller', 'manta', 'merge', diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index cb6db88901..4892df61f8 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -84,7 +84,7 @@ else SUFFIX="" fi -OPTIONS="--tools FreeBayes,HaplotypeCaller,Manta,Mutect2,Strelka,TIDDIT" +OPTIONS="--tools HaplotypeCaller,Manta,Mutect2,Strelka,TIDDIT" if [[ $TEST == "GERMLINE" ]] && [[ $OFFLINE == false ]] then @@ -117,7 +117,7 @@ case $TEST in run_sarek --tools HaplotypeCaller --input results/Preprocessing/TSV/recalibrated.tsv --step variantCalling ;; MULTIPLE) - run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,TIDDIT,snpEff,VEP,merge --input ${PATHTOSAMPLE}/tsv/tiny-multiple${SUFFIX}.tsv + run_sarek --tools HaplotypeCaller,Manta,Strelka,TIDDIT,snpEff,VEP,merge --input ${PATHTOSAMPLE}/tsv/tiny-multiple${SUFFIX}.tsv ;; SOMATIC) run_sarek ${OPTIONS} --input ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv From a48c35ee74cbd8afa0945f2758b8335fe98d66b6 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Thu, 28 Nov 2019 17:32:51 +0100 Subject: [PATCH 260/854] update workflow image --- docs/images/sarek_workflow.png | Bin 50856 -> 47599 bytes docs/images/sarek_workflow.svg | 16 ++++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/images/sarek_workflow.png b/docs/images/sarek_workflow.png index f7f019de0cd8cec8f39e17cfdc182eefb16a9160..3d7253ee44af0ebaff1486b35b3b90e6abbb58a8 100644 GIT binary patch literal 47599 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 literal 50856 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 @@ -2787,6 +2788,7 @@ + Preprocessing + • Freebayes, Mutect2 Strelka2• Mutect2, Strelka2• MantaAnnotation + Reports + 2.52.6 Date: Thu, 28 Nov 2019 17:33:09 +0100 Subject: [PATCH 261/854] remove old logo --- docs/images/CAW_logo.png | Bin 9692 -> 0 bytes docs/images/CAW_logo.svg | 649 --------------------------------------- 2 files changed, 649 deletions(-) delete mode 100644 docs/images/CAW_logo.png delete mode 100644 docs/images/CAW_logo.svg diff --git a/docs/images/CAW_logo.png b/docs/images/CAW_logo.png deleted file mode 100644 index 285d7274089e79ade109491e7103fad4758d204e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9692 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 rHPwD=?T>lm=HdSZd3Vtt diff --git a/docs/images/CAW_logo.svg b/docs/images/CAW_logo.svg deleted file mode 100644 index 9b25dec5f6..0000000000 --- a/docs/images/CAW_logo.svg +++ /dev/null @@ -1,649 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From b6942fd1084a5b3d0392316fc7e4b8d2b157d99a Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 29 Nov 2019 10:41:32 +0100 Subject: [PATCH 262/854] fix tests --- main.nf | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/main.nf b/main.nf index 973418cb02..50dff290a4 100644 --- a/main.nf +++ b/main.nf @@ -585,7 +585,10 @@ bedIntervals = bedIntervals.dump(tag:'bedintervals') inputPairReads = Channel.create() inputBam = Channel.create() -inputSample.choice(inputPairReads, inputBam) {hasExtension(it[3], "bam") ? 1 : 0} +if (step in ['recalibrate', 'variantcalling']) { + inputBam.close() + inputPairReads.close() +} else inputSample.choice(inputPairReads, inputBam) {hasExtension(it[3], "bam") ? 1 : 0} (inputBam, inputBamFastQC) = inputBam.into(2) From 503c1023a8290f65437f4b7b6b35700e30ae4156 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 29 Nov 2019 11:04:05 +0100 Subject: [PATCH 263/854] add docs about params split_fastq --- docs/usage.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/usage.md b/docs/usage.md index ef4346006d..7317872e10 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -12,6 +12,7 @@ * [Main arguments](#main-arguments) * [`-profile`](#-profile) * [`--input`](#--input) + * [`--split_fastq`](#--split_fastq) * [`--sample`](#--sample) * [`--sampleDir`](#--sampledir) * [`--annotateVCF`](#--annotatevcf) @@ -182,6 +183,15 @@ For example: Multiple VCF files can be specified if the path must be enclosed in quotes +### `--split_fastq` + +Use the Nextflow [`splitFastq`](https://www.nextflow.io/docs/latest/operator.html#splitfastq) operator to specify how many reads should be contained in the split fastq file. +For example: + +```bash +--split_fastq 10000 +``` + ### `--sample` > :warning: This params is deprecated -- it will be removed in a future release. From 7176fa58adb82f53ba94974aca8ceab0d5e1ee45 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 29 Nov 2019 11:27:51 +0100 Subject: [PATCH 264/854] update CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7238d184b1..6e2b55345b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [#46](https://github.com/nf-core/sarek/pull/46) - Add location to abstacts - [#52](https://github.com/nf-core/sarek/pull/52) - Add support for mouse data `GRCm38` +- [#61](https://github.com/nf-core/sarek/pull/61) - Add params `split_fastq` +- [#61](https://github.com/nf-core/sarek/pull/61) - Add test `SPLITFASTQ` ### `Changed` From d0ff5761e45ca77b0a9f5f3b496e2361e1403e3d Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 2 Dec 2019 10:28:47 +0100 Subject: [PATCH 265/854] improve docs --- .github/CONTRIBUTING.md | 8 ++++++-- .github/ISSUE_TEMPLATE/bug_report.md | 16 ++++++++-------- README.md | 12 ++++++------ docs/annotation.md | 3 ++- docs/input.md | 2 ++ 5 files changed, 24 insertions(+), 17 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 8c8447976d..36fed625b8 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -46,8 +46,12 @@ These tests are run both with the latest available version of `Nextflow` and als ## Patch -When patching a release, please work on your fork on a new branch named `patch` +: warning: Only in the unlikely and regretful event of a release happening with a bug. + +* On your own fork, make a new branch `patch` based on `upstream/master`. +* Fix the bug, and bump version (X.Y.Z+1). +* A PR should be made on `master` from patch to directly this particular bug. ## Getting help -For further information/help, please consult the [nf-core/sarek documentation](https://github.com/nf-core/sarek#documentation) and don't hesitate to get in touch on the nf-core Slack [#sarek](https://nfcore.slack.com/channels/sarek) channel ([join our Slack here](https://nf-co.re/join/slack)). +For further information/help, please consult the [nf-core/sarek documentation](https://nf-co.re/sarek/docs) and don't hesitate to get in touch on the nf-core Slack [#sarek](https://nfcore.slack.com/channels/sarek) channel ([join our Slack here](https://nf-co.re/join/slack)). diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 5e62bedd66..c6643b83ab 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -22,20 +22,20 @@ A clear and concise description of what you expected to happen. ## System -- Hardware: [e.g. HPC, Desktop, Cloud...] -- Executor: [e.g. slurm, local, awsbatch...] -- OS: [e.g. CentOS Linux, macOS, Linux Mint...] -- Version [e.g. 7, 10.13.6, 18.3...] +- Hardware: +- Executor: +- OS: +- Version ## Nextflow Installation -- Version: [e.g. 0.31.0] +- Version: ## Container engine -- Engine: [e.g. Conda, Docker or Singularity] -- version: [e.g. 1.0.0] -- Image tag: [e.g. nfcore/sarek:2.5.1] +- Engine: +- version: +- Image tag: ## Additional context diff --git a/README.md b/README.md index addec50a11..6c9101cbc3 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ > **An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing** -[![Nextflow](https://img.shields.io/badge/nextflow-%E2%89%A519.04.0-brightgreen)](https://www.nextflow.io/) -[![nf-core](https://img.shields.io/badge/nf--core-pipeline-brightgreen)](https://nf-co.re/) +[![Nextflow](https://img.shields.io/badge/nextflow-%E2%89%A519.04.0-brightgreen.svg)](https://www.nextflow.io/) +[![nf-core](https://img.shields.io/badge/nf--core-pipeline-brightgreen.svg)](https://nf-co.re/) [![DOI](https://zenodo.org/badge/184289291.svg)](https://zenodo.org/badge/latestdoi/184289291) [![GitHub Actions CI status](https://github.com/nf-core/sarek/workflows/nf-core%20CI/badge.svg)](https://github.com/nf-core/sarek/actions?query=workflow%3A%22sarek+CI%22) @@ -11,11 +11,11 @@ [![GitHub Actions Linting status](https://github.com/nf-core/sarek/workflows/nf-core%20linting/badge.svg)](https://github.com/nf-core/sarek/actions?query=workflow%3A%22sarek+linting%22) [![CircleCi build status](https://img.shields.io/circleci/project/github/nf-core/sarek?logo=circleci)](https://circleci.com/gh/nf-core/sarek/) -[![install with bioconda](https://img.shields.io/badge/install%20with-bioconda-brightgreen)](http://bioconda.github.io/) -[![Docker Container available](https://img.shields.io/docker/automated/nfcore/sarek)](https://hub.docker.com/r/nfcore/sarek/) -[![Install with Singularity](https://img.shields.io/badge/use%20with-singularity-purple)](https://www.sylabs.io/docs/) +[![install with bioconda](https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg)](http://bioconda.github.io/) +[![Docker Container available](https://img.shields.io/docker/automated/nfcore/sarek.svg)](https://hub.docker.com/r/nfcore/sarek/) +[![Install with Singularity](https://img.shields.io/badge/use%20with-singularity-purple.svg)](https://www.sylabs.io/docs/) -[![Join us on Slack](https://img.shields.io/badge/slack-nfcore/sarek-blue)](https://nfcore.slack.com/channels/sarek) +[![Join us on Slack](https://img.shields.io/badge/slack-nfcore/sarek-blue.svg)](https://nfcore.slack.com/channels/sarek) ## Introduction diff --git a/docs/annotation.md b/docs/annotation.md index bec92ff7d6..2d954f3ac8 100644 --- a/docs/annotation.md +++ b/docs/annotation.md @@ -14,6 +14,7 @@ With Sarek, annotation is done using `snpEff`, `VEP`, or even both consecutively - To annotate using `snpEff` followed by `VEP` VCF produced by Sarek will be annotated if `snpEff` or `VEP` are specified with the `--tools` command. +As Sarek will use `bgzip` and `tabix` to compress and index VCF files annotated, it expects VCF files to be sorted. In these examples, all command lines will be launched starting with step `annotate`. It can of course be started directly from any other step instead. @@ -23,7 +24,7 @@ It can of course be started directly from any other step instead. Sarek has already designed containers with `snpEff` and `VEP` files for `GRCh37`, `GRCh38` and `GRCm38`. Default settings will run using these containers. -The main Sarek container has also `snpEff` and `VEP` installed, but without the cache files that can be downloaded separatelly. +The main Sarek container has also `snpEff` and `VEP` installed, but without the cache files that can be downloaded separately. ## Using downloaded cache diff --git a/docs/input.md b/docs/input.md index 18e6695855..7507344cd9 100644 --- a/docs/input.md +++ b/docs/input.md @@ -131,6 +131,8 @@ G15511 XX 1 D0ENMT pathToFiles/G15511.D0ENMT.md.recal.bam pathToF Input files for Sarek can be specified using the path to a VCF directory given to the `--input` command only with the `annotate` step. Multiple VCF files can be specified if the path is enclosed in quotes. +As Sarek will use `bgzip` and `tabix` to compress and index VCF files annotated, it expects VCF files to be sorted. + ```bash nextflow run nf-core/sarek --step annotate --input "results/VariantCalling/*/.vcf.gz" ... ``` From 8c0cf0d599b49a543d931fe27a559739417748f1 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 2 Dec 2019 10:53:00 +0100 Subject: [PATCH 266/854] more tests but less NF versions --- .github/workflows/ci-extra.yml | 6 +++--- scripts/run_tests.sh | 16 ++++++++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci-extra.yml b/.github/workflows/ci-extra.yml index d37a33aae0..2d38b8c02d 100644 --- a/.github/workflows/ci-extra.yml +++ b/.github/workflows/ci-extra.yml @@ -7,15 +7,15 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - test: [ANNOTATESNPEFF, GERMLINE, SOMATIC, TARGETED] - nxf_ver: ['19.04.0', ''] + test: [ANNOTATESNPEFF, GERMLINE, TARGETED, HAPLOTYPECALLER, MANTA, MUTECT2, STRELKA, TIDDIT] steps: - uses: actions/checkout@v1 - name: Install Nextflow run: | - export NXF_VER=${{ matrix.nxf_ver }} wget -qO- get.nextflow.io | bash sudo mv nextflow /usr/local/bin/ + env: + NXF_VER: '19.04.0' - name: Download image run: | ${GITHUB_WORKSPACE}/scripts/download_image.sh -n docker --source-version dev --target-version dev --test ${{ matrix.test }} diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index 4892df61f8..6c4b0ef143 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -107,6 +107,13 @@ case $TEST in ;; esac +if [[ HAPLOTYPECALLER,MANTA,MUTECT2,STRELKA,TIDDIT =~ $TEST ]] +then + TOOLS=$TEST +fi + + + case $TEST in ANNOTATE) run_sarek --step annotate --tools ${ANNOTATOR} --input ${PATHTOSAMPLE}/vcf/Strelka_1234N_variants.vcf.gz --skipQC all @@ -116,14 +123,11 @@ case $TEST in run_sarek --tools=false --input results/Preprocessing/TSV/duplicateMarked.tsv --step recalibrate run_sarek --tools HaplotypeCaller --input results/Preprocessing/TSV/recalibrated.tsv --step variantCalling ;; - MULTIPLE) - run_sarek --tools HaplotypeCaller,Manta,Strelka,TIDDIT,snpEff,VEP,merge --input ${PATHTOSAMPLE}/tsv/tiny-multiple${SUFFIX}.tsv - ;; - SOMATIC) - run_sarek ${OPTIONS} --input ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv + TOOLS) + run_sarek --input ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv --TOOLS ${TOOLS} ;; TARGETED) - run_sarek ${OPTIONS} --input ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv --targetBED ${PATHTOSAMPLE}/target.bed + run_sarek --input ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv --targetBED ${PATHTOSAMPLE}/target.bed --tools Manta,Strelka ;; esac From df3d68a3c988b46dad5c8c4c11bd5aeb403134b5 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 2 Dec 2019 10:59:46 +0100 Subject: [PATCH 267/854] actually run the tests --- scripts/run_tests.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index 6c4b0ef143..eecf762b86 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -110,10 +110,9 @@ esac if [[ HAPLOTYPECALLER,MANTA,MUTECT2,STRELKA,TIDDIT =~ $TEST ]] then TOOLS=$TEST + TEST="TOOLS" fi - - case $TEST in ANNOTATE) run_sarek --step annotate --tools ${ANNOTATOR} --input ${PATHTOSAMPLE}/vcf/Strelka_1234N_variants.vcf.gz --skipQC all From 9b3a02730be59531797bb1c14f56d80a8258dc71 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 2 Dec 2019 11:08:37 +0100 Subject: [PATCH 268/854] typo --- scripts/run_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index eecf762b86..b84cb85a40 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -123,7 +123,7 @@ case $TEST in run_sarek --tools HaplotypeCaller --input results/Preprocessing/TSV/recalibrated.tsv --step variantCalling ;; TOOLS) - run_sarek --input ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv --TOOLS ${TOOLS} + run_sarek --input ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv --tools ${TOOLS} ;; TARGETED) run_sarek --input ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv --targetBED ${PATHTOSAMPLE}/target.bed --tools Manta,Strelka From 6b76428b40a7847232c80c005ac6c1b55372c01b Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 2 Dec 2019 15:50:13 +0100 Subject: [PATCH 269/854] simplify configs --- conf/base.config | 5 +---- main.nf | 2 ++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/conf/base.config b/conf/base.config index 5c76d275e6..7c889b04ba 100644 --- a/conf/base.config +++ b/conf/base.config @@ -54,10 +54,7 @@ process { // (exit code 141). Rerunning the process will usually work. errorStrategy = {task.exitStatus == 141 ? 'retry' : 'terminate'} } - withName:FastQCBAM { - errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} - } - withName:FastQCFQ { + withLabel:FastQC { errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} } withName:MapReads { diff --git a/main.nf b/main.nf index fef6238812..33d34766de 100644 --- a/main.nf +++ b/main.nf @@ -603,6 +603,7 @@ inputReads = inputReads.dump(tag:'INPUT') // FASTQ and uBAM files are renamed based on the sample name process FastQCFQ { + label 'FastQC' label 'cpus_2' tag {idPatient + "-" + idRun} @@ -624,6 +625,7 @@ process FastQCFQ { } process FastQCBAM { + label 'FastQC' label 'cpus_2' tag {idPatient + "-" + idRun} From b696b5a1abb50c496bfbed5e37e4567d99574f34 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 2 Dec 2019 15:50:28 +0100 Subject: [PATCH 270/854] add test for mpileup --- .github/workflows/ci-extra.yml | 2 +- scripts/run_tests.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-extra.yml b/.github/workflows/ci-extra.yml index 2d38b8c02d..b2c57a84f3 100644 --- a/.github/workflows/ci-extra.yml +++ b/.github/workflows/ci-extra.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - test: [ANNOTATESNPEFF, GERMLINE, TARGETED, HAPLOTYPECALLER, MANTA, MUTECT2, STRELKA, TIDDIT] + test: [ANNOTATESNPEFF, GERMLINE, TARGETED, HAPLOTYPECALLER, MANTA, MPILEUP, MUTECT2, STRELKA, TIDDIT] steps: - uses: actions/checkout@v1 - name: Install Nextflow diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index b84cb85a40..2b4a74436d 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -107,7 +107,7 @@ case $TEST in ;; esac -if [[ HAPLOTYPECALLER,MANTA,MUTECT2,STRELKA,TIDDIT =~ $TEST ]] +if [[ HAPLOTYPECALLER,MANTA,MPILEUP,MUTECT2,STRELKA,TIDDIT =~ $TEST ]] then TOOLS=$TEST TEST="TOOLS" From ca19e18b285c09286bfda183e339f336119cfa60 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 3 Dec 2019 12:00:47 +0100 Subject: [PATCH 271/854] update docs --- docs/output.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/output.md b/docs/output.md index 58f9af63a2..fbf8216675 100644 --- a/docs/output.md +++ b/docs/output.md @@ -152,9 +152,9 @@ For a Tumor/Normal pair only: Files created: -* `unfiltered_Mutect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz` and `unfiltered_Mutect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.tbi` +* `Mutect2_unfiltered_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz` and `Mutect2_unfiltered_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.tbi` * unfiltered (raw) Mutect2 calls VCF with Tabix index -* `filtered_Mutect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz` and `filtered_Mutect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.tbi` +* `Mutect2_filtered_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz` and `Mutect2_filtered_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.tbi` * filtered Mutect2 calls VCF with Tabix index: these entries has a PASS filter, you can get these when supplying a panel of normals using the `--pon` option * `[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.stats` * a stats file generated during calling raw variants (needed for filtering) From 67c53094ceb2ebed6b9e942a1d4019bbcd17736c Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 3 Dec 2019 16:01:05 +0100 Subject: [PATCH 272/854] go crazy with tests --- .github/workflows/branch.yml | 2 +- .github/workflows/ci-extra.yml | 52 ++++++++++++++++++++++++++++++---- .github/workflows/ci.yml | 2 +- .github/workflows/linting.yml | 6 ++-- conf/test.config | 4 ++- conf/test_annotation.config | 15 ++++++++++ conf/test_splitfastq.config | 12 ++++++++ conf/test_targeted.config | 15 ++++++++++ conf/test_tool.config | 16 +++++++++++ nextflow.config | 4 +++ scripts/download_image.sh | 13 ++------- scripts/run_tests.sh | 18 ------------ 12 files changed, 120 insertions(+), 39 deletions(-) create mode 100644 conf/test_annotation.config create mode 100644 conf/test_splitfastq.config create mode 100644 conf/test_targeted.config create mode 100644 conf/test_tool.config diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 06824f2d77..1342a9d7b3 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -7,7 +7,7 @@ on: jobs: test: - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 steps: # PRs are only ok if coming from an nf-core dev branch - uses: actions/checkout@v1 diff --git a/.github/workflows/ci-extra.yml b/.github/workflows/ci-extra.yml index 3043486bcd..f0d07178bb 100644 --- a/.github/workflows/ci-extra.yml +++ b/.github/workflows/ci-extra.yml @@ -3,11 +3,11 @@ name: sarek extra CI on: [push, pull_request] jobs: - test: - runs-on: ubuntu-latest + profile: + runs-on: ubuntu-18.04 strategy: matrix: - test: [ANNOTATESNPEFF, GERMLINE, SPLITFASTQ, TARGETED, HAPLOTYPECALLER, MANTA, MPILEUP, MUTECT2, STRELKA, TIDDIT] + profile: [splitfastq, targeted] steps: - uses: actions/checkout@v1 - name: Install Nextflow @@ -18,7 +18,49 @@ jobs: NXF_VER: '19.04.0' - name: Download image run: | - ${GITHUB_WORKSPACE}/scripts/download_image.sh -n docker --source-version dev --target-version dev --test ${{ matrix.test }} + docker pull nfcore/sarek:dev + docker tag nfcore/sarek:dev nfcore/sarek:dev - name: Run test run: | - ${GITHUB_WORKSPACE}/scripts/run_tests.sh --test ${{ matrix.test }} --verbose \ No newline at end of file + nextflow run . -profile ${{ matrix.profile }},docker --verbose + tools: + runs-on: ubuntu-18.04 + strategy: + matrix: + tool: [Haplotypecaller, Manta, mpileup, Mutect2, Strelka, TIDDIT] + steps: + - uses: actions/checkout@v1 + - name: Install Nextflow + run: | + wget -qO- get.nextflow.io | bash + sudo mv nextflow /usr/local/bin/ + env: + NXF_VER: '19.04.0' + - name: Download image + run: | + docker pull nfcore/sarek:dev + docker tag nfcore/sarek:dev nfcore/sarek:dev + - name: Run test + run: | + nextflow run . -profile test_tool,docker --verbose --tools ${{ matrix.tool }} + annotation: + runs-on: ubuntu-18.04 + strategy: + matrix: + annotator: [snpeff] + specie: [GRCh37] + steps: + - uses: actions/checkout@v1 + - name: Install Nextflow + run: | + wget -qO- get.nextflow.io | bash + sudo mv nextflow /usr/local/bin/ + env: + NXF_VER: '19.04.0' + - name: Download image + run: | + docker pull nfcore/sarek${{ matrix.annotator }}:dev.{{ matrix.specie }} + docker tag nfcore/sarek${{ matrix.annotator }}:dev.{{ matrix.specie }} nfcore/sarek${{ matrix.annotator }}:dev.{{ matrix.specie }} + - name: Run test + run: | + nextflow run . -profile test_annotation,docker --verbose --tools ${{ matrix.annotator }} \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 22c1031208..9b65872c36 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,7 @@ on: [push, pull_request] jobs: test: - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 strategy: matrix: nxf_ver: ['19.04.0', ''] diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 3892e41f2f..53f1efd031 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -4,7 +4,7 @@ on: [push, pull_request] jobs: Markdown: - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v1 - uses: actions/setup-node@v1 @@ -17,7 +17,7 @@ jobs: run: | markdownlint ${GITHUB_WORKSPACE} -c ${GITHUB_WORKSPACE}/.github/markdownlint.yml YAML: - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v1 - uses: actions/setup-node@v1 @@ -30,7 +30,7 @@ jobs: run: | yamllint $(find ${GITHUB_WORKSPACE} -type f -name "*.yml") nf-core: - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v1 - name: Install Nextflow diff --git a/conf/test.config b/conf/test.config index 9652998f3b..d8b3673d9c 100644 --- a/conf/test.config +++ b/conf/test.config @@ -24,9 +24,11 @@ params { process { withName:Snpeff { + container = 'nfcore/sareksnpeff:dev.GRCh37' maxForks = 1 } - withName:VEP { + withLabel:VEP { + container = 'nfcore/sarekvep:dev.GRCh37' maxForks = 1 } } diff --git a/conf/test_annotation.config b/conf/test_annotation.config new file mode 100644 index 0000000000..6dc8799d22 --- /dev/null +++ b/conf/test_annotation.config @@ -0,0 +1,15 @@ +/* + * ------------------------------------------------- + * Nextflow config file for running tests + * ------------------------------------------------- + * Defines bundled input files and everything required + * to run a fast and simple test. Use as follows: + * nextflow run nf-core/sarek -profile test + */ + +includeConfig 'test.config' + +params { + input = 'https://github.com/nf-core/test-datasets/raw/sarek/testdata/vcf/Strelka_1234N_variants.vcf.gz' + genome = 'GRCh37' +} \ No newline at end of file diff --git a/conf/test_splitfastq.config b/conf/test_splitfastq.config new file mode 100644 index 0000000000..734852424e --- /dev/null +++ b/conf/test_splitfastq.config @@ -0,0 +1,12 @@ +/* + * ------------------------------------------------- + * Nextflow config file for running tests + * ------------------------------------------------- + * Defines bundled input files and everything required + * to run a fast and simple test. Use as follows: + * nextflow run nf-core/sarek -profile test + */ + +params { + split_fastq = 500 +} \ No newline at end of file diff --git a/conf/test_targeted.config b/conf/test_targeted.config new file mode 100644 index 0000000000..b3575300c1 --- /dev/null +++ b/conf/test_targeted.config @@ -0,0 +1,15 @@ +/* + * ------------------------------------------------- + * Nextflow config file for running tests + * ------------------------------------------------- + * Defines bundled input files and everything required + * to run a fast and simple test. Use as follows: + * nextflow run nf-core/sarek -profile test_targeted + */ + +includeConfig 'test.config' + +params { + targetBed = 'https://github.com/nf-core/test-datasets/raw/sarek/testdata/tsv/tiny-manta-https.tsv' + tools = 'manta,strelka' +} \ No newline at end of file diff --git a/conf/test_tool.config b/conf/test_tool.config new file mode 100644 index 0000000000..fa51779592 --- /dev/null +++ b/conf/test_tool.config @@ -0,0 +1,16 @@ +/* + * ------------------------------------------------- + * Nextflow config file for running tests + * ------------------------------------------------- + * Defines bundled input files and everything required + * to run a fast and simple test. Use as follows: + * nextflow run nf-core/sarek -profile test + */ + +includeConfig 'test.config' + +params { + // Input data + input = 'https://github.com/nf-core/test-datasets/raw/sarek/testdata/tsv/tiny-recal-pair-https.tsv' + step = 'variantcalling' +} \ No newline at end of file diff --git a/nextflow.config b/nextflow.config index d5ef7098be..1038bbcc8c 100644 --- a/nextflow.config +++ b/nextflow.config @@ -121,6 +121,10 @@ profiles { singularity.enabled = true } test { includeConfig 'conf/test.config' } + test_annotation { includeConfig 'conf/test_annotation.config' } + test_splitfastq { includeConfig 'conf/test_splitfastq.config' } + test_targeted { includeConfig 'conf/test_targeted.config' } + test_tool { includeConfig 'conf/test_tool.config' } } // Load genomes.config or igenomes.config diff --git a/scripts/download_image.sh b/scripts/download_image.sh index b4ce89205b..b2955c240b 100755 --- a/scripts/download_image.sh +++ b/scripts/download_image.sh @@ -6,7 +6,7 @@ set -xeuo pipefail usage() { echo "Usage: $0 <-t test|annotation tool> <-n engine> <-S version to pull/build> <-T version to tag> <-g genome>" 1>&2; exit 1; } ENGINE=docker -GENOME=smallGRCh37 +GENOME=GRCh37 NXF_SINGULARITY_CACHEDIR=${NXF_SINGULARITY_CACHEDIR:-work/singularity/.} TEST=ALL VERSION=dev @@ -48,13 +48,6 @@ do esac done -SOURCEGENOME=${GENOME} - -if [[ smallGRCh37 =~ $SOURCEGENOME ]] -then - SOURCEGENOME=GRCh37 -fi - get_image(){ CONTAINER=$1 SOURCE=$2 @@ -72,12 +65,12 @@ get_image(){ if [[ ALL,ANNOTATEBOTH,ANNOTATESNPEFF,SNPEFF =~ $TEST ]] then - get_image sareksnpeff ${VERSION}.${SOURCEGENOME} ${TARGETVERSION}.${GENOME} + get_image sareksnpeff ${VERSION}.${GENOME} ${TARGETVERSION}.${GENOME} fi if [[ ALL,ANNOTATEBOTH,ANNOTATEVEP,VEP =~ $TEST ]] then - get_image sarekvep ${VERSION}.${SOURCEGENOME} ${TARGETVERSION}.${GENOME} + get_image sarekvep ${VERSION}.${GENOME} ${TARGETVERSION}.${GENOME} fi get_image sarek ${VERSION} ${TARGETVERSION} \ No newline at end of file diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index f45d6a5433..977543c730 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -105,16 +105,7 @@ case $TEST in ;; esac -if [[ HAPLOTYPECALLER,MANTA,MPILEUP,MUTECT2,STRELKA,TIDDIT =~ $TEST ]] -then - TOOLS=$TEST - TEST="TOOLS" -fi - case $TEST in - ANNOTATE) - run_sarek --step annotate --tools ${ANNOTATOR} --input ${PATHTOSAMPLE}/vcf/Strelka_1234N_variants.vcf.gz --skipQC all - ;; GERMLINE) run_sarek --tools=false --input data/testdata/tiny/normal run_sarek --tools=false --input results/Preprocessing/TSV/duplicateMarked.tsv --step recalibrate @@ -123,15 +114,6 @@ case $TEST in MULTIPLE) run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,snpEff,VEP,merge --input ${PATHTOSAMPLE}/tsv/tiny-multiple${SUFFIX}.tsv ;; - SPLITFASTQ) - run_sarek --input ${PATHTOSAMPLE}/tsv/tiny-manta-normal${SUFFIX}.tsv --split_fastq 500 - ;; - TARGETED) - run_sarek --input ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv --targetBED ${PATHTOSAMPLE}/target.bed --tools Manta,Strelka - ;; - TOOLS) - run_sarek --input ${PATHTOSAMPLE}/tsv/tiny-manta${SUFFIX}.tsv --tools ${TOOLS} - ;; esac if [[ $TEST == "GERMLINE" ]] && [[ $OFFLINE == false ]] From a44ae395695c131b8985ffd070817679de558cd0 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 3 Dec 2019 16:12:14 +0100 Subject: [PATCH 273/854] fix tests --- .github/workflows/ci-extra.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-extra.yml b/.github/workflows/ci-extra.yml index f0d07178bb..77d1c50e30 100644 --- a/.github/workflows/ci-extra.yml +++ b/.github/workflows/ci-extra.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-18.04 strategy: matrix: - profile: [splitfastq, targeted] + profile: [test_splitfastq, test_targeted] steps: - uses: actions/checkout@v1 - name: Install Nextflow @@ -27,7 +27,7 @@ jobs: runs-on: ubuntu-18.04 strategy: matrix: - tool: [Haplotypecaller, Manta, mpileup, Mutect2, Strelka, TIDDIT] + tool: [Haplotypecaller, Manta, mpileup, Mutect2, Strelka] steps: - uses: actions/checkout@v1 - name: Install Nextflow @@ -59,8 +59,8 @@ jobs: NXF_VER: '19.04.0' - name: Download image run: | - docker pull nfcore/sarek${{ matrix.annotator }}:dev.{{ matrix.specie }} - docker tag nfcore/sarek${{ matrix.annotator }}:dev.{{ matrix.specie }} nfcore/sarek${{ matrix.annotator }}:dev.{{ matrix.specie }} + docker pull nfcore/sarek${{ matrix.annotator }}:dev.${{ matrix.specie }} + docker tag nfcore/sarek${{ matrix.annotator }}:dev.${{ matrix.specie }} nfcore/sarek${{ matrix.annotator }}:dev.${{ matrix.specie }} - name: Run test run: | nextflow run . -profile test_annotation,docker --verbose --tools ${{ matrix.annotator }} \ No newline at end of file From b0a6557d0d5953082ff948b77f16fb29d9e8c04f Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 3 Dec 2019 16:16:34 +0100 Subject: [PATCH 274/854] includ test.config --- conf/test_splitfastq.config | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conf/test_splitfastq.config b/conf/test_splitfastq.config index 734852424e..5209ec401b 100644 --- a/conf/test_splitfastq.config +++ b/conf/test_splitfastq.config @@ -7,6 +7,8 @@ * nextflow run nf-core/sarek -profile test */ +includeConfig 'test.config' + params { split_fastq = 500 } \ No newline at end of file From 9ab028d8e440de6dd5c7b620fcd4073bf7d167b5 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 3 Dec 2019 16:38:24 +0100 Subject: [PATCH 275/854] restore FreeBayes --- .github/workflows/ci-extra.yml | 2 +- CHANGELOG.md | 1 - bin/scrape_software_versions.py | 2 ++ docs/containers.md | 1 + docs/images/sarek_workflow.png | Bin 47599 -> 49025 bytes docs/images/sarek_workflow.svg | 22 +++++++++++--- docs/output.md | 14 +++++++++ docs/usage.md | 2 +- environment.yml | 1 + main.nf | 52 +++++++++++++++++++++++++++----- 10 files changed, 83 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci-extra.yml b/.github/workflows/ci-extra.yml index 77d1c50e30..6bd09884b3 100644 --- a/.github/workflows/ci-extra.yml +++ b/.github/workflows/ci-extra.yml @@ -27,7 +27,7 @@ jobs: runs-on: ubuntu-18.04 strategy: matrix: - tool: [Haplotypecaller, Manta, mpileup, Mutect2, Strelka] + tool: [Haplotypecaller, Freebayes, Manta, mpileup, Mutect2, Strelka] steps: - uses: actions/checkout@v1 - name: Install Nextflow diff --git a/CHANGELOG.md b/CHANGELOG.md index 0877fb43de..f57c4d1f0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,7 +31,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ### `Removed` - [#46](https://github.com/nf-core/sarek/pull/46) - Remove mention of old `build.nf` script which was included in `main.nf` -- [#XXX](https://github.com/nf-core/sarek/pull/XXX) - Remove `Freebayes` ### `Fixed` diff --git a/bin/scrape_software_versions.py b/bin/scrape_software_versions.py index d85700a0e2..617740e595 100755 --- a/bin/scrape_software_versions.py +++ b/bin/scrape_software_versions.py @@ -9,6 +9,7 @@ 'bcftools': ['v_bcftools.txt', r"bcftools (\S+)"], 'BWA': ['v_bwa.txt', r"Version: (\S+)"], 'FastQC': ['v_fastqc.txt', r"FastQC v(\S+)"], + 'FreeBayes': ['v_freebayes.txt', r"version: v(\d\.\d\.\d+)"], 'GATK': ['v_gatk.txt', r"Version:(\S+)"], 'htslib': ['v_samtools.txt', r"htslib (\S+)"], 'Manta': ['v_manta.txt', r"([0-9.]+)"], @@ -32,6 +33,7 @@ results['bcftools'] = 'N/A' results['BWA'] = 'N/A' results['FastQC'] = 'N/A' +results['FreeBayes'] = 'N/A' results['GATK'] = 'N/A' results['htslib'] = 'N/A' results['Manta'] = 'N/A' diff --git a/docs/containers.md b/docs/containers.md index d8a51fb637..b75d74db9a 100644 --- a/docs/containers.md +++ b/docs/containers.md @@ -20,6 +20,7 @@ For annotation, the main container can be used, but the cache has to be download - Contain **[BWA](https://github.com/lh3/bwa)** 0.7.17 - Contain **[Control-FREEC](https://github.com/BoevaLab/FREEC)** 11.5 - Contain **[FastQC](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/)** 0.11.8 +- Contain **[FreeBayes](https://github.com/ekg/freebayes)** 1.3.1 - Contain **[GATK4](https://github.com/broadinstitute/gatk)** 4.1.4.0 - Contain **[GeneSplicer](https://ccb.jhu.edu/software/genesplicer/)** 1.0 - Contain **[HTSlib](https://github.com/samtools/htslib)** 1.9 diff --git a/docs/images/sarek_workflow.png b/docs/images/sarek_workflow.png index 3d7253ee44af0ebaff1486b35b3b90e6abbb58a8..1a1821cbf77d305e27a0a2198050f886dafdc5eb 100644 GIT binary patch delta 30537 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 delta 29100 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%0APrs#4*+H{s-7mJ4 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 Dw9ogd diff --git a/docs/images/sarek_workflow.svg b/docs/images/sarek_workflow.svg index f17b20d570..3c65217c05 100644 --- a/docs/images/sarek_workflow.svg +++ b/docs/images/sarek_workflow.svg @@ -2218,10 +2218,10 @@ id="namedview4" showgrid="false" inkscape:zoom="0.5" - inkscape:cx="75.30477" + inkscape:cx="-604.69523" inkscape:cy="732.99056" - inkscape:window-x="0" - inkscape:window-y="0" + inkscape:window-x="1920" + inkscape:window-y="759" inkscape:window-maximized="1" inkscape:current-layer="g10" units="mm" @@ -2259,6 +2259,8 @@ + + @@ -2789,6 +2791,8 @@ + + • Mutect2, Strelka2• FreeBayes, Mutect2 Strelka2• Manta v_nextflow.txt 2>&1 || true echo "SNPEFF version"\$(snpEff -h 2>&1) > v_snpeff.txt fastqc --version > v_fastqc.txt 2>&1 || true + freebayes --version > v_freebayes.txt 2>&1 || true gatk ApplyBQSR --help 2>&1 | grep Version: > v_gatk.txt 2>&1 || true multiqc --version &> v_multiqc.txt 2>&1 || true qualimap --version &> v_qualimap.txt 2>&1 || true @@ -1302,8 +1303,44 @@ intervalPairBam = pairBam.spread(bedIntervals) bamMpileup = bamMpileup.spread(intMpileup) -// intervals for Mutect2 calls and pileups for Mutect2 filtering -(pairBamMutect2, pairBamPileupSummaries) = intervalPairBam.into(2) +// intervals for Mutect2 calls, FreeBayes and pileups for Mutect2 filtering +(pairBamMutect2, pairBamFreeBayes, pairBamPileupSummaries) = intervalPairBam.into(3) + +// STEP FREEBAYES + +process FreeBayes { + tag {idSampleTumor + "_vs_" + idSampleNormal + "-" + intervalBed.baseName} + label 'cpus_1' + + input: + set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor), file(intervalBed) from pairBamFreeBayes + file(fasta) from ch_fasta + file(fastaFai) from ch_fastaFai + + output: + set val("FreeBayes"), idPatient, val("${idSampleTumor}_vs_${idSampleNormal}"), file("${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf") into vcfFreeBayes + + when: 'freebayes' in tools + + script: + """ + freebayes \ + -f ${fasta} \ + --pooled-continuous \ + --pooled-discrete \ + --genotype-qualities \ + --report-genotype-likelihood-max \ + --allele-balance-priors-off \ + --min-alternate-fraction 0.03 \ + --min-repeat-entropy 1 \ + --min-alternate-count 2 \ + -t ${intervalBed} \ + ${bamTumor} \ + ${bamNormal} > ${intervalBed.baseName}_${idSampleTumor}_vs_${idSampleNormal}.vcf + """ +} + +vcfFreeBayes = vcfFreeBayes.groupTuple(by:[0,1,2]) // STEP GATK MUTECT2.1 - RAW CALLS @@ -1392,9 +1429,9 @@ process MergeMutect2Stats { // we are merging the VCFs that are called separatelly for different intervals // so we can have a single sorted VCF containing all the calls for a given caller -// STEP MERGING VCF - GATK HAPLOTYPECALLER & GATK MUTECT2 (UNFILTERED) +// STEP MERGING VCF - FREEBAYES, GATK HAPLOTYPECALLER & GATK MUTECT2 (UNFILTERED) -vcfConcatenateVCFs = mutect2Output.mix(vcfGenotypeGVCFs, gvcfHaplotypeCaller) +vcfConcatenateVCFs = mutect2Output.mix(vcfFreeBayes, vcfGenotypeGVCFs, gvcfHaplotypeCaller) vcfConcatenateVCFs = vcfConcatenateVCFs.dump(tag:'VCF to merge') process ConcatVCF { @@ -1413,7 +1450,7 @@ process ConcatVCF { // we have this funny *_* pattern to avoid copying the raw calls to publishdir set variantCaller, idPatient, idSample, file("*_*.vcf.gz"), file("*_*.vcf.gz.tbi") into vcfConcatenated - when: ('haplotypecaller' in tools || 'mutect2' in tools) + when: ('haplotypecaller' in tools || 'mutect2' in tools || 'freebayes' in tools) script: if (variantCaller == 'HaplotypeCallerGVCF') @@ -2109,7 +2146,7 @@ if (step == 'annotate') { if (tsvPath == []) { // Sarek, by default, annotates all available vcfs that it can find in the VariantCalling directory - // Excluding g.vcf from HaplotypeCaller + // Excluding vcfs from FreeBayes, and g.vcf from HaplotypeCaller // Basically it's: VariantCalling/*/{HaplotypeCaller,Manta,Mutect2,Strelka,TIDDIT}/*.vcf.gz // Without *SmallIndels.vcf.gz from Manta, and *.genome.vcf.gz from Strelka // The small snippet `vcf.minus(vcf.fileName)[-2]` catches idSample @@ -2651,6 +2688,7 @@ def defineToolList() { return [ 'ascat', 'controlfreec', + 'freebayes', 'haplotypecaller', 'manta', 'merge', From 67e5001bdec78d9fb1acd28cb1a05811a05c15b8 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 3 Dec 2019 20:39:29 +0100 Subject: [PATCH 276/854] remove label memory_max from BaseRecalibrator process to fix #72 --- CHANGELOG.md | 1 + main.nf | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e2b55345b..0fb77cee9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [#43](https://github.com/nf-core/sarek/pull/43) - Fix automated `VEP` builds with circleCI - [#54](https://github.com/nf-core/sarek/pull/54) - Apply fixes from release `2.5.1` - [#58](https://github.com/nf-core/sarek/pull/58) - Fix issue with `.interval_list` file from the GATK bundle [#56](https://github.com/nf-core/sarek/issues/56) that was not recognized in the `CreateIntervalsBed` process +- [#73](https://github.com/nf-core/sarek/pull/73) - Fix issue with label `memory_max` for `BaseRecalibrator` process [#72](https://github.com/nf-core/sarek/issues/72) ## [2.5.1] - Årjep-Ålkatjjekna diff --git a/main.nf b/main.nf index 50dff290a4..43b61fc5ec 100644 --- a/main.nf +++ b/main.nf @@ -801,7 +801,6 @@ bamBaseRecalibrator = bamBaseRecalibrator.dump(tag:'BAM FOR BASERECALIBRATOR') // STEP 3: CREATING RECALIBRATION TABLES process BaseRecalibrator { - label 'memory_max' label 'cpus_1' tag {idPatient + "-" + idSample + "-" + intervalBed} From 89cbf62b31a31ab98ac259b3b989a6dbce08171d Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 6 Dec 2019 10:30:42 +0100 Subject: [PATCH 277/854] add --skipQC all and --tools Manta,mpileup,Strelka to minimal genome tests --- .github/workflows/ci-extra.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-extra.yml b/.github/workflows/ci-extra.yml index c9c6d82a9e..f93f75b7b8 100644 --- a/.github/workflows/ci-extra.yml +++ b/.github/workflows/ci-extra.yml @@ -23,7 +23,7 @@ jobs: docker tag nfcore/sarek:dev nfcore/sarek:dev - name: Run test run: | - nextflow run . -profile test,docker --verbose --genome ${{ matrix.genome }} ${{ matrix.intervals }} + nextflow run . -profile test,docker --skipQC all --verbose --genome ${{ matrix.genome }} ${{ matrix.intervals }} --tools Manta,mpileup,Strelka profile: runs-on: ubuntu-18.04 strategy: From 3e045b054173ff28d70e321257e32b4cc6760170 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 6 Dec 2019 10:34:45 +0100 Subject: [PATCH 278/854] update Nextflow version --- .github/workflows/ci-extra.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-extra.yml b/.github/workflows/ci-extra.yml index f93f75b7b8..190c7e36ef 100644 --- a/.github/workflows/ci-extra.yml +++ b/.github/workflows/ci-extra.yml @@ -16,7 +16,7 @@ jobs: wget -qO- get.nextflow.io | bash sudo mv nextflow /usr/local/bin/ env: - NXF_VER: '19.04.0' + NXF_VER: '19.10.0' - name: Download image run: | docker pull nfcore/sarek:dev @@ -36,7 +36,7 @@ jobs: wget -qO- get.nextflow.io | bash sudo mv nextflow /usr/local/bin/ env: - NXF_VER: '19.04.0' + NXF_VER: '19.10.0' - name: Download image run: | docker pull nfcore/sarek:dev @@ -56,7 +56,7 @@ jobs: wget -qO- get.nextflow.io | bash sudo mv nextflow /usr/local/bin/ env: - NXF_VER: '19.04.0' + NXF_VER: '19.10.0' - name: Download image run: | docker pull nfcore/sarek:dev @@ -77,7 +77,7 @@ jobs: wget -qO- get.nextflow.io | bash sudo mv nextflow /usr/local/bin/ env: - NXF_VER: '19.04.0' + NXF_VER: '19.10.0' - name: Download image run: | docker pull nfcore/sarek${{ matrix.annotator }}:dev.${{ matrix.specie }} From 544a9d505be7e29a8c7586e78ffa52baeb96a35a Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 6 Dec 2019 10:36:11 +0100 Subject: [PATCH 279/854] update Nextflow version --- .github/workflows/ci.yml | 2 +- README.md | 2 +- nextflow.config | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9b65872c36..1b01846e1c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-18.04 strategy: matrix: - nxf_ver: ['19.04.0', ''] + nxf_ver: ['19.10.0', ''] steps: - uses: actions/checkout@v1 - name: Install Nextflow diff --git a/README.md b/README.md index 6c9101cbc3..8651fb0812 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ > **An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing** -[![Nextflow](https://img.shields.io/badge/nextflow-%E2%89%A519.04.0-brightgreen.svg)](https://www.nextflow.io/) +[![Nextflow](https://img.shields.io/badge/nextflow-%E2%89%A519.10.0-brightgreen.svg)](https://www.nextflow.io/) [![nf-core](https://img.shields.io/badge/nf--core-pipeline-brightgreen.svg)](https://nf-co.re/) [![DOI](https://zenodo.org/badge/184289291.svg)](https://zenodo.org/badge/latestdoi/184289291) diff --git a/nextflow.config b/nextflow.config index b55cc7eb48..6d4d86ed5f 100644 --- a/nextflow.config +++ b/nextflow.config @@ -161,7 +161,7 @@ manifest { homePage = 'https://github.com/nf-core/sarek' description = 'An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing' mainScript = 'main.nf' - nextflowVersion = '>=19.04.0' + nextflowVersion = '>=19.10.0' version = '2.5.2dev' } From e2f01e9221554762f8c4c67d6c9bae5d6f769a6c Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 6 Dec 2019 10:55:11 +0100 Subject: [PATCH 280/854] update Nextflow --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 450539446e..3713a63aff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,7 @@ install: - sudo apt-get install npm && npm install -g markdownlint-cli env: - - NXF_VER='19.04.0' # Specify a minimum NF version that should be tested and work + - NXF_VER='19.10.0' # Specify a minimum NF version that should be tested and work - NXF_VER='' # Plus: get the latest NF version and check that it works script: From 361716a2ddbeedf819fb6db8d51fd6c6b78cbdec Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 6 Dec 2019 11:45:51 +0100 Subject: [PATCH 281/854] add --step annotation to profile --- conf/test_annotation.config | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/test_annotation.config b/conf/test_annotation.config index 6dc8799d22..2a1efe923e 100644 --- a/conf/test_annotation.config +++ b/conf/test_annotation.config @@ -12,4 +12,5 @@ includeConfig 'test.config' params { input = 'https://github.com/nf-core/test-datasets/raw/sarek/testdata/vcf/Strelka_1234N_variants.vcf.gz' genome = 'GRCh37' + step = 'annotate' } \ No newline at end of file From 357138bdf02debd17d0e65c4f54ef122598f170b Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 6 Dec 2019 12:15:36 +0100 Subject: [PATCH 282/854] don't need to specify step here --- conf/test_annotation.config | 1 - 1 file changed, 1 deletion(-) diff --git a/conf/test_annotation.config b/conf/test_annotation.config index 2a1efe923e..6dc8799d22 100644 --- a/conf/test_annotation.config +++ b/conf/test_annotation.config @@ -12,5 +12,4 @@ includeConfig 'test.config' params { input = 'https://github.com/nf-core/test-datasets/raw/sarek/testdata/vcf/Strelka_1234N_variants.vcf.gz' genome = 'GRCh37' - step = 'annotate' } \ No newline at end of file From 83fcf656f23155ee7d27f2249294f0dcf6049975 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 6 Dec 2019 12:19:23 +0100 Subject: [PATCH 283/854] move params initalization --- main.nf | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/main.nf b/main.nf index 4a45d75483..6973004aaf 100644 --- a/main.nf +++ b/main.nf @@ -150,28 +150,6 @@ annoList = defineAnnoList() annotateTools = params.annotateTools ? params.annotateTools.split(',').collect{it.trim().toLowerCase()} : [] if (!checkParameterList(annotateTools,annoList)) exit 1, 'Unknown tool(s) to annotate, see --help for more information' -// Initialize each params in params.genomes, catch the command line first if it was defined -// params.fasta has to be the first one -params.fasta = params.genome && !('annotate' in step) ? params.genomes[params.genome].fasta ?: null : null -// The rest can be sorted -params.acLoci = params.genome && 'ascat' in tools ? params.genomes[params.genome].acLoci ?: null : null -params.acLociGC = params.genome && 'ascat' in tools ? params.genomes[params.genome].acLociGC ?: null : null -params.bwaIndex = params.genome && params.fasta && 'mapping' in step ? params.genomes[params.genome].bwaIndex ?: null : null -params.chrDir = params.genome && 'controlfreec' in tools ? params.genomes[params.genome].chrDir ?: null : null -params.chrLength = params.genome && 'controlfreec' in tools ? params.genomes[params.genome].chrLength ?: null : null -params.dbsnp = params.genome && ('mapping' in step || 'controlfreec' in tools || 'haplotypecaller' in tools || 'mutect2' in tools) ? params.genomes[params.genome].dbsnp ?: null : null -params.dbsnpIndex = params.genome && params.dbsnp ? params.genomes[params.genome].dbsnpIndex ?: null : null -params.dict = params.genome && params.fasta ? params.genomes[params.genome].dict ?: null : null -params.fastaFai = params.genome && params.fasta ? params.genomes[params.genome].fastaFai ?: null : null -params.germlineResource = params.genome && 'mutect2' in tools ? params.genomes[params.genome].germlineResource ?: null : null -params.germlineResourceIndex = params.genome && params.germlineResource ? params.genomes[params.genome].germlineResourceIndex ?: null : null -params.intervals = params.genome && !('annotate' in step) ? params.genomes[params.genome].intervals ?: null : null -params.knownIndels = params.genome && 'mapping' in step ? params.genomes[params.genome].knownIndels ?: null : null -params.knownIndelsIndex = params.genome && params.knownIndels ? params.genomes[params.genome].knownIndelsIndex ?: null : null -params.snpeffDb = params.genome && 'snpeff' in tools ? params.genomes[params.genome].snpeffDb ?: null : null -params.species = params.genome && 'vep' in tools ? params.genomes[params.genome].species ?: null : null -params.vepCacheVersion = params.genome && 'vep' in tools ? params.genomes[params.genome].vepCacheVersion ?: null : null - // Handle deprecation if (params.noReports) skipQC = skipQClist @@ -240,6 +218,28 @@ if (tsvPath) { ================================================================================ */ +// Initialize each params in params.genomes, catch the command line first if it was defined +// params.fasta has to be the first one +params.fasta = params.genome && !('annotate' in step) ? params.genomes[params.genome].fasta ?: null : null +// The rest can be sorted +params.acLoci = params.genome && 'ascat' in tools ? params.genomes[params.genome].acLoci ?: null : null +params.acLociGC = params.genome && 'ascat' in tools ? params.genomes[params.genome].acLociGC ?: null : null +params.bwaIndex = params.genome && params.fasta && 'mapping' in step ? params.genomes[params.genome].bwaIndex ?: null : null +params.chrDir = params.genome && 'controlfreec' in tools ? params.genomes[params.genome].chrDir ?: null : null +params.chrLength = params.genome && 'controlfreec' in tools ? params.genomes[params.genome].chrLength ?: null : null +params.dbsnp = params.genome && ('mapping' in step || 'controlfreec' in tools || 'haplotypecaller' in tools || 'mutect2' in tools) ? params.genomes[params.genome].dbsnp ?: null : null +params.dbsnpIndex = params.genome && params.dbsnp ? params.genomes[params.genome].dbsnpIndex ?: null : null +params.dict = params.genome && params.fasta ? params.genomes[params.genome].dict ?: null : null +params.fastaFai = params.genome && params.fasta ? params.genomes[params.genome].fastaFai ?: null : null +params.germlineResource = params.genome && 'mutect2' in tools ? params.genomes[params.genome].germlineResource ?: null : null +params.germlineResourceIndex = params.genome && params.germlineResource ? params.genomes[params.genome].germlineResourceIndex ?: null : null +params.intervals = params.genome && !('annotate' in step) ? params.genomes[params.genome].intervals ?: null : null +params.knownIndels = params.genome && 'mapping' in step ? params.genomes[params.genome].knownIndels ?: null : null +params.knownIndelsIndex = params.genome && params.knownIndels ? params.genomes[params.genome].knownIndelsIndex ?: null : null +params.snpeffDb = params.genome && 'snpeff' in tools ? params.genomes[params.genome].snpeffDb ?: null : null +params.species = params.genome && 'vep' in tools ? params.genomes[params.genome].species ?: null : null +params.vepCacheVersion = params.genome && 'vep' in tools ? params.genomes[params.genome].vepCacheVersion ?: null : null + // Initialize channels based on params ch_acLoci = params.acLoci && 'ascat' in tools ? Channel.value(file(params.acLoci)) : "null" ch_acLociGC = params.acLociGC && 'ascat' in tools ? Channel.value(file(params.acLociGC)) : "null" @@ -249,6 +249,7 @@ ch_dbsnp = params.dbsnp && ('mapping' in step || 'controlfreec' in tools || 'hap ch_fasta = params.fasta && !('annotate' in step) ? Channel.value(file(params.fasta)) : "null" ch_fastaFai = params.fastaFai && !('annotate' in step) ? Channel.value(file(params.fastaFai)) : "null" ch_germlineResource = params.germlineResource && 'mutect2' in tools ? Channel.value(file(params.germlineResource)) : "null" +ch_intervals = params.intervals && !params.no_intervals && !('annotate' in step) ? Channel.value(file(params.intervals)) : "null" // knownIndels is currently a list of file for smallGRCh37, so transform it in a channel li_knownIndels = [] @@ -283,7 +284,7 @@ summary['Max Resources'] = "${params.max_memory} memory, ${params.max_cpus} if (workflow.containerEngine) summary['Container'] = "${workflow.containerEngine} - ${workflow.container}" if (params.input) summary['Input'] = params.input if (params.targetBED) summary['Target BED'] = params.targetBED -if (params.step) summary['Step'] = params.step +if (step) summary['Step'] = step if (params.tools) summary['Tools'] = tools.join(', ') if (params.skipQC) summary['QC tools skip'] = skipQC.join(', ') From 67dd6379a71f7336a188f680f1fe0fb846acc015 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 6 Dec 2019 14:26:56 +0100 Subject: [PATCH 284/854] add docs --- docs/reference.md | 14 ++++++++++++++ docs/usage.md | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/docs/reference.md b/docs/reference.md index 65d96997e0..284ff04c0a 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -37,6 +37,14 @@ Second, the jobs with largest processing time are started first, which reduces w If no runtime is given, a time of 1000 nucleotides per second is assumed. Actual figures vary from 2 nucleotides/second to 30000 nucleotides/second. +If no intervals files are specified, one will be automatically generated following: + +```bash +awk -v FS='\t' -v OFS='\t' '{ print \$1, \"0\", \$2 }' .fasta.fai > .bed +``` + +To disable this feature, please use [`--no_intervals`](usage.md#--no_intervals) + ### Working with whole exome (WES) or panel data The `--targetBED` parameter does _not_ imply that the workflow is running alignment or variant calling only for the supplied targets. @@ -44,3 +52,9 @@ Instead, we are aligning for the whole genome, and selecting variants only at th Adding every exon as an interval in case of WES can generate >200K processes or jobs, much more forks, and similar number of directories in the Nextflow work directory. Furthermore, primers and/or baits are not 100% specific, (certainly not for MHC and KIR, etc.), quite likely there going to be reads mapping to multiple locations. If you are certain that the target is unique for your genome (all the reads will certainly map to only one location), and aligning to the whole genome is an overkill, better to change the reference itself. + +### Working with other genomes + +> :warning: This is a new feature, in active development, so usage could change. + +Sarek can also do limited preprocessing from any genome, providing a `fasta` file as a reference genome, followed by limited variant calling using `mpileup`, `Manta` and `Strelka`. \ No newline at end of file diff --git a/docs/usage.md b/docs/usage.md index f0c933dc1d..8208579e58 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -23,6 +23,7 @@ * [`--step`](#--step) * [`--tools`](#--tools) * [`--noStrelkaBP`](#--nostrelkabp) + * [`--no_intervals`](#--no_intervals) * [`--targetBED`](#--targetbed) * [Reference genomes](#reference-genomes) * [`--genome` (using iGenomes)](#--genome-using-igenomes) @@ -285,6 +286,10 @@ Available: `ASCAT`, `ControlFREEC`, `FreeBayes`, `HaplotypeCaller`, `Manta`, `mp Use this not to use `Manta` `candidateSmallIndels` for `Strelka` as Best Practice. +### `--no_intervals_` + +Disable usage of intervals file, and disable automatic generation of intervals file when none are provided. + ### `--targetBED` Use this to specify the target BED file for targeted or whole exome sequencing. From 430a09b244f69c8c642aab7cb3a0efca16b9e820 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 6 Dec 2019 14:28:10 +0100 Subject: [PATCH 285/854] fix markdownlint --- docs/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference.md b/docs/reference.md index 284ff04c0a..9287cffd32 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -57,4 +57,4 @@ If you are certain that the target is unique for your genome (all the reads will > :warning: This is a new feature, in active development, so usage could change. -Sarek can also do limited preprocessing from any genome, providing a `fasta` file as a reference genome, followed by limited variant calling using `mpileup`, `Manta` and `Strelka`. \ No newline at end of file +Sarek can also do limited preprocessing from any genome, providing a `fasta` file as a reference genome, followed by limited variant calling using `mpileup`, `Manta` and `Strelka`. From 22d386ad7f0e5c683334a88f993092ba69eb6977 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Fri, 6 Dec 2019 15:16:41 +0100 Subject: [PATCH 286/854] more complete docs + sort genomes --- CHANGELOG.md | 2 +- conf/genomes.config | 22 ++------- conf/igenomes.config | 112 +++++++++++++++++++++---------------------- docs/reference.md | 2 + docs/usage.md | 89 ++++++++++++++++++++++++++++++++-- 5 files changed, 148 insertions(+), 79 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6f3ca85eb..55e65e46cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - [#60](https://github.com/nf-core/sarek/pull/60) - Add minimal support for minimal genome (only `fasta`, or `fasta` + `knownIndels`) - [#60](https://github.com/nf-core/sarek/pull/60) - Add new processes (`IndexBamFile`, `IndexBamRecal`) to deal with optional usage of interval files and minimal genome - [#60](https://github.com/nf-core/sarek/pull/60) - Add tests for minimal genome usage -- [#60](https://github.com/nf-core/sarek/pull/60) - Add new minimal genomes (`AGPv3`, `BDGP6`, `CHIMP2.1.4`, `CanFam3.1`, `EB1`, `EB2`, `EF2`, `EquCab2`, `GRCz10`, `Galgal4`, `Gm01`, `IRGSP-1.0`, `Mmul_1`, `R64-1-1`, `Rnor_6.0`, `Sbi1`, `Sscrofa10.2`, `TAIR10`, `UMD3.1`, `WBcel235`, `bosTau8`, `canFam3`, `ce10`, `danRer10`, `dm6`, `equCab2`, `galGal4`, `hg19`, `hg38`, `mm10`, `panTro4`, `rn6`, `sacCer3`, `susScr3`) to `igenomes.config` +- [#60](https://github.com/nf-core/sarek/pull/60) - Add new minimal genomes (`TAIR10`, `EB2`, `UMD3.1`, `bosTau8`, `WBcel235`, `ce10`, `CanFam3.1`, `canFam3`, `GRCz10`, `danRer10`, `BDGP6`, `dm6`, `EquCab2`, `equCab2`, `EB1`, `Galgal4`, `galGal4`, `Gm01`, `hg38`, `hg19`, `Mmul_1`, `mm10`, `IRGSP-1.0`, `CHIMP2.1.4`, `panTro4`, `Rnor_6.0`, `rn6`, `R64-1-1`, `sacCer3`, `EF2`, `Sbi1`, `Sscrofa10.2`, `susScr3`, `AGPv3`) to `igenomes.config` - [#61](https://github.com/nf-core/sarek/pull/61) - Add params `split_fastq` - [#61](https://github.com/nf-core/sarek/pull/61) - Add test `SPLITFASTQ` diff --git a/conf/genomes.config b/conf/genomes.config index acc6137506..11c449ba55 100644 --- a/conf/genomes.config +++ b/conf/genomes.config @@ -49,6 +49,9 @@ params { species = 'homo_sapiens' vepCacheVersion = '95' } + 'minimalGRCh37' { + fasta = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" + } 'smallGRCh37' { dbsnp = "${params.genomes_base}/dbsnp_138.b37.small.vcf.gz" fasta = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" @@ -59,28 +62,9 @@ params { species = 'homo_sapiens' vepCacheVersion = '95' } - 'GRCm38' { - bwaIndex = "${params.genomes_base}/genome.fa.{amb,ann,bwt,pac,sa}" - chrDir = "${params.genomes_base}/Chromosomes" - chrLength = "${params.genomes_base}/GRCm38.len" - dbsnp = "${params.genomes_base}/mgp.v5.merged.snps_all.dbSNP142.vcf.gz" - dbsnpIndex = "${params.genomes_base}/mgp.v5.merged.snps_all.dbSNP142.vcf.gz.tbi" - dict = "${params.genomes_base}/genome.dict" - fasta = "${params.genomes_base}/genome.fa" - fastaFai = "${params.genomes_base}/genome.fa.fai" - intervals = "${params.genomes_base}/GRCm38_calling_list.bed" - knownIndels = "${params.genomes_base}/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz" - knownIndelsIndex = "${params.genomes_base}/mgp.v5.merged.indels.dbSNP142.normed.vcf.gz.tbi" - snpeffDb = 'GRCm38.86' - species = 'mus_musculus' - vepCacheVersion = '98' - } 'smallerGRCh37' { fasta = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" knownIndels = "${params.genomes_base}/dbsnp_138.b37.small.vcf.gz" } - 'minimalGRCh37' { - fasta = "${params.genomes_base}/human_g1k_v37_decoy.small.fasta" - } } } diff --git a/conf/igenomes.config b/conf/igenomes.config index 0dc0f857a0..7ecdd98b40 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -77,26 +77,50 @@ params { bwaIndex = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" fasta = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/WholeGenomeFasta/genome.fa" } + 'bosTau8' { + bwaIndex = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/WholeGenomeFasta/genome.fa" + } 'WBcel235' { bwaIndex = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" fasta = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/WholeGenomeFasta/genome.fa" } + 'ce10' { + bwaIndex = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/WholeGenomeFasta/genome.fa" + } 'CanFam3.1' { bwaIndex = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" fasta = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/WholeGenomeFasta/genome.fa" } + 'canFam3' { + bwaIndex = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/WholeGenomeFasta/genome.fa" + } 'GRCz10' { bwaIndex = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" fasta = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/WholeGenomeFasta/genome.fa" } + 'danRer10' { + bwaIndex = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/WholeGenomeFasta/genome.fa" + } 'BDGP6' { bwaIndex = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" fasta = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/WholeGenomeFasta/genome.fa" } + 'dm6' { + bwaIndex = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/WholeGenomeFasta/genome.fa" + } 'EquCab2' { bwaIndex = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" fasta = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/WholeGenomeFasta/genome.fa" } + 'equCab2' { + bwaIndex = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/WholeGenomeFasta/genome.fa" + } 'EB1' { bwaIndex = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" fasta = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/WholeGenomeFasta/genome.fa" @@ -105,14 +129,30 @@ params { bwaIndex = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" fasta = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/WholeGenomeFasta/genome.fa" } + 'galGal4' { + bwaIndex = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/WholeGenomeFasta/genome.fa" + } 'Gm01' { bwaIndex = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" fasta = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/WholeGenomeFasta/genome.fa" } + 'hg38' { + bwaIndex = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/WholeGenomeFasta/genome.fa" + } + 'hg19' { + bwaIndex = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/WholeGenomeFasta/genome.fa" + } 'Mmul_1' { bwaIndex = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" fasta = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/WholeGenomeFasta/genome.fa" } + 'mm10' { + bwaIndex = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/WholeGenomeFasta/genome.fa" + } 'IRGSP-1.0' { bwaIndex = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" fasta = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/WholeGenomeFasta/genome.fa" @@ -121,14 +161,26 @@ params { bwaIndex = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" fasta = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/WholeGenomeFasta/genome.fa" } + 'panTro4' { + bwaIndex = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/WholeGenomeFasta/genome.fa" + } 'Rnor_6.0' { bwaIndex = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" fasta = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/WholeGenomeFasta/genome.fa" } + 'rn6' { + bwaIndex = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/WholeGenomeFasta/genome.fa" + } 'R64-1-1' { bwaIndex = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" fasta = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/WholeGenomeFasta/genome.fa" } + 'sacCer3' { + bwaIndex = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/WholeGenomeFasta/genome.fa" + } 'EF2' { bwaIndex = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" fasta = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/WholeGenomeFasta/genome.fa" @@ -141,65 +193,13 @@ params { bwaIndex = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" fasta = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/WholeGenomeFasta/genome.fa" } - 'AGPv3' { - bwaIndex = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" - fasta = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/WholeGenomeFasta/genome.fa" - } - 'hg38' { - bwaIndex = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" - fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/WholeGenomeFasta/genome.fa" - } - 'hg19' { - bwaIndex = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" - fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/WholeGenomeFasta/genome.fa" - } - 'mm10' { - bwaIndex = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" - fasta = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/WholeGenomeFasta/genome.fa" - } - 'bosTau8' { - bwaIndex = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" - fasta = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/WholeGenomeFasta/genome.fa" - } - 'ce10' { - bwaIndex = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" - fasta = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/WholeGenomeFasta/genome.fa" - } - 'canFam3' { - bwaIndex = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" - fasta = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/WholeGenomeFasta/genome.fa" - } - 'danRer10' { - bwaIndex = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" - fasta = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/WholeGenomeFasta/genome.fa" - } - 'dm6' { - bwaIndex = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" - fasta = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/WholeGenomeFasta/genome.fa" - } - 'equCab2' { - bwaIndex = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" - fasta = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/WholeGenomeFasta/genome.fa" - } - 'galGal4' { - bwaIndex = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" - fasta = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/WholeGenomeFasta/genome.fa" - } - 'panTro4' { - bwaIndex = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" - fasta = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/WholeGenomeFasta/genome.fa" - } - 'rn6' { - bwaIndex = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" - fasta = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/WholeGenomeFasta/genome.fa" - } - 'sacCer3' { - bwaIndex = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" - fasta = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/WholeGenomeFasta/genome.fa" - } 'susScr3' { bwaIndex = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" fasta = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/WholeGenomeFasta/genome.fa" } + 'AGPv3' { + bwaIndex = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/BWAIndex/genome.fa.{amb,ann,bwt,pac,sa}" + fasta = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/WholeGenomeFasta/genome.fa" + } } } diff --git a/docs/reference.md b/docs/reference.md index 9287cffd32..741c61bd1b 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -58,3 +58,5 @@ If you are certain that the target is unique for your genome (all the reads will > :warning: This is a new feature, in active development, so usage could change. Sarek can also do limited preprocessing from any genome, providing a `fasta` file as a reference genome, followed by limited variant calling using `mpileup`, `Manta` and `Strelka`. + +Limited support for `TAIR10`, `EB2`, `UMD3.1`, `bosTau8`, `WBcel235`, `ce10`, `CanFam3.1`, `canFam3`, `GRCz10`, `danRer10`, `BDGP6`, `dm6`, `EquCab2`, `equCab2`, `EB1`, `Galgal4`, `galGal4`, `Gm01`, `hg38`, `hg19`, `Mmul_1`, `mm10`, `IRGSP-1.0`, `CHIMP2.1.4`, `panTro4`, `Rnor_6.0`, `rn6`, `R64-1-1`, `sacCer3`, `EF2`, `Sbi1`, `Sscrofa10.2`, `susScr3`, `AGPv3`. diff --git a/docs/usage.md b/docs/usage.md index 8208579e58..b5f5d45691 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -307,9 +307,92 @@ To run the pipeline, you must specify which to use with the `--genome` flag. You can find the keys to specify the genomes in the [iGenomes config file](../conf/igenomes.config). Genomes that are supported are: -* Human - * `--genome GRCh37` - * `--genome GRCh38` +* Homo sapiens + * `--genome GRCh37` (GATK Bundle) + * `--genome GRCh38` (GATK Bundle) + +* Mus musculus + * `--genome GRCm38` (Ensembl) + +Limited support for: + +* Arabidopsis thaliana + * `--genome TAIR10` (Ensembl) + +* Bacillus subtilis 168 + * `--genome EB2` (Ensembl) + +* Bos taurus + * `--genome UMD3.1` (Ensembl) + * `--genome bosTau8` (UCSC) + +* Caenorhabditis elegans + * `--genome WBcel235` (Ensembl) + * `--genome ce10` (UCSC) + +* Canis familiaris + * `--genome CanFam3.1` (Ensembl) + * `--genome canFam3` (UCSC) + +* Danio rerio + * `--genome GRCz10` (Ensembl) + * `--genome danRer10` (UCSC) + +* Drosophila melanogaster + * `--genome BDGP6` (Ensembl) + * `--genome dm6` (UCSC) + +* Equus caballus + * `--genome EquCab2` (Ensembl) + * `--genome equCab2` (UCSC) + +* Escherichia coli K 12 DH10B + * `--genome EB1` (Ensembl) + +* Gallus gallus + * `--genome Galgal4` (Ensembl) + * `--genome galgal4` (UCSC) + +* Glycine max + * `--genome Gm01` (Ensembl) + +* Homo sapiens + * `--genome hg19` (UCSC) + * `--genome hg38` (UCSC) + +* Macaca mulatta + * `--genome Mmul_1` (Ensembl) + +* Mus musculus + * `--genome mm10` (Ensembl) + +* Oryza sativa japonica + * `--genome IRGSP-1.0` (Ensembl) + +* Pan troglodytes + * `--genome CHIMP2.1.4` (Ensembl) + * `--genome panTro4` (UCSC) + +* Rattus norvegicus + * `--genome Rnor_6.0` (Ensembl) + * `--genome rn6` (UCSC) + +* Saccharomyces cerevisiae + * `--genome R64-1-1` (Ensembl) + * `--genome sacCer3` (UCSC) + +* Schizosaccharomyces pombe + * `--genome EF2` (Ensembl) + +* Sorghum bicolor + * `--genome Sbi1` (Ensembl) + +* Sus scrofa + * `--genome Sscrofa10.2` (Ensembl) + * `--genome susScr3` (UCSC) + +* Zea mays + * `--genome AGPv3` (Ensembl) Note that you can use the same configuration setup to save sets of reference files for your own use, even if they are not part of the iGenomes resource. See the [Nextflow documentation](https://www.nextflow.io/docs/latest/config.html) for instructions on where to save such a file. From 63f48c6772791f3671b3a4d137dda1bdf8ed3c67 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 9 Dec 2019 14:09:46 +0100 Subject: [PATCH 287/854] improve tests --- .github/workflows/ci-extra.yml | 87 ---------------------- .github/workflows/ci.yml | 106 ++++++++++++++++++++++++++- Jenkinsfile | 37 ++++++---- scripts/download_image.sh | 76 -------------------- scripts/run_tests.sh | 128 --------------------------------- 5 files changed, 129 insertions(+), 305 deletions(-) delete mode 100644 .github/workflows/ci-extra.yml delete mode 100755 scripts/download_image.sh delete mode 100755 scripts/run_tests.sh diff --git a/.github/workflows/ci-extra.yml b/.github/workflows/ci-extra.yml deleted file mode 100644 index 190c7e36ef..0000000000 --- a/.github/workflows/ci-extra.yml +++ /dev/null @@ -1,87 +0,0 @@ -name: sarek extra CI -# This workflow is triggered on pushes and PRs to the repository. -on: [push, pull_request] - -jobs: - minimal: - runs-on: ubuntu-18.04 - strategy: - matrix: - genome: [smallerGRCh37, minimalGRCh37] - intervals: [--no_intervals, ''] - steps: - - uses: actions/checkout@v1 - - name: Install Nextflow - run: | - wget -qO- get.nextflow.io | bash - sudo mv nextflow /usr/local/bin/ - env: - NXF_VER: '19.10.0' - - name: Download image - run: | - docker pull nfcore/sarek:dev - docker tag nfcore/sarek:dev nfcore/sarek:dev - - name: Run test - run: | - nextflow run . -profile test,docker --skipQC all --verbose --genome ${{ matrix.genome }} ${{ matrix.intervals }} --tools Manta,mpileup,Strelka - profile: - runs-on: ubuntu-18.04 - strategy: - matrix: - profile: [test_splitfastq, test_targeted] - steps: - - uses: actions/checkout@v1 - - name: Install Nextflow - run: | - wget -qO- get.nextflow.io | bash - sudo mv nextflow /usr/local/bin/ - env: - NXF_VER: '19.10.0' - - name: Download image - run: | - docker pull nfcore/sarek:dev - docker tag nfcore/sarek:dev nfcore/sarek:dev - - name: Run test - run: | - nextflow run . -profile ${{ matrix.profile }},docker --verbose - tools: - runs-on: ubuntu-18.04 - strategy: - matrix: - tool: [Haplotypecaller, Freebayes, Manta, mpileup, Mutect2, Strelka] - steps: - - uses: actions/checkout@v1 - - name: Install Nextflow - run: | - wget -qO- get.nextflow.io | bash - sudo mv nextflow /usr/local/bin/ - env: - NXF_VER: '19.10.0' - - name: Download image - run: | - docker pull nfcore/sarek:dev - docker tag nfcore/sarek:dev nfcore/sarek:dev - - name: Run test - run: | - nextflow run . -profile test_tool,docker --verbose --tools ${{ matrix.tool }} - annotation: - runs-on: ubuntu-18.04 - strategy: - matrix: - annotator: [snpeff] - specie: [GRCh37] - steps: - - uses: actions/checkout@v1 - - name: Install Nextflow - run: | - wget -qO- get.nextflow.io | bash - sudo mv nextflow /usr/local/bin/ - env: - NXF_VER: '19.10.0' - - name: Download image - run: | - docker pull nfcore/sarek${{ matrix.annotator }}:dev.${{ matrix.specie }} - docker tag nfcore/sarek${{ matrix.annotator }}:dev.${{ matrix.specie }} nfcore/sarek${{ matrix.annotator }}:dev.${{ matrix.specie }} - - name: Run test - run: | - nextflow run . -profile test_annotation,docker --verbose --tools ${{ matrix.annotator }} \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1b01846e1c..9691252722 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,4 +21,108 @@ jobs: docker tag nfcore/sarek:dev nfcore/sarek:dev - name: Run test run: | - nextflow run ${GITHUB_WORKSPACE} -profile test,docker \ No newline at end of file + nextflow run ${GITHUB_WORKSPACE} -profile test,docker + annotation: + runs-on: ubuntu-18.04 + strategy: + matrix: + annotator: [snpeff] + specie: [GRCh37] + steps: + - uses: actions/checkout@v1 + - name: Install Nextflow + run: | + wget -qO- get.nextflow.io | bash + sudo mv nextflow /usr/local/bin/ + env: + NXF_VER: '19.10.0' + - name: Download image + run: | + docker pull nfcore/sarek${{ matrix.annotator }}:dev.${{ matrix.specie }} + docker tag nfcore/sarek${{ matrix.annotator }}:dev.${{ matrix.specie }} nfcore/sarek${{ matrix.annotator }}:dev.${{ matrix.specie }} + - name: Run test + run: | + nextflow run . -profile test_annotation,docker --verbose --tools ${{ matrix.annotator }} + germline: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v1 + - name: Install Nextflow + run: | + wget -qO- get.nextflow.io | bash + sudo mv nextflow /usr/local/bin/ + env: + NXF_VER: '19.10.0' + - name: Download image + run: | + docker pull nfcore/sarek:dev + docker tag nfcore/sarek:dev nfcore/sarek:dev + - name: Get test data + run: | + git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data + - name: Run test + run: | + nextflow run --input data/testdata/tiny/normal + nextflow run --input=false --step recalibrate -resume + nextflow run --input=false --step variantCalling + minimal: + runs-on: ubuntu-18.04 + strategy: + matrix: + genome: [smallerGRCh37, minimalGRCh37] + intervals: [--no_intervals, ''] + steps: + - uses: actions/checkout@v1 + - name: Install Nextflow + run: | + wget -qO- get.nextflow.io | bash + sudo mv nextflow /usr/local/bin/ + env: + NXF_VER: '19.10.0' + - name: Download image + run: | + docker pull nfcore/sarek:dev + docker tag nfcore/sarek:dev nfcore/sarek:dev + - name: Run test + run: | + nextflow run . -profile test,docker --skipQC all --verbose --genome ${{ matrix.genome }} ${{ matrix.intervals }} --tools Manta,mpileup,Strelka + profile: + runs-on: ubuntu-18.04 + strategy: + matrix: + profile: [test_splitfastq, test_targeted] + steps: + - uses: actions/checkout@v1 + - name: Install Nextflow + run: | + wget -qO- get.nextflow.io | bash + sudo mv nextflow /usr/local/bin/ + env: + NXF_VER: '19.10.0' + - name: Download image + run: | + docker pull nfcore/sarek:dev + docker tag nfcore/sarek:dev nfcore/sarek:dev + - name: Run test + run: | + nextflow run . -profile ${{ matrix.profile }},docker --verbose + tools: + runs-on: ubuntu-18.04 + strategy: + matrix: + tool: [Haplotypecaller, Freebayes, Manta, mpileup, Mutect2, Strelka] + steps: + - uses: actions/checkout@v1 + - name: Install Nextflow + run: | + wget -qO- get.nextflow.io | bash + sudo mv nextflow /usr/local/bin/ + env: + NXF_VER: '19.10.0' + - name: Download image + run: | + docker pull nfcore/sarek:dev + docker tag nfcore/sarek:dev nfcore/sarek:dev + - name: Run test + run: | + nextflow run . -profile test_tool,docker --verbose --tools ${{ matrix.tool }} \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile index 00c743cde2..7dc9b45a88 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -8,35 +8,46 @@ pipeline { stages { stage('Docker setup') { steps { - sh "./scripts/download_image.sh -n docker -t ALL --source-version dev --target-version dev -g smallGRCh37" + sh "docker pull nfcore/sarek:dev" + sh "docker tag nfcore/sarek:dev nfcore/sarek:dev" + sh "docker pull nfcore/sareksnpeff:dev.GRCh37" + sh "docker tag nfcore/sareksnpeff:dev.GRCh37 nfcore/sareksnpeff:dev.GRCh37" + sh "docker pull nfcore/sarekvep:dev.GRCh37" + sh "docker tag nfcore/sarekvep:dev.GRCh37 nfcore/sarekvep:dev.GRCh37" + } + } + stage('Annotation') { + steps { + sh "nextflow run . -profile test_annotation,docker --verbose --tools snpeff,vep,merge" } } stage('Germline') { steps { sh "rm -rf data/" sh "git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data" - sh "./scripts/run_tests.sh --profile kraken --test GERMLINE --no-reports" + sh "nextflow run --input data/testdata/tiny/normal" + sh "nextflow run --input=false --step recalibrate -resume" + sh "nextflow run --input=false --step variantCalling" sh "rm -rf data/" } } - stage('Somatic') { + stage('Minimal') { steps { - sh "./scripts/run_tests.sh --profile kraken --test SOMATIC --no-reports" + sh "nextflow run . -profile test,docker --skipQC all --verbose --genome smallerGRCh37 --no_intervals --tools Manta,mpileup,Strelka" + sh "nextflow run . -profile test,docker --skipQC all --verbose --genome smallerGRCh37 --tools Manta,mpileup,Strelka" + sh "nextflow run . -profile test,docker --skipQC all --verbose --genome minimalGRCh37 --no_intervals --tools Manta,mpileup,Strelka" + sh "nextflow run . -profile test,docker --skipQC all --verbose --genome minimalGRCh37 --tools Manta,mpileup,Strelka" } } - stage('Targeted') { - steps { - sh "./scripts/run_tests.sh --profile kraken --test TARGETED --no-reports" - } - } - stage('Annotation') { + stage('Profile') { steps { - sh "./scripts/run_tests.sh --profile kraken --test ANNOTATEBOTH --no-reports" + sh "nextflow run . -profile test_splitfastq,docker --verbose" + sh "nextflow run . -profile test_targeted,docker --verbose" } } - stage('Multiple') { + stage('Tools') { steps { - sh "./scripts/run_tests.sh --profile kraken --test MULTIPLE" + sh "nextflow run . -profile test_tool,docker --verbose --tools Haplotypecaller,Freebayes,Manta,mpileup,Mutect2,Strelka" } } } diff --git a/scripts/download_image.sh b/scripts/download_image.sh deleted file mode 100755 index b2955c240b..0000000000 --- a/scripts/download_image.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/bash -set -xeuo pipefail - -# This script download and tag image for sarek tests - -usage() { echo "Usage: $0 <-t test|annotation tool> <-n engine> <-S version to pull/build> <-T version to tag> <-g genome>" 1>&2; exit 1; } - -ENGINE=docker -GENOME=GRCh37 -NXF_SINGULARITY_CACHEDIR=${NXF_SINGULARITY_CACHEDIR:-work/singularity/.} -TEST=ALL -VERSION=dev -TARGETVERSION=${VERSION} - -while [[ $# -gt 0 ]] -do - key=$1 - case $key in - -g|--genome) - GENOME=$2 - shift # past argument - shift # past value - ;; - -n|--engine) - ENGINE=$2 - shift # past argument - shift # past value - ;; - -T|--target-version) - TARGETVERSION=$2 - shift # past argument - shift # past value - ;; - -S|--source-version) - VERSION=$2 - shift # past argument - shift # past value - ;; - -t|--test|--tool) - TEST=$2 - shift # past argument - shift # past value - ;; - *) # unknown option - usage - shift # past argument - ;; - esac -done - -get_image(){ - CONTAINER=$1 - SOURCE=$2 - TARGET=$3 - if [[ docker =~ $ENGINE ]] - then - docker pull nfcore/${1}:${2} - docker tag nfcore/${1}:${2} nfcore/${1}:${3} - elif [[ singularity =~ $ENGINE ]] - then - mkdir -p ${NXF_SINGULARITY_CACHEDIR} - singularity build ${NXF_SINGULARITY_CACHEDIR}/nfcore-${1}-${3}.img docker://nfcore/${1}:${2} - fi -} - -if [[ ALL,ANNOTATEBOTH,ANNOTATESNPEFF,SNPEFF =~ $TEST ]] -then - get_image sareksnpeff ${VERSION}.${GENOME} ${TARGETVERSION}.${GENOME} -fi - -if [[ ALL,ANNOTATEBOTH,ANNOTATEVEP,VEP =~ $TEST ]] -then - get_image sarekvep ${VERSION}.${GENOME} ${TARGETVERSION}.${GENOME} -fi - -get_image sarek ${VERSION} ${TARGETVERSION} \ No newline at end of file diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh deleted file mode 100755 index 00c6d30ef5..0000000000 --- a/scripts/run_tests.sh +++ /dev/null @@ -1,128 +0,0 @@ -#!/bin/bash -set -xeuo pipefail - -# This script run sarek tests -# https://github.com/nf-core/test-datasets/raw/sarek - -usage() { echo "Usage: $0 <-p profile> <-t test> <-c cpus> <-n> <-v> <-m memory>" 1>&2; exit 1; } - -CPUS=2 -LOGS='' -MEMORY='6.GB' -NXF_SINGULARITY_CACHEDIR=${NXF_SINGULARITY_CACHEDIR:-work/singularity/.} -OFFLINE=false -PROFILE=docker -REPORTS='' -TEST=MULTIPLE -TRAVIS=${TRAVIS:-false} -TRAVIS_BUILD_DIR=${TRAVIS_BUILD_DIR:-.} -VERBOSE='' - -while [[ $# -gt 0 ]] -do - key=$1 - case $key in - -c|--cpus) - CPUS=$2 - shift # past value - ;; - -m|--memory) - MEMORY=$2 - shift # past argument - shift # past value - ;; - -n|--no-logs) - LOGS=true - shift # past value - ;; - --no-reports) - REPORTS="--skipQC all" - shift # past value - ;; - --offline) - OFFLINE=true - shift # past value - ;; - -p|--profile) - PROFILE=$2 - shift # past argument - shift # past value - ;; - -t|--test) - TEST=$2 - shift # past argument - shift # past value - ;; - -v|--verbose) - VERBOSE="-ansi-log false -dump-channels" - shift # past value - ;; - *) # unknown option - usage - shift # past argument - ;; - esac -done - -function manage_logs() { - if [[ $LOGS ]] - then - rm -rf .nextflow* results/ work/ - fi -} - -function run_sarek() { - nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile test,${PROFILE} ${VERBOSE} --monochrome_logs ${REPORTS} --max_memory ${MEMORY} $@ -} - -if [[ $OFFLINE == false ]] -then - PATHTOSAMPLE="https://github.com/nf-core/test-datasets/raw/sarek/testdata" - SUFFIX="-https" -else - PATHTOSAMPLE="data/testdata" - SUFFIX="" -fi - -if [[ $TEST == "GERMLINE" ]] && [[ $OFFLINE == false ]] -then - rm -rf data - git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data -fi - -case $TEST in - ANNOTATEBOTH) - ANNOTATOR="merge,snpEFF,VEP" - TEST=ANNOTATE - ;; - ANNOTATESNPEFF) - ANNOTATOR="snpEFF" - TEST=ANNOTATE - ;; - ANNOTATEVEP) - ANNOTATOR="VEP" - TEST=ANNOTATE - ;; -esac - -case $TEST in - GERMLINE) - run_sarek --tools=false --input data/testdata/tiny/normal - run_sarek --tools=false --input results/Preprocessing/TSV/duplicateMarked.tsv --step recalibrate -resume - run_sarek --tools HaplotypeCaller --input results/Preprocessing/TSV/recalibrated.tsv --step variantCalling - ;; - MINIMAL) - run_sarek --tools manta,Mpileup,strelka --input ${PATHTOSAMPLE}/tsv/tiny-manta-normal${SUFFIX}.tsv --genome smallerGRCh37 - run_sarek --tools manta,Mpileup,strelka --input ${PATHTOSAMPLE}/tsv/tiny-manta-normal${SUFFIX}.tsv --genome smallerGRCh37 --noIntervals -resume - run_sarek --tools manta,Mpileup,strelka --input ${PATHTOSAMPLE}/tsv/tiny-manta-normal${SUFFIX}.tsv --genome minimalGRCh37 -resume - run_sarek --tools manta,Mpileup,strelka --input ${PATHTOSAMPLE}/tsv/tiny-manta-normal${SUFFIX}.tsv --genome minimalGRCh37 --noIntervals -resume - ;; - MULTIPLE) - run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Mpileup,Strelka,snpEff,VEP,merge --input ${PATHTOSAMPLE}/tsv/tiny-multiple${SUFFIX}.tsv - ;; -esac - -if [[ $TEST == "GERMLINE" ]] && [[ $OFFLINE == false ]] -then - rm -rf data -fi From 21e2b3aca6572a5969ddff736e1d1f42f92ea26d Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 9 Dec 2019 14:10:02 +0100 Subject: [PATCH 288/854] update docs --- docs/annotation.md | 8 ++-- docs/containers.md | 100 ++++++++++++++++++++++++++++++++++----------- docs/use_cases.md | 12 +++--- 3 files changed, 87 insertions(+), 33 deletions(-) diff --git a/docs/annotation.md b/docs/annotation.md index 2d954f3ac8..8500a6d59e 100644 --- a/docs/annotation.md +++ b/docs/annotation.md @@ -36,8 +36,8 @@ The cache will only be used when `--annotation_cache` and cache directories are Example: ```bash -nextflow run nf-core/sarek/main.nf --tools snpEff --step annotate --sample file.vcf.gz --snpEff_cache /Path/To/snpEffCache --annotation_cache -nextflow run nf-core/sarek/main.nf --tools VEP --step annotate --sample file.vcf.gz --vep_cache /Path/To/vepCache --annotation_cache +nextflow run nf-core/sarek --tools snpEff --step annotate --sample file.vcf.gz --snpEff_cache /Path/To/snpEffCache --annotation_cache +nextflow run nf-core/sarek --tools VEP --step annotate --sample file.vcf.gz --vep_cache /Path/To/vepCache --annotation_cache ``` ## Using VEP CADD plugin @@ -51,7 +51,7 @@ To enable the use of the VEP CADD plugin: Example: ```bash -nextflow run nf-core/sarek/main.nf --step annotate --tools VEP --sample file.vcf.gz --cadd_cache \ +nextflow run nf-core/sarek --step annotate --tools VEP --sample file.vcf.gz --cadd_cache \ --cadd_InDels /PathToCADD/InDels.tsv.gz \ --cadd_InDels_tbi /PathToCADD/InDels.tsv.gz.tbi \ --cadd_WG_SNVs /PathToCADD/whole_genome_SNVs.tsv.gz \ @@ -76,5 +76,5 @@ To enable the use of the VEP GeneSplicer plugin: Example: ```bash -nextflow run nf-core/sarek/main.nf --step annotate --tools VEP --sample file.vcf.gz --genesplicer +nextflow run nf-core/sarek --step annotate --tools VEP --sample file.vcf.gz --genesplicer ``` diff --git a/docs/containers.md b/docs/containers.md index b75d74db9a..6dfd8edae2 100644 --- a/docs/containers.md +++ b/docs/containers.md @@ -48,42 +48,96 @@ For annotation, the main container can be used, but the cache has to be download - Contain **[VEP](https://github.com/Ensembl/ensembl-vep)** 98.2 - Contain cache for `GRCh37`, `GRCh38`, `GRCm38` or `CanFam3.1` -## Using helper script +## Building your own -A helper script, used for testing can also be used to help with pulling docker containers, or building singularity images. -The following parameters can be used: +Our containers are designed using [Conda](https://conda.io/). +The [`environment.yml`](../environment.yml) file can be modified if particular versions of tools are more suited to your needs. -### Engine: -n +The following commands can be used to build/download containers on your own system: -Specify which container engine to use: `docker` or `singularity`. -Default:`docker` +- Adjust `VERSION` for sarek version (typically a release or `dev`). -### Containers: -c +### Build with Conda -Specify which containers to build: `SNPEFF`, `VEP` or `ALL`. -Default:`ALL` +```Bash +conda env create -f environment.yml +``` -### Version: -T +### Build with Docker -Specify which release to pull or build: any tagged release, or `dev`. -Default:`dev` +- `sarek` -### Genome: -g +```Bash +docker build -t nfcore/sarek: . +``` -Specify which release genome to use for annotation containers (`sareksnpeff`, `sarekvep`): `smallGRCh37`, `GRCh37`, `GRCh38`, `GRCm38` or `CanFam3.1`. -Default:`smallGRCh37` +- `sareksnpeff` -### Singularity +Adjust arguments for `GENOME` version and snpEff `CACHE_VERSION` -To specify where to build singularity image, use the Nextflow ENV variable `NXF_SINGULARITY_CACHEDIR`, ie: +```Bash +docker build -t nfcore/sareksnpeff:. containers/snpeff/. --build-arg GENOME= --build-arg CACHE_VERSION= +``` -```bash -NXF_SINGULARITY_CACHEDIR=/data/singularity ./scripts/download_image.sh -n singularity -t ALL -T dev -g GRCh38 +- `sarekvep` + +Adjust arguments for `GENOME` version, `SPECIES` name and VEP `VEP_VERSION` + +```Bash +docker build -t nfcore/sarekvep:. containers/vep/. --build-arg GENOME= --build-arg SPECIES= --build-arg VEP_VERSION= ``` -That will build the main container, plus the annotation containers (`sareksnpeff`, `sarekvep`) for `GRCh38`, in the `/data/singularity` folder. +### Pull with Docker -## Building your own +- `sarek` -Our containers are designed using [Conda](https://conda.io/). -The `environment.yml` file can easilly be modified if particular versions of tools are more suited to your needs. +```Bash +docker pull nfcore/sarek: +``` + +- `sareksnpeff` + +Adjust arguments for `GENOME` version + +```Bash +docker pull nfcore/sareksnpeff:. +``` + +- `sarekvep` + +Adjust arguments for `GENOME` version + +```Bash +docker pull nfcore/sarekvep:. +``` + +### Pull with Singularity + +You can directly pull singularity image, in the path used by the Nextflow ENV variable `NXF_SINGULARITY_CACHEDIR`, ie: + +```Bash +cd $NXF_SINGULARITY_CACHEDIR +singularity build ... +``` + +- `sarek` + +```Bash +singularity build nfcore-sarek-.img docker://nfcore/sarek: +``` + +- `sareksnpeff` + +Adjust arguments for `GENOME` version + +```Bash +singularity build nfcore-sareksnpeff-..img docker://nfcore/sareksnpeff:. +``` + +- `sarekvep` + +Adjust arguments for `GENOME` version + +```Bash +singularity build nfcore-sarekvep-..img docker://nfcore/sarekvep:. +``` diff --git a/docs/use_cases.md b/docs/use_cases.md index 2491ad69e6..f94400735a 100644 --- a/docs/use_cases.md +++ b/docs/use_cases.md @@ -5,7 +5,7 @@ Using the `mapping` directive one will have a pair of mapped, deduplicated and r This is the usual option you have to give when you are starting from raw FASTQ data: ```bash -nextflow run nf-core/sarek/main.nf --input mysample.tsv --tools +nextflow run nf-core/sarek --input mysample.tsv --tools ``` `mapping` will start by default, you do not have to give any additional parameters, only the TSV file describing the sample (see below). @@ -20,7 +20,7 @@ Also, older version are renamed with incremented numbers. The workflow should be started in this case with the smallest set of options as written above: ```bash -nextflow run nf-core/sarek/main.nf --input mysample.tsv --tools +nextflow run nf-core/sarek --input mysample.tsv --tools ``` The TSV file should look like: @@ -36,7 +36,7 @@ See the [input files documentation](docs/input.md) for more information. The `--input` option can be also used to point Sarek to a directory with FASTQ files: ```bash -nextflow run nf-core/sarek/main.nf --input path/to/FASTQ/files --tools +nextflow run nf-core/sarek --input path/to/FASTQ/files --tools ``` The given directory is searched recursively for FASTQ files that are named `*_R1_*.fastq.gz`, and a matching pair with the same name except `_R2_` instead of `_R1_` is expected to exist alongside. @@ -78,7 +78,7 @@ See the [input files documentation](docs/input.md) for more information. ## Starting from recalibration ```bash -nextflow run nf-core/sarek/main.nf --input mysample.tsv --step recalibrate --tools +nextflow run nf-core/sarek --input mysample.tsv --step recalibrate --tools ``` And the corresponding TSV file should be like: @@ -97,7 +97,7 @@ See the [input files documentation](docs/input.md) for more information. At this step we are assuming that all the required preprocessing is over, we only want to run variant callers or other tools using recalibrated BAM files. ```bash -nextflow run nf-core/sarek/main.nf --step variantcalling --tools +nextflow run nf-core/sarek --step variantcalling --tools ``` And the corresponding TSV file should be like: @@ -121,5 +121,5 @@ It is adviced to pad the variant calling regions (exons or the target) to some e To add the target BED file configure the flow like: ```bash -nextflow run nf-core/sarek/main.nf --tools haplotypecaller,strelka,mutect2 --targetBED targets.bed --input my_panel.tsv +nextflow run nf-core/sarek --tools haplotypecaller,strelka,mutect2 --targetBED targets.bed --input my_panel.tsv ``` From bdec00559c99309fa52184556b20fa81d003fc38 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 9 Dec 2019 15:25:24 +0100 Subject: [PATCH 289/854] update CHANGELOG --- CHANGELOG.md | 4 ++++ README.md | 1 - downloadcache.nf | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55e65e46cd..a52ada6b0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,10 +35,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - [#60](https://github.com/nf-core/sarek/pull/60) - Update documentation - [#71](https://github.com/nf-core/sarek/pull/71) - Update `README` - [#71](https://github.com/nf-core/sarek/pull/71) - Update `CHANGELOG` +- [#74](https://github.com/nf-core/sarek/pull/74) - Update docs +- [#74](https://github.com/nf-core/sarek/pull/74) - Improve CI tests (both Jenkins and GitHub actions tests) +- [#74](https://github.com/nf-core/sarek/pull/74) - Move all ci from `ci-extra.yml` to `ci.yml` ### `Removed` - [#46](https://github.com/nf-core/sarek/pull/46) - Remove mention of old `build.nf` script which was included in `main.nf` +- [#74](https://github.com/nf-core/sarek/pull/74) - Remove `download_image.sh` and `run_tests.sh` scripts ### `Fixed` diff --git a/README.md b/README.md index 8651fb0812..e42c1f74de 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ [![DOI](https://zenodo.org/badge/184289291.svg)](https://zenodo.org/badge/latestdoi/184289291) [![GitHub Actions CI status](https://github.com/nf-core/sarek/workflows/nf-core%20CI/badge.svg)](https://github.com/nf-core/sarek/actions?query=workflow%3A%22sarek+CI%22) -[![GitHub Actions extra-CI status](https://github.com/nf-core/sarek/workflows/nf-core%20extra%20CI/badge.svg)](https://github.com/nf-core/sarek/actions?query=workflow%3A%22sarek+extra+CI%22) [![GitHub Actions Linting status](https://github.com/nf-core/sarek/workflows/nf-core%20linting/badge.svg)](https://github.com/nf-core/sarek/actions?query=workflow%3A%22sarek+linting%22) [![CircleCi build status](https://img.shields.io/circleci/project/github/nf-core/sarek?logo=circleci)](https://circleci.com/gh/nf-core/sarek/) diff --git a/downloadcache.nf b/downloadcache.nf index 8e758391d5..00bfbbb775 100644 --- a/downloadcache.nf +++ b/downloadcache.nf @@ -54,7 +54,7 @@ params.build = null params.offline = null params.cadd_cache = null params.cadd_version = 'v1.5' -params.genome = 'smallGRCh37' +params.genome = 'GRCh37' params.snpEff_cache = null params.vep_cache = null From 20c2a44752e26816d7aefee7c2fe7dfe07255654 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 9 Dec 2019 15:26:06 +0100 Subject: [PATCH 290/854] improve script --- downloadcache.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/downloadcache.nf b/downloadcache.nf index 00bfbbb775..1a1048a7e8 100644 --- a/downloadcache.nf +++ b/downloadcache.nf @@ -182,7 +182,7 @@ process BuildCache_VEP { when: params.vep_cache && params.download_cache && !params.offline script: - genome = params.genome == "smallGRCh37" ? "GRCh37" : params.genome + genome = params.genome species = genome =~ "GRCh3*" ? "homo_sapiens" : genome =~ "GRCm3*" ? "mus_musculus" : "" """ vep_install \ From d90d0b7fd193b38ae8ddbe2bea17be37cb67efcf Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 9 Dec 2019 15:30:38 +0100 Subject: [PATCH 291/854] fix tests --- .github/workflows/ci.yml | 6 +++--- Jenkinsfile | 22 +++++++++++----------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9691252722..aa6edd447d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -62,9 +62,9 @@ jobs: git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data - name: Run test run: | - nextflow run --input data/testdata/tiny/normal - nextflow run --input=false --step recalibrate -resume - nextflow run --input=false --step variantCalling + nextflow run . -profile test,docker --input data/testdata/tiny/normal + nextflow run . -profile test,docker --input=false --step recalibrate -resume + nextflow run . -profile test,docker --input=false --step variantCalling minimal: runs-on: ubuntu-18.04 strategy: diff --git a/Jenkinsfile b/Jenkinsfile index 7dc9b45a88..2a26fd3d5f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -18,36 +18,36 @@ pipeline { } stage('Annotation') { steps { - sh "nextflow run . -profile test_annotation,docker --verbose --tools snpeff,vep,merge" + sh "nextflow run . -profile test_annotation,kraken --verbose --tools snpeff,vep,merge" } } stage('Germline') { steps { sh "rm -rf data/" sh "git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data" - sh "nextflow run --input data/testdata/tiny/normal" - sh "nextflow run --input=false --step recalibrate -resume" - sh "nextflow run --input=false --step variantCalling" + sh "nextflow run . -profile test,kraken --input data/testdata/tiny/normal" + sh "nextflow run . -profile test,kraken --input=false --step recalibrate -resume" + sh "nextflow run . -profile test,kraken --input=false --step variantCalling" sh "rm -rf data/" } } stage('Minimal') { steps { - sh "nextflow run . -profile test,docker --skipQC all --verbose --genome smallerGRCh37 --no_intervals --tools Manta,mpileup,Strelka" - sh "nextflow run . -profile test,docker --skipQC all --verbose --genome smallerGRCh37 --tools Manta,mpileup,Strelka" - sh "nextflow run . -profile test,docker --skipQC all --verbose --genome minimalGRCh37 --no_intervals --tools Manta,mpileup,Strelka" - sh "nextflow run . -profile test,docker --skipQC all --verbose --genome minimalGRCh37 --tools Manta,mpileup,Strelka" + sh "nextflow run . -profile test,kraken --skipQC all --verbose --genome smallerGRCh37 --no_intervals --tools Manta,mpileup,Strelka" + sh "nextflow run . -profile test,kraken --skipQC all --verbose --genome smallerGRCh37 --tools Manta,mpileup,Strelka" + sh "nextflow run . -profile test,kraken --skipQC all --verbose --genome minimalGRCh37 --no_intervals --tools Manta,mpileup,Strelka" + sh "nextflow run . -profile test,kraken --skipQC all --verbose --genome minimalGRCh37 --tools Manta,mpileup,Strelka" } } stage('Profile') { steps { - sh "nextflow run . -profile test_splitfastq,docker --verbose" - sh "nextflow run . -profile test_targeted,docker --verbose" + sh "nextflow run . -profile test_splitfastq,kraken --verbose" + sh "nextflow run . -profile test_targeted,kraken --verbose" } } stage('Tools') { steps { - sh "nextflow run . -profile test_tool,docker --verbose --tools Haplotypecaller,Freebayes,Manta,mpileup,Mutect2,Strelka" + sh "nextflow run . -profile test_tool,kraken --verbose --tools Haplotypecaller,Freebayes,Manta,mpileup,Mutect2,Strelka" } } } From 5355c1ea63a55b98da2eafb315ab46540d35a9ea Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 9 Dec 2019 15:36:26 +0100 Subject: [PATCH 292/854] better comments --- .github/workflows/ci.yml | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa6edd447d..89ee9f46d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,11 +36,13 @@ jobs: sudo mv nextflow /usr/local/bin/ env: NXF_VER: '19.10.0' - - name: Download image + - name: Download and tag images run: | + docker pull nfcore/sarek:dev + docker tag nfcore/sarek:dev nfcore/sarek:dev docker pull nfcore/sarek${{ matrix.annotator }}:dev.${{ matrix.specie }} docker tag nfcore/sarek${{ matrix.annotator }}:dev.${{ matrix.specie }} nfcore/sarek${{ matrix.annotator }}:dev.${{ matrix.specie }} - - name: Run test + - name: Run annotation test run: | nextflow run . -profile test_annotation,docker --verbose --tools ${{ matrix.annotator }} germline: @@ -53,14 +55,14 @@ jobs: sudo mv nextflow /usr/local/bin/ env: NXF_VER: '19.10.0' - - name: Download image + - name: Download and tag image run: | docker pull nfcore/sarek:dev docker tag nfcore/sarek:dev nfcore/sarek:dev - name: Get test data run: | git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data - - name: Run test + - name: Run germline test run: | nextflow run . -profile test,docker --input data/testdata/tiny/normal nextflow run . -profile test,docker --input=false --step recalibrate -resume @@ -79,11 +81,11 @@ jobs: sudo mv nextflow /usr/local/bin/ env: NXF_VER: '19.10.0' - - name: Download image + - name: Download and tag image run: | docker pull nfcore/sarek:dev docker tag nfcore/sarek:dev nfcore/sarek:dev - - name: Run test + - name: Run test for minimal genomes run: | nextflow run . -profile test,docker --skipQC all --verbose --genome ${{ matrix.genome }} ${{ matrix.intervals }} --tools Manta,mpileup,Strelka profile: @@ -99,11 +101,11 @@ jobs: sudo mv nextflow /usr/local/bin/ env: NXF_VER: '19.10.0' - - name: Download image + - name: Download and tag image run: | docker pull nfcore/sarek:dev docker tag nfcore/sarek:dev nfcore/sarek:dev - - name: Run test + - name: Run targeted and splitfastq tests run: | nextflow run . -profile ${{ matrix.profile }},docker --verbose tools: @@ -119,10 +121,10 @@ jobs: sudo mv nextflow /usr/local/bin/ env: NXF_VER: '19.10.0' - - name: Download image + - name: Download and tag image run: | docker pull nfcore/sarek:dev docker tag nfcore/sarek:dev nfcore/sarek:dev - - name: Run test + - name: Run vriant calling test on specific tools run: | nextflow run . -profile test_tool,docker --verbose --tools ${{ matrix.tool }} \ No newline at end of file From dc043d0019a739fe6e1327a5c8c3398e18d37fc2 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 9 Dec 2019 16:10:42 +0100 Subject: [PATCH 293/854] better comments --- main.nf | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/main.nf b/main.nf index 7276c2f0bf..6ce7efc521 100644 --- a/main.nf +++ b/main.nf @@ -1431,10 +1431,13 @@ bamQCReport = bamQCReport.dump(tag:'BamQC') ================================================================================ */ +// When using sentieon for mapping, Channel bamRecal is bamRecalSentieon if (params.sentieon && step == 'mapping') bamRecal = bamRecalSentieon -bamRecal = params.knownIndels ? bamRecal : indexedBam +// When no knownIndels for mapping, Channel bamRecal is indexedBam +bamRecal = (params.knownIndels && step == 'mapping') ? bamRecal : indexedBam +// When starting with variant calling, Channel bamRecal is inputSample if (step == 'variantcalling') bamRecal = inputSample bamRecal = bamRecal.dump(tag:'BAM') From 68571f41bb110fbd5b60e61eac6021833784607b Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 9 Dec 2019 16:13:42 +0100 Subject: [PATCH 294/854] fix error on channel name --- main.nf | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/main.nf b/main.nf index 6ce7efc521..4a42883a38 100644 --- a/main.nf +++ b/main.nf @@ -755,13 +755,13 @@ fastQCReport = fastQCReport.dump(tag:'FastQC') // STEP 1: MAPPING READS TO REFERENCE GENOME WITH BWA MEM -inputReads = inputReads.dump(tag:'INPUT') +inputPairReads = inputPairReads.dump(tag:'INPUT') -inputReads = inputPairReads.mix(inputBam) +inputPairReads = inputPairReads.mix(inputBam) -(inputReads, inputReadsSentieon) = inputReads.into(2) -if (params.sentieon) inputReads.close() -else inputReadsSentieon.close() +(inputPairReads, inputPairReadsSentieon) = inputPairReads.into(2) +if (params.sentieon) inputPairReads.close() +else inputPairReadsSentieon.close() process MapReads { label 'cpus_max' @@ -769,7 +769,7 @@ process MapReads { tag {idPatient + "-" + idRun} input: - set idPatient, idSample, idRun, file(inputFile1), file(inputFile2) from inputReads + set idPatient, idSample, idRun, file(inputFile1), file(inputFile2) from inputPairReads file(bwaIndex) from ch_bwaIndex file(fasta) from ch_fasta file(fastaFai) from ch_fastaFai @@ -822,7 +822,7 @@ process SentieonMapReads { tag {idPatient + "-" + idRun} input: - set idPatient, idSample, idRun, file(inputFile1), file(inputFile2) from inputReadsSentieon + set idPatient, idSample, idRun, file(inputFile1), file(inputFile2) from inputPairReadsSentieon file(bwaIndex) from ch_bwaIndex file(fasta) from ch_fasta file(fastaFai) from ch_fastaFai From 4286ef33d17279aad1df1c69cb045aca7ec2d877 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Mon, 9 Dec 2019 16:40:52 +0100 Subject: [PATCH 295/854] fix output for MergeBamRecal --- main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.nf b/main.nf index 4a42883a38..664975d474 100644 --- a/main.nf +++ b/main.nf @@ -1295,7 +1295,7 @@ process MergeBamRecal { set idPatient, idSample, file(bam) from bamMergeBamRecal output: - set idPatient, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bai") into bamRecal + set idPatient, idSample, file("${idSample}.recal.bam") into bamRecal set idPatient, idSample, file("${idSample}.recal.bam") into bamRecalQC set idPatient, idSample into bamRecalTSV From 77de22886778f0713e8bbbc7d3d1ec71df8eb5ab Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 10 Dec 2019 09:45:14 +0100 Subject: [PATCH 296/854] fix MergeBamRecal output --- main.nf | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/main.nf b/main.nf index 664975d474..997cd9c318 100644 --- a/main.nf +++ b/main.nf @@ -1295,7 +1295,7 @@ process MergeBamRecal { set idPatient, idSample, file(bam) from bamMergeBamRecal output: - set idPatient, idSample, file("${idSample}.recal.bam") into bamRecal + set idPatient, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bam.bai") into bamRecal set idPatient, idSample, file("${idSample}.recal.bam") into bamRecalQC set idPatient, idSample into bamRecalTSV @@ -1321,7 +1321,7 @@ process IndexBamRecal { set idPatient, idSample, file("${idSample}.recal.bam") from bamMergeBamRecalNoInt output: - set idPatient, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bai") into bamRecalNoInt + set idPatient, idSample, file("${idSample}.recal.bam"), file("${idSample}.recal.bam.bai") into bamRecalNoInt set idPatient, idSample, file("${idSample}.recal.bam") into bamRecalQCnoInt set idPatient, idSample into bamRecalTSVnoInt @@ -1330,7 +1330,6 @@ process IndexBamRecal { script: """ samtools index ${idSample}.recal.bam - mv ${idSample}.recal.bam.bai ${idSample}.recal.bai """ } From 72fb6027ef32f87d4de4d20eb293e7424dade1aa Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 10 Dec 2019 09:52:56 +0100 Subject: [PATCH 297/854] fix TSV file --- main.nf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.nf b/main.nf index 997cd9c318..1265c244f8 100644 --- a/main.nf +++ b/main.nf @@ -1345,7 +1345,7 @@ bamRecalTSV.map { idPatient, idSample -> gender = genderMap[idPatient] status = statusMap[idPatient, idSample] bam = "${params.outdir}/Preprocessing/${idSample}/Recalibrated/${idSample}.recal.bam" - bai = "${params.outdir}/Preprocessing/${idSample}/Recalibrated/${idSample}.recal.bai" + bai = "${params.outdir}/Preprocessing/${idSample}/Recalibrated/${idSample}.recal.bam.bai" "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\n" }.collectFile( name: 'recalibrated.tsv', sort: true, storeDir: "${params.outdir}/Preprocessing/TSV" @@ -1357,7 +1357,7 @@ bamRecalSampleTSV status = statusMap[idPatient, idSample] gender = genderMap[idPatient] bam = "${params.outdir}/Preprocessing/${idSample}/Recalibrated/${idSample}.recal.bam" - bai = "${params.outdir}/Preprocessing/${idSample}/Recalibrated/${idSample}.recal.bai" + bai = "${params.outdir}/Preprocessing/${idSample}/Recalibrated/${idSample}.recal.bam.bai" ["recalibrated_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\n"] } From d896596d6bb6f6fc89b6f3a16063e138655757b1 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 10 Dec 2019 11:29:29 +0100 Subject: [PATCH 298/854] update comments and docs --- docs/output.md | 557 ++++++++++++++++++++++++++++--------------------- docs/usage.md | 423 +++++++++++++++++++------------------ main.nf | 16 +- 3 files changed, 542 insertions(+), 454 deletions(-) diff --git a/docs/output.md b/docs/output.md index 58f9af63a2..3c62b97abb 100644 --- a/docs/output.md +++ b/docs/output.md @@ -1,72 +1,97 @@ -# nf-core/sarek: Output +# nf-core/sarek: Output This document describes the output produced by the pipeline. -## Pipeline overview +## Pipeline overview The pipeline processes data using the following steps: -1. [**Preprocessing**](#Preprocessing) _(based on [GATK best practices](https://software.broadinstitute.org/gatk/best-practices/))_ - * Map reads to Reference - * `BWA mem` - * Mark Duplicates - * `GATK MarkDuplicates` - * Base (Quality Score) Recalibration - * `GATK BaseRecalibrator` - * `GATK GatherBQSRReports` - * `GATK ApplyBQSR` -2. [**Variant calling**](#Variant-Calling) - * SNVs and small indels - * [`FreeBayes`](#FreeBayes) - * [`GATK HaplotypeCaller`](#HaplotypeCaller) - * [`GATK GenotypeGVCFs`](#GenotypeGVCFs) - * [`GATK Mutect2`](#Mutect2) - * [`Strelka2`](#Strelka2) - * Structural variants - * [`Manta`](#Manta) - * [`TIDDIT`](#TIDDIT) - * Sample heterogeneity, ploidy and CNVs - * `alleleCounter` - * [`ConvertAlleleCounts`](#ConvertAlleleCounts) - * [`ASCAT`](#ASCAT) - * [`samtools mpileup`](#mpileup) - * [`Control-FREEC`](#Control-FREEC) -3. [**Annotation**](#Annotation) - * Variant annotation - * [`snpEff`](#snpEff) - * [`VEP` (Variant Effect Predictor)](#VEP) -4. [**QC and Reporting**](#QC-and-reporting) - * QC - * [`FastQC`](#FastQC) - * [`Qualimap bamqc`](#bamQC) - * [`GATK MarkDuplicates`](#MarkDuplicates-reports) - * [`samtools stats`](#Samtools-stats) - * [`bcftools stats`](#bcftools-stats) - * [`VCFtools`](#VCFtools) - * [`snpeff`](#snpEff-reports) - * [`VEP`](#snpEff-reports) - * Reporting - * [`MultiQC`](#MultiQC) +- [Preprocessing](#preprocessing) + - [Map to Reference](#map-to-reference) + - [BWA mem](#bwa-mem) + - [Mark Duplicates](#mark-duplicates) + - [GATK MarkDuplicates](#gatk-markduplicates) + - [Base (Quality Score) Recalibration](#base-quality-score-recalibration) + - [GATK BaseRecalibrator](#gatk-baserecalibrator) + - [GATK ApplyBQSR](#gatk-applybqsr) + - [TSV files](#tsv-files) +- [Variant Calling](#variant-calling) + - [SNVs and small indels](#snvs-and-small-indels) + - [FreeBayes](#freebayes) + - [GATK HaplotypeCaller](#gatk-haplotypecaller) + - [GATK GenotypeGVCFs](#gatk-genotypegvcfs) + - [GATK Mutect2](#gatk-mutect2) + - [samtools mpileup](#samtools-mpileup) + - [Strelka2](#strelka2) + - [Sentieon DNAseq](#sentieon-dnaseq) + - [Sentieon DNAscope](#sentieon-dnascope) + - [Sentieon TNscope](#sentieon-tnscope) + - [Structural Variants](#structural-variants) + - [Manta](#manta) + - [TIDDIT](#tiddit) + - [Sentieon DNAscope SV](#sentieon-dnascope-sv) + - [Sample heterogeneity, ploidy and CNVs](#sample-heterogeneity-ploidy-and-cnvs) + - [ConvertAlleleCounts](#convertallelecounts) + - [ASCAT](#ascat) + - [Control-FREEC](#control-freec) +- [Variant annotation](#variant-annotation) + - [snpEff](#snpeff) + - [VEP](#vep) +- [QC and reporting](#qc-and-reporting) + - [QC](#qc) + - [FastQC](#fastqc) + - [bamQC](#bamqc) + - [MarkDuplicates reports](#markduplicates-reports) + - [samtools stats](#samtools-stats) + - [bcftools stats](#bcftools-stats) + - [VCFtools](#vcftools) + - [snpEff reports](#snpeff-reports) + - [VEP reports](#vep-reports) + - [Reporting](#reporting) + - [MultiQC](#multiqc) ## Preprocessing Sarek preprocesses raw FastQ files or unmapped BAM files, based on [GATK best practices](https://software.broadinstitute.org/gatk/best-practices/). -BAM files with Recalibration tables can also be used as an input to start with the recalibration of said BAM files, for more information see [TSV files output information](#TSV-files) +BAM files with Recalibration tables can also be used as an input to start with the recalibration of said BAM files, for more information see [TSV files output information](#tsv-files) -### Duplicate Marked BAM file(s) with Recalibration Table(s) +### Map to Reference -This directory is the location for the BAM files delivered to users. Besides the duplicate marked BAM files, the recalibration tables (`*.recal.table`) are also stored, and can be used to create base recalibrated files. +#### BWA mem + +[BWA mem](http://bio-bwa.sourceforge.net/) is a software package for mapping low-divergent sequences against a large reference genome. + +Such files are intermediate and not kept in the final files delivered to users. + +### Mark Duplicates + +#### GATK MarkDuplicates + +[GATK MarkDuplicates](https://software.broadinstitute.org/gatk/documentation/tooldocs/4.1.4.0/picard_sam_markduplicates_MarkDuplicates.php) locates and tags duplicate reads in a BAM or SAM file, where duplicate reads are defined as originating from a single fragment of DNA. + +This directory is the location for the BAM files delivered to users. +Besides the duplicate marked BAM files, the recalibration tables (`*.recal.table`) are also stored, and can be used to create base recalibrated files. For further reading and documentation see the [data pre-processing workflow from the GATK best practices](https://software.broadinstitute.org/gatk/best-practices/workflow?id=11165). For all samples: **Output directory: `results/Preprocessing/[SAMPLE]/DuplicateMarked`** -* `[SAMPLE].md.bam`, `[SAMPLE].md.bai` and `[SAMPLE].recal.table` - * BAM file and index with Recalibration Table +- `[SAMPLE].md.bam`, `[SAMPLE].md.bai` and `[SAMPLE].recal.table` + - BAM file and index with Recalibration Table + +### Base (Quality Score) Recalibration + +#### GATK BaseRecalibrator + +[GATK BaseRecalibrator](https://software.broadinstitute.org/gatk/documentation/tooldocs/current/org_broadinstitute_hellbender_tools_walkers_bqsr_BaseRecalibrator.php) generates a recalibration table based on various covariates. -### Recalibrated BAM file(s) +Such files are intermediate and not kept in the final files delivered to users. + +#### GATK ApplyBQSR + +[GATK ApplyBQSR](https://software.broadinstitute.org/gatk/documentation/tooldocs/current/org_broadinstitute_hellbender_tools_walkers_bqsr_ApplyBQSR.php) recalibrates the base qualities of the input reads based on the recalibration table produced by the [`BaseRecalibrator`](#gatk-baserecalibrator) tool. This directory is usually empty, it is the location for the final recalibrated BAM files. Recalibrated BAM files are usually 2-3 times larger than the duplicate marked BAM files. @@ -77,30 +102,32 @@ For further reading and documentation see the [data pre-processing workflow from For all samples: **Output directory: `results/Preprocessing/[SAMPLE]/Recalibrated`** -* `[SAMPLE].recal.bam` and `[SAMPLE].recal.bai` - * BAM file and index +- `[SAMPLE].recal.bam` and `[SAMPLE].recal.bai` + - BAM file and index ### TSV files -The TSV files are autogenerated and can be used by Sarek for further processing and/or variant calling. +The TSV files are auto-generated and can be used by Sarek for further processing and/or variant calling. For further reading and documentation see the [input documentation](https://github.com/nf-core/sarek/blob/master/docs/input.md). For all samples: **Output directory: `results/Preprocessing/TSV`** -* `duplicateMarked.tsv` and `recalibrated.tsv` - * TSV files to start Sarek from `recalibration` or `variantcalling` steps. -* `duplicateMarked_[SAMPLE].tsv` and `recalibrated_[SAMPLE].tsv` - * TSV files to start Sarek from `recalibration` or `variantcalling` steps for a specific sample. +- `duplicateMarked.tsv` and `recalibrated.tsv` + - TSV files to start Sarek from `recalibration` or `variantcalling` steps. +- `duplicateMarked_[SAMPLE].tsv` and `recalibrated_[SAMPLE].tsv` + - TSV files to start Sarek from `recalibration` or `variantcalling` steps for a specific sample. ## Variant Calling -All the results regarding variant-calling are collected in this directory. +All the results regarding Variant Calling are collected in this directory. + +Recalibrated BAM files can also be used as an input to start the Variant Calling, for more information see [TSV files output information](#tsv-files) -Recalibrated BAM files can also be used as an input to start the Variant Calling, for more information see [TSV files output information](#TSV-files) +### SNVs and small indels -### FreeBayes +#### FreeBayes [FreeBayes](https://github.com/ekg/freebayes) is a Bayesian genetic variant detector designed to find small polymorphisms, specifically SNPs, indels, MNPs, and complex events smaller than the length of a short-read sequencing alignment.. @@ -109,10 +136,10 @@ For further reading and documentation see the [FreeBayes manual](https://github. For a Tumor/Normal pair only: **Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/FreeBayes`** -* `FreeBayes_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz` and `FreeBayes_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.tbi` - * VCF with Tabix index +- `FreeBayes_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz` and `FreeBayes_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.tbi` + - VCF with Tabix index -### HaplotypeCaller +#### GATK HaplotypeCaller [GATK HaplotypeCaller](https://github.com/broadinstitute/gatk) calls germline SNPs and indels via local re-assembly of haplotypes. @@ -123,10 +150,10 @@ For further reading and documentation see the [HaplotypeCaller manual](https://s For all samples: **Output directory: `results/VariantCalling/[SAMPLE]/HaploTypeCaller`** -* `HaplotypeCaller_[SAMPLE].vcf.gz` and `HaplotypeCaller_[SAMPLE].vcf.gz.tbi` - * VCF with Tabix index +- `HaplotypeCaller_[SAMPLE].vcf.gz` and `HaplotypeCaller_[SAMPLE].vcf.gz.tbi` + - VCF with Tabix index -### GenotypeGVCFs +#### GATK GenotypeGVCFs [GATK GenotypeGVCFs](https://github.com/broadinstitute/gatk) performs joint genotyping on one or more samples pre-called with HaplotypeCaller. @@ -137,10 +164,10 @@ For further reading and documentation see the [GenotypeGVCFs manual](https://sof For all samples: **Output directory: `results/VariantCalling/[SAMPLE]/HaplotypeCallerGVCF`** -* `HaplotypeCaller_[SAMPLE].g.vcf.gz` and `HaplotypeCaller_[SAMPLE].g.vcf.gz.tbi` - * VCF with Tabix index +- `HaplotypeCaller_[SAMPLE].g.vcf.gz` and `HaplotypeCaller_[SAMPLE].g.vcf.gz.tbi` + - VCF with Tabix index -### Mutect2 +#### GATK Mutect2 [GATK Mutect2](https://github.com/broadinstitute/gatk) calls somatic SNVs and indels via local assembly of haplotypes. @@ -152,41 +179,28 @@ For a Tumor/Normal pair only: Files created: -* `unfiltered_Mutect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz` and `unfiltered_Mutect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.tbi` - * unfiltered (raw) Mutect2 calls VCF with Tabix index -* `filtered_Mutect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz` and `filtered_Mutect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.tbi` - * filtered Mutect2 calls VCF with Tabix index: these entries has a PASS filter, you can get these when supplying a panel of normals using the `--pon` option -* `[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.stats` - * a stats file generated during calling raw variants (needed for filtering) -* `[TUMORSAMPLE]_contamination.table` - * a text file exported when panel-of-normals provided about sample contamination +- `unfiltered_Mutect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz` and `unfiltered_Mutect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.tbi` + - unfiltered (raw) Mutect2 calls VCF with Tabix index +- `filtered_Mutect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz` and `filtered_Mutect2_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.tbi` + - filtered Mutect2 calls VCF with Tabix index: these entries has a PASS filter, you can get these when supplying a panel of normals using the `--pon` option +- `[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.stats` + - a stats file generated during calling raw variants (needed for filtering) +- `[TUMORSAMPLE]_contamination.table` + - a text file exported when panel-of-normals provided about sample contamination -### TIDDIT - -[TIDDIT](https://github.com/SciLifeLab/TIDDIT) identifies intra and inter-chromosomal translocations, deletions, tandem-duplications and inversions. +#### samtools mpileup -Germline calls are provided for all samples, to able comparison of both tumor and normal for possible mixup. -Low quality calls are removed internally, to simplify processing of variant calls but they are saved by Sarek. +[samtools mpileup](https://www.htslib.org/doc/samtools.html) generate pileup for a BAM file. -For further reading and documentation see the [TIDDIT manual](https://github.com/SciLifeLab/TIDDIT/blob/master/README.md). +For further reading and documentation see the [samtools manual](https://www.htslib.org/doc/samtools.html#COMMANDS_AND_OPTIONS). For all samples: -**Output directory: `results/VariantCalling/[SAMPLE]/TIDDIT`** +**Output directory: `results/VariantCalling/[SAMPLE]/mpileup`** -* `TIDDIT_[SAMPLE].vcf.gz` and `TIDDIT_[SAMPLE].vcf.gz.tbi` - * VCF with Tabix index -* `TIDDIT_[SAMPLE].signals.tab` - * tab file describing coverage across the genome, binned per 50 bp -* `TIDDIT_[SAMPLE].ploidy.tab` - * tab file describing the estimated ploïdy and coverage across each contig -* `TIDDIT_[SAMPLE].old.vcf` - * VCF including the low qualiy calls -* `TIDDIT_[SAMPLE].wig` - * wiggle file containing coverage across the genome, binned per 50 bp -* `TIDDIT_[SAMPLE].gc.wig` - * wiggle file containing fraction of gc content, binned per 50 bp - -### Strelka2 +- `[SAMPLE].pileup.gz` + - The pileup format is a text-based format for summarizing the base calls of aligned reads to a reference sequence. Alignment records are grouped by sample (SM) identifiers in @RG header lines. + +#### Strelka2 [Strelka2](https://github.com/Illumina/strelka) is a fast and accurate small variant caller optimized for analysis of germline variation in small cohorts and somatic variation in tumor/normal sample pairs. @@ -195,28 +209,66 @@ For further reading and documentation see the [Strelka2 user guide](https://gith For all samples: **Output directory: `results/VariantCalling/[SAMPLE]/Strelka`** -* `Strelka_Sample_genome.vcf.gz` and `Strelka_Sample_genome.vcf.gz.tbi` - * VCF with Tabix index -* `Strelka_Sample_variants.vcf.gz` and `Strelka_Sample_variants.vcf.gz.tbi` - * VCF with Tabix index +- `Strelka_Sample_genome.vcf.gz` and `Strelka_Sample_genome.vcf.gz.tbi` + - VCF with Tabix index +- `Strelka_Sample_variants.vcf.gz` and `Strelka_Sample_variants.vcf.gz.tbi` + - VCF with Tabix index For a Tumor/Normal pair: **Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/Strelka`** -* `Strelka_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_indels.vcf.gz` and `Strelka_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_indels.vcf.gz.tbi` - * VCF with Tabix index -* `Strelka_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_snvs.vcf.gz` and `Strelka_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_snvs.vcf.gz.tbi` - * VCF with Tabix index +- `Strelka_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_indels.vcf.gz` and `Strelka_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_indels.vcf.gz.tbi` + - VCF with Tabix index +- `Strelka_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_snvs.vcf.gz` and `Strelka_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_snvs.vcf.gz.tbi` + - VCF with Tabix index Using [Strelka Best Practices](https://github.com/Illumina/strelka/blob/v2.9.x/docs/userGuide/README.md#somatic-configuration-example) with the `candidateSmallIndels` from `Manta`: **Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/Strelka`** -* `StrelkaBP_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_indels.vcf.gz` and `StrelkaBP_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_indels.vcf.gz.tbi` - * VCF with Tabix index -* `StrelkaBP_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_snvs.vcf.gz` and `StrelkaBP_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_snvs.vcf.gz.tbi` - * VCF with Tabix index +- `StrelkaBP_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_indels.vcf.gz` and `StrelkaBP_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_indels.vcf.gz.tbi` + - VCF with Tabix index +- `StrelkaBP_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_snvs.vcf.gz` and `StrelkaBP_[TUMORSAMPLE]_vs_[NORMALSAMPLE]_somatic_snvs.vcf.gz.tbi` + - VCF with Tabix index + +#### Sentieon DNAseq + +[Sentieon DNAseq](https://www.sentieon.com/products/#dnaseq) implements the same mathematics used in the Broad Institute’s BWA-GATK HaplotypeCaller 3.3-4.1 Best Practices Workflow pipeline. + +For further reading and documentation see the [Sentieon DNAseq user guide](https://support.sentieon.com/manual/DNAseq_usage/dnaseq/). + +For all samples: +**Output directory: `results/VariantCalling/[SAMPLE]/SentieonDNAseq`** + +- `DNAseq_Sample.vcf.gz` and `DNAseq_Sample.vcf.gz.tbi` + - VCF with Tabix index + +#### Sentieon DNAscope + +[Sentieon DNAscope](https://www.sentieon.com/products) calls SNPs and small indels. + +For further reading and documentation see the [Sentieon DNAscope user guide](https://support.sentieon.com/manual/DNAscope_usage/dnascope/). + +For all samples: +**Output directory: `results/VariantCalling/[SAMPLE]/SentieonDNAscope`** + +- `DNAscope_Sample.vcf.gz` and `DNAscope_Sample.vcf.gz.tbi` + - VCF with Tabix index + +#### Sentieon TNscope + +[Sentieon TNscope](https://www.sentieon.com/products/#tnscope) calls SNPs and small indels on an Tumor/Normal pair. -### Manta +For further reading and documentation see the [Sentieon TNscope user guide](https://support.sentieon.com/manual/TNscope_usage/tnscope/). + +For a Tumor/Normal pair: +**Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/SentieonTNscope`** + +- `TNscope_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz` and `TNscope_[TUMORSAMPLE]_vs_[NORMALSAMPLE].vcf.gz.tbi` + - VCF with Tabix index + +### Structural Variants + +#### Manta [Manta](https://github.com/Illumina/manta) calls structural variants (SVs) and indels from mapped paired-end sequencing reads. It is optimized for analysis of germline variation in small sets of individuals and somatic variation in tumor/normal sample pairs. @@ -227,46 +279,85 @@ For further reading and documentation see the [Manta user guide](https://github. For all samples: **Output directory: `results/VariantCalling/[SAMPLE]/Manta`** -* `Manta_[SAMPLE].candidateSmallIndels.vcf.gz` and `Manta_[SAMPLE].candidateSmallIndels.vcf.gz.tbi` - * VCF with Tabix index -* `Manta_[SAMPLE].candidateSV.vcf.gz` and `Manta_[SAMPLE].candidateSV.vcf.gz.tbi` - * VCF with Tabix index +- `Manta_[SAMPLE].candidateSmallIndels.vcf.gz` and `Manta_[SAMPLE].candidateSmallIndels.vcf.gz.tbi` + - VCF with Tabix index +- `Manta_[SAMPLE].candidateSV.vcf.gz` and `Manta_[SAMPLE].candidateSV.vcf.gz.tbi` + - VCF with Tabix index For Normal sample only: -* `Manta_[NORMALSAMPLE].diploidSV.vcf.gz` and `Manta_[NORMALSAMPLE].diploidSV.vcf.gz.tbi` - * VCF with Tabix index +- `Manta_[NORMALSAMPLE].diploidSV.vcf.gz` and `Manta_[NORMALSAMPLE].diploidSV.vcf.gz.tbi` + - VCF with Tabix index For a Tumor sample only: -* `Manta_[TUMORSAMPLE].tumorSV.vcf.gz` and `Manta_[TUMORSAMPLE].tumorSV.vcf.gz.tbi` - * VCF with Tabix index +- `Manta_[TUMORSAMPLE].tumorSV.vcf.gz` and `Manta_[TUMORSAMPLE].tumorSV.vcf.gz.tbi` + - VCF with Tabix index For a Tumor/Normal pair only: **Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/Manta`** -* `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].candidateSmallIndels.vcf.gz` and `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].candidateSmallIndels.vcf.gz.tbi` - * VCF with Tabix index -* `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].candidateSV.vcf.gz` and `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].candidateSV.vcf.gz.tbi` - * VCF with Tabix index -* `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].diploidSV.vcf.gz` and `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].diploidSV.vcf.gz.tbi` - * VCF with Tabix index -* `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].somaticSV.vcf.gz` and `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].somaticSV.vcf.gz.tbi` - * VCF with Tabix index +- `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].candidateSmallIndels.vcf.gz` and `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].candidateSmallIndels.vcf.gz.tbi` + - VCF with Tabix index +- `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].candidateSV.vcf.gz` and `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].candidateSV.vcf.gz.tbi` + - VCF with Tabix index +- `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].diploidSV.vcf.gz` and `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].diploidSV.vcf.gz.tbi` + - VCF with Tabix index +- `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].somaticSV.vcf.gz` and `Manta_[TUMORSAMPLE]_vs_[NORMALSAMPLE].somaticSV.vcf.gz.tbi` + - VCF with Tabix index + +#### TIDDIT + +[TIDDIT](https://github.com/SciLifeLab/TIDDIT) identifies intra and inter-chromosomal translocations, deletions, tandem-duplications and inversions. + +Germline calls are provided for all samples, to able comparison of both tumor and normal for possible mixup. +Low quality calls are removed internally, to simplify processing of variant calls but they are saved by Sarek. + +For further reading and documentation see the [TIDDIT manual](https://github.com/SciLifeLab/TIDDIT/blob/master/README.md). + +For all samples: +**Output directory: `results/VariantCalling/[SAMPLE]/TIDDIT`** + +- `TIDDIT_[SAMPLE].vcf.gz` and `TIDDIT_[SAMPLE].vcf.gz.tbi` + - VCF with Tabix index +- `TIDDIT_[SAMPLE].signals.tab` + - tab file describing coverage across the genome, binned per 50 bp +- `TIDDIT_[SAMPLE].ploidy.tab` + - tab file describing the estimated ploïdy and coverage across each contig +- `TIDDIT_[SAMPLE].old.vcf` + - VCF including the low qualiy calls +- `TIDDIT_[SAMPLE].wig` + - wiggle file containing coverage across the genome, binned per 50 bp +- `TIDDIT_[SAMPLE].gc.wig` + - wiggle file containing fraction of gc content, binned per 50 bp + +#### Sentieon DNAscope SV -### ConvertAlleleCounts +[Sentieon DNAscope](https://www.sentieon.com/products) can perform structural variant calling in addition to calling SNPs and small indels. + +For further reading and documentation see the [Sentieon DNAscope user guide](https://support.sentieon.com/manual/DNAscope_usage/dnascope/). + +For all samples: +**Output directory: `results/VariantCalling/[SAMPLE]/SentieonDNAscope`** + +- `DNAscope_SV_Sample.vcf.gz` and `DNAscope_SV_Sample.vcf.gz.tbi` + - VCF with Tabix index + +### Sample heterogeneity, ploidy and CNVs + +#### ConvertAlleleCounts [ConvertAlleleCounts](https://github.com/nf-core/sarek/blob/master/bin/convertAlleleCounts.r) is a R-script for converting output from AlleleCount to BAF and LogR values. For a Tumor/Normal pair only: **Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/ASCAT`** -* `[TUMORSAMPLE].BAF` and `[NORMALSAMPLE].BAF` - * file with beta allele frequencies -* `[TUMORSAMPLE].LogR` and `[NORMALSAMPLE].LogR` - * file with total copy number on a logarithmic scale +- `[TUMORSAMPLE].BAF` and `[NORMALSAMPLE].BAF` + - file with beta allele frequencies +- `[TUMORSAMPLE].LogR` and `[NORMALSAMPLE].LogR` + - file with total copy number on a logarithmic scale -### ASCAT +#### ASCAT [ASCAT](https://github.com/Crick-CancerGenomics/ascat) is a method to derive copy number profiles of tumor cells, accounting for normal cell admixture and tumor aneuploidy. ASCAT infers tumor purity and ploidy and calculates whole-genome allele-specific copy number profiles. @@ -276,38 +367,26 @@ For further reading and documentation see [the Sarek documentation about ASCAT]( For a Tumor/Normal pair only: **Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/ASCAT`** -* `[TUMORSAMPLE].aberrationreliability.png` - * Image with information about aberration reliability -* `[TUMORSAMPLE].ASCATprofile.png` - * Image with information about ASCAT profile -* `[TUMORSAMPLE].ASPCF.png` - * Image with information about ASPCF -* `[TUMORSAMPLE].rawprofile.png` - * Image with information about raw profile -* `[TUMORSAMPLE].sunrise.png` - * Image with information about sunrise -* `[TUMORSAMPLE].tumour.png` - * Image with information about tumor -* `[TUMORSAMPLE].cnvs.txt` - * file with information about CNVS -* `[TUMORSAMPLE].LogR.PCFed.txt` - * file with information about LogR -* `[TUMORSAMPLE].purityploidy.txt` - * file with information about purity ploidy - -### mpileup - -[samtools mpileup](https://www.htslib.org/doc/samtools.html) generate pileup for a BAM file. - -For further reading and documentation see the [samtools manual](https://www.htslib.org/doc/samtools.html#COMMANDS_AND_OPTIONS). - -For all samples: -**Output directory: `results/VariantCalling/[SAMPLE]/mpileup`** - -* `[SAMPLE].pileup.gz` - * The pileup format is a text-based format for summarizing the base calls of aligned reads to a reference sequence. Alignment records are grouped by sample (SM) identifiers in @RG header lines. - -### Control-FREEC +- `[TUMORSAMPLE].aberrationreliability.png` + - Image with information about aberration reliability +- `[TUMORSAMPLE].ASCATprofile.png` + - Image with information about ASCAT profile +- `[TUMORSAMPLE].ASPCF.png` + - Image with information about ASPCF +- `[TUMORSAMPLE].rawprofile.png` + - Image with information about raw profile +- `[TUMORSAMPLE].sunrise.png` + - Image with information about sunrise +- `[TUMORSAMPLE].tumour.png` + - Image with information about tumor +- `[TUMORSAMPLE].cnvs.txt` + - file with information about CNVS +- `[TUMORSAMPLE].LogR.PCFed.txt` + - file with information about LogR +- `[TUMORSAMPLE].purityploidy.txt` + - file with information about purity ploidy + +#### Control-FREEC [Control-FREEC](https://github.com/BoevaLab/FREEC) is a tool for detection of copy-number changes and allelic imbalances (including LOH) using deep-sequencing data. Control-FREEC automatically computes, normalizes, segments copy number and beta allele frequency profiles, then calls copy number alterations and LOH. @@ -318,16 +397,16 @@ For further reading and documentation see the [Control-FREEC manual](http://boev For a Tumor/Normal pair only: **Output directory: `results/VariantCalling/[TUMOR_vs_NORMAL]/ControlFREEC`** -* `[TUMORSAMPLE]_vs_[NORMALSAMPLE].config.txt` - * Configuration file used to run Control-FREEC -* `[TUMORSAMPLE].pileup.gz_CNVs` and `[TUMORSAMPLE].pileup.gz_normal_CNVs` - * file with coordinates of predicted copy number alterations -* `[TUMORSAMPLE].pileup.gz_ratio.txt` and `[TUMORSAMPLE].pileup.gz_normal_ratio.txt` - * file with ratios and predicted copy number alterations for each window -* `[TUMORSAMPLE].pileup.gz_BAF.txt` and `[NORMALSAMPLE].pileup.gz_BAF.txt` - * file with beta allele frequencies for each possibly heterozygous SNP position +- `[TUMORSAMPLE]_vs_[NORMALSAMPLE].config.txt` + - Configuration file used to run Control-FREEC +- `[TUMORSAMPLE].pileup.gz_CNVs` and `[TUMORSAMPLE].pileup.gz_normal_CNVs` + - file with coordinates of predicted copy number alterations +- `[TUMORSAMPLE].pileup.gz_ratio.txt` and `[TUMORSAMPLE].pileup.gz_normal_ratio.txt` + - file with ratios and predicted copy number alterations for each window +- `[TUMORSAMPLE].pileup.gz_BAF.txt` and `[NORMALSAMPLE].pileup.gz_BAF.txt` + - file with beta allele frequencies for each possibly heterozygous SNP position -## Annotation +## Variant annotation This directory contains results from the final annotation steps: two software are used for annotation, [snpEff](http://snpeff.sourceforge.net/) and [VEP](https://www.ensembl.org/info/docs/tools/vep/index.html). Only a subset of the VCF files are annotated, and only variants that have a PASS filter. @@ -345,8 +424,8 @@ For further reading and documentation see the [snpEff manual](http://snpeff.sour For all samples: **Output directory: `results/Annotation/[SAMPLE]/snpEff`** -* `VariantCaller_Sample_snpEff.ann.vcf.gz` and `VariantCaller_Sample_snpEff.ann.vcf.gz.tbi` - * VCF with Tabix index +- `VariantCaller_Sample_snpEff.ann.vcf.gz` and `VariantCaller_Sample_snpEff.ann.vcf.gz.tbi` + - VCF with Tabix index ### VEP @@ -355,29 +434,31 @@ The generated VCF header contains the software version, also the version numbers The format of the [consequence annotations](https://www.ensembl.org/info/genome/variation/prediction/predicted_data.html) is also in the VCF header describing the INFO field. In the moment it contains: -* Consequence: impact of the variation, if there is any -* Codons: the codon change, i.e. cGt/cAt -* Amino_acids: change in amino acids, i.e. R/H if there is any -* Gene: ENSEMBL gene name -* SYMBOL: gene symbol -* Feature: actual transcript name -* EXON: affected exon -* PolyPhen: prediction based on [PolyPhen](http://genetics.bwh.harvard.edu/pph2/) -* SIFT: prediction by [SIFT](http://sift.bii.a-star.edu.sg/) -* Protein_position: Relative position of amino acid in protein -* BIOTYPE: Biotype of transcript or regulatory feature +- Consequence: impact of the variation, if there is any +- Codons: the codon change, i.e. cGt/cAt +- Amino_acids: change in amino acids, i.e. R/H if there is any +- Gene: ENSEMBL gene name +- SYMBOL: gene symbol +- Feature: actual transcript name +- EXON: affected exon +- PolyPhen: prediction based on [PolyPhen](http://genetics.bwh.harvard.edu/pph2/) +- SIFT: prediction by [SIFT](http://sift.bii.a-star.edu.sg/) +- Protein_position: Relative position of amino acid in protein +- BIOTYPE: Biotype of transcript or regulatory feature For further reading and documentation see the [VEP manual](https://www.ensembl.org/info/docs/tools/vep/index.html) For all samples: **Output directory: `results/Annotation/[SAMPLE]/VEP`** -* `VariantCaller_Sample_VEP.ann.vcf.gz` and `VariantCaller_Sample_VEP.ann.vcf.gz.tbi` - * VCF with Tabix index +- `VariantCaller_Sample_VEP.ann.vcf.gz` and `VariantCaller_Sample_VEP.ann.vcf.gz.tbi` + - VCF with Tabix index ## QC and reporting -### FastQC +### QC + +#### FastQC [FastQC](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/) gives general quality metrics about your reads. It provides information about the quality score distribution across your reads, the per base sequence content (%T/A/G/C). @@ -388,28 +469,28 @@ For further reading and documentation see the [FastQC help](http://www.bioinform For all samples: **Output directory: `results/Reports/[SAMPLE]/fastqc`** -* `sample_R1_XXX_fastqc.html` and `sample_R2_XXX_fastqc.html` - * FastQC report, containing quality metrics for each pair of the raw fastq files -* `sample_R1_XXX_fastqc.zip` and `sample_R2_XXX_fastqc.zip` - * zip file containing the FastQC reports, tab-delimited data files and plot images +- `sample_R1_XXX_fastqc.html` and `sample_R2_XXX_fastqc.html` + - FastQC report, containing quality metrics for each pair of the raw fastq files +- `sample_R1_XXX_fastqc.zip` and `sample_R2_XXX_fastqc.zip` + - zip file containing the FastQC reports, tab-delimited data files and plot images -### bamQC +#### bamQC [Qualimap bamqc](http://qualimap.bioinfo.cipf.es/) reports information for the evaluation of the quality of the provided alignment data. In short, the basic statistics of the alignment (number of reads, coverage, GC-content, etc.) are summarized and a number of useful graphs are produced. Plot will show: -* Stats by non-reference allele frequency, depth distribution, stats by quality and per-sample counts, singleton stats, etc. +- Stats by non-reference allele frequency, depth distribution, stats by quality and per-sample counts, singleton stats, etc. For all samples: **Output directory: `results/Reports/[SAMPLE]/bamQC`** -* `VariantCaller_[SAMPLE].bcf.tools.stats.out` - * RAW statistics used by MultiQC +- `VariantCaller_[SAMPLE].bcf.tools.stats.out` + - RAW statistics used by MultiQC For more information about how to use Qualimap bamqc reports, see [Qualimap bamqc manual](http://qualimap.bioinfo.cipf.es/doc_html/analysis.html#id7) -### MarkDuplicates reports +#### MarkDuplicates reports [GATK MarkDuplicates](https://github.com/broadinstitute/gatk) locates and tags duplicate reads in a BAM or SAM file, where duplicate reads are defined as originating from a single fragment of DNA. Duplicates can arise during sample preparation e.g. @@ -420,99 +501,101 @@ These duplication artifacts are referred to as optical duplicates. For all samples: **Output directory: `results/Reports/[SAMPLE]/MarkDuplicates`** -* `[SAMPLE].bam.metrics` - * RAW statistics used by MultiQC +- `[SAMPLE].bam.metrics` + - RAW statistics used by MultiQC For further reading and documentation see the [MarkDuplicates manual](https://software.broadinstitute.org/gatk/documentation/tooldocs/4.1.2.0/picard_sam_markduplicates_MarkDuplicates.php). -### samtools stats +#### samtools stats [samtools stats](https://www.htslib.org/doc/samtools.html) collects statistics from BAM files and outputs in a text format. Plots will show: -* Alignment metrics. +- Alignment metrics. For all samples: **Output directory: `results/Reports/[SAMPLE]/SamToolsStats`** -* `[SAMPLE].bam.samtools.stats.out` - * RAW statistics used by MultiQC +- `[SAMPLE].bam.samtools.stats.out` + - RAW statistics used by MultiQC For further reading and documentation see the [samtools manual](https://www.htslib.org/doc/samtools.html#COMMANDS_AND_OPTIONS) -### bcftools stats +#### bcftools stats [bcftools](https://samtools.github.io/bcftools/) is a program for variant calling and manipulating files in the Variant Call Format. Plot will show: -* Stats by non-reference allele frequency, depth distribution, stats by quality and per-sample counts, singleton stats, etc. +- Stats by non-reference allele frequency, depth distribution, stats by quality and per-sample counts, singleton stats, etc. For all samples: **Output directory: `results/Reports/[SAMPLE]/BCFToolsStats`** -* `VariantCaller_[SAMPLE].bcf.tools.stats.out` - * RAW statistics used by MultiQC +- `VariantCaller_[SAMPLE].bcf.tools.stats.out` + - RAW statistics used by MultiQC For further reading and documentation see the [bcftools stats manual](https://samtools.github.io/bcftools/bcftools.html#stats) -### VCFtools +#### VCFtools [VCFtools](https://vcftools.github.io/) is a program package designed for working with VCF files. Plots will show: -* the summary counts of each type of transition to transversion ratio for each FILTER category. -* the transition to transversion ratio as a function of alternative allele count (using only bi-allelic SNPs). -* the transition to transversion ratio as a function of SNP quality threshold (using only bi-allelic SNPs). +- the summary counts of each type of transition to transversion ratio for each FILTER category. +- the transition to transversion ratio as a function of alternative allele count (using only bi-allelic SNPs). +- the transition to transversion ratio as a function of SNP quality threshold (using only bi-allelic SNPs). For all samples: **Output directory: `results/Reports/[SAMPLE]/VCFTools`** -* `VariantCaller_[SAMPLE].FILTER.summary` - * RAW statistics used by MultiQC -* `VariantCaller_[SAMPLE].TsTv.count` - * RAW statistics used by MultiQC -* `VariantCaller_[SAMPLE].TsTv.qual` - * RAW statistics used by MultiQC +- `VariantCaller_[SAMPLE].FILTER.summary` + - RAW statistics used by MultiQC +- `VariantCaller_[SAMPLE].TsTv.count` + - RAW statistics used by MultiQC +- `VariantCaller_[SAMPLE].TsTv.qual` + - RAW statistics used by MultiQC For further reading and documentation see the [VCFtools manual](https://vcftools.github.io/man_latest.html#OUTPUT%20OPTIONS) -### snpEff reports +#### snpEff reports [snpeff](http://snpeff.sourceforge.net/) is a genetic variant annotation and effect prediction toolbox. It annotates and predicts the effects of variants on genes (such as amino acid changes) using multiple databases for annotations. Plots will shows : -* locations of detected variants in the genome and the number of variants for each location. -* the putative impact of detected variants and the number of variants for each impact. -* the effect of variants at protein level and the number of variants for each effect type. -* the quantity as function of the variant quality score. +- locations of detected variants in the genome and the number of variants for each location. +- the putative impact of detected variants and the number of variants for each impact. +- the effect of variants at protein level and the number of variants for each effect type. +- the quantity as function of the variant quality score. For all samples: **Output directory: `results/Reports/[SAMPLE]/snpEff`** -* `VariantCaller_Sample_snpEff.csv` - * RAW statistics used by MultiQC -* `VariantCaller_Sample_snpEff.html` - * Statistics to be visualised with a web browser -* `VariantCaller_Sample_snpEff.txt` - * TXT (tab separated) summary counts for variants affecting each transcript and gene +- `VariantCaller_Sample_snpEff.csv` + - RAW statistics used by MultiQC +- `VariantCaller_Sample_snpEff.html` + - Statistics to be visualised with a web browser +- `VariantCaller_Sample_snpEff.txt` + - TXT (tab separated) summary counts for variants affecting each transcript and gene For further reading and documentation see the [snpEff manual](http://snpeff.sourceforge.net/SnpEff_manual.html#outputSummary) -### VEP reports +#### VEP reports [VEP (Variant Effect Predictor)](https://www.ensembl.org/info/docs/tools/vep/index.html), based on Ensembl, is a tools to determine the effects of all sorts of variants, including SNPs, indels, structural variants, CNVs. For all samples: **Output directory: `results/Reports/[SAMPLE]/VEP`** -* `VariantCaller_Sample_VEP.summary.html` - * Summary of the VEP run to be visualised with a web browser +- `VariantCaller_Sample_VEP.summary.html` + - Summary of the VEP run to be visualised with a web browser For further reading and documentation see the [VEP manual](https://www.ensembl.org/info/docs/tools/vep/index.html) -### MultiQC +### Reporting + +#### MultiQC [MultiQC](http://multiqc.info) is a visualisation tool that generates a single HTML report summarising all samples in your project. Most of the pipeline QC results are visualised in the report and further statistics are available in within the report data directory. @@ -522,9 +605,9 @@ The pipeline has special steps which allow the software versions used to be repo For the whole Sarek run: **Output directory: `results/Reports/MultiQC`** -* `multiqc_report.html` - * MultiQC report - a standalone HTML file that can be viewed in your web browser -* `multiqc_data/` - * Directory containing parsed statistics from the different tools used in the pipeline +- `multiqc_report.html` + - MultiQC report - a standalone HTML file that can be viewed in your web browser +- `multiqc_data/` + - Directory containing parsed statistics from the different tools used in the pipeline For further reading and documentation see the [MultiQC website](http://multiqc.info) diff --git a/docs/usage.md b/docs/usage.md index b5f5d45691..1d74294890 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -1,77 +1,73 @@ -# nf-core/sarek: Usage - -## Table of contents - - - -* [Table of contents](#table-of-contents) -* [Introduction](#introduction) -* [Running the pipeline](#running-the-pipeline) - * [Updating the pipeline](#updating-the-pipeline) - * [Reproducibility](#reproducibility) -* [Main arguments](#main-arguments) - * [`-profile`](#-profile) - * [`--input`](#--input) - * [`--split_fastq`](#--split_fastq) - * [`--sample`](#--sample) - * [`--sampleDir`](#--sampledir) - * [`--annotateVCF`](#--annotatevcf) - * [`--noGVCF`](#--nogvcf) - * [`--skipQC`](#--skipqc) - * [`--noReports`](#--noreports) - * [`--nucleotidesPerSecond`](#--nucleotidespersecond) - * [`--step`](#--step) - * [`--tools`](#--tools) - * [`--noStrelkaBP`](#--nostrelkabp) - * [`--no_intervals`](#--no_intervals) - * [`--targetBED`](#--targetbed) -* [Reference genomes](#reference-genomes) - * [`--genome` (using iGenomes)](#--genome-using-igenomes) - * [`--acLoci`](#--acloci) - * [`--acLociGC`](#--aclocigc) - * [`--bwaIndex`](#--bwaindex) - * [`--chrDir`](#--chrdir) - * [`--chrLength`](#--chrlength) - * [`--dbsnp`](#--dbsnp) - * [`--dbsnpIndex`](#--dbsnpindex) - * [`--dict`](#--dict) - * [`--fasta`](#--fasta) - * [`--fastaFai`](#--fastafai) - * [`--genomeDict`](#--genomedict) - * [`--genomeFile`](#--genomefile) - * [`--genomeIndex`](#--genomeindex) - * [`--germlineResource`](#--germlineresource) - * [`--germlineResourceIndex`](#--germlineresourceindex) - * [`--intervals`](#--intervals) - * [`--knownIndels`](#--knownindels) - * [`--knownIndelsIndex`](#--knownindelsindex) - * [`--pon`](#--pon) - * [`--snpeffDb`](#--snpeffdb) - * [`--vepCacheVersion`](#--vepcacheversion) - * [`--igenomesIgnore`](#--igenomesignore) - * [`--species`](#--species) -* [Job resources](#job-resources) - * [Automatic resubmission](#automatic-resubmission) - * [Custom resource requests](#custom-resource-requests) -* [AWS Batch specific parameters](#aws-batch-specific-parameters) - * [`--awsqueue`](#--awsqueue) - * [`--awsregion`](#--awsregion) -* [Other command line parameters](#other-command-line-parameters) - * [`--outdir`](#--outdir) - * [`--sequencing_center`](#--sequencing_center) - * [`--email`](#--email) - * [`-name`](#-name) - * [`-resume`](#-resume) - * [`-c`](#-c) - * [`--custom_config_version`](#--custom_config_version) - * [`--custom_config_base`](#--custom_config_base) - * [`--max_memory`](#--max_memory) - * [`--max_time`](#--max_time) - * [`--max_cpus`](#--max_cpus) - * [`--plaintext_email`](#--plaintext_email) - * [`--monochrome_logs`](#--monochrome_logs) - * [`--multiqc_config`](#--multiqc_config) - +# nf-core/sarek: Usage + +- [Introduction](#introduction) +- [Running the pipeline](#running-the-pipeline) + - [Updating the pipeline](#updating-the-pipeline) + - [Reproducibility](#reproducibility) +- [Main arguments](#main-arguments) + - [-profile](#-profile) + - [--input](#--input) + - [--split_fastq](#--split_fastq) + - [--sample](#--sample) + - [--sampleDir](#--sampledir) + - [--annotateVCF](#--annotatevcf) + - [--noGVCF](#--nogvcf) + - [--skipQC](#--skipqc) + - [--noReports](#--noreports) + - [--nucleotidesPerSecond](#--nucleotidespersecond) + - [--step](#--step) + - [--tools](#--tools) + - [--sentieon](#--sentieon) + - [--noStrelkaBP](#--nostrelkabp) + - [--no_intervals](#--no_intervals) + - [--targetBED](#--targetbed) +- [Reference genomes](#reference-genomes) + - [--genome (using iGenomes)](#--genome-using-igenomes) + - [--acLoci](#--acloci) + - [--acLociGC](#--aclocigc) + - [--bwaIndex](#--bwaindex) + - [--chrDir](#--chrdir) + - [--chrLength](#--chrlength) + - [--dbsnp](#--dbsnp) + - [--dbsnpIndex](#--dbsnpindex) + - [--dict](#--dict) + - [--fasta](#--fasta) + - [--fastaFai](#--fastafai) + - [--genomeDict](#--genomedict) + - [--genomeFile](#--genomefile) + - [--genomeIndex](#--genomeindex) + - [--germlineResource](#--germlineresource) + - [--germlineResourceIndex](#--germlineresourceindex) + - [--intervals](#--intervals) + - [--knownIndels](#--knownindels) + - [--knownIndelsIndex](#--knownindelsindex) + - [--pon](#--pon) + - [--pon_index](#--pon_index) + - [--snpeffDb](#--snpeffdb) + - [--vepCacheVersion](#--vepcacheversion) + - [--igenomesIgnore](#--igenomesignore) + - [--species](#--species) +- [Job resources](#job-resources) + - [Automatic resubmission](#automatic-resubmission) + - [Custom resource requests](#custom-resource-requests) +- [AWS Batch specific parameters](#aws-batch-specific-parameters) + - [--awsqueue](#--awsqueue) + - [--awsregion](#--awsregion) +- [Other command line parameters](#other-command-line-parameters) + - [--outdir](#--outdir) + - [--sequencing_center](#--sequencing_center) + - [--email](#--email) + - [-name](#-name) + - [-resume](#-resume) + - [-c](#-c) + - [--custom_config_version](#--custom_config_version) + - [--custom_config_base](#--custom_config_base) + - [--max_memory](#--max_memory) + - [--max_time](#--max_time) + - [--max_cpus](#--max_cpus) + - [--plaintext_email](#--plaintext_email) + - [--monochrome_logs](#--monochrome_logs) + - [--multiqc_config](#--multiqc_config) ## Introduction @@ -109,8 +105,8 @@ results # Finished results (configurable, see below) The nf-core/sarek pipeline comes with more documentation about running the pipeline, found in the `docs/` directory: -* [Output and how to interpret the results](output.md) -* [Extra Documentation on annotation](annotation.md) +- [Output and how to interpret the results](output.md) +- [Extra Documentation on annotation](annotation.md) ### Updating the pipeline @@ -135,7 +131,7 @@ This version number will be logged in reports when you run the pipeline, so that ## Main arguments -### `-profile` +### -profile Use this parameter to choose a configuration profile. Profiles can give configuration presets for different compute environments. @@ -143,22 +139,22 @@ Note that multiple profiles can be loaded, for example: `-profile docker` - the If `-profile` is not specified at all the pipeline will be run locally and expects all software to be installed and available on the `PATH`. -* `awsbatch` - * A generic configuration profile to be used with AWS Batch. -* `conda` - * A generic configuration profile to be used with [conda](https://conda.io/docs/) - * Pulls most software from [Bioconda](https://bioconda.github.io/) -* `docker` - * A generic configuration profile to be used with [Docker](http://docker.com/) - * Pulls software from dockerhub: [`nfcore/sarek`](http://hub.docker.com/r/nfcore/sarek/) -* `singularity` - * A generic configuration profile to be used with [Singularity](http://singularity.lbl.gov/) - * Pulls software from DockerHub: [`nfcore/sarek`](http://hub.docker.com/r/nfcore/sarek/) -* `test` - * A profile with a complete configuration for automated testing - * Includes links to test data so needs no other parameters - -### `--input` +- `awsbatch` + - A generic configuration profile to be used with AWS Batch. +- `conda` + - A generic configuration profile to be used with [conda](https://conda.io/docs/) + - Pulls most software from [Bioconda](https://bioconda.github.io/) +- `docker` + - A generic configuration profile to be used with [Docker](http://docker.com/) + - Pulls software from dockerhub: [`nfcore/sarek`](http://hub.docker.com/r/nfcore/sarek/) +- `singularity` + - A generic configuration profile to be used with [Singularity](http://singularity.lbl.gov/) + - Pulls software from DockerHub: [`nfcore/sarek`](http://hub.docker.com/r/nfcore/sarek/) +- `test` + - A profile with a complete configuration for automated testing + - Includes links to test data so needs no other parameters + +### --input Use this to specify the location of your input TSV file, on `mapping`, `recalibrate` and `variantcalling` steps. For example: @@ -185,7 +181,7 @@ For example: Multiple VCF files can be specified if the path must be enclosed in quotes -### `--split_fastq` +### --split_fastq Use the Nextflow [`splitFastq`](https://www.nextflow.io/docs/latest/operator.html#splitfastq) operator to specify how many reads should be contained in the split fastq file. For example: @@ -194,7 +190,7 @@ For example: --split_fastq 10000 ``` -### `--sample` +### --sample > :warning: This params is deprecated -- it will be removed in a future release. > Please check: [`--input`](#--input) @@ -224,7 +220,7 @@ For example: Multiple VCF files can be specified if the path must be enclosed in quotes -### `--sampleDir` +### --sampleDir > :warning: This params is deprecated -- it will be removed in a future release. > Please check: [`--input`](#--input) @@ -236,7 +232,7 @@ For example: --sampleDir PathToDirectory ``` -### `--annotateVCF` +### --annotateVCF > :warning: This params is deprecated -- it will be removed in a future release. > Please check: [`--input`](#--input) @@ -250,47 +246,56 @@ For example: Multiple VCF files can be specified if the path must be enclosed in quotes -### `--noGVCF` +### --noGVCF Use this to disable g.vcf from `HaplotypeCaller`. -### `--skipQC` +### --skipQC Use this to disable specific QC and Reporting tools. Available: `all`, `bamQC`, `BCFtools`, `FastQC`, `MultiQC`, `samtools`, `vcftools`, `versions` Default: `None` -### `--noReports` +### --noReports > :warning: This params is deprecated -- it will be removed in a future release. > Please check: [`--skipQC`](#--skipQC) Use this to disable all QC and Reporting tools. -### `--nucleotidesPerSecond` +### --nucleotidesPerSecond Use this to estimate of how many seconds it will take to call variants on any interval, the default value is `1000` is it's not specified in the `.bed` file. -### `--step` +### --step Use this to specify the starting step: Default `mapping` Available: `mapping`, `recalibrate`, `variantcalling` and `annotate` -### `--tools` +### --tools Use this to specify the tools to run: Available: `ASCAT`, `ControlFREEC`, `FreeBayes`, `HaplotypeCaller`, `Manta`, `mpileup`, `Mutect2`, `Strelka`, `TIDDIT` -### `--noStrelkaBP` +### --sentieon + +If [Sentieon](https://www.sentieon.com/) is available, use this to enable it for preprocessing, and variant calling. +Adds the following tools for the [`--tools`](#--tools) options: `DNAseq`, `DNAscope` and `TNscope`. + +Please refer to the [nf-core/configs](https://github.com/nf-core/configs#adding-a-new-pipeline-specific-config) repository on how to make a pipeline-specific configuration file based on the [munin-sarek specific configuration file](https://github.com/nf-core/configs/blob/master/conf/pipeline/sarek/munin.config). + +Or ask us on the [nf-core Slack](http://nf-co.re/join/slack) on the following channels: [#sarek](https://nfcore.slack.com/channels/sarek) [#configs](https://nfcore.slack.com/channels/configs). + +### --noStrelkaBP Use this not to use `Manta` `candidateSmallIndels` for `Strelka` as Best Practice. -### `--no_intervals_` +### --no_intervals Disable usage of intervals file, and disable automatic generation of intervals file when none are provided. -### `--targetBED` +### --targetBED Use this to specify the target BED file for targeted or whole exome sequencing. @@ -299,7 +304,7 @@ Use this to specify the target BED file for targeted or whole exome sequencing. The pipeline config files come bundled with paths to the Illumina iGenomes reference index files. If running with docker or AWS, the configuration is set up to use the [AWS-iGenomes](https://ewels.github.io/AWS-iGenomes/) resource. -### `--genome` (using iGenomes) +### --genome (using iGenomes) There are 2 different species supported by Sarek in the iGenomes references. To run the pipeline, you must specify which to use with the `--genome` flag. @@ -307,92 +312,92 @@ To run the pipeline, you must specify which to use with the `--genome` flag. You can find the keys to specify the genomes in the [iGenomes config file](../conf/igenomes.config). Genomes that are supported are: -* Homo sapiens - * `--genome GRCh37` (GATK Bundle) - * `--genome GRCh38` (GATK Bundle) +- Homo sapiens + - `--genome GRCh37` (GATK Bundle) + - `--genome GRCh38` (GATK Bundle) -* Mus musculus - * `--genome GRCm38` (Ensembl) +- Mus musculus + - `--genome GRCm38` (Ensembl) Limited support for: -* Arabidopsis thaliana - * `--genome TAIR10` (Ensembl) +- Arabidopsis thaliana + - `--genome TAIR10` (Ensembl) -* Bacillus subtilis 168 - * `--genome EB2` (Ensembl) +- Bacillus subtilis 168 + - `--genome EB2` (Ensembl) -* Bos taurus - * `--genome UMD3.1` (Ensembl) - * `--genome bosTau8` (UCSC) +- Bos taurus + - `--genome UMD3.1` (Ensembl) + - `--genome bosTau8` (UCSC) -* Caenorhabditis elegans - * `--genome WBcel235` (Ensembl) - * `--genome ce10` (UCSC) +- Caenorhabditis elegans + - `--genome WBcel235` (Ensembl) + - `--genome ce10` (UCSC) -* Canis familiaris - * `--genome CanFam3.1` (Ensembl) - * `--genome canFam3` (UCSC) +- Canis familiaris + - `--genome CanFam3.1` (Ensembl) + - `--genome canFam3` (UCSC) -* Danio rerio - * `--genome GRCz10` (Ensembl) - * `--genome danRer10` (UCSC) +- Danio rerio + - `--genome GRCz10` (Ensembl) + - `--genome danRer10` (UCSC) -* Drosophila melanogaster - * `--genome BDGP6` (Ensembl) - * `--genome dm6` (UCSC) +- Drosophila melanogaster + - `--genome BDGP6` (Ensembl) + - `--genome dm6` (UCSC) -* Equus caballus - * `--genome EquCab2` (Ensembl) - * `--genome equCab2` (UCSC) +- Equus caballus + - `--genome EquCab2` (Ensembl) + - `--genome equCab2` (UCSC) -* Escherichia coli K 12 DH10B - * `--genome EB1` (Ensembl) +- Escherichia coli K 12 DH10B + - `--genome EB1` (Ensembl) -* Gallus gallus - * `--genome Galgal4` (Ensembl) - * `--genome galgal4` (UCSC) +- Gallus gallus + - `--genome Galgal4` (Ensembl) + - `--genome galgal4` (UCSC) -* Glycine max - * `--genome Gm01` (Ensembl) +- Glycine max + - `--genome Gm01` (Ensembl) -* Homo sapiens - * `--genome hg19` (UCSC) - * `--genome hg38` (UCSC) +- Homo sapiens + - `--genome hg19` (UCSC) + - `--genome hg38` (UCSC) -* Macaca mulatta - * `--genome Mmul_1` (Ensembl) +- Macaca mulatta + - `--genome Mmul_1` (Ensembl) -* Mus musculus - * `--genome mm10` (Ensembl) +- Mus musculus + - `--genome mm10` (Ensembl) -* Oryza sativa japonica - * `--genome IRGSP-1.0` (Ensembl) +- Oryza sativa japonica + - `--genome IRGSP-1.0` (Ensembl) -* Pan troglodytes - * `--genome CHIMP2.1.4` (Ensembl) - * `--genome panTro4` (UCSC) +- Pan troglodytes + - `--genome CHIMP2.1.4` (Ensembl) + - `--genome panTro4` (UCSC) -* Rattus norvegicus - * `--genome Rnor_6.0` (Ensembl) - * `--genome rn6` (UCSC) +- Rattus norvegicus + - `--genome Rnor_6.0` (Ensembl) + - `--genome rn6` (UCSC) -* Saccharomyces cerevisiae - * `--genome R64-1-1` (Ensembl) - * `--genome sacCer3` (UCSC) +- Saccharomyces cerevisiae + - `--genome R64-1-1` (Ensembl) + - `--genome sacCer3` (UCSC) -* Schizosaccharomyces pombe - * `--genome EF2` (Ensembl) +- Schizosaccharomyces pombe + - `--genome EF2` (Ensembl) -* Sorghum bicolor - * `--genome Sbi1` (Ensembl) +- Sorghum bicolor + - `--genome Sbi1` (Ensembl) -* Sus scrofa - * `--genome Sscrofa10.2` (Ensembl) - * `--genome susScr3` (UCSC) +- Sus scrofa + - `--genome Sscrofa10.2` (Ensembl) + - `--genome susScr3` (UCSC) -* Zea mays - * `--genome AGPv3` (Ensembl) +- Zea mays + - `--genome AGPv3` (Ensembl) Note that you can use the same configuration setup to save sets of reference files for your own use, even if they are not part of the iGenomes resource. See the [Nextflow documentation](https://www.nextflow.io/docs/latest/config.html) for instructions on where to save such a file. @@ -422,7 +427,7 @@ params { } ``` -### `--acLoci` +### --acLoci If you prefer, you can specify the full path to your reference genome when you run the pipeline: @@ -430,7 +435,7 @@ If you prefer, you can specify the full path to your reference genome when you r --acLoci '[path to the acLoci file]' ``` -### `--acLociGC` +### --acLociGC If you prefer, you can specify the full path to your reference genome when you run the pipeline: @@ -438,7 +443,7 @@ If you prefer, you can specify the full path to your reference genome when you r --acLociGC '[path to the acLociGC file]' ``` -### `--bwaIndex` +### --bwaIndex If you prefer, you can specify the full path to your reference genome when you run the pipeline: @@ -446,7 +451,7 @@ If you prefer, you can specify the full path to your reference genome when you r --bwaIndex '[path to the bwa indexes]' ``` -### `--chrDir` +### --chrDir If you prefer, you can specify the full path to your reference genome when you run the pipeline: @@ -454,7 +459,7 @@ If you prefer, you can specify the full path to your reference genome when you r --chrDir '[path to the Chromosomes folder]' ``` -### `--chrLength` +### --chrLength If you prefer, you can specify the full path to your reference genome when you run the pipeline: @@ -462,7 +467,7 @@ If you prefer, you can specify the full path to your reference genome when you r --chrLength '[path to the Chromosomes length file]' ``` -### `--dbsnp` +### --dbsnp If you prefer, you can specify the full path to your reference genome when you run the pipeline: @@ -470,7 +475,7 @@ If you prefer, you can specify the full path to your reference genome when you r --dbsnp '[path to the dbsnp file]' ``` -### `--dbsnpIndex` +### --dbsnpIndex If you prefer, you can specify the full path to your reference genome when you run the pipeline: @@ -478,7 +483,7 @@ If you prefer, you can specify the full path to your reference genome when you r --dbsnpIndex '[path to the dbsnp index]' ``` -### `--dict` +### --dict If you prefer, you can specify the full path to your reference genome when you run the pipeline: @@ -486,7 +491,7 @@ If you prefer, you can specify the full path to your reference genome when you r --dict '[path to the dict file]' ``` -### `--fasta` +### --fasta If you prefer, you can specify the full path to your reference genome when you run the pipeline: @@ -494,7 +499,7 @@ If you prefer, you can specify the full path to your reference genome when you r --fasta '[path to the reference fasta file]' ``` -### `--fastaFai` +### --fastaFai If you prefer, you can specify the full path to your reference genome when you run the pipeline: @@ -502,7 +507,7 @@ If you prefer, you can specify the full path to your reference genome when you r --fastaFai '[path to the reference index]' ``` -### `--genomeDict` +### --genomeDict > :warning: This params is deprecated -- it will be removed in a future release. > Please check: [`--dict`](#--dict) @@ -513,7 +518,7 @@ If you prefer, you can specify the full path to your reference genome when you r --dict '[path to the dict file]' ``` -### `--genomeFile` +### --genomeFile > :warning: This params is deprecated -- it will be removed in a future release. > Please check: [`--fasta`](#--fasta) @@ -524,7 +529,7 @@ If you prefer, you can specify the full path to your reference genome when you r --fasta '[path to the reference fasta file]' ``` -### `--genomeIndex` +### --genomeIndex > :warning: This params is deprecated -- it will be removed in a future release. > Please check: [`--fastaFai`](#--fastaFai) @@ -535,7 +540,7 @@ If you prefer, you can specify the full path to your reference genome when you r --fastaFai '[path to the reference index]' ``` -### `--germlineResource` +### --germlineResource The [germline resource VCF file](https://software.broadinstitute.org/gatk/documentation/tooldocs/current/org_broadinstitute_hellbender_tools_walkers_mutect_Mutect2.php#--germline-resource) (bgzipped and tabixed) needed by GATK4 Mutect2 is a collection of calls that are likely present in the sample, with allele frequencies. The AF info field must be present. @@ -546,7 +551,7 @@ To add your own germline resource supply --germlineResource '[path to my resource.vcf.gz]' ``` -### `--germlineResourceIndex` +### --germlineResourceIndex Tabix index of the germline resource specified at [`--germlineResource`](#--germlineResource). To add your own germline resource supply @@ -555,7 +560,7 @@ To add your own germline resource supply --germlineResourceIndex '[path to my resource.vcf.gz.idx]' ``` -### `--intervals` +### --intervals If you prefer, you can specify the full path to your reference genome when you run the pipeline: @@ -563,7 +568,7 @@ If you prefer, you can specify the full path to your reference genome when you r --intervals '[path to the intervals file]' ``` -### `--knownIndels` +### --knownIndels If you prefer, you can specify the full path to your reference genome when you run the pipeline: @@ -571,7 +576,7 @@ If you prefer, you can specify the full path to your reference genome when you r --knownIndels '[path to the knownIndels file]' ``` -### `--knownIndelsIndex` +### --knownIndelsIndex If you prefer, you can specify the full path to your reference genome when you run the pipeline: @@ -579,7 +584,7 @@ If you prefer, you can specify the full path to your reference genome when you r --knownIndelsIndex '[path to the knownIndels index]' ``` -### `--pon` +### --pon When a panel of normals [PON](https://gatkforums.broadinstitute.org/gatk/discussion/24057/how-to-call-somatic-mutations-using-gatk4-mutect2#latest) is defined, you will get filtered somatic calls as a result. Without PON, there will be no calls with PASS in the INFO field, only an _unfiltered_ VCF is written. @@ -593,7 +598,11 @@ Provide your PON by: If the PON file is bgzipped, there has to be a tabixed index file at the same directory. -### `--snpeffDb` +### --pon_index + +Tabix index of the panel-of-normals bgzipped VCF file. + +### --snpeffDb If you prefer, you can specify the DB version when you run the pipeline: @@ -601,7 +610,7 @@ If you prefer, you can specify the DB version when you run the pipeline: --snpeffDb '[version of the snpEff DB]' ``` -### `--vepCacheVersion` +### --vepCacheVersion If you prefer, you can specify the cache version when you run the pipeline: @@ -609,12 +618,12 @@ If you prefer, you can specify the cache version when you run the pipeline: --vepCacheVersion '[version of the VEP cache]' ``` -### `--igenomesIgnore` +### --igenomesIgnore Do not load `igenomes.config` when running the pipeline. You may choose this option if you observe clashes between custom parameters and those supplied in `igenomes.config`. -### `--species` +### --species This specifies the species used for running VEP annotation. For human data, this needs to be set to `homo_sapiens`, for mouse data `mus_musculus` as the annotation needs to know where to look for appropriate annotation references. If you use iGenomes or a local resource with `genomes.conf`, this has already been set for you appropriately. @@ -642,11 +651,11 @@ If you have any questions or issues please send us a message on [Slack](https:// Running the pipeline on AWS Batch requires a couple of specific parameters to be set according to your AWS Batch configuration. Please use the `-awsbatch` profile and then specify all of the following parameters. -### `--awsqueue` +### --awsqueue The JobQueue that you intend to use on AWS Batch. -### `--awsregion` +### --awsregion The AWS region to run your job in. Default is set to `eu-west-1` but can be adjusted to your needs. @@ -655,21 +664,21 @@ Please make sure to also set the `-w/--work-dir` and `--outdir` parameters to a ## Other command line parameters -### `--outdir` +### --outdir The output directory where the results will be saved. Default: `results/ -### `--sequencing_center` +### --sequencing_center The sequencing center that will be used in the BAM CN field -### `--email` +### --email 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. -### `-name` +### -name Name for the pipeline run. If not specified, Nextflow will automatically generate a random mnemonic. @@ -678,7 +687,7 @@ This is used in the MultiQC report (if not default) and in the summary HTML / e- **NB:** Single hyphen (core Nextflow option) -### `-resume` +### -resume Specify this when restarting a pipeline. Nextflow will used cached results from any pipeline steps where the inputs are the same, continuing from where it got to previously. @@ -688,7 +697,7 @@ Use the `nextflow log` command to show previous run names. **NB:** Single hyphen (core Nextflow option) -### `-c` +### -c Specify the path to a specific config file (this is a core NextFlow command). @@ -696,7 +705,7 @@ Specify the path to a specific config file (this is a core NextFlow command). Note - you can use this to override pipeline defaults. -### `--custom_config_version` +### --custom_config_version Provide git commit id for custom Institutional configs hosted at `nf-core/configs`. This was implemented for reproducibility purposes. @@ -707,7 +716,7 @@ Default is set to `master`. --custom_config_version d52db660777c4bf36546ddb188ec530c3ada1b96 ``` -### `--custom_config_base` +### --custom_config_base If you're running offline, nextflow will not be able to fetch the institutional config files from the internet. @@ -729,29 +738,29 @@ nextflow run /path/to/pipeline/ --custom_config_base /path/to/my/configs/configs > Note that the nf-core/tools helper package has a `download` command to download all required pipeline > files + singularity containers + institutional configs in one go for you, to make this process easier. -### `--max_memory` +### --max_memory Use to set a top-limit for the default memory requirement for each process. Should be a string in the format integer-unit eg. `--max_memory '8.GB'` -### `--max_time` +### --max_time Use to set a top-limit for the default time requirement for each process. Should be a string in the format integer-unit eg. `--max_time '2.h'` -### `--max_cpus` +### --max_cpus Use to set a top-limit for the default CPU requirement for each process. Should be a string in the format integer-unit eg. `--max_cpus 1` -### `--plaintext_email` +### --plaintext_email Set to receive plain-text e-mails instead of HTML formatted. -### `--monochrome_logs` +### --monochrome_logs Set to disable colourful command line output and live life in monochrome. -### `--multiqc_config` +### --multiqc_config Specify a path to a custom MultiQC configuration file. diff --git a/main.nf b/main.nf index 1265c244f8..2ef926a2cb 100644 --- a/main.nf +++ b/main.nf @@ -35,9 +35,9 @@ def helpMessage() { Works also with the path to a directory on mapping step with a single germline sample only Alternatively, path to VCF input file on annotate step Multiple VCF files can be specified with quotes - - -profile Configuration profile to use. Can use multiple (comma separated) - Available: conda, docker, singularity, awsbatch, test and more. + -profile Configuration profile to use + Can use multiple (comma separated) + Available: conda, docker, singularity, test and more Options: --genome Name of iGenomes reference @@ -62,6 +62,8 @@ def helpMessage() { --annotateTools Specify from which tools Sarek will look for VCF files to annotate, only for step annotate Available: HaplotypeCaller, Manta, Mutect2, Strelka, TIDDIT Default: None + --sentieon If sentieon is available, will enable it for preprocessing, and variant calling + Adds the following tools for --tools: DNAseq, DNAscope and TNscope --annotation_cache Enable the use of cache for annotation, to be used with --snpEff_cache and/or --vep_cache --snpEff_cache Specity the path to snpEff cache, to be used with --annotation_cache --vep_cache Specity the path to VEP cache, to be used with --annotation_cache @@ -1538,8 +1540,6 @@ process SentieonDNAseq { tag {idSample} - publishDir "${params.outdir}/VariantCalling/${idSample}/SentieonDNAseq", mode: params.publishDirMode - input: set idPatient, idSample, file(bam), file(bai) from bamSentieonDNAseq file(dbsnp) from ch_dbsnp @@ -1575,8 +1575,6 @@ process SentieonDNAscope { tag {idSample} - publishDir "${params.outdir}/VariantCalling/${idSample}/SentieonDNAscope", mode: params.publishDirMode - input: set idPatient, idSample, file(bam), file(bai) from bamSentieonDNAscope file(dbsnp) from ch_dbsnp @@ -2098,8 +2096,6 @@ process SentieonTNscope { tag {idSampleTumor + "_vs_" + idSampleNormal} - publishDir "${params.outdir}/VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/SentieonTNscope", mode: params.publishDirMode - input: set idPatient, idSampleNormal, file(bamNormal), file(baiNormal), idSampleTumor, file(bamTumor), file(baiTumor) from pairBamTNscope file(dict) from ch_dict @@ -2128,7 +2124,7 @@ process SentieonTNscope { --normal_sample ${idSampleNormal} \ --dbsnp ${dbsnp} \ ${PON} \ - SentieonTNscope_${idSampleTumor}_vs_${idSampleNormal}.vcf + TNscope_${idSampleTumor}_vs_${idSampleNormal}.vcf """ } From c75a95b861fb9b40f8cf4158335b9d04f5640350 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 10 Dec 2019 13:01:34 +0100 Subject: [PATCH 299/854] add warning for sentieon only processes --- docs/output.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/output.md b/docs/output.md index 3c62b97abb..4d4813dbc3 100644 --- a/docs/output.md +++ b/docs/output.md @@ -119,6 +119,16 @@ For all samples: - `duplicateMarked_[SAMPLE].tsv` and `recalibrated_[SAMPLE].tsv` - TSV files to start Sarek from `recalibration` or `variantcalling` steps for a specific sample. +> :warning: Only with [`--sentieon`](usage.md#--sentieon) + +For all samples: +**Output directory: `results/Preprocessing/TSV`** + +- `recalibrated_sentieon.tsv` + - TSV files to start Sarek from `variantcalling` step. +- `recalibrated_sentieon_[SAMPLE].tsv` + - TSV files to start Sarek from `variantcalling` step for a specific sample. + ## Variant Calling All the results regarding Variant Calling are collected in this directory. @@ -232,6 +242,8 @@ Using [Strelka Best Practices](https://github.com/Illumina/strelka/blob/v2.9.x/d #### Sentieon DNAseq +> :warning: Only with [`--sentieon`](usage.md#--sentieon) + [Sentieon DNAseq](https://www.sentieon.com/products/#dnaseq) implements the same mathematics used in the Broad Institute’s BWA-GATK HaplotypeCaller 3.3-4.1 Best Practices Workflow pipeline. For further reading and documentation see the [Sentieon DNAseq user guide](https://support.sentieon.com/manual/DNAseq_usage/dnaseq/). @@ -244,6 +256,8 @@ For all samples: #### Sentieon DNAscope +> :warning: Only with [`--sentieon`](usage.md#--sentieon) + [Sentieon DNAscope](https://www.sentieon.com/products) calls SNPs and small indels. For further reading and documentation see the [Sentieon DNAscope user guide](https://support.sentieon.com/manual/DNAscope_usage/dnascope/). @@ -256,6 +270,8 @@ For all samples: #### Sentieon TNscope +> :warning: Only with [`--sentieon`](usage.md#--sentieon) + [Sentieon TNscope](https://www.sentieon.com/products/#tnscope) calls SNPs and small indels on an Tumor/Normal pair. For further reading and documentation see the [Sentieon TNscope user guide](https://support.sentieon.com/manual/TNscope_usage/tnscope/). @@ -333,6 +349,8 @@ For all samples: #### Sentieon DNAscope SV +> :warning: Only with [`--sentieon`](usage.md#--sentieon) + [Sentieon DNAscope](https://www.sentieon.com/products) can perform structural variant calling in addition to calling SNPs and small indels. For further reading and documentation see the [Sentieon DNAscope user guide](https://support.sentieon.com/manual/DNAscope_usage/dnascope/). From 5e0d034eaf6868ca0161d989140ad127d8a22aa6 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 10 Dec 2019 15:11:03 +0100 Subject: [PATCH 300/854] add GATK4-spark possibilities --- main.nf | 24 +++++++++++------------- nextflow.config | 1 - 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/main.nf b/main.nf index 6973004aaf..2fb9bb5e1e 100644 --- a/main.nf +++ b/main.nf @@ -822,15 +822,14 @@ process IndexBamFile { // STEP 2: MARKING DUPLICATES -process MarkDuplicates { +process MarkDuplicatesSpark { label 'cpus_16' tag {idPatient + "-" + idSample} publishDir params.outdir, mode: params.publishDirMode, saveAs: { - if (it == "${idSample}.bam.metrics" && 'markduplicates' in skipQC) null - else if (it == "${idSample}.bam.metrics") "Reports/${idSample}/MarkDuplicates/${it}" + if (it == "${idSample}.bam.metrics") "Reports/${idSample}/MarkDuplicates/${it}" else "Preprocessing/${idSample}/DuplicateMarked/${it}" } @@ -838,23 +837,22 @@ process MarkDuplicates { set idPatient, idSample, file("${idSample}.bam") from mergedBam output: - set idPatient, idSample, file("${idSample}.md.bam"), file("${idSample}.md.bai") into duplicateMarkedBams - file ("${idSample}.bam.metrics") into markDuplicatesReport + set idPatient, idSample, file("${idSample}.md.bam"), file("${idSample}.md.bam.bai") into duplicateMarkedBams + file ("${idSample}.bam.metrics") optional true into markDuplicatesReport when: step == 'mapping' && params.knownIndels script: markdup_java_options = task.memory.toGiga() > 8 ? params.markdup_java_options : "\"-Xms" + (task.memory.toGiga() / 2).trunc() + "g -Xmx" + (task.memory.toGiga() - 1) + "g\"" + metrics = 'markduplicates' in skipQC ? '' : "-M ${idSample}.bam.metrics" """ gatk --java-options ${markdup_java_options} \ - MarkDuplicates \ - --MAX_RECORDS_IN_RAM 50000 \ - --INPUT ${idSample}.bam \ - --METRICS_FILE ${idSample}.bam.metrics \ - --TMP_DIR . \ - --ASSUME_SORT_ORDER coordinate \ - --CREATE_INDEX true \ - --OUTPUT ${idSample}.md.bam + MarkDuplicatesSpark \ + -I ${idSample}.bam \ + -O ${idSample}.md.bam \ + ${metrics} \ + --tmp-dir . \ + --create-output-bam-index true """ } diff --git a/nextflow.config b/nextflow.config index 6d4d86ed5f..fde1b6f3b8 100644 --- a/nextflow.config +++ b/nextflow.config @@ -112,7 +112,6 @@ profiles { docker { enabled = true fixOwnership = true - runOptions = "-u \$(id -u):\$(id -g)" } singularity.enabled = false } From 3b29c785f072e70172f2b713b8c654f0cf88737f Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 10 Dec 2019 15:16:58 +0100 Subject: [PATCH 301/854] update docs and containers --- CHANGELOG.md | 3 +++ docs/containers.md | 3 ++- docs/output.md | 6 +++--- environment.yml | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a52ada6b0f..b5e0a50814 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - [#60](https://github.com/nf-core/sarek/pull/60) - Add new minimal genomes (`TAIR10`, `EB2`, `UMD3.1`, `bosTau8`, `WBcel235`, `ce10`, `CanFam3.1`, `canFam3`, `GRCz10`, `danRer10`, `BDGP6`, `dm6`, `EquCab2`, `equCab2`, `EB1`, `Galgal4`, `galGal4`, `Gm01`, `hg38`, `hg19`, `Mmul_1`, `mm10`, `IRGSP-1.0`, `CHIMP2.1.4`, `panTro4`, `Rnor_6.0`, `rn6`, `R64-1-1`, `sacCer3`, `EF2`, `Sbi1`, `Sscrofa10.2`, `susScr3`, `AGPv3`) to `igenomes.config` - [#61](https://github.com/nf-core/sarek/pull/61) - Add params `split_fastq` - [#61](https://github.com/nf-core/sarek/pull/61) - Add test `SPLITFASTQ` +- [#66](https://github.com/nf-core/sarek/pull/66) - Add `Sentieon` possibilities to Sarek +- [#76](https://github.com/nf-core/sarek/pull/76) - Add `GATK Spark` possibilities to Sarek ### `Changed` @@ -38,6 +40,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - [#74](https://github.com/nf-core/sarek/pull/74) - Update docs - [#74](https://github.com/nf-core/sarek/pull/74) - Improve CI tests (both Jenkins and GitHub actions tests) - [#74](https://github.com/nf-core/sarek/pull/74) - Move all ci from `ci-extra.yml` to `ci.yml` +- [#76](https://github.com/nf-core/sarek/pull/76) - Use `MarkDuplicatesSpark` instead of `MarkDuplicates` ### `Removed` diff --git a/docs/containers.md b/docs/containers.md index 6dfd8edae2..96d3c0c2af 100644 --- a/docs/containers.md +++ b/docs/containers.md @@ -21,7 +21,8 @@ For annotation, the main container can be used, but the cache has to be download - Contain **[Control-FREEC](https://github.com/BoevaLab/FREEC)** 11.5 - Contain **[FastQC](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/)** 0.11.8 - Contain **[FreeBayes](https://github.com/ekg/freebayes)** 1.3.1 -- Contain **[GATK4](https://github.com/broadinstitute/gatk)** 4.1.4.0 +- Contain **[GATK4](https://github.com/broadinstitute/gatk)** 4.1.4.1 +- Contain **[GATK4-spark](https://github.com/broadinstitute/gatk)** 4.1.4.1 - Contain **[GeneSplicer](https://ccb.jhu.edu/software/genesplicer/)** 1.0 - Contain **[HTSlib](https://github.com/samtools/htslib)** 1.9 - Contain **[Manta](https://github.com/Illumina/manta)** 1.6.0 diff --git a/docs/output.md b/docs/output.md index 4d4813dbc3..dda76b9072 100644 --- a/docs/output.md +++ b/docs/output.md @@ -10,7 +10,7 @@ The pipeline processes data using the following steps: - [Map to Reference](#map-to-reference) - [BWA mem](#bwa-mem) - [Mark Duplicates](#mark-duplicates) - - [GATK MarkDuplicates](#gatk-markduplicates) + - [GATK MarkDuplicatesSpark](#gatk-markduplicatesspark) - [Base (Quality Score) Recalibration](#base-quality-score-recalibration) - [GATK BaseRecalibrator](#gatk-baserecalibrator) - [GATK ApplyBQSR](#gatk-applybqsr) @@ -66,9 +66,9 @@ Such files are intermediate and not kept in the final files delivered to users. ### Mark Duplicates -#### GATK MarkDuplicates +#### GATK MarkDuplicatesSpark -[GATK MarkDuplicates](https://software.broadinstitute.org/gatk/documentation/tooldocs/4.1.4.0/picard_sam_markduplicates_MarkDuplicates.php) locates and tags duplicate reads in a BAM or SAM file, where duplicate reads are defined as originating from a single fragment of DNA. +[GATK MarkDuplicatesSpark](https://software.broadinstitute.org/gatk/documentation/tooldocs/current/org_broadinstitute_hellbender_tools_spark_transforms_markduplicates_MarkDuplicatesSpark.php) is a Spark implementation of [Picard MarkDuplicates](https://software.broadinstitute.org/gatk/documentation/tooldocs/current/picard_sam_markduplicates_MarkDuplicates.php) and locates and tags duplicate reads in a BAM or SAM file, where duplicate reads are defined as originating from a single fragment of DNA. This directory is the location for the BAM files delivered to users. Besides the duplicate marked BAM files, the recalibration tables (`*.recal.table`) are also stored, and can be used to create base recalibrated files. diff --git a/environment.yml b/environment.yml index 56e57e8f0a..1350b15716 100644 --- a/environment.yml +++ b/environment.yml @@ -14,7 +14,7 @@ dependencies: - ensembl-vep=98.2 - fastqc=0.11.8 - freebayes=1.3.1 - - gatk4=4.1.4.0 + - gatk4-spark=4.1.4.1 - genesplicer=1.0 - htslib=1.9 - manta=1.6.0 From b17ce672a2d579ecb79011ab885522aaa2428ba1 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 10 Dec 2019 15:22:01 +0100 Subject: [PATCH 302/854] update CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5e0a50814..48154ff601 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,11 +41,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - [#74](https://github.com/nf-core/sarek/pull/74) - Improve CI tests (both Jenkins and GitHub actions tests) - [#74](https://github.com/nf-core/sarek/pull/74) - Move all ci from `ci-extra.yml` to `ci.yml` - [#76](https://github.com/nf-core/sarek/pull/76) - Use `MarkDuplicatesSpark` instead of `MarkDuplicates` +- [#76](https://github.com/nf-core/sarek/pull/76) - Use `gatk4-spark` instead of `gatk4` in `environment.yml` ### `Removed` - [#46](https://github.com/nf-core/sarek/pull/46) - Remove mention of old `build.nf` script which was included in `main.nf` - [#74](https://github.com/nf-core/sarek/pull/74) - Remove `download_image.sh` and `run_tests.sh` scripts +- [#76](https://github.com/nf-core/sarek/pull/76) - Remove `runOptions = "-u \$(id -u):\$(id -g)"` in `nextflow.config` to enable `Spark` possibilities ### `Fixed` From 428b51f132a9b8a7d5d8f64e65678c27c0acaf4e Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 10 Dec 2019 15:33:06 +0100 Subject: [PATCH 303/854] fix TSV --- main.nf | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/main.nf b/main.nf index 7acbdf0bde..d9c966f330 100644 --- a/main.nf +++ b/main.nf @@ -1130,7 +1130,7 @@ recalTableTSV.map { idPatient, idSample -> status = statusMap[idPatient, idSample] gender = genderMap[idPatient] bam = "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${idSample}.md.bam" - bai = "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${idSample}.md.bai" + bai = "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${idSample}.md.bam.bai" recalTable = "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${idSample}.recal.table" "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\t${recalTable}\n" }.collectFile( @@ -1143,7 +1143,7 @@ recalTableSampleTSV status = statusMap[idPatient, idSample] gender = genderMap[idPatient] bam = "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${idSample}.md.bam" - bai = "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${idSample}.md.bai" + bai = "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${idSample}.md.bam.bai" recalTable = "${params.outdir}/Preprocessing/${idSample}/DuplicateMarked/${idSample}.recal.table" ["duplicateMarked_${idSample}.tsv", "${idPatient}\t${gender}\t${status}\t${idSample}\t${bam}\t${bai}\t${recalTable}\n"] } @@ -1153,12 +1153,10 @@ bamApplyBQSR = bamMDToJoin.join(recalTable, by:[0,1]) if (step == 'recalibrate') bamApplyBQSR = inputSample bamApplyBQSR = bamApplyBQSR.dump(tag:'BAM + BAI + RECAL TABLE') -// [DUMP: recal.table] ['normal', 'normal', normal.md.bam, normal.md.bai, normal.recal.table] bamApplyBQSR = bamApplyBQSR.combine(intApplyBQSR) bamApplyBQSR = bamApplyBQSR.dump(tag:'BAM + BAI + RECAL TABLE + INT') -// [DUMP: BAM + BAI + RECAL TABLE + INT] ['normal', 'normal', normal.md.bam, normal.md.bai, normal.recal.table, 1_1-200000.bed] // STEP 4: RECALIBRATING From e894dc9aee827b585fad4fb6054c276a1c4215f1 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 10 Dec 2019 16:28:42 +0100 Subject: [PATCH 304/854] fix syntax for IndexFeatureFile --- main.nf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main.nf b/main.nf index d9c966f330..627c224e7d 100644 --- a/main.nf +++ b/main.nf @@ -1513,7 +1513,8 @@ process GenotypeGVCFs { // Using -L is important for speed and we have to index the interval files also """ gatk --java-options -Xmx${task.memory.toGiga()}g \ - IndexFeatureFile -F ${gvcf} + IndexFeatureFile \ + -I ${gvcf} gatk --java-options -Xmx${task.memory.toGiga()}g \ GenotypeGVCFs \ From 88aa09f3835f00574048895971af6fd1519d179e Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Tue, 10 Dec 2019 17:02:01 +0100 Subject: [PATCH 305/854] typo --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89ee9f46d5..11d5eec8ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -125,6 +125,6 @@ jobs: run: | docker pull nfcore/sarek:dev docker tag nfcore/sarek:dev nfcore/sarek:dev - - name: Run vriant calling test on specific tools + - name: Run variant calling test on specific tools run: | nextflow run . -profile test_tool,docker --verbose --tools ${{ matrix.tool }} \ No newline at end of file From 09deda678c93c06a8c837bb54da6cd14070282da Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 11 Dec 2019 11:27:18 +0100 Subject: [PATCH 306/854] nf-core bump-version . 2.5.2 --- .travis.yml | 2 +- Dockerfile | 2 +- environment.yml | 2 +- nextflow.config | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3713a63aff..1ee0bf40db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ before_install: - docker pull nfcore/sarek:dev # Fake the tag locally so that the pipeline runs properly # Looks weird when this is :dev to :dev, but makes sense when testing code for a release (:dev to :1.0.1) - - docker tag nfcore/sarek:dev nfcore/sarek:dev + - docker tag nfcore/sarek:dev nfcore/sarek:2.5.2 install: # Install Nextflow diff --git a/Dockerfile b/Dockerfile index 2179ebbdda..84d313d85a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,4 +4,4 @@ LABEL authors="Maxime Garcia, Szilveszter Juhos" \ COPY environment.yml / RUN conda env create -f /environment.yml && conda clean -a -ENV PATH /opt/conda/envs/nf-core-sarek-2.5.2dev/bin:$PATH +ENV PATH /opt/conda/envs/nf-core-sarek-2.5.2/bin:$PATH diff --git a/environment.yml b/environment.yml index 56e57e8f0a..55c919d180 100644 --- a/environment.yml +++ b/environment.yml @@ -1,6 +1,6 @@ # You can use this file to create a conda environment for this pipeline: # conda env create -f environment.yml -name: nf-core-sarek-2.5.2dev +name: nf-core-sarek-2.5.2 channels: - conda-forge - bioconda diff --git a/nextflow.config b/nextflow.config index 22baf9ad56..909ad25108 100644 --- a/nextflow.config +++ b/nextflow.config @@ -90,7 +90,7 @@ params { // Container slug. Stable releases should specify release tag! // Developmental code should specify :dev -process.container = 'nfcore/sarek:dev' +process.container = 'nfcore/sarek:2.5.2' // Load base.config by default for all pipelines includeConfig 'conf/base.config' @@ -171,7 +171,7 @@ manifest { description = 'An open-source analysis pipeline to detect germline or somatic variants from whole genome or targeted sequencing' mainScript = 'main.nf' nextflowVersion = '>=19.10.0' - version = '2.5.2dev' + version = '2.5.2' } // Return the minimum between requirements and a maximum limit to ensure that resource requirements don't go over From ce8c4df616be9d5090ff715d484f27bd8202e6c4 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 11 Dec 2019 11:32:32 +0100 Subject: [PATCH 307/854] manual bump-version . 2.5.2 --- .circleci/config.yml | 8 ++++---- .github/workflows/ci.yml | 14 +++++++------- Jenkinsfile | 6 +++--- conf/base.config | 4 ++-- conf/test.config | 4 ++-- containers/snpeff/Dockerfile | 2 +- containers/snpeff/environment.yml | 2 +- containers/vep/Dockerfile | 2 +- containers/vep/environment.yml | 2 +- 9 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 582f2750a9..540c2fb782 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,11 +10,11 @@ jobs: - checkout - setup_remote_docker - run: - command: docker build -t nfcore/sareksnpeff:dev.${GENOME} containers/snpeff/. --build-arg GENOME=${GENOME} --build-arg SNPEFF_CACHE_VERSION=${SNPEFF_CACHE_VERSION} + command: docker build -t nfcore/sareksnpeff:2.5.2.${GENOME} containers/snpeff/. --build-arg GENOME=${GENOME} --build-arg SNPEFF_CACHE_VERSION=${SNPEFF_CACHE_VERSION} - run: command: | echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin - docker push nfcore/sareksnpeff:dev.${GENOME} + docker push nfcore/sareksnpeff:2.5.2.${GENOME} snpeffgrch38: << : *buildsnpeff @@ -45,10 +45,10 @@ jobs: - checkout - setup_remote_docker - run: - command: docker build -t nfcore/sarekvep:dev.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} + command: docker build -t nfcore/sarekvep:2.5.2.${GENOME} containers/vep/. --build-arg GENOME=${GENOME} --build-arg SPECIES=${SPECIES} --build-arg VEP_VERSION=${VEP_VERSION} no_output_timeout: 3h - run: - command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:dev.${GENOME} + command: echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ; docker push nfcore/sarekvep:2.5.2.${GENOME} vepgrch38: << : *buildvep diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89ee9f46d5..eb37d34cef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: - name: Download and tag image run: | docker pull nfcore/sarek:dev - docker tag nfcore/sarek:dev nfcore/sarek:dev + docker tag nfcore/sarek:dev nfcore/sarek:2.5.2 - name: Run test run: | nextflow run ${GITHUB_WORKSPACE} -profile test,docker @@ -39,9 +39,9 @@ jobs: - name: Download and tag images run: | docker pull nfcore/sarek:dev - docker tag nfcore/sarek:dev nfcore/sarek:dev + docker tag nfcore/sarek:dev nfcore/sarek:2.5.2 docker pull nfcore/sarek${{ matrix.annotator }}:dev.${{ matrix.specie }} - docker tag nfcore/sarek${{ matrix.annotator }}:dev.${{ matrix.specie }} nfcore/sarek${{ matrix.annotator }}:dev.${{ matrix.specie }} + docker tag nfcore/sarek${{ matrix.annotator }}:dev.${{ matrix.specie }} nfcore/sarek${{ matrix.annotator }}:2.5.2.${{ matrix.specie }} - name: Run annotation test run: | nextflow run . -profile test_annotation,docker --verbose --tools ${{ matrix.annotator }} @@ -58,7 +58,7 @@ jobs: - name: Download and tag image run: | docker pull nfcore/sarek:dev - docker tag nfcore/sarek:dev nfcore/sarek:dev + docker tag nfcore/sarek:dev nfcore/sarek:2.5.2 - name: Get test data run: | git clone --single-branch --branch sarek https://github.com/nf-core/test-datasets.git data @@ -84,7 +84,7 @@ jobs: - name: Download and tag image run: | docker pull nfcore/sarek:dev - docker tag nfcore/sarek:dev nfcore/sarek:dev + docker tag nfcore/sarek:dev nfcore/sarek:2.5.2 - name: Run test for minimal genomes run: | nextflow run . -profile test,docker --skipQC all --verbose --genome ${{ matrix.genome }} ${{ matrix.intervals }} --tools Manta,mpileup,Strelka @@ -104,7 +104,7 @@ jobs: - name: Download and tag image run: | docker pull nfcore/sarek:dev - docker tag nfcore/sarek:dev nfcore/sarek:dev + docker tag nfcore/sarek:dev nfcore/sarek:2.5.2 - name: Run targeted and splitfastq tests run: | nextflow run . -profile ${{ matrix.profile }},docker --verbose @@ -124,7 +124,7 @@ jobs: - name: Download and tag image run: | docker pull nfcore/sarek:dev - docker tag nfcore/sarek:dev nfcore/sarek:dev + docker tag nfcore/sarek:dev nfcore/sarek:2.5.2 - name: Run vriant calling test on specific tools run: | nextflow run . -profile test_tool,docker --verbose --tools ${{ matrix.tool }} \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile index 2a26fd3d5f..71ea4d76b7 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -9,11 +9,11 @@ pipeline { stage('Docker setup') { steps { sh "docker pull nfcore/sarek:dev" - sh "docker tag nfcore/sarek:dev nfcore/sarek:dev" + sh "docker tag nfcore/sarek:dev nfcore/sarek:2.5.2" sh "docker pull nfcore/sareksnpeff:dev.GRCh37" - sh "docker tag nfcore/sareksnpeff:dev.GRCh37 nfcore/sareksnpeff:dev.GRCh37" + sh "docker tag nfcore/sareksnpeff:dev.GRCh37 nfcore/sareksnpeff:2.5.2.GRCh37" sh "docker pull nfcore/sarekvep:dev.GRCh37" - sh "docker tag nfcore/sarekvep:dev.GRCh37 nfcore/sarekvep:dev.GRCh37" + sh "docker tag nfcore/sarekvep:dev.GRCh37 nfcore/sarekvep:2.5.2.GRCh37" } } stage('Annotation') { diff --git a/conf/base.config b/conf/base.config index 7c889b04ba..a21c748ba9 100644 --- a/conf/base.config +++ b/conf/base.config @@ -65,11 +65,11 @@ process { errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} } withName:Snpeff { - container = {(params.annotation_cache && params.snpEff_cache) ? 'nfcore/sarek:dev' : "nfcore/sareksnpeff:dev.${params.genome}"} + container = {(params.annotation_cache && params.snpEff_cache) ? 'nfcore/sarek:2.5.2' : "nfcore/sareksnpeff:2.5.2.${params.genome}"} errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} } withLabel:VEP { - container = {(params.annotation_cache && params.vep_cache) ? 'nfcore/sarek:dev' : "nfcore/sarekvep:dev.${params.genome}"} + container = {(params.annotation_cache && params.vep_cache) ? 'nfcore/sarek:2.5.2' : "nfcore/sarekvep:2.5.2.${params.genome}"} errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} } } diff --git a/conf/test.config b/conf/test.config index d8b3673d9c..55b2defe4d 100644 --- a/conf/test.config +++ b/conf/test.config @@ -24,11 +24,11 @@ params { process { withName:Snpeff { - container = 'nfcore/sareksnpeff:dev.GRCh37' + container = 'nfcore/sareksnpeff:2.5.2.GRCh37' maxForks = 1 } withLabel:VEP { - container = 'nfcore/sarekvep:dev.GRCh37' + container = 'nfcore/sarekvep:2.5.2.GRCh37' maxForks = 1 } } diff --git a/containers/snpeff/Dockerfile b/containers/snpeff/Dockerfile index cbd68c52d8..65aea05046 100644 --- a/containers/snpeff/Dockerfile +++ b/containers/snpeff/Dockerfile @@ -7,7 +7,7 @@ LABEL \ COPY environment.yml / RUN conda env create -f /environment.yml && conda clean -a -ENV PATH /opt/conda/envs/sarek-snpeff-2.5.2dev/bin:$PATH +ENV PATH /opt/conda/envs/sarek-snpeff-2.5.2/bin:$PATH # Setup default ARG variables ARG GENOME=GRCh38 diff --git a/containers/snpeff/environment.yml b/containers/snpeff/environment.yml index 5e73063ece..35279d068c 100644 --- a/containers/snpeff/environment.yml +++ b/containers/snpeff/environment.yml @@ -1,6 +1,6 @@ # You can use this file to create a conda environment for this pipeline: # conda env create -f environment.yml -name: sarek-snpeff-2.5.2dev +name: sarek-snpeff-2.5.2 channels: - conda-forge - bioconda diff --git a/containers/vep/Dockerfile b/containers/vep/Dockerfile index 562b770bef..3f9b7d10ab 100644 --- a/containers/vep/Dockerfile +++ b/containers/vep/Dockerfile @@ -7,7 +7,7 @@ LABEL \ COPY environment.yml / RUN conda env create -f /environment.yml && conda clean -a -ENV PATH /opt/conda/envs/sarek-vep-2.5.2dev/bin:$PATH +ENV PATH /opt/conda/envs/sarek-vep-2.5.2/bin:$PATH # Setup default ARG variables ARG GENOME=GRCh38 diff --git a/containers/vep/environment.yml b/containers/vep/environment.yml index 993a963ab0..2c8854d968 100644 --- a/containers/vep/environment.yml +++ b/containers/vep/environment.yml @@ -1,6 +1,6 @@ # You can use this file to create a conda environment for this pipeline: # conda env create -f environment.yml -name: sarek-vep-2.5.2dev +name: sarek-vep-2.5.2 channels: - conda-forge - bioconda From 9b2df57ab0a5e7bb96684badf319ee1c11e181a1 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 11 Dec 2019 11:37:29 +0100 Subject: [PATCH 308/854] update workflow image --- docs/images/sarek_workflow.png | Bin 49025 -> 127219 bytes docs/images/sarek_workflow.svg | 20 +++++++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/docs/images/sarek_workflow.png b/docs/images/sarek_workflow.png index 1a1821cbf77d305e27a0a2198050f886dafdc5eb..2ded2109327042bc93b3fa54aa2ca68568087183 100644 GIT binary patch literal 127219 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­zFf$9TjSuwAzO5;=g+8Uzw>*Uu~yqo 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 Q6#QeLyI<#-*6}O<1LT@63IG5A diff --git a/docs/images/sarek_workflow.svg b/docs/images/sarek_workflow.svg index 3c65217c05..0b1e65f314 100644 --- a/docs/images/sarek_workflow.svg +++ b/docs/images/sarek_workflow.svg @@ -2217,11 +2217,11 @@ inkscape:window-height="1012" id="namedview4" showgrid="false" - inkscape:zoom="0.5" - inkscape:cx="-604.69523" - inkscape:cy="732.99056" - inkscape:window-x="1920" - inkscape:window-y="759" + inkscape:zoom="0.70710678" + inkscape:cx="394.00446" + inkscape:cy="931.73227" + inkscape:window-x="0" + inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="g10" units="mm" @@ -2261,6 +2261,7 @@ + @@ -2793,6 +2794,7 @@ + • HaplotypeCaller Strelka2 mpileup, Strelka2• Manta, TIDDIT2.62.5.2 Date: Wed, 11 Dec 2019 11:39:07 +0100 Subject: [PATCH 309/854] downgrade tools for release --- CHANGELOG.md | 8 -------- environment.yml | 16 ++++++++-------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a52ada6b0f..a6bb8e1334 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,14 +22,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ### `Changed` -- [#41](https://github.com/nf-core/sarek/pull/41) - Update `control-freec` from `11.4` to `11.5` -- [#41](https://github.com/nf-core/sarek/pull/41) - Update `ensembl-vep` from `95.2` to `98.2` -- [#41](https://github.com/nf-core/sarek/pull/41) - Update `freebayes` from `1.2.0` to `1.3.1` -- [#41](https://github.com/nf-core/sarek/pull/41) - Update `gatk4` from `4.1.2.0` to `4.1.4.0` -- [#41](https://github.com/nf-core/sarek/pull/41) - Update `manta` from `1.5.0` to `1.6.0` -- [#41](https://github.com/nf-core/sarek/pull/41) - Update `qualimap` from `2.2.2b` to `2.2.2c` -- [#41](https://github.com/nf-core/sarek/pull/41), [#55](https://github.com/nf-core/sarek/pull/55) - Update `tiddit` from `2.7.1` to `2.8.1` -- [#41](https://github.com/nf-core/sarek/pull/41) - Update `vcfanno` from `0.3.1` to `0.3.2` - [#54](https://github.com/nf-core/sarek/pull/54) - Bump version to `2.5.2dev` - [#60](https://github.com/nf-core/sarek/pull/60) - Some process (`BaseRecalibrator`, `ApplyBQSR`, `Mpileup`) have now optional usage of interval files - [#60](https://github.com/nf-core/sarek/pull/60) - Update documentation diff --git a/environment.yml b/environment.yml index 55c919d180..00a6acf06b 100644 --- a/environment.yml +++ b/environment.yml @@ -10,19 +10,19 @@ dependencies: - bcftools=1.9 - bwa=0.7.17 - cancerit-allelecount=4.0.2 - - control-freec=11.5 - - ensembl-vep=98.2 + - control-freec=11.4 + - ensembl-vep=95.2 - fastqc=0.11.8 - - freebayes=1.3.1 - - gatk4=4.1.4.0 + - freebayes=1.2.0 + - gatk4=4.1.2.0 - genesplicer=1.0 - htslib=1.9 - - manta=1.6.0 + - manta=1.5.0 - multiqc=1.7 - - qualimap=2.2.2c + - qualimap=2.2.2b - samtools=1.9 - snpeff=4.3.1t - strelka=2.9.10 - - tiddit=2.8.1 - - vcfanno=0.3.2 + - tiddit=2.7.1 + - vcfanno=0.3.1 - vcftools=0.1.16 \ No newline at end of file From feb865688fdce99a886e7be46687243017e38548 Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Wed, 11 Dec 2019 12:09:11 +0100 Subject: [PATCH 310/854] update CHANGELOG --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6bb8e1334..1a6bfcaf79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## dev +## [2.5.2] - Jåkkåtjkaskajekna + +Jåkkåtjkaskajekna is one of the two glaciers of the Ålkatj Massif. ### `Added` @@ -29,7 +31,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - [#71](https://github.com/nf-core/sarek/pull/71) - Update `CHANGELOG` - [#74](https://github.com/nf-core/sarek/pull/74) - Update docs - [#74](https://github.com/nf-core/sarek/pull/74) - Improve CI tests (both Jenkins and GitHub actions tests) -- [#74](https://github.com/nf-core/sarek/pull/74) - Move all ci from `ci-extra.yml` to `ci.yml` +- [#74](https://github.com/nf-core/sarek/pull/74) - Move all CI from `ci-extra.yml` to `ci.yml` ### `Removed` From 8cd87a4fb25c7d82f1796197d7f0a7a928a0e40d Mon Sep 17 00:00:00 2001 From: MaxUlysse Date: Thu, 12 Dec 2019 13:16:59 +0100 Subject: [PATCH 311/854] clean up and update workflow image --- README.md | 2 +- conf/awsbatch.config | 18 -- docs/images/sarek_workflow.png | Bin 127219 -> 138905 bytes docs/images/sarek_workflow.svg | 329 +++++++++++++++++---------------- nextflow.config | 12 +- 5 files changed, 179 insertions(+), 182 deletions(-) delete mode 100644 conf/awsbatch.config diff --git a/README.md b/README.md index e42c1f74de..d817195e18 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Software dependencies are handled using [Conda](https://conda.io/), [Docker](htt Thus making installation trivial and results highly reproducible.

- +

It's listed on the [Elixir - Tools and Data Services Registry](https://bio.tools/Sarek), [Dockstore](https://dockstore.org/workflows/github.com/nf-core/sarek) and [omicX - Bioinformatics tools](https://omictools.com/sarek-tool). diff --git a/conf/awsbatch.config b/conf/awsbatch.config deleted file mode 100644 index 14af5866f5..0000000000 --- a/conf/awsbatch.config +++ /dev/null @@ -1,18 +0,0 @@ -/* - * ------------------------------------------------- - * Nextflow config file for running on AWS batch - * ------------------------------------------------- - * Base config needed for running with -profile awsbatch - */ -params { - config_profile_name = 'AWSBATCH' - config_profile_description = 'AWSBATCH Cloud Profile' - config_profile_contact = 'Alexander Peltzer (@apeltzer)' - config_profile_url = 'https://aws.amazon.com/de/batch/' -} - -aws.region = params.awsregion -process.executor = 'awsbatch' -process.queue = params.awsqueue -executor.awscli = '/home/ec2-user/miniconda/bin/aws' -params.tracedir = './' diff --git a/docs/images/sarek_workflow.png b/docs/images/sarek_workflow.png index 2ded2109327042bc93b3fa54aa2ca68568087183..4499cf75d4cfbdc7be50a8aac28d03bd0413c339 100644 GIT binary patch literal 138905 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 literal 127219 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­zFf$9TjSuwAzO5;=g+8Uzw>*Uu~yqo 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/svg+xml @@ -2795,6 +2803,8 @@ + + 2.5.2

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 + + +image/svg+xmlMaxime Garcia1, Szilveszter Juhos2, Malin Larsson3, Teresita Diaz de Ståhl4, Johanna Sandgren4, Jesper Eisfeldt5,Sebastian DiLorenzo6, Marcel Martin7, Pall Olason8, Björn Nystedt8, Monica Nistér4, Max Käller9 + +Cancer Analysis Workflow toprocess normal/tumor WGS data + As WGS (whole genome sequencing), the broadly used research tool is getting cheaper and being introduced to clinics, it is now possible to compare data from normal and tumor samples of numerous patients. There are still many challenges, mostly regarding bioinformatics: datasets are huge, workflows are complex, and there are multiple tools to choose from for somatic and structural variant detection and quality control. The pipeline can use GRCh37 or GRCh38 as a reference genome. Docker containers are also available for easier deployment and testing purposes. CAW can be downloaded from our GitHub repository. The authors thank the Swedish Childhood Cancer Foundation for the funding of Barntumörbanken. We would like to acknowledge support from Science for Life Laboratory, the National Genomics Infrastructure, NGI, and UPPMAX for providing assistance in massive parallel sequencing and computational infrastructure.AknowledgementsReferencesLinkshttp://opensource.scilifelab.se/projects/cawhttps://github.com/SciLifeLab/CAWhttps://gitter.im/SciLifeLab/CAWhttps://www.scilifelab.se/facilities/genomics-applications/ +* : http://dx.doi.org/10.1038/nbt.3820 +Core principlesbstractAWACWGS normal/tumor pairs analysis workflow written inFollows GATK best practices. Provides SNVs, small indels, structural variants, heterogeneity, ploidy CNVs, annotation and QC reportsTools used:- ASCAT- Freebayes- HaplotypeCaller- Manta- MultiQC- MuTect1- MuTect2- snpEff- Strelka- VEPL;DRTEasily deployable, supports containersThe MIT License (MIT) Copyright © 2016 SciLifeLabCan be used onCan also analyse normal only samples1 - BarnTumörBanken, Dept. of Oncology Pathology, Science for Life Laboratory, Karolinska Institutet2 - Dept. of Biochemistry and Biophysics, Science for Life Laboratory, Stockholm University3 - Dept. of Physics, Chemistry and Biology, National Bioinformatics Infrastructure Sweden, Science for Life Laboratory, Linköping University4 - BarnTumörBanken, Dept. of Oncology Pathology, Karolinska Institutet5 - Clinical Genetics, Dept. of Molecular Medicine and Surgery, Karolinska Institutet6 - Dept. of Medical Sciences, National Bioinformatics Infrastructure Sweden, Science for Life Laboratory, Uppsala University7 - Dept. of Biochemistry and Biophysics, National Bioinformatics Infrastructure Sweden, Science for Life Laboratory, Stockholm University 8 - Dept. of Cell and Molecular Biology, National Bioinformatics Infrastructure Sweden, Science for Life Laboratory, Uppsala University9 - Science for Life Laboratory, School of Biotechnology, Division of Gene Technology, Royal Institute of TechnologyJoin the chat on gitterOpen source, contribute on githubAknowledgementsUPPMAX Preprocessing takes arround 4 days on one Huawei XH620 V3 compute node with dual CPUs (Intel Xeon E5-2630 v3, each with 8 cores) with 45 coverage normal/tumor pairs. Further Variant Calling can take up to 10 hours for each variant caller. CAW is prepared to process normal/tumor pairs and can handle additional relapse samples. It can also be used to preprocess and analyse normal only samples using GATK best practices and HaplotypeCaller. CAW can start the analysis from raw FASTQ files, from the realignment step, or directly with any subset of variant callers. Resulting VCF files can be annotated using snpEff or VEP. At the end of the analysis the final VCF files are merged to facilitate further downstream processing, though the individual results are also retained. The flow is capable of accommodating further variant calling software or CNV callers. We are utilizing GATK best practices to align, realign and recalibrate short-read data in parallel for both tumor and normal samples. After preprocessing, several somatic variant callers scan the resulting BAM files; MuTect1, MuTect2 and Strelka are used to find somatic SNVs and small indels. For structural variants we use Manta. Furthermore, we are applying ASCAT to estimate sample heterogeneity, ploidy and CNVs. The workflow also provides quality controls presented by MultiQC.orkflow specificitiesW We are presenting CAW (Cancer Analysis Workflow), a complete open source pipeline to resolve somatic variants from WGS data: it is written in Nextflow*, a domain specific language for workflow building.Variant Calling +Structural +Variants +SNVs +CNV +Indels +Preprocessing +GATK +Best Practices +normal +BAM, bai +GATK +Best Practices +tumor +BAM, bai +GATK +Best Practices +relapse +BAM, bai +Configuration +Metadata +Statistics & QC +Results +Annotation +Pre-filter +Merge + \ No newline at end of file diff --git a/docs/posters/PMC_2018_Mgarcia.pdf b/docs/posters/PMC_2018_Mgarcia.pdf new file mode 100644 index 0000000000000000000000000000000000000000..cb7686ffd0dc16836f5cbcfc8a2eb168d4dda84b GIT binary patch literal 307620 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≦WvvWN;MU{)@;zcaDc#}k4J?}U${1_-ak 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ͤaH?^|WWw%EtBb)=#4|*3;5N0^!)} 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 fy0$@GduiwFV(R3ww(~ + + +image/svg+xmlMaxime Garcia1, Szilveszter Juhos1, Malin Larsson2, Teresita Diaz de Ståhl3, Johanna Sandgren3, Jesper Eisfeldt4,Sebastian DiLorenzo5, Marcel Martin6, Pall Olason7, Phil Ewels8, Björn Nystedt7, Monica Nistér3, Max Käller9 + +Sarek, a workflow for WGS analysisof germline and somatic mutations +Portable WGS germline and normal/tumor pairs analysis workflow written inSummaryEasily deployable with containersThe MIT License (MIT) Copyright © 2016 SciLifeLabCan be used onJoin the chat on GitterOpen source, contribute on GitHubAcknowledgementsUPPMAX1 - BarnTumörBanken, Dept. of Oncology Pathology, Science for Life Laboratory, Karolinska Institutet2 - Dept. of Physics, Chemistry and Biology, National Bioinformatics Infrastructure Sweden, Science for Life Laboratory, Linköping University3 - BarnTumörBanken, Dept. of Oncology Pathology, Karolinska Institutet4 - Clinical Genetics, Dept. of Molecular Medicine and Surgery, Karolinska Institutet5 - Dept. of Medical Sciences, National Bioinformatics Infrastructure Sweden, Science for Life Laboratory, Uppsala University6 - Dept. of Biochemistry and Biophysics, National Bioinformatics Infrastructure Sweden, Science for Life Laboratory, Stockholm University 7 - Dept. of Cell and Molecular Biology, National Bioinformatics Infrastructure Sweden, Science for Life Laboratory, Uppsala University8 - Dept. of Biochemistry and Biophysics, Science for Life Laboratory, Stockholm University9 - Science for Life Laboratory, School of Biotechnology, Division of Gene Technology, Royal Institute of Technology + +rThe authors thank the Swedish Childhood Cancer Foundation for the funding of Barntumörbanken. We would like to acknowledge support from Science for Life Laboratory, the National Genomics Infrastructure, NGI, and UPPMAX for providing assistance in massive parallel sequencing and computational infrastructure.AcknowledgementsSarek is based on Docker and Singularity2 containers, enabling version tracking, reproducibility and handling sensitive data.The workflow is capable of accommodating further variant callers.Besides variant calls, the workflow provides quality controls presented by MultiQC3.Checkpoints allow the software to be started from FastQ, BAM or VCF.The pipeline currently use GRCh37 or GRCh38 as a reference genome, it is also possible to add custom genomes.The MIT licensed Open Source code can be downloaded from GitHub.Linksopensource.scilifelab.se/projects/sarekgithub.com/SciLifeLab/Sarekgitter.im/SciLifeLab/Sarekngisweden.scilifelab.se +References1: doi.org/10.1038/nbt.38202: doi.org/10.1371/journal.pone.01774593: doi.org/10.1093/bioinformatics/btw354 +We present Sarek, a portable Open Source pipeline to resolve germline and somatic variants from WGS data: it is written in Nextflow1, a domain-specific language for workflow building.It processes normal samples or normal/tumor pairs (with the option to include matched relapses).Sarek is based on GATK best practices to prepare short-read data, which is done in parallel for a tumor/normal pair sample.After these preprocessing steps several variant callers scan the resulting BAM files:- Manta for structural variants- Strelka and GATK HaplotypeCaller for germline variants- Freebayes, MuTect1, MuTect2 and Strelka for somatic variants- ASCAT to estimate sample heterogeneity, ploidy and CNVsAt the end of the analysis the resulting VCF files can be annotated to facilitate further downstream processing.Fig1: CPU usage for 90x tumor/normal pair sample (hours)Map, merge, dedup - 27%Realign, recalibrate - 20%HaplotypeCaller - 8%Strelka - 1%Manta - 10%FreeBayes - 5%MuTect2 - 6%MuTect1 - 3%ASCAT - 5%PrintReads - 16%84621815302548159Preprocessing based on GATK best practicesVariant Calling with:- HaplotypeCaller- Manta- StrelkaVariant Calling with:- ASCAT- Freebayes- HaplotypeCaller- Manta- MuTect1- MuTect2- StrelkaAnnotation with:- snpEff- VEPReports aggregated byFig2: Workflow organizationhtmlorfastqbambambairecalvcfvcfvcfVariant Calling +- HaplotypeCaller, Strelka- MantaPreprocessing +Based on GATK Best PracticesfastqbamorfastqbambambairecalbambairecalvcfvcfvcfvcfvcfvcfvcfvcfPreprocessing +Based on GATK Best PracticesVariant Calling +- HaplotypeCaller, Freebayes MuTect1, MuTect2, Strelka- ASCAT- MantaAnnotation +snpEff, VEPReports +SarekSomaticSarekGermlineSarekSarekGermlineSarekSomatic \ No newline at end of file diff --git a/docs/reference.md b/docs/reference.md index 55d267d023..eb77557ddc 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -7,6 +7,35 @@ Both `GRCh37` and `GRCh38` are available with `--genome GRCh37` or `--genome GRC Use `--genome smallGRCh37` to map against a small reference genome based on GRCh37. Settings in `igenomes.config` can be tailored to your needs. +### Intervals + +To speed up the variant calling processes, the reference is chopped into smaller pieces. +The intervals are chromosomes cut at their centromeres (so each chromosome arm processed separately) also additional unassigned contigs. +We are ignoring the hs37d5 contig that contains concatenated decoy sequences. +Parts of preprocessing and variant calling are done by this intervals, and the different resulting files are then merged. +This can parallelize processes, and push down wall clock time significantly. + +The calling intervals can be defined using a `.list` or a `.bed` file. +A `.list` file contains one interval per line in the format `chromosome:start-end` (1-based coordinates). + +When the intervals file is in BED format, the file must be a tab-separated text file with one interval per line. +There must be at least three columns: chromosome, start, and end. +In BED format, the coordinates are 0-based, so the interval `chrom:1-10` becomes `chrom010`. + +Additionally, the "score" column of the BED file can be used to provide an estimate of how many seconds it will take to call variants on that interval. +The fourth column remains unused. +Example (the fields would actually be tab-separated, this is not shown here): + +`chr1 10000 207666 NA 47.3` + +This indicates that variant calling on the interval chr1:10001-207666 takes approximately 47.3 seconds. + +The runtime estimate is used in two different ways. +First, when there are multiple consecutive intervals in the file that take little time to compute, they are processed as a single job, thus reducing the number of processes that needs to be spawned. +Second, the jobs with largest processing time are started first, which reduces wall-clock time. +If no runtime is given, a time of 1000 nucleotides per second is assumed. +Actual figures vary from 2 nucleotides/second to 30000 nucleotides/second. + ## build.nf The [`build.nf`](#buildnf) script is used to build reference needed for smallGRCh37. diff --git a/docs/usage.md b/docs/usage.md index bf63ec88fb..48d5864794 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -194,7 +194,7 @@ The syntax for this reference configuration is as follows: ```nextflow params { genomes { - 'GRCh37' { + 'GRCh38' { acLoci = '' acLociGC = '' bwaIndex = '' diff --git a/docs/use_cases.md b/docs/use_cases.md new file mode 100644 index 0000000000..894343f37c --- /dev/null +++ b/docs/use_cases.md @@ -0,0 +1,122 @@ +# Use cases + +The workflow has two pre-processing options: `mapping` and `recalibrate`. +Using the `mapping` directive one will have a pair of mapped, deduplicated and recalibrated BAM files in the `Preprocessing/Recalibrated/` directory. +This is the usual option you have to give when you are starting from raw FASTQ data: + +```bash +nextflow run nf-core/sarek/main.nf --sample mysample.tsv --tools +``` + +`mapping` will start by default, you do not have to give any additional parameters, only the TSV file describing the sample (see below). + +During the execution of the workflow a `execution_trace.txt`, a `execution_timeline.html` and a `execution_report.html` files are generated automatically. +These files contain statistics about resources used and processes finished. +If you start a new workflow or restart/resume a sample, the previous version will be renamed as `execution_trace.txt.1`, `execution_timeline.html.1` and `execution_report.html.1` respectively. +Also, older version are renamed with incremented numbers. + +## Starting from raw FASTQ - pair of FASTQ files + +The workflow should be started in this case with the smallest set of options as written above: + +```bash +nextflow run nf-core/sarek/main.nf --sample mysample.tsv --tools +``` + +The TSV file should look like: +``` +SUBJECT_ID XX 0 SAMPLE_ID 1 /samples/normal_1.fastq.gz /samples/normal_2.fastq.gz +``` + +See the [input files documentation](docs/input.md) for more information. + +## Starting from raw FASTQ - a directory with normal sample only + +The `--sample` option can be also used to point Sarek to a directory with FASTQ files: +```bash +nextflow run nf-core/sarek/main.nf --sample path/to/FASTQ/files --tools +``` +The given directory is searched recursively for FASTQ files that are named `*_R1_*.fastq.gz`, and a matching pair with the same name except `_R2_` instead of `_R1_` is expected to exist alongside. +All of the found FASTQ files are considered to belong to the sample. +Each FASTQ file pair gets its own read group (`@RG`) in the resulting BAM file. + +### Metadata when using `--sample` with a directory + +When using `--sample` with a directory, the metadata about the sample that are written to the BAM header in the `@RG` tag are determined in the following way. + +- The sample name (`SM`) is derived from the the last component of the path given to `--sample`. +That is, you should make sure that that directory has a meaningful name! For example, with `--sample=/my/fastqs/sample123`, the sample name will be `sample123`. +- The read group id is set to *flowcell.samplename.lane*. +The flowcell id and lane number are auto-detected from the name of the first read in the FASTQ file. + +## Starting from raw FASTQ - pair of FASTQ files for tumor/normal samples + +The workflow command line is just the same as before, but the TSV contains extra lines. +You can see the second column is used to distinguish normal and tumor samples. +You can add as many relapse samples as many you have, providing their name in the third column is different. +Each will be compared to the normal one-by-one. +Usually there are more read groups - sequencing lanes - for a single sequencing run, and in a flowcell different lanes have to be recalibrated separately. +This is captured in the TSV file only in the following manner, adding read group numbers or IDs in the fourth column. +All lanes belonging to the same Sample will be merged together after the FASTQ pairs are mapped to the reference genome. +Obviously, if you do not have relapse samples, you can leave out the two last lines. + +``` +SUBJECT_ID XX 0 SAMPLE_ID_N 1 /samples/normal1_1.fastq.gz /samples/normal1_2.fastq.gz +SUBJECT_ID XX 0 SAMPLE_ID_N 2 /samples/normal2_1.fastq.gz /samples/normal2_2.fastq.gz +SUBJECT_ID XX 1 SAMPLE_ID_T 3 /samples/tumor3_1.fastq.gz /samples/tumor3_2.fastq.gz +SUBJECT_ID XX 1 SAMPLE_ID_T 4 /samples/tumor4_1.fastq.gz /samples/tumor4_2.fastq.gz +SUBJECT_ID XX 1 SAMPLE_ID_T 5 /samples/tumor5_1.fastq.gz /samples/tumor5_2.fastq.gz +SUBJECT_ID XX 1 SAMPLE_ID_R 7 /samples/relapse7_1.fastq.gz /samples/relapse7_2.fastq.gz +SUBJECT_ID XX 1 SAMPLE_ID_R 9 /samples/relapse9_1.fastq.gz /samples/relapse9_2.fastq.gz +``` + +See the [input files documentation](docs/input.md) for more information. + +## Starting from recalibration + +```bash +nextflow run nf-core/sarek/main.nf --sample mysample.tsv --step recalibrate --tools +``` + +And the corresponding TSV file should be like: +Obviously, if you do not have tumor or relapse samples, you can leave out the two last lines. + +``` +SUBJECT_ID XX 0 SAMPLE_ID_N /samples/SAMPLE_ID_N.bam /samples/SAMPLE_ID_N.bai /samples/SAMPLE_ID_N.recal.table +SUBJECT_ID XX 1 SAMPLE_ID_T /samples/SAMPLE_ID_T.bam /samples/SAMPLE_ID_T.bai /samples/SAMPLE_ID_T.recal.table +SUBJECT_ID XX 1 SAMPLE_ID_R /samples/SAMPLE_ID_R.bam /samples/SAMPLE_ID_R.bai /samples/SAMPLE_ID_R.recal.table +``` + +See the [input files documentation](docs/input.md) for more information. + +## Starting from a recalibrated BAM file + +At this step we are assuming that all the required preprocessing is over, we only want to run variant callers or other tools using recalibrated BAM files. + +```bash +nextflow run nf-core/sarek/main.nf --step variantcalling --tools +``` + +And the corresponding TSV file should be like: + +``` +SUBJECT_ID XX 0 SAMPLE_ID_N /samples/SAMPLE_ID_N.bam /samples/SAMPLE_ID_N.bai +SUBJECT_ID XX 1 SAMPLE_ID_T /samples/SAMPLE_ID_T.bam /samples/SAMPLE_ID_T.bai +SUBJECT_ID XX 1 SAMPLE_ID_R /samples/SAMPLE_ID_R.bam /samples/SAMPLE_ID_R.bai +``` + +See the [input files documentation](docs/input.md) for more information. + +If you want to restart a previous run of the pipeline, you may not have a recalibrated BAM file. +In this case, you need to start with `--step=recalibrate` (see previous section). + +## Using Sarek with targeted (whole exome or panel) sequencing data + +The recommended flow for targeted sequencing data is to use the workflow as it is, but also provide a BED file containing targets for all steps using the `--targetBED` option. +The workflow will pick up these intervals, and activate the `--exome` flag to process deeper coverage. +It is adviced to pad the variant calling regions (exons or the target) to some extent before submitting to the workflow. +To add the target BED file configure the flow like: + +```bash +nextflow run nf-core/sarek/main.nf --tools haplotypecaller,strelka,mutect2 --targetBED targets.bed --sample my_panel.tsv +``` diff --git a/main.nf b/main.nf index 44cbb28c91..7bff7070ea 100644 --- a/main.nf +++ b/main.nf @@ -53,7 +53,6 @@ def helpMessage() { --tools Specify tools to use for variant calling Available: ASCAT, ControlFREEC, FreeBayes, HaplotypeCaller Manta, mpileup, MuTect2, Strelka - Default: HaplotypeCaller, Manta, Strelka --annotateTools Specify from which tools Sarek will annotate VCF, only for step annotate Available: HaplotypeCaller, Manta, MuTect2, Strelka @@ -118,7 +117,7 @@ params.sequencing_center = null params.snpEff_cache = null params.step = 'mapping' params.targetBED = null -params.tools = "HaplotypeCaller,Manta,Strelka" +params.tools = null params.vep_cache = null stepList = defineStepList() @@ -1409,7 +1408,7 @@ mpileupMerge = mpileupMerge.groupTuple(by:[0,1]) process MergeMpileup { tag {idSample} - publishDir params.outdir, mode: params.publishDirMode, saveAs: { it == "${idSample}.pileup.gz" ? "VariantCalling/${idSampleTumor}_vs_${idSampleNormal}/mpileup/${it}" : '' } + publishDir params.outdir, mode: params.publishDirMode, saveAs: { it == "${idSample}.pileup.gz" ? "VariantCalling/${idSample}/mpileup/${it}" : '' } input: set idPatient, idSample, file(mpileup) from mpileupMerge @@ -1707,8 +1706,7 @@ process Snpeff { val snpeffDb from Channel.value(params.genomes[params.genome].snpeffDb) output: - set file("${reducedVCF}_snpEff.txt"), file("${reducedVCF}_snpEff.html") into snpeffOut - file("${reducedVCF}_snpEff.csv") into snpeffReport + set file("${reducedVCF}_snpEff.txt"), file("${reducedVCF}_snpEff.html"), file("${reducedVCF}_snpEff.csv") into snpeffReport set val("snpEff"), variantCaller, idSample, file("${reducedVCF}_snpEff.ann.vcf") into snpeffVCF when: 'snpeff' in tools || 'merge' in tools @@ -1732,7 +1730,6 @@ process Snpeff { """ } -snpeffOut = snpeffOut.dump(tag:'snpEff output') snpeffReport = snpeffReport.dump(tag:'snpEff report') if ('merge' in tools) { @@ -1754,7 +1751,7 @@ process VEP { tag {"${idSample} - ${variantCaller} - ${vcf}"} publishDir params.outdir, mode: params.publishDirMode, saveAs: { - if (it == "${reducedVCF}_VEP.summary.html") "Annotation/${idSample}/VEP/${it}" + if (it == "${reducedVCF}_VEP.summary.html") "Reports/${idSample}/VEP/${it}" else null } @@ -1857,7 +1854,7 @@ multiQCReport = Channel.empty() Channel.fromPath(params.multiqc_config) -process RunMultiQC { +process MultiQC { publishDir "${params.outdir}/Reports/MultiQC", mode: params.publishDirMode input: diff --git a/bin/ascat.R b/scripts/ascat.R similarity index 100% rename from bin/ascat.R rename to scripts/ascat.R diff --git a/bin/build_reference.sh b/scripts/build_reference.sh similarity index 100% rename from bin/build_reference.sh rename to scripts/build_reference.sh diff --git a/bin/download_docker.sh b/scripts/download_docker.sh similarity index 100% rename from bin/download_docker.sh rename to scripts/download_docker.sh diff --git a/bin/run_tests.sh b/scripts/run_tests.sh similarity index 89% rename from bin/run_tests.sh rename to scripts/run_tests.sh index 1a19312a68..8b9c49c4f0 100755 --- a/bin/run_tests.sh +++ b/scripts/run_tests.sh @@ -2,6 +2,7 @@ set -xeuo pipefail CPUS=2 +LOGS='' PROFILE=docker TEST=ALL TRAVIS_BUILD_DIR=${TRAVIS_BUILD_DIR:-.} @@ -12,9 +13,12 @@ while [[ $# -gt 0 ]] do key=$1 case $key in - -t|--test) - TEST=$2 - shift # past argument + -c|--cpus) + CPUS=$2 + shift # past value + ;; + -n|--no-logs) + LOGS=true shift # past value ;; -p|--profile) @@ -22,12 +26,13 @@ do shift # past argument shift # past value ;; - -v|--verbose) - VERBOSE="-ansi-log false -dump-channels" + -t|--test) + TEST=$2 + shift # past argument shift # past value ;; - -c|--cpus) - CPUS=$2 + -v|--verbose) + VERBOSE="-ansi-log false -dump-channels" shift # past value ;; *) # unknown option @@ -36,6 +41,13 @@ do esac done +function manage_logs() { + if [[ $LOGS ]] + then + rm -rf .nextflow* results/ work/ + fi +} + function run_sarek() { nextflow run ${TRAVIS_BUILD_DIR}/main.nf -profile test,${PROFILE} ${VERBOSE} --monochrome_logs $@ } @@ -47,19 +59,20 @@ then run_sarek --tools=false --sample data/testdata/tiny/normal --noReports run_sarek --tools=false --sample results/Preprocessing/TSV/duplicateMarked.tsv --step recalibrate --noReports run_sarek --tools HaplotypeCaller,Strelka --sample results/Preprocessing/TSV/recalibrated.tsv --step variantCalling --noReports - rm -rf .nextflow* results/ work/ + rm -rf data/ + manage_logs fi if [[ ALL,SOMATIC =~ $TEST ]] then run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports - rm -rf .nextflow* results/ work/ + manage_logs fi if [[ ALL,TARGETED =~ $TEST ]] then run_sarek --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports --targetBED https://github.com/nf-core/test-datasets/raw/sarek/testdata/target.bed - rm -rf .nextflow* results/ work/ + manage_logs fi if [[ ALL,ANNOTATEALL,ANNOTATESNPEFF,ANNOTATEVEP =~ $TEST ]] @@ -75,11 +88,11 @@ then ANNOTATOR=merge,snpEFF,VEP fi run_sarek --step annotate --tools ${ANNOTATOR} --sample https://github.com/nf-core/test-datasets/raw/sarek/testdata/vcf/Strelka_1234N_variants.vcf.gz --noReports - rm -rf .nextflow* results/ work/ + manage_logs fi if [[ MULTIPLE =~ $TEST ]] then run_sarek --sample https://github.com/nf-core/test-datasets/raw/sarek/testdata/tsv/tiny-multiple-https.tsv --tools FreeBayes,HaplotypeCaller,Manta,Strelka,Mutect2 --noReports - rm -rf .nextflow* results/ work/ + manage_logs fi diff --git a/scripts/speedseq.filter.awk b/scripts/speedseq.filter.awk new file mode 100644 index 0000000000..d5d9ab0020 --- /dev/null +++ b/scripts/speedseq.filter.awk @@ -0,0 +1,50 @@ +# somatic filter for FreeBayes VCF files, based on SpeedSeq: https://github.com/hall-lab/speedseq +# recommended to filter the large VCF files like: +# vcfsamplediff -s VT normal tumour freebayesresult.vcf | \ +# awk '/^#/{print}!/^#/&&!/germline/' |\ +# vcffilter -f "QUAL > 20" | vcfflatten |\ +# awk -f speedseq.filter.awk -v NORMAL_IDX=10 -v TUMOUR_IDX=11 > filtered.vcf +# where "normal" and "tumour" are the sample names in the VCF respectively, and the IDX variables are their 1-based column numbers in the #CHROM line of the VCF +# also check the index for these sample names also +BEGIN{ + MINQUAL=1; + SSC_THRES=1; # somatic score threshold ssc = LOD_T + LOD_N, log of odds (LOD) is the genotype quality ratio (http://www.nature.com/nmeth/journal/v12/n10/pdf/nmeth.3505.pdf) + ONLY_SOMATIC=1; # prints out only somatic lines if not zero + GL_IDX=0; # GL in the original: PL is the Normalized, Phred-scaled likelihoods for genotypes +} +{ + OFS="\t"; + + if ($0~"^#" && $0!~"^#CHROM") { print ; next; } + # add extra header line + if ($0~"^#CHROM") { + print "##INFO=" + print ; + } + if (! GL_IDX) { + split($9,fmt,":") + for (i=1;i<=length(fmt);++i) { if (fmt[i]=="GL") GL_IDX=i } + } + split($NORMAL_IDX,N,":"); # split field 10 and put values into + split(N[GL_IDX],NGL,","); + split($TUMOR_IDX,T,":"); + split(T[GL_IDX],TGL,","); + LOD_NORM=NGL[1]-NGL[2]; + LOD_TUMOR_HET=TGL[2]-TGL[1]; + LOD_TUMOR_HOM=TGL[3]-TGL[1]; + + if (LOD_TUMOR_HET > LOD_TUMOR_HOM) { LOD_TUMOR=LOD_TUMOR_HET } + else { LOD_TUMOR=LOD_TUMOR_HOM } + + DQUAL=LOD_TUMOR+LOD_NORM; + + if (DQUAL>=SSC_THRES && $NORMAL_IDX~"^0/0") { + $7="PASS" + $8="DQUAL="DQUAL";"$8 + print + } + else if (!ONLY_SOMATIC && $6>=MINQUAL && $NORMAL_IDX~"^0/0" && ! match($TUMOUR_IDX,"^0/0")) { + $8="DQUAL="DQUAL";"$8 + print + } +} From a9cb70ece9a9689c4954622658e9c5694e4499bf Mon Sep 17 00:00:00 2001 From: Maxime Garcia Date: Wed, 12 Jun 2019 16:52:00 +0200 Subject: [PATCH 019/854] Configs and docs (#12) * Update CI scripts * Add possibility to download singularity images with helper script * Update Docs * Improve build.nf * Use label for processes configuration * Update configuration files * Disable Docker in singularity profile * Disable Singularity in docker profile * Disable Docker and Singularity in conda profile * Simplify check_max() function --- .travis.yml | 2 +- CHANGELOG.md | 429 ++- Jenkinsfile | 2 +- README.md | 1 + bin/concatenateVCFs.sh | 59 +- build.nf | 54 +- conf/base.config | 104 +- docs/README.md | 9 + docs/install_bianca.md | 179 ++ docs/output.md | 1 - docs/posters/ESHG_2019.pdf | Bin 0 -> 341880 bytes docs/posters/ESHG_2019.svg | 5580 +++++++++++++++++++++++++++++++++++ docs/reference.md | 2 +- main.nf | 263 +- nextflow.config | 50 +- scripts/build_reference.sh | 14 +- scripts/download_docker.sh | 37 - scripts/download_image.sh | 73 + scripts/filter_locifile.py | 25 + scripts/make_snapshot.sh | 53 + scripts/run_tests.sh | 56 +- scripts/selectROI.py | 232 ++ scripts/speedseq.filter.awk | 50 - 23 files changed, 6963 insertions(+), 312 deletions(-) create mode 100644 docs/install_bianca.md create mode 100644 docs/posters/ESHG_2019.pdf create mode 100644 docs/posters/ESHG_2019.svg delete mode 100755 scripts/download_docker.sh create mode 100755 scripts/download_image.sh create mode 100644 scripts/filter_locifile.py create mode 100755 scripts/make_snapshot.sh create mode 100644 scripts/selectROI.py delete mode 100644 scripts/speedseq.filter.awk diff --git a/.travis.yml b/.travis.yml index 08f48f99a3..4db211fa00 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ before_install: # PRs to master are only ok if coming from dev branch - '[ $TRAVIS_PULL_REQUEST = "false" ] || [ $TRAVIS_BRANCH != "master" ] || ([ $TRAVIS_PULL_REQUEST_SLUG = $TRAVIS_REPO_SLUG ] && [ $TRAVIS_PULL_REQUEST_BRANCH = "dev" ])' # Pull the docker image first so the test doesn't wait for this - - "travis_retry ./scripts/download_docker.sh --test $TEST" + - "travis_retry ./scripts/download_image.sh -n docker --test $TEST" install: # Install Nextflow diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a0c68eccd..a3f5c33d86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,429 @@ # nf-core/sarek: Changelog -## v2.5dev - [date] -Initial release of nf-core/sarek, created with the [nf-core](http://nf-co.re/) template. +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## Unreleased +Initial release of `nf-core/sarek`, created with the [nf-core](http://nf-co.re/) template. + +### `Added` +- [#2](https://github.com/nf-core/sarek/pull/2) - Create `nf-core/sarek` `environment.yml` file +- [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#7](https://github.com/nf-core/sarek/pull/7), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Add CI for `nf-core/sarek` +- [#3](https://github.com/nf-core/sarek/pull/3) - Add preprocessing to `nf-core/sarek` +- [#4](https://github.com/nf-core/sarek/pull/4) - Add variant calling to `nf-core/sarek` with `HaplotypeCaller`, and single mode `Manta` and `Strelka` +- [#5](https://github.com/nf-core/sarek/pull/5) - Add variant calling to `nf-core/sarek` with `Manta`, `Strelka`, `Strelka Best Practices`, `MuTecT2`, `FreeBayes`, `ASCAT`, `ControlFREEC` +- [#6](https://github.com/nf-core/sarek/pull/6) - Add default containers for annotation to `nf-core/sarek` +- [#7](https://github.com/nf-core/sarek/pull/7) - Add annotation +- [#7](https://github.com/nf-core/sarek/pull/7) - Add MultiQC +- [#7](https://github.com/nf-core/sarek/pull/7) - Add social preview image in `png` and `svg` format +- [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#11](https://github.com/nf-core/sarek/pull/11) - Add helper script `run_tests.sh` to run different tests +- [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9) - Add automatic build of specific containers for annotation for `GRCh37`, `GRCh38` and `GRCm38` using `CircleCI` +- [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11) - Add helper script `build_reference.sh` to build small reference from [nf-core/test-datasets:sarek](https://github.com/nf-core/test-datasets/tree/sarek) +- [#7](https://github.com/nf-core/sarek/pull/7), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Add helper script `download_image.sh` to download containers for testing +- [#8](https://github.com/nf-core/sarek/pull/8) - Add test configation for easier testing +- [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11) - Add scripts for `ASCAT` +- [#11](https://github.com/nf-core/sarek/pull/11) - Add automatic build of specific containers for annotation for `CanFam3.1` using `CircleCI` +- [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Add posters and abstracts +- [#12](https://github.com/nf-core/sarek/pull/12) - Use `label` for processes configation +- [#12](https://github.com/nf-core/sarek/pull/12) - Add helper scripts `filter_locifile.py` and `selectROI.py` +- [#12](https://github.com/nf-core/sarek/pull/12) - Add helper script `make_snapshot.sh` to make an archive for usage on a secure cluster + +### `Changed` +- [#1](https://github.com/nf-core/sarek/pull/1), [#2](https://github.com/nf-core/sarek/pull/2), [#3](https://github.com/nf-core/sarek/pull/3), [#4](https://github.com/nf-core/sarek/pull/4), [#5](https://github.com/nf-core/sarek/pull/5), [#6](https://github.com/nf-core/sarek/pull/6), [#7](https://github.com/nf-core/sarek/pull/7), [#8](https://github.com/nf-core/sarek/pull/8), [#9](https://github.com/nf-core/sarek/pull/9), [#11](https://github.com/nf-core/sarek/pull/11), [#12](https://github.com/nf-core/sarek/pull/12) - Update docs +- [#4](https://github.com/nf-core/sarek/pull/4) - Update `cancerit-allelecount` from `2.1.2` to `4.0.2` +- [#4](https://github.com/nf-core/sarek/pull/4) - Update `gatk4` from `4.1.1.0` to `4.1.2.0` +- [#7](https://github.com/nf-core/sarek/pull/7) - `--sampleDir` is now deprecated, use `--sample` instead +- [#7](https://github.com/nf-core/sarek/pull/8) - `--annotateVCF` is now deprecated, use `--sample` instead +- [#8](https://github.com/nf-core/sarek/pull/8), [#12](https://github.com/nf-core/sarek/pull/12) - Improve helper script `build.nf` for downloading and building reference files +- [#9](https://github.com/nf-core/sarek/pull/9) - ApplyBQSR is now parallelized +- [#9](https://github.com/nf-core/sarek/pull/9) - Fastq files are named following "${idRun}_R1.fastq.gz" in the FastQC output for easier reporting +- [#9](https://github.com/nf-core/sarek/pull/9) - Status is now a map with `idpatient`, `idsample` as keys (ie: `status = statusMap[idPatient, idSample]`) +- [#9](https://github.com/nf-core/sarek/pull/9) - Use `ensembl-vep` `95.2` instead of `96.0` +- [#11](https://github.com/nf-core/sarek/pull/11) - Summary HTML from VWP is now in the `Reports` directory +- [#12](https://github.com/nf-core/sarek/pull/12) - Update configuration files +- [#12](https://github.com/nf-core/sarek/pull/12) - Disable `Docker` in `singularity` profile +- [#12](https://github.com/nf-core/sarek/pull/12) - Disable `Singularity` in `docker` profile +- [#12](https://github.com/nf-core/sarek/pull/12) - Disable `Docker` and `Singularity` in `conda` profile +- [#12](https://github.com/nf-core/sarek/pull/12) - Simplify `check_max()` function + +### `Removed` + +- [#9](https://github.com/nf-core/sarek/pull/9) - Removed `relatedness2` graph from `vcftools stats` + +### `Fixed` +- [#3](https://github.com/nf-core/sarek/pull/3) - Fix Docker ownership +- [#11](https://github.com/nf-core/sarek/pull/11) - Fix MergeMpileup PublishDir + +## [2.3.FIX1] - 2019-03-04 + +### `Fixed` +- [#742](https://github.com/SciLifeLab/Sarek/pull/742) - Fix output dirs (HaplotypeCaller that was not recognized by annotate.nf introduced by [#728](https://github.com/SciLifeLab/Sarek/pull/728)) + +## [2.3] - Äpar - 2019-02-27 + +### `Added` +- [#628](https://github.com/SciLifeLab/Sarek/pull/628), [#722](https://github.com/SciLifeLab/Sarek/pull/722) - `ASCAT` now use `.gc` file +- [#712](https://github.com/SciLifeLab/Sarek/pull/712), [#718](https://github.com/SciLifeLab/Sarek/pull/718) - Added possibilities to run Sarek with `conda` +- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - Annotation documentation +- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - Helper script to download `snpeff` and `VEP` cache files +- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - New `--annotation_cache`, `--snpEff_cache`, `--vep_cache` parameters +- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - Possibility to use cache wen annotating with `snpEff` and `VEP` +- [#722](https://github.com/SciLifeLab/Sarek/pull/722) - Add path to ASCAT `.gc` file in `igenomes.config` +- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Update `Sarek-data` submodule with multiple patients TSV file +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Add `cadd_WG_SNVs`, `cadd_WG_SNVs_tbi`, `cadd_InDels`, `cadd_InDels_tbi` and `cadd_cache` params +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Add tabix indexed cache for VEP +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - New `DownloadCADD` process to download CADD files +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Specify values for `cadd_WG_SNVs`, `cadd_WG_SNVs_tbi`, `cadd_InDels`, `cadd_InDels_tbi` and `cadd_cache` params in `munin.conf` file +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Use `cadd_cache` param for optional use of CADD VEP plugin in `annotate.nf` +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - VEP cache has now fasta files for `--HGVS` +- [#735](https://github.com/SciLifeLab/Sarek/pull/735) - Added `--exome` for Manta, and for StrelkaBP +- [#735](https://github.com/SciLifeLab/Sarek/pull/735) - Added Travis CI test for targeted + +### `Changed` + +- [#710](https://github.com/SciLifeLab/Sarek/pull/710) - Improve release checklist and script +- [#711](https://github.com/SciLifeLab/Sarek/pull/711) - Improve configuration priorities +- [#716](https://github.com/SciLifeLab/Sarek/pull/716) - Update paths to containers and iGenomes +- [#717](https://github.com/SciLifeLab/Sarek/pull/717) - `checkFileExtension` has changed to `hasExtension`, and now only verify if file has extension +- [#717](https://github.com/SciLifeLab/Sarek/pull/717) - `fastqFiles` renamed to `inputFiles` +- [#717](https://github.com/SciLifeLab/Sarek/pull/717) - `mapping` step can now map BAM files too +- [#717](https://github.com/SciLifeLab/Sarek/pull/717) - `MapReads` can now convert BAM to FASTQ and feed it to BWA on the fly +- [#717](https://github.com/SciLifeLab/Sarek/pull/717), [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Update documentation +- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - `snpeff` and `vep` containers are now built with conda +- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - `vepCacheVersion` is now defined in `conf/genomes.config` or `conf/igenomes.config` +- [#722](https://github.com/SciLifeLab/Sarek/pull/722) - Add path to ASCAT `.gc` file in `igenomes.config` +- [#722](https://github.com/SciLifeLab/Sarek/pull/722) - Update `Sarek-data` submodule +- [#723](https://github.com/SciLifeLab/Sarek/pull/723), [#725](https://github.com/SciLifeLab/Sarek/pull/725) - Update docs +- [#724](https://github.com/SciLifeLab/Sarek/pull/724) - Improved AwsBatch configuration +- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Improved usage of `targetBED` params +- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Strelka Best Practices output is now prefixed with `StrelkaBP_` +- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - VCFs and Annotated VCFs are now ordered by Patient, then tools +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Merge `buildContainers.nf` and `buildReferences.nf` in `build.nf` +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Reduce number of CPUs for `RunVEP` to `4` cf: [VEP docs](https://www.ensembl.org/info/docs/tools/vep/script/vep_other.html) +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Update VEP from `95.1` to `95.2` + +### `Removed` +- [#715](https://github.com/SciLifeLab/Sarek/pull/715) - Remove `defReferencesFiles` function from `buildReferences.nf` +- [#719](https://github.com/SciLifeLab/Sarek/pull/719) - `snpEff` base container is no longer used +- [#721](https://github.com/SciLifeLab/Sarek/pull/721) - Remove COSMIC docs +- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Remove `defineDirectoryMap()` +- [#732](https://github.com/SciLifeLab/Sarek/pull/732) - Removed `--database` option for VEP cf: [VEP docs](https://www.ensembl.org/info/docs/tools/vep/script/vep_other.html) + +### `Fixed` +- [#720](https://github.com/SciLifeLab/Sarek/pull/720) - bamQC is now run on the recalibrated bams, and not after MarkDuplicates +- [#726](https://github.com/SciLifeLab/Sarek/pull/726) - Fix Ascat ref file input (one file can't be a set) +- [#727](https://github.com/SciLifeLab/Sarek/pull/727) - bamQC outputs are no longer overwritten (name of dir is now the file instead of sample) +- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Fix issue with annotation that was consuming `cache` channels +- [#728](https://github.com/SciLifeLab/Sarek/pull/728) - Fix multi sample TSV file [#691](https://github.com/SciLifeLab/Sarek/issues/691) +- [#733](https://github.com/SciLifeLab/Sarek/pull/733) - Fix the possibility to specify reference files on the command line + +## [2.2.2] - 2018-12-19 + +### `Added` + +- [#671](https://github.com/SciLifeLab/Sarek/pull/671) - New `publishDirMode` param and docs +- [#673](https://github.com/SciLifeLab/Sarek/pull/673), [#675](https://github.com/SciLifeLab/Sarek/pull/675), [#676](https://github.com/SciLifeLab/Sarek/pull/676) - Profiles for BinAC and CFC clusters in Tübingen +- [#679](https://github.com/SciLifeLab/Sarek/pull/679) - Add container for `CreateIntervalBeds` +- [#692](https://github.com/SciLifeLab/Sarek/pull/692), [#697](https://github.com/SciLifeLab/Sarek/pull/697) - Add AWS iGenomes possibilities (within `conf/igenomes.conf`) +- [#694](https://github.com/SciLifeLab/Sarek/pull/694) - Add monochrome and grey logos for light or dark background +- [#698](https://github.com/SciLifeLab/Sarek/pull/698) - Add btb profile for munin server +- [#702](https://github.com/SciLifeLab/Sarek/pull/702) - Add font-ttf-dejavu-sans-mono `2.37` and fontconfig `2.12.6` to container + +### `Changed` + +- [#663](https://github.com/SciLifeLab/Sarek/pull/663) - Update `do_release.sh` script +- [#671](https://github.com/SciLifeLab/Sarek/pull/671) - publishDir modes are now params +- [#677](https://github.com/SciLifeLab/Sarek/pull/677), [#698](https://github.com/SciLifeLab/Sarek/pull/698), [#703](https://github.com/SciLifeLab/Sarek/pull/703) - Update docs +- [#678](https://github.com/SciLifeLab/Sarek/pull/678) - Changing VEP to v92 and adjusting CPUs for VEP +- [#679](https://github.com/SciLifeLab/Sarek/pull/679) - Update old awsbatch configuration +- [#682](https://github.com/SciLifeLab/Sarek/pull/682) - Specifications for memory and cpus for awsbatch +- [#693](https://github.com/SciLifeLab/Sarek/pull/693) - Qualimap bamQC is now ran after mapping and after recalibration for better QC +- [#700](https://github.com/SciLifeLab/Sarek/pull/700) - Update GATK to `4.0.9.0` +- [#702](https://github.com/SciLifeLab/Sarek/pull/702) - Update FastQC to `0.11.8` +- [#705](https://github.com/SciLifeLab/Sarek/pull/705) - Change `--TMP_DIR` by `--tmp-dir` for GATK `4.0.9.0` BaseRecalibrator +- [#706](https://github.com/SciLifeLab/Sarek/pull/706) - Update TravisCI testing + +### `Fixed` + +- [#665](https://github.com/SciLifeLab/Sarek/pull/665) - Input bam file now has always the same name (whether it is from a single fastq pair or multiple) in the MarkDuplicates process, so metrics too +- [#672](https://github.com/SciLifeLab/Sarek/pull/672) - process `PullSingularityContainers` from `buildContainers.nf` now expect a file with the correct `.simg` extension for singularity images, and no longer the `.img` one. +- [#679](https://github.com/SciLifeLab/Sarek/pull/679) - Add publishDirMode for `germlineVC.nf` +- [#700](https://github.com/SciLifeLab/Sarek/pull/700) - Fix [#699](https://github.com/SciLifeLab/Sarek/issues/699) missing DP in the FORMAT column VCFs for MuTect2 +- [#702](https://github.com/SciLifeLab/Sarek/pull/702) - Fix [#701](https://github.com/SciLifeLab/Sarek/issues/701) +- [#705](https://github.com/SciLifeLab/Sarek/pull/705) - Fix [#704](https://github.com/SciLifeLab/Sarek/issues/704) + +## [2.2.1] - 2018-10-04 + +### `Changed` + +- [#646](https://github.com/SciLifeLab/Sarek/pull/646) - Update [`pathfindr`](https://github.com/NBISweden/pathfindr) submodule +- [#659](https://github.com/SciLifeLab/Sarek/pull/659) - Update Nextflow to `0.32.0` +- [#660](https://github.com/SciLifeLab/Sarek/pull/660) - Update docs + +### `Fixed` + +- [#657](https://github.com/SciLifeLab/Sarek/pull/657) - Fix `RunMultiQC.nf` bug +- [#659](https://github.com/SciLifeLab/Sarek/pull/659) - Fix bugs due to updating Nextflow + +## [2.2.0] - Skårki - 2018-09-21 + +### `Added` + +- [#613](https://github.com/SciLifeLab/Sarek/pull/613) - Add Issue Templates (bug report and feature request) +- [#614](https://github.com/SciLifeLab/Sarek/pull/614) - Add PR Template +- [#615](https://github.com/SciLifeLab/Sarek/pull/615) - Add presentation +- [#616](https://github.com/SciLifeLab/Sarek/pull/616) - Update documentation +- [#620](https://github.com/SciLifeLab/Sarek/pull/620) - Add `tmp/` to `.gitignore` +- [#625](https://github.com/SciLifeLab/Sarek/pull/625) - Add [`pathfindr`](https://github.com/NBISweden/pathfindr) as a submodule +- [#635](https://github.com/SciLifeLab/Sarek/pull/635) - To process targeted sequencing with a target BED +- [#639](https://github.com/SciLifeLab/Sarek/pull/639) - Add a complete example analysis to docs +- [#640](https://github.com/SciLifeLab/Sarek/pull/640), [#642](https://github.com/SciLifeLab/Sarek/pull/642) - Add helper script for changing version number + +### `Changed` + +- [#608](https://github.com/SciLifeLab/Sarek/pull/608) - Update Nextflow required version +- [#615](https://github.com/SciLifeLab/Sarek/pull/615) - Use `splitCsv` instead of `readlines` +- [#616](https://github.com/SciLifeLab/Sarek/pull/616) - Update CHANGELOG +- [#621](https://github.com/SciLifeLab/Sarek/pull/621), [#638](https://github.com/SciLifeLab/Sarek/pull/638) - Improve install script +- [#621](https://github.com/SciLifeLab/Sarek/pull/621), [#638](https://github.com/SciLifeLab/Sarek/pull/638) - Simplify tests +- [#627](https://github.com/SciLifeLab/Sarek/pull/627), [#629](https://github.com/SciLifeLab/Sarek/pull/629), [#637](https://github.com/SciLifeLab/Sarek/pull/637) - Refactor docs +- [#629](https://github.com/SciLifeLab/Sarek/pull/629) - Refactor config +- [#632](https://github.com/SciLifeLab/Sarek/pull/632) - Use 2 threads and 2 cpus FastQC processes +- [#637](https://github.com/SciLifeLab/Sarek/pull/637) - Update tool version gathering +- [#638](https://github.com/SciLifeLab/Sarek/pull/638) - Use correct `.simg` extension for Singularity images +- [#639](https://github.com/SciLifeLab/Sarek/pull/639) - Smaller refactoring of the docs +- [#640](https://github.com/SciLifeLab/Sarek/pull/640) - Update RELEASE_CHECKLIST +- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - MultiQC 1.5 -> 1.6 +- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - Qualimap 2.2.2a -> 2.2.2b +- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - Update conda channel order priorities +- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - VCFanno 0.2.8 -> 0.3.0 +- [#642](https://github.com/SciLifeLab/Sarek/pull/642) - VCFtools 0.1.15 -> 0.1.16 + +### `Removed` + +- [#616](https://github.com/SciLifeLab/Sarek/pull/616) - Remove old Issue Template +- [#629](https://github.com/SciLifeLab/Sarek/pull/629) - Remove old Dockerfiles +- [#637](https://github.com/SciLifeLab/Sarek/pull/637) - Remove old comments + +### `Fixed` + +- [#621](https://github.com/SciLifeLab/Sarek/pull/621) - Fix VEP tests +- [#637](https://github.com/SciLifeLab/Sarek/pull/637) - Fix links in MD files + +## [2.1.0] - Ruotes - 2018-08-14 + +### `Added` + +- [#555](https://github.com/SciLifeLab/Sarek/pull/555) - `snpEff` output into `VEP` +- [#556](https://github.com/SciLifeLab/Sarek/pull/556) - `Strelka` Best Practices +- [#563](https://github.com/SciLifeLab/Sarek/pull/563) - Use `SnpEFF` reports in `MultiQC` +- [#568](https://github.com/SciLifeLab/Sarek/pull/568) - `VCFTools` process `RunVcftools` for QC +- [#574](https://github.com/SciLifeLab/Sarek/pull/574), [#580](https://github.com/SciLifeLab/Sarek/pull/580) - Abstracts for NPMI, JOBIM and EACR25 +- [#577](https://github.com/SciLifeLab/Sarek/pull/577) - New repository for testing: [Sarek-data](https://github.com/SciLifeLab/Sarek-data) +- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - New library `QC` for functions `bamQC`, `bcftools`, `samtoolsStats`, `vcftools`, `getVersionBCFtools`, `getVersionGATK`, `getVersionManta`, `getVersionSnpEFF`, `getVersionStrelka`, `getVersionVCFtools`, `getVersionVEP` +- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - New Processes `GetVersionBCFtools`, `GetVersionGATK`, `GetVersionManta`, `GetVersionSnpEFF`, `GetVersionStrelka`, `GetVersionVCFtools`, `GetVersionVEP` +- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - new Python script `bin/scrape_tool_versions.py` inspired by @ewels and @apeltzer +- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - New QC Process `RunVcftools` +- [#596](https://github.com/SciLifeLab/Sarek/pull/596) - New profile for BinAC cluster +- [#597](https://github.com/SciLifeLab/Sarek/pull/597) - New function `sarek_ascii()` in `SarekUtils` +- [#599](https://github.com/SciLifeLab/Sarek/pull/599), [#602](https://github.com/SciLifeLab/Sarek/pull/602) - New Process `CompressVCF` +- [#601](https://github.com/SciLifeLab/Sarek/pull/601), [#603](https://github.com/SciLifeLab/Sarek/pull/603) - Container for GATK4 +- [#606](https://github.com/SciLifeLab/Sarek/pull/606) - Add test data as a submodule from [`Sarek-data`](https://github.com/SciLifeLab/Sarek-data) +- [#608](https://github.com/SciLifeLab/Sarek/pull/608) - Add documentation on how to install Nextflow on `bianca` + +### `Changed` + +- [#557](https://github.com/SciLifeLab/Sarek/pull/557), [#583](https://github.com/SciLifeLab/Sarek/pull/583), [#585](https://github.com/SciLifeLab/Sarek/pull/585), [#588](https://github.com/SciLifeLab/Sarek/pull/588) - Update help +- [#560](https://github.com/SciLifeLab/Sarek/pull/560) - GitHub langage for the repository is now `Nextflow` +- [#561](https://github.com/SciLifeLab/Sarek/pull/561) - `do_all.sh` build only containers for one genome reference (default `GRCh38`) only +- [#571](https://github.com/SciLifeLab/Sarek/pull/571) - Only one container for all QC tools +- [#582](https://github.com/SciLifeLab/Sarek/pull/582), [#587](https://github.com/SciLifeLab/Sarek/pull/587) - Update figures +- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - Function `defineDirectoryMap()` is now part of `SarekUtils` +- [#595](https://github.com/SciLifeLab/Sarek/pull/595) - Process `GenerateMultiQCconfig` replace by function `createMultiQCconfig()` +- [#597](https://github.com/SciLifeLab/Sarek/pull/597) - `extractBams()` now takes an extra parameter. +- [#597](https://github.com/SciLifeLab/Sarek/pull/597) - Move `checkFileExtension()`, `checkParameterExistence()`, `checkParameterList()`, `checkReferenceMap()`, `checkRefExistence()`, `extractBams()`, `extractGenders()`, `returnFile()`, `returnStatus()` and `returnTSV()` functions to `SarekUtils` +- [#597](https://github.com/SciLifeLab/Sarek/pull/597) - Reduce data footprint for Process `CreateRecalibrationTable` +- [#597](https://github.com/SciLifeLab/Sarek/pull/597) - Replace deprecated operator `phase` by `join`. +- [#599](https://github.com/SciLifeLab/Sarek/pull/599) - Merge is tested with `ANNOTATEALL` +- [#604](https://github.com/SciLifeLab/Sarek/pull/604) - Synching `GRCh38` `wgs_calling_regions` bedfiles +- [#607](https://github.com/SciLifeLab/Sarek/pull/607) - One container approach +- [#607](https://github.com/SciLifeLab/Sarek/pull/607) - Update to GATK4 +- [#608](https://github.com/SciLifeLab/Sarek/pull/608) - Update Nextflow required version +- [#616](https://github.com/SciLifeLab/Sarek/pull/616) - Update CHANGELOG +- [#617](https://github.com/SciLifeLab/Sarek/pull/617) - Replace deprecated $name syntax with withName + +### `Fixed` + +- [#560](https://github.com/SciLifeLab/Sarek/pull/560) - Display message for `repository` and `containerPath` +- [#566](https://github.com/SciLifeLab/Sarek/pull/566) - `slurmDownload` profile +- [#579](https://github.com/SciLifeLab/Sarek/pull/579), [#584](https://github.com/SciLifeLab/Sarek/pull/584) - `Manta` output reorganized after modification for `Strelka Best Practices` process +- [#585](https://github.com/SciLifeLab/Sarek/pull/583) - Trace file is plain txt +- [#590](https://github.com/SciLifeLab/Sarek/pull/590), [#593](https://github.com/SciLifeLab/Sarek/pull/593) - Fix Singularity installation in Travis CI testing +- [#598](https://github.com/SciLifeLab/Sarek/pull/598), [#601](https://github.com/SciLifeLab/Sarek/pull/601) - Fixes for Python script `selectROI.py` to work with CLC viewer + +### `Removed` + +- [#607](https://github.com/SciLifeLab/Sarek/pull/607) - Remove Mutect1 + +## [2.0.0] - 2018-03-23 + +### `Added` + +- basic wrapper script +- Abstract, posters and figures +- ROI selector and FreeBayes sanitizer scripts +- New logo and icon for the project +- check for existing tumor/normal channel +- `SarekUtils` with `checkParams()`, `checkParameterList()`, `checkParameterExistence()` and `isAllowedParams()` functions +- some `runOptions` for `docker` (prevent some user right problem) +- This `CHANGELOG` + +### `Changed` + +- `CAW` is now `Sarek` +- Dissect Workflow in 5 new scripts: `annotate.nf`, `main.nf`, `germlineVC.nf`, `runMultiQC.nf` and `somaticVC.nf` +- `report.html`, `timeline.html` and `trace.html` are generated in `Reports/` +- `--version` is now used to define the workflow version +- most params are now defined in the base.config file instead of in the scripts +- update RELEASE_CHECKLIST.md +- `checkParams()`, `checkParameterList()`, `checkParameterExistence()` and `isAllowedParams()` in script functions are now called within `SarekUtils` +- `nf_required_version` is now `params.nfRequiredVersion` +- in `buildReferences.nf` script, channels now begin by `ch_`, and files by `f_` +- use `PublishDir mode: 'link'` instead of `copy` +- `directoryMap` now contains `params.outDir` +- [#539](https://github.com/SciLifeLab/Sarek/issues/539) - use Nextflow support of scratch +- reordered Travis CI tests +- update documentation +- `MultiQC` version in container from v`1.4` to v`1.5` +- `vepgrch37` container base image from `release_90.6` to `release_92` +- `vepgrch38` container base image from `release_90.6` to `release_92` +- `VEP` version in containers from v`90` to v`91` +- `nucleotidesPerSecond` is now `params.nucleotidesPerSecond` +- default `params.tag` is now `latest` instead of current version, so --tag needs to be specified with the right version to be sure of using the `containers` corresponding + +### `Deprecated` + +- `standard` profile +- `uppmax-localhost.config` file + +### `Removed` + +- `scripts/skeleton_batch.sh` +- old data and tsv files +- UPPMAX directories from containers +- `--step` in `annotate.nf`, `germlineVC.nf` and `somatic.nf` +- some `runOptions` for Singularity (binding not needed anymore on UPPMAX) +- `download` profile + +### `Fixed` + +- [#530](https://github.com/SciLifeLab/Sarek/issues/530) - use `$PWD` for default `outDir` +- [#533](https://github.com/SciLifeLab/Sarek/issues/533) - Replace `VEP` `--pick` option by `--per_gene` + +## [1.2.5] - 2018-01-18 + +### `Added` + +- Zenodo for DOI +- Delivery README +- Document use of the `--sampleDir` option +- Contributing Guidelines +- Issue Templates +- Release Checklist +- `--outDir` +- `awsbatch` profile +- `aws-batch.config` config file +- `--noBAMQC` params (failing sometimes on Bianca) + +### `Changed` + +- Update `Nextflow` to `0.26.0` (new fancy report + AWS Batch) +- Extra time on Travis CI testing +- Replace `bundleDir` by `params.genome_base` +- Update `MultiQC` to `1.3` (MEGAQC FTW) +- Move and rename some test files + +### `Fixed` + +- Version of COSMIC GRCh37 v83 +- Write an error message when `--sampleDir` does not find any FASTQ files +- `base.config` for ConcatVCF process +- File specification for recalibrationReport in RecalibrateBam process (got error on AWS Batch) + +## [1.2.4] - 2017-10-27 + +### `Fixed` + +- [#488](https://github.com/SciLifeLab/Sarek/issues/488) - Better CPU requirements for `ConcatVCF` +- [#489](https://github.com/SciLifeLab/Sarek/issues/489) - Exception handling for `ASCAT` +- [#490](https://github.com/SciLifeLab/Sarek/issues/490) - CPU requirements for `runSingleStrelka` and `runSingleManta` + +## [1.2.3] - 2017-10-18 + +### `Fixed` + +- [#357](https://github.com/SciLifeLab/Sarek/issues/357) - `ASCAT` works for GRCh38 +- [#471](https://github.com/SciLifeLab/Sarek/issues/471) - Running `Singularity` on `/scratch` +- [#475](https://github.com/SciLifeLab/Sarek/issues/475) - 16 cpus for local executor +- [#480](https://github.com/SciLifeLab/Sarek/issues/480) - No `tsv` file needed for step `annotate` + +## [1.2.2] - 2017-10-06 + +### `Fixed` + +- [#479](https://github.com/SciLifeLab/Sarek/issues/479) - Typo in `uppmax-localhost.config` + +## [1.2.1] - 2017-10-06 + +### `Changed` + +- `runascat` and `runconvertallelecounts` containers are now replaced by `r-base` +- `willmclaren/ensembl-vep:release_90.5` is now base for `vepgrch37` and `vepgrch38` + +### `Removed` + +- `vep` container +- `strelka_config.ini` file + +### `Fixed` + +- [#471](https://github.com/SciLifeLab/Sarek/issues/471) - Running `Singularity` on /scratch +- [#472](https://github.com/SciLifeLab/Sarek/issues/472) - Update function to check Nextflow version +- [#473](https://github.com/SciLifeLab/Sarek/issues/473) - Remove `returnMin()` function + +## [1.2.0] - 2017-10-02 + +### `Changed` + +- Fix version for Manuscript + +## [1.1] - 2017-09-15 + +### `Added` + +- Singularity possibilities + +### `Changed` + +- Reports made by default +- Intervals file can be a bed file +- Normal sample preprocessing + HaplotypeCaller is possible +- Better Travis CI tests + +### `Fixed` + +- Memory requirements + +## [1.0] - 2017-02-16 + +### `Added` + +- Docker possibilities + +## [0.9] - 2016-11-16 + +## [0.8] - 2016-11-16 + +## [0.1] - 2016-04-05 diff --git a/Jenkinsfile b/Jenkinsfile index 42d6074d46..b4b5aa501f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -8,7 +8,7 @@ pipeline { stages { stage('Docker setup') { steps { - sh "./scripts/download_docker.sh" + sh "./scripts/download_image.sh -n docker -t ALL" } } stage('Build references') { diff --git a/README.md b/README.md index a055578752..d2b544541c 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ The nf-core/sarek pipeline comes with documentation about the pipeline, found in 2. Pipeline configuration * [Local installation](https://nf-co.re/usage/local_installation) * [Adding your own system config](https://nf-co.re/usage/adding_own_config) + * [Install on a secure cluster](docs/install_bianca.md) * [Reference genomes](https://nf-co.re/usage/reference_genomes) * [Extra documentation on reference](docs/reference.md) 3. [Running the pipeline](docs/usage.md) diff --git a/bin/concatenateVCFs.sh b/bin/concatenateVCFs.sh index 89bf9d125e..da01138eed 100755 --- a/bin/concatenateVCFs.sh +++ b/bin/concatenateVCFs.sh @@ -1,48 +1,59 @@ #!/usr/bin/env bash -# this script concatenates all VCFs that are in the local directory: the -# purpose is to make a single VCF from all the VCFs that were created from different intervals +set -euo pipefail + +# This script concatenates all VCF files that are in the local directory, +# that were created from different intervals to make a single final VCF usage() { echo "Usage: $0 [-i genome_index_file] [-o output.file.no.gz.extension] <-t target.bed> <-c cpus>" 1>&2; exit 1; } -while getopts "i:c:o:t:" p; do - case "${p}" in - i) - genomeIndex=${OPTARG} +while [[ $# -gt 0 ]] +do + key=$1 + case $key in + -i) + genomeIndex=$2 + shift # past argument + shift # past value ;; - c) - cpus=${OPTARG} + -c) + cpus=$2 + shift # past argument + shift # past value ;; - o) - outputFile=${OPTARG} + -o) + outputFile=$2 + shift # past argument + shift # past value ;; - t) - targetBED=${OPTARG} + -t) + targetBED=$2 + shift # past argument + shift # past value ;; *) usage + shift # past argument ;; esac done -shift $((OPTIND-1)) if [ -z ${genomeIndex} ]; then echo "Missing index file "; usage; fi if [ -z ${cpus} ]; then echo "No CPUs defined: setting to 1"; cpus=1; fi if [ -z ${outputFile} ]; then echo "Missing output file name"; usage; fi -set -euo pipefail - -# first make a header from one of the VCF intervals -# get rid of interval information only from the GATK command-line, but leave the rest +# First make a header from one of the VCF +# Remove interval information from the GATK command-line, but leave the rest FIRSTVCF=$(ls *.vcf | head -n 1) sed -n '/^[^#]/q;p' $FIRSTVCF | \ awk '!/GATKCommandLine/{print}/GATKCommandLine/{for(i=1;i<=NF;i++){if($i!~/intervals=/ && $i !~ /out=/){printf("%s ",$i)}}printf("\n")}' \ > header -# Get list of contigs from the FASTA index (.fai). We cannot use the ##contig -# header in the VCF as it is optional (FreeBayes does not save it, for example) +# Get list of contigs from the FASTA index (.fai) +# ##contig header in the VCF cannot be used as it is optional (FreeBayes does not save it, for example) + CONTIGS=($(cut -f1 ${genomeIndex})) -# concatenate VCFs in the correct order +# Concatenate VCFs in the correct order ( cat header @@ -72,14 +83,12 @@ tabix rawcalls.vcf.gz set +u -# now we have the concatenated VCF file, check for WES/panel targets, and generate a subset if there is a BED provided -echo "target is $targetBED" +# Now we have the concatenated VCF file, check for WES/panel targets, and generate a subset if there is a BED provided if [ ! -z ${targetBED+x} ]; then - echo "Selecting subset..." + echo "Target is $targetBED - Selecting subset..." bcftools isec --targets-file ${targetBED} rawcalls.vcf.gz | bgzip -@${cpus} > ${outputFile}.gz tabix ${outputFile}.gz else - # simply rename the raw calls as WGS results + # Rename the raw calls as WGS results for f in rawcalls*; do mv -v $f ${outputFile}${f#rawcalls.vcf}; done fi - diff --git a/build.nf b/build.nf index 583fccac5a..bcf1fe38d4 100644 --- a/build.nf +++ b/build.nf @@ -74,15 +74,16 @@ params.vep_cache = null ch_referencesFiles = Channel.empty() -if ((params.build) && (params.offline)) ch_referencesFiles = Channel.fromPath("data/reference/*") -if ((params.build) && (!params.offline)) ch_referencesFiles = ch_referencesFiles.mix( - Channel.fromPath("https://github.com/nf-core/test-datasets/raw/sarek/reference/1000G_phase1.indels.b37.small.vcf.gz"), - Channel.fromPath("https://github.com/nf-core/test-datasets/raw/sarek/reference/1000G_phase3_20130502_SNP_maf0.3.small.loci"), - Channel.fromPath("https://github.com/nf-core/test-datasets/raw/sarek/reference/1000G_phase3_20130502_SNP_maf0.3.small.loci.gc"), - Channel.fromPath("https://github.com/nf-core/test-datasets/raw/sarek/reference/Mills_and_1000G_gold_standard.indels.b37.small.vcf.gz"), - Channel.fromPath("https://github.com/nf-core/test-datasets/raw/sarek/reference/dbsnp_138.b37.small.vcf.gz"), - Channel.fromPath("https://github.com/nf-core/test-datasets/raw/sarek/reference/human_g1k_v37_decoy.small.fasta.gz"), - Channel.fromPath("https://github.com/nf-core/test-datasets/raw/sarek/reference/small.intervals")) +pathToSource = params.offline ? "data/reference/" : "https://github.com/nf-core/test-datasets/raw/sarek/reference" + +if (params.build) ch_referencesFiles = ch_referencesFiles.mix( + Channel.fromPath("${pathToSource}/1000G_phase1.indels.b37.small.vcf.gz"), + Channel.fromPath("${pathToSource}/1000G_phase3_20130502_SNP_maf0.3.small.loci"), + Channel.fromPath("${pathToSource}/1000G_phase3_20130502_SNP_maf0.3.small.loci.gc"), + Channel.fromPath("${pathToSource}/Mills_and_1000G_gold_standard.indels.b37.small.vcf.gz"), + Channel.fromPath("${pathToSource}/dbsnp_138.b37.small.vcf.gz"), + Channel.fromPath("${pathToSource}/human_g1k_v37_decoy.small.fasta.gz"), + Channel.fromPath("${pathToSource}/small.intervals")) ch_referencesFiles = ch_referencesFiles.dump(tag:'Reference Files') @@ -134,7 +135,8 @@ if (params.email) { summary['MultiQC maxsize'] = params.maxMultiqcEmailFileSize } log.info summary.collect { k,v -> "${k.padRight(18)}: $v" }.join("\n") -log.info "\033[2m----------------------------------------------------\033[0m" +if (params.monochrome_logs) log.info "----------------------------------------------------" +else log.info "\033[2m----------------------------------------------------\033[0m" // Check the hostnames against configured profiles checkHostname() @@ -166,7 +168,7 @@ ch_compressedfiles = Channel.create() ch_notCompressedfiles = Channel.create() ch_referencesFiles - .choice(ch_compressedfiles, ch_notCompressedfiles) {it =~ ".(gz|tar.bz2)" ? 0 : 1} + .choice(ch_compressedfiles, ch_notCompressedfiles) {it =~ ".gz" ? 0 : 1} process DecompressFile { tag {f_reference} @@ -178,15 +180,9 @@ process DecompressFile { file("*.{vcf,fasta,loci}") into ch_decompressedFiles script: - realReferenceFile="readlink ${f_reference}" - if (f_reference =~ ".gz") - """ - gzip -d -c \$(${realReferenceFile}) > ${f_reference.baseName} - """ - else if (f_reference =~ ".tar.bz2") - """ - tar xvjf \$(${realReferenceFile}) - """ + """ + gzip -d -c -f ${f_reference} > ${f_reference.baseName} + """ } ch_decompressedFiles = ch_decompressedFiles.dump(tag:'DecompressedFile') @@ -306,7 +302,7 @@ process BuildCache_snpEff { output: file("*") - when: params.snpEff_cache && params.download_cache + when: params.snpEff_cache && params.download_cache && !params.offline script: """ @@ -325,7 +321,7 @@ process BuildCache_VEP { output: file("*") - when: params.vep_cache && params.download_cache + when: params.vep_cache && params.download_cache && !params.offline script: genome = params.genome == "smallGRCh37" ? "GRCh37" : params.genome @@ -363,7 +359,7 @@ process DownloadCADD { output: set file("*.tsv.gz"), file("*.tsv.gz.tbi") - when: params.cadd_cache && params.download_cache + when: params.cadd_cache && params.download_cache && !params.offline script: """ @@ -391,12 +387,12 @@ def nfcoreHeader(){ ${c_blue} |\\ | |__ __ / ` / \\ |__) |__ ${c_yellow}} {${c_reset} ${c_blue} | \\| | \\__, \\__/ | \\ |___ ${c_green}\\`-._,-`-,${c_reset} ${c_green}`._,._,\'${c_reset} - ${c_black} ____ ${c_blue} _____ _ ${c_reset} - ${c_black} .' ${c_green}_${c_black} `. ${c_blue} / ____| | | ${c_reset} - ${c_black} / ${c_green}|\\${c_white}`-_${c_black} \\ ${c_blue} | (___ ___ _ __ __ | | __ ${c_reset} - ${c_black} | ${c_green}| \\ ${c_white}`-${c_black}| ${c_blue} \\___ \\/__ \\| ´__/ _\\| |/ / ${c_reset} - ${c_black} \\ ${c_green}| \\ ${c_black}/ ${c_blue} ____) | __ | | | __| < ${c_reset} - ${c_black} `${c_green}|${c_black}____${c_green}\\${c_black}' ${c_blue} |_____/\\____|_| \\__/|_|\\_\\ ${c_reset} + ${c_white} ____ ${c_blue} _____ _ ${c_reset} + ${c_white} .' _ `. ${c_blue} / ____| | | ${c_reset} + ${c_white} / ${c_green}|\\${c_white}`-_${c_white} \\ ${c_blue} | (___ ___ _ __ __ | | __ ${c_reset} + ${c_white} | ${c_green}| \\ ${c_white}`-${c_white}| ${c_blue} \\___ \\/__ \\| ´__/ _\\| |/ / ${c_reset} + ${c_white} \\ ${c_green}| \\ ${c_white}/ ${c_blue} ____) | __ | | | __| < ${c_reset} + ${c_white} `${c_green}|${c_white}____${c_green}\\${c_white}' ${c_blue} |_____/\\____|_| \\__/|_|\\_\\ ${c_reset} ${c_purple} nf-core/sarek v${workflow.manifest.version}${c_reset} ${c_dim}----------------------------------------------------${c_reset} diff --git a/conf/base.config b/conf/base.config index 14c8f70aef..cb98eb8e6e 100644 --- a/conf/base.config +++ b/conf/base.config @@ -9,27 +9,95 @@ * run on the logged in environment. */ -process { +params { + // Defaults only, expecting to be overwritten + cpus = 10 + igenomes_base = 's3://ngi-igenomes/igenomes/' + markdup_java_options = '"-Xms4000m -Xmx7g"' //Established values for markDuplicate memory consumption, see issue PR #689 for details + max_cpus = 16 // Base specifications + max_memory = 128.GB // Base specifications + max_time = 240.h // Base specifications + singleCPUMem = 7.GB // for processes that are using more memory but a single CPU only. Use the 'core' queue for these +} - // TODO nf-core: Check the defaults for all processes - cpus = { check_max( 1 * task.attempt, 'cpus' ) } - memory = { check_max( 8.GB * task.attempt, 'memory' ) } - time = { check_max( 2.h * task.attempt, 'time' ) } +process { + cpus = {check_max(params.cpus * task.attempt)} + memory = {check_max(15.GB * task.attempt)} + time = {check_max(24.h * task.attempt)} + shell = ['/bin/bash', '-euo', 'pipefail'] - errorStrategy = { task.exitStatus in [143,137,104,134,139] ? 'retry' : 'finish' } + errorStrategy = {task.exitStatus in [143,137,104,134,139] ? 'retry' : 'finish'} maxErrors = '-1' - maxRetries = 1 + maxRetries = 3 - // Process-specific resource requirements - // TODO nf-core: Customise requirements for specific processes. - // See https://www.nextflow.io/docs/latest/config.html#config-process-selectors -} + withLabel:singleCPUmem_x_task { + memory = {check_max(params.singleCPUMem * task.attempt)} + } + withLabel:singleCPUmem_x2_task { + memory = {check_max(params.singleCPUMem * task.attempt * task.attempt)} + } + withLabel:singleCPUmem_2x_task { + memory = {check_max(params.singleCPUMem * 2 * task.attempt)} + } + withLabel:max_cpus { + cpus = {params.max_cpus} + } + withLabel:max_memory { + memory = {check_max(params.max_memory)} + } -params { - // Defaults only, expecting to be overwritten - igenomes_base = 's3://ngi-igenomes/igenomes/' - markdup_java_options = '"-Xms4000m -Xmx7g"' //Established values for markDuplicate memory consumption, see issue PR #689 for details - max_cpus = 16 - max_memory = 128.GB - max_time = 240.h + withName:BamQCmapped { + cpus = {check_max(16)} + } + withName:BamQCrecalibrated { + cpus = {check_max(16)} + } + withName:BaseRecalibrator { + cpus = {check_max(16)} + } + withName:ConcatVCF { + cpus = {check_max(8)} + // For unknown reasons, ConcatVCF sometimes fails with SIGPIPE + // (exit code 141). Rerunning the process will usually work. + errorStrategy = {task.exitStatus == 141 ? 'retry' : 'terminate'} + } + withName:FastQCBAM { + cpus = {check_max(2)} + errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} + } + withName:FastQCFQ { + // FastQC is only capable of running one thread per fastq file. + cpus = {check_max(2)} + errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} + } + withName:GatherBQSRReports { + cpus = {check_max(2)} + } + withName:MapReads { + memory = {check_max(check_max(60.GB * task.attempt))} + } + withName:MarkDuplicates { + cpus = {check_max(16)} + } + withName:MergeBamMapped { + cpus = {check_max(8)} + } + withName:MergeBamRecal { + cpus = {check_max(8)} + } + withName:MultiQC { + errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} + } + withName:SamtoolsStats { + cpus = {check_max(2)} + } + withName:Snpeff { + container = {(params.annotation_cache && params.snpEff_cache) ? 'nfcore/sarek:dev' : "nfcore/sareksnpeff:dev.${params.genome}"} + errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} + } + withName:VEP { + container = {(params.annotation_cache && params.vep_cache) ? 'nfcore/sarek:dev' : "nfcore/sarekvep:dev.${params.genome}"} + cpus = {check_max(4)} + errorStrategy = {task.exitStatus == 143 ? 'retry' : 'ignore'} + } } diff --git a/docs/README.md b/docs/README.md index ca3fe27a91..879c20f793 100644 --- a/docs/README.md +++ b/docs/README.md @@ -6,7 +6,16 @@ The nf-core/sarek documentation is split into the following files: 2. Pipeline configuration * [Local installation](https://nf-co.re/usage/local_installation) * [Adding your own system config](https://nf-co.re/usage/adding_own_config) + * [Install on a secure cluster](install_bianca.md) * [Reference genomes](https://nf-co.re/usage/reference_genomes) + * [Extra documentation on reference](reference.md) 3. [Running the pipeline](usage.md) + * [Examples](use_cases.md) + * [Input files documentation](input.md) + * [Extra documentation on variant calling](variantcalling.md) + * [Documentation about containers](containers.md) + * [Extra documentation for targeted sequencing](targetseq.md) 4. [Output and how to interpret the results](output.md) + * [Complementary information about ASCAT](ascat.md) + * [Extra documentation on annotation](annotation.md) 5. [Troubleshooting](https://nf-co.re/usage/troubleshooting) diff --git a/docs/install_bianca.md b/docs/install_bianca.md new file mode 100644 index 0000000000..667aa850a3 --- /dev/null +++ b/docs/install_bianca.md @@ -0,0 +1,179 @@ +# Installation on a secure cluster + +This small tutorial will explain to you how to install and run nf-core/sarek on a small sample test data on the Swedish UPPMAX cluster `bianca` made for sensitive data. +It can be followed to install on any similar secure cluster. + +For more information about `bianca`, follow the [`bianca` user guide](http://uppmax.uu.se/support/user-guides/bianca-user-guide/). +For more information about using Singularity with UPPMAX, follow the [Singularity UPPMAX guide](https://www.uppmax.uu.se/support-sv/user-guides/singularity-user-guide/). + +## Install Nextflow + +```bash +# Connect to rackham +> ssh -AX [USER]@rackham.uppmax.uu.se +# Or just open a terminal + +# Download the all Nextflow bundle +> wget https://github.com/nextflow-io/nextflow/releases/download/v[xx.yy.zz]/nextflow-[xx.yy.zz]-all + +# Send to bianca (here using sftp) +# For FileZilla follow the bianca user guide +> sftp [USER]-[PROJECT]@bianca-sftp.uppmax.uu.se:[USER]-[PROJECT] +> put nextflow-[xx.yy.zz]-all + +# Exit sftp +> exit + +# Connect to bianca +> ssh -A [USER]-[PROJECT]@bianca.uppmax.uu.se + +# Go to your project +> cd /castor/project/proj_nobackup + +# Make directory for Nextflow +> mkdir tools +> mkdir tools/nextflow + +# Move Nextflow from wharf to its directory +> mv /castor/project/proj_nobackup/wharf/[USER]/[USER]-[PROJECT]/nextflow-[xx.yy.zz]-all /castor/project/proj_nobackup/tools/nextflow + +# Establish permission +> chmod a+x /castor/project/proj_nobackup/tools/nextflow/nextflow-[xx.yy.zz]-all + +# If you want other people to use it +# Be sure that your group has rights to the directory as well + +> chown -R .[PROJECT] /castor/project/proj_nobackup/tools/nextflow/nextflow-[xx.yy.zz]-all + +# Make a link to it +> ln -s /castor/project/proj_nobackup/tools/nextflow/nextflow-[xx.yy.zz]-all /castor/project/proj_nobackup/tools/nextflow/nextflow + +# And everytime you're launching Nextflow, don't forget to export the following ENV variables +# Or add them to your .bashrc file +> export NXF_HOME=/castor/project/proj/nobackup/tools/nextflow/ +> export PATH=${NXF_HOME}:${PATH} +> export NXF_TEMP=$SNIC_TMP +> export NXF_LAUNCHER=$SNIC_TMP +> export NXF_SINGULARITY_CACHEDIR=/sw/data/uppnex/ToolBox/sarek +``` + +## Install nf-core/sarek + +nf-core/sarek use Singularity containers to package all the different tools. +All containers, and all Reference files are already stored on UPPMAX. + +As `bianca` is secure, no direct download is available, so nf-core/sarek will have to be installed and updated manually. + +You can either download nf-core/sarek on your computer or on `rackham`, make an archive, and send it to `bianca` using `FileZilla` or `sftp` given your preferences. + +```bash +# Connect to rackham +> ssh -AX [USER]@rackham.uppmax.uu.se +# Or just open a terminal + +# Clone the repository +> git clone https://github.com/nf-core/sarek.git + +# Go to the newly created directory +> cd sarek + +# It is also possible to checkout a specific version using +> git checkout + +# You also include the nf-core/test-datasets and nf-core/configs using git-archive-all +# Install pip +> curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py +> python get-pip.py + +# If it fails due to permission, you could consider using +> python get-pip.py --user + +# Install git-archive-all using pip +> pip install git-archive-all +# If you used --user before, you might want to do that here too +> pip install git-archive-all --user +> ./scripts/makeSnapshot.sh --include-test-data --include-configs + +# Or you can just include nf-core/sarek: +> ./scripts/makeSnapshot.sh + +# You will get this message in your terminal +Wrote sarek-[snapID].tar.gz + +# Send the archive to bianca (here using sftp) +# For FileZilla follow the bianca user guide +> sftp [USER]-[PROJECT]@bianca-sftp.uppmax.uu.se:[USER]-[PROJECT] +> put sarek-[snapID].tar.gz +> exit + +# The archive will be in the wharf folder in your user home on your bianca project + +# Connect to bianca +> ssh -A [USER]-[PROJECT]@bianca.uppmax.uu.se + +# Go to your project +> cd /castor/project/proj_nobackup + +# Make and go into a nf-core/sarek directoy (where you will store all nf-core/sarek versions) +> mkdir sarek +> cd sarek + +# Copy the tar from wharf to the project +> cp /castor/project/proj_nobackup/wharf/[USER]/[USER]-[PROJECT]/sarek-[snapID].tgz /castor/project/proj_nobackup/sarek + +# extract the archive. Also remember to extract the containers you uploaded. +> tar xvzf sarek-[snapID].tgz + +# If you want other people to use it, +# Be sure that your group has rights to the directory as well +> chown -R .[PROJECT] sarek-[snapID] + +# Make a symbolic link to the extracted repository +> ln -s sarek-[snapID] default +``` + +The principle is to have every member of your project to be able to use the same nf-core/sarek version at the same time. +So every member of the project who wants to use nf-core/sarek will need to do: + +```bash +# Connect to bianca +> ssh -A [USER]-[PROJECT]@bianca.uppmax.uu.se + +# Go to your user directory +> cd /home/[USER] + +# Make a symbolic link to the default nf-core/sarek +> ln -s /castor/project/proj_nobackup/sarek/default sarek +``` + +And then nf-core/sarek can be used with: + +```bash +> nextflow run ~/sarek/main.nf -c ~/sarek/configs/conf/uppmax.config --project [PROJECT] --genome [GENOME ASSEMBLY] ... +``` + +This is an example of how to run sarek with the tool Manta and the genome assembly version GRCh38: + +```bash +> nextflow run ~/sarek/main.nf -c ~/sarek/configs/conf/uppmax.config --project [PROJECT] --tools Manta --sample [SAMPLE.TSV] --genome GRCh38 +``` + +## Update nf-core/sarek + +Repeat the same steps as for installing nf-core/sarek, and once the tar has been extracted, you can replace the link. + +```bash +# Connect to bianca (Connect to rackham first if needed) +> ssh -A [USER]-[PROJECT]@bianca.uppmax.uu.se + +# Go to the sarek directory in your project +> cd /castor/project/proj_nobackup/sarek + +# Remove link +> rm default + +# Link to new nf-core/sarek version +> ln -s sarek-[NEWsnapID] default +``` + +You can for example keep a `default` version that you are sure is working, an make a link for a `testing` or `development` diff --git a/docs/output.md b/docs/output.md index 08bd9b3b66..2987103493 100644 --- a/docs/output.md +++ b/docs/output.md @@ -97,7 +97,6 @@ Recalibrated BAM files can also be used as an input to start the Variant Calling ### FreeBayes [FreeBayes](https://github.com/ekg/freebayes) is a Bayesian genetic variant detector designed to find small polymorphisms, specifically SNPs, indels, MNPs, and complex events smaller than the length of a short-read sequencing alignment.. -The single VCF file generated by `FreeBayes` being huge, it is recommended to flatten and filter this VCF, i.e. using the provided [SpeedSeq](https://github.com/nf-core/sarek/blob/master/scripts/speedseq.filter.awk) filter. For further reading and documentation see the [FreeBayes manual](https://github.com/ekg/freebayes/blob/master/README.md#user-manual-and-guide). diff --git a/docs/posters/ESHG_2019.pdf b/docs/posters/ESHG_2019.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d65b0415f4a7d2228bb5c086bb7692a0cd7f934d GIT binary patch literal 341880 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

-${summary.collect { k,v -> "
$k
${v ?: 'N/A'}
" }.join("\n")} -