diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 32eca5fd3..ba6cb8bb8 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -8,14 +8,14 @@ These are the most common things requested on pull requests (PRs). Remember that PRs should be made against the dev branch, unless you're preparing a pipeline release. -Learn more about contributing: [CONTRIBUTING.md](https://github.com/bigbio/quantms/tree/master/.github/CONTRIBUTING.md) +Learn more about contributing: [CONTRIBUTING.md](https://github.com/bigbio/quantms/tree/master/docs/CONTRIBUTING.md) --> ## 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 you've added a new tool - have you followed the pipeline conventions in the [contribution docs](https://github.com/bigbio/quantms/tree/master/.github/CONTRIBUTING.md) +- [ ] If you've added a new tool - have you followed the pipeline conventions in the [contribution docs](https://github.com/bigbio/quantms/tree/master/docs/CONTRIBUTING.md) - [ ] If necessary, also make a PR on the bigbio/quantms _branch_ on the [nf-core/test-datasets](https://github.com/nf-core/test-datasets) repository. - [ ] Make sure your code lints (`nf-core pipelines lint`). - [ ] Ensure the test suite passes (`nextflow run . -profile test,docker --outdir `). diff --git a/.github/actions/get-shards/action.yml b/.github/actions/get-shards/action.yml index 34085279f..e2833ee97 100644 --- a/.github/actions/get-shards/action.yml +++ b/.github/actions/get-shards/action.yml @@ -21,7 +21,7 @@ runs: using: "composite" steps: - name: Install nf-test - uses: nf-core/setup-nf-test@v1 + uses: nf-core/setup-nf-test@4069fbbaabe94c08faba4ad261bfa88225ba133f # v2 with: version: ${{ env.NFT_VER }} - name: Get number of shards diff --git a/.github/actions/nf-test/action.yml b/.github/actions/nf-test/action.yml index 3b9724c76..ad686e8e8 100644 --- a/.github/actions/nf-test/action.yml +++ b/.github/actions/nf-test/action.yml @@ -20,24 +20,24 @@ runs: using: "composite" steps: - name: Setup Nextflow - uses: nf-core/setup-nextflow@v2 + uses: nf-core/setup-nextflow@b4ec1bc7c16a94435159de94a05253542fddf6ef # v3 with: version: "${{ env.NXF_VERSION }}" - name: Set up Python - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: python-version: "3.14" - name: Install nf-test - uses: nf-core/setup-nf-test@v1 + uses: nf-core/setup-nf-test@4069fbbaabe94c08faba4ad261bfa88225ba133f # v2 with: version: "${{ env.NFT_VER }}" install-pdiff: true - name: Setup apptainer if: contains(inputs.profile, 'singularity') - uses: eWaterCycle/setup-apptainer@main + uses: eWaterCycle/setup-apptainer@3f706d898c9db585b1d741b4692e66755f3a1b40 # v2 - name: Set up Singularity if: contains(inputs.profile, 'singularity') @@ -48,7 +48,7 @@ runs: - name: Conda setup if: contains(inputs.profile, 'conda') - uses: conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830 # v3 + uses: conda-incubator/setup-miniconda@8ee1f361103df19b6f8c8655fd3967a8ecb162d5 # v4 with: auto-update-conda: true conda-solver: libmamba diff --git a/.github/skills/sdrf/SKILL.md b/.github/skills/sdrf/SKILL.md new file mode 100644 index 000000000..05ab396b2 --- /dev/null +++ b/.github/skills/sdrf/SKILL.md @@ -0,0 +1,586 @@ +--- +name: Create SDRF +description: Create a sample-to-data-relationship format (SDRF) file (usually from another type of samplesheet) +--- + +Create a sample-to-data-relationship format file based on the specification document. By default +generate a csv. Quote where necessary. If required columns are missing, let the user know and provide help +in further filling by asking questions. In the end, self-validate the file by doing: + +```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +uvx --from sdrf-pipelines parse_sdrf validate-sdrf -s $YOUR_GENERATED_SDRF +``` + +Additional online resources: + +- https://github.com/bigbio/proteomics-sample-metadata (specification repo) +- https://github.com/bigbio/proteomics-metadata-standard/tree/master/annotated-projects (example annotated projects) +- https://github.com/bigbio/sdrf-pipelines (python validator) + +Specification document: + +[[status]] +== Status of this document + +This document provides information to the proteomics community about a proposed standard for sample metadata annotations in public repositories called Sample and Data Relationship File (SDRF)-Proteomics format. Distribution is unlimited. + +**Version 1.0.1** - 2023-05-24 + +[[abstract]] +== Abstract + +The Human Proteome Organisation (HUPO) Proteomics Standards Initiative (PSI) defines community standards for data representation in proteomics to facilitate data comparison, exchange, and verification. This document presents a specification for a sample metadata annotation of proteomics experiments. + +Further detailed information, including any updates to this document, implementations, and examples is available at https://github.com/bigbio/proteomics-metadata-standard. The official PSI web page for the document is the following: http://psidev.info/sdrf. + +[[introduction]] +== Introduction + +Many resources have emerged that provide raw or integrated proteomics data in the public domain. If these are valuable individually, their integration through re-analysis represents a huge asset for the community [1]. Unfortunately, proteomics experimental design and sample related information are often missing in public repositories or stored in very diverse ways and formats. For example, the CPTAC consortium (https://cptac-data-portal.georgetown.edu/) provides for every dataset a set of Excel files with the information on each sample (e.g. https://cptac-data-portal.georgetown.edu/study-summary/S048) including tumor size, origin, but also how every sample is related to a specific raw file (e.g. instrument configuration parameters). As a resource routinely re-analysing public datasets, ProteomicsDB, captures for each sample in the database a minimum number of properties to describe the sample and the related experimental protocol such as tissue, digestion method and instrument (e.g. https://www.proteomicsdb.org/#projects/4267/6228). Such heterogeneity often prevents data interpretation, reproducibility, and integration of data from different resources. This is why we propose a homogenous standard for proteomics metadata annotation. For every proteomics dataset we propose to capture at least three levels of metadata: (i) dataset description, (ii) the sample and data files related information; and (iii) the technical/proteomics specific information in standard data file formats (e.g. the PSI formats mzIdentML, mzML, or mzTab, among others). + +The general description includes minimum information to describe the study overall: title, description, date of publication, type of experiment (e.g. http://proteomecentral.proteomexchange.org/cgi/GetDataset?ID=PXD016060.0-1&outputMode=XML). The standard data files contain mostly the technical metadata associated with the dataset including search engine settings, scores, workflows, configuration files, but do not include information about the sample metadata and/or the experimental design. Currently, all ProteomeXchange partners mandate this information for each dataset. However, the information regarding the sample and its relation to the data files (**Figure 1**) is mostly missing [1]. + +These three levels of metadata are combined in the well-established data formats ISA-TAB [2] (https://www.isacommons.org/) or MAGE-TAB [3], which are used in other omics fields such as metabolomics and transcriptomics. In both data formats, a tab-delimited file is used to annotate the sample metadata and link it to the corresponding data file(s) (sample and data relationship file format—SDRF). Both data formats encode the properties and sample attributes as columns, and each row represents a sample in the study. However, more important that the file-format itself, general guidelines about what information should be encoded to enable reproducibility of the proteomics results are needed. The lack of guidelines to annotate information such as disease stage, cell line code, or organism part, or the analytical information about labelling channels (e.g. TMT, SILAC) makes the data representation incomplete. The consequence is that it is not possible to understand the original experiment, and/or perform a re-analysis of the dataset having all the necessary information for reproducibility purposes. If the information about the fractions, labelling channels, or enrichment methods is not annotated, the reuse and reproduction of the original results will be challenging, if possible, at all. + +image::https://github.com/bigbio/proteomics-metadata-standard/raw/master/sdrf-proteomics/images/sample-metadata.png[] + +**Figure 1**: SDRF-Proteomics file format stores the information of the sample and its relation to the data files in the dataset. The file format includes not only information about the sample but also about how the data was acquired and processed. + +[[requirements]] +=== Requirements + +The SDRF-Proteomics format describes the sample characteristics and the relationships between samples and data files included in a dataset. The information in SDRF files is organised so that it follows the natural flow of a proteomics experiment. The main requirements to be fulfilled for SDRF-Proteomics format are: + +- The SDRF file is a tab-delimited format where each ROW corresponds to a relationship between a Sample and a Data file (and MS signal corresponding to labelling in the context of multiplexed experiments). +- Each column MUST correspond to an attribute/property of the Sample or the Data file. +- Each value in each cell MUST be the property for a given Sample or Data file. +- The file MUST begin with columns describing the samples of origin and continue with the data files generated from their MS analyses. +- Support for handling unknown values/characteristics. + +[[issues-addressed]] +=== Issues to be addressed + +The main issues to be addressed by the SDRF are: + +- It MUST be able to represent the sample metadata and the data files generated by the instruments or the analyses. +- It MUST be able to represent the experimental design including the way samples and data have been collected. + +[[notation-conventions]] +== Notational Conventions + +The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMEND/RECOMMENDED”, “MAY”, “COULD BE”, and “OPTIONAL” are to be interpreted as described in RFC 2119 (2). + +[[document-structure]] +== Documentation + +The official website for SDRF-Proteomics project is https://github.com/bigbio/proteomics-metadata-standard. New use cases, changes to the specification and examples can be added by using Pull requests or issues in GitHub (see introduction to GitHub - https://lab.github.com/githubtraining/introduction-to-github). + +A set of examples and annotated projects from ProteomeXchange can be found here: https://github.com/bigbio/proteomics-metadata-standard/tree/master/annotated-projects + +Multiple tools have been implemented to validate SDRF-Proteomics files for users familiar with Python and Java: + +- sdrf-pipelines (Python - https://github.com/bigbio/sdrf-pipelines): This tool allows to validate an SDRF-Proteomics file. In addition, it allows converting SDRF to other popular pipelines and software configure files such as MaxQuant or OpenMS. + +- jsdrf (Java - https://github.com/bigbio/jsdrf ): These Java library and tool allow validating SDRF-Proteomics files. It also includes a generic data model that can be used by Java applications. + +[[relationship-specifications]] +== Relationship to other specifications + +SDRF-Proteomics is fully compatible with the SDRF file format part of https://www.ebi.ac.uk/arrayexpress/help/magetab_spec.html[MAGE-TAB]. MAGE-TAB is the file format used to store metadata and sample information for transcriptomics experiments. When the proteomeXchange project file is converted to idf file (project description in MAGE-TAB) and is combined with the SDRF-Proteomics a valid MAGE-TAB is obtained. + +SDRF-Proteomics sample information can be embedded into mzTab metadata files. The sample metadata in mzTab contains properties as the columns in the SDRF-Proteomics and values as Sample cell values. + +The SDRF-Proteomics aims to capture the sample metadata and its relationship with the data files (e.g. raw files from mass spectrometers). The SDRF-Proteomics do not aim to capture the downstream analysis part of the experimental design such as what samples should be compared, how they can be combined or parameters for the downstream analysis (FDR or p-values thresholds). The HUPO-PSI community will work in the future to include this information in other file formats such as mzTab or a new type of file format. + +[[ontologies-supported]] +== Ontologies/Controlled Vocabularies Supported + +The list of ontologies/controlled vocabularies (CV) supported are: + +- PSI Mass Spectrometry CV (PSI-MS) +- Experimental Factor Ontology (EFO). +- Unimod protein modification database for mass spectrometry +- PSI-MOD CV (PSI-MOD) +- Cell line ontology +- Drosophila anatomy ontology +- Cell ontology +- Plant ontology +- Uber-anatomy ontology +- Zebrafish anatomy and development ontology +- Zebrafish developmental stages ontology +- Plant Environment Ontology +- FlyBase Developmental Ontology +- Rat Strain Ontology +- Chemical Entities of Biological Interest Ontology +- NCBI organismal classification +- PATO - the Phenotype and Trait Ontology +- PRIDE Controlled Vocabulary (CV) +- Mondo Disease Ontology (MONDO): A unified disease ontology integrating multiple disease resources. + +[[sdrf-file-format]] +== SDRF-Proteomics file format + +The SDRF-Proteomics file format describes the sample characteristics and the relationships between samples and data files. The file format is a tab-delimited one where each ROW corresponds to a relationship between a Sample and a Data file (and MS signal corresponding to labelling in the context of multiplexed experiments), each column corresponds to an attribute/property of the Sample, and the value in each cell is the specific value of the property for a given Sample (**Figure 2**). + +[#img-sunset] +image::https://github.com/bigbio/proteomics-metadata-standard/raw/master/sdrf-proteomics/images/sdrf-nutshell.png[] + +**Figure 2**: SDRF-Proteomics in a nutshell. The file format is a tab-delimited one where columns are properties of the sample, the data file or the variables under study. The rows are the samples of origin and the cells are the values for one property in a specific sample. + +[[sdrf-file-rules]] +=== SDRF-Proteomics format rules + +There are general scenarios/use cases that are addressed by the following rules: + +- **Unknown values**: In some cases, the column is mandatory in the format, but for some samples the corresponding value is unknown. In those cases, users SHOULD use ‘not available’. +- **Not Applicable values**: In some cases, the column is mandatory, but for some samples the corresponding value is not applicable. In those cases, users SHOULD use ‘not applicable’. +- **Case sensitivity**: By specification the SDRF is case-insensitive, but we RECOMMEND using lowercase characters throughout all the text (Column names and values). +- **Spaces**: By specification the SDRF is case-sensitive to spaces (sourcename != source name). +- **Column order**: The SDRF MUST start with the source name column (accession/name of the sample of origin), then all the sample characteristics; followed by the assay name corresponding to the MS run. Finally, after the assay name all the comments (properties of the data file generated). +- **Extension**: The extension of the SDRF should be .tsv or .txt. + +[[sdrf-file-standarization]] +=== SDRF-Proteomics values + +The value for each property, (e.g. characteristics, comment) corresponding to each sample can be represented in multiple ways. + +- Free Text (Human readable): In the free text representation, the value is provided as text without Ontology support (e.g. colon or providing accession numbers). This is only RECOMMENDED when the text inserted in the table is the exact name of an ontology/CV term in EFO. If the term is not in EFO, other ontologies can be used. + +|=== +| source name | characteristics[organism] + +| sample 1 |homo sapiens +| sample 2 |homo sapiens +|=== + +- Ontology url (Computer readable): Users can provide the corresponding URI (Uniform Resource Identifier) of the ontology/CV term as a value. This is recommended for enriched files where the user does not want to use intermediate tools to map from free text to ontology/CV terms. + +|=== +| source name | characteristics[organism] + +| Sample 1 |http://purl.obolibrary.org/obo/NCBITaxon_9606 +| Sample 2 |http://purl.obolibrary.org/obo/NCBITaxon_9606 +|=== + +- Key=value representation (Human and Computer readable): The current representation aims to provide a mechanism to represent the complete information of the ontology/CV term including Accession, Name and other additional properties. In the key=value pair representation, the Value of the property is represented as an Object with multiple properties, where the key is one of the properties of the object and the value is the corresponding value for the particular key. An example of key value pairs is post-translational modification <> + + NT=Glu->pyro-Glu;MT=fixed;PP=Anywhere;AC=Unimod:27;TA=E + +[[from-sample-metadata]] +== SDRF-Proteomics: Samples metadata + +The Sample metadata has different Categories/Headings to organize all the attributes/ column headers of a given sample. Each Sample contains a _source name_ (accession) and a set of _characteristics_. Any proteomics sample MUST contain the following characteristics: + +- _source name_: Unique sample name (it can be present multiple times if the same sample is used several times in the same dataset) +- _characteristics[organism]_: The organism of the Sample of origin. +- _characteristics[disease]_: The disease under study in the Sample. +- _characteristics[organism part]_: The part of organism's anatomy or substance arising from an organism from which the biomaterial was derived, (e.g., liver) +- _characteristics[cell type]_: A cell type is a distinct morphological or functional form of cell. Examples are epithelial, glial etc. + +Example: + +|=== +| source name | characteristics[organism] | characteristics[organism part] | characteristics[disease] | characteristics[cell type] + +|sample_treat | homo sapiens | liver | liver cancer | not available +|sample_control | homo sapiens | liver | liver cancer | not available +|=== + +NOTE: Additional characteristics can be added depending on the type of the experiment and sample. The https://github.com/bigbio/proteomics-metadata-standard/tree/master/templates[SDRF-Proteomics templates] defines a set of templates and checklists of properties that should be provided depending on the proteomics experiment. + +Some important notes: + +- Each characteristic name in the column header SHOULD be a CV term from the EFO ontology. For example, the header _characteristics[organism]_ corresponds to the ontology term Organism. However the values could be from EFO or other ontologies. For example, we RECOMMEND to use MONDO for diseases because it has better coverage than EFO. + +- Multiple values (columns) for the same characteristics term are allowed in SDRF-Proteomics. However, it is RECOMMENDED not to use the same column in the same file. If you have multiple phenotypes, you can specify what it refers to or use another more specific term, e.g., "immunophenotype". + +[[from-sample-data]] +== SDRF-Proteomics: Data files metadata + +The connection between the Samples to the Data files is done by using a series of properties and attributes (comments - for backward compatibility with SDRF in transcriptomics comment MUST be used). All the properties referring to the MS run (file) itself are annotated with the category **comment**. The use of comment is mainly aimed at differentiating sample properties from the data properties. It matches a given sample to the corresponding file(s). The word comment is used for backwards-compatibility with gene expression experiments (RNA-Seq and Microarrays experiments). + +The order of the columns is important, _assay name_ SHOULD always be located before the comments. It is RECOMMENDED to put the last column as _comment[data file]_. The following properties MUST be provided for each data file (ms run) file: + +- **assay name**: For SDRF back-compatibility, MSRun cannot be used. Instead, _assay name_ is used. Examples of assay names are: “run 1”, “run_fraction_1_2”. +- **comment[fraction identifier]**: The fraction identifier allows recording the number of a given fraction. The fraction identifier corresponds to this ontology term. It MUST start from 1, and if the experiment is not fractionated, 1 MUST be used for each MSRun (assay). +- **comment[label]**: label describes the label applied to each Sample (if any). In the case of multiplex experiments such as TMT, SILAC, and/or ITRAQ the corresponding label SHOULD be added. For Label-free experiments the label-free sample term MUST be used <>. +- **comment[data file]**: The data file provides the name of the raw file generated by the instrument. The data files can be instrument raw files but also converted peak lists such as mzML, MGF or result files like mzIdentML. +- **comment[instrument]**: Instrument model used to capture the sample <>. + +Example: + +|=== +| | assay name | comment[label] | comment[fraction identifier] | comment[instrument]| comment[data file] +|sample 1| run 1 | label free sample | 1 | NT=LTQ Orbitrap XL | 000261_C05_P0001563_A00_B00K_R1.RAW +|sample 1| run 2 | label free sample | 2 | NT=LTQ Orbitrap XL | 000261_C05_P0001563_A00_B00K_R2.RAW +|=== + +TIP: All the possible _label_ values can be seen in the in the PRIDE CV under the https://www.ebi.ac.uk/ols/ontologies/pride/terms?iri=http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FPRIDE_0000514&viewMode=All&siblings=false[Label] node. + +[[label-data]] +=== Label annotations + +In order to annotate quantitative datasets, the SDRF file format uses tags for each channel associated with the sample in _comment[label]_. The label values are organized under the following ontology term Label. Some of the most popular labels are: + +- For label-free experiments the value SHOULD be: label free sample +- For TMT experiments, the SDRF uses the PRIDE ontology terms under sample label. Here are some examples of TMT channels: + + TMT126, TMT127, TMT127C, TMT127N, TMT128 , TMT128C, TMT128N, TMT129, TMT129C, TMT129N, TMT130, TMT130C, TMT130N, TMT131 + +In order to achieve a clear relationship between the label and the sample characteristics, each channel of each sample (in multiplex experiments) SHOULD be defined in a separate row: one row per channel used (annotated with the corresponding _comment[label]_ per file. + +Examples: + +• https://github.com/bigbio/proteomics-sample-metadata/blob/master/annotated-projects/PXD000612/PXD000612.sdrf.tsv[Label free] +• https://github.com/bigbio/proteomics-sample-metadata/blob/master/annotated-projects/PXD011799/PXD011799.sdrf.tsv[TMT] +• https://github.com/bigbio/proteomics-sample-metadata/blob/master/annotated-projects/PXD017710/PXD017710-silac.sdrf.tsv[SILAC] + +[[instrument]] +=== Type and Model of Mass Spectrometer + +The model of the mass spectrometer SHOULD be specified as _comment[instrument]_. Possible values are listed under https://www.ebi.ac.uk/ols/ontologies/ms/terms?iri=http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FMS_1000031&viewMode=All&siblings=false[instrument model term]. + +Additionally, it is strongly RECOMMENDED to include comment[MS2 analyzer type]. This is important, e.g., for Orbitrap models where MS2 scans can be acquired either in the Orbitrap or in the ion trap. Setting this value allows differentiating high-resolution MS/MS data. Possible values of _comment[MS2 analyzer type]_ are mass analyzer types. + +[[technology-type]] +=== Technology type + +Technology type is used in SDRF and MAGE-TAB formats to specify the technology applied in the study to capture the data. For transcriptomics, common values include technologies such as microarray, RNA-seq, and ChIP-seq (as seen in https://www.ebi.ac.uk/biostudies/arrayexpress/studies/E-MTAB-13567[ArrayExpress Example]). In SDRF-Proteomics, the technology type field is REQUIRED to describe the experimental approach used to generate the data. We RECOMMEND including the technology type column immediately after the `assay name`` column in the SDRF file, clearly indicating which technology was used to produce the data files. + +|=== +| | assay name | technology type +|sample 1| run 1 | proteomic profiling by mass spectrometry +|=== + +NOTE: While we RECOMMEND positioning the technology type column after the assay name, in some original templates, this column was placed before the assay name. We will allow the technology type column to appear either directly before or after the assay name column but RECOMMEND placing it after the assay name for consistency. + +For proteomics experiments the possible values for technology types can be obtained from PRIDE Ontology term https://www.ebi.ac.uk/ols4/ontologies/pride/classes/http%253A%252F%252Fpurl.obolibrary.org%252Fobo%252FPRIDE_0000663[technology type]. + +Here, the list of valid values: + +- proteomic profiling by mass spectrometry + +[[additional-data-files]] +=== Additional Data files technical properties + +It is RECOMMENDED to encode some of the technical parameters of the MS experiment as comments, including the following parameters: + +- Protein Modifications +- Precursor and Fragment ion mass tolerances +- Digestion Enzymes + +[[ptms]] +==== Protein Modifications + +Sample modifications, (including both chemical modifications and post-translational modifications, PTMs) are originated from multiple sources: artifact modifications, isotope labeling, adducts that are encoded as PTMs (e.g. sodium) or the most biologically relevant PTMs. + +It is RECOMMENDED to provide the modifications expected in the sample including the amino acid affected, whether it is Variable or Fixed (also Custom and Annotated modifications are supported) and included other properties such as mass shift/delta mass and the position (e.g. anywhere in the sequence). + +The RECOMMENDED name of the column for sample modification parameters is: comment[modification parameters]. + +The modification parameters are the name of the ontology term MS:1001055. + +For each modification, different properties are captured using a key=value pair structure including name, position, etc. All the possible (optional) features available for modification parameters are: + +|=== +|Property |Key |Example | Mandatory(:white_check_mark:)/Optional(:zero:) |comment + +|Name of the Modification| NT | NT=Acetylation | :white*check_mark: | \* Name of the Term in this particular case Modification, for custom modifications can be a name defined by the user. +|Modification Accession | AC |AC=UNIMOD:1 | :zero: | Accession in an external database UNIMOD or PSI-MOD supported. +|Chemical Formula | CF | CF=H(2)C(2)O | :zero: | This is the chemical formula of the added or removed atoms. For the formula composition please follow the guidelines from http://www.unimod.org/names.html[UNIMOD] +|Modification Type | MT | MT=Fixed | :zero: | This specifies which modification group the modification should be included with. Choose from the following options: [Fixed, Variable, Annotated]. \_Annotated* is used to search for all the occurrences of the modification into an annotated protein database file like UNIPROT XML or PEFF. +|Position of the modification in the Polypeptide | PP | PP=Any N-term | :zero: | Choose from the following options: [Anywhere, Protein N-term, Protein C-term, Any N-term, Any C-term]. Default is _Anywhere_. +|Target Amino acid | TA | TA=S,T,Y | :white_check_mark: | The target amino acid letter. If the modification targets multiple sites, it can be separated by `,`. +|Monoisotopic Mass | MM | MM=42.010565 | :zero: | The exact atomic mass shift produced by the modification. Please use at least 5 decimal places of accuracy. This should only be used if the chemical formula of the modification is not known. If the chemical formula is specified, the monoisotopic mass will be overwritten by the calculated monoisotopic mass. +|Target Site | TS | TS=N[^P][ST] | :zero: | For some software, it is important to capture complex rules for modification sites as regular expressions. These use cases should be specified as regular expressions. +|=== + +We RECOMMEND for indicating the modification name, to use the UNIMOD interim name or the PSI-MOD name. For custom modifications, we RECOMMEND using an intuitive name. If the PTM is unknown (custom), the Chemical Formula or Monoisotopic Mass MUST be annotated. + +An example of an SDRF-Proteomics file with sample modifications annotated, where each modification needs an extra column: + +|=== +| |comment[modification parameters] | comment[modification parameters] + +|sample 1| NT=Glu->pyro-Glu; MT=fixed; PP=Anywhere;AC=Unimod:27; TA=E | NT=Oxidation; MT=Variable; TA=M +|=== + +[[cleavage-agents]] +==== Cleavage agents + +The REQUIRED _comment [cleavage agent details]_ property is used to capture the enzyme information. Similar to protein modification, a key=value pair representation is used to encode the following properties for each enzyme: + +|=== +|Property |Key |Example | Mandatory(:white_check_mark:)/Optional(:zero:) | comment +|Name of the Enzyme | NT | NT=Trypsin | :white_check_mark: | \* Name of the Term in this particular case Name of the Enzyme. +|Enzyme Accession | AC |AC=MS:1001251 | :zero: | Accession in an external PSI-MS Ontology definition under the following category https://www.ebi.ac.uk/ols/ontologies/ms/terms?iri=http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FMS_1001045[Cleavage agent name]. +|Cleavage site regular expression | CS | CS=(?<=[KR])(?!P) | :zero: | The cleavage site defined as a regular expression. +|=== + +An example of an SDRF-Proteomics with annotated endopeptidase: + +|=== +| source name |...|comment[cleavage agent details] + +|sample 1| ....|NT=Trypsin;AC=MS:1001251 +|=== + +NOTE: If no endopeptidase is used, for example, in the case of Top-down/intact protein experiments, the value SHOULD be ‘not applicable’. + +[[mass-tolerances]] +==== Precursor and Fragment mass tolerances + +For proteomics experiments, it is important to encode different mass tolerances (for precursor and fragment ions). + +|=== +| |comment[fragment mass tolerance] | comment[precursor mass tolerance] + +|sample 1| 0.6 Da | 20 ppm +|=== + +Units for the mass tolerances (either Da or ppm) MUST be provided. + +[[study-variables]] +== SDRF-Proteomics study variables + +The variable/property under study SHOULD be highlighted using the factor value category. For example, the _factor value[tissue]_ is used when the user wants to compare expression across different tissues. You can add Multiple variables under study by providing multiple factor values. + +|=== +|factor value | :zero: | 0..\* | “factor value” columns SHOULD indicate which experimental factor/variable is used as the hypothesis to perform the data analysis. The “factor value” columns SHOULD occur after all characteristics and the attributes of the samples. | factor value[phenotype] +|=== + +[[conventions]] +== SDRF-Proteomics conventions + +Conventions define how to encode some particular information in the file format in specific use cases. Conventions define a set of new columns that are needed to represent a particular use case or experiment type (e.g. phosphorylation dataset). In addition, conventions define how some specific free-text columns (value that is not defined as ontology terms) should be written. Conventions are compiled from the proteomics community using https://github.com/bigbio/proteomics-metadata-standard/issues or pull-request and will be added to updated versions of this specification document in the future. + +In the convention section <>, the columns are described and defined, while in the section use cases and templates <> the columns needed to describe a use case are specified. + +[[age-encoding]] +=== How to encode age + +One of the characteristics of a patient sample can be the age of an individual. It is RECOMMENDED to provide the age in the following format: {X}Y{X}M{X}D. Some valid examples are: + +- 40Y (forty years) +- 40Y5M (forty years and 5 months) +- 40Y5M2D (forty years, 5 months, and 2 days) + +When needed, weeks can also be used: 8W (eight weeks) + +Age interval: + +Sometimes the sample does not have an exact age but a range of age. To annotate an age range the following standard is RECOMMENDED: + + 40Y-85Y + +This means that the subject (sample) is between 40 and 85 years old. Other temporal information can be encoded similarly. + +[[phos-pho]] +=== Phosphoproteomics and other post-translational modifications enriched studies + +In PTM-enriched experiments, the _characteristics[enrichment process]_ SHOULD be provided. The different values already included in EFO are: + +- enrichment of phosphorylated Protein +- enrichment of glycosylated Protein + +This characteristic can be used as a _factor value[enrichment process]_ to differentiate the expression between proteins in the phospho-enriched sample compared with the control. + +[[pooled-samples]] +=== Pooled samples + +When multiple samples are pooled into one, the general approach is to annotate them separately, abiding by the general rule: one row stands for one sample-to-file relationship. In this case, multiple rows are created for the corresponding data file, much like in <>. + +One possible exception is made for the case when one channel e.g., in a TMT/iTRAQ multiplexed experiment is used for a sample pooled from all other channels, typically for normalization purposes. In this case, it is not necessary to repeat all sample annotations. Instead, a special characteristic can be used: + +|=== +|source name |characteristics[pooled sample] | assay name | comment[label] | comment[data file] + +| sample 1 | not pooled | run 1 | TMT131 | file01.raw +| sample 2 | not pooled | run 1 | TMT131C | file01.raw +| sample 10 | SN=sample 1,sample 2, ... sample 9| run 1 | TMT128 | file01.raw +|=== + +`SN` stands for source names and lists `source name` fields of samples that are annotated in the same file and _used in the same experiment and same MS run_. + +Another possible value for _characteristics[pooled sample]_ is a string `pooled` for cases when it is known that a sample is pooled but the individual samples cannot be annotated. + +[[derived-samples]] +=== Derived samples (such as patient-derived xenografts) + +In cancer research, patient-derived xenografts (PDX) are commonly used. In those, the patient’s tumor is transplanted into another organism, usually a mouse. In these cases, the metadata, such as age and sex, MUST refer to the original patient and not the mouse. + +PDX samples SHOULD be annotated by using the column name _characteristics[xenograft]_. The value should then describe the growth condition, such as ‘pancreatic cancer cells grown in nude mice’. + +For experiments where both the PDX and the original tumor are measured, the PDX entry SHOULD reference the respective tumor sample’s source name in the _characteristics[source name]_ column. Non-PDX samples SHOULD contain the “not applicable” value in the _characteristics[xenograft]_ and the characteristics[source name] column. Both tumor and PDX samples SHOULD reference the patient using the characteristics[individual] column. This column SHOULD contain some sort of patient identifier. + +[[spiked-in]] +=== Spiked-in samples + +There are multiple scenarios when a sample is spiked with additional analytes. Peptides, proteins, or mixtures can be added to the sample as controlled amounts to provide a standard or ground truth for quantification, or for retention time alignment, etc. + +To include information about the spiked compounds, use _characteristics[spiked compound]_. The information is provided in key-value pairs. Here are the keys and values that SHOULD be provided: + +|=== +|Key | Meaning | Examples | Peptide | Protein | Mixture | Other + +|SP | Species | Escherichia coli K-12 | :zero: | :zero: | :zero: | :zero: +|CT | Compound type | protein, peptide, mixture, other | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: +|QY | Quantity (molar or mass) | 10 mg, 20 nmol | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: +|PS | Peptide sequence | PEPTIDESEQ |:white_check_mark: | | | +|AC | Uniprot Accession | A9WZ33 | | :white_check_mark: | | +|CN | Compound name | `iRT mixture`, `substance name` | | :zero: | :zero: | :zero: +|CV | Compound vendor | `in-house` or vendor name | :zero: | :zero: | :white_check_mark: | :zero: +|CS | Compound specification URI | `http://vendor.web.site/specs/coomercial-kit.xlsx` | :zero: | :zero: | :zero: | :zero: +|CF | Compound formula | `C2H2O` | | | | :zero: +|=== + +In addition to specifying the component and its quantity, the injected mass of the main sample SHOULD be specified as _characteristics[mass]_. + +An example of SDRF-Proteomics for a sample spiked with a peptide would be: + +|=== +|characteristics[mass] | characteristics[spiked compound] +|1 ug | CT=peptide;PS=PEPTIDESEQ;QY=10 fmol +|=== + +For multiple spiked components, the column _characteristics[spiked compound]_ may be repeated. + +If the spiked component is another biological sample (e.g. **E. coli** lysate spiked into human sample), then the spiked component MUST be annotated in its own row. Both components of the sample SHOULD have `characteristics[mass]` specified. Inclusion of _characteristics[spiked compound]_ is optional in this case; if provided, it SHOULD be the string `spiked` for the spiked sample. + +[[synthetic-peptide]] +=== Synthetic peptide libraries + +It is common to use synthetic peptide libraries for proteomics, and MS use cases include: + +• Benchmark of analytical and bioinformatics methods and algorithms. +• Improvement of peptide identification/quantification using spectral libraries. + +When describing synthetic peptide libraries, most of the sample metadata can be declared as “not applicable”. However, some authors can annotate the organism for example because they know the library has been designed from specific peptide species, see example Synthetic Peptide experiment (https://github.com/bigbio/proteomics-metadata-standard/blob/master/annotated-projects/PXD000759/sdrf.tsv). + +It is important to annotate that the sample is a synthetic peptide library, this can be done by adding the characteristics[synthetic peptide]. The possible values are “synthetic” or “not synthetic”. + +[[normal-healthy]] +=== Normal and healthy samples + +Samples from healthy patients or individuals normally appear in manuscripts and annotations as healthy or normal. We RECOMMEND using the word “normal” mapped to term PATO_0000461 that is in EFO: normal PATO term. Example: + +|=== +| source name | characteristics[organism] | characteristics[organism part] | characteristics[phenotype] | characteristics[compound] | factor value[phenotype] + +|sample_treat | homo sapiens | Whole Organism | necrotic tissue | drug A | necrotic tissue +|sample_control | homo sapiens | Whole Organism | normal | none | normal +|=== + +[[sample-technical-biological-replicates]] +=== Encoding sample technical and biological replicates + +Different measurements of the same biological sample are often categorized as (i) Technical or (ii) Biological replicates, based on whether they are (i) matched on all variables, e.g. same sample and same protocol; or (ii) different samples matched on explanatory variable(s), e.g. different patients receiving a placebo, in a placebo vs. drug trial. Technical and biological replicates have different levels of independence, which must be taken into account during data interpretation. + +For a given experiment, there are different levels to which samples can be matched - e.g., same sample, sample protocol, covariates - the definition of technical replicate can therefore vary based on the number of variables included. In addition, an experiment might be used in multiple models with different explanatory variable(s), and biological replicates in one model would not be replicates in another. Therefore, Technical vs. Biological considerations, while sometimes relevant to analytical and statistical interpretation, fall beyond the scope of the SDRF-Proteomics format. However, data providers are encouraged to provide any identifier - e.g. Biological_replicate_1, Technical_replicate_2 - that would help link the samples to their analytical and statistical analysis as comments. A good starting point for the SDRF-Proteomics specification is the following: + +**technical replicate**: It is defined as repeated measurements of the same sample that represent independent measures of the random noise associated with protocols or equipment [4]. + +In MS-based proteomics, a technical replicate can be, for example, doing the full sample preparation from extraction to MS multiple times to control variability in the instrument and sample preparation. Another valid example would be to replicate only one part of the analytical method, for example, run the sample twice on the LC-MS/MS. technical replicates indicate if measurements are scientifically robust or noisy, and how large the measured effect must be to stand out above that noise. + +In the following example, only if the technical replicate column is provided, one can distinguish quantitative values of the same fraction but different technical replicates. + +|=== +| source name | assay name | comment[label] | comment[fraction identifier] | comment[technical replicate] | comment[data file] +| Sample 1 | run 1 | label free sample | 1 | 1 | F1_TR1.RAW +| Sample 1 | run 2 | label free sample | 2 | 1 | F2_TR1.RAW +| Sample 1 | run 3 | label free sample | 1 | 2 | F1_TR2.RAW +| Sample 1 | run 4 | label free sample | 2 | 2 | F2_TR2.RAW +|=== + +The _comment[technical replicate]_ column is MANDATORY. Please fill it with 1 if technical replicates are not performed in a study. + +**Biological replicate**: parallel measurements of biologically distinct samples that capture biological variation, which may itself be a subject of study or a source of noise. Biological replicates address if and how widely the results of an experiment can be generalized. For example, repeating a particular assay with independently generated samples, individuals or samples derived from various cell types, tissue types, or organisms, to see if similar results can be observed. Context is critical, and appropriate biological replicates will indicate whether an experimental effect is sustainable under a different set of biological variables or an anomaly itself. + +In SDRF-Proteomics, biological replicates can be annotated using _characteristics[biological replicate]_ and it is MANDATORY. Please fill it with 1 if biological replicates are not performed in a study. + +Some examples with explicit annotation of the biological replicates can be found here: + +- https://github.com/bigbio/proteomics-metadata-standard/blob/c3a56b076ef381280dfcb0140d2520126ace53ff/annotated-projects/PXD006401/sdrf.tsv + +[[sample-prep]] +=== Sample preparation properties + +In order to encode sample preparation details, we strongly RECOMMEND specifying the following parameters. + +- **comment [depletion]**: The removal of specific components of a complex mixture of proteins or peptides based on some specific property of those components. The values of the columns will be `no depletion` or `depletion`. In the case of depletion `depleted fraction` of `bound fraction` can be specified. + +- **comment [reduction reagent]**: The chemical reagent that is used to break disulfide bonds in proteins. The values of the column are under the term https://www.ebi.ac.uk/ols/ontologies/pride/terms?iri=http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FPRIDE_0000607&viewMode=All&siblings=false[reduction reagent]. For example, DTT. + +- **comment [alkylation reagent]**: The alkylation reagent that is used to covalently modify cysteine SH-groups after reduction, preventing them from forming unwanted novel disulfide bonds. The values of the column are under the term https://www.ebi.ac.uk/ols/ontologies/pride/terms?iri=http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FPRIDE_0000598&viewMode=All&siblings=false[alkylation reagent]. For example, IAA. + +- **comment [fractionation method]**: The fraction method used to separate the sample. The values of this term can be read under PRIDE ontology term https://www.ebi.ac.uk/ols/ontologies/pride/terms?iri=http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FPRIDE_0000550[Fractionation method]. For example, Off-gel electrophoresis. + +[[fragment-proper]] +=== MS/MS properties + +- **comment[collision energy]**: Collision energy can be added as non-normalized (10000 eV) or normalized (1000 NCE) value. + +- **comment[dissociation method]**: This property will provide information about the fragmentation method, like HCD, CID. The values of the column are under the term https://www.ebi.ac.uk/ols/ontologies/ms/terms?iri=http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FMS_1000044&viewMode=All&siblings=false[dissociation method]. + +[[raw-file-uri]] +=== RAW file URI + +We RECOMMEND including the public URI of the file if available. For example, for ProteomeXchange datasets, the URI from the FTP can be provided: + +|=== +| |... |comment[file uri] + +|sample 1| ... |https://ftp.pride.ebi.ac.uk/pride/data/archive/2017/09/PXD005946/000261_C05_P0001563_A00_B00K_R1.RAW +|=== + +[[multiple-projects]] +=== Multiple projects into one annotation file + +Curators can decide to annotate multiple ProteomeXchange datasets into one large SDRF-Proteomics file for reanalysis purposes. If that is the case, it is RECOMMENDED to use the comment[proteomexchange accession number] to differentiate between different datasets. + +[[data-acquisition-method]] +=== Data acquisition method: DDA and DIA and others + +Proteomics data acquisition method can happen in two ways: Data Dependent Acquisition (DDA) or Data Independent Acquisition (DIA). The SDRF-Proteomics file format allows to capture the method used for the data acquisition in the _comment[proteomics data acquisition method]_ column. The following values are RECOMMENDED for DDA and DIA: + +- https://www.ebi.ac.uk/ols4/ontologies/pride/classes/http%253A%252F%252Fpurl.obolibrary.org%252Fobo%252FPRIDE_0000627[data-dependent acquisition] +- https://www.ebi.ac.uk/ols4/ontologies/pride/classes/http%253A%252F%252Fpurl.obolibrary.org%252Fobo%252FPRIDE_0000450[data-independent acquisition] + - https://www.ebi.ac.uk/ols4/ontologies/pride/classes/http%253A%252F%252Fpurl.obolibrary.org%252Fobo%252FPRIDE_0000650?lang=en[diaPASEF] + - https://www.ebi.ac.uk/ols4/ontologies/pride/classes/http%253A%252F%252Fpurl.obolibrary.org%252Fobo%252FPRIDE_0000447[SWATH MS] +- https://www.ebi.ac.uk/ols4/ontologies/pride/classes/http%253A%252F%252Fpurl.obolibrary.org%252Fobo%252FPRIDE_0000629[parallel reaction monitoring] +- https://www.ebi.ac.uk/ols4/ontologies/pride/classes/http%253A%252F%252Fpurl.obolibrary.org%252Fobo%252FPRIDE_0000630[selected reaction monitoring] + +TIP: If the SDRF do not specified the proteomics data acquisition method as _comment[proteomics data acquisition method]_, it is assumed that the method used is DDA which is the most common method used in proteomics. + +You can find an example of a DIA experiment in the following link: https://github.com/bigbio/proteomics-sample-metadata/blob/master/annotated-projects/PXD018830/PXD018830-DIA.sdrf.tsv[DIA example] + +[[dia-ms1-scan]] +==== Data Independent Acquisition - Scan window limits + +Additionally to the general _comment[proteomics data acquisition method]_ column, the SDRF-Proteomics file format allows to capture other properties for the DIA method. The following properties are RECOMMENDED for DIA: + +- _comment[MS1 scan range]_: The MS1 scan range is the m/z range used for the DIA acquisition. The values are expressed in m/z units. + +Example: + +|=== +|assay name | comment[MS1 scan range] | comment[data file] +|run 1 | 400m/z - 1200m/z | FILE_R1.RAW +|run 2 | 400m/z - 1200m/z | FILE_R2.RAW +|=== + +TIP: While the specification recommend to write the MS1 scan range as an interval (e.g. 400m/z - 1200m/z), it is also possible to write the MS1 scan range as a single value (e.g. 400m/z) using two columns for the lower and upper limits. In those cases you can write the lower limit in the _comment[scan window lower limit]_ and the uper limit in _comment[scan window upper limit]_ + +[[use-cases]] +== SDRF-Proteomics use-cases representation (templates) + +Please visit the following document to read about SDRF-Proteomics use cases, templates, and https://github.com/bigbio/proteomics-metadata-standard/blob/master/templates/README.adoc[checklists]. + +[[example-annotated-datasets]] +== Examples of annotated datasets + +|=== +|Dataset Type | ProteomeXchange / Pubmed Accession | SDRF URL +|Label-free | PXD008934 | https://github.com/bigbio/proteomics-metadata-standard/tree/master/annotated-projects/PXD008934 +|TMT | PXD017710 | https://github.com/bigbio/proteomics-metadata-standard/tree/master/annotated-projects/PXD017710 diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 3743d71a3..99d72df62 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -21,7 +21,7 @@ jobs: # NOTE - this doesn't currently work if the PR is coming from a fork, due to limitations in GitHub actions secrets - name: Post PR comment if: failure() - uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2 + uses: mshick/add-pr-comment@8e4927817251f1ff60c001f04568532b38e0b4a0 # v3 with: message: | ## This PR is against the `${{github.event.pull_request.base.ref}}` branch :x: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d78de8d33..3cdf898dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,11 +34,10 @@ jobs: fail-fast: false matrix: NXF_VER: - - "25.04.0" + - "25.10.4" test_profile: [ "test_lfq", - "test_dia", "test_localize", "test_tmt", "test_dda_id_alphapeptdeep", diff --git a/.github/workflows/clean-up.yml b/.github/workflows/clean-up.yml index 6adb0fff4..172de6f37 100644 --- a/.github/workflows/clean-up.yml +++ b/.github/workflows/clean-up.yml @@ -10,7 +10,7 @@ jobs: issues: write pull-requests: write steps: - - uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10 + - uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10 with: stale-issue-message: "This issue has been tagged as awaiting-changes or awaiting-feedback by an nf-core contributor. Remove stale label or add a comment otherwise this issue will be closed in 20 days." stale-pr-message: "This PR has been tagged as awaiting-changes or awaiting-feedback by an nf-core contributor. Remove stale label or add a comment if it is still useful." diff --git a/.github/workflows/diann_private.yml b/.github/workflows/diann_private.yml deleted file mode 100644 index deb7e8a2d..000000000 --- a/.github/workflows/diann_private.yml +++ /dev/null @@ -1,86 +0,0 @@ -name: Fork-specific CI for test_latest_dia - -# Trigger only for your fork and the 'test_latest_dia' test profile -on: - push: - branches: - - dev - pull_request: - branches: - - dev - paths: - - "**.yml" - -env: - NXF_ANSI_LOG: false - -concurrency: - group: "${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}" - cancel-in-progress: true - -jobs: - test: - name: Run test_latest_dia with Docker - runs-on: ubuntu-latest - env: - NXF_ANSI_LOG: false - CAPSULE_LOG: none - TEST_PROFILE: test_latest_dia - EXEC_PROFILE: docker - - # Ensure this workflow only runs for your fork - if: ${{ github.repository == 'ypriverol/quantms' }} - - steps: - - name: Check out pipeline code - uses: actions/checkout@v4 - - - name: Set up Nextflow - uses: nf-core/setup-nextflow@v2 - with: - version: "25.04.0" # Or the Nextflow version you prefer - - - name: Log in to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ secrets.GHCR_USERNAME }} - password: ${{ secrets.GHCR_TOKEN }} - - - name: Run test_latest_dia with Docker - run: | - nextflow run ${GITHUB_WORKSPACE} -profile $TEST_PROFILE,$EXEC_PROFILE --outdir ${TEST_PROFILE}_${EXEC_PROFILE}_results - - - name: Gather failed logs - if: failure() || cancelled() - run: | - mkdir failed_logs - failed=$(grep "FAILED" ${TEST_PROFILE}_${EXEC_PROFILE}_results/pipeline_info/execution_trace.txt | cut -f 2) - while read -r line ; do cp $(ls work/${line}*/*.log) failed_logs/ | true ; done <<< "$failed" - - - uses: actions/upload-artifact@v4 - if: failure() || cancelled() - name: Upload failed logs - with: - name: failed_logs_${{ env.TEST_PROFILE }}_${{ env.EXEC_PROFILE }} - include-hidden-files: true - path: failed_logs - overwrite: false - - - uses: actions/upload-artifact@v4 - if: always() - name: Upload results - with: - name: ${{ matrix.test_profile }}_${{ matrix.exec_profile }}_results - include-hidden-files: true - path: ${{ matrix.test_profile }}_${{ matrix.exec_profile }}_results - overwrite: false - - - uses: actions/upload-artifact@v4 - if: always() - name: Upload log - with: - name: nextflow_${{ matrix.test_profile }}_${{ matrix.exec_profile }}.log - include-hidden-files: true - path: .nextflow.log - overwrite: false diff --git a/.github/workflows/download_pipeline.yml b/.github/workflows/download_pipeline.yml new file mode 100644 index 000000000..a7bf4fc21 --- /dev/null +++ b/.github/workflows/download_pipeline.yml @@ -0,0 +1,142 @@ +name: Test successful pipeline download with 'nf-core pipelines download' + +# Run the workflow when: +# - dispatched manually +# - when a PR is opened or reopened to main/master branch +# - the head branch of the pull request is updated, i.e. if fixes for a release are pushed last minute to dev. +on: + workflow_dispatch: + inputs: + testbranch: + description: "The specific branch you wish to utilize for the test execution of nf-core pipelines download." + required: true + default: "dev" + pull_request: + branches: + - main + - master + +env: + NXF_ANSI_LOG: false + +jobs: + configure: + runs-on: ubuntu-latest + outputs: + REPO_LOWERCASE: ${{ steps.get_repo_properties.outputs.REPO_LOWERCASE }} + REPOTITLE_LOWERCASE: ${{ steps.get_repo_properties.outputs.REPOTITLE_LOWERCASE }} + REPO_BRANCH: ${{ steps.get_repo_properties.outputs.REPO_BRANCH }} + steps: + - name: Get the repository name and current branch + id: get_repo_properties + run: | + echo "REPO_LOWERCASE=${GITHUB_REPOSITORY,,}" >> "$GITHUB_OUTPUT" + echo "REPOTITLE_LOWERCASE=$(basename ${GITHUB_REPOSITORY,,})" >> "$GITHUB_OUTPUT" + echo "REPO_BRANCH=${{ github.event.inputs.testbranch || 'dev' }}" >> "$GITHUB_OUTPUT" + + download: + runs-on: ubuntu-latest + needs: configure + steps: + - name: Check out pipeline code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + + - name: Install Nextflow + uses: nf-core/setup-nextflow@b4ec1bc7c16a94435159de94a05253542fddf6ef # v3 + + - name: Disk space cleanup + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 + with: + python-version: "3.14" + architecture: "x64" + + - name: Setup Apptainer + uses: eWaterCycle/setup-apptainer@4bb22c52d4f63406c49e94c804632975787312b3 # v2.0.0 + with: + apptainer-version: 1.3.4 + + - name: Read .nf-core.yml + id: read_yml + run: | + echo "nf_core_version=$(yq '.nf_core_version' ${{ github.workspace }}/.nf-core.yml)" >> "$GITHUB_OUTPUT" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install nf-core==${{ steps.read_yml.outputs['nf_core_version'] }} + + - name: Make a cache directory for the container images + run: | + mkdir -p ./singularity_container_images + + - name: Download the pipeline + env: + NXF_SINGULARITY_CACHEDIR: ./singularity_container_images + run: | + nf-core pipelines download ${{ needs.configure.outputs.REPO_LOWERCASE }} \ + --revision ${{ needs.configure.outputs.REPO_BRANCH }} \ + --outdir ./${{ needs.configure.outputs.REPOTITLE_LOWERCASE }} \ + --compress "none" \ + --container-system 'singularity' \ + --container-library "quay.io" -l "docker.io" -l "community.wave.seqera.io/library/" \ + --container-cache-utilisation 'amend' \ + --download-configuration 'yes' + + - name: Inspect download + run: tree ./${{ needs.configure.outputs.REPOTITLE_LOWERCASE }} + + - name: Inspect container images + run: tree ./singularity_container_images | tee ./container_initial + + - name: Count the downloaded number of container images + id: count_initial + run: | + image_count=$(ls -1 ./singularity_container_images | wc -l | xargs) + echo "Initial container image count: $image_count" + echo "IMAGE_COUNT_INITIAL=$image_count" >> "$GITHUB_OUTPUT" + + - name: Run the downloaded pipeline (stub) + id: stub_run_pipeline + continue-on-error: true + env: + NXF_SINGULARITY_CACHEDIR: ./singularity_container_images + NXF_SINGULARITY_HOME_MOUNT: true + run: nextflow run ./${{needs.configure.outputs.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ needs.configure.outputs.REPO_BRANCH }}) -stub -profile test,singularity --outdir ./results + - name: Run the downloaded pipeline (stub run not supported) + id: run_pipeline + if: ${{ steps.stub_run_pipeline.outcome == 'failure' }} + env: + NXF_SINGULARITY_CACHEDIR: ./singularity_container_images + NXF_SINGULARITY_HOME_MOUNT: true + run: nextflow run ./${{ needs.configure.outputs.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ needs.configure.outputs.REPO_BRANCH }}) -profile test,singularity --outdir ./results + + - name: Count the downloaded number of container images + id: count_afterwards + run: | + image_count=$(ls -1 ./singularity_container_images | wc -l | xargs) + echo "Post-pipeline run container image count: $image_count" + echo "IMAGE_COUNT_AFTER=$image_count" >> "$GITHUB_OUTPUT" + + - name: Compare container image counts + id: count_comparison + run: | + if [ "${{ steps.count_initial.outputs.IMAGE_COUNT_INITIAL }}" -ne "${{ steps.count_afterwards.outputs.IMAGE_COUNT_AFTER }}" ]; then + initial_count=${{ steps.count_initial.outputs.IMAGE_COUNT_INITIAL }} + final_count=${{ steps.count_afterwards.outputs.IMAGE_COUNT_AFTER }} + difference=$((final_count - initial_count)) + echo "$difference additional container images were \n downloaded at runtime . The pipeline has no support for offline runs!" + tree ./singularity_container_images > ./container_afterwards + diff ./container_initial ./container_afterwards + exit 1 + else + echo "The pipeline can be downloaded successfully!" + fi + + - name: Upload Nextflow logfile for debugging purposes + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: nextflow_logfile.txt + path: .nextflow.log* + include-hidden-files: true diff --git a/.github/workflows/extended_ci.yml b/.github/workflows/extended_ci.yml index 9d0740f2e..1f29a9758 100644 --- a/.github/workflows/extended_ci.yml +++ b/.github/workflows/extended_ci.yml @@ -28,12 +28,11 @@ jobs: fail-fast: false matrix: NXF_VER: - - "25.04.0" + - "25.10.4" - "latest-everything" test_profile: [ "test_lfq", - "test_dia", "test_localize", "test_tmt", "test_dda_id_alphapeptdeep", @@ -41,11 +40,12 @@ jobs: "test_dda_id_ms2pip", "test_tmt_corr", ] + exec_profile: ["docker"] env: NXF_ANSI_LOG: false CAPSULE_LOG: none TEST_PROFILE: ${{ matrix.test_profile }} - EXEC_PROFILE: docker + EXEC_PROFILE: ${{ matrix.exec_profile }} steps: - name: Checkout repository @@ -120,12 +120,11 @@ jobs: fail-fast: false matrix: NXF_VER: - - "25.04.0" + - "25.10.4" - "latest-everything" test_profile: [ "test_lfq", - "test_dia", "test_localize", "test_tmt", "test_dda_id_ms2pip", @@ -133,11 +132,12 @@ jobs: "test_tmt_corr", "test_dda_id_fine_tuning", ] + exec_profile: ["singularity"] env: NXF_ANSI_LOG: false CAPSULE_LOG: none TEST_PROFILE: ${{ matrix.test_profile }} - EXEC_PROFILE: singularity + EXEC_PROFILE: ${{ matrix.exec_profile }} steps: - name: Check out pipeline code uses: actions/checkout@v4 diff --git a/.github/workflows/fix_linting.yml b/.github/workflows/fix_linting.yml index 471fd48c9..4a8dcab97 100644 --- a/.github/workflows/fix_linting.yml +++ b/.github/workflows/fix_linting.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: # Use the @nf-core-bot token to check out so we can push later - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: token: ${{ secrets.nf_core_bot_auth_token }} @@ -31,22 +31,18 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.nf_core_bot_auth_token }} - # Install and run pre-commit - - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6 - with: - python-version: "3.14" - - - name: Install pre-commit - run: pip install pre-commit + - name: Install Nextflow + uses: nf-core/setup-nextflow@b4ec1bc7c16a94435159de94a05253542fddf6ef # v3 - - name: Run pre-commit - id: pre-commit - run: pre-commit run --all-files + # Install and run prek + - name: Run prek + id: prek + uses: j178/prek-action@6ad80277337ad479fe43bd70701c3f7f8aa74db3 # v2 continue-on-error: true # indication that the linting has finished - name: react if linting finished succesfully - if: steps.pre-commit.outcome == 'success' + if: steps.prek.outcome == 'success' uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 with: comment-id: ${{ github.event.comment.id }} @@ -54,7 +50,7 @@ jobs: - name: Commit & push changes id: commit-and-push - if: steps.pre-commit.outcome == 'failure' + if: steps.prek.outcome == 'failure' run: | git config user.email "core@nf-co.re" git config user.name "nf-core-bot" diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 7a527a346..8738ffc99 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -11,33 +11,31 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - name: Set up Python 3.14 - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6 - with: - python-version: "3.14" - - - name: Install pre-commit - run: pip install pre-commit + - name: Install Nextflow + uses: nf-core/setup-nextflow@b4ec1bc7c16a94435159de94a05253542fddf6ef # v3 - - name: Run pre-commit - run: pre-commit run --all-files + - name: Run prek + uses: j178/prek-action@6ad80277337ad479fe43bd70701c3f7f8aa74db3 # v2 nf-core: runs-on: ubuntu-latest steps: - name: Check out pipeline code - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: Install Nextflow - uses: nf-core/setup-nextflow@v2 + uses: nf-core/setup-nextflow@b4ec1bc7c16a94435159de94a05253542fddf6ef # v3 - - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: python-version: "3.14" architecture: "x64" + - name: Setup uv + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + - name: read .nf-core.yml uses: pietrobolcato/action-read-yaml@9f13718d61111b69f30ab4ac683e67a56d254e1d # 1.1.0 id: read_yml @@ -45,12 +43,10 @@ jobs: config: ${{ github.workspace }}/.nf-core.yml - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install nf-core==${{ steps.read_yml.outputs['nf_core_version'] }} + run: uv tool install nf-core==${{ steps.read_yml.outputs['nf_core_version'] }} - name: Run nf-core pipelines lint - if: ${{ github.base_ref != 'master' }} + if: ${{ github.base_ref != 'master' || github.base_ref != 'main' }} env: GITHUB_COMMENTS_URL: ${{ github.event.pull_request.comments_url }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -58,7 +54,7 @@ jobs: run: nf-core -l lint_log.txt pipelines lint --dir ${GITHUB_WORKSPACE} --markdown lint_results.md - name: Run nf-core pipelines lint --release - if: ${{ github.base_ref == 'master' }} + if: ${{ github.base_ref == 'master' || github.base_ref == 'main' }} env: GITHUB_COMMENTS_URL: ${{ github.event.pull_request.comments_url }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -71,7 +67,7 @@ jobs: - name: Upload linting log file artifact if: ${{ always() }} - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: linting-logs path: | diff --git a/.github/workflows/linting_comment.yml b/.github/workflows/linting_comment.yml index e6e9bc269..5b0c24f75 100644 --- a/.github/workflows/linting_comment.yml +++ b/.github/workflows/linting_comment.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download lint results - uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 # v11 + uses: dawidd6/action-download-artifact@b6e2e70617bc3265edd6dab6c906732b2f1ae151 # v21 with: workflow: linting.yml workflow_conclusion: completed @@ -21,7 +21,7 @@ jobs: run: echo "pr_number=$(cat linting-logs/PR_number.txt)" >> $GITHUB_OUTPUT - name: Post PR comment - uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2 + uses: marocchino/sticky-pull-request-comment@70d2764d1a7d5d9560b100cbea0077fc8f633987 # v3 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} number: ${{ steps.pr_number.outputs.pr_number }} diff --git a/.github/workflows/nf-test.yml b/.github/workflows/nf-test.yml new file mode 100644 index 000000000..efd72d653 --- /dev/null +++ b/.github/workflows/nf-test.yml @@ -0,0 +1,144 @@ +name: Run nf-test +on: + pull_request: + paths-ignore: + - "docs/**" + - "**/meta.yml" + - "**/*.md" + - "**/*.png" + - "**/*.svg" + release: + types: [published] + workflow_dispatch: + +# Cancel if a newer run is started +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NFT_VER: "0.9.4" + NFT_WORKDIR: "~" + NXF_ANSI_LOG: false + NXF_SINGULARITY_CACHEDIR: ${{ github.workspace }}/.singularity + NXF_SINGULARITY_LIBRARYDIR: ${{ github.workspace }}/.singularity + +jobs: + nf-test-changes: + name: nf-test-changes + runs-on: # use self-hosted runners + - runs-on=${{ github.run_id }}-nf-test-changes + - runner=4cpu-linux-x64 + outputs: + shard: ${{ steps.set-shards.outputs.shard }} + total_shards: ${{ steps.set-shards.outputs.total_shards }} + steps: + - name: Clean Workspace # Purge the workspace in case it's running on a self-hosted runner + run: | + ls -la ./ + rm -rf ./* || true + rm -rf ./.??* || true + ls -la ./ + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + fetch-depth: 0 + + - name: get number of shards + id: set-shards + uses: ./.github/actions/get-shards + env: + NFT_VER: ${{ env.NFT_VER }} + with: + max_shards: 7 + + - name: debug + run: | + echo ${{ steps.set-shards.outputs.shard }} + echo ${{ steps.set-shards.outputs.total_shards }} + + nf-test: + name: "${{ matrix.profile }} | ${{ matrix.NXF_VER }} | ${{ matrix.shard }}/${{ needs.nf-test-changes.outputs.total_shards }}" + needs: [nf-test-changes] + if: ${{ needs.nf-test-changes.outputs.total_shards != '0' }} + runs-on: # use self-hosted runners + - runs-on=${{ github.run_id }}-nf-test + - runner=4cpu-linux-x64 + strategy: + fail-fast: false + matrix: + shard: ${{ fromJson(needs.nf-test-changes.outputs.shard) }} + profile: [conda, docker, singularity] + isMain: + - ${{ github.base_ref == 'master' || github.base_ref == 'main' }} + # Exclude conda and singularity on dev + exclude: + - isMain: false + profile: "conda" + - isMain: false + profile: "singularity" + NXF_VER: + - "25.10.4" + - "latest-everything" + env: + NXF_ANSI_LOG: false + TOTAL_SHARDS: ${{ needs.nf-test-changes.outputs.total_shards }} + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + fetch-depth: 0 + + - name: Run nf-test + id: run_nf_test + uses: ./.github/actions/nf-test + continue-on-error: ${{ matrix.NXF_VER == 'latest-everything' }} + env: + NFT_WORKDIR: ${{ env.NFT_WORKDIR }} + NXF_VERSION: ${{ matrix.NXF_VER }} + with: + profile: ${{ matrix.profile }} + shard: ${{ matrix.shard }} + total_shards: ${{ env.TOTAL_SHARDS }} + + - name: Report test status + if: ${{ always() }} + run: | + if [[ "${{ steps.run_nf_test.outcome }}" == "failure" ]]; then + echo "::error::Test with ${{ matrix.NXF_VER }} failed" + # Add to workflow summary + echo "## ❌ Test failed: ${{ matrix.profile }} | ${{ matrix.NXF_VER }} | Shard ${{ matrix.shard }}/${{ env.TOTAL_SHARDS }}" >> $GITHUB_STEP_SUMMARY + if [[ "${{ matrix.NXF_VER }}" == "latest-everything" ]]; then + echo "::warning::Test with latest-everything failed but will not cause workflow failure. Please check if the error is expected or if it needs fixing." + fi + if [[ "${{ matrix.NXF_VER }}" != "latest-everything" ]]; then + exit 1 + fi + fi + + confirm-pass: + needs: [nf-test] + if: always() + runs-on: # use self-hosted runners + - runs-on=${{ github.run_id }}-confirm-pass + - runner=2cpu-linux-x64 + steps: + - name: One or more tests failed (excluding latest-everything) + if: ${{ contains(needs.*.result, 'failure') }} + run: exit 1 + + - name: One or more tests cancelled + if: ${{ contains(needs.*.result, 'cancelled') }} + run: exit 1 + + - name: All tests ok + if: ${{ contains(needs.*.result, 'success') }} + run: exit 0 + + - name: debug-print + if: always() + run: | + echo "::group::DEBUG: `needs` Contents" + echo "DEBUG: toJSON(needs) = ${{ toJSON(needs) }}" + echo "DEBUG: toJSON(needs.*.result) = ${{ toJSON(needs.*.result) }}" + echo "::endgroup::" diff --git a/.github/workflows/release-announcements.yml b/.github/workflows/release-announcements.yml new file mode 100644 index 000000000..78d5dbe05 --- /dev/null +++ b/.github/workflows/release-announcements.yml @@ -0,0 +1,46 @@ +name: release-announcements +# Automatic release toot and tweet anouncements +on: + release: + types: [published] + workflow_dispatch: + +jobs: + toot: + runs-on: ubuntu-latest + steps: + - name: get topics and convert to hashtags + id: get_topics + run: | + echo "topics=$(curl -s https://nf-co.re/pipelines.json | jq -r '.remote_workflows[] | select(.full_name == "${{ github.repository }}") | .topics[]' | awk '{print "#"$0}' | tr '\n' ' ')" | sed 's/-//g' >> $GITHUB_OUTPUT + + - name: get description + id: get_description + run: | + echo "description=$(curl -s https://nf-co.re/pipelines.json | jq -r '.remote_workflows[] | select(.full_name == "${{ github.repository }}") | .description')" >> $GITHUB_OUTPUT + - uses: rzr/fediverse-action@563159eb8d45f70ab6aaba36ed55cd037e51f441 # master + with: + access-token: ${{ secrets.MASTODON_ACCESS_TOKEN }} + host: "mstdn.science" # custom host if not "mastodon.social" (default) + # GitHub event payload + # https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#release + message: | + Pipeline release! ${{ github.repository }} v${{ github.event.release.tag_name }} - ${{ github.event.release.name }}! + ${{ steps.get_description.outputs.description }} + Please see the changelog: ${{ github.event.release.html_url }} + + ${{ steps.get_topics.outputs.topics }} #nfcore #openscience #nextflow #bioinformatics + + bsky-post: + runs-on: ubuntu-latest + steps: + - uses: zentered/bluesky-post-action@5a91cc2ad10a304a4e96c16182dbe4918710bcf6 # v0.4.0 + with: + post: | + Pipeline release! ${{ github.repository }} v${{ github.event.release.tag_name }} - ${{ github.event.release.name }}! + + Please see the changelog: ${{ github.event.release.html_url }} + env: + BSKY_IDENTIFIER: ${{ secrets.BSKY_IDENTIFIER }} + BSKY_PASSWORD: ${{ secrets.BSKY_PASSWORD }} + # diff --git a/.github/workflows/template-version-comment.yml b/.github/workflows/template-version-comment.yml index e8560fc7c..ea30827ec 100644 --- a/.github/workflows/template-version-comment.yml +++ b/.github/workflows/template-version-comment.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out pipeline code - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: ref: ${{ github.event.pull_request.head.sha }} @@ -29,7 +29,7 @@ jobs: run: echo "OUTPUT=$(pip list --outdated | grep nf-core)" >> ${GITHUB_ENV} - name: Post nf-core template version comment - uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2 + uses: mshick/add-pr-comment@8e4927817251f1ff60c001f04568532b38e0b4a0 # v3 if: | contains(env.OUTPUT, 'nf-core') with: @@ -42,5 +42,5 @@ jobs: > Your pipeline is using an old version of the nf-core template: ${{ steps.read_yml.outputs['nf_core_version'] }}. > Please update your pipeline to the latest version. > - > For more documentation on how to update your pipeline, please see the [nf-core documentation](https://github.com/nf-core/tools?tab=readme-ov-file#sync-a-pipeline-with-the-template) and [Synchronisation documentation](https://nf-co.re/docs/contributing/sync). + > For more documentation on how to update your pipeline, please see the [Synchronisation documentation](https://nf-co.re/docs/developing/template-syncs/overview). # diff --git a/.gitignore b/.gitignore index 6c86bf8a4..cc2b1a778 100644 --- a/.gitignore +++ b/.gitignore @@ -7,11 +7,4 @@ testing/ testing* *.pyc null/ -.idea/ -/lint_log.txt -/lint_results.md - - -#Ignore cursor AI rules -.cursor/rules/codacy.mdc -.codacy/ +.lineage/ diff --git a/.nf-core.yml b/.nf-core.yml index 0f14d5cbf..44c9b564e 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -23,7 +23,7 @@ lint: modules_config: false multiqc_config: false nextflow_config: false -nf_core_version: 3.5.1 +nf_core_version: 4.0.2 repository_type: pipeline template: author: Yasset Perez-Riverol @@ -33,4 +33,4 @@ template: name: quantms org: bigbio outdir: . - version: 1.7.0 + version: 1.8.0 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d06777a8f..f51e1a28d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ repos: hooks: - id: prettier additional_dependencies: - - prettier@3.6.2 + - prettier@3.8.3 - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: @@ -13,15 +13,21 @@ repos: exclude: | (?x)^( .*ro-crate-metadata.json$| - modules/nf-core/.*| - subworkflows/nf-core/.*| + modules/(?!local/).*| + subworkflows/(?!local/).*| .*\.snap$ )$ - id: end-of-file-fixer exclude: | (?x)^( .*ro-crate-metadata.json$| - modules/nf-core/.*| - subworkflows/nf-core/.*| + modules/(?!local/).*| + subworkflows/(?!local/).*| .*\.snap$ )$ + - repo: https://github.com/seqeralabs/nf-lint-pre-commit + rev: v0.3.0 + hooks: + - id: nextflow-lint + files: '\.nf$|nextflow\.config$' + args: ["-output", "json"] diff --git a/.prettierignore b/.prettierignore index dd749d43d..eb78728c9 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,6 +1,4 @@ email_template.html -adaptivecard.json -slackreport.json .nextflow* work/ data/ @@ -14,3 +12,6 @@ bin/ ro-crate-metadata.json modules/nf-core/ subworkflows/nf-core/ +# Ignore potentially non-human-readable markdown files +.github/**/SKILL.md +AGENT.md diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..a33b527cc --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "markdown.styles": ["public/vscode_markdown.css"] +} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..ebc18f2a0 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,839 @@ +# AI Agent Guidelines for quantms Development + +This document provides comprehensive guidance for AI agents working with the **quantms** bioinformatics pipeline. These guidelines ensure code quality, maintainability, and compliance with project standards. + +## 🚨 Critical: Mandatory Validation Before ANY Commit + +**ALWAYS run pre-commit hooks before committing ANY changes:** + +```bash +pre-commit run --all-files +``` + +This is **non-negotiable**. All code must pass formatting and style checks before being committed. + +--- + +## 📋 Table of Contents + +1. [Project Overview](#project-overview) +2. [Technology Stack](#technology-stack) +3. [Validation Workflow](#validation-workflow) +4. [Testing Strategy](#testing-strategy) +5. [Development Conventions](#development-conventions) +6. [CI/CD Awareness](#cicd-awareness) +7. [Common Tasks](#common-tasks) +8. [Troubleshooting](#troubleshooting) + +--- + +## Project Overview + +**quantms** is an nf-core bioinformatics best-practice analysis pipeline for **Quantitative Mass Spectrometry (MS)**. It supports three major analytical workflows: + +- **DDA-LFQ**: Data-dependent acquisition with label-free quantification +- **DDA-ISO**: Data-dependent acquisition with isobaric labeling (TMT, iTRAQ) +- **DIA-LFQ**: Data-independent acquisition with label-free quantification + +**Key Features:** + +- Built with Nextflow DSL2 +- Integrates multiple search engines: Comet, MSGF+, Sage, DIA-NN +- Uses OpenMS tools for proteomics processing +- Statistical analysis with MSstats +- Quality control with pmultiqc +- Complies with nf-core standards + +**Repository:** https://github.com/bigbio/quantms +**Documentation:** https://quantms.readthedocs.io/ + +--- + +## Technology Stack + +### Core Technologies + +- **Nextflow**: >=25.04.0 (DSL2 syntax) +- **nf-schema plugin**: 2.5.1 (parameter validation) +- **nf-test**: Testing framework (config: `nf-test.config`) +- **nf-core tools**: Pipeline standards and linting +- **Containers**: Docker/Singularity/Apptainer/Podman (Conda deprecated) + +### Key Configuration Files + +- `nextflow.config` - Main pipeline configuration (541 lines) +- `nextflow_schema.json` - Parameter schema (auto-generated) +- `nf-test.config` - Testing configuration +- `.nf-core.yml` - nf-core compliance settings +- `modules.json` - Module dependencies +- `.pre-commit-config.yaml` - Pre-commit hooks + +### Project Structure + +``` +quantms/ +├── main.nf # Pipeline entry point +├── workflows/ # Main workflows (quantms.nf, lfq.nf, tmt.nf, dia.nf) +├── subworkflows/local/ # Reusable subworkflows +├── modules/ # Process definitions +│ ├── local/ # Custom modules +│ ├── bigbio/ # BigBio shared modules +│ └── nf-core/ # nf-core modules +├── conf/ # Configuration files +│ ├── base.config # Resource definitions +│ ├── modules/ # Module-specific configs +│ └── tests/ # Test profile configs (13 profiles) +├── tests/ # nf-test test cases +├── bin/ # Utility scripts (R scripts for MSstats) +└── assets/ # Pipeline assets and schemas +``` + +--- + +## Validation Workflow + +### 1. Pre-commit Hooks (MANDATORY) + +**Installation:** + +```bash +pip install pre-commit +pre-commit install # Install git hooks (one-time setup) +``` + +**Run before EVERY commit:** + +```bash +pre-commit run --all-files +``` + +**Configured Hooks** (`.pre-commit-config.yaml`): + +1. **Prettier** (v3.1.0 with prettier@3.6.2) + - Formats code consistently across multiple file types + - Auto-fixes formatting issues + +2. **trailing-whitespace** + - Removes trailing whitespace (preserves markdown linebreaks) + +3. **end-of-file-fixer** + - Ensures files end with a single newline + +**Excluded Files:** + +- `CHANGELOG.md` (manually maintained) +- `modules/nf-core/**` (managed by nf-core) +- `subworkflows/nf-core/**` (managed by nf-core) +- `*.snap` (test snapshots) + +**Auto-fix in CI:** +If you forget to run pre-commit locally, comment on your PR: + +``` +@nf-core-bot fix linting +``` + +The bot will run pre-commit and push fixes automatically. + +### 2. Pipeline Linting (RECOMMENDED) + +**Run before creating PR:** + +```bash +nf-core pipelines lint +``` + +**For master branch PRs:** + +```bash +nf-core pipelines lint --release +``` + +This validates: + +- nf-core pipeline standards compliance +- File structure and naming +- Configuration completeness +- Documentation requirements + +### 3. Schema Validation (REQUIRED for parameter changes) + +**After adding/modifying parameters in `nextflow.config`:** + +```bash +nf-core pipelines schema build +``` + +This updates `nextflow_schema.json` with interactive prompts to add descriptions and validation rules. + +--- + +## Testing Strategy + +### Testing Philosophy + +**Do NOT run the full test suite before every commit.** The CI system runs comprehensive tests automatically. Instead: + +1. **Pre-commit hooks**: ALWAYS (fast, catches style issues) +2. **Targeted tests**: Run tests relevant to your changes +3. **CI validation**: Trust the CI to catch integration issues + +### When to Run Tests Locally + +#### 🟢 Documentation/Config-Only Changes + +**No testing required:** + +- README, CHANGELOG, docs/ updates +- Minor config tweaks (labels, descriptions) +- Comment additions +- Asset file updates (email templates, correction matrices) + +#### 🟡 Targeted Testing Required + +**Run specific test profile(s):** + +| Change Area | Test Profile(s) | Command | +| ----------------------- | --------------------------- | --------------------------------------------------------------------------- | +| LFQ workflow | `test_lfq` | `nextflow run . -profile test_lfq,docker --outdir results` | +| TMT/iTRAQ workflow | `test_tmt` | `nextflow run . -profile test_tmt,docker --outdir results` | +| TMT with correction | `test_tmt_corr` | `nextflow run . -profile test_tmt_corr,docker --outdir results` | +| DIA workflow | `test_dia` | `nextflow run . -profile test_dia,docker --outdir results` | +| PTM localization | `test_localize` | `nextflow run . -profile test_localize,docker --outdir results` | +| Sage search engine | `test_lfq_sage` | `nextflow run . -profile test_lfq_sage,docker --outdir results` | +| AlphaPeptDeep rescoring | `test_dda_id_alphapeptdeep` | `nextflow run . -profile test_dda_id_alphapeptdeep,docker --outdir results` | +| MS2PIP rescoring | `test_dda_id_ms2pip` | `nextflow run . -profile test_dda_id_ms2pip,docker --outdir results` | + +#### 🔴 Comprehensive Testing Required + +**Run nf-test suite:** + +```bash +# Run all tests with nf-test +nf-test test --profile debug,test,docker --verbose + +# Or run specific test file +nf-test test tests/default.nf.test --profile debug,test,docker --verbose +``` + +**When to run comprehensive tests:** + +- Core pipeline logic changes (main.nf, quantms.nf) +- Cross-cutting subworkflow modifications +- Module changes affecting multiple workflows +- Before final PR submission (optional but recommended) + +### Test Configuration Files + +All test profiles are in `conf/tests/`: + +- `test_lfq.config` - Quick LFQ test (default) +- `test_tmt.config` - TMT isobaric labeling +- `test_tmt_corr.config` - TMT with plex correction +- `test_dia.config` - DIA label-free +- `test_latest_dia.config` - Latest DIA version +- `test_localize.config` - PTM localization +- `test_lfq_sage.config` - LFQ with Sage +- `test_full_lfq.config` - Full-size LFQ dataset +- `test_full_tmt.config` - Full-size TMT dataset +- `test_full_dia.config` - Full-size DIA dataset +- `test_dda_id_alphapeptdeep.config` - AlphaPeptDeep rescoring +- `test_dda_id_ms2pip.config` - MS2PIP rescoring +- `test_dda_id_fine_tuning.config` - Fine-tuning workflow + +### Snapshot Testing + +The pipeline uses snapshot-based testing (`tests/default.nf.test`): + +- Compares stable file names and content +- Validates workflow success +- Ignores volatile files (pipeline_info/\*.{html,json,txt}) + +**Updating snapshots after intentional changes:** + +```bash +nf-test test --profile debug,test,docker --update-snapshot +``` + +--- + +## Development Conventions + +### Branch Strategy + +- **Target branch**: `dev` (NOT master) +- **Master branch**: Release-ready code only +- **PR process**: Fork → feature branch → PR to `dev` + +### Naming Conventions + +#### Channel Names + +**Initial output from a process:** + +```groovy +ch_output_from_ +``` + +**Intermediate/terminal channels:** + +```groovy +ch__for_ +``` + +**Examples:** + +```groovy +ch_output_from_comet +ch_comet_for_fdr_control +ch_fdr_for_protein_inference +``` + +#### Process/Module Names + +- Use lowercase with underscores: `peptide_indexer`, `protein_inference` +- Be descriptive: `OPENMS_PERCOLATORADAPTER` not `PERCOLATOR` +- Follow nf-core conventions for consistency + +### Resource Labels + +Defined in `conf/base.config`: + +| Label | CPU | Memory | Time | Use Case | +| ------------------ | --- | ------ | ---- | --------------------- | +| `process_single` | 1 | 6 GB | 4h | Single-threaded tools | +| `process_tiny` | 1 | 1 GB | 1h | Minimal processing | +| `process_very_low` | 2 | 12 GB | 4h | Light parallelism | +| `process_low` | 4 | 36 GB | 8h | Moderate workload | +| `process_medium` | 8 | 72 GB | 16h | Standard processing | +| `process_high` | 12 | 108 GB | 20h | Heavy computation | + +**Usage in process:** + +```groovy +process MY_PROCESS { + label 'process_medium' + + cpus task.cpus + memory task.memory +} +``` + +### Adding a New Step + +When adding a new processing step to the pipeline: + +1. **Define input/output channels** in the workflow +2. **Write process block** in `modules/local/` or reuse from nf-core/bigbio +3. **Add parameters** to `nextflow.config` with sensible defaults +4. **Update schema**: + ```bash + nf-core pipelines schema build + ``` +5. **Add parameter validation** (type, range, enum constraints) +6. **Perform local testing** with appropriate test profile +7. **Add test configuration** in `conf/tests/` if needed +8. **Update MultiQC config** (`assets/multiqc_config.yml`) if generates reports +9. **Update documentation**: + - `docs/usage.md` - Parameter descriptions + - `docs/output.md` - Output file descriptions +10. **Update CHANGELOG.md** and `CITATIONS.md` if adds new tools + +### Module Configuration + +Module-specific settings in `conf/modules/modules.config`: + +```groovy +withName: 'OPENMS_PERCOLATORADAPTER' { + ext.args = [ + params.fdr_threshold ? "-score_type q-value -threshold ${params.fdr_threshold}" : '', + params.train_FDR ? "-train_FDR ${params.train_FDR}" : '' + ].join(' ').trim() + publishDir = [ + path: { "${params.outdir}/intermediate_results/fdr_control" }, + mode: params.publish_dir_mode, + pattern: '*.idparquet' + ] +} +``` + +### Code Style + +- **Indentation**: 4 spaces (enforced by Prettier) +- **Line length**: Aim for <120 characters +- **Comments**: Use `//` for single-line, `/* */` for multi-line +- **Strings**: Use single quotes `'text'` unless interpolation needed `"$var"` +- **Groovy closures**: Follow Nextflow DSL2 patterns + +--- + +## CI/CD Awareness + +### GitHub Actions Workflows + +Understanding what runs automatically helps you anticipate issues: + +#### 1. **Linting** (`.github/workflows/linting.yml`) + +**Triggers**: All PRs, releases +**Runs**: + +- Pre-commit hooks (prettier, whitespace, EOF) +- `nf-core pipelines lint` (with `--release` for master PRs) + +**Artifacts**: `lint_log.txt`, `lint_results.md` + +#### 2. **CI Testing** (`.github/workflows/ci.yml`) + +**Triggers**: Push to dev/master, PRs, releases +**Matrix**: + +- Nextflow: `25.04.0` +- Test profiles: All 7 main profiles (lfq, tmt, dia, localize, sage, alphapeptdeep, ms2pip) +- Container: Docker + +**Steps**: + +1. Checkout with full history +2. Setup Java 17 +3. Install Nextflow +4. Free disk space +5. Run pipeline with test profile +6. Upload artifacts on failure + +**Artifacts**: Failed logs, results, nextflow logs (timestamped) + +**Concurrency**: Cancels in-progress runs for same PR + +#### 3. **Extended CI** (`.github/workflows/ci_extended.yml`) + +**Matrix**: + +- Nextflow: `25.04.0` + `latest-everything` +- Test profiles: All 8 profiles including `test_tmt_corr` +- Runs without `dev` profile on master + +#### 4. **Branch Protection** (`.github/workflows/branch.yml`) + +**Purpose**: Prevents direct PRs to master +**Action**: Only allows PRs from `dev` or `patch` branches + +#### 5. **Auto-fix Linting** (`.github/workflows/fix-linting.yml`) + +**Trigger**: Comment `@nf-core-bot fix linting` on PR +**Action**: Runs pre-commit, commits fixes, pushes changes + +### What This Means for You + +✅ **You don't need to run all tests locally** - CI does this +✅ **Pre-commit failures in CI** - Use `@nf-core-bot fix linting` +✅ **Test failures** - Check artifacts for logs +✅ **Lint failures** - Run `nf-core pipelines lint` locally first +✅ **Branch errors** - Ensure PRs target `dev` not `master` + +--- + +## Common Tasks + +### Setting Up Development Environment + +```bash +# Clone repository +git clone https://github.com/bigbio/quantms.git +cd quantms + +# Install pre-commit hooks +pip install pre-commit +pre-commit install + +# Install nf-core tools +pip install nf-core + +# Install nf-test (if testing locally) +# See: https://code.askimed.com/nf-test/installation/ +``` + +### Making Changes + +```bash +# 1. Create feature branch from dev +git checkout dev +git pull origin dev +git checkout -b feature/my-new-feature + +# 2. Make your changes +# ... edit files ... + +# 3. Run pre-commit (MANDATORY) +pre-commit run --all-files + +# 4. Update schema if parameters changed +nf-core pipelines schema build + +# 5. Run targeted tests (if code changes) +nextflow run . -profile test_lfq,docker --outdir results_test + +# 6. Commit changes +git add . +git commit -m "feat: add new feature" + +# 7. Push and create PR +git push origin feature/my-new-feature +# Create PR to dev branch on GitHub +``` + +### Updating nf-core Modules + +```bash +# List installed modules +nf-core modules list local + +# Update specific module +nf-core modules update + +# Update all modules +nf-core modules update --all +``` + +### Running Pipeline Locally + +```bash +# Basic test run +nextflow run . -profile test,docker --outdir results + +# With debug output +nextflow run . -profile debug,test,docker --outdir results + +# Specific test profile +nextflow run . -profile test_lfq,docker --outdir results + +# Resume from cache +nextflow run . -profile test,docker --outdir results -resume + +# Custom parameters +nextflow run . -profile test,docker \ + --outdir results \ + --enable_mod_localization \ + --mod_residues 'S,T,Y' \ + --mod_mass_shift 79.966331 +``` + +### Checking Pipeline Reports + +After running pipeline, check these files in `results/`: + +- `pipeline_info/execution_report.html` - Resource usage +- `pipeline_info/execution_timeline.html` - Timeline visualization +- `pipeline_info/execution_trace.txt` - Detailed trace +- `multiqc/multiqc_report.html` - Quality control report + +--- + +## Troubleshooting + +### Pre-commit Issues + +**Problem**: Pre-commit hook fails with formatting issues + +``` +Files were modified by this hook. Additional output: +``` + +**Solution**: The files were auto-fixed. Stage and commit again: + +```bash +git add . +git commit -m "your message" +``` + +--- + +**Problem**: Pre-commit is slow on large changesets + +**Solution**: Run on specific files only: + +```bash +pre-commit run --files path/to/file1.nf path/to/file2.config +``` + +--- + +### Testing Issues + +**Problem**: Test fails with "Process exceeded memory limit" + +**Solution**: Ensure you're using the `test` profile with resource limits: + +```bash +nextflow run . -profile test,docker --outdir results +``` + +The `test` profile sets `process.memory = 6.GB` and `process.cpus = 2` for CI compatibility. + +--- + +**Problem**: Snapshot test fails after intentional output changes + +**Solution**: Update snapshots: + +```bash +nf-test test --profile debug,test,docker --update-snapshot +``` + +Then commit the updated `.snap` files. + +--- + +**Problem**: Container not found / pulling issues + +**Solution**: + +1. Check internet connection +2. Use alternative container engine: + ```bash + nextflow run . -profile test,singularity --outdir results + ``` +3. For Wave-enabled containers, add `wave` profile: + ```bash + nextflow run . -profile test,docker,wave --outdir results + ``` + +--- + +**Problem**: Test data not accessible + +**Solution**: Test data is hosted on GitHub. Ensure: + +1. Internet connectivity +2. No firewall blocking GitHub raw content +3. Try with `-resume` to use cached data + +--- + +### Nextflow Issues + +**Problem**: "Nextflow version is too old" + +**Solution**: Update Nextflow: + +```bash +nextflow self-update +# Or install specific version +export NXF_VER=25.04.0 +nextflow -version +``` + +--- + +**Problem**: "Process terminated with exit code 137" + +**Solution**: Out of memory. Either: + +1. Use test profile: `-profile test,docker` +2. Increase Docker memory limit in Docker Desktop settings +3. Reduce `params.max_memory` in config + +--- + +**Problem**: "Error executing process > WORKFLOW:SUBWORKFLOW:PROCESS" + +**Solution**: + +1. Check `.nextflow.log` for details: + ```bash + tail -100 .nextflow.log + ``` +2. Check work directory for process error: + ```bash + cat work//.command.err + cat work//.command.log + ``` +3. Rerun with more verbose output: + ```bash + nextflow run . -profile debug,test,docker --outdir results + ``` + +--- + +### Schema/Parameter Issues + +**Problem**: "Unknown parameter" + +**Solution**: + +1. Check if parameter is in `nextflow.config` +2. Update schema: + ```bash + nf-core pipelines schema build + ``` +3. Validate against schema: + ```bash + nf-core pipelines schema validate params.json + ``` + +--- + +**Problem**: Schema build fails / JSON validation error + +**Solution**: + +1. Check `nextflow_schema.json` syntax: + ```bash + cat nextflow_schema.json | jq . + ``` +2. If corrupted, restore from git: + ```bash + git checkout nextflow_schema.json + nf-core pipelines schema build + ``` + +--- + +### CI/CD Issues + +**Problem**: CI tests pass locally but fail in GitHub Actions + +**Solution**: Common causes: + +1. **Resource limits**: CI has stricter limits (2 CPU, 6 GB RAM) +2. **Test profile**: Ensure using `test` profile in CI config +3. **Container differences**: CI uses different architecture (amd64) +4. **Timeouts**: CI has time limits, may need to optimize slow processes + +--- + +**Problem**: Lint check fails in CI but passes locally + +**Solution**: + +1. Ensure using same nf-core version: + ```bash + # Check version in .nf-core.yml + pip install nf-core== + ``` +2. Run lint with same flags as CI: + ```bash + nf-core pipelines lint + # For master PRs: + nf-core pipelines lint --release + ``` + +--- + +**Problem**: `@nf-core-bot fix linting` doesn't work + +**Solution**: + +1. Check bot has write permissions to your fork +2. Ensure PR is from a branch (not fork's master) +3. Manually run and commit: + ```bash + pre-commit run --all-files + git add . + git commit -m "style: apply pre-commit fixes" + git push + ``` + +--- + +### Module/Subworkflow Issues + +**Problem**: "Module not found" error + +**Solution**: + +1. Check `modules.json` for module entry +2. Install module: + ```bash + nf-core modules install + ``` +3. For local modules, verify path in `modules/local/` + +--- + +**Problem**: Module config not applied + +**Solution**: Check `conf/modules/modules.config`: + +1. Use correct selector: `withName: 'EXACT_PROCESS_NAME'` +2. Process names are case-sensitive +3. For subworkflow processes: `withName: '.*:SUBWORKFLOW:PROCESS'` + +--- + +### General Debugging Tips + +1. **Always check `.nextflow.log`** - Contains detailed error info +2. **Inspect work directory** - Failed process outputs in `work//` +3. **Use `-resume`** - Saves time by using cached results +4. **Enable debug profile** - More verbose logging: `-profile debug` +5. **Check resource usage** - View `pipeline_info/execution_report.html` +6. **Test incrementally** - Test small changes before big refactors +7. **Use nf-test** - Unit test individual processes/subworkflows + +--- + +## Additional Resources + +- **Pipeline Documentation**: https://quantms.readthedocs.io/ +- **nf-core Guidelines**: https://nf-co.re/docs/guidelines +- **Nextflow Documentation**: https://www.nextflow.io/docs/latest/ +- **nf-test Documentation**: https://code.askimed.com/nf-test/ +- **GitHub Discussions**: https://github.com/bigbio/quantms/discussions +- **Issues**: https://github.com/bigbio/quantms/issues + +--- + +## Quick Reference + +### Essential Commands + +```bash +# Pre-commit (MANDATORY before commit) +pre-commit run --all-files + +# Lint pipeline +nf-core pipelines lint + +# Update schema +nf-core pipelines schema build + +# Run LFQ test +nextflow run . -profile test_lfq,docker --outdir results + +# Run TMT test +nextflow run . -profile test_tmt,docker --outdir results + +# Run DIA test +nextflow run . -profile test_dia,docker --outdir results + +# Run nf-test suite +nf-test test --profile debug,test,docker --verbose + +# Update snapshots +nf-test test --profile debug,test,docker --update-snapshot + +# Resume pipeline +nextflow run . -profile test,docker --outdir results -resume + +# Clean work directory +nextflow clean -f +``` + +### File Locations + +- **Main config**: `nextflow.config` +- **Schema**: `nextflow_schema.json` +- **Pre-commit config**: `.pre-commit-config.yaml` +- **nf-test config**: `nf-test.config` +- **Test configs**: `conf/tests/*.config` +- **Module configs**: `conf/modules/modules.config` +- **Base resources**: `conf/base.config` +- **Main workflow**: `workflows/quantms.nf` +- **Entry point**: `main.nf` + +--- + +**Last Updated**: January 14, 2026 +**Pipeline Version**: 1.8.0dev +**Minimum Nextflow**: 25.04.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 834980a69..0250d59eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,49 @@ 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 - [23/06/2026] - [Guangzhou] + +### `Added` + +- [#690](https://github.com/bigbio/quantms/pull/690) Expose `fdr_conservative` parameter to control FDR estimation formula (Keich & Noble 2025) +- [#694](https://github.com/bigbio/quantms/pull/694) Expose Biosaur2 as alternative feature seeding algorithm for LFQ via `lfq_seeding_algorithm` parameter +- [#623](https://github.com/bigbio/quantms/pull/623) Add support for `.dia` file format and improve file format documentation + +### `Changed` + +- [#639](https://github.com/bigbio/quantms/pull/639) **BREAKING: Deprecated OpenMS experimental design format**: The pipeline now only accepts SDRF files as input. All input files are treated as SDRF regardless of file extension. Supported extensions: `.sdrf`, `.tsv`, `.csv`. +- [#651](https://github.com/bigbio/quantms/pull/651) Remove redundant SDRF-derived parameters: 4 parameters (`acquisition_method`, `labelling_type`, `enzyme`, `fixed_mods`) are now read exclusively from SDRF files +- [#644](https://github.com/bigbio/quantms/pull/644) Update pipeline for Nextflow 26 strict syntax compatibility +- [#641](https://github.com/bigbio/quantms/pull/641) Enable `ext.args` support in GENERATE_CFG module for nf-core standard compliance +- [#660](https://github.com/bigbio/quantms/pull/660) Refactor DIA-NN parameter handling for extended module validation +- [#676](https://github.com/bigbio/quantms/pull/676) Fix `.d` file support and multiple Nextflow 26 compatibility issues +- [#686](https://github.com/bigbio/quantms/pull/686) Update test configurations to fetch SDRF and FASTA files from maintained repository +- [#687](https://github.com/bigbio/quantms/pull/687) Migrate thermorawfileparser module from local to bigbio/nf-modules +- [#709](https://github.com/bigbio/quantms/pull/709) Update onsite module for improved PTM localization +- [#690](https://github.com/bigbio/quantms/pull/690), [#694](https://github.com/bigbio/quantms/pull/694) OpenMS tooling improvements including FDR conservative formula and Biosaur2 feature seeding + +### `Fixed` + +- [#689](https://github.com/bigbio/quantms/pull/689) Fix typo in openms_peak_picker processOption value (`inmermory` → `inmemory`) +- [#699](https://github.com/bigbio/quantms/pull/699) Fix Comet version reporting in pmultiqc software table + +### `Removed` + +- [#702](https://github.com/bigbio/quantms/pull/702) **Remove DIA-NN workflow from quantms**: DIA users should use the dedicated repository [bigbio/quantmsdiann](https://github.com/bigbio/quantmsdiann) +- [#701](https://github.com/bigbio/quantms/pull/701) **Remove MSstats post-processing step**: R scripts (`msstats_plfq.R`, `msstats_tmt.R`, `msstats_utils.R`) and corresponding modules removed. Users should run MSstats manually outside the pipeline. +- [#706](https://github.com/bigbio/quantms/pull/706) Remove `ms2features_range` modes (`by_sample`, `by_project`) and IDRipper module. Only `independent_run` per-file Percolator is now supported. +- [#708](https://github.com/bigbio/quantms/pull/708) Remove ConsensusID module; migrate to parquet-based processing + +### `Dependencies` + +- Updated quantms-utils to version 0.0.25 +- Updated quantms-rescoring (container permissions fix) +- Migrated thermorawfileparser to bigbio/nf-modules + +### `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` @@ -292,8 +335,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.0] nfcore/quantms - [05/02/2022] - Havana -Initial release of bigbio/quantms, created with the [nf-core](https://nf-co.re/) template. - ### `Added` - New pipeline for DDA-LFQ data analysis diff --git a/CITATIONS.md b/CITATIONS.md index ac0ef1b49..dabb78233 100644 --- a/CITATIONS.md +++ b/CITATIONS.md @@ -42,10 +42,6 @@ > Röst HL., Sachsenberg T., Aiche S., Bielow C., Weisser H., Aicheler F., Andreotti S., Ehrlich HC., Gutenbrunner P., Kenar E., Liang X., Nahnsen S., Nilse L., Pfeuffer J., Rosenberger G., Rurik M., Schmitt U., Veit J., Walzer M., Wojnar D., Wolski WE., Schilling O., Choudhary JS, Malmström L., Aebersold R., Reinert K., Kohlbacher O. (2016). OpenMS: a flexible open-source software platform for mass spectrometry data analysis. Nature methods, 13(9), 741–748. doi: 10.1038/nmeth.3959. PubMed PMID: 27575624; PubMed Central PMCID: PMC5617107. -- [DIA-NN](https://pubmed.ncbi.nlm.nih.gov/31768060/) - - > Demichev V, Messner CB, Vernardis SI, Lilley KS, Ralser M. DIA-NN: neural networks and interference correction enable deep proteome coverage in high throughput. Nat Methods. 2020 Jan;17(1):41-44. doi: 10.1038/s41592-019-0638-x. Epub 2019 Nov 25. PMID: 31768060; PMCID: PMC6949130. - - [MSstats](https://www.ncbi.nlm.nih.gov/pubmed/24794931/) > Choi M., Chang CY., Clough T., Broudy D., Killeen T., MacLean B., Vitek O. (2014). MSstats: an R package for statistical analysis of quantitative mass spectrometry-based proteomic experiments. Bioinformatics (Oxford, England), 30(17), 2524–2526. doi: 10.1093/bioinformatics/btu305. PubMed PMID: 24794931. @@ -66,17 +62,13 @@ > Pfeuffer J, Sachsenberg T, Dijkstra TMH, Serang O, Reinert K, Kohlbacher O. EPIFANY: A Method for Efficient High-Confidence Protein Inference. J Proteome Res. 2020 Mar 6;19(3):1060-1072. doi: 10.1021/acs.jproteome.9b00566. Epub 2020 Feb 13. PMID: 31975601; PMCID: PMC7583457. -- [Triqler](https://pubmed.ncbi.nlm.nih.gov/30482846/) - - > The M, Käll L. Integrated Identification and Quantification Error Probabilities for Shotgun Proteomics. Mol Cell Proteomics. 2019 Mar;18(3):561-570. doi: 10.1074/mcp.RA118.001018. Epub 2018 Nov 27. PMID: 30482846; PMCID: PMC6398204. - - [luciphor](https://pubmed.ncbi.nlm.nih.gov/23918812/) > Fermin D, Walmsley SJ, Gingras AC, Choi H, Nesvizhskii AI. LuciPHOr: algorithm for phosphorylation site localization with false localization rate estimation using modified target-decoy approach. Mol Cell Proteomics. 2013 Nov;12(11):3409-19. doi: 10.1074/mcp.M113.028928. Epub 2013 Aug 5. PMID: 23918812; PMCID: PMC3820951. - [MultiQC](https://pubmed.ncbi.nlm.nih.gov/27312411/) - > Ewels P, Magnusson M, Lundin S, Käller M. MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics. 2016 Oct 1;32(19):3047-8. doi: 10.1093/bioinformatics/btw354. Epub 2016 Jun 16. PubMed PMID: 27312411; PubMed Central PMCID: PMC5039924. +> Ewels P, Magnusson M, Lundin S, Käller M. MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics. 2016 Oct 1;32(19):3047-8. doi: 10.1093/bioinformatics/btw354. Epub 2016 Jun 16. PubMed PMID: 27312411; PubMed Central PMCID: PMC5039924. ## Software packaging/containerisation tools diff --git a/README.md b/README.md index 0a4be8db4..3227b2680 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ [![Cite with Zenodo](https://zenodo.org/badge/DOI/10.5281/zenodo.15573386.svg)](https://doi.org/10.5281/zenodo.15573386) [![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com) -[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.04.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/) -[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.4.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.4.1) +[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.10.4-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/) +[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.5.2-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.5.2) [![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/) [![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/) [![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-core/quantms) @@ -16,7 +16,11 @@ ## Introduction -**bigbio/quantms** is a bioinformatics best-practice analysis pipeline for Quantitative Mass Spectrometry (MS). Currently, the workflow supports three major MS-based analytical methods: (i) Data dependant acquisition (DDA) label-free and Isobaric quantitation (e.g. TMT, iTRAQ); (ii) Data independent acquisition (DIA) label-free quantification (for details see our in-depth documentation on [quantms](https://quantms.readthedocs.io/en/latest/)). +> [!WARNING] +> **DIA (Data Independent Acquisition) support has been moved to a dedicated pipeline.** +> For DIA proteomics data, please use [quantmsdiann](https://github.com/bigbio/quantmsdiann). + +**bigbio/quantms** is a bioinformatics best-practice analysis pipeline for Quantitative Mass Spectrometry (MS). Currently, the workflow supports two major MS-based analytical methods: (i) Data dependant acquisition (DDA) label-free quantification; (ii) Isobaric quantitation (e.g. TMT, iTRAQ) (for details see our in-depth documentation on [quantms](https://quantms.readthedocs.io/en/latest/)).

bigbio/quantms workflow overview @@ -24,11 +28,11 @@ 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 uses Docker/Singularity containers making installation trivial and results highly reproducible. The [Nextflow DSL2](https://www.nextflow.io/docs/latest/dsl2.html) implementation of this pipeline uses one container per process which makes it much easier to maintain and update software dependencies. Where possible, these processes have been submitted to and installed from [nf-core/modules](https://github.com/nf-core/modules) in order to make them available to all nf-core pipelines, and to everyone within the Nextflow community! -On release, automated continuous integration tests run the pipeline on a full-sized dataset on the AWS cloud infrastructure. This ensures that the pipeline runs on AWS, has sensible resource allocation defaults set to run on real-world datasets, and permits the persistent storage of results to benchmark between pipeline releases and other analysis sources. The results obtained from the full-sized test can be viewed on the [nf-core website](https://nf-co.re/quantms/results). This gives you a hint on which reports and file types are produced by the pipeline in a standard run. The automatic continuous integration tests on every pull request evaluate different workflows, including peptide identification, quantification for LFQ, LFQ-DIA, and TMT test datasets. +On release, automated continuous integration tests run the pipeline on a full-sized dataset on the AWS cloud infrastructure. This ensures that the pipeline runs on AWS, has sensible resource allocation defaults set to run on real-world datasets, and permits the persistent storage of results to benchmark between pipeline releases and other analysis sources. The results obtained from the full-sized test can be viewed on the [nf-core website](https://nf-co.re/quantms/results). This gives you a hint on which reports and file types are produced by the pipeline in a standard run. The automatic continuous integration tests on every pull request evaluate different workflows, including peptide identification, quantification for LFQ and TMT test datasets. ## Pipeline summary -**bigbio/quantms** allows uses to perform analyses of three main types of analytical mass spectrometry-based quantitative methods: DDA-LFQ, DDA-ISO, DIA-LFQ. Each of these workflows share some processes but also includes their own steps. In summary: +**bigbio/quantms** allows uses to perform analyses of two main types of analytical mass spectrometry-based quantitative methods: DDA-LFQ and DDA-ISO. Each of these workflows share some processes but also includes their own steps. In summary: ### DDA-LFQ (data-dependent label-free quantification) @@ -57,14 +61,6 @@ On release, automated continuous integration tests run the pipeline on a full-si 10. QC report generation [`pmultiqc`](https://github.com/bigbio/pmultiqc) 11. Normalization, imputation, significance testing with [`MSstats`](https://github.com/VitekLab/MSstats) -### DIA-LFQ (data-independent label-free quantification) - -1. RAW file conversion to mzML when RAW as input([`thermorawfileparser`](https://github.com/compomics/ThermoRawFileParser)) -2. Performing an [optional step](https://github.com/bigbio/quantms/blob/HEAD/modules/local/utils/tdf2mzml/main.nf): Converting .d to mzML when bruker data as input and set `convert_dotd` to true -3. DIA-NN analysis [`dia-nn`](https://github.com/vdemichev/DiaNN/) -4. Generation of output files (msstats) -5. QC reports generation [`pmultiqc`](https://github.com/bigbio/pmultiqc) - ### Functionality overview A graphical overview of suggested routes through the pipeline depending on context can be seen below. @@ -76,7 +72,7 @@ A graphical overview of suggested routes through the pipeline depending on conte ## Usage > [!NOTE] -> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data. +> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/get_started/environment_setup/overview) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/get_started/run-your-first-pipeline) with `-profile test` before running the workflow on actual data. ### Supported file formats @@ -85,7 +81,6 @@ The pipeline supports the following mass spectrometry data file formats: - **`.raw`** - Thermo RAW files (automatically converted to mzML) - **`.mzML`** - Open standard mzML files - **`.d`** - Bruker timsTOF files (optionally converted to mzML when `--convert_dotd` is set) -- **`.dia`** - DIA-NN native binary format (passed through without conversion) Compressed variants are supported for `.raw`, `.mzML`, and `.d` formats: @@ -99,6 +94,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=*). @@ -116,8 +112,7 @@ nextflow run bigbio/quantms \ > Conda is no longer supported in this pipeline. Please use Docker, Singularity, or other container-based profiles. > [!WARNING] -> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; -> see [docs](https://nf-co.re/usage/configuration#custom-configuration-files). +> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; see [docs](https://nf-co.re/docs/running/run-pipelines#using-parameter-files). For more details and further functionality, please refer to the [usage documentation](https://nf-co.re/quantms/usage) and the [parameter documentation](https://nf-co.re/quantms/parameters). @@ -144,7 +139,7 @@ We thank the following people for their extensive assistance in the development ## Contributions and Support -If you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md). +If you would like to contribute to this pipeline, please see the [contributing guidelines](docs/CONTRIBUTING.md). For further information or help, don't hesitate to get in touch on the [Slack `#quantms` channel](https://nfcore.slack.com/channels/quantms) (you can join with [this invite](https://nf-co.re/join/slack)). diff --git a/assets/adaptivecard.json b/assets/adaptivecard.json deleted file mode 100644 index 8d42ffe97..000000000 --- a/assets/adaptivecard.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "type": "message", - "attachments": [ - { - "contentType": "application/vnd.microsoft.card.adaptive", - "contentUrl": null, - "content": { - "\$schema": "http://adaptivecards.io/schemas/adaptive-card.json", - "msteams": { - "width": "Full" - }, - "type": "AdaptiveCard", - "version": "1.2", - "body": [ - { - "type": "TextBlock", - "size": "Large", - "weight": "Bolder", - "color": "<% if (success) { %>Good<% } else { %>Attention<%} %>", - "text": "bigbio/quantms v${version} - ${runName}", - "wrap": true - }, - { - "type": "TextBlock", - "spacing": "None", - "text": "Completed at ${dateComplete} (duration: ${duration})", - "isSubtle": true, - "wrap": true - }, - { - "type": "TextBlock", - "text": "<% if (success) { %>Pipeline completed successfully!<% } else { %>Pipeline completed with errors. The full error message was: ${errorReport}.<% } %>", - "wrap": true - }, - { - "type": "TextBlock", - "text": "The command used to launch the workflow was as follows:", - "wrap": true - }, - { - "type": "TextBlock", - "text": "${commandLine}", - "isSubtle": true, - "wrap": true - } - ], - "actions": [ - { - "type": "Action.ShowCard", - "title": "Pipeline Configuration", - "card": { - "type": "AdaptiveCard", - "\$schema": "http://adaptivecards.io/schemas/adaptive-card.json", - "body": [ - { - "type": "FactSet", - "facts": [<% out << summary.collect{ k,v -> "{\"title\": \"$k\", \"value\" : \"$v\"}" - }.join(",\n") %> - ] - } - ] - } - } - ] - } - } - ] -} diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index 4b9131d57..40d716fd1 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -1,7 +1,5 @@ report_comment: > - This report has been generated by the bigbio/quantms - analysis pipeline. For information about how to interpret these results, please see the - documentation. + This report has been generated by the bigbio/quantms analysis pipeline. For information about how to interpret these results, please see the documentation. report_section_order: pmultiqc: order: 1000 @@ -77,7 +75,7 @@ sp: fn: "*_ms_info.parquet" num_lines: 0 pmultiqc/idXML: - fn: "*.idXML" + fn: "*.idparquet" num_lines: 0 pmultiqc/msstats: fn: "*msstats_in.csv" diff --git a/assets/slackreport.json b/assets/slackreport.json deleted file mode 100644 index 487dd5600..000000000 --- a/assets/slackreport.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "attachments": [ - { - "fallback": "Plain-text summary of the attachment.", - "color": "<% if (success) { %>good<% } else { %>danger<%} %>", - "author_name": "bigbio/quantms ${version} - ${runName}", - "author_icon": "https://www.nextflow.io/docs/latest/_static/favicon.ico", - "text": "<% if (success) { %>Pipeline completed successfully!<% } else { %>Pipeline completed with errors<% } %>", - "fields": [ - { - "title": "Command used to launch the workflow", - "value": "```${commandLine}```", - "short": false - } - <% - if (!success) { %> - , - { - "title": "Full error message", - "value": "```${errorReport}```", - "short": false - }, - { - "title": "Pipeline configuration", - "value": "<% out << summary.collect{ k,v -> k == "hook_url" ? "_${k}_: (_hidden_)" : ( ( v.class.toString().contains('Path') || ( v.class.toString().contains('String') && v.contains('/') ) ) ? "_${k}_: `${v}`" : (v.class.toString().contains('DateTime') ? ("_${k}_: " + v.format(java.time.format.DateTimeFormatter.ofLocalizedDateTime(java.time.format.FormatStyle.MEDIUM))) : "_${k}_: ${v}") ) }.join(",\n") %>", - "short": false - } - <% } - %> - ], - "footer": "Completed at <% out << dateComplete.format(java.time.format.DateTimeFormatter.ofLocalizedDateTime(java.time.format.FormatStyle.MEDIUM)) %> (duration: ${duration})" - } - ] -} diff --git a/assets/tmt18plex_default_correction.matrix b/assets/tmt18plex_default_correction.matrix index 79563f28d..7a4448513 100644 --- a/assets/tmt18plex_default_correction.matrix +++ b/assets/tmt18plex_default_correction.matrix @@ -1,20 +1,20 @@ -# comment: tmt18plex default -channel/<-2C13>/<-N15-C13>/<-C13>/<-N15>/<+N15>/<+C13>/<+N15+C13>/<+2C13> -126/0.00/0.00/0.00/0.00/0.10/10.40/0.00/0.30 -127N/0.00/0.00/0.00/0.60/0.00/9.80/0.00/0.30 -127C/0.00/0.00/0.80/0.00/0.20/8.40/0.00/0.30 -128N/0.00/0.00/0.70/0.50/0.00/5.20/0.00/0.20 -128C/0.00/0.00/1.40/0.00/0.30/6.30/0.00/0.20 -129N/0.00/0.10/1.30/0.90/0.00/7.50/0.00/0.10 -129C/0.10/0.00/2.60/0.00/0.30/6.10/0.00/0.10 -130N/0.00/0.00/2.40/0.50/0.00/5.50/0.00/0.00 -130C/0.30/0.00/3.20/0.00/0.30/5.10/0.00/0.10 -131N/0.00/0.00/2.70/0.50/0.00/3.10/0.00/0.10 -131C/0.10/0.00/4.00/0.00/1.20/3.60/0.00/0.00 -132N/0.00/0.00/3.10/0.70/0.00/3.40/0.00/0.00 -132C/0.10/0.00/5.10/0.00/1.20/1.90/0.00/0.00 -133N/0.10/0.00/3.40/0.60/0.00/1.20/0.00/0.00 -133C/0.20/0.00/4.10/0.00/0.40/1.10/0.00/0.00 -134N/0.30/0.10/5.50/0.40/0.00/1.10/0.00/0.00 -134C/0.00/0.00/5.50/0.00/0.30/0.00/0.00/0.00 -135N/0.20/0.00/5.80/0.30/0.00/0.00/0.00/0.00 +# comment: tmt18plex default +channel/<-2C13>/<-N15-C13>/<-C13>/<-N15>/<+N15>/<+C13>/<+N15+C13>/<+2C13> +126/0.00/0.00/0.00/0.00/0.10/10.40/0.00/0.30 +127N/0.00/0.00/0.00/0.60/0.00/9.80/0.00/0.30 +127C/0.00/0.00/0.80/0.00/0.20/8.40/0.00/0.30 +128N/0.00/0.00/0.70/0.50/0.00/5.20/0.00/0.20 +128C/0.00/0.00/1.40/0.00/0.30/6.30/0.00/0.20 +129N/0.00/0.10/1.30/0.90/0.00/7.50/0.00/0.10 +129C/0.10/0.00/2.60/0.00/0.30/6.10/0.00/0.10 +130N/0.00/0.00/2.40/0.50/0.00/5.50/0.00/0.00 +130C/0.30/0.00/3.20/0.00/0.30/5.10/0.00/0.10 +131N/0.00/0.00/2.70/0.50/0.00/3.10/0.00/0.10 +131C/0.10/0.00/4.00/0.00/1.20/3.60/0.00/0.00 +132N/0.00/0.00/3.10/0.70/0.00/3.40/0.00/0.00 +132C/0.10/0.00/5.10/0.00/1.20/1.90/0.00/0.00 +133N/0.10/0.00/3.40/0.60/0.00/1.20/0.00/0.00 +133C/0.20/0.00/4.10/0.00/0.40/1.10/0.00/0.00 +134N/0.30/0.10/5.50/0.40/0.00/1.10/0.00/0.00 +134C/0.00/0.00/5.50/0.00/0.30/0.00/0.00/0.00 +135N/0.20/0.00/5.80/0.30/0.00/0.00/0.00/0.00 diff --git a/bin/msstats_plfq.R b/bin/msstats_plfq.R deleted file mode 100755 index d0541d90a..000000000 --- a/bin/msstats_plfq.R +++ /dev/null @@ -1,240 +0,0 @@ -#!/usr/bin/env Rscript - -# R script to run MSstats for LFQ data. -# License: Apache 2.0 -# Author: Dai Chengxin, Julianus Pfeuffer, Yasset Perez-Riverol - -# load the MSstats library -require(MSstats) -require(tibble) -require(data.table) - -# TODO: Functions shared between msstats_plfq and msstats_tmt should be merge in msstats_utils.R -# Please functions syncronized between the three scripts until the code can be merged. - -### Begining Functions section - -#' Inizialize the TMT and LFQ parameters -#' -#' @param usage message to exit the script analysis -#' -#' @return -initialize_msstats <- function(usage) { - args <- commandArgs(trailingOnly = TRUE) - if (length(args) < 1) { - print(usage) - stop("At least the first argument must be supplied (input csv).n", call. = FALSE) - } - if (length(args) < 2) { - args[2] <- "pairwise" - } - - if (length(args) < 3) { - # default control condition - args[3] <- "" - } - - if (length(args) < 4) { - # removeOneFeatProts - args[4] <- FALSE - } - return(args) -} - -#' Handle the number of contrasts in the differential expression analysis. -#' It returns a matrix of the contrasts to be analyzed. -#' -#' @param l -#' @param contrast_str -#' @param lvls number of doncitions -#' -#' @return -#' -parse_contrasts <- function(l, contrast_str, lvls) { - if (contrast_str == "pairwise") { - if (control_str == "") { - contrast_mat <- matrix(nrow = l * (l - 1) / 2, ncol = l, dimnames = list(Contrasts = rep(NA, l * (l - 1) / 2), Levels = lvls)) - c <- 1 - for (i in 1:(l - 1)) { - for (j in (i + 1):l) { - comparison <- rep(0, l) - comparison[i] <- 1 - comparison[j] <- -1 - contrast_mat[c,] <- comparison - rownames(contrast_mat)[c] <- paste0(lvls[i], "-", lvls[j]) - c <- c + 1 - } - } - } else { - control <- which(as.character(lvls) == control_str) - if (length(control) == 0) { - stop("Control condition not part of found levels.n", call. = FALSE) - } - contrast_mat <- matrix(nrow = l - 1, ncol = l, dimnames = list(Contrasts = rep(NA, l - 1), Levels = lvls)) - c <- 1 - for (j in setdiff(1:l, control)) { - comparison <- rep(0, l) - comparison[i] <- -1 - comparison[j] <- 1 - contrast_mat[c,] <- comparison - rownames(contrast_mat)[c] <- paste0(lvls[i], "-", lvls[j]) - c <- c + 1 - } - } - } else { - contrast_lst <- unlist(strsplit(contrast_str, ";")) - contrast_mat <- make_contrasts(contrast_lst, lvls) - } - print("Contrasts to be tested:") - print(contrast_mat) - return(contrast_mat) -} - -#' This functions hels to define the contrasts that will be compare. -#' -#' @param contrasts -#' @param levels -#' -#' @return -make_contrasts <- function(contrasts, levels) { - #helper function - indicatorRow <- function(pos,len){ - row <- rep(0,len) - row[pos] <- 1 - return(row) - } - - if (is.factor(levels)) levels <- levels(levels) - if (!is.character(levels)) levels <- colnames(levels) - - l <- length(levels) - if (l < 1){ - stop("No levels given") - } - - ncontr <- length(contrasts) - if (ncontr < 1){ - stop("No contrasts given") - } - - levelsenv <- new.env() - for (i in 1:l) { - assign(levels[i], indicatorRow(i,l), pos=levelsenv) - } - - contrastmat <- matrix(0, l, ncontr, dimnames=list(Levels=levels,Contrasts=contrasts)) - for (j in 1:ncontr) { - contrastsj <- parse(text=contrasts[j]) - contrastmat[,j] <- eval(contrastsj, envir=levelsenv) - } - return(t(contrastmat)) -} - -#' Get missing samples by condition -#' -#' @param processedData -#' -#' @return -get_missing_in_condition <- function(processedData) { - p <- processedData - n_samples <- aggregate(p$SUBJECT, by = list(p$GROUP), FUN = function(x) {return(length(unique(as.numeric(x))))}) - colnames(n_samples) <- c("GROUP", "n_samples") - p <- p[complete.cases(p["LogIntensities"]),][,c("Protein", "GROUP", "SUBJECT")] - p_dup <- p[!duplicated(p),] - p_dup_agg <- aggregate(p_dup$SUBJECT, by = list(p_dup$Protein, p_dup$GROUP), length) - colnames(p_dup_agg) <- c("Protein", "GROUP", "non_na") - agg_join <- merge(p_dup_agg, n_samples, by = "GROUP") - agg_join$missingInCondition <- 1 - agg_join$non_na / agg_join$n_samples - - p <- dcast(setDT(agg_join), Protein~GROUP, value.var = "missingInCondition") - return(p) - } - -### End Function Sections - -char_to_boolean <- c("true"=TRUE, "false"=FALSE) -usage <- "Rscript msstats_plfq.R input.csv [list of contrasts or 'pairwise'] [default control condition or ''] ..." - -#TODO rewrite mzTab in next version -args <- initialize_msstats(usage = usage) - -removeOneFeatProts <- args[4] -if(typeof(removeOneFeatProts) == 'character'){ - removeOneFeatProts <- char_to_boolean[removeOneFeatProts] -} - -if (length(args)<5) { - # keeps features with only one or two measurements across runs - args[5] <- TRUE -} -removeFewMeasurements <- args[5] - -if(typeof(removeFewMeasurements) == 'character'){ - removeFewMeasurements <- char_to_boolean[removeFewMeasurements] -} - -if (length(args)<6) { - # which features to use for quantification per protein: 'top3' or 'highQuality' which removes outliers only" - args[6] <- 'top3' -} -if (length(args)<7) { - # which summary method to use: 'TMP' (Tukey's median polish) or 'linear' (linear mixed model) - args[7] <- 'TMP' -} -if (length(args)<8) { - # outputPrefix - args[8] <- './msstats' -} -if (length(args)<9) { - # adjusted p-value threshold - args[9] <- 0.05 -} - -csv_input <- args[1] -contrast_str <- args[2] -control_str <- args[3] - -# read dataframe into MSstats -data <- read.csv(csv_input) -quant <- OpenMStoMSstatsFormat(data, removeProtein_with1Feature = removeOneFeatProts, removeFewMeasurements=removeFewMeasurements) - -# process data -processed.quant <- dataProcess(quant, censoredInt = 'NA', featureSubset = args[6], summaryMethod = args[7]) - -lvls <- levels(as.factor(data$Condition)) -l <- length(lvls) - -if (l == 1) { - print("Only one condition found. No contrasts to be tested. If this is not the case, please check your experimental design.") -} else { - contrast_mat <- parse_contrasts(l = l, contrast_str = contrast_str, lvls = lvls) - print ("Contrasts to be tested:") - print (contrast_mat) - test.MSstats <- groupComparison(contrast.matrix=contrast_mat, data=processed.quant) - - mic <- get_missing_in_condition(processed.quant$ProteinLevelData) - test.MSstats$ComparisonResult <- merge(x=test.MSstats$ComparisonResult, y=mic, by="Protein") - commoncols <- intersect(colnames(mic), colnames(test.MSstats$ComparisonResult)) - test.MSstats$ComparisonResult[, commoncols] <- apply(test.MSstats$Comparison[, commoncols], 2, function(x) {x[is.na(x)] <- 1; return(x)}) - - #write all comparisons into one CSV file - write.table(test.MSstats$ComparisonResult, file=paste0(args[8],"_comparisons.csv"), quote=FALSE, sep='\t', row.names = FALSE) - - valid_comp_data <- test.MSstats$ComparisonResult[!is.na(test.MSstats$ComparisonResult$pvalue), ] - if (nrow(valid_comp_data[!duplicated(valid_comp_data$Protein),]) < 2) { - warning("Warning: Not enough proteins with valid p-values for comparison. Skipping groupComparisonPlots step!") - } else { - groupComparisonPlots(data=test.MSstats$ComparisonResult, type="ComparisonPlot", sig=as.numeric(args[9]), - width=12, height=12,dot.size = 2) - - groupComparisonPlots(data=valid_comp_data, type="VolcanoPlot", sig=as.numeric(args[9]), - width=12, height=12,dot.size = 2) - - # Otherwise it fails since the behaviour is undefined - if (nrow(contrast_mat) > 1) { - groupComparisonPlots(data=test.MSstats$ComparisonResult, type="Heatmap", sig=as.numeric(args[9]), - width=12, height=12,dot.size = 2) - } - } - -} diff --git a/bin/msstats_tmt.R b/bin/msstats_tmt.R deleted file mode 100755 index ffc8bfbcd..000000000 --- a/bin/msstats_tmt.R +++ /dev/null @@ -1,965 +0,0 @@ -#!/usr/bin/env Rscript - -# R script to run MSstatsTMT for TMT data. -# License: Apache 2.0 -# Author: Dai Chengxin, Julianus Pfeuffer, Yasset Perez-Riverol - -# Rscript bin/msstats_tmt.R PDC000114.sdrf_openms_design_msstats_in.csv "pairwise" "" true true true \ -# sum msstats true true true PDC000114.sdrf_openms_design_msstats_in 0.05 false -# Parameters: -# 1. input csv file -# 2. contrast type: pairwise -# 3. control condition: "" -# 4. rmProtein_with1Feature: true or false -# 5. useUniquePeptide: true or false -# 6. rmPSM_withfewMea_withinRun: true or false -# 7. summarization method: sum or max -# 8. summarization method to protein-level: msstats(default) -# 9. global median normalization on peptide level data: true or false -# 10. remove norm channel: true or false -# 11. reference norm channel: true or false -# 12. output prefix: PDC000114.sdrf_openms_design_msstats_in -# 13. adjusted p-value threshold: 0.05 -# 14. generate profile plot: true or false (default) - - - -require(MSstatsTMT) -require(stats) -require(gplots) -require(ggrepel) -require(marray) -require(data.table) -require(ggplot2) - -# TODO: Functions shared between msstats_plfq and msstats_tmt should be merge in msstats_utils.R -# Please functions syncronized between the three scripts until the code can be merged. - -### Begining Functions section - -#' Inizialize the TMT and LFQ parameters -#' -#' @param usage message to exit the script analysis -#' -#' @return -initialize_msstats <- function(usage) { - args <- commandArgs(trailingOnly = TRUE) - if (length(args) < 1) { - print(usage) - stop("At least the first argument must be supplied (input csv).n", call. = FALSE) - } - if (length(args) < 2) { - args[2] <- "pairwise" - } - - if (length(args) < 3) { - # default control condition - args[3] <- "" - } - - if (length(args) < 4) { - # removeOneFeatProts - args[4] <- FALSE - } - return(args) -} - -#' Handle the number of contrasts in the differential expression analysis. -#' It returns a matrix of the contrasts to be analyzed. -#' -#' @param l -#' @param contrast_str -#' @param lvls number of doncitions -#' -#' @return -#' -parse_contrasts <- function(l, contrast_str, lvls) { - if (contrast_str == "pairwise") { - if (control_str == "") { - contrast_mat <- matrix(nrow = l * (l - 1) / 2, ncol = l, dimnames = list(Contrasts = rep(NA, l * (l - 1) / 2), Levels = lvls)) - c <- 1 - for (i in 1:(l - 1)) { - for (j in (i + 1):l) { - comparison <- rep(0, l) - comparison[i] <- 1 - comparison[j] <- -1 - contrast_mat[c, ] <- comparison - rownames(contrast_mat)[c] <- paste0(lvls[i], "-", lvls[j]) - c <- c + 1 - } - } - } else { - control <- which(as.character(lvls) == control_str) - if (length(control) == 0) { - stop("Control condition not part of found levels.\n", call. = FALSE) - } - contrast_mat <- matrix(nrow = l - 1, ncol = l, dimnames = list(Contrasts = rep(NA, l - 1), Levels = lvls)) - c <- 1 - for (j in setdiff(1:l, control)) { - comparison <- rep(0, l) - comparison[control] <- -1 # Fixed: use 'control' instead of 'i' - comparison[j] <- 1 - contrast_mat[c, ] <- comparison - rownames(contrast_mat)[c] <- paste0(lvls[j], "-", lvls[control]) # Fixed: compare j vs. control - c <- c + 1 - } - } - } else { - contrast_lst <- unlist(strsplit(contrast_str, ";")) - contrast_mat <- make_contrasts(contrast_lst, lvls) - } - print("Contrasts to be tested:") - print(contrast_mat) - return(contrast_mat) -} - -#' This functions hels to define the contrasts that will be compare. -#' -#' @param contrasts -#' @param levels -#' -#' @return -make_contrasts <- function(contrasts, levels) { - # helper function - indicatorRow <- function(pos, len) { - row <- rep(0, len) - row[pos] <- 1 - return(row) - } - - if (is.factor(levels)) levels <- levels(levels) - if (!is.character(levels)) levels <- colnames(levels) - - l <- length(levels) - if (l < 1) { - stop("No levels given") - } - - ncontr <- length(contrasts) - if (ncontr < 1) { - stop("No contrasts given") - } - - levelsenv <- new.env() - for (i in 1:l) { - assign(levels[i], indicatorRow(i, l), pos = levelsenv) - } - - contrastmat <- matrix(0, l, ncontr, dimnames = list(Levels = levels, Contrasts = contrasts)) - for (j in 1:ncontr) { - contrastsj <- parse(text = contrasts[j]) - contrastmat[, j] <- eval(contrastsj, envir = levelsenv) - } - return(t(contrastmat)) -} - -#' Get missing samples by condition -#' -#' @param processedData -#' -#' @return -get_missing_in_condition <- function(processedData) { - p <- processedData - n_samples <- aggregate(p$SUBJECT, by = list(p$GROUP), FUN = function(x) { - return(length(unique(as.numeric(x)))) - }) - colnames(n_samples) <- c("GROUP", "n_samples") - p <- p[complete.cases(p["LogIntensities"]), ][, c("Protein", "GROUP", "SUBJECT")] - p_dup <- p[!duplicated(p), ] - p_dup_agg <- aggregate(p_dup$SUBJECT, by = list(p_dup$Protein, p_dup$GROUP), length) - colnames(p_dup_agg) <- c("Protein", "GROUP", "non_na") - agg_join <- merge(p_dup_agg, n_samples, by = "GROUP") - agg_join$missingInCondition <- 1 - agg_join$non_na / agg_join$n_samples - - p <- dcast(setDT(agg_join), Protein ~ GROUP, value.var = "missingInCondition") - return(p) -} - -#' Check groupComparisonPlots parameters -#' @param type type of a plot: HEATMAP/VOLCANOPLOT/COMPARISONPLOT -#' @param log_base 2 or 10 -#' @param selected_labels character vector of contrast labels -#' @param all_labels character vector of all contrast labels -#' @keywords internal -.checkGCPlotsInput <- function(type, log_base, selected_labels, all_labels) { - checkmate::assertChoice(type, c("HEATMAP", "VOLCANOPLOT", "COMPARISONPLOT")) - checkmate::assertChoice(log_base, c(2, 10)) - if (selected_labels != "all") { - if (is.character(selected_labels)) { - chosen_labels <- selected_labels - wrong_labels <- setdiff(chosen_labels, all_labels) - if (length(wrong_labels) > 0) { - msg_1 <- paste( - "Please check labels of comparisons.", - "Result does not have the following comparisons:" - ) - msg_2 <- paste(wrong_labels, sep = ", ", collapse = ", ") - msg <- paste(msg_1, msg_2) - stop(msg) - } - } - if (is.numeric(selected_labels)) { - n_labels <- length(all_labels) - if (n_labels < max(selected_labels)) { - msg <- paste( - "Please check your selection of comparisons. There are", - n_labels, "comparisons in this result." - ) - stop(msg) - } else { - chosen_labels <- all_labels[selected_labels] - } - } - } else { - chosen_labels <- all_labels - } - chosen_labels -} - - -#' @importFrom stats quantile dist -#' @keywords internal -.getOrderedMatrix <- function(input, type) { - input_tmp <- input - input_tmp[is.na(input)] <- 50 - if (toupper(type) == "PROTEIN") { - input <- input[hclust(dist(input_tmp), method = "ward.D")$order, ] - } else if (toupper(type) == "COMPARISON") { - input <- input[, hclust(dist(t(input_tmp)), method = "ward.D")$order] - } else if (toupper(type) == "BOTH") { - input <- input[ - hclust(dist(input_tmp), method = "ward.D")$order, - hclust(dist(t(input)), method = "ward.D")$order - ] - } - input -} - - -#' Create heatmap -#' @param input data.table -#' @inheritParams groupComparisonPlots -#' @keywords internal -.makeHeatmap <- function(input, my.colors, my.breaks, x.axis.size, y.axis.size) { - par(oma = c(3, 0, 0, 4)) - heatmap.2(as.matrix(input), - col = my.colors, - Rowv = FALSE, Colv = FALSE, - dendrogram = "none", breaks = my.breaks, - trace = "none", na.color = "grey", - cexCol = (x.axis.size / 10), - cexRow = (y.axis.size / 10), - key = FALSE, - lhei = c(0.1, 0.9), lwid = c(0.1, 0.9) - ) -} - - -#' Create a volcano plot -#' @inheritParams groupComparisonPlots -#' @param input data.table -#' @param label_name contrast label -#' @param log_base_FC 2 or 10 -#' @param log_base_pval 2 or 10 -#' @keywords internal -.makeVolcano <- function( - input, label_name, log_base_FC, log_base_pval, x.lim, ProteinName, dot.size, - y.limdown, y.limup, text.size, FCcutoff, sig, x.axis.size, y.axis.size, - legend.size, log_adjp) { - Protein <- NULL - - plot <- ggplot( - aes_string( - x = "logFC", - y = log_adjp, - color = "colgroup", - label = "Protein" - ), - data = input - ) + - geom_point(size = dot.size) + - scale_colour_manual( - values = c("gray65", "blue", "red"), - limits = c("black", "blue", "red"), - breaks = c("black", "blue", "red"), - labels = c("No regulation", "Down-regulated", "Up-regulated") - ) + - scale_y_continuous(paste0("-Log", log_base_pval, " (adjusted p-value)"), - limits = c(y.limdown, y.limup) - ) + - labs(title = unique(label_name)) - plot <- plot + - scale_x_continuous(paste0("Log", log_base_pval, " fold change"), - limits = c(-x.lim, x.lim) - ) - if (ProteinName) { - if (!(length(unique(input$colgroup)) == 1 & any(unique(input$colgroup) == "black"))) { - plot <- plot + - geom_text_repel( - data = input[input$colgroup != "black", ], - aes(label = Protein), - size = text.size, - col = "black" - ) - } - } - if (!FCcutoff | is.numeric(FCcutoff)) { - l <- ifelse(!FCcutoff, 20, 10) - sigcut <- data.table::setnames( - data.table::data.table( - "sigline", - seq(-x.lim, x.lim, length.out = l), - (-log(sig, base = log_base_pval)), - "twodash" - ), - c("Protein", "logFC", log_adjp, "line") - ) - } - if (!FCcutoff) { - plot <- plot + - geom_line( - data = sigcut, - aes_string(x = "logFC", y = log_adjp, linetype = "line"), - colour = "darkgrey", - size = 0.6, - show.legend = TRUE - ) + - scale_linetype_manual( - values = c("twodash" = 6), - labels = c(paste0("Adj p-value cutoff (", sig, ")")) - ) + - guides( - colour = guide_legend(override.aes = list(linetype = 0)), - linetype = guide_legend() - ) - } - if (is.numeric(FCcutoff)) { - FCcutpos <- data.table::setnames( - data.table( - "sigline", - log(FCcutoff, log_base_pval), - seq(y.limdown, y.limup, length.out = 10), - "dotted" - ), - c("Protein", "logFC", log_adjp, "line") - ) - FCcutneg <- data.table::setnames( - data.table( - "sigline", - (-log(FCcutoff, log_base_pval)), - seq(y.limdown, y.limup, length.out = 10), - "dotted" - ), - c("Protein", "logFC", log_adjp, "line") - ) - plot <- plot + - geom_line( - data = sigcut, - aes_string(x = "logFC", y = log_adjp, linetype = "line"), - colour = "darkgrey", - size = 0.6, - show.legend = TRUE - ) + - geom_line( - data = FCcutpos, - aes_string(x = "logFC", y = log_adjp, linetype = "line"), - colour = "darkgrey", - size = 0.6, - show.legend = TRUE - ) + - geom_line( - data = FCcutneg, - aes_string(x = "logFC", y = log_adjp, linetype = "line"), - colour = "darkgrey", - size = 0.6 - ) + - scale_linetype_manual( - values = c("dotted" = 3, "twodash" = 6), - labels = c( - paste0("Fold change cutoff (", FCcutoff, ")"), - paste0("Adj p-value cutoff (", sig, ")") - ) - ) + - guides( - colour = guide_legend(override.aes = list(linetype = 0)), - linetype = guide_legend() - ) - } - plot <- plot + - theme_msstats("VOLCANOPLOT", x.axis.size, y.axis.size, - legend.size, - strip_background = element_rect(), - strip_text_x = element_text(), - legend_position = "bottom", legend.title = element_blank() - ) - plot -} - - -#' Create comparison plot -#' @param input data.table -#' @param log_base 2 or 10 -#' @inheritParams groupComparisonPlots -#' @keywords internal -.makeComparison <- function( - input, log_base, dot.size, x.axis.size, y.axis.size, - text.angle, hjust, vjust, y.limdown, y.limup) { - logFC <- ciw <- NULL - - protein <- unique(input$Protein) - plot <- ggplot(input, aes_string(x = "Label", y = "logFC")) + - geom_errorbar(aes(ymax = logFC + ciw, ymin = logFC - ciw), - data = input, - width = 0.1, - colour = "red" - ) + - geom_point( - size = dot.size, - colour = "darkred" - ) + - scale_x_discrete("Comparison") + - geom_hline( - yintercept = 0, - linetype = "twodash", - colour = "darkgrey", - size = 0.6 - ) + - labs(title = protein) + - theme_msstats("COMPARISONPLOT", x.axis.size, y.axis.size, - text_angle = text.angle, text_hjust = hjust, - text_vjust = vjust - ) - plot <- plot + - scale_y_continuous(paste0("Log", log_base, "-Fold Change"), - limits = c(y.limdown, y.limup) - ) - plot -} - -groupComparisonPlots <- function( - data, type, sig = 0.05, FCcutoff = FALSE, logBase.pvalue = 10, ylimUp = FALSE, - ylimDown = FALSE, xlimUp = FALSE, x.axis.size = 10, y.axis.size = 10, - dot.size = 3, text.size = 4, text.angle = 0, legend.size = 13, - ProteinName = TRUE, colorkey = TRUE, numProtein = 100, clustering = "both", - width = 10, height = 10, which.Comparison = "all", which.Protein = "all", - address = "") { - Label <- Protein <- NULL - - type <- toupper(type) - input <- data.table::as.data.table(data) - all_labels <- as.character(unique(data$Label)) - log_base_FC <- ifelse(is.element("log2FC", colnames(data)), 2, 10) - - chosen_labels <- .checkGCPlotsInput( - type, logBase.pvalue, which.Comparison, - all_labels - ) - input <- input[Label %in% chosen_labels] - input[, Protein := factor(Protein)] - input[, Label := factor(Label)] - - if (type == "HEATMAP") { - .plotHeatmap( - input, logBase.pvalue, ylimUp, FCcutoff, sig, clustering, - numProtein, colorkey, width, height, log_base_FC, - x.axis.size, y.axis.size, address - ) - } - if (type == "VOLCANOPLOT") { - .plotVolcano( - input, which.Comparison, address, width, height, logBase.pvalue, - ylimUp, ylimDown, FCcutoff, sig, xlimUp, ProteinName, dot.size, - text.size, legend.size, x.axis.size, y.axis.size, log_base_FC - ) - } - if (type == "COMPARISONPLOT") { - .plotComparison( - input, which.Protein, address, width, height, sig, ylimUp, - ylimDown, text.angle, dot.size, x.axis.size, y.axis.size, - log_base_FC - ) - } -} - - -#' Prepare data for heatmaps and plot them -#' @inheritParams groupComparisonPlots -#' @param input data.table -#' @param log_base_pval log base for p-values -#' @param log_base_FC log base for log-fold changes - 2 or 10 -#' @keywords internal -.plotHeatmap <- function( - input, log_base_pval, ylimUp, FCcutoff, sig, clustering, numProtein, colorkey, - width, height, log_base_FC, x.axis.size, y.axis.size, address) { - adj.pvalue <- heat_val <- NULL - - if (length(unique(input$Protein)) <= 1) { - stop("At least two proteins are needed for heatmaps.") - } - if (length(unique(input$Label)) <= 1) { - stop("At least two comparisons are needed for heatmaps.") - } - - if (is.numeric(ylimUp)) { - y.limUp <- ylimUp - } else { - y.limUp <- ifelse(log_base_pval == 2, 30, 10) - input[adj.pvalue < log_base_pval^(-y.limUp), adj.pvalue := log_base_pval^(-y.limUp)] - } - - if (is.numeric(FCcutoff)) { - input$adj.pvalue <- ifelse(input[, 3] < log(FCcutoff, log_base_FC) & input[, 3] > -log(FCcutoff, log_base_FC), - 1, input$adj.pvalue - ) - } - - input[, heat_val := -log(adj.pvalue, log_base_pval) * sign(input[, 3])] - wide <- data.table::dcast(input, Protein ~ Label, - value.var = "heat_val" - ) - proteins <- wide$Protein - wide <- as.matrix(wide[, -1]) - rownames(wide) <- proteins - wide <- wide[rowSums(!is.na(wide)) != 0, colSums(!is.na(wide)) != 0] - wide <- .getOrderedMatrix(wide, clustering) - - blue.red.18 <- maPalette(low = "blue", high = "red", mid = "black", k = 12) - my.colors <- blue.red.18 - my.colors <- c(my.colors, "grey") # for NA - up <- 10 - temp <- 10^(-sort(ceiling(seq(2, up, length = 10)[c(1, 2, 3, 5, 10)]), decreasing = TRUE)) - breaks <- c(temp, sig) - neg.breaks <- log(breaks, log_base_pval) - my.breaks <- c(neg.breaks, 0, -neg.breaks[6:1], 101) - blocks <- c(-breaks, 1, breaks[6:1]) - x.at <- seq(-0.05, 1.05, length.out = 13) - namepro <- rownames(wide) - totalpro <- length(namepro) - numheatmap <- totalpro %/% numProtein + 1 - if (colorkey) { - par(mar = c(3, 3, 3, 3), mfrow = c(3, 1), oma = c(3, 0, 3, 0)) - plot.new() - image( - z = matrix(seq(seq_len(length(my.colors) - 1)), ncol = 1), - col = my.colors[-length(my.colors)], - xaxt = "n", - yaxt = "n" - ) - mtext("Color Key", side = 3, line = 1, cex = 3) - mtext("(sign) Adjusted p-value", side = 1, line = 3, at = 0.5, cex = 1.7) - mtext(blocks, side = 1, line = 1, at = x.at, cex = 1) - } - - savePlot(address, "Heatmap", width, height) - for (j in seq_len(numheatmap)) { - if (j != numheatmap) { - partial_wide <- wide[((j - 1) * numProtein + 1):(j * numProtein), ] - } else { - partial_wide <- wide[((j - 1) * numProtein + 1):nrow(wide), ] - } - heatmap <- .makeHeatmap(partial_wide, my.colors, my.breaks, x.axis.size, y.axis.size) - } - if (address != FALSE) { - dev.off() - } -} - - -#' Save a plot to pdf file -#' -#' @inheritParams .saveTable -#' @param width width of a plot -#' @param height height of a plot -#' -#' @return NULL -#' -#' @export -#' -savePlot <- function(name_base, file_name, width, height) { - if (name_base != FALSE) { - all_files <- list.files(".") - if (file_name == "ProfilePlot") { - num_same_name <- sum(grepl(paste0("^", name_base, file_name, "_[0-9]?"), all_files)) - } else { - num_same_name <- sum(grepl(paste0("^", name_base, file_name, "[0-9]?"), all_files)) - } - if (num_same_name > 0) { - file_name <- paste(file_name, num_same_name + 1, sep = "_") - } - file_path <- paste0(name_base, file_name, ".pdf") - pdf(file_path, width = width, height = height) - } - NULL -} - -#' Theme for MSstats plots -#' -#' @param type type of a plot -#' @param x.axis.size size of text on the x axis -#' @param y.axis.size size of text on the y axis -#' @param legend_size size of the legend -#' @param strip_background background of facet -#' @param strip_text_x size of text on facets -#' @param legend_position position of the legend -#' @param legend_box legend.box -#' @param text_angle angle of text on the x axis (for condition and comparison plots) -#' @param text_hjust hjust parameter for x axis text (for condition and comparison plots) -#' @param text_vjust vjust parameter for x axis text (for condition and comparison plots) -#' @param ... additional parameters passed on to ggplot2::theme() -#' -#' @import ggplot2 -#' @export -#' -theme_msstats <- function( - type, x.axis.size = 10, y.axis.size = 10, legend_size = 13, - strip_background = element_rect(fill = "gray95"), - strip_text_x = element_text(colour = c("black"), size = 14), - legend_position = "top", legend_box = "vertical", text_angle = 0, text_hjust = NULL, text_vjust = NULL, - ...) { - if (type %in% c("CONDITIONPLOT", "COMPARISONPLOT")) { - ggplot2::theme( - panel.background = element_rect(fill = "white", colour = "black"), - axis.title.x = element_text(size = x.axis.size + 5, vjust = -0.4), - axis.title.y = element_text(size = y.axis.size + 5, vjust = 0.3), - axis.ticks = element_line(colour = "black"), - title = element_text(size = x.axis.size + 8, vjust = 1.5), - panel.grid.major.y = element_line(colour = "grey95"), - panel.grid.minor.y = element_blank(), - axis.text.y = element_text(size = y.axis.size, colour = "black"), - axis.text.x = element_text( - size = x.axis.size, colour = "black", - angle = text_angle, hjust = text_hjust, - vjust = text_vjust - ), - ... - ) - } else { - ggplot2::theme( - panel.background = element_rect(fill = "white", colour = "black"), - legend.key = element_rect(fill = "white", colour = "white"), - panel.grid.minor = element_blank(), - strip.background = strip_background, - axis.text.x = element_text(size = x.axis.size, colour = "black"), - axis.text.y = element_text(size = y.axis.size, colour = "black"), - axis.title.x = element_text(size = x.axis.size + 5, vjust = -0.4), - axis.title.y = element_text(size = y.axis.size + 5, vjust = 0.3), - axis.ticks = element_line(colour = "black"), - title = element_text(size = x.axis.size + 8, vjust = 1.5), - strip.text.x = strip_text_x, - legend.position = legend_position, - legend.box = legend_box, - legend.text = element_text(size = legend_size), - ... - ) - } -} - -#' Get proteins based on names or integer IDs -#' -#' @param chosen_proteins protein names or integers IDs -#' @param all_proteins all unique proteins -#' -#' @return character -#' -#' @export -getSelectedProteins <- function(chosen_proteins, all_proteins) { - if (is.character(chosen_proteins)) { - selected_proteins <- chosen_proteins - missing_proteins <- setdiff(selected_proteins, all_proteins) - if (length(missing_proteins) > 0) { - stop(paste("Please check protein name. Dataset does not have this protein. -", - toString(missing_proteins), - sep = " " - )) - } - } - if (is.numeric(chosen_proteins)) { - selected_proteins <- all_proteins[chosen_proteins] - if (length(all_proteins) < max(chosen_proteins)) { - stop(paste( - "Please check your selection of proteins. There are ", - length(all_proteins), " proteins in this dataset." - )) - } - } - selected_proteins -} - -#' Preprocess data for volcano plots and create them -#' @inheritParams groupComparisonPlots -#' @keywords internal -.plotVolcano <- function( - input, which.Comparison, address, width, height, log_base_pval, - ylimUp, ylimDown, FCcutoff, sig, xlimUp, ProteinName, dot.size, - text.size, legend.size, x.axis.size, y.axis.size, log_base_FC) { - adj.pvalue <- colgroup <- logFC <- Protein <- issue <- Label <- newlogFC <- NULL - - log_adjp <- paste0("log", log_base_pval, "adjp") - all_labels <- unique(input$Label) - input <- input[!is.na(adj.pvalue), ] - colname_log_fc <- intersect(colnames(input), c("log2FC", "log10FC")) - data.table::setnames(input, colname_log_fc, c("logFC")) - - if (address == FALSE) { - if (which.Comparison == "all") { - if (length(unique(input$Label)) > 1) { - stop("** Cannnot generate all volcano plots in a screen. Please set one comparison at a time.") - } - } else if (length(which.Comparison) > 1) { - stop("** Cannnot generate multiple volcano plots in a screen. Please set one comparison at a time.") - } - } - - if (is.numeric(ylimUp)) { - y.limUp <- ylimUp - } else { - y.limUp <- ifelse(log_base_pval == 2, 30, 10) - } - input[, adj.pvalue := ifelse(adj.pvalue < log_base_pval^(-y.limUp), - log_base_pval^(-y.limUp), adj.pvalue - )] - - if (!FCcutoff) { - logFC_cutoff <- 0 - } else { - logFC_cutoff <- log(FCcutoff, log_base_FC) - } - input[, colgroup := ifelse(adj.pvalue >= sig, "black", - ifelse(logFC > logFC_cutoff, - "red", "blue" - ) - )] - input[, colgroup := factor(colgroup, levels = c("black", "blue", "red"))] - input[, Protein := as.character(Protein)] - input[ - !is.na(issue) & issue == "oneConditionMissing", - Protein := paste0("*", Protein) - ] - - savePlot(address, "VolcanoPlot", width, height) - for (i in seq_along(all_labels)) { - label_name <- all_labels[i] - single_label <- input[Label == label_name, ] - - y.limup <- ceiling(max(-log(single_label[!is.na(single_label$adj.pvalue), "adj.pvalue"], log_base_pval))) - if (y.limup < (-log(sig, log_base_pval))) { - y.limup <- (-log(sig, log_base_pval) + 1) ## for too small y.lim - } - y.limdown <- ifelse(is.numeric(ylimDown), ylimDown, 0) - x_ceiling <- ceiling(max(abs(single_label[!is.na(single_label$logFC) & is.finite(single_label$logFC), logFC]))) - x.lim <- ifelse(is.numeric(xlimUp), xlimUp, ifelse((x_ceiling < 3), 3, x_ceiling)) - - single_label[[log_adjp]] <- -log(single_label$adj.pvalue, log_base_pval) - single_label$newlogFC <- single_label$logFC - single_label[!is.na(issue) & - issue == "oneConditionMissing" & - logFC == Inf, newlogFC := (x.lim - 0.2)] - single_label[!is.na(issue) & - issue == "oneConditionMissing" & - logFC == (-Inf), newlogFC := (x.lim - 0.2) * (-1)] - plot <- .makeVolcano( - single_label, label_name, log_base_FC, log_base_pval, x.lim, ProteinName, dot.size, - y.limdown, y.limup, text.size, FCcutoff, sig, x.axis.size, y.axis.size, - legend.size, log_adjp - ) - print(plot) - } - if (address != FALSE) { - dev.off() - } -} - - -#' Preprocess data for comparison plots and create them -#' @inheritParams groupComparisonPlots -#' @param input data.table -#' @param log_base_FC log base for log-fold changes - 2 or 10 -#' @keywords internal -.plotComparison <- function( - input, proteins, address, width, height, sig, ylimUp, ylimDown, - text.angle, dot.size, x.axis.size, y.axis.size, log_base_FC) { - adj.pvalue <- Protein <- ciw <- NULL - - input <- input[!is.na(adj.pvalue), ] - all_proteins <- unique(input$Protein) - - if (address == FALSE) { - if (proteins == "all" | length(proteins) > 1) { - stop("** Cannnot generate all comparison plots in a screen. Please set one protein at a time.") - } - } - if (proteins != "all") { - selected_proteins <- getSelectedProteins(proteins, all_proteins) - input <- input[Protein %in% selected_proteins, ] - } - - all_proteins <- unique(input$Protein) - input$Protein <- factor(input$Protein) - savePlot(address, "ComparisonPlot", width, height) - log_fc_column <- intersect(colnames(input), c("log2FC", "log10FC")) - for (i in seq_along(all_proteins)) { - single_protein <- input[Protein == all_proteins[i], ] - single_protein[, ciw := qt(1 - sig / (2 * nrow(single_protein)), single_protein$DF) * single_protein$SE] - data.table::setnames(single_protein, log_fc_column, "logFC") - y.limup <- ifelse(is.numeric(ylimUp), ylimUp, ceiling(max(single_protein$logFC + single_protein$ciw))) - y.limdown <- ifelse(is.numeric(ylimDown), ylimDown, floor(min(single_protein$logFC - single_protein$ciw))) - hjust <- ifelse(text.angle != 0, 1, 0.5) - vjust <- ifelse(text.angle != 0, 1, 0.5) - - plot <- .makeComparison( - single_protein, log_base_FC, dot.size, x.axis.size, - y.axis.size, text.angle, hjust, vjust, y.limdown, - y.limup - ) - print(plot) - } - if (address != FALSE) { - dev.off() - } -} - -### End Function Sections - -char_to_boolean <- c("true" = TRUE, "false" = FALSE) -usage <- "Rscript msstats_tmt.R input.csv [list of contrasts or 'pairwise'] [default control condition or '']... [normalization based reference channel]" - -args <- initialize_msstats(usage = usage) - -rmProtein_with1Feature <- args[4] -if (typeof(rmProtein_with1Feature) == "character") { - rmProtein_with1Feature <- char_to_boolean[rmProtein_with1Feature] -} - -if (length(args) < 5) { - # use unique peptide - args[5] <- TRUE -} -useUniquePeptide <- args[5] -if (typeof(useUniquePeptide) == "character") { - useUniquePeptide <- char_to_boolean[useUniquePeptide] -} - -if (length(args) < 6) { - # remove the features that have 1 or 2 measurements within each Run. - args[6] <- TRUE -} -rmPSM_withfewMea_withinRun <- args[6] -if (typeof(rmPSM_withfewMea_withinRun) == "character") { - rmPSM_withfewMea_withinRun <- char_to_boolean[rmPSM_withfewMea_withinRun] -} - -if (length(args) < 7) { - # sum or max - when there are multiple measurements for certain feature in certain Run. - args[7] <- "sum" -} - -if (length(args) < 8) { - # summarization methods to protein-level can be performed: "msstats(default)" - args[8] <- "msstats" -} - -if (length(args) < 9) { - # Global median normalization on peptide level data - args[9] <- TRUE -} -global_norm <- args[9] -if (typeof(global_norm) == "character") { - global_norm <- char_to_boolean[global_norm] -} - -if (length(args) < 10) { - # Remove norm channel - args[10] <- TRUE -} -remove_norm_channel <- args[10] -if (typeof(remove_norm_channel) == "character") { - remove_norm_channel <- char_to_boolean[remove_norm_channel] -} - -if (length(args) < 11) { - # default Reference channel based normalization between MS runs on protein level data. - # Reference Channel annotated by 'Norm' in Condition. - args[11] <- TRUE -} -reference_norm <- args[11] -if (typeof(reference_norm) == "character") { - reference_norm <- char_to_boolean[reference_norm] -} - -if (length(args) < 12) { - # outputPrefix - args[12] <- "./msstats" -} - -if (length(args) < 13) { - # adjusted p-value threshold - args[13] <- 0.05 -} - -if (length(args) < 14) { - # Plot profile plot for all proteins - args[14] <- FALSE -} -plot_profile_all <- args[14] -if (typeof(plot_profile_all) == "character") { - plot_profile_all <- char_to_boolean[plot_profile_all] -} - -csv_input <- args[1] -contrast_str <- args[2] -control_str <- args[3] - -# read dataframe into MSstatsTMT -data <- read.csv(csv_input) -quant <- OpenMStoMSstatsTMTFormat(data, - useUniquePeptide = useUniquePeptide, rmPSM_withfewMea_withinRun = rmPSM_withfewMea_withinRun, - rmProtein_with1Feature = rmProtein_with1Feature -) - -# protein summarization -processed.quant <- proteinSummarization(quant, - method = args[8], remove_empty_channel = TRUE, global_norm = global_norm, - reference_norm = reference_norm, remove_norm_channel = remove_norm_channel -) - -if (plot_profile_all) { - dataProcessPlotsTMT(processed.quant, "ProfilePlot", width = 12, height = 12, which.Protein = "all") - dataProcessPlotsTMT(processed.quant, "QCPlot", width = 12, height = 12, which.Protein = "allonly") -} - -lvls <- levels(as.factor(processed.quant$ProteinLevelData$Condition)) -l <- length(lvls) - -if (l == 1) { - print("Only one condition found. No contrasts to be tested. If this is not the case, please check your experimental design.") -} else { - contrast_mat <- parse_contrasts(l = l, contrast_str = contrast_str, lvls = lvls) - print("Contrasts to be tested:") - print(contrast_mat) - # TODO allow for user specified contrasts - test.MSstatsTMT <- groupComparisonTMT(contrast.matrix = contrast_mat, data = processed.quant) - - # TODO allow manual input (e.g. proteins of interest) - write.table(test.MSstatsTMT$ComparisonResult, file = paste0(args[12], "_comparisons.csv"), quote = FALSE, sep = "\t", row.names = FALSE) - - valid_comp_data <- test.MSstatsTMT$ComparisonResult[!is.na(test.MSstatsTMT$ComparisonResult$pvalue), ] - - if (nrow(valid_comp_data[!duplicated(valid_comp_data$Protein), ]) < 2) { - warning("Warning: Not enough proteins with valid p-values for comparison. Skipping groupComparisonPlots step!") - } else { - groupComparisonPlots(data = test.MSstatsTMT$ComparisonResult, type = "ComparisonPlot", sig = as.numeric(args[13]), width = 12, height = 12, dot.size = 2) - - groupComparisonPlots( - data = valid_comp_data, type = "VolcanoPlot", sig = as.numeric(args[13]), - width = 12, height = 12, dot.size = 2 - ) - - # Otherwise it fails since the behavior is undefined - if (nrow(contrast_mat) > 1) { - groupComparisonPlots( - data = test.MSstatsTMT$ComparisonResult, type = "Heatmap", sig = as.numeric(args[13]), - width = 12, height = 12, dot.size = 2 - ) - } - } -} diff --git a/bin/msstats_utils.R b/bin/msstats_utils.R deleted file mode 100644 index d44370c18..000000000 --- a/bin/msstats_utils.R +++ /dev/null @@ -1,139 +0,0 @@ -### Begining Functions section - -#' Inizialize the TMT and LFQ parameters -#' -#' @param usage message to exit the script analysis -#' -#' @return -initialize_msstats <- function(usage) { - args <- commandArgs(trailingOnly = TRUE) - if (length(args) < 1) { - print(usage) - stop("At least the first argument must be supplied (input csv).n", call. = FALSE) - } - if (length(args) < 2) { - args[2] <- "pairwise" - } - - if (length(args) < 3) { - # default control condition - args[3] <- "" - } - - if (length(args) < 4) { - # removeOneFeatProts - args[4] <- FALSE - } - return(args) -} - -#' Handle the number of contrasts in the differential expression analysis. -#' It returns a matrix of the contrasts to be analyzed. -#' -#' @param l -#' @param contrast_str -#' @param lvls number of doncitions -#' -#' @return -#' -parse_contrasts <- function(l, contrast_str, lvls) { - if (contrast_str == "pairwise") { - if (control_str == "") { - contrast_mat <- matrix(nrow = l * (l - 1) / 2, ncol = l, dimnames = list(Contrasts = rep(NA, l * (l - 1) / 2), Levels = lvls)) - c <- 1 - for (i in 1:(l - 1)) { - for (j in (i + 1):l) { - comparison <- rep(0, l) - comparison[i] <- 1 - comparison[j] <- -1 - contrast_mat[c,] <- comparison - rownames(contrast_mat)[c] <- paste0(lvls[i], "-", lvls[j]) - c <- c + 1 - } - } - } else { - control <- which(as.character(lvls) == control_str) - if (length(control) == 0) { - stop("Control condition not part of found levels.n", call. = FALSE) - } - contrast_mat <- matrix(nrow = l - 1, ncol = l, dimnames = list(Contrasts = rep(NA, l - 1), Levels = lvls)) - c <- 1 - for (j in setdiff(1:l, control)) { - comparison <- rep(0, l) - comparison[i] <- -1 - comparison[j] <- 1 - contrast_mat[c,] <- comparison - rownames(contrast_mat)[c] <- paste0(lvls[i], "-", lvls[j]) - c <- c + 1 - } - } - } else { - contrast_lst <- unlist(strsplit(contrast_str, ";")) - contrast_mat <- make_contrasts(contrast_lst, lvls) - } - print("Contrasts to be tested:") - print(contrast_mat) - return(contrast_mat) -} - -#' This functions hels to define the contrasts that will be compare. -#' -#' @param contrasts -#' @param levels -#' -#' @return -make_contrasts <- function(contrasts, levels) { - #helper function - indicatorRow <- function(pos,len){ - row <- rep(0,len) - row[pos] <- 1 - return(row) - } - - if (is.factor(levels)) levels <- levels(levels) - if (!is.character(levels)) levels <- colnames(levels) - - l <- length(levels) - if (l < 1){ - stop("No levels given") - } - - ncontr <- length(contrasts) - if (ncontr < 1){ - stop("No contrasts given") - } - - levelsenv <- new.env() - for (i in 1:l) { - assign(levels[i], indicatorRow(i,l), pos=levelsenv) - } - - contrastmat <- matrix(0, l, ncontr, dimnames=list(Levels=levels,Contrasts=contrasts)) - for (j in 1:ncontr) { - contrastsj <- parse(text=contrasts[j]) - contrastmat[,j] <- eval(contrastsj, envir=levelsenv) - } - return(t(contrastmat)) -} - -#' Get missing samples by condition -#' -#' @param processedData -#' -#' @return -get_missing_in_condition <- function(processedData) { - p <- processedData - n_samples <- aggregate(p$SUBJECT, by = list(p$GROUP), FUN = function(x) {return(length(unique(as.numeric(x))))}) - colnames(n_samples) <- c("GROUP", "n_samples") - p <- p[complete.cases(p["LogIntensities"]),][,c("Protein", "GROUP", "SUBJECT")] - p_dup <- p[!duplicated(p),] - p_dup_agg <- aggregate(p_dup$SUBJECT, by = list(p_dup$Protein, p_dup$GROUP), length) - colnames(p_dup_agg) <- c("Protein", "GROUP", "non_na") - agg_join <- merge(p_dup_agg, n_samples, by = "GROUP") - agg_join$missingInCondition <- 1 - agg_join$non_na / agg_join$n_samples - - p <- dcast(setDT(agg_join), Protein~GROUP, value.var = "missingInCondition") - return(p) - } - -### End Function Sections diff --git a/conf/base.config b/conf/base.config index a9fe49c97..b9146baa7 100644 --- a/conf/base.config +++ b/conf/base.config @@ -10,11 +10,12 @@ process { + // TODO nf-core: Check the defaults for all processes cpus = { 1 * task.attempt } memory = { 6.GB * task.attempt } time = { 4.h * task.attempt } - errorStrategy = { task.exitStatus in ((130..145) + 104 + 175) ? 'retry' : 'finish' } + errorStrategy = { task.exitStatus in ((130..145) + 104 + (175..177)) ? 'retry' : 'finish' } maxRetries = 1 maxErrors = '-1' @@ -23,29 +24,20 @@ process { // These labels are used and recognised by default in DSL2 files hosted on nf-core/modules. // If possible, it would be nice to keep the same label naming convention when // adding in your local modules too. - - withLabel:process_tiny { - cpus = { 1 } - memory = { 1.GB * task.attempt } - time = { 1.h * task.attempt } - } + // TODO nf-core: Customise requirements for specific processes. + // See https://www.nextflow.io/docs/latest/config.html#config-process-selectors withLabel:process_single { cpus = { 1 } memory = { 6.GB * task.attempt } time = { 4.h * task.attempt } } withLabel:process_low { - cpus = { 4 * task.attempt } + cpus = { 2 * task.attempt } memory = { 12.GB * task.attempt } - time = { 6.h * task.attempt } - } - withLabel:process_very_low { - cpus = { 2 * task.attempt} - memory = { 4.GB * task.attempt} - time = { 3.h * task.attempt} + time = { 4.h * task.attempt } } withLabel:process_medium { - cpus = { 8 * task.attempt } + cpus = { 6 * task.attempt } memory = { 36.GB * task.attempt } time = { 8.h * task.attempt } } diff --git a/conf/dev.config b/conf/dev.config index cafcbe19a..c630801fd 100644 --- a/conf/dev.config +++ b/conf/dev.config @@ -19,11 +19,11 @@ params { process { withLabel: openms { // Conda is no longer supported - container = {"${ ( workflow.containerEngine == 'singularity' || workflow.containerEngine == 'apptainer' ) && !task.ext.singularity_pull_docker_container ? 'oras://ghcr.io/openms/openms-tools-thirdparty-sif:latest' : 'ghcr.io/openms/openms-tools-thirdparty:latest' }"} + container = {"${ ( workflow.containerEngine == 'singularity' || workflow.containerEngine == 'apptainer' ) && !task.ext.singularity_pull_docker_container ? 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2026.06.06' : 'ghcr.io/bigbio/openms-tools-thirdparty:2026.06.06' }"} } // ONSITE uses its own container (not OpenMS thirdparty) withName: '.*:PHOSPHO_SCORING:ONSITE' { - container = {"${ ( workflow.containerEngine == 'singularity' || workflow.containerEngine == 'apptainer' ) && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/pyonsite:0.0.2--pyhdfd78af_0' : 'quay.io/biocontainers/pyonsite:0.0.2--pyhdfd78af_0' }"} + container = {"${ ( workflow.containerEngine == 'singularity' || workflow.containerEngine == 'apptainer' ) && !task.ext.singularity_pull_docker_container ? 'oras://ghcr.io/bigbio/pyonsite-sif:0.0.5' : 'ghcr.io/bigbio/pyonsite:0.0.5' }"} } } diff --git a/conf/modules/id.config b/conf/modules/id.config new file mode 100644 index 000000000..6221e69f0 --- /dev/null +++ b/conf/modules/id.config @@ -0,0 +1,31 @@ +/* +======================================================================================== + ID/PSM processing module options — shared across DDA workflows +======================================================================================== +*/ + +process { + + // ONSITE phospho scoring + withName: '.*:ID:PHOSPHO_SCORING:ONSITE' { + ext.args = "-debug $params.onsite_debug" + } + + // PERCOLATOR + withName: '.*:PERCOLATOR' { + ext.args = [ + "-debug $params.percolator_debug", + (params.fdr_level != 'psm_level_fdrs') ? "-" + params.fdr_level : "" + ].join(' ').trim() + } + + // MS2RESCORE + withName: 'MSRESCORE_FEATURES' { + ext.args = [ + "--ms2_model ${params.ms2features_model}", + "--calibration_set_size ${params.ms2features_calibration}", + params.ms2features_generators.trim() ? "--feature_generators ${params.ms2features_generators}" : '' + ].join(' ').trim() + } + +} diff --git a/conf/modules/lfq.config b/conf/modules/lfq.config new file mode 100644 index 000000000..a56770350 --- /dev/null +++ b/conf/modules/lfq.config @@ -0,0 +1,13 @@ +/* +======================================================================================== + LFQ module options — LFQ-specific processes +======================================================================================== +*/ + +process { + + // PROTEOMICSLFQ + withName: '.*:LFQ:PROTEOMICSLFQ' { + ext.args = "-debug $params.plfq_debug" + } +} diff --git a/conf/modules/modules.config b/conf/modules/modules.config deleted file mode 100644 index 979da993a..000000000 --- a/conf/modules/modules.config +++ /dev/null @@ -1,233 +0,0 @@ -/* -======================================================================================== - Config file for defining DSL2 per module options -======================================================================================== - Available keys to override module options: - ext.args = Additional arguments appended to command in module. - ext.args2 = Second set of arguments appended to command in module (multi-tool modules). - ext.args3 = Third set of arguments appended to command in module (multi-tool modules). - ext.prefix = File name prefix for output files. ----------------------------------------------------------------------------------------- -*/ - -process { - // Set default publish directory default naming for each module - //publishDir = [ - // path: { "${params.outdir}/${task.process.tokenize(':')[-1].toLowerCase()}" }, - // mode: params.publish_dir_mode, - // saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - //] - - // Set default publish directory for software versions - withName: 'BIGBIO_QUANTMS:QUANTMS:CUSTOM_DUMPSOFTWAREVERSIONS' { - publishDir = [ - path: { "${params.outdir}/pipeline_info" }, - mode: 'copy', - pattern: '*_versions.yml' - ] - } - - // Set default publish directory for pmultiqc reports - withName: 'BIGBIO_QUANTMS:QUANTMS:SUMMARY_PIPELINE' { - publishDir = [ - path: { "${params.outdir}/pmultiqc" }, - mode: 'copy', - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - - // Set default publish directory for SDRF files - withName: 'BIGBIO_QUANTMS:QUANTMS:INPUT_CHECK:SAMPLESHEET_CHECK' { - publishDir = [ - path: { "${params.outdir}/sdrf" }, - mode: 'copy', - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - - // Set default publish directory for configurations files from SDRF parsing - withName: '.*:SDRF_PARSING' { - publishDir = [ - path: { "${params.outdir}/sdrf" }, - mode: 'copy', - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - - // Set default publish directory for all msstats outputs lfq and tmt - withName: '.*:MSSTATS_LFQ|MSSTATS_TMT' { - publishDir = [ - path: { "${params.outdir}/msstats" }, - mode: 'copy', - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - - // Result tables from multiple pipelines including LFQ, TMT, DIA, DDA - withName: '.*:PROTEOMICSLFQ|PROTEIN_QUANTIFIER|MSSTATS_CONVERTER|FINAL_QUANTIFICATION|CONVERT_RESULTS' { - publishDir = [ - path: { "${params.outdir}/quant_tables" }, - mode: 'copy', - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - - // Set default publish directory for all psm tables on id workflow - withName: '.*:PSM_CONVERSION' { - publishDir = [ - path: { "${params.outdir}/psm_tables" }, - mode: 'copy', - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } -} - -// Set default publish directory for all features tables -if (params.mzml_features) { - process { - - withName: '.*:MZML_STATISTICS' { - publishDir = [ - path: { "${params.outdir}/spectra/mzml_statistics" }, - mode: 'copy', - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - } -} - - -if (params.search_engines.split(",").size() > 1) { - process { - // FDRCONSENSUSID - withName: '.*:FDR_CONSENSUSID' { - ext.args = "-PSM true -protein false" - } - } -} - -if (params.enable_mod_localization) { - process { - - // ID_SCORE_SWITCHER_ONSITE - withName: '.*:ID:PHOSPHO_SCORING:ID_SCORE_SWITCHER' { - ext.args = [ - "-new_score_orientation lower_better", - "-old_score \"q-value\"", - "-new_score_type \"Posterior Error Probability\"", - "-debug $params.idscoreswitcher_debug" - ].join(' ').trim() - } - - // onsite - withName: '.*:ID:PHOSPHO_SCORING:ONSITE' { - ext.args = "-debug $params.onsite_debug" - } - } -} - -process { - - // IDMAPPER - withName: '.*:TMT:.*:ID_MAPPER' { - ext.args = "-debug $params.idmapper_debug" - } - - // IDFILTER on PROTEIN LEVEL - level = params.protein_quant == 'strictly_unique_peptides' ? 'prot' : 'proteingroup' - decoys_present = params.quantify_decoys ? ' ' : '-remove_decoys' - withName: '.*:TMT:PROTEIN_INFERENCE:ID_FILTER' { - ext.args = [ - "-score:${level} \"$params.protein_level_fdr_cutoff\"", - "-score:psm \"$params.psm_level_fdr_cutoff\"", - "-delete_unreferenced_peptide_hits", - "${decoys_present}" - ].join(' ').trim() - ext.suffix = '.consensusXML' - } - - // PROTEINQUANTIFIER - withName: '.*:TMT:PROTEIN_QUANT:PROTEIN_QUANTIFIER' { - ext.args = "-debug $params.protein_quant_debug" - } - - // MSSTATSCONVERTER - withName: '.*:TMT:PROTEIN_QUANT:MSSTATS_CONVERTER' { - ext.args = "-debug $params.protein_quant_debug" - } - - //PERCOLATOR - withName: '.*:PERCOLATOR' { - ext.args = [ - "-debug $params.percolator_debug", - (params.fdr_level != 'psm_level_fdrs') ? "-" + params.fdr_level : "" - ].join(' ').trim() - } -} - -if (params.protein_inference_method.equals("bayesian")) { - process { - // EPIFANY - withName: '.*:PROTEIN_INFERENCE_EPIFANY' { - ext.args = "-keep_best_psm_only false -debug $params.protein_inference_debug" - } - } -} else { - process { - // PROTEIN_INFERENCE - withName: '.*:PROTEIN_INFERENCE' { - ext.args = "-debug $params.protein_inference_debug" - } - } -} - -process { - // IDFILTER - withName: '.*:ID:PSM_FDR_CONTROL:ID_FILTER' { - ext.args = "-score:psm \"$params.run_fdr_cutoff\"" - ext.suffix = '.idXML' - } - - withName: '.*:DDA_ID:PSM_FDR_CONTROL:ID_FILTER' { - ext.args = "-score:psm \"$params.run_fdr_cutoff\"" - ext.suffix = '.idXML' - } - - // PROTEOMICSLFQ - withName: '.*:LFQ:PROTEOMICSLFQ' { - ext.args = "-debug $params.plfq_debug" - } - - // DIA-NN - - withName: ".*:DIA:INSILICO_LIBRARY_GENERATION" { - ext.args = [ - "--met-excision", - ].join(' ').trim() - } - - withName: ".*:DIA:PRELIMINARY_ANALYSIS" { - ext.args = [ - params.quick_mass_acc ? "--quick-mass-acc" : '', // if mass-acc is given, this will be ignored - params.performance_mode ? "--min-corr 2 --corr-diff 1 --time-corr-only" : '' - ].join(' ').trim() - } - - // MS2RESCORE - withName: 'MSRESCORE_FEATURES' { - ext.args = [ - "--ms2_model ${params.ms2features_model}", - "--calibration_set_size ${params.ms2features_calibration}", - params.ms2features_generators.trim() ? "--feature_generators ${params.ms2features_generators}" : '' - ].join(' ').trim() - } - - withName: '.*:DDA_ID:PHOSPHO_SCORING:ID_SCORE_SWITCHER' { - ext.args = [ - "-new_score_orientation lower_better", - "-old_score \"q-value\"", - "-new_score_type \"Posterior Error Probability\"", - "-debug $params.idscoreswitcher_debug" - ].join(' ').trim() - } -} diff --git a/conf/modules/shared.config b/conf/modules/shared.config new file mode 100644 index 000000000..ebdd5dddf --- /dev/null +++ b/conf/modules/shared.config @@ -0,0 +1,53 @@ +/* +======================================================================================== + Shared module options — publishDir for outputs used across all workflows +======================================================================================== +*/ + +process { + + // publishDir for pmultiqc reports + withName: 'BIGBIO_QUANTMS:QUANTMS:SUMMARY_PIPELINE' { + publishDir = [ + path: { "${params.outdir}/pmultiqc" }, + mode: 'copy', + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + + // publishDir for SDRF files + withName: 'BIGBIO_QUANTMS:QUANTMS:INPUT_CHECK:SAMPLESHEET_CHECK' { + publishDir = [ + path: { "${params.outdir}/sdrf" }, + mode: 'copy', + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + + // publishDir for configurations files from SDRF parsing + withName: '.*:SDRF_PARSING' { + publishDir = [ + path: { "${params.outdir}/sdrf" }, + mode: 'copy', + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + + // Result tables from multiple pipelines including LFQ, TMT, DDA + withName: '.*:PROTEOMICSLFQ|PROTEIN_QUANTIFIER|MSSTATS_CONVERTER|ISOBARIC_WORKFLOW' { + publishDir = [ + path: { "${params.outdir}/quant_tables" }, + mode: 'copy', + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + + // publishDir for all features tables + withName: '.*:MZML_STATISTICS' { + publishDir = [ + path: { "${params.outdir}/spectra/mzml_statistics" }, + mode: 'copy', + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } +} diff --git a/conf/modules/tmt.config b/conf/modules/tmt.config new file mode 100644 index 000000000..7ce86541a --- /dev/null +++ b/conf/modules/tmt.config @@ -0,0 +1,12 @@ +/* +======================================================================================== + TMT module options — TMT-specific processes +======================================================================================== +*/ + +process { + // MSSTATSCONVERTER + withName: '.*:TMT:MSSTATS_CONVERTER' { + ext.args = "-debug $params.protein_quant_debug" + } +} diff --git a/conf/modules/verbose_modules.config b/conf/modules/verbose_modules.config index e9a5503e9..6cba0f5f9 100644 --- a/conf/modules/verbose_modules.config +++ b/conf/modules/verbose_modules.config @@ -124,38 +124,6 @@ process { ] } - withName: '.*:PROTEIN_INFERENCE_GENERIC|PROTEIN_INFERENCE_EPIFANY' { - publishDir = [ - path: { "${params.outdir}/peptide_postprocessing/protein_inference" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - - withName: '.*:FILE_MERGE' { - publishDir = [ - path: { "${params.outdir}/peptide_postprocessing/file_merge" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - - withName: '.*:ID_MAPPER' { - publishDir = [ - path: { "${params.outdir}/peptide_postprocessing/id_mapper" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - - withName: '.*:ID_SCORE_SWITCHER' { - publishDir = [ - path: { "${params.outdir}/peptide_postprocessing/id_score_switcher" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - // Set the default publish for PTM processing steps withName: '.*:ONSITE' { publishDir = [ @@ -165,48 +133,6 @@ process { ] } - // DIANN preprocessing steps, final results will be stored in quant_tables directory - withName: '.*:INDIVIDUAL_ANALYSIS' { - publishDir = [ - path: { "${params.outdir}/diann_preprocessing/individual_analysis" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - - withName: '.*:PRELIMINARY_ANALYSIS' { - publishDir = [ - path: { "${params.outdir}/diann_preprocessing/preliminary_analysis" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - - // Database generation steps and subworkflows - withName: '.*:GENERATE_DECOY_DATABASE' { - publishDir = [ - path: { "${params.outdir}/database_generation/generate_decoy_database" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - - withName: '.*:ASSEMBLE_EMPIRICAL_LIBRARY' { - publishDir = [ - path: { "${params.outdir}/database_generation/assemble_empirical_library" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - - withName: '.*:INSILICO_LIBRARY_GENERATION' { - publishDir = [ - path: { "${params.outdir}/database_generation/insilico_library_generation" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } - withName: '.*:MSGF_DB_INDEXING' { publishDir = [ path: { "${params.outdir}/database_generation/msgf_db_indexing" }, @@ -215,12 +141,4 @@ process { ] } - // Additional config files generated in DIANN configuration - withName: '.*:GENERATE_CFG' { - publishDir = [ - path: { "${params.outdir}/sdrf" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } - ] - } } diff --git a/conf/tests/test_dia.config b/conf/tests/test_dia.config deleted file mode 100644 index 155016aac..000000000 --- a/conf/tests/test_dia.config +++ /dev/null @@ -1,48 +0,0 @@ -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Nextflow config file for running minimal tests (DIA) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Defines input files and everything required to run a fast and simple test. - - Use as follows: - nextflow run bigbio/quantms -profile test_dia, [--outdir ] - ------------------------------------------------------------------------------------------------- -*/ - -process { - resourceLimits = [ - cpus: 4, - memory: '6.GB', - time: '48.h' - ] -} -params { - config_profile_name = 'Test profile for DIA' - config_profile_description = 'Minimal test dataset to check pipeline function for the data-independent acquisition pipeline branch.' - - outdir = './results_dia' - - // Input data - input = 'https://raw.githubusercontent.com/bigbio/quantms-test-datasets/quantms/testdata/dia_ci/PXD026600.sdrf.tsv' - database = 'https://raw.githubusercontent.com/bigbio/quantms-test-datasets/quantms/testdata/dia_ci/REF_EColi_K12_UPS1_combined.fasta' - min_pr_mz = 350 - max_pr_mz = 950 - min_fr_mz = 500 - max_fr_mz = 1500 - min_peptide_length = 15 - max_peptide_length = 30 - max_precursor_charge = 3 - allowed_missed_cleavages = 1 - diann_normalize = false - skip_post_msstats = false - publish_dir_mode = 'symlink' - max_mods = 2 -} - -process { - // thermorawfileparser - withName: 'BIGBIO_QUANTMS:QUANTMS:FILE_PREPARATION:THERMORAWFILEPARSER' { - publishDir = [path: { "${params.outdir}/${task.process.tokenize(':')[-1].toLowerCase()}" }, pattern: "*.log" ] - } -} diff --git a/conf/tests/test_full_dia.config b/conf/tests/test_full_dia.config deleted file mode 100644 index 61b531891..000000000 --- a/conf/tests/test_full_dia.config +++ /dev/null @@ -1,38 +0,0 @@ -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Nextflow config file for running real full dia tests (DIA) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Defines input files and everything required to run a real and full-size test. - - Use as follows: - nextflow run bigbio/quantms -profile test_full_dia, [--outdir ] - ------------------------------------------------------------------------------------------------- -*/ - -process { - resourceLimits = [ - cpus: 4, - memory: '6.GB', - time: '48.h' - ] -} - -params { - config_profile_name = 'Real full-size test profile for DIA' - config_profile_description = 'Real full-size test dataset to check pipeline function for the data-independent acquisition pipeline branch.' - - outdir = './results_dia_full' - - // Input data - input = 'https://raw.githubusercontent.com/nf-core/test-datasets/quantms/testdata-aws/dia_full/PXD004684.sdrf.tsv' - database = 'https://raw.githubusercontent.com/bigbio/quantms-test-datasets/quantms/testdata/dia_ci/REF_EColi_K12_UPS1_combined.fasta' - min_pr_mz = 450 - max_pr_mz = 1080 - min_fr_mz = 500 - max_fr_mz = 1500 - max_precursor_charge = 3 - allowed_missed_cleavages = 1 - diann_normalize = false - max_mods = 1 -} diff --git a/conf/tests/test_full_lfq.config b/conf/tests/test_full_lfq.config index c028754bd..3c5a80574 100644 --- a/conf/tests/test_full_lfq.config +++ b/conf/tests/test_full_lfq.config @@ -25,11 +25,10 @@ params { outdir = "./results_lfq_full" // Input data - input = 'https://raw.githubusercontent.com/nf-core/test-datasets/quantms/testdata-aws/lfq_full/PXD001819.sdrf.tsv' - database = 'https://raw.githubusercontent.com/nf-core/test-datasets/quantms/testdata-aws/lfq_full/yeast_2021_04_reviewed.fasta' + input = 'https://raw.githubusercontent.com/bigbio/quantms-test-datasets/quantms/testdata-aws/lfq_full/PXD001819.sdrf.tsv' + database = 'https://raw.githubusercontent.com/bigbio/quantms-test-datasets/quantms/testdata-aws/lfq_full/yeast_2021_04_reviewed.fasta' search_engines = "msgf,comet" add_decoys = true - add_triqler_output = true protein_level_fdr_cutoff = 0.01 psm_level_fdr_cutoff = 0.01 } diff --git a/conf/tests/test_full_tmt.config b/conf/tests/test_full_tmt.config index f834f1ac1..fbf933589 100644 --- a/conf/tests/test_full_tmt.config +++ b/conf/tests/test_full_tmt.config @@ -25,8 +25,8 @@ params { outdir = "./results_iso_full" // Input data for full size test - input = 'https://raw.githubusercontent.com/nf-core/test-datasets/quantms/testdata-aws/tmt_full/PXD005486.sdrf.tsv' - database = 'https://raw.githubusercontent.com/nf-core/test-datasets/quantms/testdata-aws/tmt_full/uniprot_E_coli_13spiked_reviewed_2021_04.fasta' + input = 'https://raw.githubusercontent.com/bigbio/quantms-test-datasets/quantms/testdata-aws/tmt_full/PXD005486.sdrf.tsv' + database = 'https://raw.githubusercontent.com/bigbio/quantms-test-datasets/quantms/testdata-aws/tmt_full/uniprot_E_coli_13spiked_reviewed_2021_04.fasta' search_engines = "comet,msgf" protein_level_fdr_cutoff = 0.01 psm_level_fdr_cutoff = 0.01 diff --git a/conf/tests/test_latest_dia.config b/conf/tests/test_latest_dia.config deleted file mode 100644 index eefa5ed88..000000000 --- a/conf/tests/test_latest_dia.config +++ /dev/null @@ -1,55 +0,0 @@ -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Nextflow config file for running minimal tests (DIA) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Defines input files and everything required to run a fast and simple test. - - Use as follows: - nextflow run bigbio/quantms -profile test_dia, [--outdir ] - ------------------------------------------------------------------------------------------------- -*/ - -params { - config_profile_name = 'Test profile for latest DIA' - config_profile_description = 'Minimal test dataset to check pipeline function for the data-independent acquisition pipeline branch for latest DIA-NN.' - - outdir = './results_latest_dia' - - // Input data - input = 'https://raw.githubusercontent.com/bigbio/quantms-test-datasets/quantms/testdata/dia_ci/PXD026600.sdrf.tsv' - database = 'https://raw.githubusercontent.com/bigbio/quantms-test-datasets/quantms/testdata/dia_ci/REF_EColi_K12_UPS1_combined.fasta' - min_pr_mz = 350 - max_pr_mz = 950 - min_fr_mz = 500 - max_fr_mz = 1500 - min_peptide_length = 15 - max_peptide_length = 30 - max_precursor_charge = 3 - allowed_missed_cleavages = 1 - diann_normalize = false - skip_post_msstats = false - publish_dir_mode = 'symlink' - max_mods = 2 -} - -process { - // thermorawfileparser - withName: 'BIGBIO_QUANTMS:QUANTMS:FILE_PREPARATION:THERMORAWFILEPARSER' { - publishDir = [path: { "${params.outdir}/${task.process.tokenize(':')[-1].toLowerCase()}" }, pattern: "*.log" ] - } - - withLabel: diann { - container = 'ghcr.io/bigbio/diann:2.1.0' // This docker container is private in for quantms - } - - resourceLimits = [ - cpus: 4, - memory: '12.GB', - time: '48.h' - ] - -} - -singularity.enabled = false // Force to use docker -docker.enabled = true diff --git a/conf/tests/test_lfq.config b/conf/tests/test_lfq.config index abad4b7a9..eb7d517c9 100644 --- a/conf/tests/test_lfq.config +++ b/conf/tests/test_lfq.config @@ -25,15 +25,12 @@ params { outdir = "./results_lfq" // 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" - add_triqler_output = true protein_level_fdr_cutoff = 1.0 psm_level_fdr_cutoff = 1.0 - acquisition_method = "dda" quantify_decoys = true mzml_features = true } diff --git a/conf/tests/test_lfq_sage.config b/conf/tests/test_lfq_sage.config index 955194103..cb96cc344 100644 --- a/conf/tests/test_lfq_sage.config +++ b/conf/tests/test_lfq_sage.config @@ -26,18 +26,13 @@ params { tracedir = "${params.outdir}/pipeline_info" // 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' database = 'https://raw.githubusercontent.com/bigbio/quantms-test-datasets/quantms/testdata/lfq_ci/BSA/18Protein_SoCe_Tr_detergents_trace.fasta' add_decoys = true search_engines = "sage,comet" - precursor_mass_tolerance = 20 - fragment_mass_tolerance = 0.1 decoy_string= "rev" - add_triqler_output = true protein_level_fdr_cutoff = 1.0 psm_level_fdr_cutoff = 1.0 run_fdr_cutoff = 0.5 - acquisition_method = "dda" quantify_decoys = true } diff --git a/conf/tests/test_localize.config b/conf/tests/test_localize.config index 3c1b78b9f..352996444 100644 --- a/conf/tests/test_localize.config +++ b/conf/tests/test_localize.config @@ -28,10 +28,11 @@ params { input = 'https://raw.githubusercontent.com/bigbio/quantms-test-datasets/quantms/testdata/lfq_ci_phospho/test_phospho.sdrf' database = 'https://raw.githubusercontent.com/bigbio/quantms-test-datasets/quantms/testdata/lfq_ci_phospho/pools_crap_targetdecoy.fasta' enable_mod_localization = true + onsite_target_modifications = "Phospho(S),Phospho(T),Phospho(Y),PhosphoDecoy(A)" search_engines = 'comet,msgf' protein_level_fdr_cutoff = 0.20 psm_level_fdr_cutoff = 0.50 - skip_post_msstats = true + onsite_modeling_score_threshold = 0.3 quantify_decoys = true fdr_level = "psm_level_fdrs" } diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 000000000..687c1e0a3 --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,185 @@ +--- +title: Contributing +markdownPlugin: checklist +--- + +# `bigbio/quantms`: Contributing guidelines + +Hi there! +Thanks for taking an interest in improving bigbio/quantms. + +This page describes the recommended nf-core way to contribute to both bigbio/quantms and nf-core pipelines in general, including: + +- [General contribution guidelines](#general-contribution-guidelines): common procedures or guides across all nf-core pipelines. +- [Pipeline-specific contribution guidelines](#pipeline-specific-contribution-guidelines): procedures or guides specific to the development conventions of bigbio/quantms. + +> [!NOTE] +> If you need help using or modifying bigbio/quantms, ask on the nf-core Slack [#quantms](https://nfcore.slack.com/channels/quantms) channel ([join our Slack here](https://nf-co.re/join/slack)). + +## General contribution guidelines + +### Contribution quick start + +To contribute code to any nf-core pipeline: + +- [ ] Ensure you have Nextflow, nf-core tools, and nf-test installed. See the [nf-core/tools repository](https://github.com/nf-core/tools) for instructions. +- [ ] Check whether a GitHub [issue](https://github.com/bigbio/quantms/issues) about your idea already exists. If an issue does not exist, create one so that others are aware you are working on it. +- [ ] [Fork](https://help.github.com/en/github/getting-started-with-github/fork-a-repo) the [bigbio/quantms repository](https://github.com/bigbio/quantms) to your GitHub account. +- [ ] Create a branch on your forked repository and make your changes following [pipeline conventions](#pipeline-contribution-conventions) (if applicable). +- [ ] To fix major bugs, name your branch `patch` and follow the [patch release](#patch-release) process. +- [ ] Update relevant documentation within the `docs/` folder, use nf-core/tools to update `nextflow_schema.json`, and update `CITATIONS.md`. +- [ ] Run and/or update tests. See [Testing](#testing) for more information. +- [ ] [Lint](#lint-tests) your code with nf-core/tools. +- [ ] Submit a pull request (PR) against the `dev` branch and request a review. + +If you are not used to this workflow with Git, see the [GitHub documentation](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests) or [Git resources](https://try.github.io/) for more information. + +## Use of AI and LLMs + +The nf-core stance on the use of AI and LLMs is that humans are still ultimately responsible for their submitted code, regardless of the tools they use. + +If you’re using AI tools, try to stick by these guidelines: + +- Keep PRs as small and focussed as possible +- Avoid any unnecessary changes, such as moving or refactoring code (unless that is the explicit intention of the PR) +- Review all generated code yourself before opening a PR, and ensure that you understand it +- Engage with the community review process and expect to make revisions + +For more detail, see the the [blog post](https://nf-co.re/blog/2026/statement-on-ai) for a statement from the nf-core/core team. + +### Getting help + +For further information and help, see the [bigbio/quantms documentation](https://nf-co.re/quantms/usage) or ask on the nf-core [#quantms](https://nfcore.slack.com/channels/quantms) Slack channel ([join our Slack here](https://nf-co.re/join/slack)). + +### GitHub Codespaces + +You can contribute to bigbio/quantms without installing a local development environment on your machine by using [GitHub Codespaces](https://github.com/codespaces). + +[GitHub Codespaces](https://github.com/codespaces) is an online developer environment that runs in your browser, complete with VS Code and a terminal. +Most nf-core repositories include a devcontainer configuration, which creates a GitHub Codespaces environment specifically for Nextflow development. +The environment includes pre-installed nf-core tools, Nextflow, and a few other helpful utilities via a Docker container. + +To get started, open the repository in [Codespaces](https://github.com/bigbio/quantms/codespaces). + +### Testing + +Once you have made your changes, run the pipeline with nf-test to test them locally. +For additional information, use the `--verbose` flag to view the Nextflow console log output. + +```bash +nf-test test --tag test --profile +docker --verbose +``` + +If you have added new functionality, ensure you update the test assertions in the `.nf.test` files in the `tests/` directory. +Update the snapshots with the following command: + +```bash +nf-test test --tag test --profile +docker --verbose --update-snapshots +``` + +When you create a pull request with changes, GitHub Actions will run automatic tests. +Pull requests are typically reviewed when these tests are passing. + +Two types of tests are typically run: + +#### Lint tests + +nf-core has a [set of guidelines](https://nf-co.re/docs/specifications/overview) which all pipelines must follow. +To enforce these, run linting with nf-core/tools: + +```bash +nf-core pipelines lint +``` + +If you encounter failures or warnings, follow the linked documentation printed to screen. +For more information about linting tests, see [nf-core/tools API documentation](https://nf-co.re/docs/nf-core-tools/api_reference/latest/pipeline_lint_tests/actions_awsfulltest). + +#### Pipeline tests + +Each nf-core pipeline should be set up with a minimal set of test data. +GitHub Actions runs the pipeline on this data to ensure it runs through and exits successfully. +If there are any failures then the automated tests fail. +These tests are run with the latest available version of Nextflow and the minimum required version specified in the pipeline code. + +### Patch release + +> [!WARNING] +> Only in the unlikely event of a release that contains a critical bug. + +- [ ] Create a new branch `patch` on your fork based on `upstream/main` or `upstream/master`. +- [ ] Fix the bug and use nf-core/tools to bump the version to the next semantic version, for example, `1.2.3` → `1.2.4`. +- [ ] Open a Pull Request from `patch` directly to `main`/`master` with the changes. + +### Pipeline contribution conventions + +nf-core semi-standardises how you write code and other contributions to make the bigbio/quantms code and processing logic more understandable for new contributors and to ensure quality. + +#### Add a new pipeline step + +To contribute a new step to the pipeline, follow the general nf-core coding procedure. +Please also refer to the [pipeline-specific contribution guidelines](#pipeline-specific-contribution-guidelines): + +- [ ] Define the corresponding [input channel](#channel-naming-schemes) into your new process from the expected previous process channel. +- [ ] Install a module with nf-core/tools, or write a local module (see [default processes resource requirements](#default-processes-resource-requirements)), and add it to the target `.nf`. +- [ ] Define the output channel if needed. Mix the version output channel into `ch_versions` and relevant files into `ch_multiqc`. +- [ ] Add new or updated parameters to `nextflow.config` with a [default value](#default-parameter-values). +- [ ] Add new or updated parameters and relevant help text to `nextflow_schema.json` with [nf-core/tools](#default-parameter-values). +- [ ] Add validation for relevant parameters to the pipeline utilisation section of `utils_nfcore_\_pipeline/main.nf` subworkflow. +- [ ] Perform local tests to validate that the new code works as expected. + - [ ] If applicable, add a new test in the `tests` directory. +- [ ] Update `usage.md`, `output.md`, and `citation.md` as appropriate. +- [ ] [Lint](lint) the code with nf-core/tools. +- [ ] Update any diagrams or pipeline images as necessary. +- [ ] Update MultiQC config `assets/multiqc_config.yml` so relevant suffixes, file name cleanup, and module plots are in the appropriate order. +- [ ] If applicable, create a [MultiQC](https://seqera.io/multiqc/) module. +- [ ] Add a description of the output files and, if relevant, images from the MultiQC report to `docs/output.md`. + +To update the minimum required Nextflow version, see the [Nextflow version bumping](#nextflow-version-bumping) section below. For more information about pipeline contributions, see [pipeline-specific contribution guidelines](#pipeline-specific-contribution-guidelines). + +#### Channel naming schemes + +Use the following naming schemes for channels to make the channel flow easier to understand: + +- Initial process channel: `ch_output_from_` +- Intermediate and terminal channels: `ch__for_` + +#### Default parameter values + +Parameters should be initialised and defined with default values within the `params` scope in `nextflow.config`. +They should also be documented in the pipeline JSON schema. + +To update `nextflow_schema.json`, run: + +```bash +nf-core pipelines schema build +``` + +The schema builder interface that loads in your browser should automatically update the defaults in the parameter documentation. + +#### Default processes resource requirements + +If you write a local module, specify a default set of resource requirements for the process. + +Sensible defaults for process resource requirements (CPUs, memory, time) should be defined in `conf/base.config`. +Specify these with generic `withLabel:` selectors, so they can be shared across multiple processes and steps of the pipeline. + +nf-core provides a set of standard labels that you should follow where possible, as seen in the [nf-core pipeline template](https://github.com/nf-core/tools/blob/main/nf_core/pipeline-template/conf/base.config). +These labels define resource defaults for single-core processes, modules that require a GPU, and different levels of multi-core configurations with increasing memory requirements. + +Values assigned within these labels can be dynamically passed to a tool using the the `${task.cpus}` and `${task.memory}` Nextflow variables in the `script:` block of a module (see an example in the [modules repository](https://github.com/nf-core/modules/blob/bd1b6a40f55933d94b8c9ca94ec8c1ea0eaf4b82/modules/nf-core/samtools/bam2fq/main.nf#L30)). + +#### Nextflow version bumping + +If you use a new feature from core Nextflow, bump the minimum required Nextflow version in the pipeline with: + +```bash +nf-core pipelines bump-version --nextflow . +``` + +#### Images and figures guidelines + +If you update images or graphics, follow the nf-core [style guidelines](https://nf-co.re/docs/community/brand/workflow-schematics). + +## Pipeline specific contribution guidelines + + diff --git a/docs/images/full-DDA.svg b/docs/images/full-DDA.svg deleted file mode 100644 index 36edfc697..000000000 --- a/docs/images/full-DDA.svg +++ /dev/null @@ -1,228 +0,0 @@ - - - - - - - - - - - - - - ID Comet - - - - - - mix - - - - - if multi-engine - - - - - if single-engine - - - - merge - - - - - - Percolator - - - - - - ID MSGF - - - - - - - ConsensusID - - - - - - onsite - - - - - - combined FDR - - - - - - - - Quantification +... - - - - - - Switch to - q-value/FDR - - - - - - IDFilter - - - - MSstats - - - - PMultiQC - - - - - - Raw file - conversion/... - - - - - - - - - - - - if localize - - - - if necessary - - - - Decoy generation - - - - if requested - - - - Database - - - - Input - - - - + - - - Design - - - - Spectra - - - - or - - - - ID Sage - - quantms-rescoring - - - - - -fasta - -mzML - - -raw - - - -sdrf - - - - - - diff --git a/docs/images/id-dda-pipeline.png b/docs/images/id-dda-pipeline.png deleted file mode 100644 index fd87862a7..000000000 Binary files a/docs/images/id-dda-pipeline.png and /dev/null differ diff --git a/docs/images/id_pipeline.png b/docs/images/id_pipeline.png deleted file mode 100644 index fd87862a7..000000000 Binary files a/docs/images/id_pipeline.png and /dev/null differ diff --git a/docs/images/id_pipeline.svg b/docs/images/id_pipeline.svg deleted file mode 100644 index 36edfc697..000000000 --- a/docs/images/id_pipeline.svg +++ /dev/null @@ -1,228 +0,0 @@ - - - - - - - - - - - - - - ID Comet - - - - - - mix - - - - - if multi-engine - - - - - if single-engine - - - - merge - - - - - - Percolator - - - - - - ID MSGF - - - - - - - ConsensusID - - - - - - onsite - - - - - - combined FDR - - - - - - - - Quantification +... - - - - - - Switch to - q-value/FDR - - - - - - IDFilter - - - - MSstats - - - - PMultiQC - - - - - - Raw file - conversion/... - - - - - - - - - - - - if localize - - - - if necessary - - - - Decoy generation - - - - if requested - - - - Database - - - - Input - - - - + - - - Design - - - - Spectra - - - - or - - - - ID Sage - - quantms-rescoring - - - - - -fasta - -mzML - - -raw - - - -sdrf - - - - - - diff --git a/docs/images/quantms.png b/docs/images/quantms.png index 58beffae7..41155c76d 100644 Binary files a/docs/images/quantms.png and b/docs/images/quantms.png differ diff --git a/docs/images/quantms.svg b/docs/images/quantms.svg index 945f9b00f..483e4d750 100644 --- a/docs/images/quantms.svg +++ b/docs/images/quantms.svg @@ -5,7 +5,7 @@ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 822 1170.6" style="enable-background:new 0 0 822 1170.6;" xml:space="preserve"> - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - fasta + + + + + + + + + + + + + + + + + + + + + + - - - - - xml + + + + + + + + + + + + + + + + + + + + - - - - - fasta + + + + + + + + + + + + + + + + + + + + - - - - - fasta + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + fasta + + + + + + + qpx + + + + + + + fasta + + + + - + - + - + + + - + - + - - - - Annotation - - + + + + Annotation + + + + - + - + - - Reports - - - - - - - - - - - - - - - - - - - + + Reports + + + + + + + + + + + + + + + + + + + + + - + - + - - - - - - - Peptide Protein Identification - Protein Quantification - - - + +Peptide Protein Identification +Protein Quantification + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + - - TMT - quantms - DIA-LFQ - LFQ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - raw - - - - - - - - - - - - - - - - - + +TMT +quantms +LFQ + + + + + + + + + + + + + - - - - - + - raw + + + + - + raw + + - - + + - - - - + + - - - - - - - + + + + + + + + - - - - - - raw + + + + + - MS-GF+, SAGE, Comet - Percolator, MS2Rescore, ConsesusID - DIA-NN - IsobaricAnalyzer - ProteinInference - proteomicsLFQ - inference,mbr,quantification - DIA-NN + raw +MS-GF+, SAGE, Comet +Percolator, quantms-rescoring +proteomicsLFQ | isobaric workflow +inference,mbr,quantification diff --git a/docs/images/quantms_lfq.svg b/docs/images/quantms_lfq.svg deleted file mode 100644 index 315e50ef3..000000000 --- a/docs/images/quantms_lfq.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -
ID Comet
ID Comet
mix
mix
if multi-engine
if multi-engine
if single-engine
if single-engine
merge
merge
Percolator
Percolator
ID MSGF
ID MSGF
FDR
FDR
Distribution-based PEP
Distribution-based P...
ConsensusID
ConsensusID
Luciphor
Luciphor
combined FDR
combined FDR
Quantification +
Inference and experiment-wide FDR filter
Quantification +...
Switch to q-value/FDR
Switch to q-value/FDR
IDFilter
IDFilter
MSstats
MSstats
PTXQC
PTXQC
Raw file conversion/Indexing
Raw file conversion/...
if !multi-engine
if !multi-engine
if localize
if localize
if necessary
if necessary
Decoy generation
Decoy generation
if requested
if requested
Database
Database
Input
Input
+
+
Design
Spectra
Spectra
or
or
or
or
Viewer does not support full SVG 1.1
diff --git a/docs/images/quantms_metro.drawio.svg b/docs/images/quantms_metro.drawio.svg index 78266fb82..4283dddce 100644 --- a/docs/images/quantms_metro.drawio.svg +++ b/docs/images/quantms_metro.drawio.svg @@ -1,1071 +1,297 @@ - + - + + .st0{fill:none;stroke:#DA291C;stroke-width:11;stroke-miterlimit:10;} + .st1{fill:none;stroke:#56A8CB;stroke-width:10;stroke-miterlimit:10;} + .st2{fill:none;} + .st3{fill:none;stroke:#CDA2BE;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st4{fill:none;stroke:#9673A6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:3,3;} + .st5{font-family:'ArialMT';} + .st6{font-size:12.8756px;} + .st7{fill:none;stroke:#FFFFFF;stroke-width:13;stroke-miterlimit:10;} + .st8{fill:#FFFFFF;stroke:#000000;} + .st9{fill:#FFBE7A;stroke:#000000;} + .st10{fill:#FFBE7A;stroke:#000000;stroke-width:1.5;stroke-dasharray:4.5,4.5;} + .st11{fill:#FFFFFF;} + .st12{fill:none;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:3,3;} + .st13{font-family:'Arial-BoldMT';} + .st14{fill:none;stroke:#DA291C;stroke-width:11;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st15{fill:none;stroke:#56A8CB;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st16{font-size:11.8539px;} + .st17{font-family:'ArialNarrow-Bold';} + .st18{letter-spacing:1.1;} + .st19{fill:#FFFFFF;stroke:#000000;stroke-dasharray:3,3;} + .st20{font-size:12.1693px;} + .st21{letter-spacing:27.4;} + .st22{fill:none;stroke:#53A567;stroke-width:10;stroke-miterlimit:10;} + .st23{clip-path:url(#SVGID_2_);} + .st24{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;stroke:#2F528F;stroke-width:1.3333;stroke-miterlimit:8;} + .st25{fill-rule:evenodd;clip-rule:evenodd;stroke:#2F528F;stroke-width:1.3333;stroke-miterlimit:8;} + .st26{font-size:8.5714px;} + .st27{clip-path:url(#SVGID_4_);} + .st28{clip-path:url(#SVGID_6_);} + .st29{clip-path:url(#SVGID_8_);} + .st30{font-size:6.1224px;} + .st31{clip-path:url(#SVGID_10_);} + .st32{font-size:6.4378px;} + .st33{clip-path:url(#SVGID_12_);} + .st34{font-size:6.5691px;} + .st35{letter-spacing:33.3;} + .st36{font-size:10.0751px;} + + + - - - - + + + + + c1.7-50.1,0.7-97.9,0-169.5"/> - Search engines - (at least one) - - - - - - - - - - - - - - - Rescoring - (exactly one) - - - - - - - - - - - - - - - + Search engines + (at least one) + + + + + + + + + + + + + + + + + + + - ThermoRaw - FileParser - - - - - - - + ThermoRaw + FileParser +
+ + + + + + - Comet - - - - - - - - ConsensusID - - - - - - Distribution - fitting - - - - - - - - FDR - control - - - - Isobaric - Analyzer - - - - - - - - - + Comet +
+ + + + + + + - Mod. - localization - - - - quantms-rescoring + Percolator + FDR - - - - - - - - + Mod. + localization +
+ + + + + - Legend + Legend - - - + + - DDA-LFQ + DDA-LFQ - DDA-ISO + DDA-ISO - DIA-LFQ - Parallel step + Parallel step - - - - - IDMapper - - + + + - Protein - inference - - - - + IsobaricWorkflow +
+ + + - bigbio/quantms v1.3 - - Example analysis pathways + bigbio/quantms v1.8 + + Example analysis pathways - mzML - indexing - - - - - DIA-NN - insilico lib. predict - - - - preanalysis + mzML + indexing - - DIA-NN - empirical lib. gen. - - + - Add - decoys - - - - - - + Add + decoys +
+ + + + - Proteomics - LFQ + Proteomics + LFQ - + - mzTab + mzTab - - - Protein - Quantifier - - - - Triqler + qpx - - + - MSstats - - - - DIA-NN - summary - - - - - DIA-NN - individual final analysis + MSstats - - MSGF+ - - - - - - - - + MSGF+ +
+ + + - tdf2mzml + tdf2mzml - + - - Identification subworkflow - + + Identification subworkflow +
+ + quantms-rescoring + Percolator + + + + + +
- + - - - - - - - - -Job n -In Parallel - -Job 1 -...... + + + + - - - - - - - - - - mzML - + + + + + + + + + + + + mzML + + + @@ -1079,22 +305,22 @@ - - - - - - - - - - raw - + + + + + + + + + + + + raw + + + @@ -1108,22 +334,22 @@ - - - - - - - - - - fasta - + + + + + + + + + + + + fasta + + + @@ -1137,22 +363,22 @@ - - - - - - - - - - tsv - + + + + + + + + + + + + tsv + + + @@ -1166,22 +392,22 @@ - - - - - - - - - - mzTab - + + + + + + + + + + + + mzTab + + + @@ -1195,22 +421,22 @@ - - - - - - - - - - tsv - + + + + + + + + + + + + tsv + + + @@ -1218,412 +444,212 @@ - - - -Job 1 -...... -Job n - In Parallel - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - Sage + + Sage - - - - - - - - - - - -speclib -skip + + - + - + V-1565.6L-1708.6-1565.6z M-1677-1512.1h-31.6v-11.1h31.6V-1512.1L-1677-1512.1z"/> - + /> - + V-1553.9z M-1673-1500.4h-31.6v-11.1h31.6V-1500.4L-1673-1500.4z"/> - + - - + V-1542.2L-1700.6-1542.2z M-1669-1488.7h-31.6v-11.1h31.6V-1488.7L-1669-1488.7z"/> + - raw + raw - + - + V-1718.2L-1708.6-1718.2z M-1677-1664.7h-31.6v-11.1h31.6V-1664.7L-1677-1664.7z"/> - + L-1677-1664.7z"/> - + V-1706.5z M-1673-1653h-31.6v-11.1h31.6V-1653L-1673-1653z"/> - + - - + + /> - mzML + mzML - + - + V-1346.6L-1705.2-1346.6z M-1673.6-1293.1h-31.6v-11.1h31.6V-1293.1L-1673.6-1293.1z"/> - + V-1293.1L-1673.6-1293.1z"/> - + z M-1669.6-1281.5h-31.6v-11.1h31.6V-1281.5L-1669.6-1281.5z"/> - + - - + + L-1665.6-1269.7z"/> - fasta + fasta - + - + V-1462.3L-1708.6-1462.3z M-1677-1408.8h-31.6v-11.1h31.6V-1408.8L-1677-1408.8z"/> - + L-1677-1408.8z"/> - + z M-1673-1397.2h-31.6v-11.1h31.6V-1397.2L-1673-1397.2z"/> - + "/> - - + V-1439L-1700.6-1439z M-1669-1385.5h-31.6v-11.1h31.6V-1385.5L-1669-1385.5z"/> + - .d + .d - - + + diff --git a/docs/images/quantms_metro.png b/docs/images/quantms_metro.png index 36ac2b325..5047a764b 100644 Binary files a/docs/images/quantms_metro.png and b/docs/images/quantms_metro.png differ diff --git a/docs/output.md b/docs/output.md index d1e31dee1..108ba18d9 100644 --- a/docs/output.md +++ b/docs/output.md @@ -27,13 +27,6 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d 15. (**DDA-ISO**) Protein Quantification 16. Generation of QC reports using pMultiQC, a library for QC proteomics data analysis. -For DIA-LFQ experiments, the workflow is different: - -1. RAW data is converted to mzML using the ThermoRawFileParser -2. DIA-NN is used for identification and quantification of the peptides and proteins -3. Generation of output files -4. Generation of QC reports using pMultiQC, a library for QC proteomics data analysis. - As an example, a rough visualization of the DDA identification subworkflow can be seen here: ![quantms LFQ workflow](./images/id-dda-pipeline.png) @@ -47,7 +40,7 @@ Output will be saved to the folder defined by the parameter `--outdir`. Each ste ### Default Output Structure -By default, quantms organizes output files in a structured way, with specific directories for different types of outputs. The structure varies slightly depending on the workflow type (DIA, ISO, LFQ, etc.), but follows a consistent organization pattern. +By default, quantms organizes output files in a structured way, with specific directories for different types of outputs. The structure varies slightly depending on the workflow type (ISO, LFQ, etc.), but follows a consistent organization pattern. #### Common directories across all workflows: @@ -60,24 +53,6 @@ By default, quantms organizes output files in a structured way, with specific di - `svg/`: SVG format plots - `pdf/`: PDF format plots -#### DIA workflow output structure: - -``` -results_dia/ -├── pipeline_info/ # Nextflow pipeline information -├── sdrf/ # SDRF files and configs -├── spectra/ # Spectra-related data (only present if --mzml_features is enabled) - ├──thermorawfileparser/ # Converted raw files -├── quant_tables/ # Quantification tables and results -├── msstats/ # MSstats processed results -└── pmultiqc/ # pMultiQC reports - ├── multiqc_plots/ - │ ├── png/ - │ ├── svg/ - │ └── pdf/ - └── multiqc_data/ -``` - #### ISO quantification workflow output structure: ``` @@ -85,7 +60,6 @@ results_iso/ ├── pipeline_info/ # Nextflow pipeline information ├── sdrf/ # SDRF files and configs ├── quant_tables/ # Quantification tables and results -├── msstats/ # MSstats processed results └── pmultiqc/ # pMultiQC reports ├── multiqc_data/ └── multiqc_plots/ @@ -103,7 +77,6 @@ results_lfq/ ├── spectra/ # Spectra-related data (only present if --mzml_features is enabled) │ └── mzml_statistics/ # Statistics about mzML files ├── quant_tables/ # Quantification tables and results -├── msstats/ # MSstats processed results └── pmultiqc/ # pMultiQC reports ├── multiqc_data/ └── multiqc_plots/ @@ -166,7 +139,6 @@ results/ │ ├── fdr_consensusid/ # FDR calculation results │ └── id_filter/ # Filtered identification results ├── quant_tables/ # Quantification tables and results -├── msstats/ # MSstats processed results └── pmultiqc/ # pMultiQC reports ├── multiqc_plots/ │ ├── svg/ @@ -175,38 +147,15 @@ results/ └── multiqc_data/ ``` -For DIA workflows, the verbose output structure includes additional directories: - -``` -results/ -├── pipeline_info/ # Nextflow pipeline information -├── sdrf/ # SDRF files and configs -├── spectra/ # Spectra-related data (only present if --mzml_features is enabled) -│ ├── thermorawfileparser/ # Converted raw files -│ └── mzml_statistics/ # Statistics about mzML files -├── database_generation/ # Database generation for DIA -│ ├── insilico_library_generation/ # In silico library generation -│ └── assemble_empirical_library/ # Empirical library assembly -├── diann_preprocessing/ # DIA-NN preprocessing -│ ├── preliminary_analysis/ # Preliminary analysis results -│ └── individual_analysis/ # Individual analysis results -├── quant_tables/ # Quantification tables and results -├── msstats/ # MSstats processed results -└── pmultiqc/ # pMultiQC reports - ├── multiqc_plots/ - │ ├── png/ - │ ├── pdf/ - │ └── svg/ - └── multiqc_data/ -``` - ### Key Output Files +> [!NOTE] +> DIA (Data Independent Acquisition) workflow outputs have been moved to the dedicated [quantmsdiann](https://github.com/bigbio/quantmsdiann) pipeline. Please refer to that pipeline for DIA-specific output files and documentation. + Depending on the workflow type, the main output files will be found in the following directories: -- `quant_tables/`: Contains all quantification results including mzTab files, MSstats input files, and other quantification tables +- `quant_tables/`: Contains all quantification results including mzTab files, MSstats-compatible input files, and other quantification tables - `psm_tables/`: Contains PSM-level results from the identification pipeline in parquet format -- `msstats/`: Contains MSstats processed results and reports - `pmultiqc/`: Contains quality control reports and visualizations The specific files include: @@ -214,7 +163,6 @@ The specific files include: - DDA-LFQ quantification results: - `quant_tables/out.consensusXML` - [ConsensusXML](#consensusxml) format with quantification data - `quant_tables/msstats_in.csv` - [MSstats-ready](#msstats-ready-quantity-tables) quantity tables - - `quant_tables/out_triqler.tsv` - [Triqler](#triqler) input format - `quant_tables/out.mzTab` - [mzTab](#mztab) format with identifications and quantities - DDA-ISO quantification results: @@ -223,17 +171,6 @@ The specific files include: - `quant_tables/protein_out.csv` - [Tab-based](#tab-based-openms-formats) protein quantities - `quant_tables/out_msstats_in.csv` - [MSstats-ready](#msstats-ready-quantity-tables) quantity tables -- DIA-LFQ quantification results: - - `quant_tables/diann_report.tsv` - DIA-NN main report with peptide and protein quantification - - `quant_tables/diann_report.pr_matrix.tsv` - Protein quantification matrix from DIA-NN - - `quant_tables/diann_report.pg_matrix.tsv` - Protein group quantification matrix from DIA-NN - - `quant_tables/diann_report.peptide_matrix.tsv` - Peptide quantification matrix from DIA-NN - - `quant_tables/diann_report.lib` - DIA-NN spectral library - - `quant_tables/out_msstats_in.csv` - [MSstats-ready](#msstats-ready-quantity-tables) quantity tables - -- MSstats-processed results: - - `msstats/out_msstats.mzTab` - [MSstats-processed](#msstats-processed-mztab) mzTab - ## Output description ### Nextflow pipeline info @@ -303,18 +240,14 @@ In addition to the consensusXML and idXML formats, OpenMS generates other format ##### MSstats-ready quantity tables -MSstats output is generated for all three pipelines DDA-LFQ, DDA-ISO and DIA-LFQ. A simple tsv file ready to be read by the -OpenMStoMSstats function of the MSstats R package. It should hold the same quantities as the consensusXML but rearranged in a "long" table format with additional -information about the experimental design used by MSstats. - -##### Triqler - -Output to be used as input in Triqler has similar information in a tsv format as the output for MSstats. Additionally, it contains quantities for -decoy identifications and search engine scores. +MSstats-compatible input files (`*_msstats_in.csv`) are produced for both DDA-LFQ and DDA-ISO pipelines. These are CSV files ready to be read by the +OpenMStoMSstats function of the MSstats R package. They hold the same quantities as the consensusXML but rearranged in a "long" table format with additional +information about the experimental design used by MSstats, and the filename prefix depends on the experimental design or report basename. Users can take these files and run +MSstats independently outside the pipeline. #### mzTab -The mzTab is exported for all three workflows DDA-LFQ, DDA-ISO and DIA-LFQ. It is a complete [mzTab](https://github.com/HUPO-PSI/mzTab) file +The mzTab is exported for both workflows DDA-LFQ and DDA-ISO. It is a complete [mzTab](https://github.com/HUPO-PSI/mzTab) file ready for submission to [PRIDE](https://www.ebi.ac.uk/pride/). It contains both identifications (only those responsible for a quantification), quantities and some metadata about both the experiment and the quantification. @@ -363,10 +296,9 @@ PSM section: Note that columns with scores heavily depend on the chosen search engines and rescoring tools and are better looked up in the documentation of the underlying tool. -#### MSstats-processed mzTab +#### MSstats post-processing (external) -If MSstats was enabled, the pipeline additionally exports an mzTab file where the quantities are replaced with the normalized and imputed ones from -MSstats. +The pipeline no longer runs MSstats post-processing. Instead, quantms produces MSstats-compatible input files (`quant_tables/*_msstats_in.csv`) that users can provide directly to MSstats outside the pipeline for normalization, imputation, and statistical analysis. ### MultiQC and pMultiQC diff --git a/docs/usage.md b/docs/usage.md index 2afa6e8be..bc0f7417e 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -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 @@ -89,20 +86,24 @@ Starting with version 1.7.0, luciphor-specific parameters have been replaced wit #### Onsite Parameters -| Parameter | Default | Description | -| -------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------- | -| `onsite_algorithm` | `'lucxor'` | PTM localization algorithm: `'ascore'`, `'phosphors'`, or `'lucxor'` | -| `onsite_fragment_method` | `'CID'` | Fragmentation method: `'CID'` or `'HCD'` | -| `onsite_fragment_tolerance` | `0.5` | Fragment mass tolerance | -| `onsite_fragment_error_units` | `'Da'` | Fragment error units: `'Da'` or `'ppm'` | -| `onsite_add_decoys` | `false` | Add decoy modifications for validation | -| `onsite_neutral_losses` | `null` | List of neutral losses to consider for modification localization (replaces `luciphor_neutral_losses`) | -| `onsite_decoy_mass` | `null` | Mass to add to an amino acid to make it a decoy (replaces `luciphor_decoy_mass`) | -| `onsite_decoy_neutral_losses` | `null` | List of neutral losses for decoy sequences (replaces `luciphor_decoy_neutral_losses`) | -| `onsite_threads` | `1` | Number of threads for onsite processing | -| `onsite_min_psms` | `5` | Minimum number of high-scoring PSMs for lucxor model training | -| `onsite_disable_split_by_charge` | `false` | Disable splitting PSMs by charge state for lucxor | -| `onsite_compute_all_scores` | `false` | Compute all scores for all candidate sites | +| Parameter | Default | Description | +| --------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------- | +| `onsite_algorithm` | `'lucxor'` | PTM localization algorithm: `'ascore'`, `'phosphors'`, or `'lucxor'` | +| `onsite_fragment_method` | `'CID'` | Fragmentation method: `'CID'` or `'HCD'` | +| `onsite_fragment_tolerance` | `0.5` | Fragment mass tolerance | +| `onsite_fragment_error_units` | `'Da'` | Fragment error units: `'Da'` or `'ppm'` | +| `onsite_add_decoys` | `false` | Add decoy modifications for validation | +| `onsite_neutral_losses` | `null` | List of neutral losses to consider for modification localization (replaces `luciphor_neutral_losses`) | +| `onsite_decoy_mass` | `null` | Mass to add to an amino acid to make it a decoy (replaces `luciphor_decoy_mass`) | +| `onsite_decoy_neutral_losses` | `null` | List of neutral losses for decoy sequences (replaces `luciphor_decoy_neutral_losses`) | +| `onsite_threads` | `1` | Number of threads for onsite processing | +| `onsite_rt_tolerance` | `0.01` | RT tolerance for PTM localization | +| `onsite_modeling_score_threshold` | `0.95` | Modeling score threshold for LucXor model training | +| `onsite_scoring_threshold` | `0.0` | Scoring threshold for PTM localization | +| `onsite_target_modifications` | `null` | Comma-separated list of target modifications to search for (defaults to `mod_localization` value) | +| `onsite_min_num_psms_model` | `5` | Minimum number of high-scoring PSMs for lucxor model training | +| `onsite_disable_split_by_charge` | `false` | Disable splitting PSMs by charge state for lucxor | +| `onsite_compute_all_scores` | `false` | Compute all scores for all candidate sites | **Note:** The old `luciphor_*` parameters are no longer supported. Update your configuration files to use the `onsite_*` parameters above. The default algorithm is `'lucxor'`, which provides the same functionality as the previous luciphor module. diff --git a/main.nf b/main.nf index 4f4a03272..6ee45415b 100644 --- a/main.nf +++ b/main.nf @@ -68,7 +68,6 @@ workflow { params.plaintext_email, params.outdir, params.monochrome_logs, - params.hook_url, BIGBIO_QUANTMS.out.multiqc_report ) } diff --git a/modules.json b/modules.json index ba6ed93ea..eb7368f78 100644 --- a/modules.json +++ b/modules.json @@ -7,13 +7,14 @@ "bigbio": { "onsite": { "branch": "main", - "git_sha": "ffe3c99ee867c4d7d6400f95d0b5658eccf16212", + "git_sha": "1c93e068aeca6704d042b92c26249cdd801da278", "installed_by": ["modules"] }, "thermorawfileparser": { "branch": "main", - "git_sha": "a1a4a11ff508b2b5c23c9fb21c51c3327b748d4d", - "installed_by": ["modules"] + "git_sha": "53f2d78652a7040e3d44610286471642b1e1b55b", + "installed_by": ["modules"], + "patch": "modules/bigbio/thermorawfileparser/thermorawfileparser.diff" } } } @@ -21,14 +22,9 @@ "https://github.com/nf-core/modules.git": { "modules": { "nf-core": { - "custom/dumpsoftwareversions": { - "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["modules"] - }, "multiqc": { "branch": "master", - "git_sha": "8deffd6a402233ebf905c66dbf804bd4c2637946", + "git_sha": "008f9d3e61209bf995edac3ba531f54e269e1215", "installed_by": ["modules"] } } @@ -42,12 +38,12 @@ }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "271e7fc14eb1320364416d996fb077421f3faed2", + "git_sha": "a3fb7351b1fdb2b1de282b765816bbea190e86a8", "installed_by": ["subworkflows"] }, "utils_nfschema_plugin": { "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "git_sha": "fdc08b8b1ae74f56686ce21f7ea11ad11990ce57", "installed_by": ["subworkflows"] } } diff --git a/modules/bigbio/onsite/environment.yml b/modules/bigbio/onsite/environment.yml index f1d5c7885..dccfdef3b 100644 --- a/modules/bigbio/onsite/environment.yml +++ b/modules/bigbio/onsite/environment.yml @@ -1,7 +1,6 @@ -name: onsite channels: - conda-forge - bioconda - defaults dependencies: - - bioconda::pyonsite=0.0.2 + - bioconda::pyonsite=0.0.5 diff --git a/modules/bigbio/onsite/main.nf b/modules/bigbio/onsite/main.nf index 4101b3e25..c59d65234 100644 --- a/modules/bigbio/onsite/main.nf +++ b/modules/bigbio/onsite/main.nf @@ -1,23 +1,26 @@ process ONSITE { - tag "$meta.mzml_id" + tag "${meta.mzml_id}" label 'process_medium' label 'onsite' - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pyonsite:0.0.2--pyhdfd78af_0' : - 'quay.io/biocontainers/pyonsite:0.0.2--pyhdfd78af_0' }" + container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container + ? 'oras://ghcr.io/bigbio/pyonsite-sif:0.0.5' + : 'ghcr.io/bigbio/pyonsite:0.0.5'}" input: tuple val(meta), path(mzml_file), path(id_file) output: - tuple val(meta), path("${id_file.baseName}_*.idXML"), emit: ptm_in_id_onsite + tuple val(meta), path("${prefix}_*.{idparquet,idXML,mzIdentML}"), emit: ptm_in_id_onsite path "versions.yml", emit: versions path "*.log", emit: log + when: + task.ext.when == null || task.ext.when + script: def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.mzml_id}" + prefix = task.ext.prefix ?: "${meta.mzml_id}" // Algorithm selection: lucxor (default), ascore, or phosphors def algorithm = params.onsite_algorithm ?: 'lucxor' @@ -33,41 +36,50 @@ process ONSITE { def fragment_unit = '' def add_decoys = onsite_add_decoys ? '--add-decoys' : '' def debug = params.onsite_debug ? '--debug' : '' + def suffix = id_file.name.endsWith(".idparquet") + ? "idparquet" + : id_file.name.endsWith(".idXML") + ? "idXML" + : id_file.name.endsWith(".mzIdentML") + ? "mzIdentML" : "idparquet" // Build algorithm-specific command def algorithm_cmd = '' if (algorithm == 'ascore') { // AScore: uses -in, -id, -out, --fragment-mass-unit - fragment_unit = params.onsite_fragment_unit ?: 'Da' - def optional_flags = [add_decoys, compute_all_scores, debug].findAll { it }.join(' \\\n ') + fragment_unit = params.onsite_fragment_error_units ?: 'Da' + def optional_flags = [add_decoys, compute_all_scores, debug].findAll { a -> a }.join(' \\\n ') algorithm_cmd = """ onsite ascore \\ -in ${mzml_file} \\ -id ${id_file} \\ - -out ${id_file.baseName}_ascore.idXML \\ + -out ${prefix}_ascore.${suffix} \\ --fragment-mass-tolerance ${fragment_tolerance} \\ --fragment-mass-unit ${fragment_unit}${optional_flags ? ' \\\n ' + optional_flags : ''} """ - } else if (algorithm == 'phosphors') { + } + else if (algorithm == 'phosphors') { // PhosphoRS: uses -in, -id, -out, --fragment-mass-unit - fragment_unit = params.onsite_fragment_unit ?: 'Da' - def optional_flags = [add_decoys, compute_all_scores, debug].findAll { it }.join(' \\\n ') + fragment_unit = params.onsite_fragment_error_units ?: 'Da' + def optional_flags = [add_decoys, compute_all_scores, debug].findAll { a -> a }.join(' \\\n ') algorithm_cmd = """ onsite phosphors \\ -in ${mzml_file} \\ -id ${id_file} \\ - -out ${id_file.baseName}_phosphors.idXML \\ + -out ${prefix}_phosphors.${suffix} \\ --fragment-mass-tolerance ${fragment_tolerance} \\ --fragment-mass-unit ${fragment_unit}${optional_flags ? ' \\\n ' + optional_flags : ''} + ${args} """ - } else if (algorithm == 'lucxor') { + } + else if (algorithm == 'lucxor') { // LucXor: uses -in, -id, -out, --fragment-error-units (note: error-units not mass-unit) fragment_unit = params.onsite_fragment_error_units ?: 'Da' def fragment_method = params.onsite_fragment_method ?: 'CID' def min_mz = params.onsite_min_mz ?: '150.0' - def max_charge = params.onsite_max_charge_state ?: '5' - def max_peptide_len = params.onsite_max_peptide_length ?: '40' + def max_charge = params.max_precursor_charge ?: '5' + def max_peptide_len = params.max_peptide_length ?: '40' def max_num_perm = params.onsite_max_num_perm ?: '16384' def modeling_threshold = params.onsite_modeling_score_threshold ?: '0.95' def scoring_threshold = params.onsite_scoring_threshold ?: '0.0' @@ -76,17 +88,17 @@ process ONSITE { def disable_split_by_charge = params.onsite_disable_split_by_charge ? '--disable-split-by-charge' : '' // Optional target modifications - default for LucXor includes decoy - def target_mods = params.onsite_target_modifications ? "--target-modifications ${params.onsite_target_modifications}" : "--target-modifications 'Phospho(S),Phospho(T),Phospho(Y),PhosphoDecoy(A)'" - def neutral_losses = params.onsite_neutral_losses ? "--neutral-losses ${params.onsite_neutral_losses}" : "--neutral-losses 'sty -H3PO4 -97.97690'" + def target_mods = params.onsite_target_modifications ? "--target-modifications '${params.onsite_target_modifications}'" : "--target-modifications 'Phospho(S),Phospho(T),Phospho(Y),PhosphoDecoy(A)'" + def neutral_losses = params.onsite_neutral_losses ? "--neutral-losses '${params.onsite_neutral_losses}'" : "--neutral-losses 'sty -H3PO4 -97.97690'" def decoy_mass = params.onsite_decoy_mass ? "--decoy-mass ${params.onsite_decoy_mass}" : "--decoy-mass 79.966331" - def decoy_losses = params.onsite_decoy_neutral_losses ? "--decoy-neutral-losses ${params.onsite_decoy_neutral_losses}" : "--decoy-neutral-losses 'X -H3PO4 -97.97690'" + def decoy_losses = params.onsite_decoy_neutral_losses ? "--decoy-neutral-losses '${params.onsite_decoy_neutral_losses}'" : "--decoy-neutral-losses 'X -H3PO4 -97.97690'" - def optional_flags = [disable_split_by_charge, compute_all_scores, debug].findAll { it }.join(' \\\n ') + def optional_flags = [disable_split_by_charge, compute_all_scores, debug].findAll { a -> a }.join(' \\\n ') algorithm_cmd = """ onsite lucxor \\ -in ${mzml_file} \\ -id ${id_file} \\ - -out ${id_file.baseName}_lucxor.idXML \\ + -out ${prefix}_lucxor.${suffix} \\ --fragment-method ${fragment_method} \\ --fragment-mass-tolerance ${fragment_tolerance} \\ --fragment-error-units ${fragment_unit} \\ @@ -103,16 +115,17 @@ process ONSITE { --min-num-psms-model ${min_num_psms} \\ --rt-tolerance ${rt_tolerance}${optional_flags ? ' \\\n ' + optional_flags : ''} """ - } else { - error "Unknown onsite algorithm: ${algorithm}. Supported algorithms: ascore, phosphors, lucxor" + } + else { + error("Unknown onsite algorithm: ${algorithm}. Supported algorithms: ascore, phosphors, lucxor") } """ - ${algorithm_cmd.trim()} 2>&1 | tee ${id_file.baseName}_${algorithm}.log + ${algorithm_cmd.trim()} 2>&1 | tee ${prefix}_${algorithm}.log cat <<-END_VERSIONS > versions.yml "${task.process}": - onsite: \$(onsite --version 2>&1 | grep -oP 'version \\K[0-9.]+' || echo "unknown") + onsite: \$(onsite --version 2>&1 | grep -oE 'version \\K[0-9.]+' || echo "unknown") algorithm: ${algorithm} END_VERSIONS """ diff --git a/modules/bigbio/onsite/meta.yml b/modules/bigbio/onsite/meta.yml index 62a06aa4f..b8f4e1640 100644 --- a/modules/bigbio/onsite/meta.yml +++ b/modules/bigbio/onsite/meta.yml @@ -1,5 +1,6 @@ name: onsite -description: Post-translational modification (PTM) localization using onsite algorithms (AScore, PhosphoRS, LucXor) +description: Post-translational modification (PTM) localization using onsite + algorithms (AScore, PhosphoRS, LucXor) keywords: - onsite - PTM @@ -18,40 +19,51 @@ tools: homepage: https://github.com/bigbio/onsite documentation: https://github.com/bigbio/onsite/blob/main/README.md tool_dev_url: https://github.com/bigbio/onsite - doi: "" - licence: ["MIT"] + licence: + - "MIT" + identifier: "" input: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', mzml_id:'sample1' ] - - mzml_file: - type: file - description: Input spectrum file in mzML format - pattern: "*.mzML" - - id_file: - type: file - description: Protein/peptide identifications file in idXML format - pattern: "*.idXML" + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', mzml_id:'sample1' ]` + - mzml_file: + type: file + description: Input spectrum file in mzML format + pattern: "*.mzML" + ontologies: [] + - id_file: + type: file + description: Protein/peptide identifications file + pattern: "*.{idparquet,idXML,mzIdentML}" + ontologies: [] output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', mzml_id:'sample1' ] - - ptm_in_id_onsite: - type: file - description: Protein/peptide identifications file with PTM localization scores - pattern: "*_{ascore,phosphors,lucxor}.idXML" - - log: - type: file - description: Log file from onsite execution - pattern: "*.log" - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" + ptm_in_id_onsite: + - - meta: + type: map + description: | + Groovy Map containing sample information + - ${prefix}_*.idparquet: + type: file + description: Output id file containing PTM localization results from + onsite + pattern: "${prefix}_*.{idparquet,idXML,mzIdentML}" + ontologies: [] + log: + - "*.log": + type: file + description: Log file from onsite execution + pattern: "*.log" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 authors: - "@ypriverol" - "@weizhongchun" + - "@enryh" diff --git a/modules/bigbio/onsite/tests/main.nf.test b/modules/bigbio/onsite/tests/main.nf.test index 8e4520638..587af855c 100644 --- a/modules/bigbio/onsite/tests/main.nf.test +++ b/modules/bigbio/onsite/tests/main.nf.test @@ -5,16 +5,99 @@ nextflow_process { process "ONSITE" tag "modules" tag "modules_onsite" + tag "modules_bigbio" tag "onsite" test("Should run AScore algorithm") { + when { + process { + """ + input[0] = channel.from([ + [ + [ id: 'test', mzml_id: 'test_sample' ], + file(params.test_data['proteomics']['onsite']['mzml'], checkIfExists: true) + ] + ]).combine(channel.fromPath(params.test_data['proteomics']['onsite']['idparquet'])) + """ + } + params { + onsite_algorithm = 'ascore' + } + } + + then { + assert process.success + assert snapshot(process.out.versions).match("versions_ascore") + assert process.out.ptm_in_id_onsite.size() == 1 + assert process.out.log.size() == 1 + // Check output file has correct naming + assert process.out.ptm_in_id_onsite[0][1].toString().endsWith('_ascore.idparquet') + } + } + + test("Should run PhosphoRS algorithm") { + when { process { """ input[0] = [ [ id: 'test', mzml_id: 'test_sample' ], file(params.test_data['proteomics']['onsite']['mzml'], checkIfExists: true), + file(params.test_data['proteomics']['onsite']['idparquet'], checkIfExists: true) + ] + """ + } + params { + onsite_algorithm = 'phosphors' + } + } + + then { + assert process.success + assert snapshot(process.out.versions).match("versions_phosphors") + assert process.out.ptm_in_id_onsite.size() == 1 + assert process.out.log.size() == 1 + // Check output file has correct naming + assert process.out.ptm_in_id_onsite[0][1].toString().endsWith('_phosphors.idparquet') + } + } + + test("Should run LucXor algorithm") { + + when { + process { + """ + input[0] = [ + [ id: 'test', mzml_id: 'test_sample' ], + file(params.test_data['proteomics']['onsite']['mzml'], checkIfExists: true), + file(params.test_data['proteomics']['onsite']['idparquet'], checkIfExists: true) + ] + """ + } + params { + onsite_algorithm = 'lucxor' + } + } + + then { + assert process.success + assert snapshot(process.out.versions).match("versions_lucxor") + assert process.out.ptm_in_id_onsite.size() == 1 + assert process.out.log.size() == 1 + // Check output file has correct naming + assert process.out.ptm_in_id_onsite[0][1].toString().endsWith('_lucxor.idparquet') + } + } + + test("Should run AScore algorithm with idXML input") { + + when { + process { + """ + input[0] = [ + [ id: 'test', mzml_id: 'test_sample' ], + file(params.test_data['proteomics']['onsite']['idxml_mzml'], checkIfExists: true), file(params.test_data['proteomics']['onsite']['idxml'], checkIfExists: true) ] """ @@ -26,7 +109,7 @@ nextflow_process { then { assert process.success - assert snapshot(process.out.versions).match("versions_ascore") + assert snapshot(process.out.versions).match("versions_ascore_idxml") assert process.out.ptm_in_id_onsite.size() == 1 assert process.out.log.size() == 1 // Check output file has correct naming @@ -34,14 +117,14 @@ nextflow_process { } } - test("Should run PhosphoRS algorithm") { + test("Should run PhosphoRS algorithm with idXML input") { when { process { """ input[0] = [ [ id: 'test', mzml_id: 'test_sample' ], - file(params.test_data['proteomics']['onsite']['mzml'], checkIfExists: true), + file(params.test_data['proteomics']['onsite']['idxml_mzml'], checkIfExists: true), file(params.test_data['proteomics']['onsite']['idxml'], checkIfExists: true) ] """ @@ -53,7 +136,7 @@ nextflow_process { then { assert process.success - assert snapshot(process.out.versions).match("versions_phosphors") + assert snapshot(process.out.versions).match("versions_phosphors_idxml") assert process.out.ptm_in_id_onsite.size() == 1 assert process.out.log.size() == 1 // Check output file has correct naming @@ -61,14 +144,14 @@ nextflow_process { } } - test("Should run LucXor algorithm") { + test("Should run LucXor algorithm with idXML input") { when { process { """ input[0] = [ [ id: 'test', mzml_id: 'test_sample' ], - file(params.test_data['proteomics']['onsite']['mzml'], checkIfExists: true), + file(params.test_data['proteomics']['onsite']['idxml_mzml'], checkIfExists: true), file(params.test_data['proteomics']['onsite']['idxml'], checkIfExists: true) ] """ @@ -80,7 +163,7 @@ nextflow_process { then { assert process.success - assert snapshot(process.out.versions).match("versions_lucxor") + assert snapshot(process.out.versions).match("versions_lucxor_idxml") assert process.out.ptm_in_id_onsite.size() == 1 assert process.out.log.size() == 1 // Check output file has correct naming @@ -98,7 +181,7 @@ nextflow_process { input[0] = [ [ id: 'test', mzml_id: 'test_sample' ], file(params.test_data['proteomics']['onsite']['mzml'], checkIfExists: true), - file(params.test_data['proteomics']['onsite']['idxml'], checkIfExists: true) + file(params.test_data['proteomics']['onsite']['idparquet'], checkIfExists: true) ] """ } diff --git a/modules/bigbio/onsite/tests/main.nf.test.snap b/modules/bigbio/onsite/tests/main.nf.test.snap new file mode 100644 index 000000000..19a3f6131 --- /dev/null +++ b/modules/bigbio/onsite/tests/main.nf.test.snap @@ -0,0 +1,50 @@ +{ + "versions_phosphors": { + "content": [ + [ + "versions.yml:md5,bafdb21e8e35a3f6128f4b8fb2f17fa6" + ] + ], + "timestamp": "2026-03-22T22:19:06.163312", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "versions_ascore": { + "content": [ + [ + "versions.yml:md5,e0bda208d6e29ca106d701db6ff8c6c9" + ] + ], + "timestamp": "2026-03-22T22:17:57.833213", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "versions_stub": { + "content": [ + [ + "versions.yml:md5,669fa42376f9ff6641abd22c67e507d6" + ] + ], + "timestamp": "2026-03-22T22:25:52.844037", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "versions_lucxor": { + "content": [ + [ + "versions.yml:md5,669fa42376f9ff6641abd22c67e507d6" + ] + ], + "timestamp": "2026-03-22T22:22:30.192671", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + } +} \ No newline at end of file diff --git a/modules/bigbio/thermorawfileparser/environment.yml b/modules/bigbio/thermorawfileparser/environment.yml index 63b8fc64e..dbe6ffe5c 100644 --- a/modules/bigbio/thermorawfileparser/environment.yml +++ b/modules/bigbio/thermorawfileparser/environment.yml @@ -1,4 +1,3 @@ -name: thermorawfileparser channels: - conda-forge - bioconda diff --git a/modules/bigbio/thermorawfileparser/main.nf b/modules/bigbio/thermorawfileparser/main.nf index 31ce4d0b2..ac6a16f88 100644 --- a/modules/bigbio/thermorawfileparser/main.nf +++ b/modules/bigbio/thermorawfileparser/main.nf @@ -1,62 +1,67 @@ process THERMORAWFILEPARSER { - tag "$meta.mzml_id" + tag "${meta.mzml_id}" label 'process_low' label 'process_single' label 'error_retry' conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/thermorawfileparser:1.4.5--h05cac1d_1' : - 'biocontainers/thermorawfileparser:1.4.5--h05cac1d_1' }" + container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container + ? 'https://depot.galaxyproject.org/singularity/thermorawfileparser:1.4.5--h05cac1d_1' + : 'biocontainers/thermorawfileparser:1.4.5--h05cac1d_1'}" - stageInMode { - if (task.attempt == 1) { - if (task.executor == "awsbatch") { - 'symlink' - } else { - 'link' - } - } else if (task.attempt == 2) { - if (task.executor == "awsbatch") { - 'copy' - } else { - 'symlink' - } - } else { - 'copy' - } - } input: - tuple val(meta), path(rawfile) + tuple val(meta), path(raw) output: - tuple val(meta), path("*.{mzML,mgf,parquet}"), emit: convert_files - path "versions.yml", emit: versions - path "*.log", emit: log + tuple val(meta), path("*.{mzML,mzML.gz,mgf,mgf.gz,parquet,parquet.gz}"), emit: spectra + tuple val("${task.process}"), val('thermorawfileparser'), eval("ThermoRawFileParser.sh --version"), emit: versions_thermorawfileparser, topic: versions + path "*.log", emit: log + + when: + task.ext.when == null || task.ext.when script: def args = task.ext.args ?: '' + // Detect existing format options in any supported syntax: -f=2, -f 2, --format=2, + // or --format 2. + def hasFormatArg = (args =~ /(^|\s)(-f(=|\s)\d+|--format(=|\s)\d+)/).find() // Default to indexed mzML format (-f=2) if not specified in args - def formatArg = args.contains('-f=') ? '' : '-f=2' + def formatArg = hasFormatArg ? '' : '-f=2' + def prefix = task.ext.prefix ?: "${meta.mzml_id}" + def suffix = args.contains("--format 0") || args.contains("-f 0") + ? "mgf" + : args.contains("--format 1") || args.contains("-f 1") + ? "mzML" + : args.contains("--format 2") || args.contains("-f 2") + ? "mzML" + : args.contains("--format 3") || args.contains("-f 3") + ? "parquet" + : "mzML" + suffix = args.contains("--gzip") ? "${suffix}.gz" : "${suffix}" """ - ThermoRawFileParser.sh -i='${rawfile}' ${formatArg} ${args} -o=./ 2>&1 | tee '${rawfile.baseName}_conversion.log' - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - ThermoRawFileParser: \$(ThermoRawFileParser.sh --version) - END_VERSIONS + ThermoRawFileParser.sh \\ + -i='${raw}' \\ + ${formatArg} ${args} \\ + -o=./ 2>&1 | tee '${prefix}_conversion.log' """ stub: - def prefix = task.ext.prefix ?: "${meta.mzml_id}" def args = task.ext.args ?: '' - // Determine output format from args, default to mzML - // Format 0 = MGF, formats 1-2 = mzML, format 3 = Parquet, format 4 = None - def outputExt = (args =~ /-f=0\b/).find() ? 'mgf' : 'mzML' + def prefix = task.ext.prefix ?: "${meta.mzml_id}" + def suffix = args.contains("--format 0") || args.contains("-f 0") + ? "mgf" + : args.contains("--format 1") || args.contains("-f 1") + ? "mzML" + : args.contains("--format 2") || args.contains("-f 2") + ? "mzML" + : args.contains("--format 3") || args.contains("-f 3") + ? "parquet" + : "mzML" + suffix = args.contains("--gzip") ? "${suffix}.gz" : "${suffix}" """ - touch '${prefix}.${outputExt}' + touch '${prefix}.${suffix}' touch '${prefix}_conversion.log' cat <<-END_VERSIONS > versions.yml diff --git a/modules/bigbio/thermorawfileparser/meta.yml b/modules/bigbio/thermorawfileparser/meta.yml index b6f99c9a3..48b7d3422 100644 --- a/modules/bigbio/thermorawfileparser/meta.yml +++ b/modules/bigbio/thermorawfileparser/meta.yml @@ -1,10 +1,12 @@ name: thermorawfileparser -description: Convert RAW file to mzML or MGF files +description: Convert RAW file to mzML or MGF files format keywords: - raw - - mzML - - MGF - - OpenMS + - mzml + - mgf + - parquet + - parser + - proteomics tools: - thermorawfileparser: description: | @@ -14,36 +16,66 @@ tools: - `-L` or `--msLevel=VALUE` to select MS levels (e.g., `-L=1,2` or `--msLevel=1-3`) homepage: https://github.com/compomics/ThermoRawFileParser documentation: https://github.com/compomics/ThermoRawFileParser + tool_dev_url: https://github.com/compomics/ThermoRawFileParser + doi: "10.1021/acs.jproteome.9b00328" + licence: + - "Apache Software" + identifier: biotools:ThermoRawFileParser input: - - meta: - type: map - description: | - Groovy Map containing sample information - - rawfile: - type: file - description: | - Thermo RAW file - pattern: "*.{raw,RAW}" + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1', single_end:false ]` + - raw: + type: file + description: Thermo RAW file + pattern: "*.{raw,RAW}" + ontologies: [] output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'sample1', mzml_id:'UPS1_50amol_R3' ] - - convert_files: - type: file - description: | - Converted files in mzML or MGF format depending on the format parameter (-f). - Format options: 0 for MGF, 1 for mzML, 2 for indexed mzML (default), 3 for Parquet, 4 for None. - pattern: "*.{mzML,mgf,parquet}" - - log: - type: file - description: log file - pattern: "*.log" - - versions: - type: file - description: File containing software version - pattern: "versions.yml" + spectra: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1', single_end:false ]` + - "*.{mzML,mzML.gz,mgf,mgf.gz,parquet,parquet.gz}": + type: file + description: Mass spectra in open format + pattern: "*.{mzML,mzML.gz,mgf,mgf.gz,parquet,parquet.gz}" + ontologies: [] + versions_thermorawfileparser: + - - ${task.process}: + type: string + description: The process the versions were collected from + - thermorawfileparser: + type: string + description: The name of the tool + - ThermoRawFileParser.sh --version: + type: eval + description: The expression to obtain the version of the tool + log: + - "*.log": + type: file + description: Log file from the conversion process + pattern: "*.log" + ontologies: [] +topics: + versions: + - - ${task.process}: + type: string + description: The process the versions were collected from + - thermorawfileparser: + type: string + description: The name of the tool + - ThermoRawFileParser.sh --version: + type: eval + description: The expression to obtain the version of the tool authors: + - "@jonasscheid" + - "@daichengxin" + - "@ypriverol" +maintainers: + - "@jonasscheid" - "@daichengxin" - "@ypriverol" diff --git a/modules/bigbio/thermorawfileparser/tests/main.nf.test b/modules/bigbio/thermorawfileparser/tests/main.nf.test index 355fbb150..c1f8ce955 100644 --- a/modules/bigbio/thermorawfileparser/tests/main.nf.test +++ b/modules/bigbio/thermorawfileparser/tests/main.nf.test @@ -22,8 +22,8 @@ nextflow_process { then { assert process.success - assert snapshot(process.out.versions).match("versions") - assert new File(process.out.convert_files[0][1]).name == 'TMT_Erwinia_1uLSike_Top10HCD_isol2_45stepped_60min_01.mzML' + assert snapshot(process.out.versions_thermorawfileparser).match("versions") + assert new File(process.out.spectra[0][1]).name == 'TMT_Erwinia_1uLSike_Top10HCD_isol2_45stepped_60min_01.mzML' assert process.out.log.size() == 1 } } @@ -36,7 +36,7 @@ nextflow_process { process { """ input[0] = [ - [ id: 'test', mzml_id: 'test_sample' ], + [ id: 'test_sample', mzml_id: 'test_sample' ], file(params.test_data['proteomics']['msspectra']['ups1_50amol_r3'], checkIfExists: false) ] """ @@ -45,8 +45,9 @@ nextflow_process { then { assert process.success - assert snapshot(process.out.versions).match("versions_stub") - assert new File(process.out.convert_files[0][1]).name == 'test_sample.mzML' + assert snapshot(process.out.versions_thermorawfileparser).match("versions_stub") + assert new File(process.out.spectra[0][1]).name == 'test_sample.mzML' + assert snapshot(process.out).match() assert process.out.log.size() == 1 } } diff --git a/modules/bigbio/thermorawfileparser/tests/main.nf.test.snap b/modules/bigbio/thermorawfileparser/tests/main.nf.test.snap index 6562491ed..f194dbb44 100644 --- a/modules/bigbio/thermorawfileparser/tests/main.nf.test.snap +++ b/modules/bigbio/thermorawfileparser/tests/main.nf.test.snap @@ -1,26 +1,34 @@ { - "versions": { - "content": [ - [ - "versions.yml:md5,dc9625538c025d615109ef8cac3a86ab" - ] - ], - "meta": { - "nf-test": "0.9.3", - "nextflow": "25.04.8" + "versions_stub": { + "content": [ + [ + [ + "THERMORAWFILEPARSER", + "thermorawfileparser", + "1.4.5" + ] + ] + ], + "timestamp": "2026-03-20T12:41:22.8183", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, - "timestamp": "2025-12-11T06:27:00.000000" - }, - "versions_stub": { - "content": [ - [ - "versions.yml:md5,dc9625538c025d615109ef8cac3a86ab" - ] - ], - "meta": { - "nf-test": "0.9.3", - "nextflow": "25.04.8" - }, - "timestamp": "2025-12-11T06:27:00.000000" - } -} + "versions": { + "content": [ + [ + [ + "THERMORAWFILEPARSER", + "thermorawfileparser", + "1.4.5" + ] + ] + ], + "timestamp": "2026-03-20T12:36:30.88531", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } + } +} \ No newline at end of file diff --git a/modules/bigbio/thermorawfileparser/thermorawfileparser.diff b/modules/bigbio/thermorawfileparser/thermorawfileparser.diff new file mode 100644 index 000000000..05f21ecd5 --- /dev/null +++ b/modules/bigbio/thermorawfileparser/thermorawfileparser.diff @@ -0,0 +1,36 @@ +Changes in component 'bigbio/thermorawfileparser' +'modules/bigbio/thermorawfileparser/environment.yml' is unchanged +'modules/bigbio/thermorawfileparser/meta.yml' is unchanged +Changes in 'thermorawfileparser/main.nf': +--- modules/bigbio/thermorawfileparser/main.nf ++++ modules/bigbio/thermorawfileparser/main.nf +@@ -1,5 +1,5 @@ + process THERMORAWFILEPARSER { +- tag "${meta.id}" ++ tag "${meta.mzml_id}" + label 'process_low' + label 'process_single' + label 'error_retry' +@@ -27,7 +27,7 @@ + def hasFormatArg = (args =~ /(^|\s)(-f(=|\s)\d+|--format(=|\s)\d+)/).find() + // Default to indexed mzML format (-f=2) if not specified in args + def formatArg = hasFormatArg ? '' : '-f=2' +- def prefix = task.ext.prefix ?: "${meta.id}" ++ def prefix = task.ext.prefix ?: "${meta.mzml_id}" + def suffix = args.contains("--format 0") || args.contains("-f 0") + ? "mgf" + : args.contains("--format 1") || args.contains("-f 1") +@@ -48,7 +48,7 @@ + + stub: + def args = task.ext.args ?: '' +- def prefix = task.ext.prefix ?: "${meta.id}" ++ def prefix = task.ext.prefix ?: "${meta.mzml_id}" + def suffix = args.contains("--format 0") || args.contains("-f 0") + ? "mgf" + : args.contains("--format 1") || args.contains("-f 1") + +'modules/bigbio/thermorawfileparser/tests/main.nf.test.snap' is unchanged +'modules/bigbio/thermorawfileparser/tests/nextflow.config' is unchanged +'modules/bigbio/thermorawfileparser/tests/main.nf.test' is unchanged +************************************************************ diff --git a/modules/local/diann/assemble_empirical_library/main.nf b/modules/local/diann/assemble_empirical_library/main.nf deleted file mode 100644 index 6e56511ce..000000000 --- a/modules/local/diann/assemble_empirical_library/main.nf +++ /dev/null @@ -1,65 +0,0 @@ -process ASSEMBLE_EMPIRICAL_LIBRARY { - tag "$meta.experiment_id" - label 'process_low' - label 'diann' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://containers.biocontainers.pro/s3/SingImgsRepo/diann/v1.8.1_cv1/diann_v1.8.1_cv1.img' : - 'docker.io/biocontainers/diann:v1.8.1_cv1' }" - - input: - // In this step the real files are passed, and not the names - path(ms_files) - val(meta) - path("quant/*") - path(lib) - - output: - path "empirical_library.*", emit: empirical_library - path "assemble_empirical_library.log", emit: log - path "versions.yml", emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - - if (params.mass_acc_automatic) { - mass_acc = '--individual-mass-acc' - } else if (meta['precursormasstoleranceunit'].toLowerCase().endsWith('ppm') && meta['fragmentmasstoleranceunit'].toLowerCase().endsWith('ppm')){ - mass_acc = "--mass-acc ${meta['fragmentmasstolerance']} --mass-acc-ms1 ${meta['precursormasstolerance']}" - } else { - mass_acc = '--individual-mass-acc' - } - scan_window = params.scan_window_automatic ? '--individual-windows' : "--window $params.scan_window" - - """ - # Precursor Tolerance value was: ${meta['precursormasstolerance']} - # Fragment Tolerance value was: ${meta['fragmentmasstolerance']} - # Precursor Tolerance unit was: ${meta['precursormasstoleranceunit']} - # Fragment Tolerance unit was: ${meta['fragmentmasstoleranceunit']} - - ls -lcth - - diann --f ${(ms_files as List).join(' --f ')} \\ - --lib ${lib} \\ - --threads ${task.cpus} \\ - --out-lib empirical_library \\ - --verbose $params.diann_debug \\ - --rt-profiling \\ - --temp ./quant/ \\ - --use-quant \\ - ${mass_acc} \\ - ${scan_window} \\ - --gen-spec-lib \\ - $args - - cp report.log.txt assemble_empirical_library.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - DIA-NN: \$(diann 2>&1 | grep "DIA-NN" | grep -oP "\\d+\\.\\d+(\\.\\w+)*(\\.[\\d]+)?") - END_VERSIONS - """ -} diff --git a/modules/local/diann/assemble_empirical_library/meta.yml b/modules/local/diann/assemble_empirical_library/meta.yml deleted file mode 100644 index 0d1f5b7f7..000000000 --- a/modules/local/diann/assemble_empirical_library/meta.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: assemble_empirical_library -description: A module for assembling an empirical library based on a preliminary analysis of the in-silico library with DIA-NN. -keywords: - - DIA-NN - - DIA -tools: - - DIA-NN: - description: | - DIA-NN - a universal software for data-independent acquisition (DIA) proteomics data processing by Demichev. - homepage: https://github.com/vdemichev/DiaNN - documentation: https://github.com/vdemichev/DiaNN -input: - - mzMLs: - type: file - description: Spectra file in mzML format - pattern: "*.mzML" - - quant: - type: file - description: The .quant files from DIA-NN preliminary analysis, containing IDs and quantification information. - pattern: "*.quant" - - lib: - type: file - description: Spectra library file - pattern: "*.tsv" -output: - - empirical_library: - type: file - description: An empirical spectral library from the .quant files. - pattern: "empirical_library.tsv" - - log: - type: file - description: DIA-NN log file - pattern: "assemble_empirical_library.log" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" diff --git a/modules/local/diann/convert_results/main.nf b/modules/local/diann/convert_results/main.nf deleted file mode 100644 index 37011791d..000000000 --- a/modules/local/diann/convert_results/main.nf +++ /dev/null @@ -1,52 +0,0 @@ -process CONVERT_RESULTS { - tag "$meta.experiment_id" - label 'process_medium' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/quantms-utils:0.0.24--pyh7e72e81_0' : - 'biocontainers/quantms-utils:0.0.24--pyh7e72e81_0' }" - - input: - path(report) - path(exp_design) - path(report_pg) - path(report_pr) - path(ms_information) - val(meta) - path(fasta) - path("version/versions.yml") - - output: - path "*msstats_in.csv", emit: out_msstats - path "*triqler_in.tsv", emit: out_triqler - path "*.mzTab", optional: true, emit: out_mztab - path "*.log", emit: log - path "versions.yml", emit: versions - - exec: - log.info "DIANNCONVERT is based on the output of DIA-NN 1.8.1, 2.0.* and 2.1.*, other versions of DIA-NN don't support mzTab conversion." - - script: - def args = task.ext.args ?: '' - def dia_params = [meta.fragmentmasstolerance,meta.fragmentmasstoleranceunit,meta.precursormasstolerance, - meta.precursormasstoleranceunit,meta.enzyme,meta.fixedmodifications,meta.variablemodifications].join(';') - def diann2mztab = params.enable_diann_mztab ? "--enable_diann2mztab" : "" - - """ - quantmsutilsc diann2mztab \\ - --folder ./ \\ - --exp_design ${exp_design} \\ - --diann_version ./version/versions.yml \\ - --dia_params "${dia_params}" \\ - --charge $params.max_precursor_charge \\ - --missed_cleavages $params.allowed_missed_cleavages \\ - --qvalue_threshold $params.protein_level_fdr_cutoff \\ - ${diann2mztab} \\ - 2>&1 | tee convert_report.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - quantms-utils: \$(pip show quantms-utils | grep "Version" | awk -F ': ' '{print \$2}') - END_VERSIONS - """ -} diff --git a/modules/local/diann/convert_results/meta.yml b/modules/local/diann/convert_results/meta.yml deleted file mode 100644 index 94d097004..000000000 --- a/modules/local/diann/convert_results/meta.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: convert_results -description: A module to convert DIA report files to MSstats, Triqler and mzTab -keywords: - - DIA-NN - - conversion - - MSstats - - Triqler - - mzTab -tools: - - custom: - description: | - A custom module for DIA-NN report file conversion. - homepage: https://github.com/bigbio/quantms - documentation: https://github.com/bigbio/quantms/tree/readthedocs -input: - - report: - type: file - description: DIA-NN main report file - pattern: "*.tsv" - - exp_design: - type: file - description: An experimental design file including Sample and replicates column et al. - pattern: "*.tsv" - - report_pr: - type: file - description: A text table containing normalized quantities for precursors. They are filtered at 1% FDR, using both global and run-specific q-values for precursors - pattern: "*pr_matrix.tsv" - - report_pg: - type: file - description: A text table containing normalized quantities for protein groups. They are filtered at 1% FDR, using global q-values for protein groups - pattern: "*pg_matrix.tsv" - - report_pg: - type: file - description: A text table containing information from mzMLs - pattern: "*_mzml_info.tsv" - - meta: - type: map - description: Groovy Map containing sample information - - fasta: - type: file - description: Protein sequence database in Fasta format. - pattern: "*.{fasta,fa}" - - version: - type: file - description: File containing Dia-NN version - pattern: "versions.yml" -output: - - out_msstats: - type: file - description: MSstats input file - pattern: "out_msstats.csv" - - out_triqler: - type: file - description: Triqler input file - pattern: "out_triqler.tsv" - - out_mztab: - type: file - description: mzTab - pattern: "*.mztab" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" - - "@wanghong" diff --git a/modules/local/diann/final_quantification/main.nf b/modules/local/diann/final_quantification/main.nf deleted file mode 100644 index ddc9ef5c6..000000000 --- a/modules/local/diann/final_quantification/main.nf +++ /dev/null @@ -1,78 +0,0 @@ -process FINAL_QUANTIFICATION { - tag "$meta.experiment_id" - label 'process_high' - label 'diann' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://containers.biocontainers.pro/s3/SingImgsRepo/diann/v1.8.1_cv1/diann_v1.8.1_cv1.img' : - 'docker.io/biocontainers/diann:v1.8.1_cv1' }" - - input: - // Note that the files are passed as names and not paths, this prevents them from being staged - // in the directory - val(ms_files) - val(meta) - path(empirical_library) - // The quant path is passed, and diann will use the files in the quant directory instead - // of the ones passed in ms_files. - path("quant/") - path(fasta) - - output: - // DIA-NN 2.0 don't return report in tsv format - path "diann_report.tsv", emit: main_report, optional: true - path "diann_report.parquet", emit: report_parquet, optional: true - path "diann_report.manifest.txt", emit: report_manifest, optional: true - path "diann_report.protein_description.tsv", emit: protein_description, optional: true - path "diann_report.stats.tsv", emit: report_stats - path "diann_report.pr_matrix.tsv", emit: pr_matrix - path "diann_report.pg_matrix.tsv", emit: pg_matrix - path "diann_report.gg_matrix.tsv", emit: gg_matrix - path "diann_report.unique_genes_matrix.tsv", emit: unique_gene_matrix - path "diannsummary.log", emit: log - - // Different library files format are exported due to different DIA-NN versions - path "empirical_library.tsv", emit: final_speclib, optional: true - path "empirical_library.tsv.skyline.speclib", emit: skyline_speclib, optional: true - path "versions.yml", emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - - scan_window = params.scan_window_automatic ? "--individual-windows" : "--window $params.scan_window" - species_genes = params.species_genes ? "--species-genes": "" - report_decoys = params.diann_report_decoys ? "--report-decoys": "" - diann_export_xic = params.diann_export_xic ? "--xic": "" - - """ - # Notes: if .quant files are passed, mzml/.d files are not accessed, so the name needs to be passed but files - # do not need to pe present. - - diann --lib ${empirical_library} \\ - --fasta ${fasta} \\ - --f ${(ms_files as List).join(' --f ')} \\ - --threads ${task.cpus} \\ - --verbose $params.diann_debug \\ - --temp ./quant/ \\ - --relaxed-prot-inf \\ - --pg-level $params.pg_level \\ - ${species_genes} \\ - --use-quant \\ - --matrices \\ - --out diann_report.tsv \\ - --qvalue $params.protein_level_fdr_cutoff \\ - ${report_decoys} \\ - ${diann_export_xic} \\ - $args - - cp diann_report.log.txt diannsummary.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - DIA-NN: \$(diann 2>&1 | grep "DIA-NN" | grep -oP "\\d+\\.\\d+(\\.\\w+)*(\\.[\\d]+)?") - END_VERSIONS - """ -} diff --git a/modules/local/diann/final_quantification/meta.yml b/modules/local/diann/final_quantification/meta.yml deleted file mode 100644 index 4f8422524..000000000 --- a/modules/local/diann/final_quantification/meta.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: final_quantification -description: A module for summarization of results from DIA-NN analysis. -keywords: - - DIA-NN - - DIA -tools: - - DIA-NN: - description: | - DIA-NN - a universal software for data-independent acquisition (DIA) proteomics data processing by Demichev. - homepage: https://github.com/vdemichev/DiaNN - documentation: https://github.com/vdemichev/DiaNN -input: - - empirical_library: - type: file - description: Empirical spectral library generated by DIA-NN - pattern: "*.tsv" - - mzMLs: - type: file - description: Spectra files in mzML format. - pattern: "*.mzML" - - fasta: - type: file - description: Protein sequence database in Fasta format. - pattern: "*.{fasta,fa}" - - quant: - type: file - description: Identification and Quantification file from DIA-NN. - pattern: "*.quant" -output: - - main_report: - type: file - description: A text table containing precursor and protein IDs, as well as plenty of associated information. - pattern: "*.tsv" - - pr_matrix: - type: file - description: A text table containing normalized quantities for precursors. They are filtered at 1% FDR, using both global and run-specific q-values for precursors - pattern: "*.tsv" - - pg_matrix: - type: file - description: A text table containing normalized quantities for protein groups. They are filtered at 1% FDR, using global q-values for protein groups - pattern: "*.tsv" - - gg_matrix: - type: file - description: A text table containing normalized quantities for gene groups. - pattern: "*.tsv" - - log: - type: file - description: DIA-NN log file - pattern: "diannsummary.log" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" diff --git a/modules/local/diann/generate_cfg/main.nf b/modules/local/diann/generate_cfg/main.nf deleted file mode 100644 index 7706e9198..000000000 --- a/modules/local/diann/generate_cfg/main.nf +++ /dev/null @@ -1,32 +0,0 @@ -process GENERATE_CFG { - tag "$meta.experiment_id" - label 'process_tiny' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/quantms-utils:0.0.24--pyh7e72e81_0' : - 'biocontainers/quantms-utils:0.0.24--pyh7e72e81_0' }" - - input: - val(meta) - - output: - path 'diann_config.cfg', emit: diann_cfg - path 'versions.yml', emit: versions - path '*.log' - - script: - def args = task.ext.args ?: '' - - """ - quantmsutilsc dianncfg \\ - --enzyme "${meta.enzyme}" \\ - --fix_mod "${meta.fixedmodifications}" \\ - --var_mod "${meta.variablemodifications}" \\ - 2>&1 | tee GENERATE_DIANN_CFG.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - quantms-utils: \$(pip show quantms-utils | grep "Version" | awk -F ': ' '{print \$2}') - END_VERSIONS - """ -} diff --git a/modules/local/diann/generate_cfg/meta.yml b/modules/local/diann/generate_cfg/meta.yml deleted file mode 100644 index 350fb1fc9..000000000 --- a/modules/local/diann/generate_cfg/meta.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: generate_cfg -description: A module to generate DIA-NN configuration files, based on input files and params. -keywords: - - configure - - DIA-NN -tools: - - custom: - description: | - A custom module to generate DIA-NN configuration files from input files and params. - homepage: https://github.com/bigbio/quantms - documentation: https://github.com/bigbio/quantms/tree/readthedocs -input: - - meta: - type: map - description: Groovy Map containing sample information -output: - - diann_cfg: - type: file - description: DIA-NN configure file for search and quantification - pattern: "diann_config.cfg" - - version: - type: file - description: File containing software version - pattern: "versions.yml" - - log: - type: file - description: log file - pattern: "*.log" -authors: - - "@daichengxin" diff --git a/modules/local/diann/individual_analysis/main.nf b/modules/local/diann/individual_analysis/main.nf deleted file mode 100644 index c301d2481..000000000 --- a/modules/local/diann/individual_analysis/main.nf +++ /dev/null @@ -1,61 +0,0 @@ -process INDIVIDUAL_ANALYSIS { - tag "$ms_file.baseName" - label 'process_high' - label 'diann' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://containers.biocontainers.pro/s3/SingImgsRepo/diann/v1.8.1_cv1/diann_v1.8.1_cv1.img' : - 'docker.io/biocontainers/diann:v1.8.1_cv1' }" - - input: - tuple val(meta), path(ms_file), path(fasta), path(diann_log), path(library) - - output: - path "*.quant", emit: diann_quant - path "*_final_diann.log", emit: log - path "versions.yml", emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - scan_window = params.scan_window - - if (params.mass_acc_automatic | params.scan_window_automatic) { - mass_acc_ms2 = "\$(cat ${diann_log} | grep \"Averaged recommended settings\" | cut -d ' ' -f 11 | tr -cd \"[0-9]\")" - scan_window = "\$(cat ${diann_log} | grep \"Averaged recommended settings\" | cut -d ' ' -f 19 | tr -cd \"[0-9]\")" - mass_acc_ms1 = "\$(cat ${diann_log} | grep \"Averaged recommended settings\" | cut -d ' ' -f 15 | tr -cd \"[0-9]\")" - } else if (meta['precursormasstoleranceunit'].toLowerCase().endsWith('ppm') && meta['fragmentmasstoleranceunit'].toLowerCase().endsWith('ppm')) { - mass_acc_ms1 = meta["precursormasstolerance"] - mass_acc_ms2 = meta["fragmentmasstolerance"] - } else { - mass_acc_ms2 = "\$(cat ${diann_log} | grep \"Averaged recommended settings\" | cut -d ' ' -f 11 | tr -cd \"[0-9]\")" - scan_window = "\$(cat ${diann_log} | grep \"Averaged recommended settings\" | cut -d ' ' -f 19 | tr -cd \"[0-9]\")" - mass_acc_ms1 = "\$(cat ${diann_log} | grep \"Averaged recommended settings\" | cut -d ' ' -f 15 | tr -cd \"[0-9]\")" - } - - """ - diann --lib ${library} \\ - --f ${ms_file} \\ - --fasta ${fasta} \\ - --threads ${task.cpus} \\ - --verbose $params.diann_debug \\ - --temp ./ \\ - --mass-acc ${mass_acc_ms2} \\ - --mass-acc-ms1 ${mass_acc_ms1} \\ - --window ${scan_window} \\ - --no-ifs-removal \\ - --no-main-report \\ - --relaxed-prot-inf \\ - --pg-level $params.pg_level \\ - $args - - cp report.log.txt ${ms_file.baseName}_final_diann.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - DIA-NN: \$(diann 2>&1 | grep "DIA-NN" | grep -oP "\\d+\\.\\d+(\\.\\w+)*(\\.[\\d]+)?") - END_VERSIONS - """ -} diff --git a/modules/local/diann/individual_analysis/meta.yml b/modules/local/diann/individual_analysis/meta.yml deleted file mode 100644 index 655a16fd5..000000000 --- a/modules/local/diann/individual_analysis/meta.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: individual_analysis -description: A module for final analysis of individual raw files based on DIA-NN. -keywords: - - DIA-NN - - DIA -tools: - - DIA-NN: - description: | - DIA-NN - a universal software for data-independent acquisition (DIA) proteomics data processing by Demichev. - homepage: https://github.com/vdemichev/DiaNN - documentation: https://github.com/vdemichev/DiaNN -input: - - diann_log: - type: file - description: DIA-NN log file - pattern: "assemble_empirical_library.log" - - empirical_library: - type: file - description: An empirical spectral library from the .quant files. - pattern: "empirical_library.tsv" - - mzML: - type: file - description: Spectra file in mzML format - pattern: "*.mzML" - - fasta: - type: file - description: Protein sequence database in fasta format - pattern: "*.{fasta,fa}" -output: - - diann_quant: - type: file - description: Quantification file from DIA-NN - pattern: "*.quant" - - lib: - type: file - description: Spectral library file - pattern: "*.tsv" - - log: - type: file - description: DIA-NN log file - pattern: "*_diann.log" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" diff --git a/modules/local/diann/insilico_library_generation/main.nf b/modules/local/diann/insilico_library_generation/main.nf deleted file mode 100644 index 925208433..000000000 --- a/modules/local/diann/insilico_library_generation/main.nf +++ /dev/null @@ -1,59 +0,0 @@ -process INSILICO_LIBRARY_GENERATION { - tag "$fasta.Name" - label 'process_medium' - label 'diann' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://containers.biocontainers.pro/s3/SingImgsRepo/diann/v1.8.1_cv1/diann_v1.8.1_cv1.img' : - 'docker.io/biocontainers/diann:v1.8.1_cv1' }" - - input: - file(fasta) - file(diann_config) - - output: - path "versions.yml", emit: versions - path "*.predicted.speclib", emit: predict_speclib - path "silicolibrarygeneration.log", emit: log - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - - min_pr_mz = params.min_pr_mz ? "--min-pr-mz $params.min_pr_mz":"" - max_pr_mz = params.max_pr_mz ? "--max-pr-mz $params.max_pr_mz":"" - min_fr_mz = params.min_fr_mz ? "--min-fr-mz $params.min_fr_mz":"" - max_fr_mz = params.max_fr_mz ? "--max-fr-mz $params.max_fr_mz":"" - met_excision = params.met_excision ? "--met-excision" : "" - - """ - diann `cat diann_config.cfg` \\ - --fasta ${fasta} \\ - --fasta-search \\ - ${min_pr_mz} \\ - ${max_pr_mz} \\ - ${min_fr_mz} \\ - ${max_fr_mz} \\ - --missed-cleavages $params.allowed_missed_cleavages \\ - --min-pep-len $params.min_peptide_length \\ - --max-pep-len $params.max_peptide_length \\ - --min-pr-charge $params.min_precursor_charge \\ - --max-pr-charge $params.max_precursor_charge \\ - --var-mods $params.max_mods \\ - --threads ${task.cpus} \\ - --predictor \\ - --verbose $params.diann_debug \\ - --gen-spec-lib \\ - ${met_excision} \\ - ${args} - - cp *lib.log.txt silicolibrarygeneration.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - DIA-NN: \$(diann 2>&1 | grep "DIA-NN" | grep -oP "\\d+\\.\\d+(\\.\\w+)*(\\.[\\d]+)?") - END_VERSIONS - """ -} diff --git a/modules/local/diann/insilico_library_generation/meta.yml b/modules/local/diann/insilico_library_generation/meta.yml deleted file mode 100644 index 609caaec6..000000000 --- a/modules/local/diann/insilico_library_generation/meta.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: insilico_library_generation -description: A module for in silico predicted library generation based on DIA-NN. -keywords: - - DIA-NN - - library free - - DIA -tools: - - DIA-NN: - description: | - DIA-NN - a universal software for data-independent acquisition (DIA) proteomics data processing by Demichev. - homepage: https://github.com/vdemichev/DiaNN - documentation: https://github.com/vdemichev/DiaNN -input: - - fasta: - type: file - description: FASTA sequence databases - pattern: "*.{fasta,fa}" - - cfg: - type: file - description: specifies a configuration file to load options/commands from. - pattern: "*.cfg" -output: - - predict_speclib: - type: file - description: Silico-predicted spectral library by deep leaning predictor in DIA-NN - pattern: "*.predicted.speclib" - - log: - type: file - description: DIA-NN log file - pattern: "silicolibrarygeneration.log" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" diff --git a/modules/local/diann/preliminary_analysis/main.nf b/modules/local/diann/preliminary_analysis/main.nf deleted file mode 100644 index c3436f2ee..000000000 --- a/modules/local/diann/preliminary_analysis/main.nf +++ /dev/null @@ -1,63 +0,0 @@ -process PRELIMINARY_ANALYSIS { - tag "$ms_file.baseName" - label 'process_high' - label 'diann' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://containers.biocontainers.pro/s3/SingImgsRepo/diann/v1.8.1_cv1/diann_v1.8.1_cv1.img' : - 'docker.io/biocontainers/diann:v1.8.1_cv1' }" - - input: - tuple val(meta), path(ms_file), path(predict_library) - - output: - path "*.quant", emit: diann_quant - tuple val(meta), path("*_diann.log"), emit: log - path "versions.yml", emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - - // I am using here the ["key"] syntax, since the preprocessed meta makes - // was evaluating to null when using the dot notation. - - if (params.mass_acc_automatic) { - mass_acc = "" - } else if (meta['precursormasstoleranceunit'].toLowerCase().endsWith('ppm') && meta['fragmentmasstoleranceunit'].toLowerCase().endsWith('ppm')){ - mass_acc = "--mass-acc ${meta['fragmentmasstolerance']} --mass-acc-ms1 ${meta['precursormasstolerance']}" - } else { - log.info "Warning: DIA-NN only supports ppm unit tolerance for MS1 and MS2. Falling back to `mass_acc_automatic`=`true` to automatically determine the tolerance by DIA-NN!" - mass_acc = "" - } - - // Notes: Use double quotes for params, so that it is escaped in the shell. - scan_window = params.scan_window_automatic ? '' : "--window $params.scan_window" - - """ - # Precursor Tolerance value was: ${meta['precursormasstolerance']} - # Fragment Tolerance value was: ${meta['fragmentmasstolerance']} - # Precursor Tolerance unit was: ${meta['precursormasstoleranceunit']} - # Fragment Tolerance unit was: ${meta['fragmentmasstoleranceunit']} - - # Final mass accuracy is '${mass_acc}' - - diann --lib ${predict_library} \\ - --f ${ms_file} \\ - --threads ${task.cpus} \\ - --verbose $params.diann_debug \\ - ${scan_window} \\ - --temp ./ \\ - ${mass_acc} \\ - $args - - cp report.log.txt ${ms_file.baseName}_diann.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - DIA-NN: \$(diann 2>&1 | grep "DIA-NN" | grep -oP "\\d+\\.\\d+(\\.\\w+)*(\\.[\\d]+)?") - END_VERSIONS - """ -} diff --git a/modules/local/diann/preliminary_analysis/meta.yml b/modules/local/diann/preliminary_analysis/meta.yml deleted file mode 100644 index 7d9320cbc..000000000 --- a/modules/local/diann/preliminary_analysis/meta.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: preliminary_analysis -description: A module for preliminary analysis of individual raw files with DIA-NN using the in-silico generated library (also from DIA-NN). -keywords: - - DIA-NN - - DIA -tools: - - DIA-NN: - description: | - DIA-NN - a universal software for data-independent acquisition (DIA) proteomics data processing by Demichev. - homepage: https://github.com/vdemichev/DiaNN - documentation: https://github.com/vdemichev/DiaNN -input: - - meta: - type: map - description: Groovy Map containing sample information - - predict_tsv: - type: file - description: Silico-predicted spectral library by deep leaning predictor in DIA-NN - pattern: "*.tsv" - - mzML: - type: file - description: Spectra file in mzML format - pattern: "*.mzML" -output: - - diann_quant: - type: file - description: Quantification file from DIA-NN - pattern: "*.quant" - - log: - type: file - description: DIA-NN log file - pattern: "*_diann.log" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" diff --git a/modules/local/msstats/msstats_lfq/main.nf b/modules/local/msstats/msstats_lfq/main.nf deleted file mode 100644 index a05b28e5c..000000000 --- a/modules/local/msstats/msstats_lfq/main.nf +++ /dev/null @@ -1,44 +0,0 @@ -process MSSTATS_LFQ { - tag "$msstats_csv_input.Name" - label 'process_medium' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/bioconductor-msstats:4.14.0--r44he5774e6_0' : - 'biocontainers/bioconductor-msstats:4.14.0--r44he5774e6_0' }" - - input: - path msstats_csv_input - - output: - // The generation of the PDFs from MSstats are very unstable, especially with auto-contrasts. - // And users can easily fix anything based on the csv and the included script -> make optional - path "*.pdf", optional: true - path "*.csv", emit: msstats_csv - path "*.log", emit: log - path "versions.yml" , emit: versions - - script: - def args = task.ext.args ?: '' - ref_con = params.ref_condition ?: "" - - """ - msstats_plfq.R \\ - ${msstats_csv_input} \\ - "${params.contrasts}" \\ - "${ref_con}" \\ - ${params.msstats_remove_one_feat_prot} \\ - ${params.msstatslfq_removeFewMeasurements} \\ - ${params.msstatslfq_feature_subset_protein} \\ - ${params.msstatslfq_quant_summary_method} \\ - ${msstats_csv_input.baseName} \\ - ${params.msstats_threshold} \\ - $args \\ - 2>&1 | tee msstats.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - r-base: \$(echo \$(R --version 2>&1) | sed 's/^.*R version //; s/ .*\$//') - bioconductor-msstats: \$(Rscript -e "library(MSstats); cat(as.character(packageVersion('MSstats')))") - END_VERSIONS - """ -} diff --git a/modules/local/msstats/msstats_lfq/meta.yml b/modules/local/msstats/msstats_lfq/meta.yml deleted file mode 100644 index d2c892617..000000000 --- a/modules/local/msstats/msstats_lfq/meta.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: msstats_lfq -description: A module to performance proteomics statistical analysis using MSstats tool. -keywords: - - MSstats - - Downstream Analysis -tools: - - MSstats: - description: | - An R package for statistical analysis of quantitative mass spectrometry-based proteomics experiments. - homepage: https://github.com/Vitek-Lab/MSstats - documentation: https://www.bioconductor.org/packages/release/bioc/manuals/MSstats/man/MSstats.pdf -input: - - out_msstats: - type: file - description: MSstats input file with analysis results for statistical downstream analysis in MSstats. - pattern: "out_msstats.csv" -output: - - msstats_csv: - type: file - description: csv file with results of statistical testing - pattern: "*.csv" - - version: - type: file - description: File containing software version - pattern: "versions.yml" - - log: - type: file - description: log file - pattern: "*.log" -authors: - - "@daichengxin" diff --git a/modules/local/msstats/msstats_tmt/main.nf b/modules/local/msstats/msstats_tmt/main.nf deleted file mode 100644 index 11587332b..000000000 --- a/modules/local/msstats/msstats_tmt/main.nf +++ /dev/null @@ -1,50 +0,0 @@ -process MSSTATS_TMT { - tag "$msstatstmt_csv_input.Name" - label 'process_medium' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/bioconductor-msstatstmt:2.10.0--r43hdfd78af_0' : - 'biocontainers/bioconductor-msstatstmt:2.10.0--r43hdfd78af_0' }" - - input: - path msstatstmt_csv_input - - output: - // The generation of the PDFs from MSstatsTMT are very unstable, especially with auto-contrasts. - // And users can easily fix anything based on the csv and the included script -> make optional - path "*.pdf", optional: true - path "*.csv", emit: msstats_csv - path "*.log" - path "versions.yml" , emit: versions - - script: - def args = task.ext.args ?: '' - ref_con = params.ref_condition ?: "" - - """ - msstats_tmt.R \\ - ${msstatstmt_csv_input} \\ - "${params.contrasts}" \\ - "${ref_con}" \\ - ${params.msstats_remove_one_feat_prot} \\ - ${params.msstatsiso_useunique_peptide} \\ - ${params.msstatsiso_rmpsm_withfewmea_withinrun} \\ - ${params.msstatsiso_summaryformultiple_psm} \\ - ${params.msstatsiso_summarization_method} \\ - ${params.msstatsiso_global_norm} \\ - ${params.msstatsiso_remove_norm_channel} \\ - ${params.msstatsiso_reference_normalization} \\ - ${msstatstmt_csv_input.baseName} \\ - ${params.msstats_threshold} \\ - ${params.msstats_plot_profile_qc} \\ - $args \\ - 2>&1 | tee msstats_tmt.log - - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - r-base: \$(echo \$(R --version 2>&1) | sed 's/^.*R version //; s/ .*\$//') - bioconductor-msstatstmt: \$(Rscript -e "library(MSstatsTMT); cat(as.character(packageVersion('MSstatsTMT')))") - END_VERSIONS - """ -} diff --git a/modules/local/msstats/msstats_tmt/meta.yml b/modules/local/msstats/msstats_tmt/meta.yml deleted file mode 100644 index da1e16fb0..000000000 --- a/modules/local/msstats/msstats_tmt/meta.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: msstats_tmt -description: | - A module to performance proteomics statistical analysis with tandem mass tag (TMT) labeling using MSstatsTMT tool. - - MSstatsTMT - - downStream analysis -tools: - - MSstatsTMT: - description: | - MSstatsTMT is an R-based package for detecting differentially abundant proteins in shotgun mass spectrometry-based proteomic experiments with tandem mass tag (TMT) labeling - homepage: https://github.com/Vitek-Lab/MSstatsTMT - documentation: https://www.bioconductor.org/packages/release/bioc/vignettes/MSstatsTMT/inst/doc/MSstatsTMT.html -input: - - out_msstats: - type: file - description: MSstats input file with analysis results for statistical downstream analysis in MSstatsTMT. - pattern: "out_msstats.csv" -output: - - msstats_csv: - type: file - description: csv file with results of statistical testing - pattern: "*.csv" - - version: - type: file - description: File containing software version - pattern: "versions.yml" - - log: - type: file - description: log file - pattern: "*.log" -authors: - - "@daichengxin" diff --git a/modules/local/openms/comet/main.nf b/modules/local/openms/comet/main.nf index 92bbdd43e..8d96b1f44 100644 --- a/modules/local/openms/comet/main.nf +++ b/modules/local/openms/comet/main.nf @@ -4,14 +4,14 @@ process COMET { label 'openms' container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2025.04.14' : - 'ghcr.io/bigbio/openms-tools-thirdparty:2025.04.14' }" + 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2026.06.06' : + 'ghcr.io/bigbio/openms-tools-thirdparty:2026.06.06' }" input: tuple val(meta), path(mzml_file), path(database) output: - tuple val(meta), path("${mzml_file.baseName}_comet.idXML"), emit: id_files_comet + tuple val(meta), path("${mzml_file.baseName}_comet.idparquet"), emit: id_files_comet path "versions.yml", emit: versions path "*.log", emit: log @@ -48,11 +48,9 @@ process COMET { def isoSlashComet = "0/1" if (params.isotope_error_range) { def isoRangeComet = params.isotope_error_range.split(",") - isoSlashComet = "" - for (c in isoRangeComet[0].toInteger()..isoRangeComet[1].toInteger()-1) { - isoSlashComet += c + "/" - } - isoSlashComet += isoRangeComet[1] + def range = (isoRangeComet[0].toInteger()..isoRangeComet[1].toInteger()-1).collect { v -> v.toString() } + range.add(isoRangeComet[1]) + isoSlashComet = range.join("/") } // for consensusID the cutting rules need to be the same. So we adapt to the loosest rules from MSGF // TODO find another solution. In ProteomicsLFQ we re-run PeptideIndexer (remove??) and if we @@ -84,7 +82,7 @@ process COMET { """ CometAdapter \\ -in ${mzml_file} \\ - -out ${mzml_file.baseName}_comet.idXML \\ + -out ${mzml_file.baseName}_comet.idparquet \\ -threads $task.cpus \\ -database "${database}" \\ -instrument ${inst} \\ @@ -96,8 +94,8 @@ process COMET { -enzyme "${enzyme}" \\ -isotope_error ${isoSlashComet} \\ -precursor_charge $params.min_precursor_charge:$params.max_precursor_charge \\ - -fixed_modifications ${meta.fixedmodifications.tokenize(',').collect { "'$it'" }.join(" ") } \\ - -variable_modifications ${meta.variablemodifications.tokenize(',').collect { "'$it'" }.join(" ") } \\ + -fixed_modifications ${meta.fixedmodifications.tokenize(',').collect { mod -> "'$mod'" }.join(" ") } \\ + -variable_modifications ${meta.variablemodifications.tokenize(',').collect { mod -> "'$mod'" }.join(" ") } \\ -max_variable_mods_in_peptide $params.max_mods \\ -precursor_mass_tolerance $meta.precursormasstolerance \\ -precursor_error_units $meta.precursormasstoleranceunit \\ @@ -115,7 +113,7 @@ process COMET { cat <<-END_VERSIONS > versions.yml "${task.process}": CometAdapter: \$(CometAdapter 2>&1 | grep -E '^Version(.*)' | sed 's/Version: //g' | cut -d ' ' -f 1) - Comet: \$(comet 2>&1 | grep -E "Comet version.*" | sed 's/ Comet version //g' | sed 's/"//g') + Comet: \$(/opt/OpenMS/thirdparty/Comet/comet.exe 2>&1 | grep -m1 -E "^[[:space:]]*Comet version.*" | sed 's/^[[:space:]]*Comet version //g' | sed 's/"//g') END_VERSIONS """ } diff --git a/modules/local/openms/comet/meta.yml b/modules/local/openms/comet/meta.yml index 5f255f4f9..a36a020c2 100644 --- a/modules/local/openms/comet/meta.yml +++ b/modules/local/openms/comet/meta.yml @@ -29,7 +29,7 @@ output: - id_files_comet: type: file description: Output file - pattern: "*.idXML" + pattern: "*.idparquet" - log: type: file description: log file diff --git a/modules/local/openms/consensusid/main.nf b/modules/local/openms/consensusid/main.nf deleted file mode 100644 index 76346fb21..000000000 --- a/modules/local/openms/consensusid/main.nf +++ /dev/null @@ -1,40 +0,0 @@ -process CONSENSUSID { - tag "$meta.mzml_id" - label 'process_single' - label 'openms' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2025.04.14' : - 'ghcr.io/bigbio/openms-tools-thirdparty:2025.04.14' }" - - input: - tuple val(meta), path(id_file) - - output: - tuple val(meta), path("${meta.mzml_id}_consensus.idXML"), emit: consensusids - path "versions.yml", emit: versions - path "*.log", emit: log - - script: - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.mzml_id}" - - """ - ConsensusID \\ - -in ${id_file} \\ - -out ${meta.mzml_id}_consensus.idXML \\ - -per_spectrum \\ - -threads $task.cpus \\ - -algorithm $params.consensusid_algorithm \\ - -filter:min_support $params.min_consensus_support \\ - -filter:considered_hits $params.consensusid_considered_top_hits \\ - -debug $params.consensusid_debug \\ - $args \\ - 2>&1 | tee ${meta.mzml_id}_consensusID.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - ConsensusID: \$(ConsensusID 2>&1 | grep -E '^Version(.*)' | sed 's/Version: //g' | cut -d ' ' -f 1) - END_VERSIONS - """ -} diff --git a/modules/local/openms/consensusid/meta.yml b/modules/local/openms/consensusid/meta.yml deleted file mode 100644 index c8a7df5a0..000000000 --- a/modules/local/openms/consensusid/meta.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: consensusid -description: Computes a consensus from results of multiple peptide identification engines. -keywords: - - consensus scoring - - peptide database search - - OpenMS -tools: - - ConsensusID: - description: | - Tool to Computes a consensus from results of multiple peptide identification engines. - homepage: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_ConsensusID.html - documentation: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_ConsensusID.html -input: - - meta: - type: map - description: Groovy Map containing sample information - - id_file: - type: file - description: | - Putative peptide-spectrum matches in idXML format (potentially multiple per spectrum). Score needs to be comparable (e.g. probability) - pattern: "*.idXML" -output: - - meta: - type: map - description: Groovy Map containing sample information - - id_files_idx_ForIDPEP_FDR: - type: file - description: | - Identifications with annotated FDR. - pattern: "*.idXML" - - log: - type: file - description: log file - pattern: "*.log" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" diff --git a/modules/local/openms/false_discovery_rate/main.nf b/modules/local/openms/false_discovery_rate/main.nf deleted file mode 100644 index f0cf7e2e4..000000000 --- a/modules/local/openms/false_discovery_rate/main.nf +++ /dev/null @@ -1,39 +0,0 @@ -process FALSE_DISCOVERY_RATE { - tag "$meta.mzml_id" - label 'process_low' - label 'process_single' - label 'openms' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2025.04.14' : - 'ghcr.io/bigbio/openms-tools-thirdparty:2025.04.14' }" - - input: - tuple val(meta), path(id_file) - - output: - tuple val(meta), path("${id_file.baseName}_fdr.idXML"), emit: id_files_idx_ForIDPEP_FDR - path "versions.yml", emit: versions - path "*.log", emit: log - - script: - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.mzml_id}" - - """ - FalseDiscoveryRate \\ - -in ${id_file} \\ - -out ${id_file.baseName}_fdr.idXML \\ - -threads $task.cpus \\ - -FDR:PSM ${params.run_fdr_cutoff} \\ - -algorithm:add_decoy_peptides \\ - -algorithm:add_decoy_proteins \\ - $args \\ - 2>&1 | tee ${id_file.baseName}_fdr.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - FalseDiscoveryRate: \$(FalseDiscoveryRate 2>&1 | grep -E '^Version(.*)' | sed 's/Version: //g' | cut -d ' ' -f 1) - END_VERSIONS - """ -} diff --git a/modules/local/openms/false_discovery_rate/meta.yml b/modules/local/openms/false_discovery_rate/meta.yml deleted file mode 100644 index 62fa100fc..000000000 --- a/modules/local/openms/false_discovery_rate/meta.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: false_discovery_rate -description: Estimates the false discovery rate on peptide and protein level using decoy searches. -keywords: - - FDR - - decoy - - OpenMS -tools: - - FalseDiscoveryRate: - description: | - Tool to estimate the false discovery rate on peptide and protein level. - homepage: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_FalseDiscoveryRate.html - documentation: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_FalseDiscoveryRate.html -input: - - meta: - type: map - description: Groovy Map containing sample information - - id_file: - type: file - description: | - Identifications from searching a target-decoy database. - pattern: "*.idXML" -output: - - meta: - type: map - description: Groovy Map containing sample information - - id_files_idx_ForIDPEP_FDR: - type: file - description: | - Identifications with annotated FDR. - pattern: "*.idXML" - - log: - type: file - description: log file - pattern: "*.log" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" diff --git a/modules/local/openms/generate_decoy_database/main.nf b/modules/local/openms/generate_decoy_database/main.nf index 23c766193..5ed2d7dd3 100644 --- a/modules/local/openms/generate_decoy_database/main.nf +++ b/modules/local/openms/generate_decoy_database/main.nf @@ -3,8 +3,8 @@ process GENERATE_DECOY_DATABASE { label 'openms' container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2025.04.14' : - 'ghcr.io/bigbio/openms-tools-thirdparty:2025.04.14' }" + 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2026.06.06' : + 'ghcr.io/bigbio/openms-tools-thirdparty:2026.06.06' }" input: path(db_for_decoy) diff --git a/modules/local/openms/id_conflict_resolver/main.nf b/modules/local/openms/id_conflict_resolver/main.nf deleted file mode 100644 index d9b135afc..000000000 --- a/modules/local/openms/id_conflict_resolver/main.nf +++ /dev/null @@ -1,33 +0,0 @@ -process ID_CONFLICT_RESOLVER { - label 'process_low' - label 'openms' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2025.04.14' : - 'ghcr.io/bigbio/openms-tools-thirdparty:2025.04.14' }" - - input: - path consus_file - - output: - path "${consus_file.baseName}_resconf.consensusXML", emit: pro_resconf - path "versions.yml", emit: versions - path "*.log", emit: log - - script: - def args = task.ext.args ?: '' - - """ - IDConflictResolver \\ - -in ${consus_file} \\ - -threads $task.cpus \\ - -out ${consus_file.baseName}_resconf.consensusXML \\ - $args \\ - 2>&1 | tee ${consus_file.baseName}_resconf.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - IDConflictResolver: \$(IDConflictResolver 2>&1 | grep -E '^Version(.*)' | sed 's/Version: //g' | cut -d ' ' -f 1) - END_VERSIONS - """ -} diff --git a/modules/local/openms/id_conflict_resolver/meta.yml b/modules/local/openms/id_conflict_resolver/meta.yml deleted file mode 100644 index 62db48b4f..000000000 --- a/modules/local/openms/id_conflict_resolver/meta.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: id_conflict_resolver -description: Resolves ambiguous annotations of features with peptide identifications. -keywords: - - ambiguous - - OpenMS -tools: - - IDConflictResolver: - description: | - Resolves ambiguous annotations of features with peptide identifications. - homepage: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_IDConflictResolver.html - documentation: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_IDConflictResolver.html -input: - - consus_file: - type: file - description: | - Input file (data annotated with identifications) - pattern: "*.{featureXML,consensusXML}" -output: - - pro_resconf: - type: file - description: Output file (data with one peptide identification per feature) - - log: - type: file - description: log file - pattern: "*.log" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" diff --git a/modules/local/openms/id_filter/main.nf b/modules/local/openms/id_filter/main.nf deleted file mode 100644 index 3b4a39a86..000000000 --- a/modules/local/openms/id_filter/main.nf +++ /dev/null @@ -1,37 +0,0 @@ -process ID_FILTER { - tag {task.ext.suffix == ".idXML" ? "$meta.mzml_id" : "$id_file.baseName"} - label 'process_very_low' - label 'process_single' - label 'openms' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2025.04.14' : - 'ghcr.io/bigbio/openms-tools-thirdparty:2025.04.14' }" - - input: - tuple val(meta), path(id_file), val(score_type) - - output: - tuple val(meta), path("${id_file.baseName}_filter$task.ext.suffix"), emit: id_filtered - path "versions.yml", emit: versions - path "*.log", emit: log - - script: - def args = task.ext.args ?: '' - def suffix = task.ext.suffix - - """ - IDFilter \\ - -in ${id_file} \\ - -out ${id_file.baseName}_filter$suffix \\ - -threads $task.cpus \\ - ${score_type} \\ - $args \\ - 2>&1 | tee ${id_file.baseName}_idfilter.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - IDFilter: \$(IDFilter 2>&1 | grep -E '^Version(.*)' | sed 's/Version: //g' | cut -d ' ' -f 1) - END_VERSIONS - """ -} diff --git a/modules/local/openms/id_filter/meta.yml b/modules/local/openms/id_filter/meta.yml deleted file mode 100644 index 48fa43e41..000000000 --- a/modules/local/openms/id_filter/meta.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: id_filter -description: Filters peptide/protein identification results by different criteria. -keywords: - - Filter - - identification - - OpenMS -tools: - - IDFilter: - description: | - Tool to Filters results from protein or peptide identification engines based on different criteria. - homepage: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_IDFilter.html - documentation: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_IDFilter.html -input: - - meta: - type: map - description: Groovy Map containing sample information - - id_file: - type: file - description: Peptide-spectrum matches. - pattern: "*.{idXML,consensusXML}" -output: - - meta: - type: map - description: Groovy Map containing sample information - - id_files_idx_ForIDPEP_FDR: - type: file - description: Output file - pattern: "*.{idXML,consensusXML}" - - log: - type: file - description: log file - pattern: "*.log" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" diff --git a/modules/local/openms/id_mapper/main.nf b/modules/local/openms/id_mapper/main.nf deleted file mode 100644 index 1c88cede2..000000000 --- a/modules/local/openms/id_mapper/main.nf +++ /dev/null @@ -1,36 +0,0 @@ -process ID_MAPPER { - tag "$meta.mzml_id" - label 'process_medium' - label 'openms' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2025.04.14' : - 'ghcr.io/bigbio/openms-tools-thirdparty:2025.04.14' }" - - input: - tuple val(meta), path(id_file), path(map_file) - - output: - path "${id_file.baseName}_map.consensusXML", emit: id_map - path "versions.yml", emit: versions - path "*.log", emit: log - - script: - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.mzml_id}" - - """ - IDMapper \\ - -id ${id_file} \\ - -in ${map_file} \\ - -threads $task.cpus \\ - -out ${id_file.baseName}_map.consensusXML \\ - $args \\ - 2>&1 | tee ${id_file.baseName}_map.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - IDMapper: \$(IDMapper 2>&1 | grep -E '^Version(.*)' | sed 's/Version: //g' | cut -d ' ' -f 1) - END_VERSIONS - """ -} diff --git a/modules/local/openms/id_mapper/meta.yml b/modules/local/openms/id_mapper/meta.yml deleted file mode 100644 index 67e9ed6d3..000000000 --- a/modules/local/openms/id_mapper/meta.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: id_mapper -description: Assigns protein/peptide identifications to features or consensus features. -keywords: - - feature - - identification - - OpenMS -tools: - - IDMapper: - description: | - Assigns protein/peptide identifications to features or consensus features. - homepage: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_IDMapper.html - documentation: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_IDMapper.html -input: - - meta: - type: map - description: Groovy Map containing sample information - - id_file: - type: file - description: | - Identifications file - pattern: "*.{idXML, mzid}" - - map_file: - type: file - description: Feature map/consensus map file - pattern: "*.{featureXML, consensusXML, mzq}" -output: - - id_map: - type: file - description: Output file - pattern: "*.{featureXML, consensusXML, mzq}" - - log: - type: file - description: log file - pattern: "*.log" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" diff --git a/modules/local/openms/id_merger/main.nf b/modules/local/openms/id_merger/main.nf index 8e06d4f82..e58f3f714 100644 --- a/modules/local/openms/id_merger/main.nf +++ b/modules/local/openms/id_merger/main.nf @@ -11,7 +11,7 @@ process ID_MERGER { tuple val(meta), path(id_files), val(groupkey) output: - tuple val(meta), path("*_merged.idXML"), emit: id_merged + tuple val(meta), path("*_merged.idparquet"), emit: id_merged path "versions.yml", emit: versions path "*.log", emit: log @@ -19,29 +19,11 @@ process ID_MERGER { def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${groupkey}" - if (params.ms2features_range == "by_project") { - if (id_files[0].baseName.contains('sage')){ - prefix = "${groupkey}_sage" - } else if (id_files[0].baseName.contains('comet')){ - prefix = "${groupkey}_comet" - } else { - prefix = "${groupkey}_msgf" - } - } else if (params.ms2features_range == "by_sample") { - if (id_files[0].baseName.contains('sage')){ - prefix = "${groupkey}_sage" - } else if (id_files[0].baseName.contains('comet')){ - prefix = "${groupkey}_comet" - } else { - prefix = "${groupkey}_msgf" - } - } - """ IDMerger \\ -in ${id_files.join(' ')} \\ -threads $task.cpus \\ - -out ${prefix}_merged.idXML \\ + -out ${prefix}_merged.idparquet \\ -merge_proteins_add_PSMs \\ $args \\ 2>&1 | tee ${prefix}_merged.log diff --git a/modules/local/openms/id_ripper/main.nf b/modules/local/openms/id_ripper/main.nf deleted file mode 100644 index 65976628a..000000000 --- a/modules/local/openms/id_ripper/main.nf +++ /dev/null @@ -1,51 +0,0 @@ -process ID_RIPPER { - tag "$meta.mzml_id" - label 'process_medium' - label 'openms' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2025.04.14' : - 'ghcr.io/bigbio/openms-tools-thirdparty:2025.04.14' }" - - input: - tuple val(meta), path(id_file) - - output: - val(meta), emit: meta - path("*.idXML"), emit: id_rippers - path "versions.yml", emit: versions - path "*.log", emit: log - - script: - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.mzml_id}" - - if (id_file.baseName.contains('sage')){ - pattern = "_sage_perc.idXML" - } else if (id_file.baseName.contains('comet')){ - pattern = "_comet_perc.idXML" - } else { - pattern = "_msgf_perc.idXML" - } - - """ - IDRipper \\ - -in ${id_file} \\ - -threads $task.cpus \\ - -out ./ \\ - -split_ident_runs \\ - $args \\ - 2>&1 | tee ${prefix}_idripper.log - - for i in `ls | grep -v \"_perc.idXML\$\" | grep \".idXML\$\"` - do - mv \$i `ls \"\$i\" |awk -F \".\" \'{print \$1\"${pattern}\"}\'` - done - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - IDRipper: \$(IDRipper 2>&1 | grep -E '^Version(.*)' | sed 's/Version: //g' | cut -d ' ' -f 1) - END_VERSIONS - """ -} -// diff --git a/modules/local/openms/id_ripper/meta.yml b/modules/local/openms/id_ripper/meta.yml deleted file mode 100644 index a543bd39a..000000000 --- a/modules/local/openms/id_ripper/meta.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: id_ripper -description: Splits the protein/peptide identifications of an idXML file into several idXML files according their annotated file origin. -keywords: - - split - - idXML - - OpenMS -tools: - - IDMerger: - description: | - IDRipper splits the protein/peptide identifications of an idXML file into several idXML files according their annotated file origin. - homepage: https://www.openms.org/documentation/html/TOPP_IDRipper.html - documentation: https://www.openms.org/documentation/html/TOPP_IDRipper.html -input: - - id_file: - type: file - description: | - Input file, in which the protein/peptide identifications must be tagged with 'file_origin' - pattern: "*.{idXML}" -output: - - id_rippers: - type: file - description: Output split files - pattern: "*.{idXML}" - - log: - type: file - description: log file - pattern: "*.log" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" diff --git a/modules/local/openms/id_score_switcher/main.nf b/modules/local/openms/id_score_switcher/main.nf deleted file mode 100644 index bedd9fd71..000000000 --- a/modules/local/openms/id_score_switcher/main.nf +++ /dev/null @@ -1,37 +0,0 @@ -process ID_SCORE_SWITCHER { - tag "$meta.mzml_id" - label 'process_very_low' - label 'process_single' - label 'openms' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2025.04.14' : - 'ghcr.io/bigbio/openms-tools-thirdparty:2025.04.14' }" - - input: - tuple val(meta), path(id_file), val(new_score) - - output: - tuple val(meta), path("${id_file.baseName}_pep.idXML"), emit: id_score_switcher - path "versions.yml", emit: versions - path "*.log", emit: log - - script: - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.mzml_id}" - - """ - IDScoreSwitcher \\ - -in ${id_file} \\ - -out ${id_file.baseName}_pep.idXML \\ - -threads $task.cpus \\ - -new_score ${new_score} \\ - $args \\ - 2>&1 | tee ${id_file.baseName}_switch.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - IDScoreSwitcher: \$(IDScoreSwitcher 2>&1 | grep -E '^Version(.*)' | sed 's/Version: //g' | cut -d ' ' -f 1) - END_VERSIONS - """ -} diff --git a/modules/local/openms/id_score_switcher/meta.yml b/modules/local/openms/id_score_switcher/meta.yml deleted file mode 100644 index 246d603b7..000000000 --- a/modules/local/openms/id_score_switcher/meta.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: id_score_switcher -description: Switches between different scores of peptide hits (PSMs) or protein hits in identification data. -keywords: - - Switches - - Score - - OpenMS -tools: - - IDScoreSwitcher: - description: | - Switches between different scores of peptide or protein hits in identification data. - homepage: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/UTILS_IDScoreSwitcher.html - documentation: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/UTILS_IDScoreSwitcher.html -input: - - meta: - type: map - description: Groovy Map containing sample information - - id_file: - type: file - description: | - Identifications from searching a target-decoy database. - pattern: "*.idXML" -output: - - meta: - type: map - description: Groovy Map containing sample information - - id_score_switcher: - type: file - description: | - Identifications file - - log: - type: file - description: log file - pattern: "*.log" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" diff --git a/modules/local/openms/index_peptides/main.nf b/modules/local/openms/index_peptides/main.nf index e0628abb9..6849853e6 100644 --- a/modules/local/openms/index_peptides/main.nf +++ b/modules/local/openms/index_peptides/main.nf @@ -12,7 +12,7 @@ process INDEX_PEPTIDES { output: - tuple val(meta), path("${id_file.baseName}_idx.idXML"), emit: id_files_idx + tuple val(meta), path("${id_file.baseName}_idx.idparquet"), emit: id_files_idx path "versions.yml", emit: versions path "*.log", emit: log @@ -45,7 +45,7 @@ process INDEX_PEPTIDES { """ PeptideIndexer \\ -in ${id_file} \\ - -out ${id_file.baseName}_idx.idXML \\ + -out ${id_file.baseName}_idx.idparquet \\ -threads $task.cpus \\ -fasta ${database} \\ -enzyme:name "${enzyme}" \\ diff --git a/modules/local/openms/index_peptides/meta.yml b/modules/local/openms/index_peptides/meta.yml index eb937b22d..2a784d7ff 100644 --- a/modules/local/openms/index_peptides/meta.yml +++ b/modules/local/openms/index_peptides/meta.yml @@ -18,7 +18,7 @@ input: type: file description: | Input idXML file containing the identifications. - pattern: "*.idXML" + pattern: "*.idparquet" - database: type: file description: | @@ -32,7 +32,7 @@ output: type: file description: | Output idXML file. - pattern: "*.idXML" + pattern: "*.idparquet" - log: type: file description: log file diff --git a/modules/local/openms/isobaric_analyzer/main.nf b/modules/local/openms/isobaric_analyzer/main.nf deleted file mode 100644 index 7fb54abef..000000000 --- a/modules/local/openms/isobaric_analyzer/main.nf +++ /dev/null @@ -1,79 +0,0 @@ -process ISOBARIC_ANALYZER { - tag "$meta.mzml_id" - label 'process_medium' - label 'openms' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2025.04.14' : - 'ghcr.io/bigbio/openms-tools-thirdparty:2025.04.14' }" - - input: - tuple val(meta), path(mzml_file) - - output: - tuple val(meta), path("${mzml_file.baseName}_iso.consensusXML"), emit: id_files_consensusXML - path "versions.yml", emit: versions - path "*.log", emit: log - - script: - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.mzml_id}" - - if (params.quant_activation_method == "HCD" || params.quant_activation_method == "HCID") diss_meth = "auto" - else if (params.quant_activation_method == "CID") diss_meth = "Collision-induced dissociation" - else if (params.quant_activation_method == "ETD") diss_meth = "Electron transfer dissociation" - else if (params.quant_activation_method == "ECD") diss_meth = "Electron capture dissociation" - - def iso_normalization = params.iso_normalization ? "-quantification:normalization" : "" - def isotope_correction = params.isotope_correction ? "-quantification:isotope_correction true" : "-quantification:isotope_correction false" - - // Check for isotope correction and load the correction matrix - if (params.isotope_correction) { - if (params.plex_corr_matrix_file == null) { - error("plex_corr_matrix_file is required when isotope_correction is enabled") - } - - // Read the matrix file and format it into the command-line format - // Read the matrix file, skipping lines that start with '#' and process the matrix - def matrix_lines = new File(params.plex_corr_matrix_file).readLines() - .findAll { !it.startsWith('#') && it.trim() } // Skip lines starting with '#' and empty lines - .drop(1) // Assuming the first non-comment line is a header - .collect { line -> - def values = line.split('/') - // Handle different labelling types - if (meta.labelling_type == 'tmt18plex' || meta.labelling_type == 'tmt16plex') { - return "\"${values[1]}/${values[2]}/${values[3]}/${values[4]}/${values[5]}/${values[6]}/${values[7]}/${values[8]}\"" - } else { - return "\"${values[1]}/${values[2]}/${values[3]}/${values[4]}\"" - } - } - - // Join the matrix lines into a format for the C++ tool - def correction_matrix = matrix_lines.join(" ") - - isotope_correction += " -${meta.labelling_type}:correction_matrix ${correction_matrix}" - } - - """ - IsobaricAnalyzer \\ - -type ${meta.labelling_type} \\ - -in ${mzml_file} \\ - -threads ${task.cpus} \\ - -extraction:select_activation "${diss_meth}" \\ - -extraction:reporter_mass_shift ${params.reporter_mass_shift} \\ - -extraction:min_reporter_intensity ${params.min_reporter_intensity} \\ - -extraction:min_precursor_purity ${params.min_precursor_purity} \\ - -extraction:precursor_isotope_deviation ${params.precursor_isotope_deviation} \\ - ${iso_normalization} \\ - -${meta.labelling_type}:reference_channel ${params.reference_channel} \\ - ${isotope_correction} \\ - -out ${mzml_file.baseName}_iso.consensusXML \\ - ${args} \\ - 2>&1 | tee ${mzml_file.baseName}_isob.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - IsobaricAnalyzer: \$(IsobaricAnalyzer --version 2>&1 | grep -E '^Version(.*)' | sed 's/Version: //g' | cut -d ' ' -f 1) - END_VERSIONS - """ -} diff --git a/modules/local/openms/isobaric_analyzer/meta.yml b/modules/local/openms/isobaric_analyzer/meta.yml deleted file mode 100644 index faf4c4ae2..000000000 --- a/modules/local/openms/isobaric_analyzer/meta.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: isobaric_analyzer -description: Extracts and normalizes isobaric labeling information from an LC-MS/MS experiment. -keywords: - - peak - - OpenMS -tools: - - IsobaricAnalyzer: - description: | - Extracts and normalizes isobaric labeling information from an LC-MS/MS experiment. - homepage: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_IsobaricAnalyzer.html - documentation: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_IsobaricAnalyzer.html -input: - - meta: - type: map - description: Groovy Map containing sample information - - mzml_file: - type: file - description: Input profile data file. - pattern: "*.mzML" -output: - - meta: - type: map - description: Groovy Map containing sample information - - iso_consensusXML: - type: file - description: Output consensusXML file with quantitative information - pattern: "*.consensusXML" - - log: - type: file - description: log file - pattern: "*.log" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" diff --git a/modules/local/openms/isobaric_workflow/main.nf b/modules/local/openms/isobaric_workflow/main.nf new file mode 100644 index 000000000..10e741c1e --- /dev/null +++ b/modules/local/openms/isobaric_workflow/main.nf @@ -0,0 +1,71 @@ +process ISOBARIC_WORKFLOW { + tag "${expdes.baseName}" + label 'process_high' + label 'openms' + + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2026.06.06' : + 'ghcr.io/bigbio/openms-tools-thirdparty:2026.06.06' }" + + input: + val(labelling_type) + path(mzmls) + path(id_files) + path(expdes) + + output: + path "${expdes.baseName}_openms.mzTab", emit: out_mztab + path "${expdes.baseName}_openms.consensusXML", emit: out_consensusXML + path "${expdes.baseName}_qpx", emit: out_qpx + path "*.log", emit: log + path "versions.yml", emit: versions + + script: + def args = task.ext.args ?: '' + + // Build isotope correction matrix argument if enabled + def isotope_correction = "" + if (params.isotope_correction && params.plex_corr_matrix_file != null) { + def matrix_lines = new File(params.plex_corr_matrix_file).readLines() + .findAll { !it.startsWith('#') && it.trim() } + .drop(1) + .collect { line -> + def values = line.split('/') + if (labelling_type == 'tmt18plex' || labelling_type == 'tmt16plex') { + return "\"${values[1]}/${values[2]}/${values[3]}/${values[4]}/${values[5]}/${values[6]}/${values[7]}/${values[8]}\"" + } else { + return "\"${values[1]}/${values[2]}/${values[3]}/${values[4]}\"" + } + } + def correction_matrix = matrix_lines.join(" ") + isotope_correction = "-quantification:isotope_correction true -${labelling_type}:correction_matrix ${correction_matrix}" + } + + """ + IsobaricWorkflow \\ + -threads ${task.cpus} \\ + -in ${mzmls.join(' ')} \\ + -in_id ${id_files.join(' ')} \\ + -exp_design ${expdes} \\ + -type ${labelling_type} \\ + -inference_method ${params.protein_inference_method} \\ + -protein_quantification ${params.protein_quant} \\ + -psmFDR ${params.psm_level_fdr_cutoff} \\ + -proteinFDR ${params.protein_level_fdr_cutoff} \\ + -picked_fdr ${params.picked_fdr} \\ + -picked_decoy_string ${params.decoy_string} \\ + -extraction:min_precursor_purity ${params.min_precursor_purity} \\ + -extraction:precursor_isotope_deviation ${params.precursor_isotope_deviation} \\ + -extraction:min_reporter_intensity ${params.min_reporter_intensity} \\ + ${isotope_correction} \\ + -out ${expdes.baseName}_openms.consensusXML \\ + -out_mzTab ${expdes.baseName}_openms.mzTab \\ + -out_qpx ${expdes.baseName}_qpx \\ + $args \\ + 2>&1 | tee isobaricworkflow.log + cat <<-END_VERSIONS > versions.yml + "${task.process}": + IsobaricWorkflow: \$(IsobaricWorkflow 2>&1 | grep -E '^Version(.*)' | sed 's/Version: //g' | cut -d ' ' -f 1) + END_VERSIONS + """ +} diff --git a/modules/local/openms/isobaric_workflow/meta.yml b/modules/local/openms/isobaric_workflow/meta.yml new file mode 100644 index 000000000..448eb2ef8 --- /dev/null +++ b/modules/local/openms/isobaric_workflow/meta.yml @@ -0,0 +1,43 @@ +name: isobaric_workflow +description: Extracts and normalizes isobaric labeling information from an LC-MS/MS experiment. +keywords: + - OpenMS + - quantification +tools: + - IsobaricWorkflow: + description: | + Extracts and normalizes isobaric labeling information from an LC-MS/MS experiment. + homepage: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/release/latest/html/TOPP_IsobaricWorkflow.html + documentation: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/release/latest/html/TOPP_IsobaricWorkflow.html +input: + - mzmls: + type: file + description: Input Spectra in mzML format + pattern: "*.mzML" + - id_files: + type: file + description: Identifications in idparquet or mzIdentML format with posterior error probabilities as score type. + pattern: "*.idparquet" + - expdes: + type: file + description: An experimental design file + pattern: "*.tsv" +output: + - out_mztab: + type: file + description: mzTab file with analysis results + pattern: "*.mzTab" + - out_consensusXML: + type: file + description: ConsensusXML file for visualization and further processing in OpenMS. + pattern: "*.consensusXML" + - log: + type: file + description: log file + pattern: "*.log" + - version: + type: file + description: File containing software version + pattern: "versions.yml" +authors: + - "@MaLLLiYA" diff --git a/modules/local/openms/luciphor/main.nf b/modules/local/openms/luciphor/main.nf deleted file mode 100644 index cf7d5f819..000000000 --- a/modules/local/openms/luciphor/main.nf +++ /dev/null @@ -1,59 +0,0 @@ -process LUCIPHOR { - tag "$meta.mzml_id" - label 'process_medium' - label 'openms' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2025.04.14' : - 'ghcr.io/bigbio/openms-tools-thirdparty:2025.04.14' }" - - input: - tuple val(meta), path(mzml_file), path(id_file) - - - output: - tuple val(meta), path("${id_file.baseName}_luciphor.idXML"), emit: ptm_in_id_luciphor - path "versions.yml", emit: versions - path "*.log", emit: log - - script: - // The OpenMS adapters need the actual jar file, not the executable/shell wrapper that (bio)conda creates - luciphor_jar = '' - if ((workflow.containerEngine || (task.executor == "awsbatch")) && (task.container.indexOf("biocontainers") > -1 || task.container.indexOf("depot.galaxyproject.org") > -1)) { - luciphor_jar = "-executable \$(find /usr/local/share/luciphor2-*/luciphor2.jar -maxdepth 0)" - } else if (session.config.conda && session.config.conda.enabled) { - luciphor_jar = "-executable \$(find \$CONDA_PREFIX/share/luciphor2-*/luciphor2.jar -maxdepth 0)" - } - - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.mzml_id}" - - def losses = params.luciphor_neutral_losses ? "-neutral_losses ${params.luciphor_neutral_losses}" : "" - def dec_mass = params.luciphor_decoy_mass ? "-decoy_mass ${params.luciphor_decoy_mass}" : "" - def dec_losses = params.luciphor_decoy_neutral_losses ? "-decoy_neutral_losses ${params.luciphor_decoy_neutral_losses}" : "" - - """ - LuciphorAdapter \\ - -id ${id_file} \\ - -in ${mzml_file} \\ - ${luciphor_jar} \\ - -out ${id_file.baseName}_luciphor.idXML \\ - -threads $task.cpus \\ - -num_threads $task.cpus \\ - -target_modifications ${params.mod_localization.tokenize(',').collect { "'${it}'" }.join(" ") } \\ - -fragment_method $meta.dissociationmethod \\ - ${losses} \\ - ${dec_mass} \\ - ${dec_losses} \\ - -max_charge_state $params.max_precursor_charge \\ - -max_peptide_length $params.max_peptide_length \\ - $args \\ - 2>&1 | tee ${id_file.baseName}_luciphor.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - LuciphorAdapter: \$(LuciphorAdapter 2>&1 | grep -E '^Version(.*)' | sed 's/Version: //g' | cut -d ' ' -f 1) - Luciphor: \$(luciphor2 2>&1 | grep -E '^Version(.*)' | sed 's/Version: //g') - END_VERSIONS - """ -} diff --git a/modules/local/openms/luciphor/meta.yml b/modules/local/openms/luciphor/meta.yml deleted file mode 100644 index 72df3fc6d..000000000 --- a/modules/local/openms/luciphor/meta.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: luciphor -description: Modification site localisation using LuciPHOr2. -keywords: - - LuciPHOr2 - - modification - - OpenMS -tools: - - LuciphorAdapter: - description: | - Calculates scores for the localization of variable modifications. - homepage: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_LuciphorAdapter.html - documentation: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_LuciphorAdapter.html -input: - - meta: - type: map - description: Groovy Map containing sample information - - mzml_file: - type: file - description: Input spectrum file. - pattern: "*.mzML" - - id_file: - type: file - description: Protein/peptide identifications file - pattern: "*.idXML" -output: - - meta: - type: map - description: Groovy Map containing sample information - - out_id_ptmscores: - type: file - description: Protein/peptide identifications file. With scored potential modification sites - pattern: "*.idXML" - - log: - type: file - description: log file - pattern: "*.log" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" diff --git a/modules/local/openms/msgf/main.nf b/modules/local/openms/msgf/main.nf index 940113f50..1c81e247d 100644 --- a/modules/local/openms/msgf/main.nf +++ b/modules/local/openms/msgf/main.nf @@ -4,14 +4,14 @@ process MSGF { label 'openms' container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2025.04.14' : - 'ghcr.io/bigbio/openms-tools-thirdparty:2025.04.14' }" + 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2026.06.06' : + 'ghcr.io/bigbio/openms-tools-thirdparty:2026.06.06' }" input: tuple val(meta), path(mzml_file), path(database), path(cnlcp), path(canno), path(csarr), path(cseq) output: - tuple val(meta), path("${mzml_file.baseName}_msgf.idXML"), emit: id_files_msgf + tuple val(meta), path("${mzml_file.baseName}_msgf.idparquet"), emit: id_files_msgf path "versions.yml", emit: versions path "*.log", emit: log @@ -20,7 +20,7 @@ process MSGF { msgf_jar = '' if ((workflow.containerEngine || (task.executor == "awsbatch")) && (task.container.indexOf("biocontainers") > -1 || task.container.indexOf("depot.galaxyproject.org") > -1)) { msgf_jar = "-executable \$(find /usr/local/share/msgf_plus-*/MSGFPlus.jar -maxdepth 0)" - } else if (session.config.conda && session.config.conda.enabled) { + } else if (System.getenv('CONDA_PREFIX')) { msgf_jar = "-executable \$(find \$CONDA_PREFIX/share/msgf_plus-*/MSGFPlus.jar -maxdepth 0)" } @@ -65,7 +65,7 @@ process MSGF { MSGFPlusAdapter \\ -protocol $params.protocol \\ -in ${mzml_file} \\ - -out ${mzml_file.baseName}_msgf.idXML \\ + -out ${mzml_file.baseName}_msgf.idparquet \\ ${msgf_jar} \\ -threads $task.cpus \\ -java_memory ${task.memory.toMega()} \\ @@ -83,8 +83,8 @@ process MSGF { -tryptic ${msgf_num_enzyme_termini} \\ -precursor_mass_tolerance $meta.precursormasstolerance \\ -precursor_error_units $meta.precursormasstoleranceunit \\ - -fixed_modifications ${meta.fixedmodifications.tokenize(',').collect() { "'${it}'" }.join(" ") } \\ - -variable_modifications ${meta.variablemodifications.tokenize(',').collect() { "'${it}'" }.join(" ") } \\ + -fixed_modifications ${meta.fixedmodifications.tokenize(',').collect { mod -> "'${mod}'" }.join(" ") } \\ + -variable_modifications ${meta.variablemodifications.tokenize(',').collect { mod -> "'${mod}'" }.join(" ") } \\ -max_mods $params.max_mods \\ ${il_equiv} \\ -PeptideIndexing:unmatched_action ${params.unmatched_action} \\ diff --git a/modules/local/openms/msgf/meta.yml b/modules/local/openms/msgf/meta.yml index 8c7c8690b..d8fe9bce1 100644 --- a/modules/local/openms/msgf/meta.yml +++ b/modules/local/openms/msgf/meta.yml @@ -29,7 +29,7 @@ output: - id_files_msgf: type: file description: Output file - pattern: "*.idXML" + pattern: "*.idparquet" - log: type: file description: log file diff --git a/modules/local/openms/msstats_converter/main.nf b/modules/local/openms/msstats_converter/main.nf index 9d3045524..4bb2a356b 100644 --- a/modules/local/openms/msstats_converter/main.nf +++ b/modules/local/openms/msstats_converter/main.nf @@ -4,8 +4,8 @@ process MSSTATS_CONVERTER { label 'openms' container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2025.04.14' : - 'ghcr.io/bigbio/openms-tools-thirdparty:2025.04.14' }" + 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2026.06.06' : + 'ghcr.io/bigbio/openms-tools-thirdparty:2026.06.06' }" input: path consensusXML diff --git a/modules/local/openms/mzml_indexing/main.nf b/modules/local/openms/mzml_indexing/main.nf index 5d86fe00a..2883ff06e 100644 --- a/modules/local/openms/mzml_indexing/main.nf +++ b/modules/local/openms/mzml_indexing/main.nf @@ -21,7 +21,9 @@ process MZML_INDEXING { """ mkdir -p out - FileConverter -in ${mzmlfile} -out out/${mzmlfile.baseName}.mzML 2>&1 | tee ${mzmlfile.baseName}_mzmlindexing.log + FileConverter -in ${mzmlfile} -out out/${mzmlfile.baseName}.mzML \\ + ${args} \\ + 2>&1 | tee ${mzmlfile.baseName}_mzmlindexing.log cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/openms/openms_peak_picker/main.nf b/modules/local/openms/openms_peak_picker/main.nf index 06d965e1e..61999b179 100644 --- a/modules/local/openms/openms_peak_picker/main.nf +++ b/modules/local/openms/openms_peak_picker/main.nf @@ -19,7 +19,7 @@ process OPENMS_PEAK_PICKER { def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.mzml_id}" - in_mem = params.peakpicking_inmemory ? "inmermory" : "lowmemory" + in_mem = params.peakpicking_inmemory ? "inmemory" : "lowmemory" lvls = params.peakpicking_ms_levels ? "-algorithm:ms_levels ${params.peakpicking_ms_levels}" : "" """ diff --git a/modules/local/openms/percolator/main.nf b/modules/local/openms/percolator/main.nf index 57fd1d44c..6610d98b1 100644 --- a/modules/local/openms/percolator/main.nf +++ b/modules/local/openms/percolator/main.nf @@ -4,14 +4,14 @@ process PERCOLATOR { label 'openms' container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2025.04.14' : - 'ghcr.io/bigbio/openms-tools-thirdparty:2025.04.14' }" + 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2026.06.06' : + 'ghcr.io/bigbio/openms-tools-thirdparty:2026.06.06' }" input: tuple val(meta), path(id_file) output: - tuple val(meta), path("*_perc.idXML"), emit: id_files_perc + tuple val(meta), path("*_perc.idparquet"), emit: id_files_perc path "versions.yml", emit: versions path "*.log", emit: log @@ -22,12 +22,13 @@ process PERCOLATOR { """ OMP_NUM_THREADS=$task.cpus PercolatorAdapter \\ -in ${id_file} \\ - -out ${id_file.baseName}_perc.idXML \\ + -out ${id_file.baseName}_perc.idparquet \\ -threads $task.cpus \\ -subset_max_train $params.subset_max_train \\ -decoy_pattern $params.decoy_string \\ -post_processing_tdc \\ -score_type pep \\ + -score:fdr $params.run_fdr_cutoff \\ $args \\ 2>&1 | tee ${id_file.baseName}_percolator.log diff --git a/modules/local/openms/percolator/meta.yml b/modules/local/openms/percolator/meta.yml index b7be826db..aad911da7 100644 --- a/modules/local/openms/percolator/meta.yml +++ b/modules/local/openms/percolator/meta.yml @@ -17,7 +17,7 @@ input: type: file description: | Input idXML file containing the identifications. - pattern: "*.idXML" + pattern: "*.idparquet" output: - meta: type: map diff --git a/modules/local/openms/protein_inference_epifany/main.nf b/modules/local/openms/protein_inference_epifany/main.nf deleted file mode 100644 index ddafba50b..000000000 --- a/modules/local/openms/protein_inference_epifany/main.nf +++ /dev/null @@ -1,39 +0,0 @@ -process PROTEIN_INFERENCE_EPIFANY { - label 'process_medium' - label 'openms' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2025.04.14' : - 'ghcr.io/bigbio/openms-tools-thirdparty:2025.04.14' }" - - input: - tuple val(meta), path(consus_file) - - output: - tuple val(meta), path("${consus_file.baseName}_epi.consensusXML"), emit: epi_inference - path "versions.yml", emit: versions - path "*.log", emit: log - - script: - def args = task.ext.args ?: '' - gg = params.protein_quant == 'shared_peptides' ? 'remove_proteins_wo_evidence' : 'none' - - """ - Epifany \\ - -in ${consus_file} \\ - -protein_fdr true \\ - -threads $task.cpus \\ - -algorithm:keep_best_PSM_only $params.keep_best_PSM_only \\ - -algorithm:update_PSM_probabilities $params.update_PSM_probabilities \\ - -greedy_group_resolution $gg \\ - -algorithm:top_PSMs $params.top_PSMs \\ - -out ${consus_file.baseName}_epi.consensusXML \\ - $args \\ - 2>&1 | tee ${consus_file.baseName}_inference.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - Epifany: \$(Epifany 2>&1 | grep -E '^Version(.*)' | sed 's/Version: //g' | cut -d ' ' -f 1) - END_VERSIONS - """ -} diff --git a/modules/local/openms/protein_inference_epifany/meta.yml b/modules/local/openms/protein_inference_epifany/meta.yml deleted file mode 100644 index 23d09813b..000000000 --- a/modules/local/openms/protein_inference_epifany/meta.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: protein_inference_epifany -description: Runs a Bayesian protein inference. -keywords: - - Bayesian - - inference - - OpenMS -tools: - - Epifany: - description: | - It is a protein inference engine based on a Bayesian network. - homepage: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/UTILS_Epifany.html - documentation: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/UTILS_Epifany.html -input: - - consus_file: - type: file - description: | - identification results. - pattern: "*.{idXML,consensusXML}" -output: - - epi_inference: - type: file - description: | - identification results with scored/grouped proteins. - pattern: "*.{idXML,consensusXML}" - - log: - type: file - description: log file - pattern: "*.log" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" diff --git a/modules/local/openms/protein_inference_generic/main.nf b/modules/local/openms/protein_inference_generic/main.nf deleted file mode 100644 index 8222fb632..000000000 --- a/modules/local/openms/protein_inference_generic/main.nf +++ /dev/null @@ -1,44 +0,0 @@ -process PROTEIN_INFERENCE_GENERIC { - label 'process_medium' - label 'openms' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2025.04.14' : - 'ghcr.io/bigbio/openms-tools-thirdparty:2025.04.14' }" - - input: - tuple val(meta), path(consus_file) - - output: - tuple val(meta), path("${consus_file.baseName}_epi.consensusXML"), emit: protein_inference - path "versions.yml", emit: versions - path "*.log", emit: log - - script: - def args = task.ext.args ?: '' - gg = params.protein_quant == 'shared_peptides' ? '-Algorithm:greedy_group_resolution' : '' - groups = params.protein_quant == 'strictly_unique_peptides' ? 'false' : 'true' - - """ - ProteinInference \\ - -in ${consus_file} \\ - -threads $task.cpus \\ - -picked_fdr $params.picked_fdr \\ - -picked_decoy_string $params.decoy_string \\ - -protein_fdr true \\ - -Algorithm:use_shared_peptides $params.use_shared_peptides \\ - -Algorithm:annotate_indistinguishable_groups $groups \\ - -Algorithm:score_type "PEP" \\ - $gg \\ - -Algorithm:score_aggregation_method $params.protein_score \\ - -Algorithm:min_peptides_per_protein $params.min_peptides_per_protein \\ - -out ${consus_file.baseName}_epi.consensusXML \\ - $args \\ - 2>&1 | tee ${consus_file.baseName}_inference.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - ProteinInference: \$(ProteinInference 2>&1 | grep -E '^Version(.*) ' | sed 's/Version: //g' | cut -d ' ' -f 1) - END_VERSIONS - """ -} diff --git a/modules/local/openms/protein_inference_generic/meta.yml b/modules/local/openms/protein_inference_generic/meta.yml deleted file mode 100644 index 983479342..000000000 --- a/modules/local/openms/protein_inference_generic/meta.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: protein_inference_generic -description: Computes a protein identification score based on an aggregation of scores of identified peptides. -keywords: - - protein - - inference - - OpenMS -tools: - - ProteinInference: - description: | - Computes a protein identification score based on an aggregation of scores of identified peptides. - homepage: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_ProteinInference.html - documentation: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_ProteinInference.html -input: - - consus_file: - type: file - description: | - identification results. - pattern: "*.{idXML,consensusXML}" -output: - - protein_inference: - type: file - description: | - identification results with scored/grouped proteins. - pattern: "*.consensusXML" - - log: - type: file - description: log file - pattern: "*.log" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" diff --git a/modules/local/openms/protein_quantifier/main.nf b/modules/local/openms/protein_quantifier/main.nf deleted file mode 100644 index 5fb585d38..000000000 --- a/modules/local/openms/protein_quantifier/main.nf +++ /dev/null @@ -1,52 +0,0 @@ -process PROTEIN_QUANTIFIER { - tag "${pro_quant_exp.baseName}" - label 'process_medium' - label 'openms' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2025.04.14' : - 'ghcr.io/bigbio/openms-tools-thirdparty:2025.04.14' }" - - input: - path epi_filt_resolve - path pro_quant_exp - - output: - path "*protein_openms.csv", emit: protein_out - path "*peptide_openms.csv", emit: peptide_out - path "*.mzTab", optional: true, emit: out_mztab - path "*.log" - path "versions.yml", emit: versions - - script: - def args = task.ext.args ?: '' - - include_all = params.include_all ? "-top:include_all" : "" - fix_peptides = params.fix_peptides ? "-consensus:fix_peptides" : "" - normalize = params.normalize ? "-consensus:normalize" : "" - export_mztab = params.export_mztab ? "-mztab ${pro_quant_exp.baseName}_openms.mzTab" : "" - - """ - ProteinQuantifier \\ - -method 'top' \\ - -in ${epi_filt_resolve} \\ - -design ${pro_quant_exp} \\ - -out ${pro_quant_exp.baseName}_protein_openms.csv \\ - ${export_mztab} \\ - -peptide_out ${pro_quant_exp.baseName}_peptide_openms.csv \\ - -top:N $params.top \\ - -top:aggregate $params.average \\ - ${include_all} \\ - ${fix_peptides} \\ - -ratios \\ - -threads $task.cpus \\ - ${normalize} \\ - $args \\ - 2>&1 | tee pro_quant.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - ProteinQuantifier: \$(ProteinQuantifier 2>&1 | grep -E '^Version(.*)' | sed 's/Version: //g' | cut -c 1-50) - END_VERSIONS - """ -} diff --git a/modules/local/openms/protein_quantifier/meta.yml b/modules/local/openms/protein_quantifier/meta.yml deleted file mode 100644 index d7f81d4dc..000000000 --- a/modules/local/openms/protein_quantifier/meta.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: protein_quantifier -description: Compute peptide and protein abundances from annotated feature/consensus maps or from identification results. -keywords: - - abundances - - OpenMS -tools: - - ProteinQuantifier: - description: | - Compute peptide and protein abundances from annotated feature/consensus maps or from identification results. - homepage: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_ProteinQuantifier.html - documentation: https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_ProteinQuantifier.html -input: - - epi_filt_resolve: - type: file - description: | - Input file (data annotated with identifications) - pattern: "*.{featureXML,consensusXML,idXML}" -output: - - protein_out: - type: file - description: Output file for protein abundances - pattern: "*protein_openms.csv" - - peptide_out: - type: file - description: Output file for peptide abundances - pattern: "*peptide_openms.csv" - - out_mztab: - type: file - description: Output file (mzTab) - pattern: "*.mzTab" - - log: - type: file - description: log file - pattern: "*.log" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" diff --git a/modules/local/openms/proteomicslfq/main.nf b/modules/local/openms/proteomicslfq/main.nf index 6480649ea..0f142d02d 100644 --- a/modules/local/openms/proteomicslfq/main.nf +++ b/modules/local/openms/proteomicslfq/main.nf @@ -4,8 +4,8 @@ process PROTEOMICSLFQ { label 'openms' container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2025.04.14' : - 'ghcr.io/bigbio/openms-tools-thirdparty:2025.04.14' }" + 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2026.06.06' : + 'ghcr.io/bigbio/openms-tools-thirdparty:2026.06.06' }" input: path(mzmls) @@ -15,23 +15,22 @@ process PROTEOMICSLFQ { output: path "${expdes.baseName}_openms.mzTab", emit: out_mztab + path "${expdes.baseName}_qpx", emit: out_qpx path "${expdes.baseName}_openms.consensusXML", emit: out_consensusXML path "*msstats_in.csv", emit: out_msstats, optional: true - path "*triqler_in.tsv", emit: out_triqler, optional: true - path "debug_mergedIDs.idXML", emit: debug_mergedIDs, optional: true - path "debug_mergedIDs_inference.idXML", emit: debug_mergedIDs_inference, optional: true - path "debug_mergedIDsGreedyResolved.idXML", emit: debug_mergedIDsGreedyResolved, optional: true - path "debug_mergedIDsGreedyResolvedFDR.idXML", emit: debug_mergedIDsGreedyResolvedFDR, optional: true - path "debug_mergedIDsGreedyResolvedFDRFiltered.idXML", emit: debug_mergedIDsGreedyResolvedFDRFiltered, optional: true - path "debug_mergedIDsFDRFilteredStrictlyUniqueResolved.idXML", emit: debug_mergedIDsFDRFilteredStrictlyUniqueResolved, optional: true + path "debug_mergedIDs.idparquet", emit: debug_mergedIDs, optional: true + path "debug_mergedIDs_inference.idparquet", emit: debug_mergedIDs_inference, optional: true + path "debug_mergedIDsGreedyResolved.idparquet", emit: debug_mergedIDsGreedyResolved, optional: true + path "debug_mergedIDsGreedyResolvedFDR.idparquet", emit: debug_mergedIDsGreedyResolvedFDR, optional: true + path "debug_mergedIDsGreedyResolvedFDRFiltered.idparquet", emit: debug_mergedIDsGreedyResolvedFDRFiltered, optional: true + path "debug_mergedIDsFDRFilteredStrictlyUniqueResolved.idparquet", emit: debug_mergedIDsFDRFilteredStrictlyUniqueResolved, optional: true path "*.log", emit: log path "versions.yml", emit: versions script: def args = task.ext.args ?: '' def msstats_present = params.quantification_method == "feature_intensity" ? "-out_msstats ${expdes.baseName}_msstats_in.csv" : "" - def triqler_present = (params.quantification_method == "feature_intensity") && (params.add_triqler_output) ? "-out_triqler ${expdes.baseName}_triqler_in.tsv" : "" - def decoys_present = (params.quantify_decoys || ((params.quantification_method == "feature_intensity") && params.add_triqler_output)) ? '-PeptideQuantification:quantify_decoys' : '' + def decoys_present = params.quantify_decoys ? '-PeptideQuantification:quantify_decoys' : '' def mzml_sorted = mzmls.collect().sort{ a, b -> a.name <=> b.name} def id_sorted = id_files.collect().sort{ a, b -> a.name <=> b.name} def feature_with_id_min_score = "-feature_with_id_min_score ${params.feature_with_id_min_score}" @@ -50,6 +49,7 @@ process PROTEOMICSLFQ { ${feature_with_id_min_score} \\ ${feature_without_id_min_score} \\ -mass_recalibration ${params.mass_recalibration} \\ + -Seeding:algorithm ${params.lfq_seeding_algorithm} \\ -Seeding:intThreshold ${params.lfq_intensity_threshold} \\ -protein_quantification ${params.protein_quant} \\ -alignment_order ${params.alignment_order} \\ @@ -59,8 +59,8 @@ process PROTEOMICSLFQ { -picked_proteinFDR ${params.picked_fdr} \\ -out_cxml ${expdes.baseName}_openms.consensusXML \\ -out ${expdes.baseName}_openms.mzTab \\ + -out_qpx ${expdes.baseName}_qpx \\ ${msstats_present} \\ - ${triqler_present} \\ $args \\ 2>&1 | tee proteomicslfq.log diff --git a/modules/local/openms/proteomicslfq/meta.yml b/modules/local/openms/proteomicslfq/meta.yml index 600bee0cc..7ca500076 100644 --- a/modules/local/openms/proteomicslfq/meta.yml +++ b/modules/local/openms/proteomicslfq/meta.yml @@ -18,7 +18,7 @@ input: - id_files: type: file description: Identifications in idXML or mzIdentML format with posterior error probabilities as score type. - pattern: "*.idXML" + pattern: "*.idparquet" - expdes: type: file description: An experimental design file @@ -40,10 +40,6 @@ output: type: file description: MSstats file with analysis results for statistical downstream analysis in MSstats. pattern: "*msstats_in.csv" - - out_triqler: - type: file - description: Triqler file with analysis results for statistical downstream analysis in Triqler. - pattern: "*triqler_in.csv" - log: type: file description: log file diff --git a/modules/local/openms/sage/main.nf b/modules/local/openms/sage/main.nf index 4b67eee21..ebddb4541 100644 --- a/modules/local/openms/sage/main.nf +++ b/modules/local/openms/sage/main.nf @@ -1,11 +1,11 @@ process SAGE { - tag "${metas.toList().collect{it.mzml_id}}" + tag "${metas.toList().collect{ m -> m.mzml_id }}" label 'process_medium' // we could make it dependent on the number of files label 'openms' container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2025.04.14' : - 'ghcr.io/bigbio/openms-tools-thirdparty:2025.04.14' }" + 'oras://ghcr.io/bigbio/openms-tools-thirdparty-sif:2026.06.06' : + 'ghcr.io/bigbio/openms-tools-thirdparty:2026.06.06' }" input: tuple val(key), val(batch), val(metas), path(mzml_files), path(database) @@ -18,7 +18,7 @@ process SAGE { script: def meta = metas[0] // due to groupTuple they should all be the same (TODO check to use groupBy?) // Make sure that the output order is consistent with the meta ids - meta_order_files = metas.collect{ it.mzml_id.toString() + "*_sage.idXML" } + meta_order_files = metas.collect{ m -> m.mzml_id.toString() + "*_sage.idparquet" } def args = task.ext.args ?: '' enzyme = meta.enzyme outname = mzml_files.size() > 1 ? "out_${batch}" : mzml_files[0].baseName @@ -29,7 +29,7 @@ process SAGE { export SAGE_LOG=trace SageAdapter \\ -in ${mzml_files} \\ - -out ${outname}_sage.idXML \\ + -out ${outname}_sage.idparquet \\ -threads $task.cpus \\ -database "${database}" \\ -decoy_prefix $params.decoy_string \\ @@ -47,8 +47,8 @@ process SAGE { -fragment_tol_left ${-meta.fragmentmasstolerance} \\ -fragment_tol_right ${meta.fragmentmasstolerance} \\ -fragment_tol_unit $meta.fragmentmasstoleranceunit \\ - -fixed_modifications ${meta.fixedmodifications.tokenize(',').collect{ "'${it}'" }.join(" ") } \\ - -variable_modifications ${meta.variablemodifications.tokenize(',').collect{ "'${it}'" }.join(" ") } \\ + -fixed_modifications ${meta.fixedmodifications.tokenize(',').collect{ mod -> "'${mod}'" }.join(" ") } \\ + -variable_modifications ${meta.variablemodifications.tokenize(',').collect{ mod -> "'${mod}'" }.join(" ") } \\ -charges "$params.min_precursor_charge, $params.max_precursor_charge" \\ -min_peaks $params.min_peaks \\ -max_variable_mods $params.max_mods \\ @@ -60,11 +60,11 @@ process SAGE { 2>&1 | tee ${outname}_sage.log if [[ ${mzml_files.size()} -ge 2 ]]; then - IDRipper -in ${outname}_sage.idXML -out . -split_ident_runs - rm ${outname}_sage.idXML - for f in *.idXML + IDRipper -in ${outname}_sage.idparquet -out . -split_ident_runs + rm -r ${outname}_sage.idparquet + for f in *.idparquet do - mv "\$f" "\${f%.*}_sage.idXML" + mv "\$f" "\${f%.*}_sage.idparquet" done fi diff --git a/modules/local/openms/sage/meta.yml b/modules/local/openms/sage/meta.yml index 11eed615a..49690e826 100644 --- a/modules/local/openms/sage/meta.yml +++ b/modules/local/openms/sage/meta.yml @@ -29,7 +29,7 @@ output: - id_files_sage: type: file description: Output file - pattern: "*.idXML" + pattern: "*.idparquet" - log: type: file description: log file diff --git a/modules/local/preprocess_expdesign/main.nf b/modules/local/preprocess_expdesign/main.nf index 1880fd112..c444732a0 100644 --- a/modules/local/preprocess_expdesign/main.nf +++ b/modules/local/preprocess_expdesign/main.nf @@ -7,8 +7,8 @@ process PREPROCESS_EXPDESIGN { label 'process_tiny' container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/quantms-utils:0.0.24--pyh7e72e81_0' : - 'biocontainers/quantms-utils:0.0.24--pyh7e72e81_0' }" + 'https://depot.galaxyproject.org/singularity/quantms-utils:0.0.25--pyh106432d_0' : + 'biocontainers/quantms-utils:0.0.25--pyh106432d_0' }" input: path design diff --git a/modules/local/samplesheet_check/main.nf b/modules/local/samplesheet_check/main.nf index 42cb9b893..97faf1030 100644 --- a/modules/local/samplesheet_check/main.nf +++ b/modules/local/samplesheet_check/main.nf @@ -4,39 +4,51 @@ process SAMPLESHEET_CHECK { label 'process_tiny' container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/quantms-utils:0.0.24--pyh7e72e81_0' : - 'biocontainers/quantms-utils:0.0.24--pyh7e72e81_0' }" + 'https://depot.galaxyproject.org/singularity/quantms-utils:0.0.25--pyh106432d_0' : + 'biocontainers/quantms-utils:0.0.25--pyh106432d_0' }" 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} \\ ${string_skip_experimental_design_validation} \\ - ${string_use_ols_cache_only} 2>&1 | tee input_check.log + ${string_use_ols_cache_only} \\ + $args \\ + 2>&1 | tee input_check.log cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/samplesheet_check/meta.yml b/modules/local/samplesheet_check/meta.yml index 18ec9e783..28ed5e4de 100644 --- a/modules/local/samplesheet_check/meta.yml +++ b/modules/local/samplesheet_check/meta.yml @@ -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 @@ -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 diff --git a/modules/local/utils/decompress_dotd/main.nf b/modules/local/utils/decompress_dotd/main.nf index 9f0696a09..969b9fc7b 100644 --- a/modules/local/utils/decompress_dotd/main.nf +++ b/modules/local/utils/decompress_dotd/main.nf @@ -10,13 +10,13 @@ process DECOMPRESS { stageInMode { if (task.attempt == 1) { - if (executor == 'awsbatch') { + if (task.executor == 'awsbatch') { 'symlink' } else { 'link' } } else if (task.attempt == 2) { - if (executor == 'awsbatch') { + if (task.executor == 'awsbatch') { 'copy' } else { 'symlink' @@ -84,9 +84,20 @@ process DECOMPRESS { echo "Unpacking..." | tee -a ${compressed_file.baseName}_decompression.log extract ${compressed_file} 2>&1 | tee -a ${compressed_file.baseName}_conversion.log - [ -d ${file(compressed_file.baseName).baseName}.d ] && \\ - echo "Found ${file(compressed_file.baseName).baseName}.d" || \\ - mv *.d ${file(compressed_file.baseName).baseName}.d + + # Fix read-only permissions from Bruker/Windows zip archives (dirs extracted as dr-xr-xr-x) + chmod -R u+w . 2>/dev/null || true + + expected_dir="${file(compressed_file.baseName).baseName}.d" + if [ -d "\${expected_dir}" ]; then + echo "Found \${expected_dir}" + else + # Handle archives where internal directory name differs (e.g. spaces vs underscores) + extracted_dir=\$(find . -maxdepth 1 -name "*.d" -type d | head -1 | sed 's|^\\./||') + if [ -n "\${extracted_dir}" ]; then + mv "\${extracted_dir}" "\${expected_dir}" + fi + fi ls -l | tee -a ${compressed_file.baseName}_decompression.log diff --git a/modules/local/utils/extract_sample/main.nf b/modules/local/utils/extract_sample/main.nf deleted file mode 100644 index 3a08b88f8..000000000 --- a/modules/local/utils/extract_sample/main.nf +++ /dev/null @@ -1,29 +0,0 @@ -process GET_SAMPLE { - tag "$design.Name" - label 'process_low' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/quantms-utils:0.0.24--pyh7e72e81_0' : - 'biocontainers/quantms-utils:0.0.24--pyh7e72e81_0' }" - - - input: - path design - - output: - path "*_sample.csv", emit: ch_expdesign_sample - path "versions.yml", emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - """ - quantmsutilsc openms2sample --expdesign "${design}" 2>&1 | tee extract_sample.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - sdrf-pipelines: \$(parse_sdrf --version 2>/dev/null | awk -F ' ' '{print \$2}') - END_VERSIONS - """ -} diff --git a/modules/local/utils/extract_sample/meta.yml b/modules/local/utils/extract_sample/meta.yml deleted file mode 100644 index 93c47a381..000000000 --- a/modules/local/utils/extract_sample/meta.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: get_sample -description: A module to extract sample information from experimental design file -keywords: - - sample - - conversion -tools: - - custom: - description: | - A custom module for sample extraction. - homepage: https://github.com/bigbio/quantms - documentation: https://github.com/bigbio/quantms/tree/readthedocs -input: - - design: - type: file - description: experimental design file - pattern: "*.csv" -output: - - ch_expdesign_sample: - type: file - description: sample csv file - pattern: "*_sample.csv" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" diff --git a/modules/local/utils/msrescore_features/main.nf b/modules/local/utils/msrescore_features/main.nf index 06226e912..c7793cd7d 100644 --- a/modules/local/utils/msrescore_features/main.nf +++ b/modules/local/utils/msrescore_features/main.nf @@ -1,16 +1,16 @@ process MSRESCORE_FEATURES { tag "$meta.mzml_id" - label 'process_high' + label 'process_medium' container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/quantms-rescoring-sif:0.0.14' : - 'ghcr.io/bigbio/quantms-rescoring:0.0.14' }" + 'oras://ghcr.io/bigbio/quantms-rescoring-sif:0.0.20' : + 'ghcr.io/bigbio/quantms-rescoring:0.0.20' }" input: - tuple val(meta), path(idxml), path(mzml), path(model_weight), val(search_engine) + tuple val(meta), path(id_files), path(mzml), path(model_weight) output: - tuple val(meta), path("*ms2rescore.idXML"), val(search_engine) , emit: idxml + tuple val(meta), path("*ms2rescore.idparquet"), emit: idparquet tuple val(meta), path("*.html" ) , optional:true, emit: html path "versions.yml" , emit: versions path "*.log" , emit: log @@ -92,11 +92,11 @@ process MSRESCORE_FEATURES { """ rescoring msrescore2feature \\ - --idxml $idxml \\ + --idparquet ${id_files.join(' --idparquet ')} \\ --mzml $mzml \\ --ms2_tolerance $ms2_tolerance \\ --ms2_tolerance_unit $ms2_tolerance_unit \\ - --output ${idxml.baseName}_ms2rescore.idXML \\ + --output ${mzml.baseName}_ms2rescore.idparquet \\ ${ms2_model_dir} \\ --processes $task.cpus \\ ${find_best_model} \\ @@ -104,7 +104,7 @@ process MSRESCORE_FEATURES { ${consider_modloss} \\ ${debug_log_level} \\ $args \\ - 2>&1 | tee ${idxml.baseName}_ms2rescore.log + 2>&1 | tee ${mzml.baseName}_ms2rescore.log cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/utils/msrescore_features/meta.yml b/modules/local/utils/msrescore_features/meta.yml index 208da0e7f..fe8162c1d 100644 --- a/modules/local/utils/msrescore_features/meta.yml +++ b/modules/local/utils/msrescore_features/meta.yml @@ -13,7 +13,7 @@ input: - idxml_file: type: file description: idXML identification file - pattern: "*.idXML" + pattern: "*.idparquet" - mzml: type: file description: spectrum data file @@ -25,7 +25,7 @@ output: - idxml: type: file description: idXML identification file after MS2 rescoring - pattern: "*.idXML" + pattern: "*.idparquet" - version: type: file description: File containing software version diff --git a/modules/local/utils/msrescore_fine_tuning/main.nf b/modules/local/utils/msrescore_fine_tuning/main.nf index f6bc6f88a..b1b34423f 100644 --- a/modules/local/utils/msrescore_fine_tuning/main.nf +++ b/modules/local/utils/msrescore_fine_tuning/main.nf @@ -3,23 +3,23 @@ process MSRESCORE_FINE_TUNING { label 'process_high' container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/quantms-rescoring-sif:0.0.14' : - 'ghcr.io/bigbio/quantms-rescoring:0.0.14' }" + 'oras://ghcr.io/bigbio/quantms-rescoring-sif:0.0.20' : + 'ghcr.io/bigbio/quantms-rescoring:0.0.20' }" input: - tuple val(meta), path(idxml), path(mzml), val(groupkey), path(ms2_model_dir) + tuple val(meta), path(idparquet), path(mzml), path(ms2_model_dir) output: - tuple val(groupkey), path("retained_ms2.pth") , emit: model_weight - path "versions.yml" , emit: versions - path "*.log" , emit: log + path("retained_ms2.pth") , emit: model_weight + path "versions.yml" , emit: versions + path "*.log" , emit: log when: task.ext.when == null || task.ext.when script: def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${groupkey}_fine_tuning" + def prefix = task.ext.prefix ?: "fine_tuning" // Initialize tolerance variables def ms2_tolerance = null @@ -49,8 +49,8 @@ process MSRESCORE_FINE_TUNING { """ rescoring transfer_learning \\ - --idxml ./ \\ - --mzml ./ \\ + --idparquet ${idparquet.join(' --idparquet ')} \\ + --mzml ${mzml.join(' --mzml ')} \\ --save_model_dir ./ \\ --ms2_tolerance $ms2_tolerance \\ --ms2_tolerance_unit $ms2_tolerance_unit \\ @@ -62,7 +62,7 @@ process MSRESCORE_FINE_TUNING { ${force_transfer_learning} \\ ${consider_modloss} \\ $args \\ - 2>&1 | tee ${groupkey}_fine_tuning.log + 2>&1 | tee fine_tuning.log cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/utils/msrescore_fine_tuning/meta.yml b/modules/local/utils/msrescore_fine_tuning/meta.yml index dd98ac3fa..72fb9a60e 100644 --- a/modules/local/utils/msrescore_fine_tuning/meta.yml +++ b/modules/local/utils/msrescore_fine_tuning/meta.yml @@ -18,7 +18,7 @@ input: - idxml_file: type: file description: idXML identification file - pattern: "*.idXML" + pattern: "*.idparquet" - mzml: type: file description: spectrum data file @@ -30,7 +30,7 @@ output: - idxml: type: file description: idXML identification file after MS2 rescoring - pattern: "*.idXML" + pattern: "*.idparquet" - version: type: file description: File containing software version diff --git a/modules/local/utils/mzml_statistics/main.nf b/modules/local/utils/mzml_statistics/main.nf index 4ddebe34d..cfa2c2bc2 100644 --- a/modules/local/utils/mzml_statistics/main.nf +++ b/modules/local/utils/mzml_statistics/main.nf @@ -4,8 +4,8 @@ process MZML_STATISTICS { label 'process_single' container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/quantms-utils:0.0.24--pyh7e72e81_0' : - 'biocontainers/quantms-utils:0.0.24--pyh7e72e81_0' }" + 'https://depot.galaxyproject.org/singularity/quantms-utils:0.0.25--pyh106432d_0' : + 'biocontainers/quantms-utils:0.0.25--pyh106432d_0' }" input: tuple val(meta), path(ms_file) @@ -27,6 +27,7 @@ process MZML_STATISTICS { quantmsutilsc mzmlstats --ms_path "${ms_file}" \\ ${string_ms2_file} \\ ${string_features_file} \\ + $args \\ 2>&1 | tee ${ms_file.baseName}_mzml_statistics.log cat <<-END_VERSIONS > versions.yml diff --git a/modules/local/utils/psm_clean/main.nf b/modules/local/utils/psm_clean/main.nf index 6f93de903..781634997 100644 --- a/modules/local/utils/psm_clean/main.nf +++ b/modules/local/utils/psm_clean/main.nf @@ -3,14 +3,14 @@ process PSM_CLEAN { label 'process_high' container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/quantms-rescoring-sif:0.0.13' : - 'ghcr.io/bigbio/quantms-rescoring:0.0.13' }" + 'oras://ghcr.io/bigbio/quantms-rescoring-sif:0.0.20' : + 'ghcr.io/bigbio/quantms-rescoring:0.0.20' }" input: - tuple val(meta), path(idxml), path(mzml) + tuple val(meta), path(idparquet), path(mzml) output: - tuple val(meta), path("*clean.idXML") , emit: idxml + tuple val(meta), path("*clean.idparquet") , emit: idparquet path "versions.yml" , emit: versions path "*.log" , emit: log @@ -23,11 +23,11 @@ process PSM_CLEAN { """ rescoring psm_feature_clean \\ - --idxml $idxml \\ + --idparquet ${idparquet.join(' --idparquet ')} \\ --mzml $mzml \\ - --output ${idxml.baseName}_clean.idXML \\ + --output ${mzml.baseName}_clean.idparquet \\ $args \\ - 2>&1 | tee ${idxml.baseName}_clean.log + 2>&1 | tee ${mzml.baseName}_clean.log cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/utils/psm_clean/meta.yml b/modules/local/utils/psm_clean/meta.yml index 84b1505b0..32fb1c400 100644 --- a/modules/local/utils/psm_clean/meta.yml +++ b/modules/local/utils/psm_clean/meta.yml @@ -13,7 +13,7 @@ input: - idxml_file: type: file description: idXML identification file - pattern: "*.idXML" + pattern: "*.idparquet" - mzml: type: file description: spectrum data file @@ -25,7 +25,7 @@ output: - idxml: type: file description: idXML identification file after postprocessing - pattern: "*.idXML" + pattern: "*.idparquet" - version: type: file description: File containing software version diff --git a/modules/local/utils/psm_conversion/main.nf b/modules/local/utils/psm_conversion/main.nf deleted file mode 100644 index 8e67d4453..000000000 --- a/modules/local/utils/psm_conversion/main.nf +++ /dev/null @@ -1,35 +0,0 @@ -process PSM_CONVERSION { - tag "$meta.mzml_id" - label 'process_medium' - - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/quantms-utils:0.0.24--pyh7e72e81_0' : - 'biocontainers/quantms-utils:0.0.24--pyh7e72e81_0' }" - - - input: - tuple val(meta), path(idxml_file), path(spectrum_df) - - output: - path "*_psm.parquet", emit: psm_info - path "versions.yml", emit: versions - path "*.log", emit: log - - script: - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.mzml_id}" - def string_export_decoy_psm = params.export_decoy_psm == true ? "--export_decoy_psm" : "" - - - """ - quantmsutilsc psmconvert --idxml "${idxml_file}" \\ - --ms2_file ${spectrum_df} \\ - ${string_export_decoy_psm} \\ - 2>&1 | tee extract_idxml.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - quantms-utils: \$(pip show quantms-utils | grep "Version" | awk -F ': ' '{print \$2}') - END_VERSIONS - """ -} diff --git a/modules/local/utils/psm_conversion/meta.yml b/modules/local/utils/psm_conversion/meta.yml deleted file mode 100644 index b3b3317f8..000000000 --- a/modules/local/utils/psm_conversion/meta.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: psm_conversion -description: A module to extract PSM information from idXML file -keywords: - - PSM - - conversion -tools: - - custom: - description: | - A custom module for PSM extraction. - homepage: https://github.com/bigbio/quantms - documentation: https://github.com/bigbio/quantms/tree/readthedocs -input: - - idxml_file: - type: file - description: idXML identification file - pattern: "*.idXML" - - spectrum_df: - type: file - description: spectrum data file - pattern: "_spectrum_df.parquet" - - meta: - type: map - description: Groovy Map containing sample information -output: - - psm_info: - type: file - description: PSM parquet file - pattern: "*_psm.parquet" - - version: - type: file - description: File containing software version - pattern: "versions.yml" -authors: - - "@daichengxin" diff --git a/modules/local/utils/spectrum_features/main.nf b/modules/local/utils/spectrum_features/main.nf index 83cc150e4..2346817b3 100644 --- a/modules/local/utils/spectrum_features/main.nf +++ b/modules/local/utils/spectrum_features/main.nf @@ -3,14 +3,14 @@ process SPECTRUM_FEATURES { label 'process_low' container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'oras://ghcr.io/bigbio/quantms-rescoring-sif:0.0.13' : - 'ghcr.io/bigbio/quantms-rescoring:0.0.13' }" + 'oras://ghcr.io/bigbio/quantms-rescoring-sif:0.0.20' : + 'ghcr.io/bigbio/quantms-rescoring:0.0.20' }" input: - tuple val(meta), path(id_file), val(search_engine), path(ms_file) + tuple val(meta), path(id_file), path(ms_file) output: - tuple val(meta), path("${id_file.baseName}_snr.idXML"), val(search_engine), emit: id_files_snr + tuple val(meta), path("${id_file.baseName}_snr.idparquet"), emit: id_files_snr path "versions.yml", emit: versions path "*.log", emit: log @@ -19,7 +19,13 @@ process SPECTRUM_FEATURES { def prefix = task.ext.prefix ?: "${meta.mzml_id}" """ - rescoring spectrum2feature --mzml "${ms_file}" --idxml "${id_file}" --output "${id_file.baseName}_snr.idXML" 2>&1 | tee ${id_file.baseName}_snr_feature.log + rescoring spectrum2feature \\ + --mzml "${ms_file}" \\ + --idparquet "${id_file}" \\ + --output "${id_file.baseName}_snr.idparquet" \\ + $args \\ + 2>&1 | tee "${id_file.baseName}_snr_feature.log" + cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/local/utils/spectrum_features/meta.yml b/modules/local/utils/spectrum_features/meta.yml index 1c53ddf9a..4cfb9b9da 100644 --- a/modules/local/utils/spectrum_features/meta.yml +++ b/modules/local/utils/spectrum_features/meta.yml @@ -22,7 +22,7 @@ input: type: file description: | Input idXML file containing the identifications. - pattern: "*.idXML" + pattern: "*.idparquet" output: - meta: type: map @@ -31,7 +31,7 @@ output: type: file description: | Output file in idXML format - pattern: "*.idXML" + pattern: "*.idparquet" - log: type: file description: log file diff --git a/modules/local/utils/tdf2mzml/main.nf b/modules/local/utils/tdf2mzml/main.nf index 30d3a27e1..6e7b4d567 100644 --- a/modules/local/utils/tdf2mzml/main.nf +++ b/modules/local/utils/tdf2mzml/main.nf @@ -10,7 +10,6 @@ process TDF2MZML { output: tuple val(meta), path("*.mzML"), emit: mzmls_converted - tuple val(meta), path("*.d"), emit: dotd_files path "versions.yml", emit: versions path "*.log", emit: log @@ -20,9 +19,16 @@ process TDF2MZML { """ echo "Converting..." | tee --append ${rawfile.baseName}_conversion.log - tdf2mzml.py -i *.d 2>&1 | tee --append ${rawfile.baseName}_conversion.log - mv *.mzml ${file(rawfile.baseName).baseName}.mzML - mv *.d ${file(rawfile.baseName).baseName}.d + tdf2mzml.py -i *.d $args 2>&1 | tee --append ${rawfile.baseName}_conversion.log + + # Rename .mzml to .mzML via temp file to handle case-insensitive filesystems (e.g. macOS) + mv *.mzml __tmp_converted.mzML && mv __tmp_converted.mzML ${file(rawfile.baseName).baseName}.mzML + + # Rename .d directory only if the name differs (avoid 'same file' error) + target_d="${file(rawfile.baseName).baseName}.d" + if [ ! -d "\${target_d}" ]; then + mv *.d "\${target_d}" + fi cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/custom/dumpsoftwareversions/environment.yml b/modules/nf-core/custom/dumpsoftwareversions/environment.yml deleted file mode 100644 index c3b3413fa..000000000 --- a/modules/nf-core/custom/dumpsoftwareversions/environment.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json -channels: - - conda-forge - - bioconda -dependencies: - - bioconda::multiqc=1.27 diff --git a/modules/nf-core/custom/dumpsoftwareversions/main.nf b/modules/nf-core/custom/dumpsoftwareversions/main.nf deleted file mode 100644 index dd6e210d1..000000000 --- a/modules/nf-core/custom/dumpsoftwareversions/main.nf +++ /dev/null @@ -1,33 +0,0 @@ -def deprecation_message = """ -WARNING: This module has been deprecated. - -Reason: -This module is no longer recommended for use, as it is replaced by the function softwareVersionsToYAML -in the utils_nfcore_pipeline subworkflow that is included in the nf-core template. - -""" -process CUSTOM_DUMPSOFTWAREVERSIONS { - label 'process_single' - - // Requires `pyyaml` which does not have a dedicated container but is in the MultiQC container - conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.27--pyhdfd78af_0' : - 'biocontainers/multiqc:1.27--pyhdfd78af_0' }" - - input: - path versions - - output: - path "software_versions.yml" , emit: yml - path "software_versions_mqc.yml", emit: mqc_yml - path "versions.yml" , emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - assert true: deprecation_message - def args = task.ext.args ?: '' - template 'dumpsoftwareversions.py' -} diff --git a/modules/nf-core/custom/dumpsoftwareversions/meta.yml b/modules/nf-core/custom/dumpsoftwareversions/meta.yml deleted file mode 100644 index b81907e60..000000000 --- a/modules/nf-core/custom/dumpsoftwareversions/meta.yml +++ /dev/null @@ -1,51 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json -name: custom_dumpsoftwareversions -description: Custom module used to dump software versions within the nf-core pipeline - template -keywords: - - custom - - dump - - version -tools: - - custom: - description: Custom module used to dump software versions within the nf-core pipeline - template - homepage: https://github.com/nf-core/tools - documentation: https://github.com/nf-core/tools - licence: ["MIT"] - identifier: "" -input: - - versions: - type: file - description: YML file containing software versions - pattern: "*.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML -output: - yml: - - software_versions.yml: - type: file - description: Standard YML file containing software versions - pattern: "software_versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML - mqc_yml: - - software_versions_mqc.yml: - type: file - description: MultiQC custom content YML file containing software versions - pattern: "software_versions_mqc.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML -authors: - - "@drpatelh" - - "@grst" -maintainers: - - "@drpatelh" - - "@grst" diff --git a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py deleted file mode 100755 index aa40e5e36..000000000 --- a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env python - - -"""Provide functions to merge multiple versions.yml files.""" - -import platform -from textwrap import dedent - -import yaml - - -def _make_versions_html(versions): - """Generate a tabular HTML output of all versions for MultiQC.""" - html = [ - dedent( - """\\ - - - - - - - - - - """ - ) - ] - for process, tmp_versions in sorted(versions.items()): - html.append("") - for i, (tool, version) in enumerate(sorted(tmp_versions.items())): - html.append( - dedent( - f"""\\ - - - - - - """ - ) - ) - html.append("") - html.append("
Process Name Software Version
{process if (i == 0) else ""}{tool}{version}
") - return "\\n".join(html) - - -def main(): - """Load all version files and generate merged output.""" - versions_this_module = {} - versions_this_module["${task.process}"] = { - "python": platform.python_version(), - "yaml": yaml.__version__, - } - - with open("$versions") as f: - versions_by_process = yaml.load(f, Loader=yaml.BaseLoader) | versions_this_module - - # aggregate versions by the module name (derived from fully-qualified process name) - versions_by_module = {} - for process, process_versions in versions_by_process.items(): - module = process.split(":")[-1] - try: - if versions_by_module[module] != process_versions: - raise AssertionError( - "We assume that software versions are the same between all modules. " - "If you see this error-message it means you discovered an edge-case " - "and should open an issue in nf-core/tools. " - ) - except KeyError: - versions_by_module[module] = process_versions - - versions_by_module["Workflow"] = { - "Nextflow": "$workflow.nextflow.version", - "$workflow.manifest.name": "$workflow.manifest.version", - } - - versions_mqc = { - "id": "software_versions", - "section_name": "${workflow.manifest.name} Software Versions", - "section_href": "https://github.com/${workflow.manifest.name}", - "plot_type": "html", - "description": "are collected at run time from the software output.", - "data": _make_versions_html(versions_by_module), - } - - with open("software_versions.yml", "w") as f: - yaml.dump(versions_by_module, f, default_flow_style=False) - with open("software_versions_mqc.yml", "w") as f: - yaml.dump(versions_mqc, f, default_flow_style=False) - - with open("versions.yml", "w") as f: - yaml.dump(versions_this_module, f, default_flow_style=False) - - -if __name__ == "__main__": - main() diff --git a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test deleted file mode 100644 index b1e1630bb..000000000 --- a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test +++ /dev/null @@ -1,43 +0,0 @@ -nextflow_process { - - name "Test Process CUSTOM_DUMPSOFTWAREVERSIONS" - script "../main.nf" - process "CUSTOM_DUMPSOFTWAREVERSIONS" - tag "modules" - tag "modules_nfcore" - tag "custom" - tag "dumpsoftwareversions" - tag "custom/dumpsoftwareversions" - - test("Should run without failures") { - when { - process { - """ - def tool1_version = ''' - TOOL1: - tool1: 0.11.9 - '''.stripIndent() - - def tool2_version = ''' - TOOL2: - tool2: 1.9 - '''.stripIndent() - - input[0] = Channel.of(tool1_version, tool2_version).collectFile() - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot( - process.out.versions, - file(process.out.mqc_yml[0]).readLines()[0..10], - file(process.out.yml[0]).readLines()[0..7] - ).match() - } - ) - } - } -} diff --git a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap deleted file mode 100644 index 74e42fb10..000000000 --- a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap +++ /dev/null @@ -1,37 +0,0 @@ -{ - "Should run without failures": { - "content": [ - [ - "versions.yml:md5,42bedca466554ea4ad0b586f8a18be28" - ], - [ - "data: \"\\n\\n \\n \\n \\n \\n \\n \\n \\n\\", - " \\n\\n\\n \\n \\n\\", - " \\ \\n\\n\\n\\n \\n \\", - " \\ \\n \\n\\n\\n\\n\\", - " \\n\\n \\n \\n\\", - " \\ \\n\\n\\n\\n\\n\\n \\n\\", - " \\ \\n \\n\\n\\n\\n\\", - " \\n\\n \\n \\n\\" - ], - [ - "CUSTOM_DUMPSOFTWAREVERSIONS:", - " python: 3.13.1", - " yaml: 6.0.2", - "TOOL1:", - " tool1: 0.11.9", - "TOOL2:", - " tool2: '1.9'", - "Workflow:" - ] - ], - "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.5" - }, - "timestamp": "2025-03-11T13:50:29.789124124" - } -} \ No newline at end of file diff --git a/modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c1f4a7982b743963_1.txt b/modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c1f4a7982b743963_1.txt new file mode 100644 index 000000000..761903040 --- /dev/null +++ b/modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c1f4a7982b743963_1.txt @@ -0,0 +1,1552 @@ + +version: 6 +environments: +default: +channels: +- url: https://conda.anaconda.org/conda-forge/ +- url: https://conda.anaconda.org/bioconda/ +- url: https://conda.anaconda.org/bioconda/ +options: +pypi-prerelease-mode: if-necessary-or-explicit +packages: +linux-64: +- conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py314h3de4e8d_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.1-pyh8f84b5b_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/coloredlogs-15.0.1-pyhd8ed1ab_4.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/colormath-3.0.0-pyhd8ed1ab_4.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.3-py314hd8ed1ab_101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.7.4-hecca717_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.17.1-h27c8c51_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/humanize-4.15.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-h33c6efd_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/kaleido-core-0.2.1-h3644ca4_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.18-h0c24ade_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-5_h4a7cf45_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-5_h0358290_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.4-hecca717_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.3-ha770c72_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.3-h73754d4_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.2-hb03c661_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-5_h47877c9_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_4.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.55-h421ea60_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.10.2-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py314h67df5f8_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/mathjax-2.7.7-ha770c72_3.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda +- conda: https://conda.anaconda.org/bioconda/noarch/multiqc-1.33-pyhdfd78af_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.18.1-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/natsort-8.4.0-pyhcf101f3_2.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.3-py314h2b28147_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.1.1-py314h8ec4b1a_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/plotly-6.6.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.39.3-pyh58ad624_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-lts-cpu-1.34.0.deprecated-hc364b38_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-32-1.39.3-py310hffdcd12_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-compat-1.39.3-py310hbcd5346_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/procps-ng-4.0.6-h18c060e_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pyaml-env-1.2.2-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py314h2e6c369_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.3-h32b2ec7_101_cp314.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.3-h4df99d1_101.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python-kaleido-0.2.1-pyhd8ed1ab_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py314h67df5f8_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/regex-2026.2.28-py314h5bd0f2a_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-14.3.3-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-click-1.9.7-pyh8f84b5b_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/rpds-py-0.30.0-py314h2e6c369_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/spectra-0.0.11-pyhd8ed1ab_2.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.52.0-h04a0ce9_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/tiktoken-0.12.0-py314h67fec18_3.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.1-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhd8ed1ab_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb03c661_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.3.3-hceb46e0_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda +packages: +- conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda +build_number: 20 +sha256: 1dd3fffd892081df9726d7eb7e0dea6198962ba775bd88842135a4ddb4deb3c9 +md5: a9f577daf3de00bca7c3c76c0ecbd1de +depends: +- __glibc >=2.17,<3.0.a0 +- libgomp >=7.5.0 +constrains: +- openmp_impl <0.0a0 +license: BSD-3-Clause +license_family: BSD +size: 28948 +timestamp: 1770939786096 +- conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda +sha256: a3967b937b9abf0f2a99f3173fa4630293979bd1644709d89580e7c62a544661 +md5: aaa2a381ccc56eac91d63b6c1240312f +depends: +- cpython +- python-gil +license: MIT +license_family: MIT +size: 8191 +timestamp: 1744137672556 +- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda +sha256: e0ea1ba78fbb64f17062601edda82097fcf815012cf52bb704150a2668110d48 +md5: 2934f256a8acfe48f6ebb4fce6cde29c +depends: +- python >=3.9 +- typing-extensions >=4.0.0 +license: MIT +license_family: MIT +size: 18074 +timestamp: 1733247158254 +- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda +sha256: 1b6124230bb4e571b1b9401537ecff575b7b109cc3a21ee019f65e083b8399ab +md5: c6b0543676ecb1fb2d7643941fe375f2 +depends: +- python >=3.10 +- python +license: MIT +license_family: MIT +size: 64927 +timestamp: 1773935801332 +- conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda +noarch: generic +sha256: c31ab719d256bc6f89926131e88ecd0f0c5d003fe8481852c6424f4ec6c7eb29 +md5: a2ac7763a9ac75055b68f325d3255265 +depends: +- python >=3.14 +license: BSD-3-Clause AND MIT AND EPL-2.0 +size: 7514 +timestamp: 1767044983590 +- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py314h3de4e8d_1.conda +sha256: 3ad3500bff54a781c29f16ce1b288b36606e2189d0b0ef2f67036554f47f12b0 +md5: 8910d2c46f7e7b519129f486e0fe927a +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +constrains: +- libbrotlicommon 1.2.0 hb03c661_1 +license: MIT +license_family: MIT +size: 367376 +timestamp: 1764017265553 +- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda +sha256: 0b75d45f0bba3e95dc693336fa51f40ea28c980131fec438afb7ce6118ed05f6 +md5: d2ffd7602c02f2b316fd921d39876885 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: bzip2-1.0.6 +license_family: BSD +size: 260182 +timestamp: 1771350215188 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda +sha256: 67cc7101b36421c5913a1687ef1b99f85b5d6868da3abbf6ec1a4181e79782fc +md5: 4492fd26db29495f0ba23f146cd5638d +depends: +- __unix +license: ISC +size: 147413 +timestamp: 1772006283803 +- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda +sha256: a6b118fd1ed6099dc4fc03f9c492b88882a780fadaef4ed4f93dc70757713656 +md5: 765c4d97e877cdbbb88ff33152b86125 +depends: +- python >=3.10 +license: ISC +size: 151445 +timestamp: 1772001170301 +- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda +sha256: d86dfd428b2e3c364fa90e07437c8405d635aa4ef54b25ab51d9c712be4112a5 +md5: 49ee13eb9b8f44d63879c69b8a40a74b +depends: +- python >=3.10 +license: MIT +license_family: MIT +size: 58510 +timestamp: 1773660086450 +- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.1-pyh8f84b5b_1.conda +sha256: 38cfe1ee75b21a8361c8824f5544c3866f303af1762693a178266d7f198e8715 +md5: ea8a6c3256897cc31263de9f455e25d9 +depends: +- python >=3.10 +- __unix +- python +license: BSD-3-Clause +license_family: BSD +size: 97676 +timestamp: 1764518652276 +- conda: https://conda.anaconda.org/conda-forge/noarch/coloredlogs-15.0.1-pyhd8ed1ab_4.conda +sha256: 8021c76eeadbdd5784b881b165242db9449783e12ce26d6234060026fd6a8680 +md5: b866ff7007b934d564961066c8195983 +depends: +- humanfriendly >=9.1 +- python >=3.9 +license: MIT +license_family: MIT +size: 43758 +timestamp: 1733928076798 +- conda: https://conda.anaconda.org/conda-forge/noarch/colormath-3.0.0-pyhd8ed1ab_4.conda +sha256: 59c9e29800b483b390467f90e82b0da3a4fbf0612efe1c90813fca232780e160 +md5: 071cf7b0ce333c81718b054066c15102 +depends: +- networkx >=2.0 +- numpy +- python >=3.9 +license: BSD-3-Clause +license_family: BSD +size: 39326 +timestamp: 1735759976140 +- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.3-py314hd8ed1ab_101.conda +noarch: generic +sha256: 91b06300879df746214f7363d6c27c2489c80732e46a369eb2afc234bcafb44c +md5: 3bb89e4f795e5414addaa531d6b1500a +depends: +- python >=3.14,<3.15.0a0 +- python_abi * *_cp314 +license: Python-2.0 +size: 50078 +timestamp: 1770674447292 +- conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.7.4-hecca717_0.conda +sha256: 0cc345e4dead417996ce9a1f088b28d858f03d113d43c1963d29194366dcce27 +md5: a0535741a4934b3e386051065c58761a +depends: +- __glibc >=2.17,<3.0.a0 +- libexpat 2.7.4 hecca717_0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 145274 +timestamp: 1771259434699 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 +sha256: 58d7f40d2940dd0a8aa28651239adbf5613254df0f75789919c4e6762054403b +md5: 0c96522c6bdaed4b1566d11387caaf45 +license: BSD-3-Clause +license_family: BSD +size: 397370 +timestamp: 1566932522327 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 +sha256: c52a29fdac682c20d252facc50f01e7c2e7ceac52aa9817aaf0bb83f7559ec5c +md5: 34893075a5c9e55cdafac56607368fc6 +license: OFL-1.1 +license_family: Other +size: 96530 +timestamp: 1620479909603 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2 +sha256: 00925c8c055a2275614b4d983e1df637245e19058d79fc7dd1a93b8d9fb4b139 +md5: 4d59c254e01d9cde7957100457e2d5fb +license: OFL-1.1 +license_family: Other +size: 700814 +timestamp: 1620479612257 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda +sha256: 2821ec1dc454bd8b9a31d0ed22a7ce22422c0aef163c59f49dfdf915d0f0ca14 +md5: 49023d73832ef61042f6a237cb2687e7 +license: LicenseRef-Ubuntu-Font-Licence-Version-1.0 +license_family: Other +size: 1620504 +timestamp: 1727511233259 +- conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.17.1-h27c8c51_0.conda +sha256: aa4a44dba97151221100a637c7f4bde619567afade9c0265f8e1c8eed8d7bd8c +md5: 867127763fbe935bab59815b6e0b7b5c +depends: +- __glibc >=2.17,<3.0.a0 +- libexpat >=2.7.4,<3.0a0 +- libfreetype >=2.14.1 +- libfreetype6 >=2.14.1 +- libgcc >=14 +- libuuid >=2.41.3,<3.0a0 +- libzlib >=1.3.1,<2.0a0 +license: MIT +license_family: MIT +size: 270705 +timestamp: 1771382710863 +- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda +sha256: 54eea8469786bc2291cc40bca5f46438d3e062a399e8f53f013b6a9f50e98333 +md5: a7970cd949a077b7cb9696379d338681 +depends: +- font-ttf-ubuntu +- font-ttf-inconsolata +- font-ttf-dejavu-sans-mono +- font-ttf-source-code-pro +license: BSD-3-Clause +license_family: BSD +size: 4059 +timestamp: 1762351264405 +- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda +sha256: 84c64443368f84b600bfecc529a1194a3b14c3656ee2e832d15a20e0329b6da3 +md5: 164fc43f0b53b6e3a7bc7dce5e4f1dc9 +depends: +- python >=3.10 +- hyperframe >=6.1,<7 +- hpack >=4.1,<5 +- python +license: MIT +license_family: MIT +size: 95967 +timestamp: 1756364871835 +- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda +sha256: 6ad78a180576c706aabeb5b4c8ceb97c0cb25f1e112d76495bff23e3779948ba +md5: 0a802cb9888dd14eeefc611f05c40b6e +depends: +- python >=3.9 +license: MIT +license_family: MIT +size: 30731 +timestamp: 1737618390337 +- conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda +sha256: fa2071da7fab758c669e78227e6094f6b3608228740808a6de5d6bce83d9e52d +md5: 7fe569c10905402ed47024fc481bb371 +depends: +- __unix +- python >=3.9 +license: MIT +license_family: MIT +size: 73563 +timestamp: 1733928021866 +- conda: https://conda.anaconda.org/conda-forge/noarch/humanize-4.15.0-pyhd8ed1ab_0.conda +sha256: 6c4343b376d0b12a4c75ab992640970d36c933cad1fd924f6a1181fa91710e80 +md5: daddf757c3ecd6067b9af1df1f25d89e +depends: +- python >=3.10 +license: MIT +license_family: MIT +size: 67994 +timestamp: 1766267728652 +- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda +sha256: 77af6f5fe8b62ca07d09ac60127a30d9069fdc3c68d6b256754d0ffb1f7779f8 +md5: 8e6923fc12f1fe8f8c4e5c9f343256ac +depends: +- python >=3.9 +license: MIT +license_family: MIT +size: 17397 +timestamp: 1737618427549 +- conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-h33c6efd_0.conda +sha256: fbf86c4a59c2ed05bbffb2ba25c7ed94f6185ec30ecb691615d42342baa1a16a +md5: c80d8a3b84358cb967fa81e7075fbc8a +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +license: MIT +license_family: MIT +size: 12723451 +timestamp: 1773822285671 +- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda +sha256: ae89d0299ada2a3162c2614a9d26557a92aa6a77120ce142f8e0109bbf0342b0 +md5: 53abe63df7e10a6ba605dc5f9f961d36 +depends: +- python >=3.10 +license: BSD-3-Clause +license_family: BSD +size: 50721 +timestamp: 1760286526795 +- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda +sha256: 82ab2a0d91ca1e7e63ab6a4939356667ef683905dea631bc2121aa534d347b16 +md5: 080594bf4493e6bae2607e65390c520a +depends: +- python >=3.10 +- zipp >=3.20 +- python +license: Apache-2.0 +license_family: APACHE +size: 34387 +timestamp: 1773931568510 +- conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda +sha256: fc9ca7348a4f25fed2079f2153ecdcf5f9cf2a0bc36c4172420ca09e1849df7b +md5: 04558c96691bed63104678757beb4f8d +depends: +- markupsafe >=2.0 +- python >=3.10 +- python +license: BSD-3-Clause +license_family: BSD +size: 120685 +timestamp: 1764517220861 +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda +sha256: db973a37d75db8e19b5f44bbbdaead0c68dde745407f281e2a7fe4db74ec51d7 +md5: ada41c863af263cc4c5fcbaff7c3e4dc +depends: +- attrs >=22.2.0 +- jsonschema-specifications >=2023.3.6 +- python >=3.10 +- referencing >=0.28.4 +- rpds-py >=0.25.0 +- python +license: MIT +license_family: MIT +size: 82356 +timestamp: 1767839954256 +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda +sha256: 0a4f3b132f0faca10c89fdf3b60e15abb62ded6fa80aebfc007d05965192aa04 +md5: 439cd0f567d697b20a8f45cb70a1005a +depends: +- python >=3.10 +- referencing >=0.31.0 +- python +license: MIT +license_family: MIT +size: 19236 +timestamp: 1757335715225 +- conda: https://conda.anaconda.org/conda-forge/linux-64/kaleido-core-0.2.1-h3644ca4_0.tar.bz2 +sha256: 7f243680ca03eba7457b7a48f93a9440ba8181a8eac20a3eb5ef165ab6c96664 +md5: b3723b235b0758abaae8c82ce4d80146 +depends: +- __glibc >=2.17,<3.0.a0 +- expat >=2.2.10,<3.0.0a0 +- fontconfig +- fonts-conda-forge +- libgcc-ng >=9.3.0 +- mathjax 2.7.* +- nspr >=4.29,<5.0a0 +- nss >=3.62,<4.0a0 +- sqlite >=3.34.0,<4.0a0 +license: MIT +license_family: MIT +size: 62099926 +timestamp: 1615199463039 +- conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.18-h0c24ade_0.conda +sha256: 836ec4b895352110335b9fdcfa83a8dcdbe6c5fb7c06c4929130600caea91c0a +md5: 6f2e2c8f58160147c4d1c6f4c14cbac4 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libjpeg-turbo >=3.1.2,<4.0a0 +- libtiff >=4.7.1,<4.8.0a0 +license: MIT +license_family: MIT +size: 249959 +timestamp: 1768184673131 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda +sha256: 3d584956604909ff5df353767f3a2a2f60e07d070b328d109f30ac40cd62df6c +md5: 18335a698559cdbcd86150a48bf54ba6 +depends: +- __glibc >=2.17,<3.0.a0 +- zstd >=1.5.7,<1.6.0a0 +constrains: +- binutils_impl_linux-64 2.45.1 +license: GPL-3.0-only +license_family: GPL +size: 728002 +timestamp: 1774197446916 +- conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda +sha256: f84cb54782f7e9cea95e810ea8fef186e0652d0fa73d3009914fa2c1262594e1 +md5: a752488c68f2e7c456bcbd8f16eec275 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +license: Apache-2.0 +license_family: Apache +size: 261513 +timestamp: 1773113328888 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-5_h4a7cf45_openblas.conda +build_number: 5 +sha256: 18c72545080b86739352482ba14ba2c4815e19e26a7417ca21a95b76ec8da24c +md5: c160954f7418d7b6e87eaf05a8913fa9 +depends: +- libopenblas >=0.3.30,<0.3.31.0a0 +- libopenblas >=0.3.30,<1.0a0 +constrains: +- mkl <2026 +- liblapack 3.11.0 5*_openblas +- libcblas 3.11.0 5*_openblas +- blas 2.305 openblas +- liblapacke 3.11.0 5*_openblas +license: BSD-3-Clause +license_family: BSD +size: 18213 +timestamp: 1765818813880 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-5_h0358290_openblas.conda +build_number: 5 +sha256: 0cbdcc67901e02dc17f1d19e1f9170610bd828100dc207de4d5b6b8ad1ae7ad8 +md5: 6636a2b6f1a87572df2970d3ebc87cc0 +depends: +- libblas 3.11.0 5_h4a7cf45_openblas +constrains: +- liblapacke 3.11.0 5*_openblas +- blas 2.305 openblas +- liblapack 3.11.0 5*_openblas +license: BSD-3-Clause +license_family: BSD +size: 18194 +timestamp: 1765818837135 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda +sha256: aa8e8c4be9a2e81610ddf574e05b64ee131fab5e0e3693210c9d6d2fba32c680 +md5: 6c77a605a7a689d17d4819c0f8ac9a00 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 73490 +timestamp: 1761979956660 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.4-hecca717_0.conda +sha256: d78f1d3bea8c031d2f032b760f36676d87929b18146351c4464c66b0869df3f5 +md5: e7f7ce06ec24cfcfb9e36d28cf82ba57 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +constrains: +- expat 2.7.4.* +license: MIT +license_family: MIT +size: 76798 +timestamp: 1771259418166 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda +sha256: 31f19b6a88ce40ebc0d5a992c131f57d919f73c0b92cd1617a5bec83f6e961e6 +md5: a360c33a5abe61c07959e449fa1453eb +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 58592 +timestamp: 1769456073053 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.3-ha770c72_0.conda +sha256: 38f014a7129e644636e46064ecd6b1945e729c2140e21d75bb476af39e692db2 +md5: e289f3d17880e44b633ba911d57a321b +depends: +- libfreetype6 >=2.14.3 +license: GPL-2.0-only OR FTL +size: 8049 +timestamp: 1774298163029 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.3-h73754d4_0.conda +sha256: 16f020f96da79db1863fcdd8f2b8f4f7d52f177dd4c58601e38e9182e91adf1d +md5: fb16b4b69e3f1dcfe79d80db8fd0c55d +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libpng >=1.6.55,<1.7.0a0 +- libzlib >=1.3.2,<2.0a0 +constrains: +- freetype >=2.14.3 +license: GPL-2.0-only OR FTL +size: 384575 +timestamp: 1774298162622 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda +sha256: faf7d2017b4d718951e3a59d081eb09759152f93038479b768e3d612688f83f5 +md5: 0aa00f03f9e39fb9876085dee11a85d4 +depends: +- __glibc >=2.17,<3.0.a0 +- _openmp_mutex >=4.5 +constrains: +- libgcc-ng ==15.2.0=*_18 +- libgomp 15.2.0 he0feb66_18 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 1041788 +timestamp: 1771378212382 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda +sha256: e318a711400f536c81123e753d4c797a821021fb38970cebfb3f454126016893 +md5: d5e96b1ed75ca01906b3d2469b4ce493 +depends: +- libgcc 15.2.0 he0feb66_18 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 27526 +timestamp: 1771378224552 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_18.conda +sha256: d2c9fad338fd85e4487424865da8e74006ab2e2475bd788f624d7a39b2a72aee +md5: 9063115da5bc35fdc3e1002e69b9ef6e +depends: +- libgfortran5 15.2.0 h68bc16d_18 +constrains: +- libgfortran-ng ==15.2.0=*_18 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 27523 +timestamp: 1771378269450 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_18.conda +sha256: 539b57cf50ec85509a94ba9949b7e30717839e4d694bc94f30d41c9d34de2d12 +md5: 646855f357199a12f02a87382d429b75 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=15.2.0 +constrains: +- libgfortran 15.2.0 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 2482475 +timestamp: 1771378241063 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda +sha256: 21337ab58e5e0649d869ab168d4e609b033509de22521de1bfed0c031bfc5110 +md5: 239c5e9546c38a1e884d69effcf4c882 +depends: +- __glibc >=2.17,<3.0.a0 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 603262 +timestamp: 1771378117851 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.2-hb03c661_0.conda +sha256: cc9aba923eea0af8e30e0f94f2ad7156e2984d80d1e8e7fe6be5a1f257f0eb32 +md5: 8397539e3a0bbd1695584fb4f927485a +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +constrains: +- jpeg <0.0.0a +license: IJG AND BSD-3-Clause AND Zlib +size: 633710 +timestamp: 1762094827865 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-5_h47877c9_openblas.conda +build_number: 5 +sha256: c723b6599fcd4c6c75dee728359ef418307280fa3e2ee376e14e85e5bbdda053 +md5: b38076eb5c8e40d0106beda6f95d7609 +depends: +- libblas 3.11.0 5_h4a7cf45_openblas +constrains: +- blas 2.305 openblas +- liblapacke 3.11.0 5*_openblas +- libcblas 3.11.0 5*_openblas +license: BSD-3-Clause +license_family: BSD +size: 18200 +timestamp: 1765818857876 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda +sha256: 755c55ebab181d678c12e49cced893598f2bab22d582fbbf4d8b83c18be207eb +md5: c7c83eecbb72d88b940c249af56c8b17 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +constrains: +- xz 5.8.2.* +license: 0BSD +size: 113207 +timestamp: 1768752626120 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda +sha256: fe171ed5cf5959993d43ff72de7596e8ac2853e9021dec0344e583734f1e0843 +md5: 2c21e66f50753a083cbe6b80f38268fa +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: BSD-2-Clause +license_family: BSD +size: 92400 +timestamp: 1769482286018 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_4.conda +sha256: 199d79c237afb0d4780ccd2fbf829cea80743df60df4705202558675e07dd2c5 +md5: be43915efc66345cccb3c310b6ed0374 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libgfortran +- libgfortran5 >=14.3.0 +constrains: +- openblas >=0.3.30,<0.3.31.0a0 +license: BSD-3-Clause +license_family: BSD +size: 5927939 +timestamp: 1763114673331 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.55-h421ea60_0.conda +sha256: 36ade759122cdf0f16e2a2562a19746d96cf9c863ffaa812f2f5071ebbe9c03c +md5: 5f13ffc7d30ffec87864e678df9957b4 +depends: +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- libzlib >=1.3.1,<2.0a0 +license: zlib-acknowledgement +size: 317669 +timestamp: 1770691470744 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda +sha256: d716847b7deca293d2e49ed1c8ab9e4b9e04b9d780aea49a97c26925b28a7993 +md5: fd893f6a3002a635b5e50ceb9dd2c0f4 +depends: +- __glibc >=2.17,<3.0.a0 +- icu >=78.2,<79.0a0 +- libgcc >=14 +- libzlib >=1.3.1,<2.0a0 +license: blessing +size: 951405 +timestamp: 1772818874251 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda +sha256: 78668020064fdaa27e9ab65cd2997e2c837b564ab26ce3bf0e58a2ce1a525c6e +md5: 1b08cd684f34175e4514474793d44bcb +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc 15.2.0 he0feb66_18 +constrains: +- libstdcxx-ng ==15.2.0=*_18 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 5852330 +timestamp: 1771378262446 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda +sha256: e5f8c38625aa6d567809733ae04bb71c161a42e44a9fa8227abe61fa5c60ebe0 +md5: cd5a90476766d53e901500df9215e927 +depends: +- __glibc >=2.17,<3.0.a0 +- lerc >=4.0.0,<5.0a0 +- libdeflate >=1.25,<1.26.0a0 +- libgcc >=14 +- libjpeg-turbo >=3.1.0,<4.0a0 +- liblzma >=5.8.1,<6.0a0 +- libstdcxx >=14 +- libwebp-base >=1.6.0,<2.0a0 +- libzlib >=1.3.1,<2.0a0 +- zstd >=1.5.7,<1.6.0a0 +license: HPND +size: 435273 +timestamp: 1762022005702 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda +sha256: 1a7539cfa7df00714e8943e18de0b06cceef6778e420a5ee3a2a145773758aee +md5: db409b7c1720428638e7c0d509d3e1b5 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: BSD-3-Clause +license_family: BSD +size: 40311 +timestamp: 1766271528534 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda +sha256: 3aed21ab28eddffdaf7f804f49be7a7d701e8f0e46c856d801270b470820a37b +md5: aea31d2e5b1091feca96fcfe945c3cf9 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +constrains: +- libwebp 1.6.0 +license: BSD-3-Clause +license_family: BSD +size: 429011 +timestamp: 1752159441324 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda +sha256: 666c0c431b23c6cec6e492840b176dde533d48b7e6fb8883f5071223433776aa +md5: 92ed62436b625154323d40d5f2f11dd7 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +- pthread-stubs +- xorg-libxau >=1.0.11,<2.0a0 +- xorg-libxdmcp +license: MIT +license_family: MIT +size: 395888 +timestamp: 1727278577118 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda +sha256: 55044c403570f0dc26e6364de4dc5368e5f3fc7ff103e867c487e2b5ab2bcda9 +md5: d87ff7921124eccd67248aa483c23fec +depends: +- __glibc >=2.17,<3.0.a0 +constrains: +- zlib 1.3.2 *_2 +license: Zlib +license_family: Other +size: 63629 +timestamp: 1774072609062 +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.10.2-pyhcf101f3_0.conda +sha256: 20e0892592a3e7c683e3d66df704a9425d731486a97c34fc56af4da1106b2b6b +md5: ba0a9221ce1063f31692c07370d062f3 +depends: +- importlib-metadata >=4.4 +- python >=3.10 +- python +license: BSD-3-Clause +license_family: BSD +size: 85893 +timestamp: 1770694658918 +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda +sha256: 7b1da4b5c40385791dbc3cc85ceea9fad5da680a27d5d3cb8bfaa185e304a89e +md5: 5b5203189eb668f042ac2b0826244964 +depends: +- mdurl >=0.1,<1 +- python >=3.10 +license: MIT +license_family: MIT +size: 64736 +timestamp: 1754951288511 +- conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py314h67df5f8_1.conda +sha256: c279be85b59a62d5c52f5dd9a4cd43ebd08933809a8416c22c3131595607d4cf +md5: 9a17c4307d23318476d7fbf0fedc0cde +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +constrains: +- jinja2 >=3.0.0 +license: BSD-3-Clause +license_family: BSD +size: 27424 +timestamp: 1772445227915 +- conda: https://conda.anaconda.org/conda-forge/linux-64/mathjax-2.7.7-ha770c72_3.tar.bz2 +sha256: 02fef69bde69db264a12f21386612262f545b6e3e68d8f1ccec19f3eaae58edf +md5: 86e69bd82c2a2c6fd29f5ab7e02b3691 +license: Apache-2.0 +license_family: Apache +size: 22281629 +timestamp: 1662784498331 +- conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda +sha256: 78c1bbe1723449c52b7a9df1af2ee5f005209f67e40b6e1d3c7619127c43b1c7 +md5: 592132998493b3ff25fd7479396e8351 +depends: +- python >=3.9 +license: MIT +license_family: MIT +size: 14465 +timestamp: 1733255681319 +- conda: https://conda.anaconda.org/bioconda/noarch/multiqc-1.33-pyhdfd78af_0.conda +sha256: f005760b13093362fc9c997d603dd487de32ab2e821a3cbce52a42bcb8136517 +md5: 698a8a27c2b9d8a542c70cb47099a75e +depends: +- click +- coloredlogs +- humanize +- importlib-metadata +- jinja2 >=3.0.0 +- jsonschema +- markdown +- natsort +- numpy +- packaging +- pillow >=10.2.0 +- plotly >=5.18 +- polars-lts-cpu +- pyaml-env +- pydantic >=2.7.1 +- python >=3.8,!=3.14.1 +- python-dotenv +- python-kaleido 0.2.1 +- pyyaml >=4 +- requests +- rich >=10 +- rich-click +- spectra >=0.0.10 +- tiktoken +- tqdm +- typeguard +license: GPL-3.0-or-later +license_family: GPL3 +size: 4198799 +timestamp: 1765300743879 +- conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.18.1-pyhcf101f3_1.conda +sha256: 541fd4390a0687228b8578247f1536a821d9261389a65585af9d1a6f2a14e1e0 +md5: 30bec5e8f4c3969e2b1bd407c5e52afb +depends: +- python >=3.10 +- python +license: MIT +size: 280459 +timestamp: 1774380620329 +- conda: https://conda.anaconda.org/conda-forge/noarch/natsort-8.4.0-pyhcf101f3_2.conda +sha256: aeb1548eb72e4f198e72f19d242fb695b35add2ac7b2c00e0d83687052867680 +md5: e941e85e273121222580723010bd4fa2 +depends: +- python >=3.9 +- python +license: MIT +license_family: MIT +size: 39262 +timestamp: 1770905275632 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda +sha256: 3fde293232fa3fca98635e1167de6b7c7fda83caf24b9d6c91ec9eefb4f4d586 +md5: 47e340acb35de30501a76c7c799c41d7 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +license: X11 AND BSD-3-Clause +size: 891641 +timestamp: 1738195959188 +- conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda +sha256: f6a82172afc50e54741f6f84527ef10424326611503c64e359e25a19a8e4c1c6 +md5: a2c1eeadae7a309daed9d62c96012a2b +depends: +- python >=3.11 +- python +constrains: +- numpy >=1.25 +- scipy >=1.11.2 +- matplotlib-base >=3.8 +- pandas >=2.0 +license: BSD-3-Clause +license_family: BSD +size: 1587439 +timestamp: 1765215107045 +- conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda +sha256: e3664264bd936c357523b55c71ed5a30263c6ba278d726a75b1eb112e6fb0b64 +md5: e235d5566c9cc8970eb2798dd4ecf62f +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +license: MPL-2.0 +license_family: MOZILLA +size: 228588 +timestamp: 1762348634537 +- conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda +sha256: 44dd98ffeac859d84a6dcba79a2096193a42fc10b29b28a5115687a680dd6aea +md5: 567fbeed956c200c1db5782a424e58ee +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libsqlite >=3.51.0,<4.0a0 +- libstdcxx >=14 +- libzlib >=1.3.1,<2.0a0 +- nspr >=4.38,<5.0a0 +license: MPL-2.0 +license_family: MOZILLA +size: 2057773 +timestamp: 1763485556350 +- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.3-py314h2b28147_0.conda +sha256: f2ba8cb0d86a6461a6bcf0d315c80c7076083f72c6733c9290086640723f79ec +md5: 36f5b7eb328bdc204954a2225cf908e2 +depends: +- python +- libstdcxx >=14 +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- python_abi 3.14.* *_cp314 +- libcblas >=3.9.0,<4.0a0 +- liblapack >=3.9.0,<4.0a0 +- libblas >=3.9.0,<4.0a0 +constrains: +- numpy-base <0a0 +license: BSD-3-Clause +license_family: BSD +size: 8927860 +timestamp: 1773839233468 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda +sha256: 3900f9f2dbbf4129cf3ad6acf4e4b6f7101390b53843591c53b00f034343bc4d +md5: 11b3379b191f63139e29c0d19dee24cd +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libpng >=1.6.50,<1.7.0a0 +- libstdcxx >=14 +- libtiff >=4.7.1,<4.8.0a0 +- libzlib >=1.3.1,<2.0a0 +license: BSD-2-Clause +license_family: BSD +size: 355400 +timestamp: 1758489294972 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda +sha256: 44c877f8af015332a5d12f5ff0fb20ca32f896526a7d0cdb30c769df1144fb5c +md5: f61eb8cd60ff9057122a3d338b99c00f +depends: +- __glibc >=2.17,<3.0.a0 +- ca-certificates +- libgcc >=14 +license: Apache-2.0 +license_family: Apache +size: 3164551 +timestamp: 1769555830639 +- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda +sha256: c1fc0f953048f743385d31c468b4a678b3ad20caffdeaa94bed85ba63049fd58 +md5: b76541e68fea4d511b1ac46a28dcd2c6 +depends: +- python >=3.8 +- python +license: Apache-2.0 +license_family: APACHE +size: 72010 +timestamp: 1769093650580 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.1.1-py314h8ec4b1a_0.conda +sha256: 9e6ec8f3213e8b7d64b0ad45f84c51a2c9eba4398efda31e196c9a56186133ee +md5: 79678378ae235e24b3aa83cee1b38207 +depends: +- python +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- libwebp-base >=1.6.0,<2.0a0 +- zlib-ng >=2.3.3,<2.4.0a0 +- python_abi 3.14.* *_cp314 +- tk >=8.6.13,<8.7.0a0 +- libjpeg-turbo >=3.1.2,<4.0a0 +- libxcb >=1.17.0,<2.0a0 +- openjpeg >=2.5.4,<3.0a0 +- lcms2 >=2.18,<3.0a0 +- libtiff >=4.7.1,<4.8.0a0 +- libfreetype >=2.14.1 +- libfreetype6 >=2.14.1 +license: HPND +size: 1073026 +timestamp: 1770794002408 +- conda: https://conda.anaconda.org/conda-forge/noarch/plotly-6.6.0-pyhd8ed1ab_0.conda +sha256: c418d325359fc7a0074cea7f081ef1bce26e114d2da8a0154c5d27ecc87a08e7 +md5: 3e9427ee186846052e81fadde8ebe96a +depends: +- narwhals >=1.15.1 +- packaging +- python >=3.10 +constrains: +- ipywidgets >=7.6 +license: MIT +license_family: MIT +size: 5251872 +timestamp: 1772628857717 +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.39.3-pyh58ad624_1.conda +sha256: d332c2d5002fc440ae37ed9679ffc21b552f18d20232390005d1dd3bce0888d3 +md5: d5a4e013a30dd8dfde9ab39f45aaf9c1 +depends: +- polars-runtime-32 ==1.39.3 +- python >=3.10 +- python +constrains: +- numpy >=1.16.0 +- pyarrow >=7.0.0 +- fastexcel >=0.9 +- openpyxl >=3.0.0 +- xlsx2csv >=0.8.0 +- connectorx >=0.3.2 +- deltalake >=1.0.0 +- pyiceberg >=0.7.1 +- altair >=5.4.0 +- great_tables >=0.8.0 +- polars-runtime-32 ==1.39.3 +- polars-runtime-64 ==1.39.3 +- polars-runtime-compat ==1.39.3 +license: MIT +license_family: MIT +size: 533495 +timestamp: 1774207987966 +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-lts-cpu-1.34.0.deprecated-hc364b38_0.conda +sha256: e466fb31f67ba9bde18deafeb34263ca5eb25807f39ead0e9d753a8e82c4c4f4 +md5: ef0340e75068ac8ff96462749b5c98e7 +depends: +- polars >=1.34.0 +- polars-runtime-compat >=1.34.0 +license: MIT +license_family: MIT +size: 3902 +timestamp: 1760206808444 +- conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-32-1.39.3-py310hffdcd12_1.conda +noarch: python +sha256: 9744f8086bb0832998f5b01076f57ddc9efbe460e493b14303c3567dc4f401e7 +md5: f9327f9f2cfc4215f55b613e64afd3ba +depends: +- python +- libstdcxx >=14 +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- _python_abi3_support 1.* +- cpython >=3.10 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 37570276 +timestamp: 1774207987966 +- conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-compat-1.39.3-py310hbcd5346_1.conda +noarch: python +sha256: bf0b932713f0f27924f42159c98426e0073bb6145ed796eaa4cec79ca05363c7 +md5: 4b9b312453eebd6fbdbbe2a88fa1b5c4 +depends: +- python +- libgcc >=14 +- libstdcxx >=14 +- __glibc >=2.17,<3.0.a0 +- _python_abi3_support 1.* +- cpython >=3.10 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 37224264 +timestamp: 1774207985377 +- conda: https://conda.anaconda.org/conda-forge/linux-64/procps-ng-4.0.6-h18c060e_0.conda +sha256: 4ce2e1ee31a6217998f78c31ce7dc0a3e0557d9238b51d49dd20c52d467a126d +md5: f2c23a77b25efcad57d377b34bd84941 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- ncurses >=6.5,<7.0a0 +license: GPL-2.0-or-later AND LGPL-2.0-or-later +license_family: GPL +size: 593603 +timestamp: 1769710381284 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda +sha256: 9c88f8c64590e9567c6c80823f0328e58d3b1efb0e1c539c0315ceca764e0973 +md5: b3c17d95b5a10c6e64a21fa17573e70e +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +license: MIT +license_family: MIT +size: 8252 +timestamp: 1726802366959 +- conda: https://conda.anaconda.org/conda-forge/noarch/pyaml-env-1.2.2-pyhd8ed1ab_0.conda +sha256: 58994e0d2ea8584cb399546e6f6896d771995e6121d1a7b6a2c9948388358932 +md5: e17be1016bcc3516827b836cd3e4d9dc +depends: +- python >=3.9 +- pyyaml >=5.0,<=7.0 +license: MIT +license_family: MIT +size: 14645 +timestamp: 1736766960536 +- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda +sha256: 868569d9505b7fe246c880c11e2c44924d7613a8cdcc1f6ef85d5375e892f13d +md5: c3946ed24acdb28db1b5d63321dbca7d +depends: +- typing-inspection >=0.4.2 +- typing_extensions >=4.14.1 +- python >=3.10 +- typing-extensions >=4.6.1 +- annotated-types >=0.6.0 +- pydantic-core ==2.41.5 +- python +license: MIT +license_family: MIT +size: 340482 +timestamp: 1764434463101 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py314h2e6c369_1.conda +sha256: 7e0ae379796e28a429f8e48f2fe22a0f232979d65ec455e91f8dac689247d39f +md5: 432b0716a1dfac69b86aa38fdd59b7e6 +depends: +- python +- typing-extensions >=4.6.0,!=4.7.0 +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- python_abi 3.14.* *_cp314 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 1943088 +timestamp: 1762988995556 +- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda +sha256: 5577623b9f6685ece2697c6eb7511b4c9ac5fb607c9babc2646c811b428fd46a +md5: 6b6ece66ebcae2d5f326c77ef2c5a066 +depends: +- python >=3.9 +license: BSD-2-Clause +license_family: BSD +size: 889287 +timestamp: 1750615908735 +- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda +sha256: ba3b032fa52709ce0d9fd388f63d330a026754587a2f461117cac9ab73d8d0d8 +md5: 461219d1a5bd61342293efa2c0c90eac +depends: +- __unix +- python >=3.9 +license: BSD-3-Clause +license_family: BSD +size: 21085 +timestamp: 1733217331982 +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.3-h32b2ec7_101_cp314.conda +build_number: 101 +sha256: cb0628c5f1732f889f53a877484da98f5a0e0f47326622671396fb4f2b0cd6bd +md5: c014ad06e60441661737121d3eae8a60 +depends: +- __glibc >=2.17,<3.0.a0 +- bzip2 >=1.0.8,<2.0a0 +- ld_impl_linux-64 >=2.36.1 +- libexpat >=2.7.3,<3.0a0 +- libffi >=3.5.2,<3.6.0a0 +- libgcc >=14 +- liblzma >=5.8.2,<6.0a0 +- libmpdec >=4.0.0,<5.0a0 +- libsqlite >=3.51.2,<4.0a0 +- libuuid >=2.41.3,<3.0a0 +- libzlib >=1.3.1,<2.0a0 +- ncurses >=6.5,<7.0a0 +- openssl >=3.5.5,<4.0a0 +- python_abi 3.14.* *_cp314 +- readline >=8.3,<9.0a0 +- tk >=8.6.13,<8.7.0a0 +- tzdata +- zstd >=1.5.7,<1.6.0a0 +license: Python-2.0 +size: 36702440 +timestamp: 1770675584356 +python_site_packages_path: lib/python3.14/site-packages +- conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda +sha256: 74e417a768f59f02a242c25e7db0aa796627b5bc8c818863b57786072aeb85e5 +md5: 130584ad9f3a513cdd71b1fdc1244e9c +depends: +- python >=3.10 +license: BSD-3-Clause +license_family: BSD +size: 27848 +timestamp: 1772388605021 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.3-h4df99d1_101.conda +sha256: 233aebd94c704ac112afefbb29cf4170b7bc606e22958906f2672081bc50638a +md5: 235765e4ea0d0301c75965985163b5a1 +depends: +- cpython 3.14.3.* +- python_abi * *_cp314 +license: Python-2.0 +size: 50062 +timestamp: 1770674497152 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-kaleido-0.2.1-pyhd8ed1ab_0.tar.bz2 +sha256: e17bf63a30aec33432f1ead86e15e9febde9fc40a7f869c0e766be8d2db44170 +md5: 310259a5b03ff02289d7705f39e2b1d2 +depends: +- kaleido-core 0.2.1.* +- python >=3.5 +license: MIT +license_family: MIT +size: 18320 +timestamp: 1615204747600 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda +build_number: 8 +sha256: ad6d2e9ac39751cc0529dd1566a26751a0bf2542adb0c232533d32e176e21db5 +md5: 0539938c55b6b1a59b560e843ad864a4 +constrains: +- python 3.14.* *_cp314 +license: BSD-3-Clause +license_family: BSD +size: 6989 +timestamp: 1752805904792 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py314h67df5f8_1.conda +sha256: b318fb070c7a1f89980ef124b80a0b5ccf3928143708a85e0053cde0169c699d +md5: 2035f68f96be30dc60a5dfd7452c7941 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +- yaml >=0.2.5,<0.3.0a0 +license: MIT +license_family: MIT +size: 202391 +timestamp: 1770223462836 +- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda +sha256: 12ffde5a6f958e285aa22c191ca01bbd3d6e710aa852e00618fa6ddc59149002 +md5: d7d95fc8287ea7bf33e0e7116d2b95ec +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- ncurses >=6.5,<7.0a0 +license: GPL-3.0-only +license_family: GPL +size: 345073 +timestamp: 1765813471974 +- conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda +sha256: 0577eedfb347ff94d0f2fa6c052c502989b028216996b45c7f21236f25864414 +md5: 870293df500ca7e18bedefa5838a22ab +depends: +- attrs >=22.2.0 +- python >=3.10 +- rpds-py >=0.7.0 +- typing_extensions >=4.4.0 +- python +license: MIT +license_family: MIT +size: 51788 +timestamp: 1760379115194 +- conda: https://conda.anaconda.org/conda-forge/linux-64/regex-2026.2.28-py314h5bd0f2a_0.conda +sha256: e085e336f1446f5263a3ec9747df8c719b6996753901181add50dc4fdd8bb2e8 +md5: 3c8b6a8c4d0ff5a264e9831eac4941f4 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +license: Apache-2.0 AND CNRI-Python +license_family: PSF +size: 411924 +timestamp: 1772255161535 +- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda +sha256: 7813c38b79ae549504b2c57b3f33394cea4f2ad083f0994d2045c2e24cb538c5 +md5: c65df89a0b2e321045a9e01d1337b182 +depends: +- python >=3.10 +- certifi >=2017.4.17 +- charset-normalizer >=2,<4 +- idna >=2.5,<4 +- urllib3 >=1.21.1,<3 +- python +constrains: +- chardet >=3.0.2,<6 +license: Apache-2.0 +license_family: APACHE +size: 63602 +timestamp: 1766926974520 +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-14.3.3-pyhcf101f3_0.conda +sha256: b06ce84d6a10c266811a7d3adbfa1c11f13393b91cc6f8a5b468277d90be9590 +md5: 7a6289c50631d620652f5045a63eb573 +depends: +- markdown-it-py >=2.2.0 +- pygments >=2.13.0,<3.0.0 +- python >=3.10 +- typing_extensions >=4.0.0,<5.0.0 +- python +license: MIT +license_family: MIT +size: 208472 +timestamp: 1771572730357 +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-click-1.9.7-pyh8f84b5b_0.conda +sha256: aa3fcb167321bae51998de2e94d199109c9024f25a5a063cb1c28d8f1af33436 +md5: 0c20a8ebcddb24a45da89d5e917e6cb9 +depends: +- python >=3.10 +- rich >=12 +- click >=8 +- typing-extensions >=4 +- __unix +- python +license: MIT +license_family: MIT +size: 64356 +timestamp: 1769850479089 +- conda: https://conda.anaconda.org/conda-forge/linux-64/rpds-py-0.30.0-py314h2e6c369_0.conda +sha256: e53b0cbf3b324eaa03ca1fe1a688fdf4ab42cea9c25270b0a7307d8aaaa4f446 +md5: c1c368b5437b0d1a68f372ccf01cb133 +depends: +- python +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- python_abi 3.14.* *_cp314 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 376121 +timestamp: 1764543122774 +- conda: https://conda.anaconda.org/conda-forge/noarch/spectra-0.0.11-pyhd8ed1ab_2.conda +sha256: 7c65782d2511738e62c70462e89d65da4fa54d5a7e47c46667bcd27a59f81876 +md5: 472239e4eb7b5a84bb96b3ed7e3a596a +depends: +- colormath >=3.0.0 +- python >=3.9 +license: MIT +license_family: MIT +size: 22284 +timestamp: 1735770589188 +- conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.52.0-h04a0ce9_0.conda +sha256: c9af81e7830d9c4b67a7f48e512d060df2676b29cac59e3b31f09dbfcee29c58 +md5: 7d9d7efe9541d4bb71b5934e8ee348ea +depends: +- __glibc >=2.17,<3.0.a0 +- icu >=78.2,<79.0a0 +- libgcc >=14 +- libsqlite 3.52.0 hf4e2dac_0 +- libzlib >=1.3.1,<2.0a0 +- ncurses >=6.5,<7.0a0 +- readline >=8.3,<9.0a0 +license: blessing +size: 203641 +timestamp: 1772818888368 +- conda: https://conda.anaconda.org/conda-forge/linux-64/tiktoken-0.12.0-py314h67fec18_3.conda +sha256: 7e395d67fd249d901beb1ae269057763c0d8c3ee5f7a348694bdb16d158a37d9 +md5: d705f9d8a1185a2b01cced191177a028 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +- regex >=2022.1.18 +- requests >=2.26.0 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 939648 +timestamp: 1764028306357 +- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda +sha256: cafeec44494f842ffeca27e9c8b0c27ed714f93ac77ddadc6aaf726b5554ebac +md5: cffd3bdd58090148f4cfcd831f4b26ab +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libzlib >=1.3.1,<2.0a0 +constrains: +- xorg-libx11 >=1.8.12,<2.0a0 +license: TCL +license_family: BSD +size: 3301196 +timestamp: 1769460227866 +- conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda +sha256: 9ef8e47cf00e4d6dcc114eb32a1504cc18206300572ef14d76634ba29dfe1eb6 +md5: e5ce43272193b38c2e9037446c1d9206 +depends: +- python >=3.10 +- __unix +- python +license: MPL-2.0 and MIT +size: 94132 +timestamp: 1770153424136 +- conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.1-pyhd8ed1ab_0.conda +sha256: 39d8ae33c43cdb8f771373e149b0b4fae5a08960ac58dcca95b2f1642bb17448 +md5: 260af1b0a94f719de76b4e14094e9a3b +depends: +- importlib-metadata >=3.6 +- python >=3.10 +- typing-extensions >=4.10.0 +- typing_extensions >=4.14.0 +constrains: +- pytest >=7 +license: MIT +license_family: MIT +size: 36838 +timestamp: 1771532971545 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda +sha256: 7c2df5721c742c2a47b2c8f960e718c930031663ac1174da67c1ed5999f7938c +md5: edd329d7d3a4ab45dcf905899a7a6115 +depends: +- typing_extensions ==4.15.0 pyhcf101f3_0 +license: PSF-2.0 +license_family: PSF +size: 91383 +timestamp: 1756220668932 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhd8ed1ab_1.conda +sha256: 70db27de58a97aeb7ba7448366c9853f91b21137492e0b4430251a1870aa8ff4 +md5: a0a4a3035667fc34f29bfbd5c190baa6 +depends: +- python >=3.10 +- typing_extensions >=4.12.0 +license: MIT +license_family: MIT +size: 18923 +timestamp: 1764158430324 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda +sha256: 032271135bca55aeb156cee361c81350c6f3fb203f57d024d7e5a1fc9ef18731 +md5: 0caa1af407ecff61170c9437a808404d +depends: +- python >=3.10 +- python +license: PSF-2.0 +license_family: PSF +size: 51692 +timestamp: 1756220668932 +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda +sha256: 1d30098909076af33a35017eed6f2953af1c769e273a0626a04722ac4acaba3c +md5: ad659d0a2b3e47e38d829aa8cad2d610 +license: LicenseRef-Public-Domain +size: 119135 +timestamp: 1767016325805 +- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda +sha256: af641ca7ab0c64525a96fd9ad3081b0f5bcf5d1cbb091afb3f6ed5a9eee6111a +md5: 9272daa869e03efe68833e3dc7a02130 +depends: +- backports.zstd >=1.0.0 +- brotli-python >=1.2.0 +- h2 >=4,<5 +- pysocks >=1.5.6,<2.0,!=1.5.7 +- python >=3.10 +license: MIT +license_family: MIT +size: 103172 +timestamp: 1767817860341 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb03c661_1.conda +sha256: 6bc6ab7a90a5d8ac94c7e300cc10beb0500eeba4b99822768ca2f2ef356f731b +md5: b2895afaf55bf96a8c8282a2e47a5de0 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 15321 +timestamp: 1762976464266 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_1.conda +sha256: 25d255fb2eef929d21ff660a0c687d38a6d2ccfbcbf0cc6aa738b12af6e9d142 +md5: 1dafce8548e38671bea82e3f5c6ce22f +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 20591 +timestamp: 1762976546182 +- conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda +sha256: 6d9ea2f731e284e9316d95fa61869fe7bbba33df7929f82693c121022810f4ad +md5: a77f85f77be52ff59391544bfe73390a +depends: +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +license: MIT +license_family: MIT +size: 85189 +timestamp: 1753484064210 +- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda +sha256: b4533f7d9efc976511a73ef7d4a2473406d7f4c750884be8e8620b0ce70f4dae +md5: 30cd29cb87d819caead4d55184c1d115 +depends: +- python >=3.10 +- python +license: MIT +license_family: MIT +size: 24194 +timestamp: 1764460141901 +- conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.3.3-hceb46e0_1.conda +sha256: ea4e50c465d70236408cb0bfe0115609fd14db1adcd8bd30d8918e0291f8a75f +md5: 2aadb0d17215603a82a2a6b0afd9a4cb +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +license: Zlib +license_family: Other +size: 122618 +timestamp: 1770167931827 +- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda +sha256: 68f0206ca6e98fea941e5717cec780ed2873ffabc0e1ed34428c061e2c6268c7 +md5: 4a13eeac0b5c8e5b8ab496e6c4ddd829 +depends: +- __glibc >=2.17,<3.0.a0 +- libzlib >=1.3.1,<2.0a0 +license: BSD-3-Clause +license_family: BSD +size: 601375 +timestamp: 1764777111296 diff --git a/modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-db7c73dae76bc9e6_1.txt b/modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-db7c73dae76bc9e6_1.txt new file mode 100644 index 000000000..a55a4d49d --- /dev/null +++ b/modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-db7c73dae76bc9e6_1.txt @@ -0,0 +1,126 @@ + +# This file may be used to create an environment using: +# $ conda create --name --file +# platform: linux-64 +@EXPLICIT +https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda#239c5e9546c38a1e884d69effcf4c882 +https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda#a9f577daf3de00bca7c3c76c0ecbd1de +https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda#0aa00f03f9e39fb9876085dee11a85d4 +https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda#d2ffd7602c02f2b316fd921d39876885 +https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda#d87ff7921124eccd67248aa483c23fec +https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda#4a13eeac0b5c8e5b8ab496e6c4ddd829 +https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda#18335a698559cdbcd86150a48bf54ba6 +https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.5-hecca717_0.conda#49f570f3bc4c874a06ea69b7225753af +https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda#a360c33a5abe61c07959e449fa1453eb +https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda#b88d90cad08e6bc8ad540cb310a761fb +https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda#2c21e66f50753a083cbe6b80f38268fa +https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda#1b08cd684f34175e4514474793d44bcb +https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-h33c6efd_0.conda#c80d8a3b84358cb967fa81e7075fbc8a +https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.0-hf4e2dac_0.conda#810d83373448da85c3f673fbcb7ad3a3 +https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda#38ffe67b78c9d4de527be8315e5ada2c +https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda#47e340acb35de30501a76c7c799c41d7 +https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda#e18ad67cf881dcadee8b8d9e2f8e5f73 +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda#da1b85b6a87e141f5140bb9924cecab0 +https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda#0539938c55b6b1a59b560e843ad864a4 +https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda#d7d95fc8287ea7bf33e0e7116d2b95ec +https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda#cffd3bdd58090148f4cfcd831f4b26ab +https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda#ad659d0a2b3e47e38d829aa8cad2d610 +https://conda.anaconda.org/conda-forge/linux-64/python-3.14.4-habeac84_100_cp314.conda#a443f87920815d41bfe611296e507995 +https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.4-py314hd8ed1ab_100.conda#f111d4cfaf1fe9496f386bc98ae94452 +https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.4-h4df99d1_100.conda#e4e60721757979d01d3964122f674959 +https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda#aaa2a381ccc56eac91d63b6c1240312f +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda#0caa1af407ecff61170c9437a808404d +https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda#edd329d7d3a4ab45dcf905899a7a6115 +https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda#2934f256a8acfe48f6ebb4fce6cde29c +https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda#c6b0543676ecb1fb2d7643941fe375f2 +https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda#a2ac7763a9ac75055b68f325d3255265 +https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py314h3de4e8d_1.conda#8910d2c46f7e7b519129f486e0fe927a +https://conda.anaconda.org/conda-forge/noarch/certifi-2026.4.22-pyhd8ed1ab_0.conda#929471569c93acefb30282a22060dcd5 +https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda#a9167b9571f3baa9d448faa2139d1089 +https://conda.anaconda.org/conda-forge/noarch/click-8.3.2-pyhc90fa1f_0.conda#4d18bc3af7cfcea97bd817164672a08c +https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda#7fe569c10905402ed47024fc481bb371 +https://conda.anaconda.org/conda-forge/noarch/coloredlogs-15.0.1-pyhd8ed1ab_4.conda#b866ff7007b934d564961066c8195983 +https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda#a2c1eeadae7a309daed9d62c96012a2b +https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_18.conda#646855f357199a12f02a87382d429b75 +https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_18.conda#9063115da5bc35fdc3e1002e69b9ef6e +https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.32-pthreads_h94d23a6_0.conda#89d61bc91d3f39fda0ca10fcd3c68594 +https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-6_h4a7cf45_openblas.conda#6d6d225559bfa6e2f3c90ee9c03d4e2e +https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-6_h0358290_openblas.conda#36ae340a916635b97ac8a0655ace2a35 +https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-6_h47877c9_openblas.conda#881d801569b201c2e753f03c84b85e15 +https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.3-py314h2b28147_0.conda#36f5b7eb328bdc204954a2225cf908e2 +https://conda.anaconda.org/conda-forge/noarch/colormath-3.0.0-pyhd8ed1ab_4.conda#071cf7b0ce333c81718b054066c15102 +https://conda.anaconda.org/conda-forge/linux-64/expat-2.7.5-hecca717_0.conda#7de50d165039df32d38be74c1b34a910 +https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2#0c96522c6bdaed4b1566d11387caaf45 +https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 +https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb +https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda#49023d73832ef61042f6a237cb2687e7 +https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h421ea60_0.conda#eba48a68a1a2b9d3c0d9511548db85db +https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.3-h73754d4_0.conda#fb16b4b69e3f1dcfe79d80db8fd0c55d +https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.3-ha770c72_0.conda#e289f3d17880e44b633ba911d57a321b +https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.17.1-h27c8c51_0.conda#867127763fbe935bab59815b6e0b7b5c +https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda#a7970cd949a077b7cb9696379d338681 +https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda#0a802cb9888dd14eeefc611f05c40b6e +https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda#8e6923fc12f1fe8f8c4e5c9f343256ac +https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda#164fc43f0b53b6e3a7bc7dce5e4f1dc9 +https://conda.anaconda.org/conda-forge/noarch/humanize-4.15.0-pyhd8ed1ab_0.conda#daddf757c3ecd6067b9af1df1f25d89e +https://conda.anaconda.org/conda-forge/noarch/idna-3.13-pyhcf101f3_0.conda#fb7130c190f9b4ec91219840a05ba3ac +https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.1-pyhcf101f3_0.conda#e1c36c6121a7c9c76f2f148f1e83b983 +https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda#080594bf4493e6bae2607e65390c520a +https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py314h67df5f8_1.conda#9a17c4307d23318476d7fbf0fedc0cde +https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda#04558c96691bed63104678757beb4f8d +https://conda.anaconda.org/conda-forge/linux-64/rpds-py-0.30.0-py314h2e6c369_0.conda#c1c368b5437b0d1a68f372ccf01cb133 +https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda#870293df500ca7e18bedefa5838a22ab +https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda#439cd0f567d697b20a8f45cb70a1005a +https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda#ada41c863af263cc4c5fcbaff7c3e4dc +https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda#d5e96b1ed75ca01906b3d2469b4ce493 +https://conda.anaconda.org/conda-forge/linux-64/mathjax-2.7.7-ha770c72_3.tar.bz2#86e69bd82c2a2c6fd29f5ab7e02b3691 +https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda#e235d5566c9cc8970eb2798dd4ecf62f +https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda#567fbeed956c200c1db5782a424e58ee +https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.53.0-h04a0ce9_0.conda#dc540e5bd5616d83a1ec46af8315ff98 +https://conda.anaconda.org/conda-forge/linux-64/kaleido-core-0.2.1-h3644ca4_0.tar.bz2#b3723b235b0758abaae8c82ce4d80146 +https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.4.1-hb03c661_0.conda#6178c6f2fb254558238ef4e6c56fb782 +https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda#a752488c68f2e7c456bcbd8f16eec275 +https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda#6c77a605a7a689d17d4819c0f8ac9a00 +https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda#aea31d2e5b1091feca96fcfe945c3cf9 +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda#cd5a90476766d53e901500df9215e927 +https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.18-h0c24ade_0.conda#6f2e2c8f58160147c4d1c6f4c14cbac4 +https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda#b3c17d95b5a10c6e64a21fa17573e70e +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb03c661_1.conda#b2895afaf55bf96a8c8282a2e47a5de0 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_1.conda#1dafce8548e38671bea82e3f5c6ce22f +https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda#92ed62436b625154323d40d5f2f11dd7 +https://conda.anaconda.org/conda-forge/noarch/markdown-3.10.2-pyhcf101f3_0.conda#ba0a9221ce1063f31692c07370d062f3 +https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda#592132998493b3ff25fd7479396e8351 +https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda#5b5203189eb668f042ac2b0826244964 +https://conda.anaconda.org/conda-forge/noarch/natsort-8.4.0-pyhcf101f3_2.conda#e941e85e273121222580723010bd4fa2 +https://conda.anaconda.org/conda-forge/noarch/packaging-26.1-pyhc364b38_0.conda#b8ae38639d323d808da535fb71e31be8 +https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda#11b3379b191f63139e29c0d19dee24cd +https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.3.3-hceb46e0_1.conda#2aadb0d17215603a82a2a6b0afd9a4cb +https://conda.anaconda.org/conda-forge/linux-64/pillow-12.2.0-py314h8ec4b1a_0.conda#76c4757c0ec9d11f969e8eb44899307b +https://conda.anaconda.org/conda-forge/noarch/narwhals-2.20.0-pyhcf101f3_0.conda#6cac1a50359219d786453c6fef819f98 +https://conda.anaconda.org/conda-forge/noarch/plotly-6.6.0-pyhd8ed1ab_0.conda#3e9427ee186846052e81fadde8ebe96a +https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-32-1.40.0-py310hffdcd12_0.conda#8eacf9ff4d4e1ca1b52f8f3ba3e0c993 +https://conda.anaconda.org/conda-forge/noarch/polars-1.40.0-pyh58ad624_0.conda#fd16be490f5403adfbf27dd4901bbe34 +https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-compat-1.40.0-py310hbcd5346_0.conda#03a6899e17bb731c8e21b08212f1a64c +https://conda.anaconda.org/conda-forge/noarch/polars-lts-cpu-1.34.0.deprecated-hc364b38_0.conda#ef0340e75068ac8ff96462749b5c98e7 +https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda#a77f85f77be52ff59391544bfe73390a +https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py314h67df5f8_1.conda#2035f68f96be30dc60a5dfd7452c7941 +https://conda.anaconda.org/conda-forge/noarch/pyaml-env-1.2.2-pyhd8ed1ab_0.conda#e17be1016bcc3516827b836cd3e4d9dc +https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.46.3-py314h2e6c369_0.conda#1f3fd537f929b8d3236f9f0f0e7f7a32 +https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhd8ed1ab_1.conda#a0a4a3035667fc34f29bfbd5c190baa6 +https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.3-pyhcf101f3_0.conda#f690e6f204efd2e5c06b57518a383d98 +https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda#130584ad9f3a513cdd71b1fdc1244e9c +https://conda.anaconda.org/conda-forge/noarch/python-kaleido-0.2.1-pyhd8ed1ab_0.tar.bz2#310259a5b03ff02289d7705f39e2b1d2 +https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda#461219d1a5bd61342293efa2c0c90eac +https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda#9272daa869e03efe68833e3dc7a02130 +https://conda.anaconda.org/conda-forge/noarch/requests-2.33.1-pyhcf101f3_0.conda#10afbb4dbf06ff959ad25a92ccee6e59 +https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda#16c18772b340887160c79a6acc022db0 +https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda#0242025a3c804966bf71aa04eee82f66 +https://conda.anaconda.org/conda-forge/noarch/rich-click-1.9.7-pyh8f84b5b_0.conda#0c20a8ebcddb24a45da89d5e917e6cb9 +https://conda.anaconda.org/conda-forge/noarch/spectra-0.0.11-pyhd8ed1ab_2.conda#472239e4eb7b5a84bb96b3ed7e3a596a +https://conda.anaconda.org/conda-forge/linux-64/regex-2026.4.4-py314h5bd0f2a_0.conda#4ffb42385183c854564f1f9adcf80a63 +https://conda.anaconda.org/conda-forge/linux-64/tiktoken-0.12.0-py314h67fec18_3.conda#d705f9d8a1185a2b01cced191177a028 +https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda#e5ce43272193b38c2e9037446c1d9206 +https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.1-pyhd8ed1ab_0.conda#260af1b0a94f719de76b4e14094e9a3b +https://conda.anaconda.org/bioconda/noarch/multiqc-1.34-pyhdfd78af_0.conda#a7111ab9a6a6146b40cbce16655ac873 +https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh145f28c_0.conda#09a970fbf75e8ed1aa633827ded6aa4f +https://conda.anaconda.org/conda-forge/linux-64/procps-ng-4.0.6-h18c060e_0.conda#f2c23a77b25efcad57d377b34bd84941 diff --git a/modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-40bf3b435e89dc22_1.txt b/modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-40bf3b435e89dc22_1.txt new file mode 100644 index 000000000..a58231a01 --- /dev/null +++ b/modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-40bf3b435e89dc22_1.txt @@ -0,0 +1,1502 @@ + +version: 6 +environments: +default: +channels: +- url: https://conda.anaconda.org/conda-forge/ +- url: https://conda.anaconda.org/bioconda/ +- url: https://conda.anaconda.org/bioconda/ +options: +pypi-prerelease-mode: if-necessary-or-explicit +packages: +linux-aarch64: +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-python-1.2.0-py314h352cb57_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.1-pyh8f84b5b_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/coloredlogs-15.0.1-pyhd8ed1ab_4.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/colormath-3.0.0-pyhd8ed1ab_4.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.3-py314hd8ed1ab_101.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/expat-2.7.4-hfae3067_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/fontconfig-2.17.1-hba86a56_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/humanize-4.15.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/icu-78.3-hcab7f73_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/kaleido-core-0.2.1-he5a581e_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lcms2-2.18-h9d5b58d_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.45.1-default_h1979696_102.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lerc-4.1.0-h52b7260_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libblas-3.11.0-5_haddc8a3_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcblas-3.11.0-5_hd72aa62_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libdeflate-1.25-h1af38f5_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.7.4-hfae3067_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype-2.14.3-h8af1aa0_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype6-2.14.3-hdae7a39_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-15.2.0-he9431aa_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-15.2.0-he9431aa_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-15.2.0-h1b7bec0_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libjpeg-turbo-3.1.2-he30d5cf_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblapack-3.11.0-5_h88aeb00_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.2-he30d5cf_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopenblas-0.3.30-pthreads_h9d3fd7e_4.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libpng-1.6.55-h1abf092_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.52.0-h10b116e_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_18.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libtiff-4.7.1-hdb009f0_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.41.3-h1022ec0_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libwebp-base-1.6.0-ha2e29f5_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcb-1.17.0-h262b8f6_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_2.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.10.2-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/markupsafe-3.0.3-py314hb76de3f_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/mathjax-2.7.7-h8af1aa0_3.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda +- conda: https://conda.anaconda.org/bioconda/noarch/multiqc-1.33-pyhdfd78af_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.18.1-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/natsort-8.4.0-pyhcf101f3_2.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.5-ha32ae93_3.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/nspr-4.38-h3ad9384_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/nss-3.118-h544fa81_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-2.4.3-py314haac167e_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openjpeg-2.5.4-h5da879a_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.1-h546c87b_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pillow-12.1.1-py314hac3e5ec_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/plotly-6.6.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.39.3-pyh58ad624_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-lts-cpu-1.34.0.deprecated-hc364b38_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/polars-runtime-32-1.39.3-py310hff09b76_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/polars-runtime-compat-1.39.3-py310hf00a4a2_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/procps-ng-4.0.6-h1779866_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pthread-stubs-0.4-h86ecc28_1002.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pyaml-env-1.2.2-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pydantic-core-2.41.5-py314h451b6cc_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.3-hb06a95a_101_cp314.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.3-h4df99d1_101.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python-kaleido-0.2.1-pyhd8ed1ab_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py314h807365f_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/regex-2026.2.28-py314h51f160d_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-14.3.3-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-click-1.9.7-pyh8f84b5b_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/rpds-py-0.30.0-py314h02b7a91_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/spectra-0.0.11-pyhd8ed1ab_2.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/sqlite-3.52.0-hf1c7be2_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tiktoken-0.12.0-py314h6a36e60_3.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h0dc03b3_103.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.1-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhd8ed1ab_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxau-1.0.12-he30d5cf_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxdmcp-1.1.5-he30d5cf_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zlib-ng-2.3.3-ha7cb516_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda +packages: +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda +build_number: 20 +sha256: a2527b1d81792a0ccd2c05850960df119c2b6d8f5fdec97f2db7d25dc23b1068 +md5: 468fd3bb9e1f671d36c2cbc677e56f1d +depends: +- libgomp >=7.5.0 +constrains: +- openmp_impl <0.0a0 +license: BSD-3-Clause +license_family: BSD +size: 28926 +timestamp: 1770939656741 +- conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda +sha256: a3967b937b9abf0f2a99f3173fa4630293979bd1644709d89580e7c62a544661 +md5: aaa2a381ccc56eac91d63b6c1240312f +depends: +- cpython +- python-gil +license: MIT +license_family: MIT +size: 8191 +timestamp: 1744137672556 +- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda +sha256: e0ea1ba78fbb64f17062601edda82097fcf815012cf52bb704150a2668110d48 +md5: 2934f256a8acfe48f6ebb4fce6cde29c +depends: +- python >=3.9 +- typing-extensions >=4.0.0 +license: MIT +license_family: MIT +size: 18074 +timestamp: 1733247158254 +- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda +sha256: 1b6124230bb4e571b1b9401537ecff575b7b109cc3a21ee019f65e083b8399ab +md5: c6b0543676ecb1fb2d7643941fe375f2 +depends: +- python >=3.10 +- python +license: MIT +license_family: MIT +size: 64927 +timestamp: 1773935801332 +- conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda +noarch: generic +sha256: c31ab719d256bc6f89926131e88ecd0f0c5d003fe8481852c6424f4ec6c7eb29 +md5: a2ac7763a9ac75055b68f325d3255265 +depends: +- python >=3.14 +license: BSD-3-Clause AND MIT AND EPL-2.0 +size: 7514 +timestamp: 1767044983590 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-python-1.2.0-py314h352cb57_1.conda +sha256: 5a5b0cdcd7ed89c6a8fb830924967f6314a2b71944bc1ebc2c105781ba97aa75 +md5: a1b5c571a0923a205d663d8678df4792 +depends: +- libgcc >=14 +- libstdcxx >=14 +- python >=3.14,<3.15.0a0 +- python >=3.14,<3.15.0a0 *_cp314 +- python_abi 3.14.* *_cp314 +constrains: +- libbrotlicommon 1.2.0 he30d5cf_1 +license: MIT +license_family: MIT +size: 373193 +timestamp: 1764017486851 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda +sha256: b3495077889dde6bb370938e7db82be545c73e8589696ad0843a32221520ad4c +md5: 840d8fc0d7b3209be93080bc20e07f2d +depends: +- libgcc >=14 +license: bzip2-1.0.6 +license_family: BSD +size: 192412 +timestamp: 1771350241232 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda +sha256: 67cc7101b36421c5913a1687ef1b99f85b5d6868da3abbf6ec1a4181e79782fc +md5: 4492fd26db29495f0ba23f146cd5638d +depends: +- __unix +license: ISC +size: 147413 +timestamp: 1772006283803 +- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda +sha256: a6b118fd1ed6099dc4fc03f9c492b88882a780fadaef4ed4f93dc70757713656 +md5: 765c4d97e877cdbbb88ff33152b86125 +depends: +- python >=3.10 +license: ISC +size: 151445 +timestamp: 1772001170301 +- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda +sha256: d86dfd428b2e3c364fa90e07437c8405d635aa4ef54b25ab51d9c712be4112a5 +md5: 49ee13eb9b8f44d63879c69b8a40a74b +depends: +- python >=3.10 +license: MIT +license_family: MIT +size: 58510 +timestamp: 1773660086450 +- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.1-pyh8f84b5b_1.conda +sha256: 38cfe1ee75b21a8361c8824f5544c3866f303af1762693a178266d7f198e8715 +md5: ea8a6c3256897cc31263de9f455e25d9 +depends: +- python >=3.10 +- __unix +- python +license: BSD-3-Clause +license_family: BSD +size: 97676 +timestamp: 1764518652276 +- conda: https://conda.anaconda.org/conda-forge/noarch/coloredlogs-15.0.1-pyhd8ed1ab_4.conda +sha256: 8021c76eeadbdd5784b881b165242db9449783e12ce26d6234060026fd6a8680 +md5: b866ff7007b934d564961066c8195983 +depends: +- humanfriendly >=9.1 +- python >=3.9 +license: MIT +license_family: MIT +size: 43758 +timestamp: 1733928076798 +- conda: https://conda.anaconda.org/conda-forge/noarch/colormath-3.0.0-pyhd8ed1ab_4.conda +sha256: 59c9e29800b483b390467f90e82b0da3a4fbf0612efe1c90813fca232780e160 +md5: 071cf7b0ce333c81718b054066c15102 +depends: +- networkx >=2.0 +- numpy +- python >=3.9 +license: BSD-3-Clause +license_family: BSD +size: 39326 +timestamp: 1735759976140 +- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.3-py314hd8ed1ab_101.conda +noarch: generic +sha256: 91b06300879df746214f7363d6c27c2489c80732e46a369eb2afc234bcafb44c +md5: 3bb89e4f795e5414addaa531d6b1500a +depends: +- python >=3.14,<3.15.0a0 +- python_abi * *_cp314 +license: Python-2.0 +size: 50078 +timestamp: 1770674447292 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/expat-2.7.4-hfae3067_0.conda +sha256: 5f087bef054c681edcaae84a8c2230585b938691e371ff92957a30707b7fcdf7 +md5: b304307db639831ad7caabd2eac6fca6 +depends: +- libexpat 2.7.4 hfae3067_0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 137701 +timestamp: 1771259543650 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 +sha256: 58d7f40d2940dd0a8aa28651239adbf5613254df0f75789919c4e6762054403b +md5: 0c96522c6bdaed4b1566d11387caaf45 +license: BSD-3-Clause +license_family: BSD +size: 397370 +timestamp: 1566932522327 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 +sha256: c52a29fdac682c20d252facc50f01e7c2e7ceac52aa9817aaf0bb83f7559ec5c +md5: 34893075a5c9e55cdafac56607368fc6 +license: OFL-1.1 +license_family: Other +size: 96530 +timestamp: 1620479909603 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2 +sha256: 00925c8c055a2275614b4d983e1df637245e19058d79fc7dd1a93b8d9fb4b139 +md5: 4d59c254e01d9cde7957100457e2d5fb +license: OFL-1.1 +license_family: Other +size: 700814 +timestamp: 1620479612257 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda +sha256: 2821ec1dc454bd8b9a31d0ed22a7ce22422c0aef163c59f49dfdf915d0f0ca14 +md5: 49023d73832ef61042f6a237cb2687e7 +license: LicenseRef-Ubuntu-Font-Licence-Version-1.0 +license_family: Other +size: 1620504 +timestamp: 1727511233259 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/fontconfig-2.17.1-hba86a56_0.conda +sha256: 835aff8615dd8d8fff377679710ce81b8a2c47b6404e21a92fb349fda193a15c +md5: 0fed1ff55f4938a65907f3ecf62609db +depends: +- libexpat >=2.7.4,<3.0a0 +- libfreetype >=2.14.1 +- libfreetype6 >=2.14.1 +- libgcc >=14 +- libuuid >=2.41.3,<3.0a0 +- libzlib >=1.3.1,<2.0a0 +license: MIT +license_family: MIT +size: 279044 +timestamp: 1771382728182 +- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda +sha256: 54eea8469786bc2291cc40bca5f46438d3e062a399e8f53f013b6a9f50e98333 +md5: a7970cd949a077b7cb9696379d338681 +depends: +- font-ttf-ubuntu +- font-ttf-inconsolata +- font-ttf-dejavu-sans-mono +- font-ttf-source-code-pro +license: BSD-3-Clause +license_family: BSD +size: 4059 +timestamp: 1762351264405 +- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda +sha256: 84c64443368f84b600bfecc529a1194a3b14c3656ee2e832d15a20e0329b6da3 +md5: 164fc43f0b53b6e3a7bc7dce5e4f1dc9 +depends: +- python >=3.10 +- hyperframe >=6.1,<7 +- hpack >=4.1,<5 +- python +license: MIT +license_family: MIT +size: 95967 +timestamp: 1756364871835 +- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda +sha256: 6ad78a180576c706aabeb5b4c8ceb97c0cb25f1e112d76495bff23e3779948ba +md5: 0a802cb9888dd14eeefc611f05c40b6e +depends: +- python >=3.9 +license: MIT +license_family: MIT +size: 30731 +timestamp: 1737618390337 +- conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda +sha256: fa2071da7fab758c669e78227e6094f6b3608228740808a6de5d6bce83d9e52d +md5: 7fe569c10905402ed47024fc481bb371 +depends: +- __unix +- python >=3.9 +license: MIT +license_family: MIT +size: 73563 +timestamp: 1733928021866 +- conda: https://conda.anaconda.org/conda-forge/noarch/humanize-4.15.0-pyhd8ed1ab_0.conda +sha256: 6c4343b376d0b12a4c75ab992640970d36c933cad1fd924f6a1181fa91710e80 +md5: daddf757c3ecd6067b9af1df1f25d89e +depends: +- python >=3.10 +license: MIT +license_family: MIT +size: 67994 +timestamp: 1766267728652 +- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda +sha256: 77af6f5fe8b62ca07d09ac60127a30d9069fdc3c68d6b256754d0ffb1f7779f8 +md5: 8e6923fc12f1fe8f8c4e5c9f343256ac +depends: +- python >=3.9 +license: MIT +license_family: MIT +size: 17397 +timestamp: 1737618427549 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/icu-78.3-hcab7f73_0.conda +sha256: 49ba6aed2c6b482bb0ba41078057555d29764299bc947b990708617712ef6406 +md5: 546da38c2fa9efacf203e2ad3f987c59 +depends: +- libgcc >=14 +- libstdcxx >=14 +license: MIT +license_family: MIT +size: 12837286 +timestamp: 1773822650615 +- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda +sha256: ae89d0299ada2a3162c2614a9d26557a92aa6a77120ce142f8e0109bbf0342b0 +md5: 53abe63df7e10a6ba605dc5f9f961d36 +depends: +- python >=3.10 +license: BSD-3-Clause +license_family: BSD +size: 50721 +timestamp: 1760286526795 +- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda +sha256: 82ab2a0d91ca1e7e63ab6a4939356667ef683905dea631bc2121aa534d347b16 +md5: 080594bf4493e6bae2607e65390c520a +depends: +- python >=3.10 +- zipp >=3.20 +- python +license: Apache-2.0 +license_family: APACHE +size: 34387 +timestamp: 1773931568510 +- conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda +sha256: fc9ca7348a4f25fed2079f2153ecdcf5f9cf2a0bc36c4172420ca09e1849df7b +md5: 04558c96691bed63104678757beb4f8d +depends: +- markupsafe >=2.0 +- python >=3.10 +- python +license: BSD-3-Clause +license_family: BSD +size: 120685 +timestamp: 1764517220861 +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda +sha256: db973a37d75db8e19b5f44bbbdaead0c68dde745407f281e2a7fe4db74ec51d7 +md5: ada41c863af263cc4c5fcbaff7c3e4dc +depends: +- attrs >=22.2.0 +- jsonschema-specifications >=2023.3.6 +- python >=3.10 +- referencing >=0.28.4 +- rpds-py >=0.25.0 +- python +license: MIT +license_family: MIT +size: 82356 +timestamp: 1767839954256 +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda +sha256: 0a4f3b132f0faca10c89fdf3b60e15abb62ded6fa80aebfc007d05965192aa04 +md5: 439cd0f567d697b20a8f45cb70a1005a +depends: +- python >=3.10 +- referencing >=0.31.0 +- python +license: MIT +license_family: MIT +size: 19236 +timestamp: 1757335715225 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/kaleido-core-0.2.1-he5a581e_0.tar.bz2 +sha256: d3c7f4797566e6f983d16c2a87063a18e4b2d819a66230190a21584d70042755 +md5: 4f0d284f5d11e04277b552eb1c172c7f +depends: +- __glibc >=2.17,<3.0.a0 +- expat >=2.2.10,<3.0.0a0 +- fontconfig +- fonts-conda-forge +- libgcc-ng >=9.3.0 +- mathjax 2.7.* +- nspr >=4.29,<5.0a0 +- nss >=3.62,<4.0a0 +- sqlite >=3.34.0,<4.0a0 +license: MIT +license_family: MIT +size: 65750397 +timestamp: 1615199465742 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lcms2-2.18-h9d5b58d_0.conda +sha256: 379ef5e91a587137391a6149755d0e929f1a007d2dcb211318ac670a46c8596f +md5: bb960f01525b5e001608afef9d47b79c +depends: +- libgcc >=14 +- libjpeg-turbo >=3.1.2,<4.0a0 +- libtiff >=4.7.1,<4.8.0a0 +license: MIT +license_family: MIT +size: 293039 +timestamp: 1768184778398 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.45.1-default_h1979696_102.conda +sha256: 7abd913d81a9bf00abb699e8987966baa2065f5132e37e815f92d90fc6bba530 +md5: a21644fc4a83da26452a718dc9468d5f +depends: +- zstd >=1.5.7,<1.6.0a0 +constrains: +- binutils_impl_linux-aarch64 2.45.1 +license: GPL-3.0-only +license_family: GPL +size: 875596 +timestamp: 1774197520746 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lerc-4.1.0-h52b7260_0.conda +sha256: 8957fd460c1c132c8031f65fd5f56ec3807fd71b7cab2c5e2b0937b13404ab36 +md5: d13423b06447113a90b5b1366d4da171 +depends: +- libgcc >=14 +- libstdcxx >=14 +license: Apache-2.0 +license_family: Apache +size: 240444 +timestamp: 1773114901155 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libblas-3.11.0-5_haddc8a3_openblas.conda +build_number: 5 +sha256: 700f3c03d0fba8e687a345404a45fbabe781c1cf92242382f62cef2948745ec4 +md5: 5afcea37a46f76ec1322943b3c4dfdc0 +depends: +- libopenblas >=0.3.30,<0.3.31.0a0 +- libopenblas >=0.3.30,<1.0a0 +constrains: +- mkl <2026 +- libcblas 3.11.0 5*_openblas +- liblapack 3.11.0 5*_openblas +- liblapacke 3.11.0 5*_openblas +- blas 2.305 openblas +license: BSD-3-Clause +license_family: BSD +size: 18369 +timestamp: 1765818610617 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcblas-3.11.0-5_hd72aa62_openblas.conda +build_number: 5 +sha256: 3fad5c9de161dccb4e42c8b1ae8eccb33f4ed56bccbcced9cbb0956ae7869e61 +md5: 0b2f1143ae2d0aa4c991959d0daaf256 +depends: +- libblas 3.11.0 5_haddc8a3_openblas +constrains: +- liblapack 3.11.0 5*_openblas +- liblapacke 3.11.0 5*_openblas +- blas 2.305 openblas +license: BSD-3-Clause +license_family: BSD +size: 18371 +timestamp: 1765818618899 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libdeflate-1.25-h1af38f5_0.conda +sha256: 48814b73bd462da6eed2e697e30c060ae16af21e9fbed30d64feaf0aad9da392 +md5: a9138815598fe6b91a1d6782ca657b0c +depends: +- libgcc >=14 +license: MIT +license_family: MIT +size: 71117 +timestamp: 1761979776756 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.7.4-hfae3067_0.conda +sha256: 995ce3ad96d0f4b5ed6296b051a0d7b6377718f325bc0e792fbb96b0e369dad7 +md5: 57f3b3da02a50a1be2a6fe847515417d +depends: +- libgcc >=14 +constrains: +- expat 2.7.4.* +license: MIT +license_family: MIT +size: 76564 +timestamp: 1771259530958 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda +sha256: 3df4c539449aabc3443bbe8c492c01d401eea894603087fca2917aa4e1c2dea9 +md5: 2f364feefb6a7c00423e80dcb12db62a +depends: +- libgcc >=14 +license: MIT +license_family: MIT +size: 55952 +timestamp: 1769456078358 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype-2.14.3-h8af1aa0_0.conda +sha256: 752e4f66283d7deb4c6fd47d88df644d8daa2aaa825a54f3bf350a625190192a +md5: a229e22d4d8814a07702b0919d8e6701 +depends: +- libfreetype6 >=2.14.3 +license: GPL-2.0-only OR FTL +size: 8125 +timestamp: 1774301094057 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype6-2.14.3-hdae7a39_0.conda +sha256: 8e6b27fe4eec4c2fa7b7769a21973734c8dba1de80086fb0213e58375ac09f4c +md5: b99ed99e42dafb27889483b3098cace7 +depends: +- libgcc >=14 +- libpng >=1.6.55,<1.7.0a0 +- libzlib >=1.3.2,<2.0a0 +constrains: +- freetype >=2.14.3 +license: GPL-2.0-only OR FTL +size: 422941 +timestamp: 1774301093473 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_18.conda +sha256: 43df385bedc1cab11993c4369e1f3b04b4ca5d0ea16cba6a0e7f18dbc129fcc9 +md5: 552567ea2b61e3a3035759b2fdb3f9a6 +depends: +- _openmp_mutex >=4.5 +constrains: +- libgcc-ng ==15.2.0=*_18 +- libgomp 15.2.0 h8acb6b2_18 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 622900 +timestamp: 1771378128706 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-15.2.0-he9431aa_18.conda +sha256: 83bb0415f59634dccfa8335d4163d1f6db00a27b36666736f9842b650b92cf2f +md5: 4feebd0fbf61075a1a9c2e9b3936c257 +depends: +- libgcc 15.2.0 h8acb6b2_18 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 27568 +timestamp: 1771378136019 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-15.2.0-he9431aa_18.conda +sha256: 7dcd7dff2505d56fd5272a6e712ec912f50a46bf07dc6873a7e853694304e6e4 +md5: 41f261f5e4e2e8cbd236c2f1f15dae1b +depends: +- libgfortran5 15.2.0 h1b7bec0_18 +constrains: +- libgfortran-ng ==15.2.0=*_18 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 27587 +timestamp: 1771378169244 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-15.2.0-h1b7bec0_18.conda +sha256: 85347670dfb4a8d4c13cd7cae54138dcf2b1606b6bede42eef5507bf5f9660c6 +md5: 574d88ce3348331e962cfa5ed451b247 +depends: +- libgcc >=15.2.0 +constrains: +- libgfortran 15.2.0 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 1486341 +timestamp: 1771378148102 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_18.conda +sha256: fc716f11a6a8525e27a5d332ef6a689210b0d2a4dd1133edc0f530659aa9faa6 +md5: 4faa39bf919939602e594253bd673958 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 588060 +timestamp: 1771378040807 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libjpeg-turbo-3.1.2-he30d5cf_0.conda +sha256: 84064c7c53a64291a585d7215fe95ec42df74203a5bf7615d33d49a3b0f08bb6 +md5: 5109d7f837a3dfdf5c60f60e311b041f +depends: +- libgcc >=14 +constrains: +- jpeg <0.0.0a +license: IJG AND BSD-3-Clause AND Zlib +size: 691818 +timestamp: 1762094728337 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblapack-3.11.0-5_h88aeb00_openblas.conda +build_number: 5 +sha256: 692222d186d3ffbc99eaf04b5b20181fd26aee1edec1106435a0a755c57cce86 +md5: 88d1e4133d1182522b403e9ba7435f04 +depends: +- libblas 3.11.0 5_haddc8a3_openblas +constrains: +- liblapacke 3.11.0 5*_openblas +- blas 2.305 openblas +- libcblas 3.11.0 5*_openblas +license: BSD-3-Clause +license_family: BSD +size: 18392 +timestamp: 1765818627104 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.2-he30d5cf_0.conda +sha256: 843c46e20519651a3e357a8928352b16c5b94f4cd3d5481acc48be2e93e8f6a3 +md5: 96944e3c92386a12755b94619bae0b35 +depends: +- libgcc >=14 +constrains: +- xz 5.8.2.* +license: 0BSD +size: 125916 +timestamp: 1768754941722 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_1.conda +sha256: 57c0dd12d506e84541c4e877898bd2a59cca141df493d34036f18b2751e0a453 +md5: 7b9813e885482e3ccb1fa212b86d7fd0 +depends: +- libgcc >=14 +license: BSD-2-Clause +license_family: BSD +size: 114056 +timestamp: 1769482343003 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopenblas-0.3.30-pthreads_h9d3fd7e_4.conda +sha256: 794a7270ea049ec931537874cd8d2de0ef4b3cef71c055cfd8b4be6d2f4228b0 +md5: 11d7d57b7bdd01da745bbf2b67020b2e +depends: +- libgcc >=14 +- libgfortran +- libgfortran5 >=14.3.0 +constrains: +- openblas >=0.3.30,<0.3.31.0a0 +license: BSD-3-Clause +license_family: BSD +size: 4959359 +timestamp: 1763114173544 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libpng-1.6.55-h1abf092_0.conda +sha256: c7378c6b79de4d571d00ad1caf0a4c19d43c9c94077a761abb6ead44d891f907 +md5: be4088903b94ea297975689b3c3aeb27 +depends: +- libgcc >=14 +- libzlib >=1.3.1,<2.0a0 +license: zlib-acknowledgement +size: 340156 +timestamp: 1770691477245 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.52.0-h10b116e_0.conda +sha256: 1ddaf91b44fae83856276f4cb7ce544ffe41d4b55c1e346b504c6b45f19098d6 +md5: 77891484f18eca74b8ad83694da9815e +depends: +- icu >=78.2,<79.0a0 +- libgcc >=14 +- libzlib >=1.3.1,<2.0a0 +license: blessing +size: 952296 +timestamp: 1772818881550 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_18.conda +sha256: 31fdb9ffafad106a213192d8319b9f810e05abca9c5436b60e507afb35a6bc40 +md5: f56573d05e3b735cb03efeb64a15f388 +depends: +- libgcc 15.2.0 h8acb6b2_18 +constrains: +- libstdcxx-ng ==15.2.0=*_18 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 5541411 +timestamp: 1771378162499 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libtiff-4.7.1-hdb009f0_1.conda +sha256: 7ff79470db39e803e21b8185bc8f19c460666d5557b1378d1b1e857d929c6b39 +md5: 8c6fd84f9c87ac00636007c6131e457d +depends: +- lerc >=4.0.0,<5.0a0 +- libdeflate >=1.25,<1.26.0a0 +- libgcc >=14 +- libjpeg-turbo >=3.1.0,<4.0a0 +- liblzma >=5.8.1,<6.0a0 +- libstdcxx >=14 +- libwebp-base >=1.6.0,<2.0a0 +- libzlib >=1.3.1,<2.0a0 +- zstd >=1.5.7,<1.6.0a0 +license: HPND +size: 488407 +timestamp: 1762022048105 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.41.3-h1022ec0_0.conda +sha256: c37a8e89b700646f3252608f8368e7eb8e2a44886b92776e57ad7601fc402a11 +md5: cf2861212053d05f27ec49c3784ff8bb +depends: +- libgcc >=14 +license: BSD-3-Clause +license_family: BSD +size: 43453 +timestamp: 1766271546875 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libwebp-base-1.6.0-ha2e29f5_0.conda +sha256: b03700a1f741554e8e5712f9b06dd67e76f5301292958cd3cb1ac8c6fdd9ed25 +md5: 24e92d0942c799db387f5c9d7b81f1af +depends: +- libgcc >=14 +constrains: +- libwebp 1.6.0 +license: BSD-3-Clause +license_family: BSD +size: 359496 +timestamp: 1752160685488 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcb-1.17.0-h262b8f6_0.conda +sha256: 461cab3d5650ac6db73a367de5c8eca50363966e862dcf60181d693236b1ae7b +md5: cd14ee5cca2464a425b1dbfc24d90db2 +depends: +- libgcc >=13 +- pthread-stubs +- xorg-libxau >=1.0.11,<2.0a0 +- xorg-libxdmcp +license: MIT +license_family: MIT +size: 397493 +timestamp: 1727280745441 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_2.conda +sha256: eb111e32e5a7313a5bf799c7fb2419051fa2fe7eff74769fac8d5a448b309f7f +md5: 502006882cf5461adced436e410046d1 +constrains: +- zlib 1.3.2 *_2 +license: Zlib +license_family: Other +size: 69833 +timestamp: 1774072605429 +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.10.2-pyhcf101f3_0.conda +sha256: 20e0892592a3e7c683e3d66df704a9425d731486a97c34fc56af4da1106b2b6b +md5: ba0a9221ce1063f31692c07370d062f3 +depends: +- importlib-metadata >=4.4 +- python >=3.10 +- python +license: BSD-3-Clause +license_family: BSD +size: 85893 +timestamp: 1770694658918 +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda +sha256: 7b1da4b5c40385791dbc3cc85ceea9fad5da680a27d5d3cb8bfaa185e304a89e +md5: 5b5203189eb668f042ac2b0826244964 +depends: +- mdurl >=0.1,<1 +- python >=3.10 +license: MIT +license_family: MIT +size: 64736 +timestamp: 1754951288511 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/markupsafe-3.0.3-py314hb76de3f_1.conda +sha256: 383c188496d13a55658c06e61e7d4cdff2c9f9d5a0648769fca8250bece7e0ef +md5: e5de3c36dd548b35ff2a8aa49208dcb3 +depends: +- libgcc >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +constrains: +- jinja2 >=3.0.0 +license: BSD-3-Clause +license_family: BSD +size: 27913 +timestamp: 1772446407659 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/mathjax-2.7.7-h8af1aa0_3.tar.bz2 +sha256: 8fd4c79d6eda3d4cba73783114305a53a154ada4d1e334d4e02cb3521429599b +md5: 7b08314a6867a9d5648a1c3265e9eb8e +license: Apache-2.0 +license_family: Apache +size: 22257008 +timestamp: 1662784555011 +- conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda +sha256: 78c1bbe1723449c52b7a9df1af2ee5f005209f67e40b6e1d3c7619127c43b1c7 +md5: 592132998493b3ff25fd7479396e8351 +depends: +- python >=3.9 +license: MIT +license_family: MIT +size: 14465 +timestamp: 1733255681319 +- conda: https://conda.anaconda.org/bioconda/noarch/multiqc-1.33-pyhdfd78af_0.conda +sha256: f005760b13093362fc9c997d603dd487de32ab2e821a3cbce52a42bcb8136517 +md5: 698a8a27c2b9d8a542c70cb47099a75e +depends: +- click +- coloredlogs +- humanize +- importlib-metadata +- jinja2 >=3.0.0 +- jsonschema +- markdown +- natsort +- numpy +- packaging +- pillow >=10.2.0 +- plotly >=5.18 +- polars-lts-cpu +- pyaml-env +- pydantic >=2.7.1 +- python >=3.8,!=3.14.1 +- python-dotenv +- python-kaleido 0.2.1 +- pyyaml >=4 +- requests +- rich >=10 +- rich-click +- spectra >=0.0.10 +- tiktoken +- tqdm +- typeguard +license: GPL-3.0-or-later +license_family: GPL3 +size: 4198799 +timestamp: 1765300743879 +- conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.18.1-pyhcf101f3_1.conda +sha256: 541fd4390a0687228b8578247f1536a821d9261389a65585af9d1a6f2a14e1e0 +md5: 30bec5e8f4c3969e2b1bd407c5e52afb +depends: +- python >=3.10 +- python +license: MIT +size: 280459 +timestamp: 1774380620329 +- conda: https://conda.anaconda.org/conda-forge/noarch/natsort-8.4.0-pyhcf101f3_2.conda +sha256: aeb1548eb72e4f198e72f19d242fb695b35add2ac7b2c00e0d83687052867680 +md5: e941e85e273121222580723010bd4fa2 +depends: +- python >=3.9 +- python +license: MIT +license_family: MIT +size: 39262 +timestamp: 1770905275632 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.5-ha32ae93_3.conda +sha256: 91cfb655a68b0353b2833521dc919188db3d8a7f4c64bea2c6a7557b24747468 +md5: 182afabe009dc78d8b73100255ee6868 +depends: +- libgcc >=13 +license: X11 AND BSD-3-Clause +size: 926034 +timestamp: 1738196018799 +- conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda +sha256: f6a82172afc50e54741f6f84527ef10424326611503c64e359e25a19a8e4c1c6 +md5: a2c1eeadae7a309daed9d62c96012a2b +depends: +- python >=3.11 +- python +constrains: +- numpy >=1.25 +- scipy >=1.11.2 +- matplotlib-base >=3.8 +- pandas >=2.0 +license: BSD-3-Clause +license_family: BSD +size: 1587439 +timestamp: 1765215107045 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/nspr-4.38-h3ad9384_0.conda +sha256: 78a06e89285fef242e272998b292c1e621e3ee3dd4fba62ec014e503c7ec118f +md5: 6dd4f07147774bf720075a210f8026b9 +depends: +- libgcc >=14 +- libstdcxx >=14 +license: MPL-2.0 +license_family: MOZILLA +size: 235140 +timestamp: 1762350120355 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/nss-3.118-h544fa81_0.conda +sha256: 48942696889367ffd448f8dccfc080fb7e130b9938a4a3b6b20ef8e6af856463 +md5: 4540f9570d12db2150f42ba036154552 +depends: +- libgcc >=14 +- libsqlite >=3.51.0,<4.0a0 +- libstdcxx >=14 +- libzlib >=1.3.1,<2.0a0 +- nspr >=4.38,<5.0a0 +license: MPL-2.0 +license_family: MOZILLA +size: 2061869 +timestamp: 1763490303490 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-2.4.3-py314haac167e_0.conda +sha256: a6d42fd88afc57c3b0a57b21a12eff7492dfc419bb61ee3f74e9ba6261dabc88 +md5: 25d896c331481145720a21e5145fad65 +depends: +- python +- libgcc >=14 +- python 3.14.* *_cp314 +- libstdcxx >=14 +- libcblas >=3.9.0,<4.0a0 +- liblapack >=3.9.0,<4.0a0 +- python_abi 3.14.* *_cp314 +- libblas >=3.9.0,<4.0a0 +constrains: +- numpy-base <0a0 +license: BSD-3-Clause +license_family: BSD +size: 8008045 +timestamp: 1773839355275 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openjpeg-2.5.4-h5da879a_0.conda +sha256: bd1bc8bdde5e6c5cbac42d462b939694e40b59be6d0698f668515908640c77b8 +md5: cea962410e327262346d48d01f05936c +depends: +- libgcc >=14 +- libpng >=1.6.50,<1.7.0a0 +- libstdcxx >=14 +- libtiff >=4.7.1,<4.8.0a0 +- libzlib >=1.3.1,<2.0a0 +license: BSD-2-Clause +license_family: BSD +size: 392636 +timestamp: 1758489353577 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.1-h546c87b_1.conda +sha256: 7f8048c0e75b2620254218d72b4ae7f14136f1981c5eb555ef61645a9344505f +md5: 25f5885f11e8b1f075bccf4a2da91c60 +depends: +- ca-certificates +- libgcc >=14 +license: Apache-2.0 +license_family: Apache +size: 3692030 +timestamp: 1769557678657 +- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda +sha256: c1fc0f953048f743385d31c468b4a678b3ad20caffdeaa94bed85ba63049fd58 +md5: b76541e68fea4d511b1ac46a28dcd2c6 +depends: +- python >=3.8 +- python +license: Apache-2.0 +license_family: APACHE +size: 72010 +timestamp: 1769093650580 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pillow-12.1.1-py314hac3e5ec_0.conda +sha256: 1ca2d1616baad9bccb7ebc425ef2dcd6cebe742fbe91edf226fb606ad371ca0f +md5: d3c959c7efe560b2d7da459d69121fe9 +depends: +- python +- python 3.14.* *_cp314 +- libgcc >=14 +- zlib-ng >=2.3.3,<2.4.0a0 +- libwebp-base >=1.6.0,<2.0a0 +- tk >=8.6.13,<8.7.0a0 +- libfreetype >=2.14.1 +- libfreetype6 >=2.14.1 +- libtiff >=4.7.1,<4.8.0a0 +- lcms2 >=2.18,<3.0a0 +- python_abi 3.14.* *_cp314 +- openjpeg >=2.5.4,<3.0a0 +- libjpeg-turbo >=3.1.2,<4.0a0 +- libxcb >=1.17.0,<2.0a0 +license: HPND +size: 1051828 +timestamp: 1770794010335 +- conda: https://conda.anaconda.org/conda-forge/noarch/plotly-6.6.0-pyhd8ed1ab_0.conda +sha256: c418d325359fc7a0074cea7f081ef1bce26e114d2da8a0154c5d27ecc87a08e7 +md5: 3e9427ee186846052e81fadde8ebe96a +depends: +- narwhals >=1.15.1 +- packaging +- python >=3.10 +constrains: +- ipywidgets >=7.6 +license: MIT +license_family: MIT +size: 5251872 +timestamp: 1772628857717 +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.39.3-pyh58ad624_1.conda +sha256: d332c2d5002fc440ae37ed9679ffc21b552f18d20232390005d1dd3bce0888d3 +md5: d5a4e013a30dd8dfde9ab39f45aaf9c1 +depends: +- polars-runtime-32 ==1.39.3 +- python >=3.10 +- python +constrains: +- numpy >=1.16.0 +- pyarrow >=7.0.0 +- fastexcel >=0.9 +- openpyxl >=3.0.0 +- xlsx2csv >=0.8.0 +- connectorx >=0.3.2 +- deltalake >=1.0.0 +- pyiceberg >=0.7.1 +- altair >=5.4.0 +- great_tables >=0.8.0 +- polars-runtime-32 ==1.39.3 +- polars-runtime-64 ==1.39.3 +- polars-runtime-compat ==1.39.3 +license: MIT +license_family: MIT +size: 533495 +timestamp: 1774207987966 +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-lts-cpu-1.34.0.deprecated-hc364b38_0.conda +sha256: e466fb31f67ba9bde18deafeb34263ca5eb25807f39ead0e9d753a8e82c4c4f4 +md5: ef0340e75068ac8ff96462749b5c98e7 +depends: +- polars >=1.34.0 +- polars-runtime-compat >=1.34.0 +license: MIT +license_family: MIT +size: 3902 +timestamp: 1760206808444 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/polars-runtime-32-1.39.3-py310hff09b76_1.conda +noarch: python +sha256: c070be507c5a90df397a47ae0299660be437d5546d68f1bc0fa4402c9f07d59e +md5: 3c1a7c6b4ba8b9fb773ace9723f8a5db +depends: +- python +- libgcc >=14 +- libstdcxx >=14 +- _python_abi3_support 1.* +- cpython >=3.10 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 34785466 +timestamp: 1774207998285 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/polars-runtime-compat-1.39.3-py310hf00a4a2_1.conda +noarch: python +sha256: 683315f1a49e47ce72bf9462419733b40b588b2b3106552d95fd4cd994e174de +md5: dd3464e2132dc3a783e76e5078870c76 +depends: +- python +- libgcc >=14 +- libstdcxx >=14 +- _python_abi3_support 1.* +- cpython >=3.10 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 34652491 +timestamp: 1774207996879 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/procps-ng-4.0.6-h1779866_0.conda +sha256: e9cbcbc94e151ada3d6dc365380aaaf591f65012c16d9a2abaea4b9b90adc402 +md5: ab7288cc39545556d1bc5e71ab2df9a9 +depends: +- libgcc >=14 +- ncurses >=6.5,<7.0a0 +license: GPL-2.0-or-later AND LGPL-2.0-or-later +license_family: GPL +size: 636733 +timestamp: 1769712412683 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pthread-stubs-0.4-h86ecc28_1002.conda +sha256: 977dfb0cb3935d748521dd80262fe7169ab82920afd38ed14b7fee2ea5ec01ba +md5: bb5a90c93e3bac3d5690acf76b4a6386 +depends: +- libgcc >=13 +license: MIT +license_family: MIT +size: 8342 +timestamp: 1726803319942 +- conda: https://conda.anaconda.org/conda-forge/noarch/pyaml-env-1.2.2-pyhd8ed1ab_0.conda +sha256: 58994e0d2ea8584cb399546e6f6896d771995e6121d1a7b6a2c9948388358932 +md5: e17be1016bcc3516827b836cd3e4d9dc +depends: +- python >=3.9 +- pyyaml >=5.0,<=7.0 +license: MIT +license_family: MIT +size: 14645 +timestamp: 1736766960536 +- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda +sha256: 868569d9505b7fe246c880c11e2c44924d7613a8cdcc1f6ef85d5375e892f13d +md5: c3946ed24acdb28db1b5d63321dbca7d +depends: +- typing-inspection >=0.4.2 +- typing_extensions >=4.14.1 +- python >=3.10 +- typing-extensions >=4.6.1 +- annotated-types >=0.6.0 +- pydantic-core ==2.41.5 +- python +license: MIT +license_family: MIT +size: 340482 +timestamp: 1764434463101 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pydantic-core-2.41.5-py314h451b6cc_1.conda +sha256: f8acb2d03ebe80fed0032b9a989fc9acfb6735e3cd3f8c704b72728cb31868f6 +md5: 28f5027a1e04d67aa13fac1c5ba79693 +depends: +- python +- typing-extensions >=4.6.0,!=4.7.0 +- libgcc >=14 +- python 3.14.* *_cp314 +- python_abi 3.14.* *_cp314 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 1828339 +timestamp: 1762989038561 +- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda +sha256: 5577623b9f6685ece2697c6eb7511b4c9ac5fb607c9babc2646c811b428fd46a +md5: 6b6ece66ebcae2d5f326c77ef2c5a066 +depends: +- python >=3.9 +license: BSD-2-Clause +license_family: BSD +size: 889287 +timestamp: 1750615908735 +- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda +sha256: ba3b032fa52709ce0d9fd388f63d330a026754587a2f461117cac9ab73d8d0d8 +md5: 461219d1a5bd61342293efa2c0c90eac +depends: +- __unix +- python >=3.9 +license: BSD-3-Clause +license_family: BSD +size: 21085 +timestamp: 1733217331982 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.3-hb06a95a_101_cp314.conda +build_number: 101 +sha256: 87e9dff5646aba87cecfbc08789634c855871a7325169299d749040b0923a356 +md5: 205011b36899ff0edf41b3db0eda5a44 +depends: +- bzip2 >=1.0.8,<2.0a0 +- ld_impl_linux-aarch64 >=2.36.1 +- libexpat >=2.7.3,<3.0a0 +- libffi >=3.5.2,<3.6.0a0 +- libgcc >=14 +- liblzma >=5.8.2,<6.0a0 +- libmpdec >=4.0.0,<5.0a0 +- libsqlite >=3.51.2,<4.0a0 +- libuuid >=2.41.3,<3.0a0 +- libzlib >=1.3.1,<2.0a0 +- ncurses >=6.5,<7.0a0 +- openssl >=3.5.5,<4.0a0 +- python_abi 3.14.* *_cp314 +- readline >=8.3,<9.0a0 +- tk >=8.6.13,<8.7.0a0 +- tzdata +- zstd >=1.5.7,<1.6.0a0 +license: Python-2.0 +size: 37305578 +timestamp: 1770674395875 +python_site_packages_path: lib/python3.14/site-packages +- conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda +sha256: 74e417a768f59f02a242c25e7db0aa796627b5bc8c818863b57786072aeb85e5 +md5: 130584ad9f3a513cdd71b1fdc1244e9c +depends: +- python >=3.10 +license: BSD-3-Clause +license_family: BSD +size: 27848 +timestamp: 1772388605021 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.3-h4df99d1_101.conda +sha256: 233aebd94c704ac112afefbb29cf4170b7bc606e22958906f2672081bc50638a +md5: 235765e4ea0d0301c75965985163b5a1 +depends: +- cpython 3.14.3.* +- python_abi * *_cp314 +license: Python-2.0 +size: 50062 +timestamp: 1770674497152 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-kaleido-0.2.1-pyhd8ed1ab_0.tar.bz2 +sha256: e17bf63a30aec33432f1ead86e15e9febde9fc40a7f869c0e766be8d2db44170 +md5: 310259a5b03ff02289d7705f39e2b1d2 +depends: +- kaleido-core 0.2.1.* +- python >=3.5 +license: MIT +license_family: MIT +size: 18320 +timestamp: 1615204747600 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda +build_number: 8 +sha256: ad6d2e9ac39751cc0529dd1566a26751a0bf2542adb0c232533d32e176e21db5 +md5: 0539938c55b6b1a59b560e843ad864a4 +constrains: +- python 3.14.* *_cp314 +license: BSD-3-Clause +license_family: BSD +size: 6989 +timestamp: 1752805904792 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py314h807365f_1.conda +sha256: 496b5e65dfdd0aaaaa5de0dcaaf3bceea00fcb4398acf152f89e567c82ec1046 +md5: 9ae2c92975118058bd720e9ba2bb7c58 +depends: +- libgcc >=14 +- python >=3.14,<3.15.0a0 +- python >=3.14,<3.15.0a0 *_cp314 +- python_abi 3.14.* *_cp314 +- yaml >=0.2.5,<0.3.0a0 +license: MIT +license_family: MIT +size: 195678 +timestamp: 1770223441816 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda +sha256: fe695f9d215e9a2e3dd0ca7f56435ab4df24f5504b83865e3d295df36e88d216 +md5: 3d49cad61f829f4f0e0611547a9cda12 +depends: +- libgcc >=14 +- ncurses >=6.5,<7.0a0 +license: GPL-3.0-only +license_family: GPL +size: 357597 +timestamp: 1765815673644 +- conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda +sha256: 0577eedfb347ff94d0f2fa6c052c502989b028216996b45c7f21236f25864414 +md5: 870293df500ca7e18bedefa5838a22ab +depends: +- attrs >=22.2.0 +- python >=3.10 +- rpds-py >=0.7.0 +- typing_extensions >=4.4.0 +- python +license: MIT +license_family: MIT +size: 51788 +timestamp: 1760379115194 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/regex-2026.2.28-py314h51f160d_0.conda +sha256: 2080ecea825e1ef91a2422cc0bc63e85db9e38908ed17657fb8f41de7a6eee71 +md5: 818aa2c9f6b3c808da5e7be22a9a424c +depends: +- libgcc >=14 +- python >=3.14,<3.15.0a0 +- python >=3.14,<3.15.0a0 *_cp314 +- python_abi 3.14.* *_cp314 +license: Apache-2.0 AND CNRI-Python +license_family: PSF +size: 408097 +timestamp: 1772255205521 +- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda +sha256: 7813c38b79ae549504b2c57b3f33394cea4f2ad083f0994d2045c2e24cb538c5 +md5: c65df89a0b2e321045a9e01d1337b182 +depends: +- python >=3.10 +- certifi >=2017.4.17 +- charset-normalizer >=2,<4 +- idna >=2.5,<4 +- urllib3 >=1.21.1,<3 +- python +constrains: +- chardet >=3.0.2,<6 +license: Apache-2.0 +license_family: APACHE +size: 63602 +timestamp: 1766926974520 +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-14.3.3-pyhcf101f3_0.conda +sha256: b06ce84d6a10c266811a7d3adbfa1c11f13393b91cc6f8a5b468277d90be9590 +md5: 7a6289c50631d620652f5045a63eb573 +depends: +- markdown-it-py >=2.2.0 +- pygments >=2.13.0,<3.0.0 +- python >=3.10 +- typing_extensions >=4.0.0,<5.0.0 +- python +license: MIT +license_family: MIT +size: 208472 +timestamp: 1771572730357 +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-click-1.9.7-pyh8f84b5b_0.conda +sha256: aa3fcb167321bae51998de2e94d199109c9024f25a5a063cb1c28d8f1af33436 +md5: 0c20a8ebcddb24a45da89d5e917e6cb9 +depends: +- python >=3.10 +- rich >=12 +- click >=8 +- typing-extensions >=4 +- __unix +- python +license: MIT +license_family: MIT +size: 64356 +timestamp: 1769850479089 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/rpds-py-0.30.0-py314h02b7a91_0.conda +sha256: a587240f16eac7c6a80f9585cef679cd1cb9a287b8dfcdd36dcef1f7e7db15dc +md5: e7f6ed9e60043bb5cbcc527764897f0d +depends: +- python +- libgcc >=14 +- python_abi 3.14.* *_cp314 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 376332 +timestamp: 1764543345455 +- conda: https://conda.anaconda.org/conda-forge/noarch/spectra-0.0.11-pyhd8ed1ab_2.conda +sha256: 7c65782d2511738e62c70462e89d65da4fa54d5a7e47c46667bcd27a59f81876 +md5: 472239e4eb7b5a84bb96b3ed7e3a596a +depends: +- colormath >=3.0.0 +- python >=3.9 +license: MIT +license_family: MIT +size: 22284 +timestamp: 1735770589188 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/sqlite-3.52.0-hf1c7be2_0.conda +sha256: 4f8523f5341f0d9e1547085206c6c1f71f9fc7c277443ca363a8cf98add8fc01 +md5: d9634079df93a65ee045b3c75f35cae1 +depends: +- icu >=78.2,<79.0a0 +- libgcc >=14 +- libsqlite 3.52.0 h10b116e_0 +- libzlib >=1.3.1,<2.0a0 +- ncurses >=6.5,<7.0a0 +- readline >=8.3,<9.0a0 +license: blessing +size: 209416 +timestamp: 1772818891689 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tiktoken-0.12.0-py314h6a36e60_3.conda +sha256: c1da41c79262b27efa168407cfecc47b20270e5fc071a8307f95a2c85fb94170 +md5: 55bf7b559202236157b14323b40f19e6 +depends: +- libgcc >=14 +- libstdcxx >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +- regex >=2022.1.18 +- requests >=2.26.0 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 914402 +timestamp: 1764030357702 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h0dc03b3_103.conda +sha256: e25c314b52764219f842b41aea2c98a059f06437392268f09b03561e4f6e5309 +md5: 7fc6affb9b01e567d2ef1d05b84aa6ed +depends: +- libgcc >=14 +- libzlib >=1.3.1,<2.0a0 +constrains: +- xorg-libx11 >=1.8.12,<2.0a0 +license: TCL +license_family: BSD +size: 3368666 +timestamp: 1769464148928 +- conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda +sha256: 9ef8e47cf00e4d6dcc114eb32a1504cc18206300572ef14d76634ba29dfe1eb6 +md5: e5ce43272193b38c2e9037446c1d9206 +depends: +- python >=3.10 +- __unix +- python +license: MPL-2.0 and MIT +size: 94132 +timestamp: 1770153424136 +- conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.1-pyhd8ed1ab_0.conda +sha256: 39d8ae33c43cdb8f771373e149b0b4fae5a08960ac58dcca95b2f1642bb17448 +md5: 260af1b0a94f719de76b4e14094e9a3b +depends: +- importlib-metadata >=3.6 +- python >=3.10 +- typing-extensions >=4.10.0 +- typing_extensions >=4.14.0 +constrains: +- pytest >=7 +license: MIT +license_family: MIT +size: 36838 +timestamp: 1771532971545 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda +sha256: 7c2df5721c742c2a47b2c8f960e718c930031663ac1174da67c1ed5999f7938c +md5: edd329d7d3a4ab45dcf905899a7a6115 +depends: +- typing_extensions ==4.15.0 pyhcf101f3_0 +license: PSF-2.0 +license_family: PSF +size: 91383 +timestamp: 1756220668932 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhd8ed1ab_1.conda +sha256: 70db27de58a97aeb7ba7448366c9853f91b21137492e0b4430251a1870aa8ff4 +md5: a0a4a3035667fc34f29bfbd5c190baa6 +depends: +- python >=3.10 +- typing_extensions >=4.12.0 +license: MIT +license_family: MIT +size: 18923 +timestamp: 1764158430324 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda +sha256: 032271135bca55aeb156cee361c81350c6f3fb203f57d024d7e5a1fc9ef18731 +md5: 0caa1af407ecff61170c9437a808404d +depends: +- python >=3.10 +- python +license: PSF-2.0 +license_family: PSF +size: 51692 +timestamp: 1756220668932 +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda +sha256: 1d30098909076af33a35017eed6f2953af1c769e273a0626a04722ac4acaba3c +md5: ad659d0a2b3e47e38d829aa8cad2d610 +license: LicenseRef-Public-Domain +size: 119135 +timestamp: 1767016325805 +- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda +sha256: af641ca7ab0c64525a96fd9ad3081b0f5bcf5d1cbb091afb3f6ed5a9eee6111a +md5: 9272daa869e03efe68833e3dc7a02130 +depends: +- backports.zstd >=1.0.0 +- brotli-python >=1.2.0 +- h2 >=4,<5 +- pysocks >=1.5.6,<2.0,!=1.5.7 +- python >=3.10 +license: MIT +license_family: MIT +size: 103172 +timestamp: 1767817860341 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxau-1.0.12-he30d5cf_1.conda +sha256: e9f6e931feeb2f40e1fdbafe41d3b665f1ab6cb39c5880a1fcf9f79a3f3c84a5 +md5: 1c246e1105000c3660558459e2fd6d43 +depends: +- libgcc >=14 +license: MIT +license_family: MIT +size: 16317 +timestamp: 1762977521691 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxdmcp-1.1.5-he30d5cf_1.conda +sha256: 128d72f36bcc8d2b4cdbec07507542e437c7d67f677b7d77b71ed9eeac7d6df1 +md5: bff06dcde4a707339d66d45d96ceb2e2 +depends: +- libgcc >=14 +license: MIT +license_family: MIT +size: 21039 +timestamp: 1762979038025 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda +sha256: 66265e943f32ce02396ad214e27cb35f5b0490b3bd4f064446390f9d67fa5d88 +md5: 032d8030e4a24fe1f72c74423a46fb88 +depends: +- libgcc >=14 +license: MIT +license_family: MIT +size: 88088 +timestamp: 1753484092643 +- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda +sha256: b4533f7d9efc976511a73ef7d4a2473406d7f4c750884be8e8620b0ce70f4dae +md5: 30cd29cb87d819caead4d55184c1d115 +depends: +- python >=3.10 +- python +license: MIT +license_family: MIT +size: 24194 +timestamp: 1764460141901 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zlib-ng-2.3.3-ha7cb516_1.conda +sha256: 638a3a41a4fbfed52d3c60c8ef5a3693b3f12a5b1a3f58fa29f5698d0a0702e2 +md5: f731af71c723065d91b4c01bb822641b +depends: +- libgcc >=14 +- libstdcxx >=14 +license: Zlib +license_family: Other +size: 121046 +timestamp: 1770167944449 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda +sha256: 569990cf12e46f9df540275146da567d9c618c1e9c7a0bc9d9cfefadaed20b75 +md5: c3655f82dcea2aa179b291e7099c1fcc +depends: +- libzlib >=1.3.1,<2.0a0 +license: BSD-3-Clause +license_family: BSD +size: 614429 +timestamp: 1764777145593 diff --git a/modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-d167b8012595a136_1.txt b/modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-d167b8012595a136_1.txt new file mode 100644 index 000000000..f787dbe1e --- /dev/null +++ b/modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-d167b8012595a136_1.txt @@ -0,0 +1,125 @@ + +# This file may be used to create an environment using: +# $ conda create --name --file +# platform: linux-aarch64 +@EXPLICIT +https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_18.conda#4faa39bf919939602e594253bd673958 +https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda#468fd3bb9e1f671d36c2cbc677e56f1d +https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_18.conda#552567ea2b61e3a3035759b2fdb3f9a6 +https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda#840d8fc0d7b3209be93080bc20e07f2d +https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_2.conda#502006882cf5461adced436e410046d1 +https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda#c3655f82dcea2aa179b291e7099c1fcc +https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.45.1-default_h1979696_102.conda#a21644fc4a83da26452a718dc9468d5f +https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.7.5-hfae3067_0.conda#05d1e0b30acd816a192c03dc6e164f4d +https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda#2f364feefb6a7c00423e80dcb12db62a +https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.3-he30d5cf_0.conda#76298a9e6d71ee6e832a8d0d7373b261 +https://conda.anaconda.org/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_1.conda#7b9813e885482e3ccb1fa212b86d7fd0 +https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.53.0-h022381a_0.conda#86db4036fd08bf34e991bf48a8af405d +https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.42-h1022ec0_0.conda#a0b5de740d01c390bdbb46d7503c9fab +https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.5-ha32ae93_3.conda#182afabe009dc78d8b73100255ee6868 +https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda#e18ad67cf881dcadee8b8d9e2f8e5f73 +https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.2-h546c87b_0.conda#3b129669089e4d6a5c6871dbb4669b99 +https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda#0539938c55b6b1a59b560e843ad864a4 +https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda#3d49cad61f829f4f0e0611547a9cda12 +https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h0dc03b3_103.conda#7fc6affb9b01e567d2ef1d05b84aa6ed +https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda#ad659d0a2b3e47e38d829aa8cad2d610 +https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.4-hfd9ac0a_100_cp314.conda#3cfbe780f0f51cc8cba41db9f8a28bfe +https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.4-py314hd8ed1ab_100.conda#f111d4cfaf1fe9496f386bc98ae94452 +https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.4-h4df99d1_100.conda#e4e60721757979d01d3964122f674959 +https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda#aaa2a381ccc56eac91d63b6c1240312f +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda#0caa1af407ecff61170c9437a808404d +https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda#edd329d7d3a4ab45dcf905899a7a6115 +https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda#2934f256a8acfe48f6ebb4fce6cde29c +https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda#c6b0543676ecb1fb2d7643941fe375f2 +https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda#a2ac7763a9ac75055b68f325d3255265 +https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_18.conda#f56573d05e3b735cb03efeb64a15f388 +https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-python-1.2.0-py314h352cb57_1.conda#a1b5c571a0923a205d663d8678df4792 +https://conda.anaconda.org/conda-forge/noarch/certifi-2026.4.22-pyhd8ed1ab_0.conda#929471569c93acefb30282a22060dcd5 +https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda#a9167b9571f3baa9d448faa2139d1089 +https://conda.anaconda.org/conda-forge/noarch/click-8.3.2-pyhc90fa1f_0.conda#4d18bc3af7cfcea97bd817164672a08c +https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda#7fe569c10905402ed47024fc481bb371 +https://conda.anaconda.org/conda-forge/noarch/coloredlogs-15.0.1-pyhd8ed1ab_4.conda#b866ff7007b934d564961066c8195983 +https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda#a2c1eeadae7a309daed9d62c96012a2b +https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-15.2.0-h1b7bec0_18.conda#574d88ce3348331e962cfa5ed451b247 +https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-15.2.0-he9431aa_18.conda#41f261f5e4e2e8cbd236c2f1f15dae1b +https://conda.anaconda.org/conda-forge/linux-aarch64/libopenblas-0.3.32-pthreads_h9d3fd7e_0.conda#5d2ce5cf40443d055ec6d33840192265 +https://conda.anaconda.org/conda-forge/linux-aarch64/libblas-3.11.0-6_haddc8a3_openblas.conda#652bb20bb4618cacd11e17ae070f47ce +https://conda.anaconda.org/conda-forge/linux-aarch64/libcblas-3.11.0-6_hd72aa62_openblas.conda#939e300b110db241a96a1bed438c315b +https://conda.anaconda.org/conda-forge/linux-aarch64/liblapack-3.11.0-6_h88aeb00_openblas.conda#e23a27b52fb320687239e2c5ae4d7540 +https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-2.4.3-py314haac167e_0.conda#25d896c331481145720a21e5145fad65 +https://conda.anaconda.org/conda-forge/noarch/colormath-3.0.0-pyhd8ed1ab_4.conda#071cf7b0ce333c81718b054066c15102 +https://conda.anaconda.org/conda-forge/linux-aarch64/expat-2.7.5-hfae3067_0.conda#d2bb0c889d94f2fdc5856392c3002976 +https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2#0c96522c6bdaed4b1566d11387caaf45 +https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 +https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb +https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda#49023d73832ef61042f6a237cb2687e7 +https://conda.anaconda.org/conda-forge/linux-aarch64/libpng-1.6.58-h1abf092_0.conda#f51503ac45a4888bce71af9027a2ecc9 +https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype6-2.14.3-hdae7a39_0.conda#b99ed99e42dafb27889483b3098cace7 +https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype-2.14.3-h8af1aa0_0.conda#a229e22d4d8814a07702b0919d8e6701 +https://conda.anaconda.org/conda-forge/linux-aarch64/fontconfig-2.17.1-hba86a56_0.conda#0fed1ff55f4938a65907f3ecf62609db +https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda#a7970cd949a077b7cb9696379d338681 +https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda#0a802cb9888dd14eeefc611f05c40b6e +https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda#8e6923fc12f1fe8f8c4e5c9f343256ac +https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda#164fc43f0b53b6e3a7bc7dce5e4f1dc9 +https://conda.anaconda.org/conda-forge/noarch/humanize-4.15.0-pyhd8ed1ab_0.conda#daddf757c3ecd6067b9af1df1f25d89e +https://conda.anaconda.org/conda-forge/noarch/idna-3.13-pyhcf101f3_0.conda#fb7130c190f9b4ec91219840a05ba3ac +https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.1-pyhcf101f3_0.conda#e1c36c6121a7c9c76f2f148f1e83b983 +https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda#080594bf4493e6bae2607e65390c520a +https://conda.anaconda.org/conda-forge/linux-aarch64/markupsafe-3.0.3-py314hb76de3f_1.conda#e5de3c36dd548b35ff2a8aa49208dcb3 +https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda#04558c96691bed63104678757beb4f8d +https://conda.anaconda.org/conda-forge/linux-aarch64/rpds-py-0.30.0-py314h02b7a91_0.conda#e7f6ed9e60043bb5cbcc527764897f0d +https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda#870293df500ca7e18bedefa5838a22ab +https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda#439cd0f567d697b20a8f45cb70a1005a +https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda#ada41c863af263cc4c5fcbaff7c3e4dc +https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-15.2.0-he9431aa_18.conda#4feebd0fbf61075a1a9c2e9b3936c257 +https://conda.anaconda.org/conda-forge/linux-aarch64/mathjax-2.7.7-h8af1aa0_3.tar.bz2#7b08314a6867a9d5648a1c3265e9eb8e +https://conda.anaconda.org/conda-forge/linux-aarch64/nspr-4.38-h3ad9384_0.conda#6dd4f07147774bf720075a210f8026b9 +https://conda.anaconda.org/conda-forge/linux-aarch64/nss-3.118-h544fa81_0.conda#4540f9570d12db2150f42ba036154552 +https://conda.anaconda.org/conda-forge/linux-aarch64/sqlite-3.53.0-he8854b5_0.conda#ad8164bdeece883b825c50639c0c4725 +https://conda.anaconda.org/conda-forge/linux-aarch64/kaleido-core-0.2.1-he5a581e_0.tar.bz2#4f0d284f5d11e04277b552eb1c172c7f +https://conda.anaconda.org/conda-forge/linux-aarch64/libjpeg-turbo-3.1.4.1-he30d5cf_0.conda#a85ba48648f6868016f2741fd9170250 +https://conda.anaconda.org/conda-forge/linux-aarch64/lerc-4.1.0-h52b7260_0.conda#d13423b06447113a90b5b1366d4da171 +https://conda.anaconda.org/conda-forge/linux-aarch64/libdeflate-1.25-h1af38f5_0.conda#a9138815598fe6b91a1d6782ca657b0c +https://conda.anaconda.org/conda-forge/linux-aarch64/libwebp-base-1.6.0-ha2e29f5_0.conda#24e92d0942c799db387f5c9d7b81f1af +https://conda.anaconda.org/conda-forge/linux-aarch64/libtiff-4.7.1-hdb009f0_1.conda#8c6fd84f9c87ac00636007c6131e457d +https://conda.anaconda.org/conda-forge/linux-aarch64/lcms2-2.18-h9d5b58d_0.conda#bb960f01525b5e001608afef9d47b79c +https://conda.anaconda.org/conda-forge/linux-aarch64/pthread-stubs-0.4-h86ecc28_1002.conda#bb5a90c93e3bac3d5690acf76b4a6386 +https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxau-1.0.12-he30d5cf_1.conda#1c246e1105000c3660558459e2fd6d43 +https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxdmcp-1.1.5-he30d5cf_1.conda#bff06dcde4a707339d66d45d96ceb2e2 +https://conda.anaconda.org/conda-forge/linux-aarch64/libxcb-1.17.0-h262b8f6_0.conda#cd14ee5cca2464a425b1dbfc24d90db2 +https://conda.anaconda.org/conda-forge/noarch/markdown-3.10.2-pyhcf101f3_0.conda#ba0a9221ce1063f31692c07370d062f3 +https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda#592132998493b3ff25fd7479396e8351 +https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda#5b5203189eb668f042ac2b0826244964 +https://conda.anaconda.org/conda-forge/noarch/natsort-8.4.0-pyhcf101f3_2.conda#e941e85e273121222580723010bd4fa2 +https://conda.anaconda.org/conda-forge/noarch/packaging-26.1-pyhc364b38_0.conda#b8ae38639d323d808da535fb71e31be8 +https://conda.anaconda.org/conda-forge/linux-aarch64/openjpeg-2.5.4-h5da879a_0.conda#cea962410e327262346d48d01f05936c +https://conda.anaconda.org/conda-forge/linux-aarch64/zlib-ng-2.3.3-ha7cb516_1.conda#f731af71c723065d91b4c01bb822641b +https://conda.anaconda.org/conda-forge/linux-aarch64/pillow-12.2.0-py314hac3e5ec_0.conda#87d58d103b47c4a8567b3d7666647684 +https://conda.anaconda.org/conda-forge/noarch/narwhals-2.20.0-pyhcf101f3_0.conda#6cac1a50359219d786453c6fef819f98 +https://conda.anaconda.org/conda-forge/noarch/plotly-6.6.0-pyhd8ed1ab_0.conda#3e9427ee186846052e81fadde8ebe96a +https://conda.anaconda.org/conda-forge/linux-aarch64/polars-runtime-32-1.40.0-py310hff09b76_0.conda#d5628a33ce7652511e38fc98643dc910 +https://conda.anaconda.org/conda-forge/noarch/polars-1.40.0-pyh58ad624_0.conda#fd16be490f5403adfbf27dd4901bbe34 +https://conda.anaconda.org/conda-forge/linux-aarch64/polars-runtime-compat-1.40.0-py310hf00a4a2_0.conda#a82af0fcbb72db253dc89a7a45279372 +https://conda.anaconda.org/conda-forge/noarch/polars-lts-cpu-1.34.0.deprecated-hc364b38_0.conda#ef0340e75068ac8ff96462749b5c98e7 +https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda#032d8030e4a24fe1f72c74423a46fb88 +https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py314h807365f_1.conda#9ae2c92975118058bd720e9ba2bb7c58 +https://conda.anaconda.org/conda-forge/noarch/pyaml-env-1.2.2-pyhd8ed1ab_0.conda#e17be1016bcc3516827b836cd3e4d9dc +https://conda.anaconda.org/conda-forge/linux-aarch64/pydantic-core-2.46.3-py314h451b6cc_0.conda#1a2cb55be9a153ad6203bff6b787c240 +https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhd8ed1ab_1.conda#a0a4a3035667fc34f29bfbd5c190baa6 +https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.3-pyhcf101f3_0.conda#f690e6f204efd2e5c06b57518a383d98 +https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda#130584ad9f3a513cdd71b1fdc1244e9c +https://conda.anaconda.org/conda-forge/noarch/python-kaleido-0.2.1-pyhd8ed1ab_0.tar.bz2#310259a5b03ff02289d7705f39e2b1d2 +https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda#461219d1a5bd61342293efa2c0c90eac +https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda#9272daa869e03efe68833e3dc7a02130 +https://conda.anaconda.org/conda-forge/noarch/requests-2.33.1-pyhcf101f3_0.conda#10afbb4dbf06ff959ad25a92ccee6e59 +https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda#16c18772b340887160c79a6acc022db0 +https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda#0242025a3c804966bf71aa04eee82f66 +https://conda.anaconda.org/conda-forge/noarch/rich-click-1.9.7-pyh8f84b5b_0.conda#0c20a8ebcddb24a45da89d5e917e6cb9 +https://conda.anaconda.org/conda-forge/noarch/spectra-0.0.11-pyhd8ed1ab_2.conda#472239e4eb7b5a84bb96b3ed7e3a596a +https://conda.anaconda.org/conda-forge/linux-aarch64/regex-2026.4.4-py314h51f160d_0.conda#88a3dbd279e6b1faf0cddb8397866864 +https://conda.anaconda.org/conda-forge/linux-aarch64/tiktoken-0.12.0-py314h6a36e60_3.conda#55bf7b559202236157b14323b40f19e6 +https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda#e5ce43272193b38c2e9037446c1d9206 +https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.1-pyhd8ed1ab_0.conda#260af1b0a94f719de76b4e14094e9a3b +https://conda.anaconda.org/bioconda/noarch/multiqc-1.34-pyhdfd78af_0.conda#a7111ab9a6a6146b40cbce16655ac873 +https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh145f28c_0.conda#09a970fbf75e8ed1aa633827ded6aa4f +https://conda.anaconda.org/conda-forge/linux-aarch64/procps-ng-4.0.6-h1779866_0.conda#ab7288cc39545556d1bc5e71ab2df9a9 diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml index d02016a00..37e7612d4 100644 --- a/modules/nf-core/multiqc/environment.yml +++ b/modules/nf-core/multiqc/environment.yml @@ -4,4 +4,4 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::multiqc=1.32 + - bioconda::multiqc=1.34 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index abbef4566..e80e8cd8d 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -1,24 +1,21 @@ process MULTIQC { + tag "${meta.id}" label 'process_single' conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/8c/8c6c120d559d7ee04c7442b61ad7cf5a9e8970be5feefb37d68eeaa60c1034eb/data' : - 'community.wave.seqera.io/library/multiqc:1.32--d58f60e4deb769bf' }" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/1b/1bef8af6be88c5733461959c46ac8ef73d18f65277f62a1695d0e1633054f9c2/data' + : 'community.wave.seqera.io/library/multiqc:1.34--db7c73dae76bc9e6'}" input: - path multiqc_files, stageAs: "?/*" - path(multiqc_config) - path(extra_multiqc_config) - path(multiqc_logo) - path(replace_names) - path(sample_names) + tuple val(meta), path(multiqc_files, stageAs: "?/*"), path(multiqc_config, stageAs: "?/*"), path(multiqc_logo), path(replace_names), path(sample_names) output: - path "*.html" , emit: report - path "*_data" , emit: data - path "*_plots" , optional:true, emit: plots - path "versions.yml", emit: versions + tuple val(meta), path("*.html"), emit: report + tuple val(meta), path("*_data"), emit: data + tuple val(meta), path("*_plots"), emit: plots, optional: true + // MultiQC should not push its versions to the `versions` topic. Its input depends on the versions topic to be resolved thus outputting to the topic will let the pipeline hang forever + tuple val("${task.process}"), val('multiqc'), eval('multiqc --version | sed "s/.* //g"'), emit: versions when: task.ext.when == null || task.ext.when @@ -26,8 +23,7 @@ process MULTIQC { script: def args = task.ext.args ?: '' def prefix = task.ext.prefix ? "--filename ${task.ext.prefix}.html" : '' - def config = multiqc_config ? "--config ${multiqc_config}" : '' - def extra_config = extra_multiqc_config ? "--config ${extra_multiqc_config}" : '' + def config = multiqc_config ? multiqc_config instanceof List ? "--config ${multiqc_config.join(' --config ')}" : "--config ${multiqc_config}" : "" def logo = multiqc_logo ? "--cl-config 'custom_logo: \"${multiqc_logo}\"'" : '' def replace = replace_names ? "--replace-names ${replace_names}" : '' def samples = sample_names ? "--sample-names ${sample_names}" : '' @@ -37,16 +33,10 @@ process MULTIQC { ${args} \\ ${config} \\ ${prefix} \\ - ${extra_config} \\ ${logo} \\ ${replace} \\ ${samples} \\ . - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - multiqc: \$( multiqc --version | sed -e "s/multiqc, version //g" ) - END_VERSIONS """ stub: @@ -54,11 +44,7 @@ process MULTIQC { mkdir multiqc_data touch multiqc_data/.stub mkdir multiqc_plots + touch multiqc_plots/.stub touch multiqc_report.html - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - multiqc: \$( multiqc --version | sed -e "s/multiqc, version //g" ) - END_VERSIONS """ } diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml index 9ac86fd11..2facc627b 100644 --- a/modules/nf-core/multiqc/meta.yml +++ b/modules/nf-core/multiqc/meta.yml @@ -1,6 +1,6 @@ name: multiqc -description: Aggregate results from bioinformatics analyses across many samples into - a single report +description: Aggregate results from bioinformatics analyses across many samples + into a single report keywords: - QC - bioinformatics tools @@ -12,74 +12,91 @@ tools: It's a general use tool, perfect for summarising the output from numerous bioinformatics tools. homepage: https://multiqc.info/ documentation: https://multiqc.info/docs/ - licence: ["GPL-3.0-or-later"] + licence: + - "GPL-3.0-or-later" identifier: biotools:multiqc input: - - multiqc_files: - type: file - description: | - List of reports / files recognised by MultiQC, for example the html and zip output of FastQC - ontologies: [] - - multiqc_config: - type: file - description: Optional config yml for MultiQC - pattern: "*.{yml,yaml}" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML - - extra_multiqc_config: - type: file - description: Second optional config yml for MultiQC. Will override common sections - in multiqc_config. - pattern: "*.{yml,yaml}" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML - - multiqc_logo: - type: file - description: Optional logo file for MultiQC - pattern: "*.{png}" - ontologies: [] - - replace_names: - type: file - description: | - Optional two-column sample renaming file. First column a set of - patterns, second column a set of corresponding replacements. Passed via - MultiQC's `--replace-names` option. - pattern: "*.{tsv}" - ontologies: - - edam: http://edamontology.org/format_3475 # TSV - - sample_names: - type: file - description: | - Optional TSV file with headers, passed to the MultiQC --sample_names - argument. - pattern: "*.{tsv}" - ontologies: - - edam: http://edamontology.org/format_3475 # TSV -output: - report: - - "*.html": + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - multiqc_files: type: file - description: MultiQC report file - pattern: ".html" + description: | + List of reports / files recognised by MultiQC, for example the html and zip output of FastQC ontologies: [] - data: - - "*_data": - type: directory - description: MultiQC data dir - pattern: "multiqc_data" - plots: - - "*_plots": + - multiqc_config: + type: file + description: Optional config yml for MultiQC + pattern: "*.{yml,yaml}" + ontologies: + - edam: http://edamontology.org/format_3750 + - multiqc_logo: type: file - description: Plots created by MultiQC - pattern: "*_data" + description: Optional logo file for MultiQC + pattern: "*.{png}" ontologies: [] - versions: - - versions.yml: + - replace_names: + type: file + description: | + Optional two-column sample renaming file. First column a set of + patterns, second column a set of corresponding replacements. Passed via + MultiQC's `--replace-names` option. + pattern: "*.{tsv}" + ontologies: + - edam: http://edamontology.org/format_3475 + - sample_names: type: file - description: File containing software versions - pattern: "versions.yml" + description: | + Optional TSV file with headers, passed to the MultiQC --sample_names + argument. + pattern: "*.{tsv}" ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - edam: http://edamontology.org/format_3475 +output: + report: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - "*.html": + type: file + description: MultiQC report file + pattern: ".html" + ontologies: [] + data: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - "*_data": + type: directory + description: MultiQC data dir + pattern: "multiqc_data" + plots: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - "*_plots": + type: file + description: Plots created by MultiQC + pattern: "*_plots" + ontologies: [] + versions: + - - ${task.process}: + type: string + description: The process the versions were collected from + - multiqc: + type: string + description: The tool name + - multiqc --version | sed "s/.* //g": + type: eval + description: The expression to obtain the version of the tool authors: - "@abhi18av" - "@bunop" @@ -90,3 +107,27 @@ maintainers: - "@bunop" - "@drpatelh" - "@jfy133" +containers: + conda: + linux/amd64: + lock_file: modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-db7c73dae76bc9e6_1.txt + linux/arm64: + lock_file: modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-d167b8012595a136_1.txt + docker: + linux/amd64: + name: community.wave.seqera.io/library/multiqc:1.34--db7c73dae76bc9e6 + build_id: bd-db7c73dae76bc9e6_1 + scan_id: sc-66fc7138dbf1cf48_1 + linux/arm64: + name: community.wave.seqera.io/library/multiqc:1.34--d167b8012595a136 + build_id: bd-d167b8012595a136_1 + scan_id: sc-ac701dfa631a2af9_1 + singularity: + linux/amd64: + name: oras://community.wave.seqera.io/library/multiqc:1.34--4fc8657c816047c0 + build_id: bd-4fc8657c816047c0_1 + https: https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/1b/1bef8af6be88c5733461959c46ac8ef73d18f65277f62a1695d0e1633054f9c2/data + linux/arm64: + name: oras://community.wave.seqera.io/library/multiqc:1.34--7fbd82d945c06726 + build_id: bd-7fbd82d945c06726_1 + https: https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/9a/9a1fec9662a152683e6fcae440d0ce20920b3b89dc62d1e3a52e73f92eba0969/data diff --git a/modules/nf-core/multiqc/tests/main.nf.test b/modules/nf-core/multiqc/tests/main.nf.test index 0745e25ab..a663b1de1 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test +++ b/modules/nf-core/multiqc/tests/main.nf.test @@ -15,25 +15,84 @@ nextflow_process { when { process { """ - input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) - input[1] = [] - input[2] = [] - input[3] = [] - input[4] = [] - input[5] = [] + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + [], + [], + [], + [] + ]) """ } } then { - assertAll( - { assert process.success }, - { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, - { assert process.out.data[0] ==~ ".*/multiqc_data" }, - { assert snapshot(process.out.versions).match("multiqc_versions_single") } - ) + assert process.success + assert snapshot( + sanitizeOutput(process.out).collectEntries { key, val -> + if (key == "data") { + return [key, val.collect { [path(it[1]).list().collect { file(it.toString()).name }] }] + } + else if (key == "plots") { + return [key, val.collect { [ + "pdf", + path("${it[1]}/pdf").list().collect { file(it.toString()).name }, + "png", + path("${it[1]}/png").list().collect { file(it.toString()).name }, + "svg", + path("${it[1]}/svg").list().collect { file(it.toString()).name }] }] + } + else if (key == "report") { + return [key, file(val[0][1].toString()).name] + } + return [key, val] + } + ).match() } + } + + test("sarscov2 single-end [fastqc] - custom prefix") { + config "./custom_prefix.config" + when { + process { + """ + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + [], + [], + [], + [] + ]) + """ + } + } + + then { + assert process.success + assert snapshot( + sanitizeOutput(process.out).collectEntries { key, val -> + if (key == "data") { + return [key, val.collect { [path(it[1]).list().collect { file(it.toString()).name }] }] + } + else if (key == "plots") { + return [key, val.collect { [ + "pdf", + path("${it[1]}/pdf").list().collect { file(it.toString()).name }, + "png", + path("${it[1]}/png").list().collect { file(it.toString()).name }, + "svg", + path("${it[1]}/svg").list().collect { file(it.toString()).name }] }] + } + else if (key == "report") { + return [key, file(val[0][1].toString()).name] + } + return [key, val] + } + ).match() + } } test("sarscov2 single-end [fastqc] - custom prefix") { @@ -67,23 +126,85 @@ nextflow_process { when { process { """ - input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) - input[1] = Channel.of(file("https://github.com/nf-core/tools/raw/dev/nf_core/pipeline-template/assets/multiqc_config.yml", checkIfExists: true)) - input[2] = [] - input[3] = [] - input[4] = [] - input[5] = [] + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + file("https://raw.githubusercontent.com/nf-core/seqinspector/1.0.0/assets/multiqc_config.yml", checkIfExists: true), + [], + [], + [] + ]) """ } } then { - assertAll( - { assert process.success }, - { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, - { assert process.out.data[0] ==~ ".*/multiqc_data" }, - { assert snapshot(process.out.versions).match("multiqc_versions_config") } - ) + assert process.success + assert snapshot( + sanitizeOutput(process.out).collectEntries { key, val -> + if (key == "data") { + return [key, val.collect { [path(it[1]).list().collect { file(it.toString()).name }] }] + } + else if (key == "plots") { + return [key, val.collect { [ + "pdf", + path("${it[1]}/pdf").list().collect { file(it.toString()).name }, + "png", + path("${it[1]}/png").list().collect { file(it.toString()).name }, + "svg", + path("${it[1]}/svg").list().collect { file(it.toString()).name }] }] + } + else if (key == "report") { + return [key, file(val[0][1].toString()).name] + } + return [key, val] + } + ).match() + } + } + + test("sarscov2 single-end [fastqc] [multiple configs]") { + + when { + process { + """ + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + [ + file("https://raw.githubusercontent.com/nf-core/seqinspector/1.0.0/assets/multiqc_config.yml", checkIfExists: true), + file("https://raw.githubusercontent.com/nf-core/seqinspector/1.0.0/assets/multiqc_config.yml", checkIfExists: true) + ], + [], + [], + [] + ]) + """ + } + } + + then { + assert process.success + assert snapshot( + sanitizeOutput(process.out).collectEntries { key, val -> + if (key == "data") { + return [key, val.collect { [path(it[1]).list().collect { file(it.toString()).name }] }] + } + else if (key == "plots") { + return [key, val.collect { [ + "pdf", + path("${it[1]}/pdf").list().collect { file(it.toString()).name }, + "png", + path("${it[1]}/png").list().collect { file(it.toString()).name }, + "svg", + path("${it[1]}/svg").list().collect { file(it.toString()).name }] }] + } + else if (key == "report") { + return [key, file(val[0][1].toString()).name] + } + return [key, val] + } + ).match() } } @@ -94,25 +215,23 @@ nextflow_process { when { process { """ - input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) - input[1] = [] - input[2] = [] - input[3] = [] - input[4] = [] - input[5] = [] + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + [], + [], + [], + [] + ]) """ } } then { + assert process.success assertAll( - { assert process.success }, - { assert snapshot(process.out.report.collect { file(it).getName() } + - process.out.data.collect { file(it).getName() } + - process.out.plots.collect { file(it).getName() } + - process.out.versions ).match("multiqc_stub") } + { assert snapshot(sanitizeOutput(process.out)).match() } ) } - } } diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap index a88bafd67..7c2f370f3 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test.snap +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -1,41 +1,422 @@ { - "multiqc_versions_single": { + "sarscov2 single-end [fastqc] [multiple configs]": { "content": [ - [ - "versions.yml:md5,737bb2c7cad54ffc2ec020791dc48b8f" - ] + { + "data": [ + [ + [ + "fastqc-status-check-heatmap.txt", + "fastqc_overrepresented_sequences_plot.txt", + "fastqc_per_base_n_content_plot.txt", + "fastqc_per_base_sequence_quality_plot.txt", + "fastqc_per_sequence_gc_content_plot_Counts.txt", + "fastqc_per_sequence_gc_content_plot_Percentages.txt", + "fastqc_per_sequence_quality_scores_plot.txt", + "fastqc_sequence_counts_plot.txt", + "fastqc_sequence_duplication_levels_plot.txt", + "fastqc_sequence_length_distribution_plot.txt", + "fastqc_top_overrepresented_sequences_table.txt", + "llms-full.txt", + "multiqc.log", + "multiqc.parquet", + "multiqc_citations.txt", + "multiqc_data.json", + "multiqc_fastqc.txt", + "multiqc_general_stats.txt", + "multiqc_sources.txt" + ] + ] + ], + "plots": [ + [ + "pdf", + [ + "fastqc-status-check-heatmap.pdf", + "fastqc_overrepresented_sequences_plot.pdf", + "fastqc_per_base_n_content_plot.pdf", + "fastqc_per_base_sequence_quality_plot.pdf", + "fastqc_per_sequence_gc_content_plot_Counts.pdf", + "fastqc_per_sequence_gc_content_plot_Percentages.pdf", + "fastqc_per_sequence_quality_scores_plot.pdf", + "fastqc_sequence_counts_plot-cnt.pdf", + "fastqc_sequence_counts_plot-pct.pdf", + "fastqc_sequence_duplication_levels_plot.pdf", + "fastqc_sequence_length_distribution_plot.pdf", + "fastqc_top_overrepresented_sequences_table.pdf" + ], + "png", + [ + "fastqc-status-check-heatmap.png", + "fastqc_overrepresented_sequences_plot.png", + "fastqc_per_base_n_content_plot.png", + "fastqc_per_base_sequence_quality_plot.png", + "fastqc_per_sequence_gc_content_plot_Counts.png", + "fastqc_per_sequence_gc_content_plot_Percentages.png", + "fastqc_per_sequence_quality_scores_plot.png", + "fastqc_sequence_counts_plot-cnt.png", + "fastqc_sequence_counts_plot-pct.png", + "fastqc_sequence_duplication_levels_plot.png", + "fastqc_sequence_length_distribution_plot.png", + "fastqc_top_overrepresented_sequences_table.png" + ], + "svg", + [ + "fastqc-status-check-heatmap.svg", + "fastqc_overrepresented_sequences_plot.svg", + "fastqc_per_base_n_content_plot.svg", + "fastqc_per_base_sequence_quality_plot.svg", + "fastqc_per_sequence_gc_content_plot_Counts.svg", + "fastqc_per_sequence_gc_content_plot_Percentages.svg", + "fastqc_per_sequence_quality_scores_plot.svg", + "fastqc_sequence_counts_plot-cnt.svg", + "fastqc_sequence_counts_plot-pct.svg", + "fastqc_sequence_duplication_levels_plot.svg", + "fastqc_sequence_length_distribution_plot.svg", + "fastqc_top_overrepresented_sequences_table.svg" + ] + ] + ], + "report": "multiqc_report.html", + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.34" + ] + ] + } ], + "timestamp": "2026-03-17T16:15:42.577775492", "meta": { - "nf-test": "0.9.3", - "nextflow": "24.10.4" - }, - "timestamp": "2025-10-27T13:33:24.356715" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, - "multiqc_stub": { + "sarscov2 single-end [fastqc]": { "content": [ - [ - "multiqc_report.html", - "multiqc_data", - "multiqc_plots", - "versions.yml:md5,737bb2c7cad54ffc2ec020791dc48b8f" - ] + { + "data": [ + [ + [ + "fastqc-status-check-heatmap.txt", + "fastqc_overrepresented_sequences_plot.txt", + "fastqc_per_base_n_content_plot.txt", + "fastqc_per_base_sequence_quality_plot.txt", + "fastqc_per_sequence_gc_content_plot_Counts.txt", + "fastqc_per_sequence_gc_content_plot_Percentages.txt", + "fastqc_per_sequence_quality_scores_plot.txt", + "fastqc_sequence_counts_plot.txt", + "fastqc_sequence_duplication_levels_plot.txt", + "fastqc_sequence_length_distribution_plot.txt", + "fastqc_top_overrepresented_sequences_table.txt", + "llms-full.txt", + "multiqc.log", + "multiqc.parquet", + "multiqc_citations.txt", + "multiqc_data.json", + "multiqc_fastqc.txt", + "multiqc_general_stats.txt", + "multiqc_software_versions.txt", + "multiqc_sources.txt" + ] + ] + ], + "plots": [ + [ + "pdf", + [ + "fastqc-status-check-heatmap.pdf", + "fastqc_overrepresented_sequences_plot.pdf", + "fastqc_per_base_n_content_plot.pdf", + "fastqc_per_base_sequence_quality_plot.pdf", + "fastqc_per_sequence_gc_content_plot_Counts.pdf", + "fastqc_per_sequence_gc_content_plot_Percentages.pdf", + "fastqc_per_sequence_quality_scores_plot.pdf", + "fastqc_sequence_counts_plot-cnt.pdf", + "fastqc_sequence_counts_plot-pct.pdf", + "fastqc_sequence_duplication_levels_plot.pdf", + "fastqc_sequence_length_distribution_plot.pdf", + "fastqc_top_overrepresented_sequences_table.pdf" + ], + "png", + [ + "fastqc-status-check-heatmap.png", + "fastqc_overrepresented_sequences_plot.png", + "fastqc_per_base_n_content_plot.png", + "fastqc_per_base_sequence_quality_plot.png", + "fastqc_per_sequence_gc_content_plot_Counts.png", + "fastqc_per_sequence_gc_content_plot_Percentages.png", + "fastqc_per_sequence_quality_scores_plot.png", + "fastqc_sequence_counts_plot-cnt.png", + "fastqc_sequence_counts_plot-pct.png", + "fastqc_sequence_duplication_levels_plot.png", + "fastqc_sequence_length_distribution_plot.png", + "fastqc_top_overrepresented_sequences_table.png" + ], + "svg", + [ + "fastqc-status-check-heatmap.svg", + "fastqc_overrepresented_sequences_plot.svg", + "fastqc_per_base_n_content_plot.svg", + "fastqc_per_base_sequence_quality_plot.svg", + "fastqc_per_sequence_gc_content_plot_Counts.svg", + "fastqc_per_sequence_gc_content_plot_Percentages.svg", + "fastqc_per_sequence_quality_scores_plot.svg", + "fastqc_sequence_counts_plot-cnt.svg", + "fastqc_sequence_counts_plot-pct.svg", + "fastqc_sequence_duplication_levels_plot.svg", + "fastqc_sequence_length_distribution_plot.svg", + "fastqc_top_overrepresented_sequences_table.svg" + ] + ] + ], + "report": "multiqc_report.html", + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.34" + ] + ] + } ], + "timestamp": "2026-03-17T16:21:17.072841555", "meta": { - "nf-test": "0.9.3", - "nextflow": "24.10.4" - }, - "timestamp": "2025-10-27T13:34:11.103619" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, - "multiqc_versions_config": { + "sarscov2 single-end [fastqc] - stub": { "content": [ - [ - "versions.yml:md5,737bb2c7cad54ffc2ec020791dc48b8f" - ] + { + "data": [ + [ + { + "id": "FASTQC" + }, + [ + ".stub:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "plots": [ + [ + { + "id": "FASTQC" + }, + [ + ".stub:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "report": [ + [ + { + "id": "FASTQC" + }, + "multiqc_report.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.34" + ] + ] + } ], + "timestamp": "2026-02-26T15:14:39.789193051", "meta": { - "nf-test": "0.9.3", - "nextflow": "24.10.4" - }, - "timestamp": "2025-10-27T13:34:04.615233" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } + }, + "sarscov2 single-end [fastqc] [config]": { + "content": [ + { + "data": [ + [ + [ + "fastqc-status-check-heatmap.txt", + "fastqc_overrepresented_sequences_plot.txt", + "fastqc_per_base_n_content_plot.txt", + "fastqc_per_base_sequence_quality_plot.txt", + "fastqc_per_sequence_gc_content_plot_Counts.txt", + "fastqc_per_sequence_gc_content_plot_Percentages.txt", + "fastqc_per_sequence_quality_scores_plot.txt", + "fastqc_sequence_counts_plot.txt", + "fastqc_sequence_duplication_levels_plot.txt", + "fastqc_sequence_length_distribution_plot.txt", + "fastqc_top_overrepresented_sequences_table.txt", + "llms-full.txt", + "multiqc.log", + "multiqc.parquet", + "multiqc_citations.txt", + "multiqc_data.json", + "multiqc_fastqc.txt", + "multiqc_general_stats.txt", + "multiqc_sources.txt" + ] + ] + ], + "plots": [ + [ + "pdf", + [ + "fastqc-status-check-heatmap.pdf", + "fastqc_overrepresented_sequences_plot.pdf", + "fastqc_per_base_n_content_plot.pdf", + "fastqc_per_base_sequence_quality_plot.pdf", + "fastqc_per_sequence_gc_content_plot_Counts.pdf", + "fastqc_per_sequence_gc_content_plot_Percentages.pdf", + "fastqc_per_sequence_quality_scores_plot.pdf", + "fastqc_sequence_counts_plot-cnt.pdf", + "fastqc_sequence_counts_plot-pct.pdf", + "fastqc_sequence_duplication_levels_plot.pdf", + "fastqc_sequence_length_distribution_plot.pdf", + "fastqc_top_overrepresented_sequences_table.pdf" + ], + "png", + [ + "fastqc-status-check-heatmap.png", + "fastqc_overrepresented_sequences_plot.png", + "fastqc_per_base_n_content_plot.png", + "fastqc_per_base_sequence_quality_plot.png", + "fastqc_per_sequence_gc_content_plot_Counts.png", + "fastqc_per_sequence_gc_content_plot_Percentages.png", + "fastqc_per_sequence_quality_scores_plot.png", + "fastqc_sequence_counts_plot-cnt.png", + "fastqc_sequence_counts_plot-pct.png", + "fastqc_sequence_duplication_levels_plot.png", + "fastqc_sequence_length_distribution_plot.png", + "fastqc_top_overrepresented_sequences_table.png" + ], + "svg", + [ + "fastqc-status-check-heatmap.svg", + "fastqc_overrepresented_sequences_plot.svg", + "fastqc_per_base_n_content_plot.svg", + "fastqc_per_base_sequence_quality_plot.svg", + "fastqc_per_sequence_gc_content_plot_Counts.svg", + "fastqc_per_sequence_gc_content_plot_Percentages.svg", + "fastqc_per_sequence_quality_scores_plot.svg", + "fastqc_sequence_counts_plot-cnt.svg", + "fastqc_sequence_counts_plot-pct.svg", + "fastqc_sequence_duplication_levels_plot.svg", + "fastqc_sequence_length_distribution_plot.svg", + "fastqc_top_overrepresented_sequences_table.svg" + ] + ] + ], + "report": "multiqc_report.html", + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.34" + ] + ] + } + ], + "timestamp": "2026-03-17T16:15:30.372239611", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } + }, + "sarscov2 single-end [fastqc] - custom prefix": { + "content": [ + { + "data": [ + [ + [ + "fastqc-status-check-heatmap.txt", + "fastqc_overrepresented_sequences_plot.txt", + "fastqc_per_base_n_content_plot.txt", + "fastqc_per_base_sequence_quality_plot.txt", + "fastqc_per_sequence_gc_content_plot_Counts.txt", + "fastqc_per_sequence_gc_content_plot_Percentages.txt", + "fastqc_per_sequence_quality_scores_plot.txt", + "fastqc_sequence_counts_plot.txt", + "fastqc_sequence_duplication_levels_plot.txt", + "fastqc_sequence_length_distribution_plot.txt", + "fastqc_top_overrepresented_sequences_table.txt", + "llms-full.txt", + "multiqc.log", + "multiqc.parquet", + "multiqc_citations.txt", + "multiqc_data.json", + "multiqc_fastqc.txt", + "multiqc_general_stats.txt", + "multiqc_software_versions.txt", + "multiqc_sources.txt" + ] + ] + ], + "plots": [ + [ + "pdf", + [ + "fastqc-status-check-heatmap.pdf", + "fastqc_overrepresented_sequences_plot.pdf", + "fastqc_per_base_n_content_plot.pdf", + "fastqc_per_base_sequence_quality_plot.pdf", + "fastqc_per_sequence_gc_content_plot_Counts.pdf", + "fastqc_per_sequence_gc_content_plot_Percentages.pdf", + "fastqc_per_sequence_quality_scores_plot.pdf", + "fastqc_sequence_counts_plot-cnt.pdf", + "fastqc_sequence_counts_plot-pct.pdf", + "fastqc_sequence_duplication_levels_plot.pdf", + "fastqc_sequence_length_distribution_plot.pdf", + "fastqc_top_overrepresented_sequences_table.pdf" + ], + "png", + [ + "fastqc-status-check-heatmap.png", + "fastqc_overrepresented_sequences_plot.png", + "fastqc_per_base_n_content_plot.png", + "fastqc_per_base_sequence_quality_plot.png", + "fastqc_per_sequence_gc_content_plot_Counts.png", + "fastqc_per_sequence_gc_content_plot_Percentages.png", + "fastqc_per_sequence_quality_scores_plot.png", + "fastqc_sequence_counts_plot-cnt.png", + "fastqc_sequence_counts_plot-pct.png", + "fastqc_sequence_duplication_levels_plot.png", + "fastqc_sequence_length_distribution_plot.png", + "fastqc_top_overrepresented_sequences_table.png" + ], + "svg", + [ + "fastqc-status-check-heatmap.svg", + "fastqc_overrepresented_sequences_plot.svg", + "fastqc_per_base_n_content_plot.svg", + "fastqc_per_base_sequence_quality_plot.svg", + "fastqc_per_sequence_gc_content_plot_Counts.svg", + "fastqc_per_sequence_gc_content_plot_Percentages.svg", + "fastqc_per_sequence_quality_scores_plot.svg", + "fastqc_sequence_counts_plot-cnt.svg", + "fastqc_sequence_counts_plot-pct.svg", + "fastqc_sequence_duplication_levels_plot.svg", + "fastqc_sequence_length_distribution_plot.svg", + "fastqc_top_overrepresented_sequences_table.svg" + ] + ] + ], + "report": "custom_prefix.html", + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.34" + ] + ] + } + ], + "timestamp": "2026-03-17T16:15:18.189023981", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } } } \ No newline at end of file diff --git a/modules/nf-core/multiqc/tests/nextflow.config b/modules/nf-core/multiqc/tests/nextflow.config index c537a6a3e..374dfef2c 100644 --- a/modules/nf-core/multiqc/tests/nextflow.config +++ b/modules/nf-core/multiqc/tests/nextflow.config @@ -1,5 +1,6 @@ process { withName: 'MULTIQC' { ext.prefix = null + ext.args = '-p' } } diff --git a/nextflow.config b/nextflow.config index df333b893..21a88090c 100644 --- a/nextflow.config +++ b/nextflow.config @@ -13,7 +13,6 @@ params { root_folder = null local_input_type = 'mzML' database = null - acquisition_method = null id_only = false // Input options and validation of sdrf files @@ -32,6 +31,7 @@ params { run_fdr_cutoff = 0.10 protein_level_fdr_cutoff = 0.01 psm_level_fdr_cutoff = 0.01 + fdr_conservative = true // Use (D+1)/T formula (true) or (D+1)/(T+D) (false) for FDR estimation psm_clean = false // Debug level @@ -57,17 +57,17 @@ params { shuffle_max_attempts = 30 shuffle_sequence_identity_threshold = 0.5 - //// Peak picking if used + // Peak picking if used openms_peakpicking = false peakpicking_inmemory = false peakpicking_ms_levels = null // means all/auto - //// Conversion and mzml statistics flags + // Conversion and mzml statistics flags reindex_mzml = true + mzml_statistics = false mzml_features = false // Isobaric analyses - labelling_type = null isotope_correction = false // Disable plex isotope correction plex_corr_matrix_file = null // Path to the correction matrix file if disable isotope correction is true @@ -81,13 +81,11 @@ params { precursor_isotope_deviation = 10.0 // shared search engine parameters - enzyme = 'Trypsin' met_excision = true // Met-excision is enabled by default num_enzyme_termini = 'fully' allowed_missed_cleavages = 2 precursor_mass_tolerance = 5 precursor_mass_tolerance_unit = 'ppm' - fixed_mods = 'Carbamidomethyl (C)' variable_mods = 'Oxidation (M)' enable_mod_localization = false mod_localization = 'Phospho (S),Phospho (T),Phospho (Y)' @@ -104,15 +102,10 @@ params { num_hits = 1 max_mods = 3 min_peaks = 10 //minimum number of peaks in a spectrum - min_pr_mz = 400 - max_pr_mz = 2400 - min_fr_mz = 100 - max_fr_mz = 1800 // MS2Features flags (MS2-based features for Percolator) ms2features_enable = false ms2features_model_dir = null - ms2features_range = 'independent_run' ms2features_model = 'generic' // Default model for alphapeptdeep ms2features_generators = 'deeplc,alphapeptdeep' ms2features_calibration = 0.15 @@ -150,18 +143,24 @@ params { consensusid_considered_top_hits = 0 // onsite options - onsite_algorithm = 'lucxor' // Options: 'ascore', 'phosphors', 'lucxor' - onsite_fragment_method = 'CID' // CID or HCD - onsite_fragment_tolerance = 0.5 - onsite_fragment_error_units = 'Da' // Da or ppm - onsite_add_decoys = false // Add decoy modifications - onsite_neutral_losses = null - onsite_decoy_mass = null - onsite_decoy_neutral_losses = null - onsite_threads = 1 - onsite_min_psms = 5 // Minimum number of high-scoring PSMs for lucxor model training - onsite_disable_split_by_charge = false // Disable splitting PSMs by charge state for lucxor - onsite_compute_all_scores = false // Compute all scores for all candidate sites + onsite_algorithm = 'lucxor' // Options: 'ascore', 'phosphors', 'lucxor' + onsite_fragment_method = 'CID' // CID or HCD + onsite_rt_tolerance = 0.01 + onsite_fragment_tolerance = 0.5 + onsite_modeling_score_threshold = 0.95 + onsite_scoring_threshold = 0.0 + onsite_fragment_error_units = 'Da' // Da or ppm + onsite_add_decoys = false // Add decoy modifications + onsite_neutral_losses = null + onsite_decoy_mass = null + onsite_decoy_neutral_losses = null + onsite_threads = 1 + onsite_target_modifications = null + onsite_min_num_psms_model = 5 // Minimum number of high-scoring PSMs for lucxor model training + onsite_disable_split_by_charge = false // Disable splitting PSMs by charge state for lucxor + onsite_compute_all_scores = false // Compute all scores for all candidate sites + onsite_min_mz = 150.0 + onsite_max_num_perm = 16384 // Epifany top_PSMs = 1 @@ -187,9 +186,9 @@ params { protein_inference_method = 'aggregation' protein_quant = 'unique_peptides' quantification_method = 'feature_intensity' + lfq_seeding_algorithm = 'biosaur2' // Feature seeding: 'multiplex' (default) or 'biosaur2' mass_recalibration = false alignment_order = 'star' - add_triqler_output = false quantify_decoys = false // ProteomicsLFQ MBR parameters @@ -201,50 +200,6 @@ params { // Bruker data convert_dotd = false - // DIA-NN - diann_debug = 3 - scan_window = 8 - scan_window_automatic = true - performance_mode = true // add '--min-corr 2 --corr-diff 1 --time-corr-only' - quick_mass_acc = true - mass_acc_automatic = true - pg_level = 2 - species_genes = false - diann_normalize = true - diann_speclib = null - diann_report_decoys = false - diann_export_xic = false - - // DIA-NN: Extras - skip_preliminary_analysis = false - empirical_assembly_log = null - random_preanalysis = false - random_preanalysis_seed = 42 - empirical_assembly_ms_n = 200 - enable_diann_mztab = false - - - // MSstats general options - msstats_remove_one_feat_prot = true - ref_condition = null - contrasts = 'pairwise' - msstats_threshold = 0.05 - skip_post_msstats = false - - // MSstats LFQ options - msstatslfq_removeFewMeasurements = true - msstatslfq_feature_subset_protein = 'top3' - msstatslfq_quant_summary_method = 'TMP' - - // MSstats ISO options - msstatsiso_useunique_peptide = true - msstatsiso_rmpsm_withfewmea_withinrun = true - msstatsiso_summaryformultiple_psm = 'sum' - msstatsiso_summarization_method = 'msstats' - msstatsiso_global_norm = true - msstatsiso_remove_norm_channel = true - msstatsiso_reference_normalization = true - msstats_plot_profile_qc = false // pmultiqc options enable_pmultiqc = true @@ -266,12 +221,11 @@ params { email_on_fail = null plaintext_email = false monochrome_logs = false - hook_url = System.getenv('HOOK_URL') help = false help_full = false show_hidden = false version = false - pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/' + pipelines_testdata_base_path = 'https://raw.githubusercontent.com/bigbio/quantms-test-datasets/' trace_report_suffix = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss') // Config options @@ -288,6 +242,10 @@ params { validate_params = true } +// Backwards compatibility for publishDir syntax +outputDir = params.outdir +workflow.output.mode = params.publish_dir_mode + // Load base.config by default for all pipelines includeConfig 'conf/base.config' @@ -311,7 +269,7 @@ profiles { } arm64 { process.arch = 'arm64' - // see discussion: https://github.com/nf-core/modules/issues/6694 + // TODO https://github.com/nf-core/modules/issues/6694 // For now if you're using arm64 you have to use wave for the sake of the maintainers // wave profile apptainer.ociAutoPull = true @@ -390,11 +348,8 @@ profiles { test_tmt_corr { includeConfig 'conf/tests/test_tmt_corr.config' } test_lfq { includeConfig 'conf/tests/test_lfq.config' } test_lfq_sage { includeConfig 'conf/tests/test_lfq_sage.config' } - test_dia { includeConfig 'conf/tests/test_dia.config' } - test_latest_dia { includeConfig 'conf/tests/test_latest_dia.config' } test_full_lfq { includeConfig 'conf/tests/test_full_lfq.config' } test_full_tmt { includeConfig 'conf/tests/test_full_tmt.config' } - test_full_dia { includeConfig 'conf/tests/test_full_dia.config' } test_full { includeConfig 'conf/tests/test_full_lfq.config' } test_dda_id_alphapeptdeep { includeConfig 'conf/tests/test_dda_id_alphapeptdeep.config' } test_dda_id_ms2pip { includeConfig 'conf/tests/test_dda_id_ms2pip.config' } @@ -412,8 +367,8 @@ profiles { // Load bigbio/quantms custom profiles from different institutions. includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/nfcore_custom.config" : "/dev/null" - // Load bigbio/quantms custom profiles from different institutions. +// TODO nf-core: Optionally, you can add a pipeline-specific nf-core config at https://github.com/nf-core/configs includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/pipeline/quantms.config" : "/dev/null" // Set default registry for Apptainer, Docker, Podman, Charliecloud and Singularity independent of -profile @@ -521,8 +476,8 @@ manifest { description = """Quantitative Mass Spectrometry nf-core workflow""" mainScript = 'main.nf' defaultBranch = 'master' - nextflowVersion = '!>=25.04.0' - version = '1.7.0' + nextflowVersion = '!>=25.10.4' + version = '1.8.0' doi = '10.5281/zenodo.15573386' } @@ -536,5 +491,8 @@ validation { monochromeLogs = params.monochrome_logs } -// Load modules.config for DSL2 module specific options -includeConfig 'conf/modules/modules.config' +// Load per-workflow module configs for DSL2 module specific options +includeConfig 'conf/modules/shared.config' +includeConfig 'conf/modules/id.config' +includeConfig 'conf/modules/tmt.config' +includeConfig 'conf/modules/lfq.config' diff --git a/nextflow_schema.json b/nextflow_schema.json index f9f191726..9f5ef2679 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -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.\n\nThe following parameters are read **exclusively** from the SDRF file (required columns):\n\n * `acquisition_method` (from 'Proteomics Data Acquisition Method' column),\n * `labelling_type` (from 'Label' column),\n * `enzyme` (from 'Enzyme' column),\n * `fixed_mods` (from 'FixedModifications' column)\n\nThe following parameters are read from SDRF but can be **overridden via command line**:\n\n * `precursor_mass_tolerance` (from 'PrecursorMassTolerance' column),\n * `precursor_mass_tolerance_unit` (from 'PrecursorMassToleranceUnit' column),\n * `fragment_mass_tolerance` (from 'FragmentMassTolerance' column),\n * `fragment_mass_tolerance_unit` (from 'FragmentMassToleranceUnit' column),\n * `variable_mods` (from 'VariableModifications' column)", "fa_icon": "fas fa-file-csv" }, "outdir": { @@ -43,22 +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." - }, - "acquisition_method": { - "type": "string", - "description": "Proteomics data acquisition method", - "enum": ["dda", "dia"], - "fa_icon": "far fa-list-ol" + "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." }, "id_only": { "type": "boolean", @@ -219,6 +213,12 @@ "fa_icon": "far fa-check-square", "help_text": "Force re-indexing in the beginning of the pipeline to make sure that indices are up-to-date and to avoid redundant indexing on-demand in steps that require an index (e.g., Comet)." }, + "mzml_statistics": { + "type": "boolean", + "description": "Compute MS1/MS2 statistics from mzML files. Only runs on mzML files, .d files are always skipped.", + "help_text": "Enable to generate *_ms_info.parquet statistics for QC reporting. Only available for mzML files, Bruker .d files are always excluded.", + "fa_icon": "far fa-check-square" + }, "mzml_features": { "type": "boolean", "description": "Compute with mzmlstatistics step the features at MS1 level and output to a RAW file, only available for mzML files", @@ -248,13 +248,6 @@ "fa_icon": "fas fa-sliders-h", "help_text": "Since sage's runtime benefits from building an index only once per database and processing files in parallel, you can choose the number of sage processes to be spawned here. Input mzMLs will be distributed equally among them in arbitrary order." }, - "enzyme": { - "type": "string", - "description": "The enzyme to be used for in-silico digestion, in 'OpenMS format'", - "default": "Trypsin", - "fa_icon": "fas fa-list-ol", - "help_text": "Specify which enzymatic restriction should be applied, e.g. 'unspecific cleavage', 'Trypsin' (default), see OpenMS\n[enzymes](https://github.com/OpenMS/OpenMS/blob/develop/share/OpenMS/CHEMISTRY/Enzymes.xml). Note: MSGF does not support extended\ncutting rules, as used by default with `Trypsin`. I.e. if you specify `Trypsin` with MSGF, it will be automatically converted to\n`Trypsin/P`= 'Trypsin without proline rule'." - }, "met_excision": { "type": "boolean", "description": "Database searches accounted for N-terminal methionine excision, a common co-translational modification where the initial methionine is enzymatically removed from proteins.", @@ -280,43 +273,38 @@ "type": "integer", "description": "Precursor mass tolerance used for database search. For High-Resolution instruments a precursor mass tolerance value of 5 ppm is recommended (i.e. 5). See also [`--precursor_mass_tolerance_unit`](#precursor_mass_tolerance_unit).", "default": 5, - "fa_icon": "fas fa-sliders-h" + "fa_icon": "fas fa-sliders-h", + "help_text": "This value can be overridden via command line. If not specified, the value from the SDRF file will be used." }, "precursor_mass_tolerance_unit": { "type": "string", "description": "Precursor mass tolerance unit used for database search. Possible values are 'ppm' (default) and 'Da'.", "default": "ppm", "fa_icon": "fas fa-sliders-h", - "enum": ["Da", "ppm"] + "enum": ["Da", "ppm"], + "help_text": "This value can be overridden via command line. If not specified, the value from the SDRF file will be used." }, "fragment_mass_tolerance": { "type": "number", "description": "Fragment mass tolerance used for database search. The default of 0.03 Da is for high-resolution instruments.", "default": 0.03, "fa_icon": "fas fa-sliders-h", - "help_text": "Caution: for Comet we are estimating the `fragment_bin_tolerance` parameter based on this automatically." + "help_text": "Caution: for Comet we are estimating the `fragment_bin_tolerance` parameter based on this automatically. This value can be overridden via command line. If not specified, the value from the SDRF file will be used." }, "fragment_mass_tolerance_unit": { "type": "string", - "description": "Fragment mass tolerance unit used for database search. Possible values are 'ppm' (default) and 'Da'.", + "description": "Fragment mass tolerance unit used for database search. Possible values are 'ppm' and 'Da' (default).", "default": "Da", "fa_icon": "fas fa-list-ol", - "help_text": "Caution: for Comet we are estimating the `fragment_bin_tolerance` parameter based on this automatically.", + "help_text": "Caution: for Comet we are estimating the `fragment_bin_tolerance` parameter based on this automatically. This value can be overridden via command line. If not specified, the value from the SDRF file will be used.", "enum": ["Da", "ppm"] }, - "fixed_mods": { - "type": "string", - "description": "A comma-separated list of fixed modifications with their Unimod name to be searched during database search", - "default": "Carbamidomethyl (C)", - "fa_icon": "fas fa-tasks", - "help_text": "Specify which fixed modifications should be applied to the database search (eg. '' or 'Carbamidomethyl (C)', see Unimod modifications\nin the style '({unimod name} ({optional term specificity} {optional origin})').\nAll possible modifications can be found in the restrictions mentioned in the command line documentation of e.g. [CometAdapter](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/release/latest/html/TOPP_CometAdapter.html) (scroll down a bit for the complete set).\nMultiple fixed modifications can be specified comma separated (e.g. 'Carbamidomethyl (C),Oxidation (M)').\nFixed modifications need to be found at every matching amino acid for a peptide to be reported." - }, "variable_mods": { "type": "string", "description": "A comma-separated list of variable modifications with their Unimod name to be searched during database search", "default": "Oxidation (M)", "fa_icon": "fas fa-tasks", - "help_text": "Specify which variable modifications should be applied to the database search (eg. '' or 'Oxidation (M)', see Unimod modifications\nin the style '({unimod name} ({optional term specificity} {optional origin})').\nAll possible modifications can be found in the restrictions mentioned in the command line documentation of e.g. [CometAdapter](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/release/latest/html/TOPP_CometAdapter.html) (scroll down a bit for the complete set).\nMultiple variable modifications can be specified comma separated (e.g. 'Carbamidomethyl (C),Oxidation (M)').\nVariable modifications may or may not be found at matching amino acids for a peptide to be reported." + "help_text": "Specify which variable modifications should be applied to the database search (eg. '' or 'Oxidation (M)', see Unimod modifications in the style '({unimod name} ({optional term specificity} {optional origin})'). All possible modifications can be found in the restrictions mentioned in the command line documentation of e.g. [CometAdapter](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/release/latest/html/TOPP_CometAdapter.html). Multiple variable modifications can be specified comma separated (e.g. 'Carbamidomethyl (C),Oxidation (M)'). This value can be overridden via command line. If not specified, the value from the SDRF file will be used." }, "ms2_fragment_method": { "type": "string", @@ -386,30 +374,6 @@ "default": 10, "fa_icon": "fas fa-sliders-h" }, - "min_pr_mz": { - "type": "number", - "description": "The minimum precursor m/z for the in silico library generation or library-free search", - "fa_icon": "fas fa-filter", - "default": 400.0 - }, - "max_pr_mz": { - "type": "number", - "description": "The maximum precursor m/z for the in silico library generation or library-free search", - "fa_icon": "fas fa-filter", - "default": 2400.0 - }, - "min_fr_mz": { - "type": "number", - "description": "The minimum fragment m/z for the in silico library generation or library-free search", - "fa_icon": "fas fa-filter", - "default": 100.0 - }, - "max_fr_mz": { - "type": "number", - "description": "The maximum fragment m/z for the in silico library generation or library-free search", - "fa_icon": "fas fa-filter", - "default": 1800.0 - }, "db_debug": { "type": "integer", "description": "Debug level when running the database search. Logs become more verbose and at '>5' temporary files are kept.", @@ -453,6 +417,13 @@ "fa_icon": "fas fa-atom", "hidden": true }, + "onsite_rt_tolerance": { + "type": "number", + "description": "RT tolerance for PTM localization", + "default": 0.01, + "fa_icon": "fas fa-clock", + "hidden": true + }, "onsite_fragment_tolerance": { "type": "number", "description": "Fragment mass tolerance", @@ -468,10 +439,23 @@ "fa_icon": "fas fa-balance-scale", "hidden": true }, + "onsite_modeling_score_threshold": { + "type": "number", + "description": "Modeling score threshold for LucXor model training", + "default": 0.95, + "fa_icon": "fas fa-sliders-h", + "hidden": true + }, + "onsite_scoring_threshold": { + "type": "number", + "description": "Scoring threshold for PTM localization", + "default": 0.0, + "fa_icon": "fas fa-sliders-h", + "hidden": true + }, "onsite_add_decoys": { "type": "boolean", "description": "Add decoy modifications for validation", - "default": false, "fa_icon": "fas fa-shield-alt", "help_text": "When enabled, adds decoy modifications for validation. For AScore/PhosphoRS, adds --add-decoys flag. For LucXor, adds PhosphoDecoy(A) to target modifications.", "hidden": true @@ -503,7 +487,14 @@ "fa_icon": "fas fa-microchip", "hidden": true }, - "onsite_min_psms": { + "onsite_target_modifications": { + "type": "string", + "description": "List of target modifications to search for during PTM localization", + "fa_icon": "fas fa-tasks", + "help_text": "Specify a comma-separated list of modifications to search for. If not set, the value from mod_localization is used.", + "hidden": true + }, + "onsite_min_num_psms_model": { "type": "integer", "description": "Minimum number of high-scoring PSMs required for model training in LucXor", "default": 5, @@ -513,17 +504,28 @@ "onsite_disable_split_by_charge": { "type": "boolean", "description": "Disable splitting PSMs by charge state for lucxor", - "default": false, "fa_icon": "fas fa-ban", "hidden": true }, "onsite_compute_all_scores": { "type": "boolean", "description": "Compute all scores for all candidate sites", - "default": false, "fa_icon": "fas fa-calculator", "hidden": true }, + "onsite_max_num_perm": { + "type": "integer", + "description": "Maximum number of permutations", + "fa_icon": "fas fa-calculator", + "hidden": true + }, + "onsite_min_mz": { + "type": "number", + "description": "Minimum mz of peak", + "default": 150.0, + "fa_icon": "fas fa-ruler", + "hidden": true + }, "onsite_debug": { "type": "integer", "fa_icon": "fas fa-bug", @@ -587,14 +589,6 @@ "default": 1, "fa_icon": "fas fa-sliders-h" }, - "ms2features_range": { - "type": "string", - "description": "MS2Features processing range: independent run, Sample or whole experiments", - "help_text": "independent_run: Process each run separately (default, fastest). by_sample: Group runs by sample for better statistics. by_project: Use all runs together for maximum statistical power (slowest but most accurate).", - "fa_icon": "fas fa-font", - "default": "independent_run", - "enum": ["independent_run", "by_sample", "by_project"] - }, "ms2features_model": { "type": "string", "description": "Deep learning model for MS2 prediction. Choose based on your feature generator: alphapeptdeep uses 'generic' model, ms2pip uses instrument-specific models.", @@ -674,7 +668,6 @@ "type": "boolean", "description": "Force save fine-tuning model", "help_text": "When enabled, Force save fine-tuning model even if retrained model is not better than pretrained model", - "default": false, "fa_icon": "far fa-check-square" }, "epoch_to_train_ms2": { @@ -848,26 +841,26 @@ "min_precursor_intensity": { "type": "number", "description": "Minimum intensity of the precursor to be extracted", - "default": 1.0, + "default": 1, "fa_icon": "fas fa-sliders-h" }, "min_precursor_purity": { "type": "number", "description": "Minimum fraction of the total intensity. 0.0:1.0", - "default": 0.0, + "default": 0, "fa_icon": "fas fa-sliders-h", "help_text": "Minimum fraction of the total intensity in the isolation window of the precursor spectrum" }, "min_reporter_intensity": { "type": "number", "description": "Minimum intensity of the individual reporter ions to be extracted.", - "default": 0.0, + "default": 0, "fa_icon": "fas fa-sliders-h" }, "precursor_isotope_deviation": { "type": "number", "description": "Maximum allowed deviation (in ppm) between theoretical and observed isotopic peaks of the precursor peak", - "default": 10.0, + "default": 10, "fa_icon": "fas fa-sliders-h" }, "isotope_correction": { @@ -982,6 +975,13 @@ "fa_icon": "fas fa-filter", "help_text": "After applying protein-level FDR cutoff, this additionally filters PSMs to be used for quantification and reporting." }, + "fdr_conservative": { + "type": "boolean", + "description": "Use conservative FDR formula (D+1)/T instead of (D+1)/(T+D). Default: true", + "default": true, + "fa_icon": "fas fa-shield-alt", + "help_text": "When true, uses the conservative formula (D+1)/T for FDR estimation, which provides an upper bound on the true FDR. When false, uses (D+1)/(T+D) which gives a tighter estimate. See Keich & Noble (2025, Nature Methods) for details on FDR estimation methods." + }, "protein_inference_debug": { "type": "integer", "description": "Debug level for the protein inference step. Increase for verbose logging", @@ -998,21 +998,6 @@ "description": "General protein quantification settings for both LFQ and isobaric labelling.", "default": "", "properties": { - "labelling_type": { - "type": "string", - "description": "Specify the labelling method that was used. Will be ignored if SDRF was given but is mandatory otherwise", - "fa_icon": "fas fa-font", - "help_text": "Quantification method used in the experiment.", - "enum": [ - "label free sample", - "itraq4plex", - "itraq8plex", - "tmt6plex", - "tmt10plex", - "tmt11plex", - "tmt16plex" - ] - }, "top": { "type": "integer", "description": "Calculate protein abundance from this number of proteotypic peptides (most abundant first; '0' for all, Default 3)", @@ -1088,6 +1073,13 @@ "enum": ["feature_intensity", "spectral_counting"], "fa_icon": "fas fa-list-ol" }, + "lfq_seeding_algorithm": { + "type": "string", + "description": "Feature detection seeding algorithm for ProteomicsLFQ. 'multiplex' uses FeatureFinderMultiplex (default), 'biosaur2' uses the Biosaur2 algorithm.", + "default": "biosaur2", + "enum": ["multiplex", "biosaur2"], + "fa_icon": "fas fa-seedling" + }, "mass_recalibration": { "type": "boolean", "description": "Recalibrates masses based on precursor mass deviations to correct for instrument biases. (default: 'false')", @@ -1116,7 +1108,7 @@ "lfq_intensity_threshold": { "type": "number", "description": "The minimum intensity for a feature to be considered for quantification. (default: '1000')", - "default": 1000.0, + "default": 1000, "fa_icon": "fas fa-filter", "help_text": "The minimum intensity for a feature to be considered for quantification. (default: '1000')" }, @@ -1129,7 +1121,7 @@ }, "quantify_decoys": { "type": "boolean", - "description": "Also quantify decoys? (Usually only needed for Triqler post-processing output with [`--add_triqler_output`](#add_triqler_output), where it is auto-enabled)", + "description": "Also quantify decoys?", "fa_icon": "far fa-check-square" }, "plfq_debug": { @@ -1142,239 +1134,6 @@ }, "fa_icon": "fas fa-braille" }, - "DIA-NN": { - "title": "DIA-NN", - "type": "object", - "description": "Settings for DIA-NN - a universal software for data-independent acquisition (DIA) proteomics data processing.", - "default": "", - "properties": { - "mass_acc_automatic": { - "type": "boolean", - "default": true, - "description": "Choosing the MS2 mass accuracy setting automatically", - "fa_icon": "fas fa-toggle-on" - }, - "scan_window_automatic": { - "type": "boolean", - "description": "Choosing scan_window setting automatically", - "default": true, - "fa_icon": "fas fa-toggle-on" - }, - "scan_window": { - "type": "integer", - "description": "Set the scan window radius to a specific value", - "fa_icon": "fas fa-filter", - "help_text": " Ideally, should be approximately equal to the average number of data points per peak", - "default": 8 - }, - "performance_mode": { - "type": "boolean", - "description": "Set Low RAM & High Speed Mode for DIANN, including min-corr, corr-diff, and time-corr-only three parameters", - "fa_icon": "far fa-check-square", - "default": true - }, - "quick_mass_acc": { - "type": "boolean", - "description": "when choosing the MS2 mass accuracy setting automatically, DIA-NN will use a fast heuristical algorithm instead of IDs number optimisation", - "fa_icon": "far fa-check-square", - "default": true - }, - "pg_level": { - "type": "number", - "description": "Controls the protein inference mode", - "fa_icon": "fas fa-list-ol", - "enum": [0, 1, 2], - "default": 2 - }, - "species_genes": { - "type": "boolean", - "description": "Instructs DIA-NN to add the organism identifier to the gene names", - "fa_icon": "far fa-check-square" - }, - "diann_speclib": { - "type": "string", - "description": "The spectral library to use for DIA-NN", - "fa_icon": "fas fa-file", - "help_text": "If passed, will use that spectral library to carry out the DIA-NN search, instead of predicting one from the fasta file.", - "hidden": false - }, - "diann_report_decoys": { - "type": "boolean", - "description": "Save decoy PSMs to the main .parquet report for DIA-NN 2.0.*", - "fa_icon": "far fa-check-square", - "hidden": false - }, - "diann_export_xic": { - "type": "boolean", - "description": "instructs DIA-NN to extract MS1/fragment chromatograms for identified precursors within X seconds from the elution apex, with X set to 10s if not provided;equivalent to the 'XICs' option in the GUI", - "fa_icon": "far fa-check-square", - "hidden": false - }, - "skip_preliminary_analysis": { - "type": "boolean", - "description": "Skip the preliminary analysis step, thus use the passed spectral library as-is insted of generating a local concensus library.", - "fa_icon": "fas fa-forward", - "hidden": false - }, - "empirical_assembly_log": { - "type": "string", - "description": "The log file for the empirical assembly, Only used if `--skip_preliminary_analysis` is set to `true` and `--diann_speclib` is passed. If passed, will use that log file to carry out the DIA-NN search, instead of running a preliminary search.", - "fa_icon": "fas fa-file", - "help_text": "If passed, will use that log file to carry out the DIA-NN search, instead of predicting one from the fasta file.", - "hidden": false - }, - "diann_debug": { - "type": "integer", - "description": "Debug level", - "default": 3, - "fa_icon": "fas fa-bug", - "enum": [0, 1, 2, 3, 4], - "hidden": true - }, - "diann_normalize": { - "type": "boolean", - "description": "Enable cross-run normalization between runs by diann.", - "default": true, - "fa_icon": "far fa-check-square" - }, - "random_preanalysis": { - "type": "boolean", - "description": "Enable random selection of spectrum files to generate empirical library.", - "fa_icon": "far fa-check-square" - }, - "random_preanalysis_seed": { - "type": "integer", - "description": "Set the random seed for the random selection of spectrum files to generate the empirical library.", - "default": 42, - "fa_icon": "fas fa-filter" - }, - "empirical_assembly_ms_n": { - "type": "integer", - "description": "The number of randomly selected spectrum files.", - "default": 200, - "fa_icon": "fas fa-filter", - "hidden": true - }, - "enable_diann_mztab": { - "type": "boolean", - "description": "Export the DIA-NN and DIA results to mzTab", - "default": false, - "fa_icon": "far fa-check-square" - } - }, - "fa_icon": "fas fa-braille" - }, - "statistical_post_processing": { - "title": "Statistical post-processing", - "type": "object", - "description": "", - "default": "Parameters for the R script using MSstats for statistical post processing and quantification visualization.", - "properties": { - "skip_post_msstats": { - "type": "boolean", - "description": "Skip MSstats/MSstatsTMT for statistical post-processing?", - "fa_icon": "fas fa-forward" - }, - "ref_condition": { - "type": "string", - "description": "Experimental: Instead of all pairwise contrasts (default), uses the given condition name/number (corresponding to your experimental design) as a reference and creates pairwise contrasts against it.", - "fa_icon": "fas fa-font" - }, - "contrasts": { - "type": "string", - "description": "Experimental: Allows full control over contrasts by specifying a set of contrasts in a semicolon separated list of R-compatible contrasts with the condition names/numbers as variables (e.g. `1-2;1-3;2-3`). Overwrites [`--ref_condition`](#ref_condition).", - "fa_icon": "fas fa-font", - "default": "pairwise" - }, - "msstats_threshold": { - "type": "number", - "description": "The threshold value for differential expressed proteins in MSstats plots based on adjusted p-value", - "fa_icon": "fas fa-filter", - "default": 0.05 - }, - "add_triqler_output": { - "type": "boolean", - "description": "Also create an output in Triqler's format for an alternative manual post-processing with that tool", - "fa_icon": "far fa-check-square" - }, - "msstatslfq_feature_subset_protein": { - "type": "string", - "description": "Which features to use for quantification per protein: 'top3' or 'highQuality' which removes outliers only", - "fa_icon": "far fa-list-ol", - "default": "top3", - "enum": ["top3", "highQuality"] - }, - "msstatslfq_quant_summary_method": { - "type": "string", - "description": "which summary method to use: 'TMP' (Tukey's median polish) or 'linear' (linear mixed model)", - "fa_icon": "far fa-list-ol", - "default": "TMP", - "enum": ["TMP", "linear"] - }, - "msstats_remove_one_feat_prot": { - "type": "boolean", - "description": "Omit proteins with only one quantified feature?", - "fa_icon": "far fa-check-square", - "default": true - }, - "msstatslfq_removeFewMeasurements": { - "type": "boolean", - "description": "Keep features with only one or two measurements across runs?", - "fa_icon": "far fa-check-square", - "default": true - }, - "msstatsiso_useunique_peptide": { - "type": "boolean", - "description": "Use unique peptide for each protein", - "fa_icon": "far fa-check-square", - "default": true - }, - "msstatsiso_rmpsm_withfewmea_withinrun": { - "type": "boolean", - "description": "Remove the features that have 1 or 2 measurements within each run", - "fa_icon": "far fa-check-square", - "default": true - }, - "msstatsiso_summaryformultiple_psm": { - "type": "string", - "description": "select the feature with the largest summmation or maximal value", - "fa_icon": "far fa-list-ol", - "default": "sum", - "enum": ["sum", "max"] - }, - "msstatsiso_summarization_method": { - "type": "string", - "description": "summarization methods to protein-level can be perfomed", - "fa_icon": "far fa-list-ol", - "default": "msstats", - "enum": ["msstats", "MedianPolish", "Median", "LogSum"] - }, - "msstatsiso_global_norm": { - "type": "boolean", - "description": "Reference channel based normalization between MS runs on protein level data?", - "fa_icon": "far fa-check-square", - "default": true - }, - "msstatsiso_remove_norm_channel": { - "type": "boolean", - "description": "Remove 'Norm' channels from protein level data", - "fa_icon": "far fa-check-square", - "default": true - }, - "msstatsiso_reference_normalization": { - "type": "boolean", - "description": "Reference channel based normalization between MS runs on protein level data", - "fa_icon": "far fa-check-square", - "default": true - }, - "msstats_plot_profile_qc": { - "type": "boolean", - "description": "Export MSstats profile QC plots including all proteins", - "fa_icon": "far fa-check-square" - } - }, - "fa_icon": "fab fa-r-project" - }, "quality_control": { "title": "Quality control", "type": "object", @@ -1499,13 +1258,6 @@ "fa_icon": "fas fa-palette", "hidden": true }, - "hook_url": { - "type": "string", - "description": "Incoming hook URL for messaging service", - "fa_icon": "fas fa-people-group", - "help_text": "Incoming hook URL for messaging service. Currently, MS Teams and Slack are supported.", - "hidden": true - }, "multiqc_config": { "type": "string", "format": "file-path", @@ -1540,7 +1292,7 @@ "type": "string", "fa_icon": "far fa-check-circle", "description": "Base URL or local path to location of pipeline test dataset files", - "default": "https://raw.githubusercontent.com/nf-core/test-datasets/", + "default": "https://raw.githubusercontent.com/bigbio/quantms-test-datasets/", "hidden": true }, "trace_report_suffix": { @@ -1610,12 +1362,6 @@ { "$ref": "#/$defs/protein_quantification_lfq" }, - { - "$ref": "#/$defs/DIA-NN" - }, - { - "$ref": "#/$defs/statistical_post_processing" - }, { "$ref": "#/$defs/quality_control" }, diff --git a/ro-crate-metadata.json b/ro-crate-metadata.json index 88fbef08a..283c2bade 100644 --- a/ro-crate-metadata.json +++ b/ro-crate-metadata.json @@ -1,12 +1,29 @@ { - "@context": "https://w3id.org/ro/crate/1.1/context", + "@context": [ + "https://w3id.org/ro/crate/1.1/context", + { + "GithubService": "https://w3id.org/ro/terms/test#GithubService", + "JenkinsService": "https://w3id.org/ro/terms/test#JenkinsService", + "PlanemoEngine": "https://w3id.org/ro/terms/test#PlanemoEngine", + "TestDefinition": "https://w3id.org/ro/terms/test#TestDefinition", + "TestInstance": "https://w3id.org/ro/terms/test#TestInstance", + "TestService": "https://w3id.org/ro/terms/test#TestService", + "TestSuite": "https://w3id.org/ro/terms/test#TestSuite", + "TravisService": "https://w3id.org/ro/terms/test#TravisService", + "definition": "https://w3id.org/ro/terms/test#definition", + "engineVersion": "https://w3id.org/ro/terms/test#engineVersion", + "instance": "https://w3id.org/ro/terms/test#instance", + "resource": "https://w3id.org/ro/terms/test#resource", + "runsOn": "https://w3id.org/ro/terms/test#runsOn" + } + ], "@graph": [ { "@id": "./", "@type": "Dataset", - "creativeWorkStatus": "Stable", - "datePublished": "2025-08-13T13:06:56+00:00", - "description": "# ![bigbio/quantms](docs/images/nf-core-quantms_logo_light.png#gh-light-mode-only) ![bigbio/quantms](docs/images/nf-core-quantms_logo_dark.png#gh-dark-mode-only)\n\n[![GitHub Actions CI Status](https://github.com/bigbio/quantms/actions/workflows/ci.yml/badge.svg)](https://github.com/bigbio/quantms/actions/workflows/ci.yml)\n[![GitHub Actions Linting Status](https://github.com/bigbio/quantms/actions/workflows/linting.yml/badge.svg)](https://github.com/bigbio/quantms/actions/workflows/linting.yml)\n[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/quantms/results)\n[![Cite with Zenodo](https://zenodo.org/badge/DOI/10.5281/zenodo.15573386.svg)](https://doi.org/10.5281/zenodo.15573386)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.04.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.4.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.4.1)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-core/quantms)\n\n[![Get help on Slack](https://img.shields.io/badge/slack-nf--core%20%23quantms-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/quantms)[![Follow on Twitter](https://img.shields.io/badge/twitter-%40nf__core-1DA1F2?labelColor=000000&logo=twitter)](https://twitter.com/nf_core)[![Follow on Mastodon](https://img.shields.io/badge/mastodon-nf__core-6364ff?labelColor=FFFFFF&logo=mastodon)](https://mstdn.science/@nf_core)[![Watch on YouTube](https://img.shields.io/badge/youtube-nf--core-FF0000?labelColor=000000&logo=youtube)](https://www.youtube.com/c/nf-core)\n\n## Introduction\n\n**bigbio/quantms** is a bioinformatics best-practice analysis pipeline for Quantitative Mass Spectrometry (MS). Currently, the workflow supports three major MS-based analytical methods: (i) Data dependant acquisition (DDA) label-free and Isobaric quantitation (e.g. TMT, iTRAQ); (ii) Data independent acquisition (DIA) label-free quantification (for details see our in-depth documentation on [quantms](https://quantms.readthedocs.io/en/latest/)).\n\n

\n \"bigbio/quantms\n

\n\nThe 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 uses Docker/Singularity containers making installation trivial and results highly reproducible. The [Nextflow DSL2](https://www.nextflow.io/docs/latest/dsl2.html) implementation of this pipeline uses one container per process which makes it much easier to maintain and update software dependencies. Where possible, these processes have been submitted to and installed from [nf-core/modules](https://github.com/nf-core/modules) in order to make them available to all nf-core pipelines, and to everyone within the Nextflow community!\n\nOn release, automated continuous integration tests run the pipeline on a full-sized dataset on the AWS cloud infrastructure. This ensures that the pipeline runs on AWS, has sensible resource allocation defaults set to run on real-world datasets, and permits the persistent storage of results to benchmark between pipeline releases and other analysis sources. The results obtained from the full-sized test can be viewed on the [nf-core website](https://nf-co.re/quantms/results). This gives you a hint on which reports and file types are produced by the pipeline in a standard run. The automatic continuous integration tests on every pull request evaluate different workflows, including peptide identification, quantification for LFQ, LFQ-DIA, and TMT test datasets.\n\n## Pipeline summary\n\n**bigbio/quantms** allows uses to perform analyses of three main types of analytical mass spectrometry-based quantitative methods: DDA-LFQ, DDA-ISO, DIA-LFQ. Each of these workflows share some processes but also includes their own steps. In summary:\n\n### DDA-LFQ (data-dependent label-free quantification)\n\n1. RAW file conversion to mzML ([`thermorawfileparser`](https://github.com/compomics/ThermoRawFileParser))\n2. Peptide identification using [`comet`](https://uwpr.github.io/Comet/) and/or [`msgf+`](https://github.com/MSGFPlus/msgfplus)\n3. (Optional) Add extra PSM features using [`quantms-rescoring`](https://github.com/bigbio/quantms-rescoring)\n4. Re-scoring peptide identifications [`percolator`](https://github.com/percolator/percolator)\n5. Peptide identification FDR [`openms fdr tool`](https://github.com/bigbio/quantms/blob/HEAD/modules/local/openms/false_discovery_rate/main.nf)\n6. Modification localization [`onsite`](https://github.com/bigbio/onsite)\n7. Quantification: Feature detection [`proteomicsLFQ`](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_ProteomicsLFQ.html)\n8. Protein inference and quantification [`proteomicsLFQ`](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_ProteomicsLFQ.html)\n9. QC report generation [`pmultiqc`](https://github.com/bigbio/pmultiqc)\n10. Normalization, imputation, significance testing with [`MSstats`](https://github.com/VitekLab/MSstats)\n\n### DDA-ISO (data-dependent quantification via isobaric labelling)\n\n1. RAW file conversion to mzML ([`thermorawfileparser`](https://github.com/compomics/ThermoRawFileParser))\n2. Peptide identification using [`comet`](https://uwpr.github.io/Comet/) and/or [`msgf+`](https://github.com/MSGFPlus/msgfplus)\n3. (Optional) Add extra PSM features using [`quantms-rescoring`](https://github.com/bigbio/quantms-rescoring)\n4. Re-scoring peptide identifications [`percolator`](https://github.com/percolator/percolator)\n5. Peptide identification FDR [`openms fdr tool`](https://github.com/bigbio/quantms/blob/HEAD/modules/local/openms/false_discovery_rate/main.nf)\n6. Modification localization [`onsite`](https://github.com/bigbio/onsite)\n7. Extracts and normalizes isobaric labeling [`IsobaricAnalyzer`](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_IsobaricAnalyzer.html)\n8. Protein inference [`ProteinInference`](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_ProteinInference.html) or [`Epifany`](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_Epifany.html) for bayesian inference.\n9. Protein Quantification [`ProteinQuantifier`](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_ProteinQuantifier.html)\n10. QC report generation [`pmultiqc`](https://github.com/bigbio/pmultiqc)\n11. Normalization, imputation, significance testing with [`MSstats`](https://github.com/VitekLab/MSstats)\n\n### DIA-LFQ (data-independent label-free quantification)\n\n1. RAW file conversion to mzML when RAW as input([`thermorawfileparser`](https://github.com/compomics/ThermoRawFileParser))\n2. Performing an [optional step](https://github.com/bigbio/quantms/blob/HEAD/modules/local/utils/tdf2mzml/main.nf): Converting .d to mzML when bruker data as input and set `convert_dotd` to true\n3. DIA-NN analysis [`dia-nn`](https://github.com/vdemichev/DiaNN/)\n4. Generation of output files (msstats)\n5. QC reports generation [`pmultiqc`](https://github.com/bigbio/pmultiqc)\n\n### Functionality overview\n\nA graphical overview of suggested routes through the pipeline depending on context can be seen below.\n\n

\n \"bigbio/quantms\n

\n\n## Usage\n\n> [!NOTE]\n> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data.\n\n### Supported file formats\n\nThe pipeline supports the following mass spectrometry data file formats:\n\n- **`.raw`** - Thermo RAW files (automatically converted to mzML)\n- **`.mzML`** - Open standard mzML files\n- **`.d`** - Bruker timsTOF files (optionally converted to mzML when `--convert_dotd` is set)\n- **`.dia`** - DIA-NN native binary format (passed through without conversion)\n\nCompressed variants are supported for `.raw`, `.mzML`, and `.d` formats:\n\n- `.gz` (gzip compressed)\n- `.tar` (tar archive)\n- `.tar.gz` or `.tgz` (tar gzip compressed)\n- `.zip` (zip compressed)\n\nFirst, find or create a sample-to-data relationship file ([SDRF](https://github.com/bigbio/proteomics-sample-metadata)).\nHave a look at public datasets that were already annotated [here](https://github.com/bigbio/proteomics-sample-metadata/tree/master/annotated-projects).\nThose SDRFs should be ready for one-command re-analysis and you can just use the URL to the file on GitHub,\ne.g., `https://raw.githubusercontent.com/bigbio/proteomics-sample-metadata/master/annotated-projects/PXD000396/PXD000396.sdrf.tsv`.\nIf 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.\n\nThe 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=*).\n\nNow, you can run the pipeline using:\n\n```bash\nnextflow run bigbio/quantms \\\n -profile \\\n --input project.sdrf.tsv \\\n --database database.fasta \\\n --outdir \n```\n\n> [!NOTE]\n> Conda is no longer supported in this pipeline. Please use Docker, Singularity, or other container-based profiles.\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_;\n> see [docs](https://nf-co.re/usage/configuration#custom-configuration-files).\n\nFor more details and further functionality, please refer to the [usage documentation](https://nf-co.re/quantms/usage) and the [parameter documentation](https://nf-co.re/quantms/parameters).\n\n## Additional documentation and tutorial\n\nThe **bigbio/quantms** pipeline comes with a stand-alone [full documentation](https://quantms.readthedocs.io/en/latest/) including examples, benchmarks, and detailed explanation about the data analysis of proteomics data using quantms.\n\n## Pipeline output\n\nTo see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/quantms/results) tab on the nf-core website pipeline page.\nFor more details about the output files and reports, please refer to the\n[output documentation](https://nf-co.re/quantms/output).\n\n## Credits\n\nbigbio/quantms was originally written by: Chengxin Dai ([@daichengxin](https://github.com/daichengxin)), Julianus Pfeuffer ([@jpfeuffer](https://github.com/jpfeuffer)) and Yasset Perez-Riverol ([@ypriverol](https://github.com/ypriverol)).\n\nWe thank the following people for their extensive assistance in the development of this pipeline:\n\n- Timo Sachsenberg ([@timosachsenberg](https://github.com/timosachsenberg))\n- Wang Hong ([@WangHong007](https://github.com/WangHong007))\n- Henry Webel ([@enryH](https://github.com/enryH))\n- Fabian Egli ([@fabianegli](https://github.com/fabianegli))\n\n## Contributions and Support\n\nIf you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md).\n\nFor further information or help, don't hesitate to get in touch on the [Slack `#quantms` channel](https://nfcore.slack.com/channels/quantms) (you can join with [this invite](https://nf-co.re/join/slack)).\n\n## How to cite\n\nIf you use **bigbio/quantms** for your analysis, please cite it using the following citation:\n\n> **quantms: a cloud-based pipeline for quantitative proteomics enables the reanalysis of public proteomics data**\n>\n> Chengxin Dai, Julianus Pfeuffer, Hong Wang, Ping Zheng, Lukas K\u00e4ll, Timo Sachsenberg, Vadim Demichev, Mingze Bai, Oliver Kohlbacher & Yasset Perez-Riverol\n>\n> _Nat Methods._ 2024 July 4. doi: [10.1038/s41592-024-02343-1](https://doi.org/10.1038/s41592-024-02343-1).\n\n## How to cite nf-core\n\nAn extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file.\n\nYou can cite the `nf-core` publication as follows:\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", + "creativeWorkStatus": "InProgress", + "datePublished": "2026-06-14T11:31:18+00:00", + "description": "# ![bigbio/quantms](docs/images/nf-core-quantms_logo_light.png#gh-light-mode-only) ![bigbio/quantms](docs/images/nf-core-quantms_logo_dark.png#gh-dark-mode-only)\n\n[![GitHub Actions CI Status](https://github.com/bigbio/quantms/actions/workflows/ci.yml/badge.svg)](https://github.com/bigbio/quantms/actions/workflows/ci.yml)\n[![GitHub Actions Linting Status](https://github.com/bigbio/quantms/actions/workflows/linting.yml/badge.svg)](https://github.com/bigbio/quantms/actions/workflows/linting.yml)\n[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/quantms/results)\n[![Cite with Zenodo](https://zenodo.org/badge/DOI/10.5281/zenodo.15573386.svg)](https://doi.org/10.5281/zenodo.15573386)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.04.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.5.2-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.5.2)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-core/quantms)\n\n[![Get help on Slack](https://img.shields.io/badge/slack-nf--core%20%23quantms-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/quantms)[![Follow on Twitter](https://img.shields.io/badge/twitter-%40nf__core-1DA1F2?labelColor=000000&logo=twitter)](https://twitter.com/nf_core)[![Follow on Mastodon](https://img.shields.io/badge/mastodon-nf__core-6364ff?labelColor=FFFFFF&logo=mastodon)](https://mstdn.science/@nf_core)[![Watch on YouTube](https://img.shields.io/badge/youtube-nf--core-FF0000?labelColor=000000&logo=youtube)](https://www.youtube.com/c/nf-core)\n\n## Introduction\n\n**bigbio/quantms** is a bioinformatics best-practice analysis pipeline for Quantitative Mass Spectrometry (MS). Currently, the workflow supports three major MS-based analytical methods: (i) Data dependant acquisition (DDA) label-free and Isobaric quantitation (e.g. TMT, iTRAQ); (ii) Data independent acquisition (DIA) label-free quantification (for details see our in-depth documentation on [quantms](https://quantms.readthedocs.io/en/latest/)).\n\n

\n \"bigbio/quantms\n

\n\nThe 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 uses Docker/Singularity containers making installation trivial and results highly reproducible. The [Nextflow DSL2](https://www.nextflow.io/docs/latest/dsl2.html) implementation of this pipeline uses one container per process which makes it much easier to maintain and update software dependencies. Where possible, these processes have been submitted to and installed from [nf-core/modules](https://github.com/nf-core/modules) in order to make them available to all nf-core pipelines, and to everyone within the Nextflow community!\n\nOn release, automated continuous integration tests run the pipeline on a full-sized dataset on the AWS cloud infrastructure. This ensures that the pipeline runs on AWS, has sensible resource allocation defaults set to run on real-world datasets, and permits the persistent storage of results to benchmark between pipeline releases and other analysis sources. The results obtained from the full-sized test can be viewed on the [nf-core website](https://nf-co.re/quantms/results). This gives you a hint on which reports and file types are produced by the pipeline in a standard run. The automatic continuous integration tests on every pull request evaluate different workflows, including peptide identification, quantification for LFQ, LFQ-DIA, and TMT test datasets.\n\n## Pipeline summary\n\n**bigbio/quantms** allows uses to perform analyses of three main types of analytical mass spectrometry-based quantitative methods: DDA-LFQ, DDA-ISO, DIA-LFQ. Each of these workflows share some processes but also includes their own steps. In summary:\n\n### DDA-LFQ (data-dependent label-free quantification)\n\n1. RAW file conversion to mzML ([`thermorawfileparser`](https://github.com/compomics/ThermoRawFileParser))\n2. Peptide identification using [`comet`](https://uwpr.github.io/Comet/) and/or [`msgf+`](https://github.com/MSGFPlus/msgfplus)\n3. (Optional) Add extra PSM features using [`quantms-rescoring`](https://github.com/bigbio/quantms-rescoring)\n4. Re-scoring peptide identifications [`percolator`](https://github.com/percolator/percolator)\n5. Peptide identification FDR [`openms fdr tool`](https://github.com/bigbio/quantms/blob/HEAD/modules/local/openms/false_discovery_rate/main.nf)\n6. Modification localization [`onsite`](https://github.com/bigbio/onsite)\n7. Quantification: Feature detection [`proteomicsLFQ`](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_ProteomicsLFQ.html)\n8. Protein inference and quantification [`proteomicsLFQ`](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_ProteomicsLFQ.html)\n9. QC report generation [`pmultiqc`](https://github.com/bigbio/pmultiqc)\n10. Normalization, imputation, significance testing with [`MSstats`](https://github.com/VitekLab/MSstats)\n\n### DDA-ISO (data-dependent quantification via isobaric labelling)\n\n1. RAW file conversion to mzML ([`thermorawfileparser`](https://github.com/compomics/ThermoRawFileParser))\n2. Peptide identification using [`comet`](https://uwpr.github.io/Comet/) and/or [`msgf+`](https://github.com/MSGFPlus/msgfplus)\n3. (Optional) Add extra PSM features using [`quantms-rescoring`](https://github.com/bigbio/quantms-rescoring)\n4. Re-scoring peptide identifications [`percolator`](https://github.com/percolator/percolator)\n5. Peptide identification FDR [`openms fdr tool`](https://github.com/bigbio/quantms/blob/HEAD/modules/local/openms/false_discovery_rate/main.nf)\n6. Modification localization [`onsite`](https://github.com/bigbio/onsite)\n7. Extracts and normalizes isobaric labeling [`IsobaricAnalyzer`](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_IsobaricAnalyzer.html)\n8. Protein inference [`ProteinInference`](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_ProteinInference.html) or [`Epifany`](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_Epifany.html) for bayesian inference.\n9. Protein Quantification [`ProteinQuantifier`](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_ProteinQuantifier.html)\n10. QC report generation [`pmultiqc`](https://github.com/bigbio/pmultiqc)\n11. Normalization, imputation, significance testing with [`MSstats`](https://github.com/VitekLab/MSstats)\n\n### DIA-LFQ (data-independent label-free quantification)\n\n1. RAW file conversion to mzML when RAW as input([`thermorawfileparser`](https://github.com/compomics/ThermoRawFileParser))\n2. Performing an [optional step](https://github.com/bigbio/quantms/blob/HEAD/modules/local/utils/tdf2mzml/main.nf): Converting .d to mzML when bruker data as input and set `convert_dotd` to true\n3. DIA-NN analysis [`dia-nn`](https://github.com/vdemichev/DiaNN/)\n4. Generation of output files (msstats)\n5. QC reports generation [`pmultiqc`](https://github.com/bigbio/pmultiqc)\n\n### Functionality overview\n\nA graphical overview of suggested routes through the pipeline depending on context can be seen below.\n\n

\n \"bigbio/quantms\n

\n\n## Usage\n\n> [!NOTE]\n> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data.\n\n### Supported file formats\n\nThe pipeline supports the following mass spectrometry data file formats:\n\n- **`.raw`** - Thermo RAW files (automatically converted to mzML)\n- **`.mzML`** - Open standard mzML files\n- **`.d`** - Bruker timsTOF files (optionally converted to mzML when `--convert_dotd` is set)\n- **`.dia`** - DIA-NN native binary format (passed through without conversion)\n\nCompressed variants are supported for `.raw`, `.mzML`, and `.d` formats:\n\n- `.gz` (gzip compressed)\n- `.tar` (tar archive)\n- `.tar.gz` or `.tgz` (tar gzip compressed)\n- `.zip` (zip compressed)\n\nFirst, find or create a sample-to-data relationship file ([SDRF](https://github.com/bigbio/proteomics-sample-metadata)).\nHave a look at public datasets that were already annotated [here](https://github.com/bigbio/proteomics-sample-metadata/tree/master/annotated-projects).\nThose SDRFs should be ready for one-command re-analysis and you can just use the URL to the file on GitHub,\ne.g., `https://raw.githubusercontent.com/bigbio/proteomics-sample-metadata/master/annotated-projects/PXD000396/PXD000396.sdrf.tsv`.\nIf 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.\nThe SDRF file can have `.sdrf`, `.tsv`, or `.csv` extensions.\n\nThe 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=*).\n\nNow, you can run the pipeline using:\n\n```bash\nnextflow run bigbio/quantms \\\n -profile \\\n --input project.sdrf.tsv \\\n --database database.fasta \\\n --outdir \n```\n\n> [!NOTE]\n> Conda is no longer supported in this pipeline. Please use Docker, Singularity, or other container-based profiles.\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_;\n> see [docs](https://nf-co.re/usage/configuration#custom-configuration-files).\n\nFor more details and further functionality, please refer to the [usage documentation](https://nf-co.re/quantms/usage) and the [parameter documentation](https://nf-co.re/quantms/parameters).\n\n## Additional documentation and tutorial\n\nThe **bigbio/quantms** pipeline comes with a stand-alone [full documentation](https://quantms.readthedocs.io/en/latest/) including examples, benchmarks, and detailed explanation about the data analysis of proteomics data using quantms.\n\n## Pipeline output\n\nTo see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/quantms/results) tab on the nf-core website pipeline page.\nFor more details about the output files and reports, please refer to the\n[output documentation](https://nf-co.re/quantms/output).\n\n## Credits\n\nbigbio/quantms was originally written by: Chengxin Dai ([@daichengxin](https://github.com/daichengxin)), Julianus Pfeuffer ([@jpfeuffer](https://github.com/jpfeuffer)) and Yasset Perez-Riverol ([@ypriverol](https://github.com/ypriverol)).\n\nWe thank the following people for their extensive assistance in the development of this pipeline:\n\n- Timo Sachsenberg ([@timosachsenberg](https://github.com/timosachsenberg))\n- Wang Hong ([@WangHong007](https://github.com/WangHong007))\n- Henry Webel ([@enryH](https://github.com/enryH))\n- Fabian Egli ([@fabianegli](https://github.com/fabianegli))\n\n## Contributions and Support\n\nIf you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md).\n\nFor further information or help, don't hesitate to get in touch on the [Slack `#quantms` channel](https://nfcore.slack.com/channels/quantms) (you can join with [this invite](https://nf-co.re/join/slack)).\n\n## How to cite\n\nIf you use **bigbio/quantms** for your analysis, please cite it using the following citation:\n\n> **quantms: a cloud-based pipeline for quantitative proteomics enables the reanalysis of public proteomics data**\n>\n> Chengxin Dai, Julianus Pfeuffer, Hong Wang, Ping Zheng, Lukas K\u00e4ll, Timo Sachsenberg, Vadim Demichev, Mingze Bai, Oliver Kohlbacher & Yasset Perez-Riverol\n>\n> _Nat Methods._ 2024 July 4. doi: [10.1038/s41592-024-02343-1](https://doi.org/10.1038/s41592-024-02343-1).\n\n## How to cite nf-core\n\nAn extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file.\n\nYou can cite the `nf-core` publication as follows:\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", "hasPart": [ { "@id": "main.nf" @@ -14,9 +31,6 @@ { "@id": "assets/" }, - { - "@id": "bin/" - }, { "@id": "conf/" }, @@ -29,9 +43,6 @@ { "@id": "modules/" }, - { - "@id": "modules/local/" - }, { "@id": "modules/nf-core/" }, @@ -86,6 +97,11 @@ "mainEntity": { "@id": "main.nf" }, + "mentions": [ + { + "@id": "#8b122c62-86a0-4708-81aa-25ff47162881" + } + ], "name": "bigbio/quantms" }, { @@ -110,28 +126,13 @@ "SoftwareSourceCode", "ComputationalWorkflow" ], - "creator": [ - { - "@id": "https://orcid.org/0000-0001-8948-9209" - }, + "contributor": [ { "@id": "https://orcid.org/0000-0001-6579-6941" - }, - { - "@id": "https://orcid.org/0000-0001-8833-7617" - }, - { - "@id": "#jspaezp@users.noreply.github.com" - }, - { - "@id": "https://orcid.org/0000-0001-6943-5211" - }, - { - "@id": "https://orcid.org/0000-0001-6943-5211" } ], "dateCreated": "", - "dateModified": "2025-08-13T14:06:56Z", + "dateModified": "2026-06-14T19:31:18Z", "dct:conformsTo": "https://bioschemas.org/profiles/ComputationalWorkflow/1.0-RELEASE/", "keywords": [ "nf-core", @@ -148,17 +149,6 @@ "license": [ "MIT" ], - "maintainer": [ - { - "@id": "https://orcid.org/0000-0001-8948-9209" - }, - { - "@id": "https://orcid.org/0000-0001-6579-6941" - }, - { - "@id": "https://orcid.org/0000-0001-8833-7617" - } - ], "name": [ "bigbio/quantms" ], @@ -170,10 +160,10 @@ }, "url": [ "https://github.com/bigbio/quantms", - "https://nf-co.re/bigbio/quantms/1.6.0/" + "https://nf-co.re/bigbio/quantms/dev/" ], "version": [ - "1.6.0" + "1.8.0" ] }, { @@ -186,17 +176,43 @@ "url": { "@id": "https://www.nextflow.io/" }, - "version": "!>=25.04.0" + "version": "!>=25.10.4" }, { - "@id": "assets/", - "@type": "Dataset", - "description": "Additional files" + "@id": "#8b122c62-86a0-4708-81aa-25ff47162881", + "@type": "TestSuite", + "instance": [ + { + "@id": "#75a40f47-1124-4ab5-9861-3c288a13b497" + } + ], + "mainEntity": { + "@id": "main.nf" + }, + "name": "Test suite for bigbio/quantms" }, { - "@id": "bin/", + "@id": "#75a40f47-1124-4ab5-9861-3c288a13b497", + "@type": "TestInstance", + "name": "GitHub Actions workflow for testing bigbio/quantms", + "resource": "repos/bigbio/quantms/actions/workflows/nf-test.yml", + "runsOn": { + "@id": "https://w3id.org/ro/terms/test#GithubService" + }, + "url": "https://api.github.com" + }, + { + "@id": "https://w3id.org/ro/terms/test#GithubService", + "@type": "TestService", + "name": "Github Actions", + "url": { + "@id": "https://github.com" + } + }, + { + "@id": "assets/", "@type": "Dataset", - "description": "Scripts that must be callable from a pipeline process" + "description": "Additional files" }, { "@id": "conf/", @@ -218,11 +234,6 @@ "@type": "Dataset", "description": "Modules used by the pipeline" }, - { - "@id": "modules/local/", - "@type": "Dataset", - "description": "Pipeline-specific modules" - }, { "@id": "modules/nf-core/", "@type": "Dataset", @@ -309,35 +320,10 @@ "name": "nf-core", "url": "https://nf-co.re/" }, - { - "@id": "https://orcid.org/0000-0001-8948-9209", - "@type": "Person", - "email": "j.pfeuffer@fu-berlin.de", - "name": "Julianus Pfeuffer" - }, { "@id": "https://orcid.org/0000-0001-6579-6941", "@type": "Person", - "email": "ypriverol@gmail.com", "name": "Yasset Perez-Riverol" - }, - { - "@id": "https://orcid.org/0000-0001-8833-7617", - "@type": "Person", - "email": "heweb@dtu.dk", - "name": "Henry Webel" - }, - { - "@id": "#jspaezp@users.noreply.github.com", - "@type": "Person", - "email": "jspaezp@users.noreply.github.com", - "name": "J. Sebastian Paez" - }, - { - "@id": "https://orcid.org/0000-0001-6943-5211", - "@type": "Person", - "email": "37200167+daichengxin@users.noreply.github.com", - "name": "chengxin Dai" } ] } \ No newline at end of file diff --git a/subworkflows/local/create_input_channel/main.nf b/subworkflows/local/create_input_channel/main.nf index aeba504d3..da9103839 100644 --- a/subworkflows/local/create_input_channel/main.nf +++ b/subworkflows/local/create_input_channel/main.nf @@ -2,83 +2,60 @@ // 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() + 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 { create_meta_channel(it, is_sdrf, enzymes, files, wrapper) } - .branch { - ch_meta_config_dia: it[0].acquisition_method.contains("dia") - ch_meta_config_iso: it[0].labelling_type.contains("tmt") || it[0].labelling_type.contains("itraq") - ch_meta_config_lfq: it[0].labelling_type.contains("label free") + .map { row -> create_meta_channel(row, enzymes, files, wrapper) } + .branch { item -> + ch_meta_config_iso: item[0].labelling_type.contains("tmt") || item[0].labelling_type.contains("itraq") + ch_meta_config_lfq: item[0].labelling_type.contains("label free") } .set { result } ch_meta_config_iso = result.ch_meta_config_iso ch_meta_config_lfq = result.ch_meta_config_lfq - ch_meta_config_dia = result.ch_meta_config_dia emit: ch_meta_config_iso // [meta, [spectra_files ]] ch_meta_config_lfq // [meta, [spectra_files ]] - ch_meta_config_dia // [meta, [spectra files ]] ch_expdesign versions = ch_versions } // 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('.')) @@ -92,94 +69,151 @@ 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-dependent acquisition")) { - meta.acquisition_method = "dda" - } - else if (row["Proteomics Data Acquisition Method"].toString().toLowerCase().contains("data-independent acquisition")) { - meta.acquisition_method = "dia" + log.error("Currently only DDA is supported in quantms. For DIA data, use the quantmsdiann pipeline: https://github.com/bigbio/quantmsdiann. 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 + } + + wrapper.acquisition_method = meta.acquisition_method + + // Validate required SDRF columns - these parameters are exclusively read from SDRF (no command-line override) + def requiredColumns = [ + 'Label': row.Label, + 'Enzyme': row.Enzyme, + 'FixedModifications': row.FixedModifications + ] + + def missingColumns = [] + requiredColumns.each { colName, colValue -> + if (colValue == null || colValue.toString().trim().isEmpty()) { + missingColumns.add(colName) } - else { - log.error("Currently DIA and DDA are supported for the pipeline. Check and Fix your SDRF.") + } + + if (missingColumns.size() > 0) { + log.error("ERROR: Missing or empty required SDRF columns for file '${filestr}': ${missingColumns.join(', ')}") + log.error("These parameters must be specified in the SDRF file. Please check your SDRF annotation.") + exit(1) + } + + // Set values from SDRF (required columns) + meta.labelling_type = row.Label + meta.fixedmodifications = row.FixedModifications + meta.enzyme = row.Enzyme + + // Set tolerance values: use SDRF if available, otherwise fall back to params + def validUnits = ['ppm', 'da', 'Da', 'PPM'] + + // Precursor mass tolerance + if (row.PrecursorMassTolerance != null && !row.PrecursorMassTolerance.toString().trim().isEmpty()) { + try { + meta.precursormasstolerance = Double.parseDouble(row.PrecursorMassTolerance) + } catch (NumberFormatException e) { + log.error("ERROR: Invalid PrecursorMassTolerance value '${row.PrecursorMassTolerance}' for file '${filestr}'. Must be a valid number.") exit(1) } + } else { + meta.precursormasstolerance = params.precursor_mass_tolerance + } - // 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" + // Precursor mass tolerance unit + if (row.PrecursorMassToleranceUnit != null && !row.PrecursorMassToleranceUnit.toString().trim().isEmpty()) { + if (!validUnits.any { row.PrecursorMassToleranceUnit.toString().equalsIgnoreCase(it) }) { + log.error("ERROR: Invalid PrecursorMassToleranceUnit '${row.PrecursorMassToleranceUnit}' for file '${filestr}'. Must be 'ppm' or 'Da'.") + exit(1) } - else if (row.DissociationMethod == "ELECTRON CAPTURE DISSOCIATION") { - meta.dissociationmethod = "ECD" + meta.precursormasstoleranceunit = row.PrecursorMassToleranceUnit + } else { + meta.precursormasstoleranceunit = params.precursor_mass_tolerance_unit + } + + // Fragment mass tolerance + if (row.FragmentMassTolerance != null && !row.FragmentMassTolerance.toString().trim().isEmpty()) { + try { + meta.fragmentmasstolerance = Double.parseDouble(row.FragmentMassTolerance) + } catch (NumberFormatException e) { + log.error("ERROR: Invalid FragmentMassTolerance value '${row.FragmentMassTolerance}' for file '${filestr}'. Must be a valid number.") + exit(1) } - else { - meta.dissociationmethod = row.DissociationMethod + } else { + meta.fragmentmasstolerance = params.fragment_mass_tolerance + } + + // Fragment mass tolerance unit + if (row.FragmentMassToleranceUnit != null && !row.FragmentMassToleranceUnit.toString().trim().isEmpty()) { + if (!validUnits.any { row.FragmentMassToleranceUnit.toString().equalsIgnoreCase(it) }) { + log.error("ERROR: Invalid FragmentMassToleranceUnit '${row.FragmentMassToleranceUnit}' for file '${filestr}'. Must be 'ppm' or 'Da'.") + exit(1) } + meta.fragmentmasstoleranceunit = row.FragmentMassToleranceUnit + } else { + meta.fragmentmasstoleranceunit = params.fragment_mass_tolerance_unit + } - wrapper.acquisition_method = meta.acquisition_method - meta.labelling_type = row.Label - meta.fixedmodifications = row.FixedModifications + // Variable modifications: use SDRF if available, otherwise fall back to params + if (row.VariableModifications != null && !row.VariableModifications.toString().trim().isEmpty()) { 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 + } else { + meta.variablemodifications = params.variable_mods + } - 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) - } + 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("")) { - if (meta.labelling_type.contains("tmt") || meta.labelling_type.contains("itraq") || meta.labelling_type.contains("label free")) { - wrapper.labelling_type = meta.labelling_type - } - else { - log.error("Unsupported quantification type '${meta.labelling_type}'.") - exit(1) - } + + if (wrapper.labelling_type.equals("")) { + if (meta.labelling_type.contains("tmt") || meta.labelling_type.contains("itraq") || meta.labelling_type.contains("label free")) { + wrapper.labelling_type = meta.labelling_type } else { - if (meta.labelling_type != wrapper.labelling_type) { - log.error("Currently, only one label type per design is supported: was '${wrapper.labelling_type}', now is '${meta.labelling_type}'.") - exit(1) - } + log.error("Unsupported quantification type '${meta.labelling_type}'.") + exit(1) + } + } + else { + if (meta.labelling_type != wrapper.labelling_type) { + log.error("Currently, only one label type per design is supported: was '${wrapper.labelling_type}', now is '${meta.labelling_type}'.") + exit(1) } } - if (wrapper.labelling_type.contains("label free") || meta.acquisition_method == "dia") { + if (meta.acquisition_method == "dia") { + log.error("Unsupported acquisition type 'dia'. DIA support has been removed from quantms. Please use the quantmsdiann pipeline instead: https://github.com/bigbio/quantmsdiann") + exit(1) + } + + if (wrapper.labelling_type.contains("label free")) { if (filestr in files) { - log.error("Currently only one search engine setting/DIA-NN setting per file is supported for the whole experiment. ${filestr} has multiple entries in your SDRF. Maybe you have a (isobaric) labelled experiment? Otherwise, consider splitting your design into multiple experiments.") + log.error("Currently only one search engine setting per file is supported for the whole experiment. ${filestr} has multiple entries in your SDRF. Maybe you have a (isobaric) labelled experiment? Otherwise, consider splitting your design into multiple experiments.") exit(1) } files += filestr diff --git a/subworkflows/local/create_input_channel/meta.yml b/subworkflows/local/create_input_channel/meta.yml index 6b311082d..1ea899993 100644 --- a/subworkflows/local/create_input_channel/meta.yml +++ b/subworkflows/local/create_input_channel/meta.yml @@ -26,10 +26,6 @@ output: type: file description: | Channel containing label-free data configuration - - ch_meta_config_dia: - type: file - description: | - Channel containing DIA data configuration - ch_expdesign: type: file description: | diff --git a/subworkflows/local/dda_id/main.nf b/subworkflows/local/dda_id/main.nf index eb07c3b41..ace0508cd 100644 --- a/subworkflows/local/dda_id/main.nf +++ b/subworkflows/local/dda_id/main.nf @@ -1,17 +1,13 @@ // // MODULE: Local to the pipeline // -include { CONSENSUSID } from '../../../modules/local/openms/consensusid/main' include { PERCOLATOR } from '../../../modules/local/openms/percolator/main' -include { ID_RIPPER } from '../../../modules/local/openms/id_ripper/main' -include { PSM_CONVERSION } from '../../../modules/local/utils/psm_conversion/main' include { PHOSPHO_SCORING } from '../phospho_scoring/main' // // SUBWORKFLOW: Consisting of a mix of local and nf-core/modules // include { PEPTIDE_DATABASE_SEARCH } from '../peptide_database_search/main' -include { PSM_FDR_CONTROL } from '../psm_fdr_control/main' workflow DDA_ID { take: @@ -22,7 +18,7 @@ workflow DDA_ID { main: - ch_software_versions = Channel.empty() + ch_software_versions = channel.empty() // // SUBWORKFLOW: DatabaseSearchEngines @@ -35,88 +31,27 @@ workflow DDA_ID { ch_software_versions = ch_software_versions.mix(PEPTIDE_DATABASE_SEARCH.out.versions) ch_id_files_feats = PEPTIDE_DATABASE_SEARCH.out.ch_id_files_idx - ch_pmultiqc_consensus = Channel.empty() - ch_pmultiqc_ids = Channel.empty() + ch_pmultiqc_consensus = channel.empty() + ch_pmultiqc_ids = channel.empty() // // SUBWORKFLOW: Rescoring // - if (params.skip_rescoring == false) { - // Rescoring for independent run, Sample or whole experiments - if (params.ms2features_range == "independent_run") { - PERCOLATOR(ch_id_files_feats) - ch_software_versions = ch_software_versions.mix(PERCOLATOR.out.versions) - ch_consensus_input = PERCOLATOR.out.id_files_perc - } else { - PERCOLATOR(ch_id_files_feats) - ch_software_versions = ch_software_versions.mix(PERCOLATOR.out.versions) - // Currently only ID runs on exactly one mzML file are supported in CONSENSUSID. Split idXML by runs - ID_RIPPER(PERCOLATOR.out.id_files_perc) - ch_file_preparation_results.map{[it[0].mzml_id, it[0]]}.set{meta} - ID_RIPPER.out.id_rippers.flatten().map { add_file_prefix (it)}.set{id_rippers} - meta.combine(id_rippers, by: 0) - .map{ [it[1], it[2]]} - .set{ ch_consensus_input } - ch_software_versions = ch_software_versions.mix(ID_RIPPER.out.versions) - } - ch_rescoring_results = ch_consensus_input + PERCOLATOR(ch_id_files_feats) + ch_rescoring_results = PERCOLATOR.out.id_files_perc + ch_software_versions = ch_software_versions.mix(PERCOLATOR.out.versions) - // - // SUBWORKFLOW: PSM_FDR_CONTROL - // - ch_psmfdrcontrol = Channel.empty() - ch_consensus_results = Channel.empty() - // see comments in id.nf - if (params.search_engines.tokenize(",").unique().size() > 1) { - CONSENSUSID(ch_consensus_input.groupTuple(size: params.search_engines.tokenize(",").unique().size())) - ch_software_versions = ch_software_versions.mix(CONSENSUSID.out.versions) - ch_psmfdrcontrol = CONSENSUSID.out.consensusids - ch_psmfdrcontrol - .map { it -> it[1] } - .set { ch_pmultiqc_consensus } - } else { - ch_psmfdrcontrol = ch_consensus_input - } - - PSM_FDR_CONTROL(ch_psmfdrcontrol) - ch_software_versions = ch_software_versions.mix(PSM_FDR_CONTROL.out.versions) - - if (params.enable_mod_localization) { - PHOSPHO_SCORING(ch_file_preparation_results, PSM_FDR_CONTROL.out.id_filtered) - ch_software_versions = ch_software_versions.mix(PHOSPHO_SCORING.out.versions.ifEmpty(null)) - ch_id_results = PHOSPHO_SCORING.out.id_onsite - } else { - ch_id_results = PSM_FDR_CONTROL.out.id_filtered - } - - // Extract PSMs and export parquet format - PSM_CONVERSION(ch_id_results.combine(ch_ms2_statistics, by: 0)) - ch_software_versions = ch_software_versions.mix(PSM_CONVERSION.out.versions) - - ch_rescoring_results - .map { it -> it[1] } - .set { ch_pmultiqc_ids } + if (params.enable_mod_localization) { + PHOSPHO_SCORING(ch_file_preparation_results, ch_rescoring_results) + ch_software_versions = ch_software_versions.mix(PHOSPHO_SCORING.out.versions.ifEmpty(null)) + ch_id_results = PHOSPHO_SCORING.out.id_onsite } else { - PSM_CONVERSION(ch_id_files_feats.combine(ch_ms2_statistics, by: 0)) + ch_id_results = ch_rescoring_results } - emit: ch_pmultiqc_ids = ch_pmultiqc_ids ch_pmultiqc_consensus = ch_pmultiqc_consensus versions = ch_software_versions } - -// Function to add file prefix -def add_file_prefix(file_path) { - position = file(file_path).name.lastIndexOf('_sage_perc.idXML') - if (position == -1) { - position = file(file_path).name.lastIndexOf('_comet_perc.idXML') - if (position == -1) { - position = file(file_path).name.lastIndexOf('_msgf_perc.idXML') - } - } - file_name = file(file_path).name.take(position) - return [file_name, file_path] -} diff --git a/subworkflows/local/dda_id/meta.yml b/subworkflows/local/dda_id/meta.yml index c2dc3ca45..137b700a2 100644 --- a/subworkflows/local/dda_id/meta.yml +++ b/subworkflows/local/dda_id/meta.yml @@ -7,17 +7,11 @@ keywords: - proteomics - msms components: - - consensusid - percolator - - id/merger - - id/ripper - - psm/conversion - msrescore/features - - get/sample - spectrum/features - psm/clean - peptide_database_search - - psm_fdr_control - phospho_scoring input: - ch_input: diff --git a/subworkflows/local/feature_mapper/main.nf b/subworkflows/local/feature_mapper/main.nf deleted file mode 100644 index 433431fab..000000000 --- a/subworkflows/local/feature_mapper/main.nf +++ /dev/null @@ -1,26 +0,0 @@ -// -// Assigns protein/peptide identifications to features or consensus features. -// - -include { ISOBARIC_ANALYZER } from '../../../modules/local/openms/isobaric_analyzer/main' -include { ID_MAPPER } from '../../../modules/local/openms/id_mapper/main' - -workflow FEATURE_MAPPER { - take: - ch_mzml_files - ch_id_files - - main: - ch_version = Channel.empty() - - ISOBARIC_ANALYZER(ch_mzml_files) - ch_version = ch_version.mix(ISOBARIC_ANALYZER.out.versions) - - ID_MAPPER(ch_id_files.combine(ISOBARIC_ANALYZER.out.id_files_consensusXML, by: 0)) - ch_version = ch_version.mix(ID_MAPPER.out.versions) - - emit: - id_map = ID_MAPPER.out.id_map - - versions = ch_version -} diff --git a/subworkflows/local/feature_mapper/meta.yml b/subworkflows/local/feature_mapper/meta.yml deleted file mode 100644 index e2c40d976..000000000 --- a/subworkflows/local/feature_mapper/meta.yml +++ /dev/null @@ -1,29 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json -name: "feature_mapper" -description: Subworkflow for mapping features across different runs and conditions -keywords: - - feature - - mapping - - alignment - - proteomics -components: - - isobaric/analyzer - - id/mapper -input: - - ch_input: - type: file - description: | - Channel containing input files for feature mapping -output: - - ch_mapped_features: - type: file - description: | - Channel containing mapped features - - versions: - type: file - description: | - Software versions used in this subworkflow -authors: - - "@bigbio" -maintainers: - - "@bigbio" diff --git a/subworkflows/local/file_preparation/main.nf b/subworkflows/local/file_preparation/main.nf index c33bf16fb..0212c6a0b 100644 --- a/subworkflows/local/file_preparation/main.nf +++ b/subworkflows/local/file_preparation/main.nf @@ -14,20 +14,19 @@ workflow FILE_PREPARATION { ch_rawfiles // channel: [ val(meta), raw/mzml/d.tar ] main: - ch_versions = Channel.empty() - ch_results = Channel.empty() - ch_statistics = Channel.empty() - ch_ms2_statistics = Channel.empty() - ch_feature_statistics = Channel.empty() - ch_mqc_data = Channel.empty() + ch_versions = channel.empty() + ch_results = channel.empty() + ch_statistics = channel.empty() + ch_ms2_statistics = channel.empty() + ch_feature_statistics = channel.empty() // Divide the compressed files ch_rawfiles - .branch { - dottar: hasExtension(it[1], '.tar') - dotzip: hasExtension(it[1], '.zip') - gz: hasExtension(it[1], '.gz') + .branch { item -> + dottar: hasExtension(item[1], '.tar') + dotzip: hasExtension(item[1], '.zip') + gz: hasExtension(item[1], '.gz') uncompressed: true }.set { ch_branched_input } @@ -39,11 +38,11 @@ workflow FILE_PREPARATION { // // Divide mzml files ch_rawfiles - .branch { - raw: hasExtension(it[1], '.raw') - mzML: hasExtension(it[1], '.mzML') - dotd: hasExtension(it[1], '.d') - dia: hasExtension(it[1], '.dia') + .branch { item -> + raw: hasExtension(item[1], '.raw') + mzML: hasExtension(item[1], '.mzML') + dotd: hasExtension(item[1], '.d') + dia: hasExtension(item[1], '.dia') unsupported: true }.set { ch_branched_input } @@ -54,7 +53,7 @@ workflow FILE_PREPARATION { if (files.size() > 0) { log.warn "=" * 80 log.warn "WARNING: ${files.size()} file(s) with unsupported format(s) detected and will be SKIPPED from processing:" - files.each { meta, file -> + files.each { _meta, file -> log.warn " - ${file}" } log.warn "\nSupported formats: .raw, .mzML, .d (Bruker), .dia" @@ -86,8 +85,8 @@ workflow FILE_PREPARATION { // 'log': Path(*.txt)} // Where meta is the same as the input meta - ch_versions = ch_versions.mix(THERMORAWFILEPARSER.out.versions) - ch_results = ch_results.mix(THERMORAWFILEPARSER.out.convert_files) + // ch_versions = ch_versions.mix(THERMORAWFILEPARSER.out.versions_thermorawfileparser) + ch_results = ch_results.mix(THERMORAWFILEPARSER.out.spectra) ch_results.map{ it -> [it[0], it[1]] }.set{ indexed_mzml_bundle } @@ -96,16 +95,27 @@ workflow FILE_PREPARATION { TDF2MZML( ch_branched_input.dotd ) ch_versions = ch_versions.mix(TDF2MZML.out.versions) ch_results = indexed_mzml_bundle.mix(TDF2MZML.out.mzmls_converted) - // indexed_mzml_bundle = indexed_mzml_bundle.mix(TDF2MZML.out.mzmls_converted) } else { - ch_results = indexed_mzml_bundle.mix(ch_branched_input.dotd) + ch_results = indexed_mzml_bundle } - MZML_STATISTICS(ch_results) - ch_statistics = ch_statistics.mix(MZML_STATISTICS.out.ms_statistics.collect()) - ch_ms2_statistics = ch_statistics.mix(MZML_STATISTICS.out.ms2_statistics) - ch_feature_statistics = ch_statistics.mix(MZML_STATISTICS.out.feature_statistics.collect()) - ch_versions = ch_versions.mix(MZML_STATISTICS.out.versions) + if (params.mzml_statistics) { + // Only run on mzML files, skip .d directories + ch_mzml_for_stats = ch_results.filter { _meta, file -> + !file.toString().toLowerCase().endsWith('.d') + } + MZML_STATISTICS(ch_mzml_for_stats) + ch_statistics = ch_statistics.mix(MZML_STATISTICS.out.ms_statistics.collect()) + ch_ms2_statistics = ch_ms2_statistics.mix(MZML_STATISTICS.out.ms2_statistics) + ch_feature_statistics = ch_feature_statistics.mix(MZML_STATISTICS.out.feature_statistics.collect()) + ch_versions = ch_versions.mix(MZML_STATISTICS.out.versions) + } + + // Pass through .d files without conversion when convert_dotd=false + // (DIA-NN handles them natively; they bypass mzML statistics as they are not mzML) + if (!params.convert_dotd) { + ch_results = ch_results.mix(ch_branched_input.dotd) + } // Pass through .dia files without conversion (DIA-NN handles them natively) // Note: .dia files bypass peak picking and mzML statistics (when enabled) as they are only used with DIA-NN diff --git a/subworkflows/local/id/main.nf b/subworkflows/local/id/main.nf index 87acc62b0..d5f2f926f 100644 --- a/subworkflows/local/id/main.nf +++ b/subworkflows/local/id/main.nf @@ -1,14 +1,8 @@ -// -// MODULE: Local to the pipeline -// -include { CONSENSUSID } from '../../../modules/local/openms/consensusid/main' - // // SUBWORKFLOW: Consisting of a mix of local and nf-core/modules // include { PEPTIDE_DATABASE_SEARCH } from '../peptide_database_search/main' include { PSM_RESCORING } from '../psm_rescoring/main' -include { PSM_FDR_CONTROL } from '../psm_fdr_control/main' include { PHOSPHO_SCORING } from '../phospho_scoring/main' workflow ID { @@ -19,7 +13,7 @@ workflow ID { main: - ch_software_versions = Channel.empty() + ch_software_versions = channel.empty() // // SUBWORKFLOW: DatabaseSearchEngines @@ -34,40 +28,25 @@ workflow ID { // // SUBWORKFLOW: PSMReScoring // - PSM_RESCORING (ch_file_preparation_results, PEPTIDE_DATABASE_SEARCH.out.ch_id_files_idx, ch_expdesign) + PSM_RESCORING (PEPTIDE_DATABASE_SEARCH.out.ch_id_files_idx) ch_software_versions = ch_software_versions.mix(PSM_RESCORING.out.versions) // // SUBWORKFLOW: PSM_FDR_CONTROL // - ch_psmfdrcontrol = Channel.empty() - ch_consensus_results = Channel.empty() - // split returns String[], whereas tokenize returns a list, unique works on lists - def n_unique_search_engines = params.search_engines.tokenize(",").unique().size() - if (n_unique_search_engines > 1) { - // 'remainder: true' will keep remainders which do not match the specified size - // if the 'size' is not matched, an empty channel will be returned and - // nothing will be run for the 'CONSENSUSID' process - CONSENSUSID(PSM_RESCORING.out.results.groupTuple(size: n_unique_search_engines)) - ch_software_versions = ch_software_versions.mix(CONSENSUSID.out.versions) - ch_psmfdrcontrol = CONSENSUSID.out.consensusids - ch_consensus_results = CONSENSUSID.out.consensusids - } else { - ch_psmfdrcontrol = PSM_RESCORING.out.results - } - PSM_FDR_CONTROL(ch_psmfdrcontrol) - ch_software_versions = ch_software_versions.mix(PSM_FDR_CONTROL.out.versions) + ch_psmfdrcontrol = PSM_RESCORING.out.results + ch_consensus_results = channel.empty() // // SUBWORKFLOW:PHOSPHOSCORING // if (params.enable_mod_localization) { - PHOSPHO_SCORING(ch_file_preparation_results, PSM_FDR_CONTROL.out.id_filtered) + PHOSPHO_SCORING(ch_file_preparation_results, PSM_RESCORING.out.results) ch_software_versions = ch_software_versions.mix(PHOSPHO_SCORING.out.versions.ifEmpty(null)) ch_id_results = PHOSPHO_SCORING.out.id_onsite } else { - ch_id_results = PSM_FDR_CONTROL.out.id_filtered + ch_id_results = PSM_RESCORING.out.results } emit: diff --git a/subworkflows/local/id/meta.yml b/subworkflows/local/id/meta.yml index b3d56a96b..400b24d8c 100644 --- a/subworkflows/local/id/meta.yml +++ b/subworkflows/local/id/meta.yml @@ -7,10 +7,8 @@ keywords: - search - engine components: - - consensusid - peptide_database_search - psm_rescoring - - psm_fdr_control - phospho_scoring input: - ch_input: diff --git a/subworkflows/local/input_check/main.nf b/subworkflows/local/input_check/main.nf index 5a0535efc..f4e50c731 100644 --- a/subworkflows/local/input_check/main.nf +++ b/subworkflows/local/input_check/main.nf @@ -1,31 +1,21 @@ // -// Check input sdrf and get read channels +// Check input SDRF and get read channels // include { SAMPLESHEET_CHECK } from '../../../modules/local/samplesheet_check' workflow INPUT_CHECK { take: - input_file // file: /path/to/input_file + input_file main: - ch_software_versions = Channel.empty() + ch_software_versions = channel.empty() - if (input_file.toString().toLowerCase().contains("sdrf")) { - is_sdrf = true - } else { - is_sdrf = false - if (!params.labelling_type || !params.acquisition_method) { - log.error "If no SDRF was given, specifying --labelling_type and --acquisition_method is mandatory." - exit 1 - } - } - SAMPLESHEET_CHECK ( input_file, is_sdrf, params.validate_ontologies ) + SAMPLESHEET_CHECK ( input_file, params.validate_ontologies ) ch_software_versions = ch_software_versions.mix(SAMPLESHEET_CHECK.out.versions) emit: ch_input_file = SAMPLESHEET_CHECK.out.checked_file - is_sdrf = is_sdrf versions = ch_software_versions } diff --git a/subworkflows/local/input_check/meta.yml b/subworkflows/local/input_check/meta.yml index f064610b1..abe2c7f63 100644 --- a/subworkflows/local/input_check/meta.yml +++ b/subworkflows/local/input_check/meta.yml @@ -18,10 +18,6 @@ output: type: file description: | Channel containing validated input files - - is_sdrf: - type: boolean - description: | - Whether the input is in SDRF format - versions: type: file description: | diff --git a/subworkflows/local/peptide_database_search/main.nf b/subworkflows/local/peptide_database_search/main.nf index f936a0b65..21e240646 100644 --- a/subworkflows/local/peptide_database_search/main.nf +++ b/subworkflows/local/peptide_database_search/main.nf @@ -6,9 +6,7 @@ include { SAGE } from '../../../modules/local/openms/sage/main' include { PSM_CLEAN } from '../../../modules/local/utils/psm_clean/main' include { MSRESCORE_FINE_TUNING} from '../../../modules/local/utils/msrescore_fine_tuning/main' include { MSRESCORE_FEATURES } from '../../../modules/local/utils/msrescore_features/main' -include { GET_SAMPLE } from '../../../modules/local/utils/extract_sample/main' include { SPECTRUM_FEATURES } from '../../../modules/local/utils/spectrum_features/main' -include { ID_MERGER } from '../../../modules/local/openms/id_merger/main' workflow PEPTIDE_DATABASE_SEARCH { take: @@ -17,7 +15,7 @@ workflow PEPTIDE_DATABASE_SEARCH { ch_expdesign main: - (ch_id_msgf, ch_id_comet, ch_id_sage, ch_versions) = [ Channel.empty(), Channel.empty(), Channel.empty(), Channel.empty() ] + (ch_id_msgf, ch_id_comet, ch_id_sage, ch_versions) = [ channel.empty(), channel.empty(), channel.empty(), channel.empty() ] if (params.search_engines.contains("msgf")) { MSGF_DB_INDEXING(ch_searchengine_in_db) @@ -37,9 +35,9 @@ workflow PEPTIDE_DATABASE_SEARCH { // sorted mzmls to generate same batch ids when enable cache ch_mzmls_sorted_search = ch_mzmls_search.collect(flat: false, sort: { a, b -> a[0]["mzml_id"] <=> b[0]["mzml_id"] }).flatMap() if (params.search_engines.contains("sage")) { - cnt = 0 + def cnt = 0 ch_meta_mzml_db = ch_mzmls_sorted_search.map{ metapart, mzml -> - cnt++ + cnt += 1 def groupkey = metapart.labelling_type + metapart.dissociationmethod + metapart.fixedmodifications + @@ -72,19 +70,18 @@ workflow PEPTIDE_DATABASE_SEARCH { ch_id_sage = ch_id_sage.mix(SAGE.out.id_files_sage.transpose()) } - (ch_id_files_msgf_feats, ch_id_files_comet_feats, ch_id_files_sage_feats) = [ Channel.empty(), Channel.empty(), Channel.empty() ] + (ch_id_files_msgf_feats, ch_id_files_comet_feats, ch_id_files_sage_feats) = [ channel.empty(), channel.empty(), channel.empty() ] if (params.skip_rescoring != true) { - if (params.ms2features_enable == true){ // Only add ms2_model_dir if it's actually set and not empty // Handle cases where parameter might be empty string, null, boolean true, or whitespace // When --ms2features_model_dir is passed with no value, Nextflow may set it to boolean true if (params.ms2features_model_dir && params.ms2features_model_dir != true) { - ms2_model_dir = Channel.from(file(params.ms2features_model_dir, checkIfExists: true)) + ms2_model_dir = channel.from(file(params.ms2features_model_dir, checkIfExists: true)) } else { // create a fake channel when don't specify model dir - ms2_model_dir = Channel.from(file("pretrained_models")) + ms2_model_dir = channel.from(file("pretrained_models")) } if (params.ms2features_fine_tuning == true) { @@ -93,145 +90,75 @@ workflow PEPTIDE_DATABASE_SEARCH { } else { // Preparing train datasets and fine tuning MS2 model - sage_train_datasets = ch_id_sage - .combine(ch_mzmls_search, by: 0) - .toSortedList() - .flatMap() - .randomSample(params.fine_tuning_sample_run, 2025) - .combine(Channel.value("sage")) - .groupTuple(by: 3) - - msgf_train_datasets = ch_id_msgf + // Randomly select one search engine for fine-tuning sampling + engine_opts = [] + if (params.search_engines.contains("sage")) engine_opts.add("sage") + if (params.search_engines.contains("msgf")) engine_opts.add("msgf") + if (params.search_engines.contains("comet")) engine_opts.add("comet") + selected_engine = engine_opts[new Random(2025).nextInt(engine_opts.size())] + + ch_selected_engine = (selected_engine == "sage") ? ch_id_sage : + (selected_engine == "msgf") ? ch_id_msgf : + ch_id_comet + + train_datasets = ch_selected_engine .combine(ch_mzmls_search, by: 0) .toSortedList() .flatMap() .randomSample(params.fine_tuning_sample_run, 2025) - .combine(Channel.value("msgf")) .groupTuple(by: 3) - comet_train_datasets = ch_id_comet - .combine(ch_mzmls_search, by: 0) - .toSortedList() - .flatMap() - .randomSample(params.fine_tuning_sample_run, 2025) - .combine(Channel.value("comet")) - .groupTuple(by: 3) - - sage_train_datasets.mix(msgf_train_datasets) - .mix(comet_train_datasets) - .combine(ms2_model_dir) - .set { train_datasets } - MSRESCORE_FINE_TUNING(train_datasets) + MSRESCORE_FINE_TUNING(train_datasets.combine(ms2_model_dir)) ch_versions = ch_versions.mix(MSRESCORE_FINE_TUNING.out.versions) - Channel.value("msgf").combine(ch_id_msgf.combine(ch_mzmls_search, by: 0)) - .combine(MSRESCORE_FINE_TUNING.out.model_weight, by:0) - .map { [it[1], it[2], it[3], it[4], it[0] ] } - .set { msgf_features_input } - - Channel.value("sage").combine(ch_id_sage.combine(ch_mzmls_search, by: 0)) - .combine(MSRESCORE_FINE_TUNING.out.model_weight, by:0) - .map { [it[1], it[2], it[3], it[4], it[0] ] } - .set { sage_features_input } - - Channel.value("comet").combine(ch_id_comet.combine(ch_mzmls_search, by: 0)) - .combine(MSRESCORE_FINE_TUNING.out.model_weight, by:0) - .map { [it[1], it[2], it[3], it[4], it[0] ] } - .set { comet_features_input } + if (params.search_engines.tokenize(",").unique().size() > 1) { + ch_id_msgf.mix(ch_id_comet).mix(ch_id_sage).groupTuple(size: params.search_engines.tokenize(",").unique().size()) + .combine(ch_mzmls_search, by: 0) + .combine(MSRESCORE_FINE_TUNING.out.model_weight).set{ ch_id_rescoring } + } else { + ch_id_msgf.mix(ch_id_comet).mix(ch_id_sage).combine(ch_mzmls_search, by: 0) + .combine(MSRESCORE_FINE_TUNING.out.model_weight).set{ ch_id_rescoring } + } - MSRESCORE_FEATURES(msgf_features_input.mix(sage_features_input).mix(comet_features_input)) + MSRESCORE_FEATURES(ch_id_rescoring) ch_versions = ch_versions.mix(MSRESCORE_FEATURES.out.versions) - ch_id_files_feats = MSRESCORE_FEATURES.out.idxml - + ch_id_files_feats = MSRESCORE_FEATURES.out.idparquet } } else{ - ch_id_msgf.combine(ch_mzmls_search, by: 0) - .combine(ms2_model_dir) - .combine(Channel.value("msgf")).set{ ch_id_msgf } - ch_id_comet.combine(ch_mzmls_search, by: 0) - .combine(ms2_model_dir) - .combine(Channel.value("comet")).set{ ch_id_comet } - ch_id_sage.combine(ch_mzmls_search, by: 0) - .combine(ms2_model_dir) - .combine(Channel.value("sage")).set{ ch_id_sage } - - MSRESCORE_FEATURES(ch_id_msgf.mix(ch_id_comet).mix(ch_id_sage)) + if (params.search_engines.tokenize(",").unique().size() > 1) { + ch_id_msgf.mix(ch_id_comet).mix(ch_id_sage).groupTuple(size: params.search_engines.tokenize(",").unique().size()) + .combine(ch_mzmls_search, by: 0) + .combine(ms2_model_dir).set{ ch_id_rescoring } + } else { + ch_id_msgf.mix(ch_id_comet).mix(ch_id_sage).combine(ch_mzmls_search, by: 0) + .combine(ms2_model_dir).set{ ch_id_rescoring } + } + MSRESCORE_FEATURES(ch_id_rescoring) ch_versions = ch_versions.mix(MSRESCORE_FEATURES.out.versions) - ch_id_files_feats = MSRESCORE_FEATURES.out.idxml + ch_id_files_feats = MSRESCORE_FEATURES.out.idparquet } // Add SNR features to percolator if (params.ms2features_snr) { SPECTRUM_FEATURES(ch_id_files_feats.combine(ch_mzmls_search, by: 0)) - ch_id_files_feats_snr = SPECTRUM_FEATURES.out.id_files_snr + ch_id_files_out = SPECTRUM_FEATURES.out.id_files_snr ch_versions = ch_versions.mix(SPECTRUM_FEATURES.out.versions) } else { - ch_id_files_feats_snr = ch_id_files_feats + ch_id_files_out = ch_id_files_feats } - ch_id_files_feats_snr - .branch { meta, file_name, engine_name -> - msgf: engine_name == "msgf" - comet: engine_name == "comet" - sage: engine_name == "sage" - } - .set {ch_id_files_feats_branch} - ch_id_files_feats_branch.msgf.map {it -> [it[0], it[1]]}.set {ch_id_files_msgf_feats} - ch_id_files_feats_branch.comet.map {it -> [it[0], it[1]]}.set {ch_id_files_comet_feats} - ch_id_files_feats_branch.sage.map {it -> [it[0], it[1]]}.set {ch_id_files_sage_feats} - + } else if (params.search_engines.tokenize(",").unique().size() > 1) { + PSM_CLEAN(ch_id_msgf.mix(ch_id_comet).mix(ch_id_sage).groupTuple(size: params.search_engines.tokenize(",").unique().size()).combine(ch_mzmls_search, by: 0)) + ch_id_files_out = PSM_CLEAN.out.idparquet } else { - ch_id_files_msgf_feats = ch_id_msgf - ch_id_files_comet_feats = ch_id_comet - ch_id_files_sage_feats = ch_id_sage + ch_id_files_out = ch_id_msgf.mix(ch_id_comet).mix(ch_id_sage) } - if (params.ms2features_range == "by_sample") { - // Sample map - GET_SAMPLE(ch_expdesign) - ch_versions = ch_versions.mix(GET_SAMPLE.out.versions) - ch_expdesign_sample = GET_SAMPLE.out.ch_expdesign_sample - ch_expdesign_sample.splitCsv(header: true, sep: '\t') - .map { get_sample_map(it) }.set{ sample_map_idv } - - ch_id_files_msgf_feats.map {[it[0].mzml_id, it[0], it[1]]}.set { ch_id_files_msgf_feats } - ch_id_files_msgf_feats.combine(sample_map_idv, by: 0).map {[it[1], it[2], it[3]]}.set{ ch_id_files_msgf_feats } - - ch_id_files_comet_feats.map {[it[0].mzml_id, it[0], it[1]]}.set { ch_id_files_comet_feats } - ch_id_files_comet_feats.combine(sample_map_idv, by: 0).map {[it[1], it[2], it[3]]}.set{ ch_id_files_comet_feats } - - ch_id_files_sage_feats.map {[it[0].mzml_id, it[0], it[1]]}.set { ch_id_files_sage_feats } - ch_id_files_sage_feats.combine(sample_map_idv, by: 0).map {[it[1], it[2], it[3]]}.set{ ch_id_files_sage_feats } - - // ID_MERGER for samples group - ID_MERGER(ch_id_files_msgf_feats.groupTuple(by: 2) - .mix(ch_id_files_comet_feats.groupTuple(by: 2)) - .mix(ch_id_files_sage_feats.groupTuple(by: 2)) - ) - ch_versions = ch_versions.mix(ID_MERGER.out.versions) - ch_id_files_out = ID_MERGER.out.id_merged - - } else if (params.ms2features_range == "by_project") { - ch_id_files_msgf_feats.map {[it[0].experiment_id, it[0], it[1]]}.set { ch_id_files_msgf_feats } - ch_id_files_comet_feats.map {[it[0].experiment_id, it[0], it[1]]}.set { ch_id_files_comet_feats } - ch_id_files_sage_feats.map {[it[0].experiment_id, it[0], it[1]]}.set { ch_id_files_sage_feats } - - // ID_MERGER for whole experiments - ID_MERGER(ch_id_files_msgf_feats.groupTuple(by: 2) - .mix(ch_id_files_comet_feats.groupTuple(by: 2)) - .mix(ch_id_files_sage_feats.groupTuple(by: 2))) - ch_versions = ch_versions.mix(ID_MERGER.out.versions) - ch_id_files_out = ID_MERGER.out.id_merged - } else { - ch_id_files_out = ch_id_files_msgf_feats.mix(ch_id_files_comet_feats).mix(ch_id_files_sage_feats) - } - - } else if (params.psm_clean == true) { ch_id_files = ch_id_msgf.mix(ch_id_comet).mix(ch_id_sage) PSM_CLEAN(ch_id_files.combine(ch_mzmls_search, by: 0)) - ch_id_files_out = PSM_CLEAN.out.idxml + ch_id_files_out = PSM_CLEAN.out.idparquet ch_versions = ch_versions.mix(PSM_CLEAN.out.versions) } else { ch_id_files_out = ch_id_msgf.mix(ch_id_comet).mix(ch_id_sage) @@ -241,14 +168,3 @@ workflow PEPTIDE_DATABASE_SEARCH { ch_id_files_idx = ch_id_files_out versions = ch_versions } - -// Function to get sample map -def get_sample_map(LinkedHashMap row) { - - filestr = row.Spectra_Filepath - file_name = file(filestr).name.take(file(filestr).name.lastIndexOf('.')) - sample = row.Sample - - return [file_name, sample] - -} diff --git a/subworkflows/local/phospho_scoring/main.nf b/subworkflows/local/phospho_scoring/main.nf index 26ac839cc..aff5e5ef0 100644 --- a/subworkflows/local/phospho_scoring/main.nf +++ b/subworkflows/local/phospho_scoring/main.nf @@ -2,7 +2,6 @@ // Phospho modification site localisation and scoring. // -include { ID_SCORE_SWITCHER } from '../../../modules/local/openms/id_score_switcher/main' include { ONSITE } from '../../../modules/bigbio/onsite/main' workflow PHOSPHO_SCORING { @@ -11,17 +10,10 @@ workflow PHOSPHO_SCORING { ch_id_files main: - ch_version = Channel.empty() - if (params.search_engines.split(",").size() != 1){ - ID_SCORE_SWITCHER(ch_id_files.combine(Channel.value("\"Posterior Error Probability_score\""))) - ch_version = ch_version.mix(ID_SCORE_SWITCHER.out.versions) - ONSITE(ch_mzml_files.join(ID_SCORE_SWITCHER.out.id_score_switcher)) - ch_version = ch_version.mix(ONSITE.out.versions) - } else{ - ONSITE(ch_mzml_files.join(ch_id_files)) - ch_version = ch_version.mix(ONSITE.out.versions) - } + ch_version = channel.empty() + ONSITE(ch_mzml_files.join(ch_id_files)) + ch_version = ch_version.mix(ONSITE.out.versions) emit: diff --git a/subworkflows/local/protein_inference/main.nf b/subworkflows/local/protein_inference/main.nf deleted file mode 100644 index dec8ed133..000000000 --- a/subworkflows/local/protein_inference/main.nf +++ /dev/null @@ -1,40 +0,0 @@ -// -// ProteinInference -// - -include { PROTEIN_INFERENCE_EPIFANY } from '../../../modules/local/openms/protein_inference_epifany/main' -include { PROTEIN_INFERENCE_GENERIC } from '../../../modules/local/openms/protein_inference_generic/main' -include { ID_FILTER } from '../../../modules/local/openms/id_filter/main' - -workflow PROTEIN_INFERENCE { - take: - ch_consus_file - - main: - ch_version = Channel.empty() - - if (params.protein_inference_method == "bayesian") { - PROTEIN_INFERENCE_EPIFANY(ch_consus_file) - ch_version = ch_version.mix(PROTEIN_INFERENCE_EPIFANY.out.versions) - ch_inference = PROTEIN_INFERENCE_EPIFANY.out.epi_inference - } else { - PROTEIN_INFERENCE_GENERIC(ch_consus_file) - ch_version = ch_version.mix(PROTEIN_INFERENCE_GENERIC.out.versions) - ch_inference = PROTEIN_INFERENCE_GENERIC.out.protein_inference - } - - ID_FILTER(ch_inference.combine(Channel.value("-score:type_protein q-value"))) - ch_version = ch_version.mix(ID_FILTER.out.versions) - ID_FILTER.out.id_filtered - .multiMap{ it -> - meta: it[0] - results: it[1] - } - .set{ ch_epi_results } - - emit: - epi_idfilter = ch_epi_results.results - - versions = ch_version - -} diff --git a/subworkflows/local/protein_inference/meta.yml b/subworkflows/local/protein_inference/meta.yml deleted file mode 100644 index 7bab69e8d..000000000 --- a/subworkflows/local/protein_inference/meta.yml +++ /dev/null @@ -1,30 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json -name: "protein_inference" -description: Subworkflow for protein inference from peptide identifications -keywords: - - protein - - inference - - proteomics - - peptides -components: - - protein/inference/epifany - - protein/inference/generic - - id/filter -input: - - ch_input: - type: file - description: | - Channel containing input files for protein inference -output: - - ch_protein_results: - type: file - description: | - Channel containing protein inference results - - versions: - type: file - description: | - Software versions used in this subworkflow -authors: - - "@bigbio" -maintainers: - - "@bigbio" diff --git a/subworkflows/local/protein_quant/main.nf b/subworkflows/local/protein_quant/main.nf deleted file mode 100644 index 45cc90b75..000000000 --- a/subworkflows/local/protein_quant/main.nf +++ /dev/null @@ -1,30 +0,0 @@ -// -// ProteinQuant -// - -include { ID_CONFLICT_RESOLVER as ID_CONFLICT_RESOLVER } from '../../../modules/local/openms/id_conflict_resolver/main' -include { PROTEIN_QUANTIFIER as PROTEIN_QUANTIFIER } from '../../../modules/local/openms/protein_quantifier/main' -include { MSSTATS_CONVERTER as MSSTATS_CONVERTER } from '../../../modules/local/openms/msstats_converter/main' - -workflow PROTEIN_QUANT { - take: - ch_conflict_file - ch_expdesign_file - - main: - ch_version = Channel.empty() - - ID_CONFLICT_RESOLVER(ch_conflict_file) - ch_version = ch_version.mix(ID_CONFLICT_RESOLVER.out.versions) - - PROTEIN_QUANTIFIER(ID_CONFLICT_RESOLVER.out.pro_resconf, ch_expdesign_file) - ch_version = ch_version.mix(PROTEIN_QUANTIFIER.out.versions) - - MSSTATS_CONVERTER(ID_CONFLICT_RESOLVER.out.pro_resconf, ch_expdesign_file, "ISO") - ch_version = ch_version.mix(MSSTATS_CONVERTER.out.versions) - - emit: - msstats_csv = MSSTATS_CONVERTER.out.out_msstats - out_mztab = PROTEIN_QUANTIFIER.out.out_mztab - versions = ch_version -} diff --git a/subworkflows/local/protein_quant/meta.yml b/subworkflows/local/protein_quant/meta.yml deleted file mode 100644 index 71ae589f2..000000000 --- a/subworkflows/local/protein_quant/meta.yml +++ /dev/null @@ -1,30 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json -name: "protein_quant" -description: Subworkflow for protein quantification from MS data -keywords: - - protein - - quantification - - proteomics - - ms -components: - - id/conflict/resolver - - protein/quantifier - - msstats/converter -input: - - ch_input: - type: file - description: | - Channel containing input files for protein quantification -output: - - ch_quant_results: - type: file - description: | - Channel containing protein quantification results - - versions: - type: file - description: | - Software versions used in this subworkflow -authors: - - "@bigbio" -maintainers: - - "@bigbio" diff --git a/subworkflows/local/psm_fdr_control/main.nf b/subworkflows/local/psm_fdr_control/main.nf deleted file mode 100644 index e21a39168..000000000 --- a/subworkflows/local/psm_fdr_control/main.nf +++ /dev/null @@ -1,30 +0,0 @@ -// -// fdr control based on psm/peptide -// - -include { FALSE_DISCOVERY_RATE as FDR_CONSENSUSID } from '../../../modules/local/openms/false_discovery_rate/main' -include { ID_FILTER } from '../../../modules/local/openms/id_filter/main' - -workflow PSM_FDR_CONTROL { - - take: - ch_id_files - - main: - ch_version = Channel.empty() - ch_idfilter = Channel.empty() - - if (params.search_engines.split(",").size() == 1) { - ID_FILTER(ch_id_files.combine(Channel.value("-score:type_peptide q-value"))) - ch_version = ch_version.mix(ID_FILTER.out.versions) - ch_idfilter = ID_FILTER.out.id_filtered - } else { - FDR_CONSENSUSID(ch_id_files) - ch_version = ch_version.mix(FDR_CONSENSUSID.out.versions) - ch_idfilter = FDR_CONSENSUSID.out.id_files_idx_ForIDPEP_FDR - } - - emit: - id_filtered = ch_idfilter - versions = ch_version -} diff --git a/subworkflows/local/psm_fdr_control/meta.yml b/subworkflows/local/psm_fdr_control/meta.yml deleted file mode 100644 index b73294ca6..000000000 --- a/subworkflows/local/psm_fdr_control/meta.yml +++ /dev/null @@ -1,30 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json -name: "psm_fdr_control" -description: Subworkflow for PSM-level false discovery rate control -keywords: - - psm - - fdr - - discovery - - rate - - proteomics -components: - - false/discovery/rate - - id/filter -input: - - ch_input: - type: file - description: | - Channel containing input files for FDR control -output: - - ch_fdr_results: - type: file - description: | - Channel containing FDR-controlled results - - versions: - type: file - description: | - Software versions used in this subworkflow -authors: - - "@bigbio" -maintainers: - - "@bigbio" diff --git a/subworkflows/local/psm_rescoring/main.nf b/subworkflows/local/psm_rescoring/main.nf index 86cb44ba4..3076b3e1f 100644 --- a/subworkflows/local/psm_rescoring/main.nf +++ b/subworkflows/local/psm_rescoring/main.nf @@ -4,66 +4,17 @@ include { PERCOLATOR } from '../../../modules/local/openms/percolator/main' -include { ID_RIPPER } from '../../../modules/local/openms/id_ripper/main' - - workflow PSM_RESCORING { take: - ch_file_preparation_results ch_id_files_feats - ch_expdesign main: - ch_software_versions = Channel.empty() - ch_results = Channel.empty() - ch_fdridpep = Channel.empty() - - // Rescoring for independent run, Sample or whole experiments - if (params.ms2features_range == "independent_run") { - PERCOLATOR(ch_id_files_feats) - ch_software_versions = ch_software_versions.mix(PERCOLATOR.out.versions) - ch_consensus_input = PERCOLATOR.out.id_files_perc - } else if (params.ms2features_range == "by_sample") { - PERCOLATOR(ch_id_files_feats) - ch_software_versions = ch_software_versions.mix(PERCOLATOR.out.versions) - - // Currently only ID runs on exactly one mzML file are supported in CONSENSUSID. Split idXML by runs - ID_RIPPER(PERCOLATOR.out.id_files_perc) - ch_file_preparation_results.map{[it[0].mzml_id, it[0]]}.set{meta} - ID_RIPPER.out.id_rippers.flatten().map { add_file_prefix (it)}.set{id_rippers} - meta.combine(id_rippers, by: 0) - .map{ [it[1], it[2]]} - .set{ ch_consensus_input } - ch_software_versions = ch_software_versions.mix(ID_RIPPER.out.versions) - - } else if (params.ms2features_range == "by_project"){ - PERCOLATOR(ch_id_files_feats) - ch_software_versions = ch_software_versions.mix(PERCOLATOR.out.versions) - - // Currently only ID runs on exactly one mzML file are supported in CONSENSUSID. Split idXML by runs - ID_RIPPER(PERCOLATOR.out.id_files_perc) - ch_file_preparation_results.map{[it[0].mzml_id, it[0]]}.set{meta} - ID_RIPPER.out.id_rippers.flatten().map { add_file_prefix (it)}.set{id_rippers} - meta.combine(id_rippers, by: 0) - .map{ [it[1], it[2]]} - .set{ ch_consensus_input } - ch_software_versions = ch_software_versions.mix(ID_RIPPER.out.versions) - } - ch_rescoring_results = ch_consensus_input + ch_software_versions = channel.empty() + PERCOLATOR(ch_id_files_feats) + ch_software_versions = ch_software_versions.mix(PERCOLATOR.out.versions) + ch_rescoring_results = PERCOLATOR.out.id_files_perc emit: results = ch_rescoring_results versions = ch_software_versions } - -def add_file_prefix(file_path) { - position = file(file_path).name.lastIndexOf('_sage_perc.idXML') - if (position == -1) { - position = file(file_path).name.lastIndexOf('_comet_perc.idXML') - if (position == -1) { - position = file(file_path).name.lastIndexOf('_msgf_perc.idXML') - } - } - file_name = file(file_name).name.take(position) - return [file_name, file_path] -} diff --git a/subworkflows/local/utils_nfcore_quantms_pipeline/main.nf b/subworkflows/local/utils_nfcore_quantms_pipeline/main.nf index f7e6b6d8d..55aed7ba1 100644 --- a/subworkflows/local/utils_nfcore_quantms_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_quantms_pipeline/main.nf @@ -12,7 +12,6 @@ include { paramsSummaryMap } from 'plugin/nf-schema' include { completionEmail } from '../../nf-core/utils_nfcore_pipeline' include { completionSummary } from '../../nf-core/utils_nfcore_pipeline' -include { imNotification } from '../../nf-core/utils_nfcore_pipeline' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -35,12 +34,12 @@ workflow PIPELINE_COMPLETION { plaintext_email // boolean: Send plain-text email instead of HTML outdir // path: Path to output directory where results will be published monochrome_logs // boolean: Disable ANSI colour codes in log output - hook_url // string: hook URL for notifications multiqc_report // string: Path to MultiQC report main: summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") def multiqc_reports = multiqc_report.toList() + // // Completion email and summary // @@ -58,9 +57,6 @@ workflow PIPELINE_COMPLETION { } completionSummary(monochrome_logs) - if (hook_url) { - imNotification(summary_params, hook_url) - } } workflow.onError { @@ -78,6 +74,12 @@ workflow PIPELINE_COMPLETION { // def validateInputParameters() { genomeExistsError() + + // Removed parameters — error loudly with migration guidance. + // nf-schema only warns on unknown params by default, so these need an explicit check. + if (params.containsKey('ms2features_range')) { + error("The parameter `--ms2features_range` has been removed. Per-file Percolator (previously `independent_run`) is now the only supported topology; drop this parameter from your config.") + } } // diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index 2f30e9a46..afca54390 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -17,7 +17,7 @@ workflow UTILS_NFCORE_PIPELINE { checkProfileProvided(nextflow_cli_args) emit: - valid_config + valid_config = valid_config } /* @@ -353,67 +353,3 @@ def completionSummary(monochrome_logs=true) { log.info("-${colors.purple}[${workflow.manifest.name}]${colors.red} Pipeline completed with errors${colors.reset}-") } } - -// -// Construct and send a notification to a web server as JSON e.g. Microsoft Teams and Slack -// -def imNotification(summary_params, hook_url) { - def summary = [:] - summary_params - .keySet() - .sort() - .each { group -> - summary << summary_params[group] - } - - def misc_fields = [:] - misc_fields['start'] = workflow.start - misc_fields['complete'] = workflow.complete - misc_fields['scriptfile'] = workflow.scriptFile - misc_fields['scriptid'] = workflow.scriptId - if (workflow.repository) { - misc_fields['repository'] = workflow.repository - } - if (workflow.commitId) { - misc_fields['commitid'] = workflow.commitId - } - if (workflow.revision) { - misc_fields['revision'] = workflow.revision - } - misc_fields['nxf_version'] = workflow.nextflow.version - misc_fields['nxf_build'] = workflow.nextflow.build - misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp - - def msg_fields = [:] - msg_fields['version'] = getWorkflowVersion() - msg_fields['runName'] = workflow.runName - msg_fields['success'] = workflow.success - msg_fields['dateComplete'] = workflow.complete - msg_fields['duration'] = workflow.duration - msg_fields['exitStatus'] = workflow.exitStatus - msg_fields['errorMessage'] = (workflow.errorMessage ?: 'None') - msg_fields['errorReport'] = (workflow.errorReport ?: 'None') - msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "") - msg_fields['projectDir'] = workflow.projectDir - msg_fields['summary'] = summary << misc_fields - - // Render the JSON template - def engine = new groovy.text.GStringTemplateEngine() - // Different JSON depending on the service provider - // Defaults to "Adaptive Cards" (https://adaptivecards.io), except Slack which has its own format - def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json" - def hf = new File("${workflow.projectDir}/assets/${json_path}") - def json_template = engine.createTemplate(hf).make(msg_fields) - def json_message = json_template.toString() - - // POST - def post = new URL(hook_url).openConnection() - post.setRequestMethod("POST") - post.setDoOutput(true) - post.setRequestProperty("Content-Type", "application/json") - post.getOutputStream().write(json_message.getBytes("UTF-8")) - def postRC = post.getResponseCode() - if (!postRC.equals(200)) { - log.warn(post.getErrorStream().getText()) - } -} diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test new file mode 100644 index 000000000..8940d32d1 --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test @@ -0,0 +1,29 @@ +nextflow_workflow { + + name "Test Workflow UTILS_NFCORE_PIPELINE" + script "../main.nf" + config "subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config" + workflow "UTILS_NFCORE_PIPELINE" + tag "subworkflows" + tag "subworkflows_nfcore" + tag "utils_nfcore_pipeline" + tag "subworkflows/utils_nfcore_pipeline" + + test("Should run without failures") { + + when { + workflow { + """ + input[0] = [] + """ + } + } + + then { + assertAll( + { assert workflow.success }, + { assert snapshot(workflow.out).match() } + ) + } + } +} diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap new file mode 100644 index 000000000..859d1030f --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap @@ -0,0 +1,19 @@ +{ + "Should run without failures": { + "content": [ + { + "0": [ + true + ], + "valid_config": [ + true + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:03:25.726491" + } +} \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nfschema_plugin/main.nf b/subworkflows/nf-core/utils_nfschema_plugin/main.nf index acb397241..1df8b76fb 100644 --- a/subworkflows/nf-core/utils_nfschema_plugin/main.nf +++ b/subworkflows/nf-core/utils_nfschema_plugin/main.nf @@ -38,7 +38,7 @@ workflow UTILS_NFSCHEMA_PLUGIN { } log.info paramsHelp( help_options, - params.help instanceof String ? params.help : "", + (params.help instanceof String && params.help != "true") ? params.help : "", ) exit 0 } diff --git a/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config index 8d8c73718..f6537cc33 100644 --- a/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config +++ b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config @@ -1,5 +1,5 @@ plugins { - id "nf-schema@2.5.1" + id "nf-schema@2.6.1" } validation { diff --git a/tests/default.nf.test b/tests/default.nf.test index ee3179e5c..dfdd78282 100644 --- a/tests/default.nf.test +++ b/tests/default.nf.test @@ -13,19 +13,19 @@ nextflow_pipeline { } then { - // stable_name: All files + folders in ${params.outdir}/ with a stable name - def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}']) - // stable_path: All files in ${params.outdir}/ with stable content - def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') + // stable_path: All files + folders in ${params.outdir}/ with a stable path (including file name) + def stable_path = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}']) + // stable_content: All files in ${params.outdir}/ with stable content + def stable_content = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') + assert workflow.success assertAll( - { assert workflow.success}, { assert snapshot( // pipeline versions.yml file for multiqc from which Nextflow version is removed because we test pipelines on multiple Nextflow versions removeNextflowVersion("$outputDir/pipeline_info/nf_core_quantms_software_mqc_versions.yml"), // All stable path name, with a relative path - stable_name, + stable_path, // All files with stable contents - stable_path + stable_content ).match() } ) } diff --git a/tests/nextflow.config b/tests/nextflow.config index 07d8a65ac..c8731282c 100644 --- a/tests/nextflow.config +++ b/tests/nextflow.config @@ -7,8 +7,8 @@ // TODO nf-core: Specify any additional parameters here // Or any resources requirements params { - modules_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/modules/data/' - pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/refs/heads/quantms' + modules_testdata_base_path = 'https://raw.githubusercontent.com/bigbio/quantms-test-datasets/modules/data/' + pipelines_testdata_base_path = 'https://raw.githubusercontent.com/bigbio/quantms-test-datasets/refs/heads/quantms' } aws.client.anonymous = true // fixes S3 access issues on self-hosted runners diff --git a/workflows/dia.nf b/workflows/dia.nf deleted file mode 100644 index 5ba20728f..000000000 --- a/workflows/dia.nf +++ /dev/null @@ -1,204 +0,0 @@ -/* -======================================================================================== - IMPORT LOCAL MODULES/SUBWORKFLOWS -======================================================================================== -*/ - -// -// MODULES: Local to the pipeline -// -include { GENERATE_CFG } from '../modules/local/diann/generate_cfg/main' -include { CONVERT_RESULTS } from '../modules/local/diann/convert_results/main' -include { MSSTATS_LFQ } from '../modules/local/msstats/msstats_lfq/main' -include { PRELIMINARY_ANALYSIS } from '../modules/local/diann/preliminary_analysis/main' -include { ASSEMBLE_EMPIRICAL_LIBRARY } from '../modules/local/diann/assemble_empirical_library/main' -include { INSILICO_LIBRARY_GENERATION } from '../modules/local/diann/insilico_library_generation/main' -include { INDIVIDUAL_ANALYSIS } from '../modules/local/diann/individual_analysis/main' -include { FINAL_QUANTIFICATION } from '../modules/local/diann/final_quantification/main' - -// -// SUBWORKFLOWS: Consisting of a mix of local and nf-core/modules -// - -/* -======================================================================================== - RUN MAIN WORKFLOW -======================================================================================== -*/ - -// Info required for completion email and summary -def multiqc_report = [] - -workflow DIA { - take: - ch_file_preparation_results - ch_expdesign - ch_ms_info - - main: - - ch_software_versions = Channel.empty() - Channel.fromPath(params.database).set { ch_searchdb } - - ch_file_preparation_results.multiMap { - result -> - meta: preprocessed_meta(result[0]) - ms_file:result[1] - }.set { ch_result } - - meta = ch_result.meta.unique { it[0] } - - GENERATE_CFG(meta) - ch_software_versions = ch_software_versions - .mix(GENERATE_CFG.out.versions) - - // - // MODULE: SILICOLIBRARYGENERATION - // - if (params.diann_speclib != null && params.diann_speclib.toString() != "") { - speclib = Channel.from(file(params.diann_speclib, checkIfExists: true)) - } else { - INSILICO_LIBRARY_GENERATION(ch_searchdb, GENERATE_CFG.out.diann_cfg) - speclib = INSILICO_LIBRARY_GENERATION.out.predict_speclib - } - - if (params.skip_preliminary_analysis) { - assembly_log = Channel.fromPath(params.empirical_assembly_log) - empirical_library = Channel.fromPath(params.diann_speclib) - indiv_fin_analysis_in = ch_file_preparation_results.combine(ch_searchdb) - .combine(assembly_log) - .combine(empirical_library) - empirical_lib = empirical_library - } else { - // - // MODULE: PRELIMINARY_ANALYSIS - // - if (params.random_preanalysis) { - preanalysis_subset = ch_file_preparation_results - .toSortedList{ a, b -> file(a[1]).getName() <=> file(b[1]).getName() } - .flatMap() - .randomSample(params.empirical_assembly_ms_n, params.random_preanalysis_seed) - empirical_lib_files = preanalysis_subset - .map { result -> result[1] } - .collect( sort: { a, b -> file(a).getName() <=> file(b).getName() } ) - PRELIMINARY_ANALYSIS(preanalysis_subset.combine(speclib)) - } else { - empirical_lib_files = ch_file_preparation_results - .map { result -> result[1] } - .collect( sort: { a, b -> file(a).getName() <=> file(b).getName() } ) - PRELIMINARY_ANALYSIS(ch_file_preparation_results.combine(speclib)) - } - ch_software_versions = ch_software_versions - .mix(PRELIMINARY_ANALYSIS.out.versions) - - // - // MODULE: ASSEMBLE_EMPIRICAL_LIBRARY - // - // Order matters in DIANN, This should be sorted for reproducible results. - ASSEMBLE_EMPIRICAL_LIBRARY( - empirical_lib_files, - meta, - PRELIMINARY_ANALYSIS.out.diann_quant.collect(), - speclib - ) - ch_software_versions = ch_software_versions - .mix(ASSEMBLE_EMPIRICAL_LIBRARY.out.versions) - indiv_fin_analysis_in = ch_file_preparation_results - .combine(ch_searchdb) - .combine(ASSEMBLE_EMPIRICAL_LIBRARY.out.log) - .combine(ASSEMBLE_EMPIRICAL_LIBRARY.out.empirical_library) - - empirical_lib = ASSEMBLE_EMPIRICAL_LIBRARY.out.empirical_library - } - - // - // MODULE: INDIVIDUAL_ANALYSIS - // - INDIVIDUAL_ANALYSIS(indiv_fin_analysis_in) - ch_software_versions = ch_software_versions - .mix(INDIVIDUAL_ANALYSIS.out.versions) - - // - // MODULE: DIANNSUMMARY - // - // Order matters in DIANN, This should be sorted for reproducible results. - // NOTE: ch_results.ms_file contains the name of the ms file, not the path. - // The next step only needs the name (since it uses the cached .quant) - // Converting to a file object and using its name is necessary because ch_result.ms_file contains - // locally, evey element in ch_result is a string, whilst on cloud it is a path. - ch_result - .ms_file.map { msfile -> file(msfile).getName() } - .collect(sort: true) - .set { ms_file_names } - - FINAL_QUANTIFICATION( - ms_file_names, - meta, - empirical_lib, - INDIVIDUAL_ANALYSIS.out.diann_quant.collect(), - ch_searchdb) - - ch_software_versions = ch_software_versions.mix( - FINAL_QUANTIFICATION.out.versions - ) - - // - // MODULE: DIANNCONVERT - // - diann_main_report = FINAL_QUANTIFICATION.out.main_report.mix(FINAL_QUANTIFICATION.out.report_parquet).last() - - CONVERT_RESULTS( - diann_main_report, ch_expdesign, - FINAL_QUANTIFICATION.out.pg_matrix, - FINAL_QUANTIFICATION.out.pr_matrix, ch_ms_info, - meta, - ch_searchdb, - FINAL_QUANTIFICATION.out.versions - ) - ch_software_versions = ch_software_versions - .mix(CONVERT_RESULTS.out.versions) - - // - // MODULE: MSSTATS - ch_msstats_out = Channel.empty() - if (!params.skip_post_msstats) { - MSSTATS_LFQ(CONVERT_RESULTS.out.out_msstats) - ch_msstats_out = MSSTATS_LFQ.out.msstats_csv - ch_software_versions = ch_software_versions.mix( - MSSTATS_LFQ.out.versions - ) - } - - emit: - versions = ch_software_versions - diann_report = FINAL_QUANTIFICATION.out.main_report - diann_report_parquet = FINAL_QUANTIFICATION.out.report_parquet - msstats_in = CONVERT_RESULTS.out.out_msstats - out_triqler = CONVERT_RESULTS.out.out_triqler - final_result = CONVERT_RESULTS.out.out_mztab - msstats_out = ch_msstats_out -} - -// remove meta.id to make sure cache identical HashCode -def preprocessed_meta(LinkedHashMap meta) { - def parameters = [:] - parameters['experiment_id'] = meta.experiment_id - parameters['acquisition_method'] = meta.acquisition_method - parameters['dissociationmethod'] = meta.dissociationmethod - parameters['labelling_type'] = meta.labelling_type - parameters['fixedmodifications'] = meta.fixedmodifications - parameters['variablemodifications'] = meta.variablemodifications - parameters['precursormasstolerance'] = meta.precursormasstolerance - parameters['precursormasstoleranceunit'] = meta.precursormasstoleranceunit - parameters['fragmentmasstolerance'] = meta.fragmentmasstolerance - parameters['fragmentmasstoleranceunit'] = meta.fragmentmasstoleranceunit - parameters['enzyme'] = meta.enzyme - - return parameters -} - -/* -======================================================================================== - THE END -======================================================================================== -*/ diff --git a/workflows/lfq.nf b/workflows/lfq.nf index f569fde3b..230469105 100644 --- a/workflows/lfq.nf +++ b/workflows/lfq.nf @@ -8,7 +8,6 @@ // MODULES: Local to the pipeline // include { PROTEOMICSLFQ } from '../modules/local/openms/proteomicslfq/main' -include { MSSTATS_LFQ } from '../modules/local/msstats/msstats_lfq/main' // // SUBWORKFLOWS: Consisting of a mix of local and nf-core/modules @@ -21,8 +20,6 @@ include { ID } from '../subworkflows/local/id/main' ======================================================================================== */ -// Info required for completion email and summary -def multiqc_report = [] workflow LFQ { take: @@ -32,7 +29,7 @@ workflow LFQ { main: - ch_software_versions = Channel.empty() + ch_software_versions = channel.empty() // // SUBWORKFLOWS: ID @@ -56,16 +53,6 @@ workflow LFQ { ) ch_software_versions = ch_software_versions.mix(PROTEOMICSLFQ.out.versions) - // - // MODULE: MSSTATS - // - ch_msstats_out = Channel.empty() - if(!params.skip_post_msstats && params.quantification_method == "feature_intensity"){ - MSSTATS_LFQ(PROTEOMICSLFQ.out.out_msstats) - ch_msstats_out = MSSTATS_LFQ.out.msstats_csv - ch_software_versions = ch_software_versions.mix(MSSTATS_LFQ.out.versions) - } - ID.out.psmrescoring_results .map { it -> it[1] } .set { ch_pmultiqc_ids } @@ -80,7 +67,6 @@ workflow LFQ { final_result = PROTEOMICSLFQ.out.out_mztab versions = ch_software_versions msstats_in = PROTEOMICSLFQ.out.out_msstats - msstats_out = ch_msstats_out } /* diff --git a/workflows/quantms.nf b/workflows/quantms.nf index 62f9b5d53..6960482a6 100644 --- a/workflows/quantms.nf +++ b/workflows/quantms.nf @@ -9,10 +9,9 @@ include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipe include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline' include { methodsDescriptionText } from '../subworkflows/local/utils_nfcore_quantms_pipeline' -// Main subworkflows imported from the pipeline TMT, LFQ, DIA +// Main subworkflows imported from the pipeline TMT, LFQ include { TMT } from './tmt' include { LFQ } from './lfq' -include { DIA } from './dia' // SUBWORKFLOW: Consisting of a mix of local and nf-core/modules include { INPUT_CHECK } from '../subworkflows/local/input_check/main' @@ -36,16 +35,17 @@ workflow QUANTMS { main: // TODO check what the standard is here: ch_versions or ch_software_versions - ch_versions = Channel.empty() + ch_versions = channel.empty() // // SUBWORKFLOW: Read in samplesheet, validate and stage input files // + INPUT_CHECK( file(params.input) ) ch_versions = ch_versions.mix(INPUT_CHECK.out.versions) - // TODO: OPTIONAL, you can use nf-validation plugin to create an input channel from the samplesheet with Channel.fromSamplesheet("input") + // TODO: OPTIONAL, you can use nf-validation plugin to create an input channel from the samplesheet with channel.fromSamplesheet("input") // See the documentation https://nextflow-io.github.io/nf-validation/samplesheets/fromSamplesheet/ // ! There is currently no tooling to help you write a sample sheet schema @@ -53,8 +53,7 @@ workflow QUANTMS { // SUBWORKFLOW: Create input channel // CREATE_INPUT_CHANNEL( - INPUT_CHECK.out.ch_input_file, - INPUT_CHECK.out.is_sdrf, + INPUT_CHECK.out.ch_input_file ) ch_versions = ch_versions.mix(CREATE_INPUT_CHANNEL.out.versions) @@ -62,31 +61,30 @@ workflow QUANTMS { // SUBWORKFLOW: File preparation // FILE_PREPARATION( - CREATE_INPUT_CHANNEL.out.ch_meta_config_iso.mix(CREATE_INPUT_CHANNEL.out.ch_meta_config_lfq).mix(CREATE_INPUT_CHANNEL.out.ch_meta_config_dia) + CREATE_INPUT_CHANNEL.out.ch_meta_config_iso.mix(CREATE_INPUT_CHANNEL.out.ch_meta_config_lfq) ) ch_versions = ch_versions.mix(FILE_PREPARATION.out.versions) FILE_PREPARATION.out.results - .branch { - dia: it[0].acquisition_method.contains("dia") - iso: it[0].labelling_type.contains("tmt") || it[0].labelling_type.contains("itraq") - lfq: it[0].labelling_type.contains("label free") + .branch { item -> + iso: item[0].labelling_type.contains("tmt") || item[0].labelling_type.contains("itraq") + lfq: item[0].labelling_type.contains("label free") } .set { ch_fileprep_result } // // WORKFLOW: Run main bigbio/quantms analysis pipeline based on the quantification type // - ch_pipeline_results = Channel.empty() - ch_ids_pmultiqc = Channel.empty() - ch_msstats_in = Channel.empty() - ch_consensus_pmultiqc = Channel.empty() + ch_pipeline_results = channel.empty() + ch_ids_pmultiqc = channel.empty() + ch_msstats_in = channel.empty() + ch_consensus_pmultiqc = channel.empty() // // MODULE: Generate decoy database // if (params.database) { - ch_db_for_decoy_creation = Channel.from(file(params.database, checkIfExists: true)) + ch_db_for_decoy_creation = channel.from(file(params.database, checkIfExists: true)) } else { exit(1, 'No protein database provided') @@ -97,10 +95,10 @@ workflow QUANTMS { CREATE_INPUT_CHANNEL.out.ch_meta_config_lfq ).first() | combine(ch_db_for_decoy_creation) - | map { it[-1] } + | map { item -> item[-1] } | set { ch_db_for_decoy_creation_or_null } - ch_searchengine_in_db = params.add_decoys ? Channel.empty() : Channel.fromPath(params.database) + ch_searchengine_in_db = params.add_decoys ? channel.empty() : channel.fromPath(params.database) if (params.add_decoys) { GENERATE_DECOY_DATABASE( ch_db_for_decoy_creation_or_null @@ -152,21 +150,32 @@ workflow QUANTMS { ch_msstats_in = ch_msstats_in.mix(LFQ.out.msstats_in) ch_versions = ch_versions.mix(LFQ.out.versions) - DIA( - ch_fileprep_result.dia, - CREATE_INPUT_CHANNEL.out.ch_expdesign, - FILE_PREPARATION.out.statistics, - ) - ch_pipeline_results = ch_pipeline_results.mix(DIA.out.diann_report) - ch_pipeline_results = ch_pipeline_results.mix(DIA.out.diann_report_parquet) - ch_msstats_in = ch_msstats_in.mix(DIA.out.msstats_in) - ch_versions = ch_versions.mix(DIA.out.versions) } // Other subworkflow will return null when performing another subworkflow due to unknown reason. - ch_versions = ch_versions.filter { it != null } + ch_versions = ch_versions.filter { v -> v != null } + + // see https://nf-co.re/docs/tutorials/migrate_to_topics/update_pipelines + // which is used in https://github.com/nf-core/demo/blob/1.1.0/workflows/demo.nf + def topic_versions = channel.topic("versions") + .distinct() + .branch { entry -> + versions_file: entry instanceof Path + versions_tuple: true + } + + def topic_versions_string = topic_versions.versions_tuple + .map { process, tool, version -> + [ process[process.lastIndexOf(':')+1..-1], " ${tool}: ${version}" ] + } + .groupTuple(by:0) + .map { process, tool_versions -> + tool_versions.unique().sort() + "${process}:\n${tool_versions.join('\n')}" + } - softwareVersionsToYAML(ch_versions) + softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) + .mix(topic_versions_string) .collectFile( storeDir: "${params.outdir}/pipeline_info", name: 'nf_core_' + 'quantms_software_' + 'mqc_' + 'versions.yml', @@ -176,17 +185,15 @@ workflow QUANTMS { .set { ch_collated_versions } - ch_multiqc_config = Channel.fromPath("${projectDir}/assets/multiqc_config.yml", checkIfExists: true) - ch_multiqc_custom_config = params.multiqc_config ? Channel.fromPath(params.multiqc_config, checkIfExists: true) : Channel.empty() - ch_multiqc_logo = params.multiqc_logo ? Channel.fromPath(params.multiqc_logo, checkIfExists: true) : Channel.empty() + ch_multiqc_config = channel.fromPath("${projectDir}/assets/multiqc_config.yml", checkIfExists: true) summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") - ch_workflow_summary = Channel.value(paramsSummaryMultiqc(summary_params)) + ch_workflow_summary = channel.value(paramsSummaryMultiqc(summary_params)) ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file(params.multiqc_methods_description, checkIfExists: true) : file("${projectDir}/assets/methods_description_template.yml", checkIfExists: true) - ch_methods_description = Channel.value(methodsDescriptionText(ch_multiqc_custom_methods_description)) + ch_methods_description = channel.value(methodsDescriptionText(ch_multiqc_custom_methods_description)) // concatenate multiqc input files - ch_multiqc_files = Channel.empty() + ch_multiqc_files = channel.empty() ch_multiqc_files = ch_multiqc_files.mix(ch_multiqc_config) ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) ch_multiqc_files = ch_multiqc_files.mix(FILE_PREPARATION.out.statistics) diff --git a/workflows/tmt.nf b/workflows/tmt.nf index 97fd5a67c..a8b9f0d66 100644 --- a/workflows/tmt.nf +++ b/workflows/tmt.nf @@ -7,15 +7,12 @@ // // MODULES: Local to the pipeline // -include { FILE_MERGE } from '../modules/local/openms/file_merge/main' -include { MSSTATS_TMT } from '../modules/local/msstats/msstats_tmt/main' +include { ISOBARIC_WORKFLOW } from '../modules/local/openms/isobaric_workflow/main' +include { MSSTATS_CONVERTER } from '../modules/local/openms/msstats_converter/main' // // SUBWORKFLOWS: Consisting of a mix of local and nf-core/modules // -include { FEATURE_MAPPER } from '../subworkflows/local/feature_mapper/main' -include { PROTEIN_INFERENCE } from '../subworkflows/local/protein_inference/main' -include { PROTEIN_QUANT } from '../subworkflows/local/protein_quant/main' include { ID } from '../subworkflows/local/id/main' /* @@ -32,7 +29,7 @@ workflow TMT { main: - ch_software_versions = Channel.empty() + ch_software_versions = channel.empty() // // SUBWORKFLOWS: ID @@ -41,38 +38,28 @@ workflow TMT { ch_software_versions = ch_software_versions.mix(ID.out.versions) // - // SUBWORKFLOW: FEATUREMAPPER + // SUBWORKFLOW: ISOBARIC_WORKFLOW // - FEATURE_MAPPER(ch_file_preparation_results, ID.out.id_results) - ch_software_versions = ch_software_versions.mix(FEATURE_MAPPER.out.versions) + // Extract labelling_type from meta (auto-detected from SDRF) + ch_file_preparation_results.join(ID.out.id_results) + .multiMap { it -> + labelling_type: it[0].labelling_type + mzmls: it[1] + ids: it[2] + } + .set{ ch_iso_workflow } + ISOBARIC_WORKFLOW(ch_iso_workflow.labelling_type.first(), + ch_iso_workflow.mzmls.collect(), + ch_iso_workflow.ids.collect(), + ch_expdesign + ) + ch_software_versions = ch_software_versions.mix(ISOBARIC_WORKFLOW.out.versions) // - // MODULE: FILEMERGE + // SUBWORKFLOW: MSSTATS_CONVERTER // - FILE_MERGE(FEATURE_MAPPER.out.id_map.collect()) - ch_software_versions = ch_software_versions.mix(FILE_MERGE.out.versions) - - // - // SUBWORKFLOW: PROTEININFERENCE - // - PROTEIN_INFERENCE(FILE_MERGE.out.id_merge) - ch_software_versions = ch_software_versions.mix(PROTEIN_INFERENCE.out.versions) - - // - // SUBWORKFLOW: PROTEINQUANT - // - PROTEIN_QUANT(PROTEIN_INFERENCE.out.epi_idfilter, ch_expdesign) - ch_software_versions = ch_software_versions.mix(PROTEIN_QUANT.out.versions) - - // - // MODULE: MSSTATSTMT - // - ch_msstats_out = Channel.empty() - if(!params.skip_post_msstats){ - MSSTATS_TMT(PROTEIN_QUANT.out.msstats_csv) - ch_msstats_out = MSSTATS_TMT.out.msstats_csv - ch_software_versions = ch_software_versions.mix(MSSTATS_TMT.out.versions) - } + MSSTATS_CONVERTER(ISOBARIC_WORKFLOW.out.out_consensusXML, ch_expdesign, "ISO") + ch_software_versions = ch_software_versions.mix(MSSTATS_CONVERTER.out.versions) ID.out.psmrescoring_results .map { it -> it[1] } @@ -85,8 +72,7 @@ workflow TMT { emit: ch_pmultiqc_ids = ch_pmultiqc_ids ch_pmultiqc_consensus = ch_pmultiqc_consensus - final_result = PROTEIN_QUANT.out.out_mztab - msstats_in = PROTEIN_QUANT.out.msstats_csv - msstats_out = ch_msstats_out + final_result = ISOBARIC_WORKFLOW.out.out_mztab + msstats_in = MSSTATS_CONVERTER.out.out_msstats versions = ch_software_versions }
Process Name \\", - " \\ Software Version
CUSTOM_DUMPSOFTWAREVERSIONSpython3.13.1
yaml6.0.2
TOOL1tool10.11.9
TOOL2tool21.9
WorkflowNextflow