Header menu logo BioFSharp.Mz

BinderScriptNotebook

Andromeda-like and X!Tandem-like scoring

The SEQUEST-like scoring page turned the agreement between a predicted and a measured spectrum into a dot product of intensity vectors. The scorers on this page, AndromedaLike and XScoring, ask a probability question. Given that a candidate predicts n fragment peaks inside the measured range and k of them coincide with a measured peak, how surprising is that under random matching? The answer is a cumulative binomial probability, the chance of seeing at least k hits among n tries when each try succeeds with a fixed background probability. The score reports that probability as a -10 log10 value, so a higher score means the match is less likely to be chance. This is the scoring idea of Andromeda, the search engine behind MaxQuant, and the same matching machinery also yields an X!Tandem-style hyperscore.

Intensity enters through which measured peaks are allowed to match at all, an idea called peak depth. ratedSpectrum rates every measured peak by counting how many more intense peaks lie within a 100 Da window centered on it. At depth q, only peaks that rank among the q most intense within their own window are offered to the matcher, and q also sets the background probability of a random hit to q/100 (capped at 0.5 in the implementation), one window of width 100 Da holding q acceptable peaks. countMatches tallies n and k for every depth of a user-given range in a single pass over the predictions. scoreFuncImpl then turns each (n, k, q) triple into a score, and the best score across the depths is kept. The trade-off behind the range: a small q admits only the strongest peaks, so a random match is improbable, but genuine fragments of modest intensity are missed. A large q admits more real fragments along with more noise. Evaluating a range of depths lets every candidate be scored at the depth that suits the spectrum best.

Loading the measured spectrum

The measured side is the running example of these pages, the MS2 scan of the doubly charged peptide ANLGMEVMHER from ms2Example.mgf with its precursor at m/z 643.803548. The scorer locates matching peaks with a binary search, so the measured spectrum must be sorted ascending by m/z, which this scan is.

open BioFSharp
open BioFSharp.FileFormats.MGF
open BioFSharp.IO
open BioFSharp.Mz

let ms2 =
    MGF.read (__SOURCE_DIRECTORY__ + "/data/ms2Example.mgf")
    |> List.head

let precursorMZ =
    match MGFEntry.tryGetPrecursorMZ ms2 with
    | Some mz -> mz
    | None -> failwith "no precursor m/z in the MS2 header"

let spectrum : PeakArray<Peak> = PeakArray.zip ms2.Mass ms2.Intensity

printfn "peaks: %i covering m/z %.2f to %.2f"
    spectrum.Length spectrum.[0].Mz spectrum.[spectrum.Length - 1].Mz
peaks: 971 covering m/z 100.67 to 1337.63

Rebuilding the candidate list

The candidates are the same four isobaric sequences the SEQUEST-like page built and discussed in detail. All four weigh 1285.5907 Da, so a mass window query cannot tell them apart.

let mono : IBioItem -> float = BioItem.monoisoMass

let neutralMass (peptide: AminoAcids.AminoAcid list) =
    (peptide |> List.sumBy mono) + mono ModificationInfo.Table.H2O

// Stand-ins for what a search database mass window query would return;
// built by hand to keep the page self-contained.
let candidate modSeqId pepSeqId (sequence: string) =
    let bioSequence = BioList.ofAminoAcidString sequence
    let mass = neutralMass bioSequence
    let roundedMass = int64 (System.Math.Round(mass * 1000000.))
    SearchDB.createLookUpResult modSeqId pepSeqId mass roundedMass sequence bioSequence 0

let candidates =
    [ candidate 1 1 "ANLGMEVMHER"   // the peptide the scan was recorded from
      candidate 2 2 "MANGLEVMHER"   // permutation, same mass
      candidate 3 3 "EVMANLGMHER"   // permutation, same mass
      candidate 4 4 "AGGLGMEVMHER"  // Asn replaced by Gly-Gly, also isobaric
    ]

printfn "%s" (candidates |> List.map (fun c -> c.StringSequence) |> String.concat ", ")
ANLGMEVMHER, MANGLEVMHER, EVMANLGMHER, AGGLGMEVMHER

Predicting tagged fragment spectra

