diff --git a/tests/__pycache__/__init__.cpython-39.pyc b/tests/__pycache__/__init__.cpython-39.pyc deleted file mode 100644 index cc9a100..0000000 Binary files a/tests/__pycache__/__init__.cpython-39.pyc and /dev/null differ diff --git a/tests/__pycache__/conftest.cpython-39-pytest-8.4.2.pyc b/tests/__pycache__/conftest.cpython-39-pytest-8.4.2.pyc deleted file mode 100644 index 2c00381..0000000 Binary files a/tests/__pycache__/conftest.cpython-39-pytest-8.4.2.pyc and /dev/null differ diff --git a/tests/data/fastas/Q99536.fasta b/tests/data/fastas/Q99536.fasta new file mode 100644 index 0000000..400d2ae --- /dev/null +++ b/tests/data/fastas/Q99536.fasta @@ -0,0 +1,8 @@ +>sp|Q99536|VAT1_HUMAN Synaptic vesicle membrane protein VAT-1 homolog OS=Homo sapiens OX=9606 GN=VAT1 PE=1 SV=2 +MSDEREVAEAATGEDASSPPPKTEAASDPQHPAASEGAAAAAASPPLLRCLVLTGFGGYD +KVKLQSRPAAPPAPGPGQLTLRLRACGLNFADLMARQGLYDRLPPLPVTPGMEGAGVVIA +VGEGVSDRKAGDRVMVLNRSGMWQEEVTVPSVQTFLIPEAMTFEEAAALLVNYITAYMVL +FDFGNLQPGHSVLVHMAAGGVGMAAVQLCRTVENVTVFGTASASKHEALKENGVTHPIDY +HTTDYVDEIKKISPKGVDIVMDPLGGSDTAKGYNLLKPMGKVVTYGMANLLTGPKRNLMA +LARTWWNQFSVTALQLLQANRAVCGFHLGYLDGEVELVSGVVARLLALYNQGHIKPHIDS +VWPFEKVADAMKQMQEKKNVGKVLLVPGPEKEN diff --git a/tests/data/mzml/LQSRPAAPPAPGPGQLTLR.mzML b/tests/data/mzml/LQSRPAAPPAPGPGQLTLR.mzML new file mode 100644 index 0000000..3dfb847 --- /dev/null +++ b/tests/data/mzml/LQSRPAAPPAPGPGQLTLR.mzML @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + + + + diff --git a/tests/data/sage_params/sage_config.json b/tests/data/sage_params/sage_config.json new file mode 100644 index 0000000..a875eae --- /dev/null +++ b/tests/data/sage_params/sage_config.json @@ -0,0 +1,42 @@ +{ + "database": { + "bucket_size": 16384, + "fragment_min_mz": 150.0, + "fragment_max_mz": 1500.0, + "enzyme": { + "missed_cleavages": 1, + "cleave_at": "KR", + "restrict": "P" + }, + "static_mods": { + "C": 57.0216 + }, + "decoy_tag": "rev_", + "generate_decoys": true, + "fasta": "tests/data/fastas/Q99536.fasta" + }, + "deisotope": true, + "chimera": false, + "max_fragment_charge": 1, + "report_psms": 1, + "precursor_tol": { + "ppm": [ + -50, + 50 + ] + }, + "fragment_tol": { + "ppm": [ + -10, + 10 + ] + }, + "isotope_errors": [ + -1, + 3 + ], + "mzml_paths": [ + "tests/data/mzml/LQSRPAAPPAPGPGQLTLR.mzML" + ], + "score_type": "SageHyperScore" +} \ No newline at end of file diff --git a/tests/integrationtests/wrappers/__pycache__/test_thermorawfileparser.cpython-39-pytest-8.4.2.pyc b/tests/integrationtests/wrappers/__pycache__/test_thermorawfileparser.cpython-39-pytest-8.4.2.pyc deleted file mode 100644 index 59b1eea..0000000 Binary files a/tests/integrationtests/wrappers/__pycache__/test_thermorawfileparser.cpython-39-pytest-8.4.2.pyc and /dev/null differ diff --git a/tests/integrationtests/wrappers/test_sage.py b/tests/integrationtests/wrappers/test_sage.py new file mode 100644 index 0000000..ec02286 --- /dev/null +++ b/tests/integrationtests/wrappers/test_sage.py @@ -0,0 +1,32 @@ +"""Integration test for Sage.""" +import pandas as pd +from pathlib import Path +import urgap + +import pytest + + +def test_searchdb_sage(tmp_path: Path) -> None: + params = urgap.UFile(uri=f"file:///{urgap._test_folder}/data/sage_params?uftype={urgap.uftypes.proteomics.params.SAGE_JSON}#sage_config.json") + mzml = urgap.UFile(uri=f"file:///{urgap._test_folder}/data/mzml?uftype={urgap.uftypes.ms.converter.mzml.THERMORAWPARSER_MZML}#LQSRPAAPPAPGPGQLTLR.mzML") + urd = urgap.URunDict( + { + "parameters": {"Sage:0.14.7": { + }, + }, + "unode_parameters": { + "storage_base_uri": f"file://{tmp_path}", + }, + }, + ) + search_node = urgap.init_node("Sage:0.14.7") + search_result = search_node.run([params, mzml], urd) + assert search_result[0].path.exists() is True + + # check that output is not empty + df = pd.read_csv(search_result[0].path, delimiter="\t") + assert df.shape[0] == 1 + + search_node.remove_output_folder(output_file=search_result[0]) + + diff --git a/urgap/resources/Sage/0_14_7/LICENSE b/urgap/resources/Sage/0_14_7/LICENSE new file mode 100644 index 0000000..4a959cf --- /dev/null +++ b/urgap/resources/Sage/0_14_7/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Michael Lazear + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/urgap/resources/Sage/0_14_7/README.md b/urgap/resources/Sage/0_14_7/README.md new file mode 100644 index 0000000..ea98cdf --- /dev/null +++ b/urgap/resources/Sage/0_14_7/README.md @@ -0,0 +1,67 @@ + + +# Sage: proteomics searching so fast it seems like magic + +[![Rust](https://github.com/lazear/sage/actions/workflows/rust.yml/badge.svg)](https://github.com/lazear/sage/actions/workflows/rust.yml) [![Anaconda-Server Badge](https://anaconda.org/bioconda/sage-proteomics/badges/version.svg)](https://anaconda.org/bioconda/sage-proteomics) + + +For more information please read [the online documentation!](https://sage-docs.vercel.app/docs) + + +# Introduction + +Sage is, at it's core, a proteomics database search engine - + a tool that transforms raw mass spectra from proteomics experiments into peptide identifications + via database searching & spectral matching. + +However, Sage includes a variety of advanced features that make it a one-stop shop: retention time prediction, quantification (both isobaric & LFQ), peptide-spectrum match rescoring, and FDR control. You can directly use results from Sage without needing to use other tools for these tasks. + +Additionally, Sage was designed with cloud computing in mind - massively parallel processing and the ability to directly stream compressed mass spectrometry data to/from AWS S3 enables unprecedented search speeds with minimal cost. + + Sage also runs just as well reading local files from your Mac/PC/Linux device! + +## Why use Sage instead of other tools? + +Sage is **simple to configure**, **powerful** and **flexible**. +It also happens to be well-tested, **mind-boggingly fast**, open-source (MIT-licensed) and free. + +## Citation + +If you use Sage in a scientific publication, please cite the following paper: + +[Sage: An Open-Source Tool for Fast Proteomics Searching and Quantification at Scale](https://doi.org/10.1021/acs.jproteome.3c00486) + + +## Features + +- Incredible performance out of the box +- [Effortlessly cross-platform](https://sage-docs.vercel.app/docs/started#download-the-latest-binary-release) (Linux/MacOS/Windows), effortlessly parallel (uses all of your CPU cores) +- [Fragment indexing strategy](https://sage-docs.vercel.app/docs/how_it_works) allows for blazing fast narrow and open searches (> 500 Da precursor tolerance) +- [Isobaric quantification](https://sage-docs.vercel.app/docs/how_it_works#tmt-based) (MS2/MS3-TMT, or custom reporter ions) +- [Label-free quantification](https://sage-docs.vercel.app/docs/how_it_works#label-free): consider all charge states & isotopologues *a la* FlashLFQ +- Capable of searching for [chimeric/co-fragmenting spectra](https://sage-docs.vercel.app/docs/configuration/additional) +- Wide-window (dynamic precursor tolerance) search mode - [enables WWA/PRM/DIA searches](https://sage-docs.vercel.app/docs/configuration/tolerance#wide-window-mode) +- Retention time prediction models fit to each LC/MS run +- [PSM rescoring](https://sage-docs.vercel.app/docs/how_it_works#machine-learning-for-psm-rescoring) using built-in linear discriminant analysis (LDA) +- PEP calculation using a non-parametric model (KDE) +- FDR calculation using target-decoy competition and picked-peptide & picked-protein approaches +- Percolator/Mokapot [compatible output](https://sage-docs.vercel.app/docs/configuration#env) +- Configuration by [JSON file](https://sage-docs.vercel.app/docs/configuration#file) +- Built-in support for reading gzipped-mzML files +- Support for reading/writing directly from [AWS S3](https://sage-docs.vercel.app/docs/configuration/aws) + +## Interoperability + +Sage is well-integrated into the open-source proteomics ecosystem. The following projects support analyzing results from Sage (typically in addition to other tools), or redistribute Sage binaries for use in their pipelines. + +- [SearchGUI](http://compomics.github.io/projects/searchgui): a graphical user interface for running searches +- [PeptideShaker](http://compomics.github.io/projects/peptide-shaker): visualize peptide-spectrum matches +- [MS2Rescore](http://compomics.github.io/projects/ms2rescore): AI-assisted rescoring of results +- [Picked group FDR](https://github.com/kusterlab/picked_group_fdr): scalable protein group FDR for large-scale experiments +- [sagepy](https://github.com/theGreatHerrLebert/sagepy): Python bindings to the sage-core library +- [quantms](https://github.com/bigbio/quantms): nextflow pipeline for running searches with Sage +- [OpenMS](https://github.com/OpenMS/OpenMS): Sage is included as a "TOPP" tool in OpenMS +- [sager](https://github.com/UCLouvain-CBIO/sager): R package for analyzing results from Sage searches +- If your project supports Sage and it's not listed, please open a pull request! If you need help integrating or interfacing with Sage in some way, please reach out. + +Check out the (now outdated) [blog post introducing the first version of Sage](https://lazear.github.io/sage/) for more information and full benchmarks! diff --git a/urgap/resources/Sage/0_14_7/sage b/urgap/resources/Sage/0_14_7/sage new file mode 100644 index 0000000..3983a33 Binary files /dev/null and b/urgap/resources/Sage/0_14_7/sage differ diff --git a/urgap/resources/Sage/__init__.py b/urgap/resources/Sage/__init__.py new file mode 100644 index 0000000..26a84ea --- /dev/null +++ b/urgap/resources/Sage/__init__.py @@ -0,0 +1 @@ +"""Init Sage resources.""" diff --git a/urgap/uftypes/ms.py b/urgap/uftypes/ms.py index a197c74..cdc4982 100644 --- a/urgap/uftypes/ms.py +++ b/urgap/uftypes/ms.py @@ -29,5 +29,5 @@ ms.converter.ANY = "ms.converter.ANY" ms.converter.mzml = types.SimpleNamespace() ms.converter.mzml.ANY = "ms.converter.mzml.ANY" -ms.converter.mzml.THERMORAWPARSER_MZML = ".thermorawparser.mzML" +ms.converter.mzml.THERMORAWPARSER_MZML = ".thermorawparser.mzml" ms.converter.mzml.PYMZML_IDXGZ = ".pymzml_idx.gz" diff --git a/urgap/uftypes/proteomics.py b/urgap/uftypes/proteomics.py index 8bb8a1e..164f423 100644 --- a/urgap/uftypes/proteomics.py +++ b/urgap/uftypes/proteomics.py @@ -8,18 +8,21 @@ proteomics.MODS_XML = ".mods.xml" proteomics.TMT_CORRECTION_FACTORS = ".tmt_correction_factors.json" + proteomics.dbsearch = types.SimpleNamespace() proteomics.dbsearch.ANY = "proteomics.dbsearch.ANY" proteomics.dbsearch.COMET_MZID = ".comet.mzid" proteomics.dbsearch.MASCOT_DAT = ".mascot.dat" proteomics.dbsearch.MSAMANDA_CSV = ".msamanda.csv" proteomics.dbsearch.MSFRAGGER_TSV = ".msfragger.tsv" -proteomics.dbsearch.MSFRAGGER_PARAMS = ".msfragger.params" proteomics.dbsearch.MSGFPLUS_MZID = ".msgfplus.mzid" proteomics.dbsearch.OMSSA_CSV = ".omssa.csv" proteomics.dbsearch.XTANDEM_XML = ".xtandem.xml" proteomics.dbsearch.DIANN_QUANT = ".diann.quant" proteomics.dbsearch.DIANN_REPORT = ".diann_report.tsv" +proteomics.dbsearch.SAGE_TSV = ".sage_report.tsv" +proteomics.dbsearch.SAGE_JSON = ".sage_report.json" + proteomics.diannlibrary = types.SimpleNamespace() proteomics.diannlibrary.ANY = "proteomics.diannlibrary.ANY" @@ -61,3 +64,8 @@ proteomics.qc = types.SimpleNamespace() proteomics.qc.ANY = "proteomics.qc.ANY" proteomics.qc.OFFSET_CSV = ".offset.csv" + +proteomics.params = types.SimpleNamespace() +proteomics.params.ANY = ".msgfplus.params.ANY" +proteomics.params.MSGFPLUS_TXT = ".msgfplus_params.txt" +proteomics.params.SAGE_JSON = ".sage.json" \ No newline at end of file diff --git a/urgap/unodes/sage/__init__.py b/urgap/unodes/sage/__init__.py new file mode 100644 index 0000000..342ab8f --- /dev/null +++ b/urgap/unodes/sage/__init__.py @@ -0,0 +1 @@ +"""Init Sage Unode.""" diff --git a/urgap/unodes/sage/sage.py b/urgap/unodes/sage/sage.py new file mode 100644 index 0000000..6bd6bcd --- /dev/null +++ b/urgap/unodes/sage/sage.py @@ -0,0 +1,119 @@ +"""Urgap sage wrapper.""" + + +import json + +import urgap + + +class Sage(urgap.unode.UNodeBase): + """Sage wrapper for the Sage search engine. + + Sage is a proteomics database search engine - a tool that transforms raw mass spectra from + proteomics experiments into peptide identifications via database searching & spectral matching. + """ + + META_INFO = { + "name": "Sage", + "wrapper_version": {"major": 1, "minor": 0, "patch": 0}, + "versions": [ + {"version": "0.14.7", "exe_path": "Sage/0_14_7/sage"}, + ], + "parameters_not_triggering_rerun": [], + "input_uftypes": { + urgap.uftypes.ms.converter.mzml.THERMORAWPARSER_MZML: {"min": 0, "max": -1}, + urgap.uftypes.proteomics.params.SAGE_JSON: {"min": 1, "max": 1}, + urgap.uftypes.proteomics.FASTA: {"min": 0, "max": 1}, + }, + "output_uftypes": { + urgap.uftypes.proteomics.dbsearch.SAGE_TSV: {"min": 1, "max": 1}, + urgap.uftypes.proteomics.params.SAGE_JSON: {"min": 0, "max": 1}, + + }, + "engine": None, + "engine_type": ("identification",), + "citation": """Lazear, M. R. (2023). Sage: An open-source tool for fast proteomics searching and quantification at scale. Journal of Proteome Research, 22(11), 3652-3659. https://doi.org/10.1021/acs.jproteome.3c00486""", + } + + def __init__(self, *args: object, **kwargs: object) -> None: + """Initialize Sage class.""" + super().__init__(*args, **kwargs) + + def preflight(self, utrace: urgap.UTrace) -> urgap.UTrace: + """Preflight routine for Sage wrapper. + + During preflight, + - parameters are formatted + - mods are mapped and formatted + - param file is written + + Args: + utrace: Combination of urun_dict, ufile_list and unode.meta. + + Returns: + UTrace object, combination of urun_dict, ufile_list and unode.meta. + + Raises: + ValueError: If both a parameter file and command-line parameters + in the urun_dict are provided. Please provide only one. + """ + params_dict = utrace.urun_dict.parameters[ + f"{self.META_INFO['name']}:{self.META_INFO['versions'][0]['version']}" + ] + + param_files = utrace.input_files.get_path_objects_by_uftype( + urgap.uftypes.proteomics.params.SAGE_JSON, + ) + param_file_provided = len(param_files) == 1 + cmdline_json_provided = "-json" in params_dict + + + if param_file_provided: + param_json_path = param_files[0] + elif cmdline_json_provided: + param_json_path = params_dict["-json"] + + + mzml_file = utrace.input_files.get_path_objects_by_uftype( + urgap.uftypes.ms.converter.mzml.THERMORAWPARSER_MZML, + )[0] + + config_dict = json.loads(param_json_path.read_text()) + config_dict["output_directory"] = str(mzml_file.parent) + + config_path = param_json_path.parent / "sage_config.json" + config_path.write_text(json.dumps(config_dict)) + utrace.urun_dict.command_list = [ + str(self.exe_path), + str(config_path), + + ] + return utrace + + + + def postflight(self, utrace: urgap.UTrace) -> urgap.UTrace: + """Postflight routine for Sage wrapper. + + During postflight the Sage native .tsv output file is converted into the + pre-defined urgap output file, which is of csv format. + + Args: + utrace: Combination of urun_dict, ufile_list and unode.meta. + + Returns: + UTrace object, combination of urun_dict, ufile_list and unode.meta. + """ + full_path = utrace.input_files.get_path_objects_by_uftype( + urgap.uftypes.ms.converter.mzml.THERMORAWPARSER_MZML, + )[0] + sage_tsv = full_path.parent / "results.sage.tsv" + self.tmp_files.append(sage_tsv) + + with ( + sage_tsv.open() as fin, + utrace.output_files[0].path.open("w") as fout, + ): + for line in fin: + fout.write(line) + return utrace