Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.8.0] bigbio/quantms - [Unreleased]

### `Deprecations`

- **BREAKING: Deprecated OpenMS experimental design format as input**: The pipeline now only accepts SDRF (Sample to Data Relation Format) files as input. The OpenMS experimental design format (`.tsv` without SDRF structure) is no longer supported. All input files are now treated as SDRF regardless of file extension. Supported file extensions for SDRF input are `.sdrf`, `.tsv`, and `.csv`. This change aligns with nf-core best practices and simplifies input handling for cloud storage interfaces like Seqera Datastudios and Explorer. Users must convert their OpenMS experimental design files to SDRF format. The `--labelling_type` and `--acquisition_method` parameters are no longer used for determining input file type - all information must be specified in the SDRF file.

## [1.7.0] bigbio/quantms - [08/01/2026] - [Caracas]

### `Added`
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ Have a look at public datasets that were already annotated [here](https://github
Those SDRFs should be ready for one-command re-analysis and you can just use the URL to the file on GitHub,
e.g., `https://raw.githubusercontent.com/bigbio/proteomics-sample-metadata/master/annotated-projects/PXD000396/PXD000396.sdrf.tsv`.
If you create your own, please adhere to the specifications and point the pipeline to your local folder or a remote location where you uploaded it to.
The SDRF file can have `.sdrf`, `.tsv`, or `.csv` extensions.

The second requirement is a protein sequence database. We suggest downloading a database for the organism(s)/proteins of interest from [Uniprot](https://www.uniprot.org/proteomes?query=*).

Expand Down
2 changes: 1 addition & 1 deletion conf/tests/test_lfq.config
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ params {

// Input data
labelling_type = "label free sample"
input = 'https://raw.githubusercontent.com/bigbio/quantms-test-datasets/quantms/testdata/lfq_ci/BSA/BSA_design_urls.tsv'
input = 'https://raw.githubusercontent.com/bigbio/quantms-test-datasets/refs/heads/quantms/testdata/lfq_ci/BSA/BSA_design.sdrf.tsv'
database = 'https://raw.githubusercontent.com/bigbio/quantms-test-datasets/quantms/testdata/lfq_ci/BSA/18Protein_SoCe_Tr_detergents_trace_target_decoy.fasta'
search_engines = "comet,sage"
decoy_string= "rev"
Expand Down
5 changes: 1 addition & 4 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ The typical command for running the pipeline is as follows:
nextflow run bigbio/quantms --input '/url/path/to/your/experiment_design.sdrf.tsv' --database '/url/path/to/your/proteindatabase.fasta' --outdir './results' -profile docker
```

where the experimental design file has to be one of:

- [Sample-to-data-relationship format](https://pubs.acs.org/doi/abs/10.1021/acs.jproteome.0c00376) (.sdrf.tsv)
- [OpenMS experimental design format](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/release/latest/html/classOpenMS_1_1ExperimentalDesign.html#details) (.tsv)
The input file must be in [Sample-to-data-relationship format (SDRF)](https://pubs.acs.org/doi/abs/10.1021/acs.jproteome.0c00376) and can have `.sdrf`, `.tsv`, or `.csv` file extensions.

### Supported file formats

Expand Down
22 changes: 16 additions & 6 deletions modules/local/samplesheet_check/main.nf
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,39 @@ process SAMPLESHEET_CHECK {

input:
path input_file
val is_sdrf
val validate_ontologies

output:
path "*.log", emit: log
path "${input_file}", emit: checked_file
path "*.sdrf.tsv", includeInputs: true, emit: checked_file
path "versions.yml", emit: versions

when:
task.ext.when == null || task.ext.when

script: // This script is bundled with the pipeline, in bigbio/quantms/bin/
// TODO validate experimental design file
script:
def args = task.ext.args ?: ''
def string_skip_sdrf_validation = params.validate_ontologies == false ? "--skip_sdrf_validation" : ""
def string_skip_ms_validation = params.skip_ms_validation == true ? "--skip_ms_validation" : ""
def string_skip_factor_validation = params.skip_factor_validation == true ? "--skip_factor_validation" : ""
def string_skip_experimental_design_validation = params.skip_experimental_design_validation == true ? "--skip_experimental_design_validation" : ""
def string_use_ols_cache_only = params.use_ols_cache_only == true ? "--use_ols_cache_only" : ""
def string_is_sdrf = is_sdrf == true ? "--is_sdrf" : ""

"""
quantmsutilsc checksamplesheet --exp_design "${input_file}" ${string_is_sdrf} \\
# Get basename and create output filename
BASENAME=\$(basename "${input_file}")
# Remove .sdrf.tsv, .sdrf.csv, or .sdrf extension (in that order to match longest first)
BASENAME=\$(echo "\$BASENAME" | sed -E 's/\\.sdrf\\.(tsv|csv)\$//' | sed -E 's/\\.sdrf\$//')
OUTPUT_FILE="\${BASENAME}.sdrf.tsv"

# Convert CSV to TSV if needed using pandas
if [[ "${input_file}" == *.csv ]]; then
python -c "import pandas as pd; df = pd.read_csv('${input_file}'); df.to_csv('\$OUTPUT_FILE', sep='\\t', index=False)"
elif [[ "${input_file}" != "\$OUTPUT_FILE" ]]; then
cp "${input_file}" "\$OUTPUT_FILE"
fi

quantmsutilsc checksamplesheet --exp_design "\$OUTPUT_FILE" --is_sdrf \\
${string_skip_sdrf_validation} \\
${string_skip_ms_validation} \\
${string_skip_factor_validation} \\
Expand Down
7 changes: 2 additions & 5 deletions modules/local/samplesheet_check/meta.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ input:
- meta: input_file
type: file
description: Input samplesheet or experimental design file
pattern: "*.{tsv,txt,csv}"
- meta: is_sdrf
type: boolean
description: Whether the input file is in SDRF format
pattern: "*.{tsv,csv,sdrf}"
- meta: validate_ontologies
type: boolean
description: Whether to validate ontologies
Expand All @@ -26,7 +23,7 @@ output:
- meta: checked_file
type: file
description: Validated input file
pattern: "*.{tsv,txt,csv}"
pattern: "*.{sdrf.tsv}"
- meta: versions
type: file
description: File containing software versions
Expand Down
16 changes: 8 additions & 8 deletions nextflow_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
"type": "string",
"format": "file-path",
"exists": true,
"mimetype": "text/tsv",
"pattern": "^\\S+\\.(?:tsv|sdrf)$",
"description": "URI/path to an [SDRF](https://github.com/bigbio/proteomics-metadata-standard/tree/master/annotated-projects) file (.sdrf.tsv) **OR** [OpenMS-style experimental design](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/release/latest/html/classOpenMS_1_1ExperimentalDesign.html#details) with paths to spectra files (.tsv)",
"help_text": "Input is specified by using a path or URI to a PRIDE Sample to Data Relation Format file (SDRF), e.g. as part of a submitted and\nannotated PRIDE experiment (see [here](https://github.com/bigbio/proteomics-metadata-standard/tree/master/annotated-projects) for examples). Input files will be downloaded and cached from the URIs specified in the SDRF file.\nAn OpenMS-style experimental design will be generated based on the factor columns of the SDRF. The settings for the\nfollowing parameters will currently be overwritten by the ones specified in the SDRF:\n\n * `fixed_mods`,\n * `variable_mods`,\n * `precursor_mass_tolerance`,\n * `precursor_mass_tolerance_unit`,\n * `fragment_mass_tolerance`,\n * `fragment_mass_tolerance_unit`,\n * `fragment_method`,\n * `enzyme`\n You can also specify an [OpenMS-style experimental design](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/release/latest/html/classOpenMS_1_1ExperimentalDesign.html#details) directly (.tsv ending). In this case, the aforementioned parameters have to be specified or defaults will be used.",
"mimetype": "text/csv",
"pattern": "^\\S+\\.(?:csv|tsv|sdrf)$",
"description": "URI/path to an SDRF file in SDRF format with .sdrf, .tsv, or .csv extension. For more info see help text or docs.",
"help_text": "Input is specified by using a path or URI to a PRIDE Sample to Data Relation Format file (SDRF), e.g. as part of a submitted and annotated PRIDE experiment (see [here](https://github.com/bigbio/proteomics-metadata-standard/tree/master/annotated-projects) for examples). Input files will be downloaded and cached from the URIs specified in the SDRF file.\n\nThe SDRF file can have .sdrf, .tsv, or .csv extensions. An OpenMS-style experimental design will be generated based on the factor columns of the SDRF. The settings for the following parameters will currently be overwritten by the ones specified in the SDRF:\n\n * `fixed_mods`,\n * `variable_mods`,\n * `precursor_mass_tolerance`,\n * `precursor_mass_tolerance_unit`,\n * `fragment_mass_tolerance`,\n * `fragment_mass_tolerance_unit`,\n * `fragment_method`,\n * `enzyme`",
"fa_icon": "fas fa-file-csv"
},
"outdir": {
Expand All @@ -43,16 +43,16 @@
},
"root_folder": {
"type": "string",
"description": "Root folder in which the spectrum files specified in the SDRF/design are searched",
"description": "Root folder in which the spectrum files specified in the SDRF are searched",
"fa_icon": "fas fa-folder",
"help_text": "This optional parameter can be used to specify a root folder in which the spectrum files specified in the SDRF/design are searched.\nIt is usually used if you have a local version of the experiment already. Note that this option does not support recursive\nsearching yet."
"help_text": "This optional parameter can be used to specify a root folder in which the spectrum files specified in the SDRF are searched.\nIt is usually used if you have a local version of the experiment already. Note that this option does not support recursive\nsearching yet."
},
"local_input_type": {
"type": "string",
"description": "Overwrite the file type/extension of the filename as specified in the SDRF/design",
"description": "Overwrite the file type/extension of the filename as specified in the SDRF",
"fa_icon": "fas fa-file-invoice",
"default": "mzML",
"help_text": "If the above [`--root_folder`](#root_folder) was given to load local input files, this overwrites the file type/extension of\nthe filename as specified in the SDRF/design. Usually used in case you have an mzML-converted version of the files already. Needs to be\none of 'mzML', 'raw', 'd', or 'dia' (the letter cases should match your files exactly). Compressed variants (.gz, .tar, .tar.gz, .zip) are supported for 'mzML', 'raw', and 'd' formats."
"help_text": "If the above [`--root_folder`](#root_folder) was given to load local input files, this overwrites the file type/extension of\nthe filename as specified in the SDRF. Usually used in case you have an mzML-converted version of the files already. Needs to be\none of 'mzML', 'raw', 'd', or 'dia' (the letter cases should match your files exactly). Compressed variants (.gz, .tar, .tar.gz, .zip) are supported for 'mzML', 'raw', and 'd' formats."
},
"acquisition_method": {
"type": "string",
Expand Down
143 changes: 54 additions & 89 deletions subworkflows/local/create_input_channel/main.nf
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,34 @@
// Create channel for input file
//
include { SDRF_PARSING } from '../../../modules/local/sdrf_parsing/main'
include { PREPROCESS_EXPDESIGN } from '../../../modules/local/preprocess_expdesign'



workflow CREATE_INPUT_CHANNEL {
take:
ch_sdrf_or_design
is_sdrf
ch_sdrf

main:
ch_versions = channel.empty()

if (is_sdrf.toString().toLowerCase().contains("true")) {
SDRF_PARSING(ch_sdrf_or_design)
ch_versions = ch_versions.mix(SDRF_PARSING.out.versions)
ch_config = SDRF_PARSING.out.ch_sdrf_config_file

ch_expdesign = SDRF_PARSING.out.ch_expdesign
}
else {
PREPROCESS_EXPDESIGN(ch_sdrf_or_design)
ch_versions = ch_versions.mix(PREPROCESS_EXPDESIGN.out.versions)

ch_config = PREPROCESS_EXPDESIGN.out.ch_config
ch_expdesign = PREPROCESS_EXPDESIGN.out.ch_expdesign
}
// Always parse as SDRF (OpenMS experimental design format deprecated)
SDRF_PARSING(ch_sdrf)
ch_versions = ch_versions.mix(SDRF_PARSING.out.versions)
ch_config = SDRF_PARSING.out.ch_sdrf_config_file
ch_expdesign = SDRF_PARSING.out.ch_expdesign

def Set enzymes = []
def Set files = []

// TODO remove. We can't use the variable to direct channels anyway
def wrapper = [
labelling_type: "",
acquisition_method: "",
experiment_id: ch_sdrf_or_design,
experiment_id: ch_sdrf,
]

if (is_sdrf.toString().toLowerCase().contains("false")) {
log.info("No SDRF given. Using parameters to determine tolerance, enzyme, mod. and labelling settings")
}

ch_config
.splitCsv(header: true, sep: '\t')
.map { row -> create_meta_channel(row, is_sdrf, enzymes, files, wrapper) }
.map { row -> create_meta_channel(row, enzymes, files, wrapper) }
.branch { item ->
ch_meta_config_dia: item[0].acquisition_method.contains("dia")
ch_meta_config_iso: item[0].labelling_type.contains("tmt") || item[0].labelling_type.contains("itraq")
Expand All @@ -65,20 +49,16 @@ workflow CREATE_INPUT_CHANNEL {
}

// Function to get list of [meta, [ spectra_files ]]
def create_meta_channel(LinkedHashMap row, is_sdrf, enzymes, files, wrapper) {
def create_meta_channel(LinkedHashMap row, enzymes, files, wrapper) {
def meta = [:]
def filestr

if (is_sdrf.toString().toLowerCase().contains("false")) {
filestr = row.Spectra_Filepath.toString()
// Always use SDRF format
if (!params.root_folder) {
filestr = row.URI.toString()
}
else {
if (!params.root_folder) {
filestr = row.URI.toString()
}
else {
filestr = row.Filename.toString()
}
filestr = row.Filename.toString()
}

meta.mzml_id = file(filestr).name.take(file(filestr).name.lastIndexOf('.'))
Expand All @@ -92,72 +72,57 @@ def create_meta_channel(LinkedHashMap row, is_sdrf, enzymes, files, wrapper) {
: filestr)
}



// existence check
if (!file(filestr).exists()) {
exit(1, "ERROR: Please check input file -> File Uri does not exist!\n${filestr}")
}

// for sdrf read from config file, without it, read from params
if (is_sdrf.toString().toLowerCase().contains("false")) {
meta.labelling_type = params.labelling_type
meta.dissociationmethod = params.ms2_fragment_method
meta.fixedmodifications = params.fixed_mods
meta.variablemodifications = params.variable_mods
meta.precursormasstolerance = params.precursor_mass_tolerance
meta.precursormasstoleranceunit = params.precursor_mass_tolerance_unit
meta.fragmentmasstolerance = params.fragment_mass_tolerance
meta.fragmentmasstoleranceunit = params.fragment_mass_tolerance_unit
meta.enzyme = params.enzyme
meta.acquisition_method = params.acquisition_method
// Read metadata from SDRF config file
if (row["Proteomics Data Acquisition Method"].toString().toLowerCase().contains("data-dependent acquisition")) {
meta.acquisition_method = "dda"
}
else if (row["Proteomics Data Acquisition Method"].toString().toLowerCase().contains("data-independent acquisition")) {
meta.acquisition_method = "dia"
}
else {
if (row["Proteomics Data Acquisition Method"].toString().toLowerCase().contains("data-dependent acquisition")) {
meta.acquisition_method = "dda"
}
else if (row["Proteomics Data Acquisition Method"].toString().toLowerCase().contains("data-independent acquisition")) {
meta.acquisition_method = "dia"
}
else {
log.error("Currently DIA and DDA are supported for the pipeline. Check and Fix your SDRF.")
exit(1)
}
log.error("Currently DIA and DDA are supported for the pipeline. Check and Fix your SDRF.")
exit(1)
}

// dissociation method conversion
if (row.DissociationMethod == "COLLISION-INDUCED DISSOCIATION") {
meta.dissociationmethod = "CID"
}
else if (row.DissociationMethod == "HIGHER ENERGY BEAM-TYPE COLLISION-INDUCED DISSOCIATION") {
meta.dissociationmethod = "HCD"
}
else if (row.DissociationMethod == "ELECTRON TRANSFER DISSOCIATION") {
meta.dissociationmethod = "ETD"
}
else if (row.DissociationMethod == "ELECTRON CAPTURE DISSOCIATION") {
meta.dissociationmethod = "ECD"
}
else {
meta.dissociationmethod = row.DissociationMethod
}
// dissociation method conversion
if (row.DissociationMethod == "COLLISION-INDUCED DISSOCIATION") {
meta.dissociationmethod = "CID"
}
else if (row.DissociationMethod == "HIGHER ENERGY BEAM-TYPE COLLISION-INDUCED DISSOCIATION") {
meta.dissociationmethod = "HCD"
}
else if (row.DissociationMethod == "ELECTRON TRANSFER DISSOCIATION") {
meta.dissociationmethod = "ETD"
}
else if (row.DissociationMethod == "ELECTRON CAPTURE DISSOCIATION") {
meta.dissociationmethod = "ECD"
}
else {
meta.dissociationmethod = row.DissociationMethod
}

wrapper.acquisition_method = meta.acquisition_method
meta.labelling_type = row.Label
meta.fixedmodifications = row.FixedModifications
meta.variablemodifications = row.VariableModifications
meta.precursormasstolerance = Double.parseDouble(row.PrecursorMassTolerance)
meta.precursormasstoleranceunit = row.PrecursorMassToleranceUnit
meta.fragmentmasstolerance = Double.parseDouble(row.FragmentMassTolerance)
meta.fragmentmasstoleranceunit = row.FragmentMassToleranceUnit
meta.enzyme = row.Enzyme

enzymes += row.Enzyme
if (enzymes.size() > 1) {
log.error("Currently only one enzyme is supported for the whole experiment. Specified was '${enzymes}'. Check or split your SDRF.")
log.error(filestr)
exit(1)
}
wrapper.acquisition_method = meta.acquisition_method
meta.labelling_type = row.Label
meta.fixedmodifications = row.FixedModifications
meta.variablemodifications = row.VariableModifications
meta.precursormasstolerance = Double.parseDouble(row.PrecursorMassTolerance)
meta.precursormasstoleranceunit = row.PrecursorMassToleranceUnit
meta.fragmentmasstolerance = Double.parseDouble(row.FragmentMassTolerance)
meta.fragmentmasstoleranceunit = row.FragmentMassToleranceUnit
meta.enzyme = row.Enzyme

enzymes += row.Enzyme
if (enzymes.size() > 1) {
log.error("Currently only one enzyme is supported for the whole experiment. Specified was '${enzymes}'. Check or split your SDRF.")
log.error(filestr)
exit(1)
}

// Nothing to determine for dia. Only LFQ allowed there.
if (!meta.acquisition_method.equals("dia")) {
if (wrapper.labelling_type.equals("")) {
Expand Down
Loading
Loading