The fragment masses per candidate come from Fragmentation.Series.fragmentMasses with the b and y series, exactly as on the SEQUEST-like page. AndromedaLike.getTheoSpecs then converts every pair into a TheoreticalSpectrum whose target and decoy sides are arrays of PeakFamily<TaggedPeak>, predicted m/z values that keep their ion series tags. The prediction model of this scorer family: a singly charged precursor gets singly charged predicted fragments only, and a precursor of charge two or more gets every fragment as a singly and a doubly charged predicted peak (higher fragment charges are not emitted). The neutral-loss dependents ride on the singly charged copies. The peaks carry no predicted intensities, matching needs only the m/z and the tag. Restricting the comparison to the scan limits happens in the matching step, which skips predicted peaks outside the range.

let scanlimits = 100., 1300.

let fragmentPairs =
    candidates
    |> List.map (fun c ->
        let fragments =
            Fragmentation.Series.fragmentMasses
                Fragmentation.Series.bOfBioList
                Fragmentation.Series.yOfBioList
                mono
                c.BioSequence
        c, fragments)

let theoSpecs = AndromedaLike.getTheoSpecs scanlimits 2 fragmentPairs

theoSpecs
|> List.iter (fun ts ->
    let withLosses =
        ts.TheoSpec
        |> Array.filter (fun f -> not f.DependentPeaks.IsEmpty)
        |> Array.length
    printfn "%-13s peak families: %i  with loss dependents: %i"
        ts.LookUpResult.StringSequence ts.TheoSpec.Length withLosses)
AGGLGMEVMHER  peak families: 48  with loss dependents: 18
EVMANLGMHER   peak families: 44  with loss dependents: 22
MANGLEVMHER   peak families: 44  with loss dependents: 20
ANLGMEVMHER   peak families: 44  with loss dependents: 21

The 22 b and y fragments of an 11 residue candidate become 44 peak families, one per charge state, and the extra residue of the Gly-Gly variant adds two more fragments and four more families. The families that carry loss dependents are the singly charged copies of fragments containing loss-prone residues.

Scoring at increasing peak depths

AndromedaLike.calcAndromedaScore takes the depth range, the scan limits, the matching tolerance in ppm of the fragment m/z, the measured spectrum, the scan time, the precursor charge and isolation window target m/z, the theoretical spectra and a spectrum identifier. We evaluate depths 4 to 10 at a matching tolerance of 100 ppm. The result is the familiar list of SearchEngineResult records, one per target and decoy spectrum, ranked by descending score with the two delta fields filled in, as described on the SEQUEST-like page.

let qMinAndMax = 4, 10

let andromedaResults =
    AndromedaLike.calcAndromedaScore
        qMinAndMax scanlimits 100. spectrum 20.93 2 precursorMZ theoSpecs "ms2Example"

let printRanked (rs: SearchEngineResult.SearchEngineResult<float> list) =
    printfn "%-13s %-6s %8s %12s %8s" "sequence" "target" "score" "dBestToRest" "dNext"
    rs
    |> List.iter (fun r ->
        printfn "%-13s %-6b %8.4f %12.4f %8.4f"
            r.StringSequence r.IsTarget r.Score r.NormDeltaBestToRest r.NormDeltaNext)

printRanked andromedaResults
sequence      target    score  dBestToRest    dNext
ANLGMEVMHER   true    86.4073       0.0000   0.2577
AGGLGMEVMHER  true    64.1383       0.2577   0.5796
MANGLEVMHER   true    14.0586       0.8373   0.0871
EVMANLGMHER   true     6.5320       0.9244   0.0756
ANLGMEVMHER   false    0.0000       1.0000   0.0000
MANGLEVMHER   false    0.0000       1.0000   0.0000
EVMANLGMHER   false    0.0000       1.0000   0.0000
AGGLGMEVMHER  false    0.0000       1.0000   0.0000

The target of ANLGMEVMHER wins at 86.4, and the Gly-Gly variant is again the runner-up ahead of both permutations, the same shape the SEQUEST-like ranking had. The probability view separates the top pair more clearly, though. Where the dot product saw a near-tie with a dNext of 0.013, the binomial score puts a quarter of the top score between them. The mechanism is visible in the model: a predicted peak that finds no partner enlarges n without enlarging k and lowers the score, so the extra predictions of the 12 residue variant, and the few fragments it does not share with the true ladder, cost it directly. All four decoys land at exactly zero: their raw scores fall below the fixed correction terms explained next, and the clamp cuts them off.

Reading an Andromeda-like score

