@@ -6,14 +6,16 @@ use ordered_float::OrderedFloat;
66
77use crate :: {
88 ParserResult ,
9- chemistry:: { Element , MolecularCharge , MolecularFormula } ,
10- helper_functions:: { self , * } ,
9+ chemistry:: { Chemical , Element , MolecularCharge , MolecularFormula } ,
10+ helper_functions:: * ,
1111 ontology:: Ontologies ,
12+ quantities:: { Tolerance , WithinTolerance } ,
1213 sequence:: {
1314 AmbiguousLookup , AmbiguousLookupEntry , AminoAcid , CheckedAminoAcid , CompoundPeptidoformIon ,
14- CrossLinkLookup , Linked , MUPSettings , Peptidoform , PeptidoformIon , PlacementRule , Position ,
15- SequenceElement , SequencePosition , SimpleModification , SimpleModificationInner ,
15+ CrossLinkLookup , Linked , MUPSettings , MassTag , Peptidoform , PeptidoformIon , PlacementRule ,
16+ Position , SequenceElement , SequencePosition , SimpleModification , SimpleModificationInner ,
1617 } ,
18+ system:: OrderedMass ,
1719} ;
1820
1921use super :: { GlobalModification , Linear , ReturnModification , SemiAmbiguous } ;
@@ -274,6 +276,79 @@ impl CompoundPeptidoformIon {
274276 start = tail;
275277 }
276278
279+ if STRICT {
280+ for p in peptidoforms. iter ( ) . flat_map ( |pi| & pi. peptidoforms ) {
281+ let mut ambiguous: Option < ( std:: num:: NonZero < u32 > , Vec < AminoAcid > ) > = None ;
282+ for s in p. sequence ( ) {
283+ // Check if (iso)leucine ambiguity is written in the correct way
284+ if let Some ( id) = s. ambiguous {
285+ ambiguous = match ambiguous {
286+ Some ( ( i, mut seq) ) if i == id => {
287+ seq. push ( s. aminoacid . aminoacid ( ) ) ;
288+ Some ( ( i, seq) )
289+ }
290+ prev => {
291+ if let Some ( ( _, seq) ) = prev
292+ && ( seq == vec ! [ AminoAcid :: Isoleucine ]
293+ || seq == vec ! [ AminoAcid :: Leucine ] )
294+ {
295+ combine_error (
296+ & mut errors,
297+ BoxedError :: new (
298+ BasicKind :: Warning ,
299+ "Improper ambiguous leucine" ,
300+ "The amino acid 'J' should be used to represent leucine/isoleucine ambiguity" ,
301+ base_context. clone ( ) ,
302+ ) ,
303+ ) ;
304+ }
305+ Some ( ( id, vec ! [ s. aminoacid. aminoacid( ) ] ) )
306+ }
307+ }
308+ }
309+ // Check if X is defined with a mod
310+ if s. aminoacid . aminoacid ( ) == AminoAcid :: Unknown && s. modifications . is_empty ( ) {
311+ combine_error (
312+ & mut errors,
313+ BoxedError :: new (
314+ BasicKind :: Warning ,
315+ "Improper unknown aminoacid" ,
316+ "The amino acid 'X' should always be followed by a modification to indicate the composition of this gap" ,
317+ base_context. clone ( ) ,
318+ ) ,
319+ ) ;
320+ }
321+ for m in & s. modifications {
322+ if let & SimpleModificationInner :: Mass ( tag, mass, precision) =
323+ m. get_simple ( ) . as_ref ( )
324+ {
325+ let tolerance: Tolerance < OrderedMass > = Tolerance :: Absolute (
326+ crate :: system:: Mass :: new :: < crate :: system:: dalton > (
327+ 10.0_f64 . powf ( -f64:: from ( precision. unwrap_or ( 6 ) ) ) / 2.0 ,
328+ )
329+ . into ( ) ,
330+ ) ;
331+ if let MassTag :: Ontology ( ontology) = tag
332+ && ontologies. data ( & [ ontology] ) . all ( |m| {
333+ !tolerance. within ( & mass, & m. formula ( ) . monoisotopic_mass ( ) )
334+ } )
335+ {
336+ combine_error (
337+ & mut errors,
338+ BoxedError :: new (
339+ BasicKind :: Warning ,
340+ "Improper prefixed mass modification" ,
341+ "A prefixed mass modification must use a modification that is defined in the referenced ontology" ,
342+ base_context. clone ( ) ,
343+ ) ,
344+ ) ;
345+ }
346+ }
347+ }
348+ }
349+ }
350+ }
351+
277352 if peptidoforms. is_empty ( ) {
278353 combine_error (
279354 & mut errors,
@@ -390,20 +465,8 @@ impl CompoundPeptidoformIon {
390465 }
391466 }
392467
393- if peptides. is_empty ( ) {
394- combine_error (
395- & mut errors,
396- BoxedError :: new (
397- BasicKind :: Error ,
398- "No peptide found" ,
399- "The peptidoform definition is empty" ,
400- base_context. clone ( ) . add_highlight ( ( 0 , range) ) ,
401- ) ,
402- ) ;
403- Err ( errors)
404- } else {
468+ if let Some ( last) = peptides. last ( ) {
405469 // Ensure that only one charge is set
406- let last = peptides. last ( ) . unwrap ( ) ;
407470 let c = last. get_charge_carriers ( ) . cloned ( ) ;
408471 let len = peptides. len ( ) - 1 ;
409472 for p in & mut peptides[ ..len] {
@@ -436,6 +499,17 @@ impl CompoundPeptidoformIon {
436499 } else {
437500 Ok ( ( ( peptidoform, index) , errors) )
438501 }
502+ } else {
503+ combine_error (
504+ & mut errors,
505+ BoxedError :: new (
506+ BasicKind :: Error ,
507+ "No peptide found" ,
508+ "The peptidoform definition is empty" ,
509+ base_context. clone ( ) . add_highlight ( ( 0 , range) ) ,
510+ ) ,
511+ ) ;
512+ Err ( errors)
439513 }
440514 }
441515
0 commit comments