rustyms/identification/
peaks.rs

1use std::path::{Path, PathBuf};
2
3use crate::{
4    error::CustomError,
5    identification::PeaksFamilyId,
6    ontologies::CustomDatabase,
7    peptidoform::{SemiAmbiguous, SloppyParsingParameters},
8    system::{usize::Charge, Mass, MassOverCharge, Time},
9    Peptidoform,
10};
11use itertools::Itertools;
12use serde::{Deserialize, Serialize};
13
14use super::{
15    common_parser::{Location, OptionalColumn, OptionalLocation},
16    csv::{parse_csv, CsvLine},
17    fasta::FastaIdentifier,
18    modification::SimpleModification,
19    peptidoform::PeptideModificationSearch,
20    BoxedIdentifiedPeptideIter, IdentifiedPeptide, IdentifiedPeptideSource, MetaData, Modification,
21};
22
23static NUMBER_ERROR: (&str, &str) = (
24    "Invalid Peaks line",
25    "This column is not a number but it is required to be a number in this peaks format",
26);
27static ID_ERROR: (&str, &str) =  (
28    "Invalid Peaks line",
29    "This column is not a valid peaks ID but it is required to be in this peaks format\nExamples of valid IDs: '1234', 'F2:1234', 'F2:1234 12345'"
30);
31
32format_family!(
33    /// The format for any Peaks file
34    PeaksFormat,
35    /// The data from any peaks file
36    PeaksData,
37    PeaksVersion, [&V12, &V11, &V11_FEATURES, &XPLUS, &AB, &X_PATCHED, &X, &DB_PEPTIDE, &DB_PSM, &DB_PROTEIN_PEPTIDE], b',', None;
38    required {
39        peptide: (Option<crate::AminoAcid>, Vec<Peptidoform<SemiAmbiguous>>, Option<crate::AminoAcid>), |location: Location, custom_database: Option<&CustomDatabase>| {
40            let n_flanking: Option<crate::AminoAcid> =
41                (location.as_str().chars().nth(1) == Some('.'))
42                .then(|| location.as_str().chars().next().unwrap().try_into().map_err(|()|
43                    CustomError::error(
44                        "Invalid amino acid",
45                        "This flanking residue is not a valid amino acid",
46                        crate::error::Context::line(Some(location.line.line_index()), location.full_line(), location.location.start, 1)))).transpose()?;
47
48            let c_flanking: Option<crate::AminoAcid> =
49            (location.as_str().chars().nth_back(1) == Some('.'))
50            .then(|| location.as_str().chars().next_back().unwrap().try_into().map_err(|()|
51                    CustomError::error(
52                        "Invalid amino acid",
53                        "This flanking residue is not a valid amino acid",
54                        crate::error::Context::line(Some(location.line.line_index()), location.full_line(), location.location.end-1, location.location.end)))).transpose()?;
55            if c_flanking.is_none() && n_flanking.is_none() {
56                location.array(';').map(|l| Peptidoform::sloppy_pro_forma(
57                    l.full_line(),
58                    l.location.clone(),
59                    custom_database,
60                    &SloppyParsingParameters::default()
61                )).unique()
62                .collect::<Result<Vec<_>,_>>()
63                .map(|sequences| (n_flanking, sequences, c_flanking))
64            } else {
65            Peptidoform::sloppy_pro_forma(
66                location.full_line(),
67                n_flanking.map_or(location.location.start, |_| location.location.start+2)..c_flanking.map_or(location.location.end, |_| location.location.end-2),
68                custom_database,
69                &SloppyParsingParameters::default()
70            ).map(|p| (n_flanking, vec![p], c_flanking))
71        }};
72        mz: MassOverCharge, |location: Location, _| location.parse::<f64>(NUMBER_ERROR).map(MassOverCharge::new::<crate::system::mz>);
73        rt: Time, |location: Location, _| location.parse::<f64>(NUMBER_ERROR).map(Time::new::<crate::system::time::min>);
74        area: Option<f64>, |location: Location, _| location.or_empty().parse(NUMBER_ERROR);
75    }
76    optional {
77        mass: Mass, |location: Location, _| location.parse::<f64>(NUMBER_ERROR).map(Mass::new::<crate::system::dalton>);
78        ptm: Vec<SimpleModification>, |location: Location, custom_database: Option<&CustomDatabase>|
79            location.or_empty().array(';').map(|v| {
80                let v = v.trim();
81                Modification::sloppy_modification(v.full_line(), v.location.clone(), None, custom_database)
82            }).unique().collect::<Result<Vec<_>,_>>();
83        scan: Vec<PeaksFamilyId>, |location: Location, _| location.or_empty()
84                        .map_or(Ok(Vec::new()), |l| l.array(';').map(|v| v.parse(ID_ERROR)).collect::<Result<Vec<_>,_>>());
85        z: Charge, |location: Location, _| location.parse::<usize>(NUMBER_ERROR).map(Charge::new::<crate::system::e>);
86        alc: f64, |location: Location, _| location.parse::<f64>(NUMBER_ERROR);
87        local_confidence: Vec<f64>, |location: Location, _| location
88            .array(' ')
89            .map(|l| l.parse::<f64>(NUMBER_ERROR))
90            .collect::<Result<Vec<_>, _>>();
91        fraction: usize, |location: Location, _| location.parse(NUMBER_ERROR).map(Some);
92        raw_file: PathBuf, |location: Location, _| Ok(Some(Path::new(&location.get_string()).to_owned()));
93        feature: PeaksFamilyId, |location: Location, _| location.or_empty().parse(ID_ERROR);
94        de_novo_score: f64, |location: Location, _| location
95                .parse::<f64>(NUMBER_ERROR);
96        predicted_rt: Time, |location: Location, _| location.or_empty().parse::<f64>(NUMBER_ERROR).map(|o| o.map(Time::new::<crate::system::time::min>));
97        accession: String, |location: Location, _|  Ok(Some(location.get_string()));
98        tag: String, |location: Location, _| Ok(location.get_string());
99        mode: String, |location: Location, _| Ok(location.get_string());
100        logp: f64, |location: Location, _| location.parse::<f64>(NUMBER_ERROR);
101        area_tryp_ead: f64, |location: Location, _| location.or_empty().parse::<f64>(NUMBER_ERROR);
102        ascore: String, |location: Location, _| Ok(location.get_string());
103        found_by: String, |location: Location, _| Ok(location.get_string());
104        feature_tryp_cid: usize, |location: Location, _| location.parse(NUMBER_ERROR).map(Some);
105        feature_tryp_ead: usize, |location: Location, _| location.parse(NUMBER_ERROR).map(Some);
106        id: usize, |location: Location, _| location.parse(NUMBER_ERROR).map(Some);
107        from_chimera: bool, |location: Location, _| Ok(location.get_string().eq_ignore_ascii_case("yes"));
108        unique: bool, |location: Location, _| Ok(location.get_string() == "Y");
109        protein_group: usize, |location: Location, _| location.parse(NUMBER_ERROR).map(Some);
110        protein_id: usize, |location: Location, _| location.parse(NUMBER_ERROR).map(Some);
111        protein_accession: FastaIdentifier<String>, |location: Location, _|  location.parse(NUMBER_ERROR).map(Some);
112        start: usize, |location: Location, _| location.parse(NUMBER_ERROR).map(Some);
113        end: usize, |location: Location, _| location.parse(NUMBER_ERROR).map(Some);
114        quality: f64, |location: Location, _| location.parse::<f64>(NUMBER_ERROR);
115        rt_begin: Time, |location: Location, _| location.or_empty().parse::<f64>(NUMBER_ERROR).map(|o| o.map(Time::new::<crate::system::time::s>));
116        rt_end: Time, |location: Location, _| location.or_empty().parse::<f64>(NUMBER_ERROR).map(|o| o.map(Time::new::<crate::system::time::s>));
117        precursor_id: isize, |location: Location, _| location.parse::<isize>(NUMBER_ERROR);
118        k0_range: std::ops::RangeInclusive<f64>, |location: Location, _| location.split_once('-').map(|(start, end)| Ok(start.parse(NUMBER_ERROR)?..=end.parse(NUMBER_ERROR)?));
119    }
120
121    fn post_process(_source: &CsvLine, mut parsed: Self, _custom_database: Option<&CustomDatabase>) -> Result<Self, CustomError> {
122        // Add the meaningful modifications to replace mass modifications
123        if let Some(ptm) = parsed.ptm.clone() {
124            for pep in &mut parsed.peptide.1 {
125                *pep = PeptideModificationSearch::in_modifications(ptm.clone())
126                    .tolerance(super::Tolerance::Absolute(super::system::da(0.05)))
127                    .search(pep.clone());
128            }
129        }
130        Ok(parsed)
131    }
132);
133
134impl From<PeaksData> for IdentifiedPeptide {
135    fn from(value: PeaksData) -> Self {
136        Self {
137            score: value
138                .de_novo_score
139                .or(value.alc)
140                .map(|v| v / 100.0)
141                .or_else(|| {
142                    value
143                        .logp
144                        .map(|v| 2.0 * (1.0 / (1.0 + 1.025_f64.powf(-v)) - 0.5))
145                }),
146            local_confidence: value
147                .local_confidence
148                .as_ref()
149                .map(|lc| lc.iter().map(|v| *v / 100.0).collect()),
150            metadata: MetaData::Peaks(value),
151        }
152    }
153}
154
155/// An older version of a PEAKS export
156pub const X: PeaksFormat = PeaksFormat {
157    version: PeaksVersion::X,
158    scan: OptionalColumn::Required("scan"),
159    peptide: "peptide",
160    alc: OptionalColumn::Required("alc (%)"),
161    mz: "m/z",
162    z: OptionalColumn::Required("z"),
163    mass: OptionalColumn::Required("mass"),
164    rt: "rt",
165    area: "area",
166    ptm: OptionalColumn::Required("ptm"),
167    local_confidence: OptionalColumn::Required("local confidence (%)"),
168    tag: OptionalColumn::Required("tag (>=0%)"),
169    mode: OptionalColumn::Required("mode"),
170    fraction: OptionalColumn::NotAvailable,
171    raw_file: OptionalColumn::NotAvailable,
172    feature: OptionalColumn::NotAvailable,
173    de_novo_score: OptionalColumn::NotAvailable,
174    predicted_rt: OptionalColumn::NotAvailable,
175    accession: OptionalColumn::NotAvailable,
176    ascore: OptionalColumn::NotAvailable,
177    found_by: OptionalColumn::NotAvailable,
178    logp: OptionalColumn::NotAvailable,
179    feature_tryp_cid: OptionalColumn::NotAvailable,
180    feature_tryp_ead: OptionalColumn::NotAvailable,
181    area_tryp_ead: OptionalColumn::NotAvailable,
182    id: OptionalColumn::NotAvailable,
183    from_chimera: OptionalColumn::NotAvailable,
184    unique: OptionalColumn::NotAvailable,
185    protein_group: OptionalColumn::NotAvailable,
186    protein_id: OptionalColumn::NotAvailable,
187    protein_accession: OptionalColumn::NotAvailable,
188    start: OptionalColumn::NotAvailable,
189    end: OptionalColumn::NotAvailable,
190    quality: OptionalColumn::NotAvailable,
191    rt_begin: OptionalColumn::NotAvailable,
192    rt_end: OptionalColumn::NotAvailable,
193    precursor_id: OptionalColumn::NotAvailable,
194    k0_range: OptionalColumn::NotAvailable,
195};
196/// Version X of PEAKS export (made for build 31 January 2019)
197pub const X_PATCHED: PeaksFormat = PeaksFormat {
198    version: PeaksVersion::XPatched,
199    scan: OptionalColumn::Required("scan"),
200    peptide: "peptide",
201    alc: OptionalColumn::Required("alc (%)"),
202    mz: "m/z",
203    z: OptionalColumn::Required("z"),
204    mass: OptionalColumn::Required("mass"),
205    rt: "rt",
206    area: "area",
207    ptm: OptionalColumn::Required("ptm"),
208    local_confidence: OptionalColumn::Required("local confidence (%)"),
209    tag: OptionalColumn::Required("tag (>=0%)"),
210    mode: OptionalColumn::Required("mode"),
211    fraction: OptionalColumn::Required("fraction"),
212    raw_file: OptionalColumn::Required("source file"),
213    feature: OptionalColumn::Required("feature"),
214    de_novo_score: OptionalColumn::NotAvailable,
215    predicted_rt: OptionalColumn::NotAvailable,
216    accession: OptionalColumn::NotAvailable,
217    ascore: OptionalColumn::NotAvailable,
218    found_by: OptionalColumn::NotAvailable,
219    logp: OptionalColumn::NotAvailable,
220    feature_tryp_cid: OptionalColumn::NotAvailable,
221    feature_tryp_ead: OptionalColumn::NotAvailable,
222    area_tryp_ead: OptionalColumn::NotAvailable,
223    id: OptionalColumn::NotAvailable,
224    from_chimera: OptionalColumn::NotAvailable,
225    unique: OptionalColumn::NotAvailable,
226    protein_group: OptionalColumn::NotAvailable,
227    protein_id: OptionalColumn::NotAvailable,
228    protein_accession: OptionalColumn::NotAvailable,
229    start: OptionalColumn::NotAvailable,
230    end: OptionalColumn::NotAvailable,
231    quality: OptionalColumn::NotAvailable,
232    rt_begin: OptionalColumn::NotAvailable,
233    rt_end: OptionalColumn::NotAvailable,
234    precursor_id: OptionalColumn::NotAvailable,
235    k0_range: OptionalColumn::NotAvailable,
236};
237/// Version X+ of PEAKS export (made for build 20 November 2019)
238pub const XPLUS: PeaksFormat = PeaksFormat {
239    version: PeaksVersion::XPlus,
240    scan: OptionalColumn::Required("scan"),
241    peptide: "peptide",
242    alc: OptionalColumn::Required("alc (%)"),
243    mz: "m/z",
244    z: OptionalColumn::Required("z"),
245    mass: OptionalColumn::Required("mass"),
246    rt: "rt",
247    area: "area",
248    ptm: OptionalColumn::Required("ptm"),
249    local_confidence: OptionalColumn::Required("local confidence (%)"),
250    tag: OptionalColumn::Required("tag (>=0%)"),
251    mode: OptionalColumn::Required("mode"),
252    fraction: OptionalColumn::Required("fraction"),
253    raw_file: OptionalColumn::Required("source file"),
254    feature: OptionalColumn::Required("feature"),
255    de_novo_score: OptionalColumn::Required("denovo score"),
256    predicted_rt: OptionalColumn::Required("predict rt"),
257    accession: OptionalColumn::NotAvailable,
258    ascore: OptionalColumn::NotAvailable,
259    found_by: OptionalColumn::NotAvailable,
260    logp: OptionalColumn::NotAvailable,
261    feature_tryp_cid: OptionalColumn::NotAvailable,
262    feature_tryp_ead: OptionalColumn::NotAvailable,
263    area_tryp_ead: OptionalColumn::NotAvailable,
264    id: OptionalColumn::NotAvailable,
265    from_chimera: OptionalColumn::NotAvailable,
266    unique: OptionalColumn::NotAvailable,
267    protein_group: OptionalColumn::NotAvailable,
268    protein_id: OptionalColumn::NotAvailable,
269    protein_accession: OptionalColumn::NotAvailable,
270    start: OptionalColumn::NotAvailable,
271    end: OptionalColumn::NotAvailable,
272    quality: OptionalColumn::NotAvailable,
273    rt_begin: OptionalColumn::NotAvailable,
274    rt_end: OptionalColumn::NotAvailable,
275    precursor_id: OptionalColumn::NotAvailable,
276    k0_range: OptionalColumn::NotAvailable,
277};
278/// Version 11 of PEAKS export
279pub const V11: PeaksFormat = PeaksFormat {
280    version: PeaksVersion::V11,
281    scan: OptionalColumn::Required("scan"),
282    peptide: "peptide",
283    alc: OptionalColumn::Required("alc (%)"),
284    mz: "m/z",
285    z: OptionalColumn::Required("z"),
286    mass: OptionalColumn::Required("mass"),
287    rt: "rt",
288    area: "area",
289    ptm: OptionalColumn::Required("ptm"),
290    local_confidence: OptionalColumn::Required("local confidence (%)"),
291    tag: OptionalColumn::Required("tag(>=0.0%)"),
292    mode: OptionalColumn::Required("mode"),
293    fraction: OptionalColumn::NotAvailable,
294    raw_file: OptionalColumn::Required("source file"),
295    feature: OptionalColumn::Required("feature id"),
296    de_novo_score: OptionalColumn::NotAvailable,
297    predicted_rt: OptionalColumn::NotAvailable,
298    accession: OptionalColumn::NotAvailable,
299    ascore: OptionalColumn::NotAvailable,
300    found_by: OptionalColumn::NotAvailable,
301    logp: OptionalColumn::NotAvailable,
302    feature_tryp_cid: OptionalColumn::NotAvailable,
303    feature_tryp_ead: OptionalColumn::NotAvailable,
304    area_tryp_ead: OptionalColumn::NotAvailable,
305    id: OptionalColumn::NotAvailable,
306    from_chimera: OptionalColumn::NotAvailable,
307    unique: OptionalColumn::NotAvailable,
308    protein_group: OptionalColumn::NotAvailable,
309    protein_id: OptionalColumn::NotAvailable,
310    protein_accession: OptionalColumn::NotAvailable,
311    start: OptionalColumn::NotAvailable,
312    end: OptionalColumn::NotAvailable,
313    quality: OptionalColumn::NotAvailable,
314    rt_begin: OptionalColumn::NotAvailable,
315    rt_end: OptionalColumn::NotAvailable,
316    precursor_id: OptionalColumn::Optional("precursor id"),
317    k0_range: OptionalColumn::Optional("1/k0 range"),
318};
319/// Version 11 of PEAKS export
320pub const V11_FEATURES: PeaksFormat = PeaksFormat {
321    version: PeaksVersion::V11Features,
322    scan: OptionalColumn::NotAvailable,
323    peptide: "denovo peptide",
324    alc: OptionalColumn::Required("alc (%)"),
325    quality: OptionalColumn::Required("quality"),
326    mz: "m/z",
327    z: OptionalColumn::Required("z"),
328    mass: OptionalColumn::NotAvailable,
329    rt: "rt",
330    rt_begin: OptionalColumn::Required("rt begin"),
331    rt_end: OptionalColumn::Required("rt end"),
332    area: "area",
333    ptm: OptionalColumn::NotAvailable,
334    local_confidence: OptionalColumn::NotAvailable,
335    tag: OptionalColumn::NotAvailable,
336    mode: OptionalColumn::NotAvailable,
337    fraction: OptionalColumn::NotAvailable,
338    raw_file: OptionalColumn::Required("source file"),
339    feature: OptionalColumn::Required("feature id"),
340    de_novo_score: OptionalColumn::NotAvailable,
341    predicted_rt: OptionalColumn::NotAvailable,
342    accession: OptionalColumn::NotAvailable,
343    ascore: OptionalColumn::NotAvailable,
344    found_by: OptionalColumn::NotAvailable,
345    logp: OptionalColumn::NotAvailable,
346    feature_tryp_cid: OptionalColumn::NotAvailable,
347    feature_tryp_ead: OptionalColumn::NotAvailable,
348    area_tryp_ead: OptionalColumn::NotAvailable,
349    id: OptionalColumn::NotAvailable,
350    from_chimera: OptionalColumn::NotAvailable,
351    unique: OptionalColumn::NotAvailable,
352    protein_group: OptionalColumn::NotAvailable,
353    protein_id: OptionalColumn::NotAvailable,
354    protein_accession: OptionalColumn::NotAvailable,
355    start: OptionalColumn::NotAvailable,
356    end: OptionalColumn::NotAvailable,
357    precursor_id: OptionalColumn::NotAvailable,
358    k0_range: OptionalColumn::NotAvailable,
359};
360/// Version 12 of PEAKS export
361pub const V12: PeaksFormat = PeaksFormat {
362    version: PeaksVersion::V12,
363    scan: OptionalColumn::Required("scan"),
364    peptide: "peptide",
365    alc: OptionalColumn::Required("alc (%)"),
366    mz: "m/z",
367    z: OptionalColumn::Required("z"),
368    mass: OptionalColumn::Required("mass"),
369    rt: "rt",
370    area: "area",
371    ptm: OptionalColumn::Required("ptm"),
372    local_confidence: OptionalColumn::Required("local confidence (%)"),
373    tag: OptionalColumn::Required("tag(>=0%)"),
374    mode: OptionalColumn::Required("mode"),
375    fraction: OptionalColumn::NotAvailable,
376    raw_file: OptionalColumn::Required("source file"),
377    feature: OptionalColumn::Required("feature id"),
378    de_novo_score: OptionalColumn::Required("deep novo score (%)"),
379    predicted_rt: OptionalColumn::NotAvailable,
380    accession: OptionalColumn::NotAvailable,
381    ascore: OptionalColumn::NotAvailable,
382    found_by: OptionalColumn::NotAvailable,
383    logp: OptionalColumn::NotAvailable,
384    feature_tryp_cid: OptionalColumn::NotAvailable,
385    feature_tryp_ead: OptionalColumn::NotAvailable,
386    area_tryp_ead: OptionalColumn::NotAvailable,
387    id: OptionalColumn::NotAvailable,
388    from_chimera: OptionalColumn::NotAvailable,
389    unique: OptionalColumn::NotAvailable,
390    protein_group: OptionalColumn::NotAvailable,
391    protein_id: OptionalColumn::NotAvailable,
392    protein_accession: OptionalColumn::NotAvailable,
393    start: OptionalColumn::NotAvailable,
394    end: OptionalColumn::NotAvailable,
395    quality: OptionalColumn::NotAvailable,
396    rt_begin: OptionalColumn::NotAvailable,
397    rt_end: OptionalColumn::NotAvailable,
398    precursor_id: OptionalColumn::NotAvailable,
399    k0_range: OptionalColumn::NotAvailable,
400};
401/// Version Ab of PEAKS export
402pub const AB: PeaksFormat = PeaksFormat {
403    version: PeaksVersion::Ab,
404    scan: OptionalColumn::Required("scan"),
405    peptide: "peptide",
406    alc: OptionalColumn::Required("alc (%)"),
407    mz: "m/z",
408    z: OptionalColumn::Required("z"),
409    mass: OptionalColumn::Required("mass"),
410    rt: "rt",
411    area: "area",
412    ptm: OptionalColumn::Required("ptm"),
413    local_confidence: OptionalColumn::Required("local confidence (%)"),
414    tag: OptionalColumn::Required("tag (>=0%)"),
415    mode: OptionalColumn::Required("mode"),
416    fraction: OptionalColumn::NotAvailable,
417    raw_file: OptionalColumn::NotAvailable,
418    feature: OptionalColumn::NotAvailable,
419    de_novo_score: OptionalColumn::NotAvailable,
420    predicted_rt: OptionalColumn::NotAvailable,
421    accession: OptionalColumn::Required("accession"),
422    ascore: OptionalColumn::NotAvailable,
423    found_by: OptionalColumn::NotAvailable,
424    logp: OptionalColumn::NotAvailable,
425    feature_tryp_cid: OptionalColumn::NotAvailable,
426    feature_tryp_ead: OptionalColumn::NotAvailable,
427    area_tryp_ead: OptionalColumn::NotAvailable,
428    id: OptionalColumn::NotAvailable,
429    from_chimera: OptionalColumn::NotAvailable,
430    unique: OptionalColumn::NotAvailable,
431    protein_group: OptionalColumn::NotAvailable,
432    protein_id: OptionalColumn::NotAvailable,
433    protein_accession: OptionalColumn::NotAvailable,
434    start: OptionalColumn::NotAvailable,
435    end: OptionalColumn::NotAvailable,
436    quality: OptionalColumn::NotAvailable,
437    rt_begin: OptionalColumn::NotAvailable,
438    rt_end: OptionalColumn::NotAvailable,
439    precursor_id: OptionalColumn::NotAvailable,
440    k0_range: OptionalColumn::NotAvailable,
441};
442/// Version DB peptide of PEAKS export
443pub const DB_PEPTIDE: PeaksFormat = PeaksFormat {
444    version: PeaksVersion::DBPeptide,
445    scan: OptionalColumn::Required("scan"),
446    peptide: "peptide",
447    alc: OptionalColumn::NotAvailable,
448    mz: "m/z",
449    z: OptionalColumn::NotAvailable,
450    mass: OptionalColumn::Required("mass"),
451    rt: "rt",
452    area: "area tryp-cid",
453    ptm: OptionalColumn::Required("ptm"),
454    local_confidence: OptionalColumn::NotAvailable,
455    tag: OptionalColumn::NotAvailable,
456    mode: OptionalColumn::NotAvailable,
457    fraction: OptionalColumn::Required("fraction"),
458    raw_file: OptionalColumn::Required("source file"),
459    feature: OptionalColumn::Required("#feature"),
460    de_novo_score: OptionalColumn::NotAvailable,
461    predicted_rt: OptionalColumn::NotAvailable,
462    accession: OptionalColumn::Required("accession"),
463    ascore: OptionalColumn::Required("ascore"),
464    found_by: OptionalColumn::Required("found by"),
465    logp: OptionalColumn::Required("-10lgp"),
466    feature_tryp_cid: OptionalColumn::Required("#feature tryp-cid"),
467    feature_tryp_ead: OptionalColumn::Required("#feature tryp ead"),
468    area_tryp_ead: OptionalColumn::Required("area tryp ead"),
469    id: OptionalColumn::NotAvailable,
470    from_chimera: OptionalColumn::NotAvailable,
471    unique: OptionalColumn::NotAvailable,
472    protein_group: OptionalColumn::NotAvailable,
473    protein_id: OptionalColumn::NotAvailable,
474    protein_accession: OptionalColumn::NotAvailable,
475    start: OptionalColumn::NotAvailable,
476    end: OptionalColumn::NotAvailable,
477    quality: OptionalColumn::NotAvailable,
478    rt_begin: OptionalColumn::NotAvailable,
479    rt_end: OptionalColumn::NotAvailable,
480    precursor_id: OptionalColumn::NotAvailable,
481    k0_range: OptionalColumn::NotAvailable,
482};
483/// Version DB psm of PEAKS export
484pub const DB_PSM: PeaksFormat = PeaksFormat {
485    version: PeaksVersion::DBPSM,
486    scan: OptionalColumn::Required("scan"),
487    peptide: "peptide",
488    alc: OptionalColumn::NotAvailable,
489    mz: "m/z",
490    z: OptionalColumn::Required("z"),
491    mass: OptionalColumn::Required("mass"),
492    rt: "rt",
493    area: "area",
494    ptm: OptionalColumn::Required("ptm"),
495    local_confidence: OptionalColumn::NotAvailable,
496    tag: OptionalColumn::NotAvailable,
497    mode: OptionalColumn::NotAvailable,
498    fraction: OptionalColumn::Required("fraction"),
499    raw_file: OptionalColumn::Required("source file"),
500    feature: OptionalColumn::NotAvailable,
501    de_novo_score: OptionalColumn::NotAvailable,
502    predicted_rt: OptionalColumn::NotAvailable,
503    accession: OptionalColumn::Required("accession"),
504    ascore: OptionalColumn::Required("ascore"),
505    found_by: OptionalColumn::Required("found by"),
506    logp: OptionalColumn::Required("-10lgp"),
507    feature_tryp_cid: OptionalColumn::NotAvailable,
508    feature_tryp_ead: OptionalColumn::NotAvailable,
509    area_tryp_ead: OptionalColumn::NotAvailable,
510    id: OptionalColumn::Required("id"),
511    from_chimera: OptionalColumn::Required("from chimera"),
512    unique: OptionalColumn::NotAvailable,
513    protein_group: OptionalColumn::NotAvailable,
514    protein_id: OptionalColumn::NotAvailable,
515    protein_accession: OptionalColumn::NotAvailable,
516    start: OptionalColumn::NotAvailable,
517    end: OptionalColumn::NotAvailable,
518    quality: OptionalColumn::NotAvailable,
519    rt_begin: OptionalColumn::NotAvailable,
520    rt_end: OptionalColumn::NotAvailable,
521    precursor_id: OptionalColumn::NotAvailable,
522    k0_range: OptionalColumn::NotAvailable,
523};
524/// Version DB protein peptide of PEAKS export
525/// protein group, protein id, protein accession, unique, start, end,
526pub const DB_PROTEIN_PEPTIDE: PeaksFormat = PeaksFormat {
527    version: PeaksVersion::DBProteinPeptide,
528    scan: OptionalColumn::Required("scan"),
529    peptide: "peptide",
530    alc: OptionalColumn::NotAvailable,
531    mz: "m/z",
532    z: OptionalColumn::Required("z"),
533    mass: OptionalColumn::Required("mass"),
534    rt: "rt",
535    area: "area tryp-cid",
536    ptm: OptionalColumn::Required("ptm"),
537    local_confidence: OptionalColumn::NotAvailable,
538    tag: OptionalColumn::NotAvailable,
539    mode: OptionalColumn::NotAvailable,
540    fraction: OptionalColumn::Required("fraction"),
541    raw_file: OptionalColumn::Required("source file"),
542    feature: OptionalColumn::NotAvailable,
543    de_novo_score: OptionalColumn::NotAvailable,
544    predicted_rt: OptionalColumn::NotAvailable,
545    accession: OptionalColumn::NotAvailable,
546    ascore: OptionalColumn::Required("ascore"),
547    found_by: OptionalColumn::Required("found by"),
548    logp: OptionalColumn::Required("-10lgp"),
549    feature_tryp_cid: OptionalColumn::Required("#feature tryp-cid"),
550    feature_tryp_ead: OptionalColumn::Required("#feature tryp ead"),
551    area_tryp_ead: OptionalColumn::Required("area tryp ead"),
552    id: OptionalColumn::NotAvailable,
553    from_chimera: OptionalColumn::NotAvailable,
554    unique: OptionalColumn::Required("unique"),
555    protein_group: OptionalColumn::Required("protein group"),
556    protein_id: OptionalColumn::Required("protein id"),
557    protein_accession: OptionalColumn::Required("protein accession"),
558    start: OptionalColumn::Required("start"),
559    end: OptionalColumn::Required("end"),
560    quality: OptionalColumn::NotAvailable,
561    rt_begin: OptionalColumn::NotAvailable,
562    rt_end: OptionalColumn::NotAvailable,
563    precursor_id: OptionalColumn::NotAvailable,
564    k0_range: OptionalColumn::NotAvailable,
565};
566
567/// All possible peaks versions
568#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, Serialize, Deserialize)]
569#[allow(clippy::upper_case_acronyms)]
570pub enum PeaksVersion {
571    /// An older version of a PEAKS export
572    X,
573    /// Version X of PEAKS export (made for build 31 January 2019)
574    XPatched,
575    /// Version X+ of PEAKS export (made for build 20 November 2019)
576    XPlus,
577    /// Version DB peptide of PEAKS export
578    DBPeptide,
579    /// Version DB PSM of PEAKS export
580    DBPSM,
581    /// Version DB Protein Peptide of PEAKS export
582    DBProteinPeptide,
583    /// Version Ab of PEAKS export
584    Ab,
585    /// Version 11 denovo file
586    V11,
587    /// Version 11 features file
588    V11Features,
589    /// Version 12
590    #[default]
591    V12,
592}
593
594impl std::fmt::Display for PeaksVersion {
595    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
596        write!(
597            f,
598            "{}",
599            match self {
600                Self::X => "X",
601                Self::XPatched => "X patched",
602                Self::XPlus => "X+",
603                Self::DBPeptide => "DB peptide",
604                Self::DBPSM => "DB PSM",
605                Self::DBProteinPeptide => "DB protein peptide",
606                Self::Ab => "Ab",
607                Self::V11 => "11",
608                Self::V11Features => "11 features",
609                Self::V12 => "12",
610            }
611        )
612    }
613}