The score is derived from -10 log10 of the cumulative binomial probability. On that scale a value of 60 corresponds to a probability of 10^-6 under the random-match model. The implementation adds a mass-dependent correction computed from the precursor m/z plus constant modification and cleavage correction terms taken from the original Andromeda release, then subtracts 100. Negative results are clamped to zero. Absolute values are therefore calibrated for ranking within this implementation.

Getting a hyperscore alongside

XScoring.calcAndromedaAndXTandemScore runs the same rating and matching machinery once per candidate and returns a pair of result lists, an Andromeda-like ranking whose records carry SearchEngine = AndromedaLike and an X!Tandem-like ranking carrying SearchEngine = XTandemLike, each independently score-sorted with its own delta fields. It accepts the same arguments and the same theoretical spectra as calcAndromedaScore.

The X!Tandem score is the hyperscore: the summed intensity of all matched measured peaks, taken as a logarithm, plus the log factorials of the number of matched b ions and matched y ions, and a third log factorial for a separate neutral-loss count. The factorials reward candidates that match many ions of both series, since ten matched y ions weigh far more than twice five. The counting is b/y-oriented, a matched peak contributes to the count of the series flag it is tagged with, and since the loss peaks of this library's generator carry their parent series flag, the separate neutral-loss count stays empty here. The hyperscore is computed at the deepest peak depth of the range, where the most measured peaks are admitted to matching.

let andromedaResults2, hyperscoreResults =
    XScoring.calcAndromedaAndXTandemScore
        qMinAndMax scanlimits 100. spectrum 20.93 2 precursorMZ theoSpecs "ms2Example"

printRanked hyperscoreResults
sequence      target    score  dBestToRest    dNext
ANLGMEVMHER   true    49.3979       0.0000   0.0994
AGGLGMEVMHER  true    44.4862       0.0994   0.5145
MANGLEVMHER   true    19.0709       0.6139   0.1745
EVMANLGMHER   true    10.4505       0.7884   0.1250
EVMANLGMHER   false    4.2767       0.9134   0.0082
ANLGMEVMHER   false    3.8712       0.9216   0.0000
MANGLEVMHER   false    3.8712       0.9216   0.0000
AGGLGMEVMHER  false    3.8712       0.9216   0.0000

Both rankings agree on the order of the four targets. The decoys behave differently under the hyperscore: a decoy still matches a few peaks by chance, and the logarithm of their summed intensity enters the score even when the factorial terms contribute nothing, so the decoys settle at a nonzero floor around 4 where the corrected Andromeda score clamped them to zero.

The Andromeda-like ranking returned alongside agrees with what AndromedaLike.calcAndromedaScore produced on the same input, both modules implement the same score.

printfn "%-13s %-6s %14s %9s" "sequence" "target" "AndromedaLike" "XScoring"
List.zip andromedaResults andromedaResults2
|> List.iter (fun (a, x) ->
    printfn "%-13s %-6b %14.4f %9.4f" a.StringSequence a.IsTarget a.Score x.Score)
sequence      target  AndromedaLike  XScoring
ANLGMEVMHER   true          86.4073   86.4073
AGGLGMEVMHER  true          64.1383   64.1383
MANGLEVMHER   true          14.0586   14.0586
EVMANLGMHER   true           6.5320    6.5320
ANLGMEVMHER   false          0.0000    0.0000
MANGLEVMHER   false          0.0000    0.0000
EVMANLGMHER   false          0.0000    0.0000
AGGLGMEVMHER  false          0.0000    0.0000

The score columns are identical for all eight records, so results from the combined call can stand in for a separate AndromedaLike run.

Scoring whole runs

For batch searches over many spectra the library also offers SearchEngineGeneric.OrderedCache.generateTheoSpectra. It wires the database lookup and the spectrum predictors together: given the ion series calculator, the mass function, a peptide lookup function and three caches (one for lookup results, one for Andromeda-style and one for SEQUEST-style theoretical spectra), it answers a precursor mass window with the theoretical spectra for both engine families, keeping previously generated spectra in memory across consecutive windows and clearing the caches when a memory ceiling is exceeded. The per-engine getTheoSpecs calls shown on this page and the SEQUEST-like page are the direct route for scoring individual spectra.

Where the scores go next

The target and decoy scores and their deltas collected across a run feed false discovery rate control, and the identified peptides move on to quantification.

namespace BioFSharp
namespace BioFSharp.FileFormats
module MGF from BioFSharp.FileFormats
<summary> Mgf &lt;http://www.matrixscience.com/help/data_file_help.html&gt;`_ is a simple human-readable format for MS/MS data. It allows storing MS/MS peak lists and exprimental parameters. </summary>
namespace BioFSharp.IO
namespace BioFSharp.Mz
val ms2: MGFEntry
module MGF from BioFSharp.IO
val read: path: string -> MGFEntry list
<summary> Reads an mgf file into a collection of MgfEntries </summary>
Multiple items
module List from Microsoft.FSharp.Collections

--------------------
type List<'T> = | op_Nil | op_ColonColon of Head: 'T * Tail: 'T list interface IReadOnlyList<'T> interface IReadOnlyCollection<'T> interface IEnumerable interface IEnumerable<'T> member GetReverseIndex: rank: int * offset: int -> int member GetSlice: startIndex: int option * endIndex: int option -> 'T list static member Cons: head: 'T * tail: 'T list -> 'T list member Head: 'T member IsEmpty: bool member Item: index: int -> 'T with get ...
val head: list: 'T list -> 'T
val precursorMZ: float
type MGFEntry = { Parameters: Map<string,string> Mass: float array Intensity: float array } static member create: parameters: Map<string,string> -> mass: float array -> intensity: float array -> MGFEntry static member toLines: mgf: MGFEntry -> string seq static member toString: mgf: MGFEntry -> string static member tryGetPrecursorCharges: mgf: MGFEntry -> int list option static member tryGetPrecursorMZ: mgf: MGFEntry -> float option static member tryGetPrecursorMass: mgf: MGFEntry -> float option static member tryGetTitle: mgf: MGFEntry -> string option
<summary> Represents </summary>
static member MGFEntry.tryGetPrecursorMZ: mgf: MGFEntry -> float option
union case Option.Some: Value: 'T -> Option<'T>
val mz: float
union case Option.None: Option<'T>
val failwith: message: string -> 'T
val spectrum: PeakArray<Peak>
Multiple items
module PeakArray from BioFSharp.Mz

--------------------
type PeakArray<'a (requires 'a :> IPeak)> = 'a array
Multiple items
[<Struct>] type Peak = interface IPeak new: mz: float * intensity: float -> Peak member Equals: Peak * IEqualityComparer -> bool member Intensity: float member Mz: float

--------------------
Peak ()
new: mz: float * intensity: float -> Peak
val zip: mz: float array -> intensity: float array -> PeakArray<Peak>
<summary> Iterates the mz and intensity array and creates a Peak(mz,intensity) for each value pair. Returns a new Peak array. </summary>
MGFEntry.Mass: float array
MGFEntry.Intensity: float array
val printfn: format: Printf.TextWriterFormat<'T> -> 'T
property System.Array.Length: int with get
<summary>Gets the total number of elements in all the dimensions of the <see cref="T:System.Array" />.</summary>
<exception cref="T:System.OverflowException">The array is multidimensional and contains more than <see cref="F:System.Int32.MaxValue">Int32.MaxValue</see> elements.</exception>
<returns>The total number of elements in all the dimensions of the <see cref="T:System.Array" />; zero if there are no elements in the array.</returns>
val mono: (IBioItem -> float)
type IBioItem = abstract Formula: Formula abstract Name: string abstract Symbol: char abstract isGap: bool abstract isTerminator: bool
<summary> Marker interface for BioItem base. </summary>
Multiple items
val float: value: 'T -> float (requires member op_Explicit)

--------------------
type float = System.Double

--------------------
type float<'Measure> = float
module BioItem from BioFSharp
<summary> Basic functions on IBioItems interface </summary>
val monoisoMass<'a (requires 'a :> IBioItem)> : (IBioItem -> float) (requires 'a :> IBioItem)
<summary> Returns the monoisotopic mass of a bio item (without H20) </summary>
val neutralMass: peptide: AminoAcids.AminoAcid list -> float
val peptide: AminoAcids.AminoAcid list
module AminoAcids from BioFSharp
<summary> Contains the AminoAcid type and its according functions. The AminoAcid type is a complex presentation of amino acids, allowing modifications </summary>
type AminoAcid = | Ala | Cys | Asp | Glu | Phe | Gly | His | Ile | Lys | Leu ... interface IBioItem static member op_Explicit: value: #IBioItem -> byte + 1 overload
<summary> Amino acid Codes </summary>
type 'T list = List<'T>
val sumBy: projection: ('T -> 'U) -> list: 'T list -> 'U (requires member (+) and member Zero)
module ModificationInfo from BioFSharp
<summary> Functionality for creating formula modifications </summary>
module Table from BioFSharp.ModificationInfo
<summary> Contains frequent modifications </summary>
val H2O: ModificationInfo.Modification
val candidate: modSeqId: int -> pepSeqId: int -> sequence: string -> SearchDB.LookUpResult<AminoAcids.AminoAcid>
val modSeqId: int
val pepSeqId: int
val sequence: string
Multiple items
val string: value: 'T -> string

--------------------
type string = System.String
val bioSequence: BioList.BioList<AminoAcids.AminoAcid>
Multiple items
module BioList from BioFSharp.BioCollectionsExtensions

--------------------
module BioList from BioFSharp
<summary> This module contains the BioList type and its according functions. The BioList type is a List of objects using the IBioItem interface </summary>
val ofAminoAcidString: s: #(char seq) -> BioList.BioList<AminoAcids.AminoAcid>
<summary> Generates amino acid sequence of one-letter-code raw string </summary>
val mass: float
val roundedMass: int64
Multiple items
val int64: value: 'T -> int64 (requires member op_Explicit)

--------------------
type int64 = System.Int64

--------------------
type int64<'Measure> = int64
namespace System
type Math = static member Abs: value: decimal -> decimal + 7 overloads static member Acos: d: float -> float static member Acosh: d: float -> float static member Asin: d: float -> float static member Asinh: d: float -> float static member Atan: d: float -> float static member Atan2: y: float * x: float -> float static member Atanh: d: float -> float static member BigMul: a: int * b: int -> int64 + 5 overloads static member BitDecrement: x: float -> float ...
<summary>Provides constants and static methods for trigonometric, logarithmic, and other common mathematical functions.</summary>
System.Math.Round(a: float) : float
System.Math.Round(d: decimal) : decimal
System.Math.Round(value: float, mode: System.MidpointRounding) : float
System.Math.Round(value: float, digits: int) : float
System.Math.Round(d: decimal, mode: System.MidpointRounding) : decimal
System.Math.Round(d: decimal, decimals: int) : decimal
System.Math.Round(value: float, digits: int, mode: System.MidpointRounding) : float
System.Math.Round(d: decimal, decimals: int, mode: System.MidpointRounding) : decimal
module SearchDB from BioFSharp.Mz
val createLookUpResult: modSequenceId: int -> pepSequenceId: int -> mass: float -> roundedMass: int64 -> stringSequence: string -> bioSequence: 'a list -> globalMod: int -> SearchDB.LookUpResult<'a> (requires 'a :> IBioItem)
val candidates: SearchDB.LookUpResult<AminoAcids.AminoAcid> list
val map: mapping: ('T -> 'U) -> list: 'T list -> 'U list
val c: SearchDB.LookUpResult<AminoAcids.AminoAcid>
SearchDB.LookUpResult.StringSequence: string
module String from Microsoft.FSharp.Core
val concat: sep: string -> strings: string seq -> string
val scanlimits: float * float
val fragmentPairs: (SearchDB.LookUpResult<AminoAcids.AminoAcid> * Fragmentation.FragmentMasses) list
val fragments: Fragmentation.FragmentMasses
module Fragmentation from BioFSharp.Mz
module Series from BioFSharp.Mz.Fragmentation
val fragmentMasses: nTerminalSeries: ((#IBioItem -> float) -> AminoAcids.AminoAcid list -> PeakFamily<TaggedMass.TaggedMass> list) -> cTerminalSeries: ((#IBioItem -> float) -> AminoAcids.AminoAcid list -> PeakFamily<TaggedMass.TaggedMass> list) -> massFunction: (IBioItem -> float) -> aal: AminoAcids.AminoAcid list -> Fragmentation.FragmentMasses
<summary> Returns the fragment masses of the amino acid sequence specified by aal. The ionseries are specified by functions "nTerminalSeries" and "cTerminalSeries". The mass accuracy is determined by the massfunction applied. </summary>
val bOfBioList: massfunction: (IBioItem -> float) -> aal: AminoAcids.AminoAcid list -> PeakFamily<TaggedMass.TaggedMass> list
<summary> Returns the b series of the given amino acids list. The mass accuracy is determined by the massfunction applied. </summary>
val yOfBioList: massfunction: (IBioItem -> float) -> aal: AminoAcids.AminoAcid list -> PeakFamily<TaggedMass.TaggedMass> list
<summary> Returns the y series of the given amino acids list. The mass accuracy is determined by the massfunction applied. </summary>
SearchDB.LookUpResult.BioSequence: AminoAcids.AminoAcid list
val theoSpecs: TheoreticalSpectra.TheoreticalSpectrum<PeakFamily<TaggedPeak.TaggedPeak> array> list
module AndromedaLike from BioFSharp.Mz
val getTheoSpecs: float * float -> chargeState: int -> possiblePeptideInfos: (SearchDB.LookUpResult<AminoAcids.AminoAcid> * Fragmentation.FragmentMasses) list -> TheoreticalSpectra.TheoreticalSpectrum<PeakFamily<TaggedPeak.TaggedPeak> array> list
<summary> Converts the fragment ion ladders to a theoretical Sequestlike spectrum at a given charge state. Subsequently, the spectrum is binned to the nearest mz bin (binwidth = 1 Da). Filters out peaks that are not within the scanLimits. </summary>
val iter: action: ('T -> unit) -> list: 'T list -> unit
val ts: TheoreticalSpectra.TheoreticalSpectrum<PeakFamily<TaggedPeak.TaggedPeak> array>
val withLosses: int
TheoreticalSpectra.TheoreticalSpectrum.TheoSpec: PeakFamily<TaggedPeak.TaggedPeak> array
module Array from Microsoft.FSharp.Collections
val filter: predicate: ('T -> bool) -> array: 'T array -> 'T array
val f: PeakFamily<TaggedPeak.TaggedPeak>
PeakFamily.DependentPeaks: TaggedPeak.TaggedPeak list
property List.IsEmpty: bool with get
val length: array: 'T array -> int
TheoreticalSpectra.TheoreticalSpectrum.LookUpResult: SearchDB.LookUpResult<AminoAcids.AminoAcid>
val qMinAndMax: int * int
val andromedaResults: SearchEngineResult.SearchEngineResult<float> list
val calcAndromedaScore: int * int -> float * float -> matchingTolPPM: float -> spectrum: PeakArray<#IPeak> -> scanTime: float -> chargeState: int -> isolationWindowTargetMz: float -> theoreticalSpectra: TheoreticalSpectra.TheoreticalSpectrum<PeakFamily<TaggedPeak.TaggedPeak> array> list -> spectrumID: string -> SearchEngineResult.SearchEngineResult<float> list
<summary> Calculates the AndromedaLike scores for all theoretical spectra. </summary>
val printRanked: rs: SearchEngineResult.SearchEngineResult<float> list -> unit
val rs: SearchEngineResult.SearchEngineResult<float> list
module SearchEngineResult from BioFSharp.Mz
type SearchEngineResult<'a> = { SearchEngine: SearchEngine SpectrumID: string ModSequenceID: int PepSequenceID: int GlobalMod: int IsTarget: bool ScanTime: float StringSequence: string PrecursorCharge: int PrecursorMZ: float ... } member Equals: SearchEngineResult<'a> * IEqualityComparer -> bool
val r: SearchEngineResult.SearchEngineResult<float>
SearchEngineResult.SearchEngineResult.StringSequence: string
SearchEngineResult.SearchEngineResult.IsTarget: bool
SearchEngineResult.SearchEngineResult.Score: float
SearchEngineResult.SearchEngineResult.NormDeltaBestToRest: float
SearchEngineResult.SearchEngineResult.NormDeltaNext: float
val andromedaResults2: SearchEngineResult.SearchEngineResult<float> list
val hyperscoreResults: SearchEngineResult.SearchEngineResult<float> list
module XScoring from BioFSharp.Mz
val calcAndromedaAndXTandemScore: int * int -> float * float -> matchingTolPPM: float -> spectrum: PeakArray<#IPeak> -> scanTime: float -> chargeState: int -> isolationWindowTargetMz: float -> theoreticalSpectra: TheoreticalSpectra.TheoreticalSpectrum<PeakFamily<TaggedPeak.TaggedPeak> array> list -> spectrumID: string -> SearchEngineResult.SearchEngineResult<float> list * SearchEngineResult.SearchEngineResult<float> list
<summary> Calculates the AndromedaLike scores for all theoretical spectra. </summary>
val zip: list1: 'T1 list -> list2: 'T2 list -> ('T1 * 'T2) list
val a: SearchEngineResult.SearchEngineResult<float>
val x: SearchEngineResult.SearchEngineResult<float>

Type something to start searching.