#import "template.typ": *
#import "@preview/proteograph:0.2.2": *

#show: doc => conf(
  authors: (
    (
      name: "Benoît Valot",
    ),
    (
      name: "Olivier Langella",
    ),
    (
      name: "Edlira Nano",
    ),
    (
      name: "Filippo Rusconi",
    ),
  ),
  toc: true,
  lang: "en",
  font: "EB Garamond 12",
  date: "14/02/2025",
  years: 2025,
  version: json("../user-manual-version.json").masschroq_version,
  subtitle: "Free and Open Source Peptide Quantification Software",
  "MassChroQ3 User Manual",
  doc,
)


#set text(lang: "en")
#set heading(numbering: "1.1")
#show figure.where(kind: "attribute"): set align(start)
= #mcq3


== Introduction

#mcq is designed to extract ion current of a list of peptide and measure the area under the curve on a single run.

== Input format

#code-block(read("input.json"), "json", title: "input file format")

=== JSON input root file structure
#attribute(parent: "root", tag: "project_parameters", nature: "object", required: false)[
  Controlled vocabulary summarising important parameters of the project.
]
#attribute(parent: "root", tag: "masschroq_methods", nature: "object", required: true)[
  This object contains all required parameters for the #mcq engine, see the @masschroq_methods section
]
#attribute(parent: "root", tag: "identification_data", nature: "object", required: true)[]
#attribute(parent: "root", tag: "actions", nature: "object", required: true)[]

= #mcq methods <masschroq_methods>

#code-block(read("json/methods.json"), "json", title: "masschroq_methods JSON object")
#attribute(parent: "masschroq_methods", tag: "alignment_method", nature: "object", required: true)[
  Describes how to align retention time between MS runs, see @alignment_method
]
#attribute(parent: "masschroq_methods", tag: "quantification_method", nature: "object", required: true)[
  Describes how #mcq extracts ion current, detects peaks and then quantify ion intensities, see @quantification_method
]

=== Alignment method <alignment_method>

#code-block(read("json/alignment.json"), "json", title: "alignment_method JSON object")

=== Quantification method <quantification_method>

#code-block(read("json/quantification.json"), "json", title: "quantification_method JSON object")

#attribute(parent: "quantification_method", tag: "match_between_run", nature: "boolean", required: true)[
  Boolean, true if a match between run is required, false otherwise
]
#attribute(parent: "quantification_method", tag: "isotope_minimum_ratio", nature: "float", required: true)[
  Ratio between 0 and 1 (not included): the ratio of minimum intensity of the whole theoretical isotopic pattern that must be reached. If the value is 0, then only the most theoretically intense isotope will be extracted and quantified. If the value is 0.8, it selects isotopes from the most intense to the least intense and stops when 80% of the whole theoretical intensity is reached.
]

#attribute(parent: "quantification_method", tag: "extraction", nature: "object", required: true)[
  Describes how the ion current is extracted at a given m/z and retention time.
]
#attribute(parent: "quantification_method", tag: "prefilter", nature: "object", required: true)[
  Signal process to apply on ion exctracted current before the peak detection. Can be empty.
]
#attribute(parent: "quantification_method", tag: "detection", nature: "object", required: true)[
  Peak detection method (see @peak_detection_method) to use. This is important to separate real peaks from artefacts and to accurately determine peak boundaries.
]

==== Peak detection method <peak_detection_method>

#code-block(read("json/peak_detection.json"), "json", title: "quantification_method JSON object")




#let xic = json("data/onexicpeak.json")
#xic.insert("title", "ion current")
#let maxmin = json("data/onexicpeak_maxmin.json")
#maxmin.insert("title", "maxmin curve")
#let minmax = json("data/onexicpeak_minmax.json")
#minmax.insert("title", "minmax curve")
#let th_max = (x: (3750, 3810), y: (500000, 500000))
//#xic2.insert("peak-begin",data_json.found_list_first_pass.first().xics.at(2).peak.rt.first())
//#xic2.insert("peak-end",data_json.found_list_first_pass.first().xics.at(2).peak.rt.last())
//
#figure(placement: auto, caption: "peak detection using minmax and maxmin filters", [
  #xic-plot(height: 8cm, width: 12cm, title: "peak detection", xic, maxmin, minmax, th_max)
])<peak-detection-min-max-curve>

The default detection method called "zivy" differantiates real MS1 peaks from noise by performing a morphology algorithm#footnote([https://en.wikipedia.org/wiki/Mathematical_morphology]).
As shown in @peak-detection-min-max-curve, it uses two curves:
- "minmax" is the closing curve #footnote([https://en.wikipedia.org/wiki/Closing_(morphology)])
- "maxmin" is the opening curve #footnote([https://en.wikipedia.org/wiki/Opening_(morphology)])

"minmax"@attribute-detection-minmax is used to determine the boundary of the peaks : where it starts and where it ends and to validate the peak with @attribute-detection-threshold_on_max.

"maxmin"@attribute-detection-maxmin is used to validate the peak as a true MS1 peak using @attribute-detection-threshold_on_min.

A peak is considered only when the @attribute-detection-threshold_on_max is reached on "minmax" *and* @attribute-detection-threshold_on_min is reached on "maxmin".


#attribute(parent: "detection", tag: "type", nature: "string", required: true)[
  The detection method to use. Only "zivy" is available in #mcq 3.
]

#attribute(parent: "detection", tag: "meanfilter", nature: "integer", required: true)[
  Applies a mean filter on the signal before processing the minmax and maxmin process. The mean is computed in a window of width :
  - $"meanfilter" dot 2$ for odd values
  - $("meanfilter" dot 2) + 1$ for even values.

  The peak area is always computed on the original signal, not the signal after the mean filter. But keep in mind that this filter must be used only on very noisy signals, with extremely high random variations.

  Do not use a value more than 1, and if the signal is stable, prefer a 0 value (no mean filter at all).
]


#attribute(parent: "detection", tag: "minmax", nature: "integer", required: true)[
  Computes the "closing" signal to fit the upper shape of the peak, filling random noise (see @peak-detection-min-max-curve). It uses a window of width :
  - $"minmax" dot 2$ for odd values
  - $("minmax" dot 2) + 1$ for even values.
]
#attribute(parent: "detection", tag: "maxmin", nature: "integer", required: true)[
  Computes the "opening" signal to fit the lower shape (from below) of the peak, filling random noise (see @peak-detection-min-max-curve). It uses a window of width :
  - $"maxmin" dot 2$ for odd values
  - $("maxmin" dot 2) + 1$ for even values.
]
#attribute(parent: "detection", tag: "threshold_on_max", nature: "integer", required: true)[
  Intensity threshold of the @attribute-detection-maxmin.
]
#attribute(parent: "detection", tag: "threshold_on_min", nature: "integer", required: true)[
  Intensity threshold of the @attribute-detection-minmax.
]

= #mcq export tool

#mcq3 comes with a CLI tool #emph[masschroq-export] to extract data from the CBOR #mcq3 output file

#code-prompt("masschroq-export -h", title: "masschroq-export online help")


== Export alignment data to JSON<mcq-export-json>

#code-prompt(
  "masschroq-export --json alignment_data.json mcq_quantification_results.cbor",
  title: "extracting alignment data to JSON file",
)

== Generate PDF alignment data report using Typst

You need the JSON alignment data file generated in @mcq-export-json.
Prepare a simple Typst file (text file with .typ extension) called "alignment.typ" with this content:

#let code_typst = read("example_alignment.typ")
#code-block(
  title: "",
  code_typst.replace("_proteograph_version_", json("../user-manual-version.json").proteograph_version),
  "typst",
)

And compile this file using :
#code-prompt("typst compile alignment.typ", title: "Compile alignment typst file")




== Export quantification data to JSON<mcq-export-peptide-json>

#code-prompt(
  "masschroq-export --peptide pepa1b12 --json quantification.json mcq_quantification_results.cbor",
  title: "extracting quantification data of pepa1b12 to JSON file",
)

== Generate PDF quantification report using Typst

You need the JSON alignment data file generated in @mcq-export-peptide-json.
Prepare a simple Typst file (text file with .typ extension) called "quantification.typ" with this content:

#let code_typst = read("example_peptide_quantification.typ")
#code-block(
  title: "",
  code_typst.replace("_proteograph_version_", json("../user-manual-version.json").proteograph_version),
  "typst",
)

And compile this file using :
#code-prompt("typst compile quantification.typ", title: "Compile peptide quantification typst file")


= Peak quality code

/ aa: best quality : many MS2 fragmentation event, only one peak directly detected
/ zaa: same as aa, but this charge state was not directly observed in MS2 fragmentation events in this MSrun
/ a: good quality, single MS2 fragmentation event, one peak detected
/ za: same as a, but this charge state was not directly observed in MS2 fragmentation events in this MSrun
/ ab: many MS2 fragmentation event, but more than one peak detected, the greater peak (area) is chosen, it is obviously fragmented... perhaps a hint to check for peak detection parameters
/ zab: same as ab, but this charge state was not directly observed in MS2 fragmentation events in this MSrun
/ b: peak obtained by "match between run" on the mean aligned observed retention times in MS2 fragmentation events *and* also matching with the retention time given by other detected and quantifified MS1 apex peaks in other MS runs
/ c: peak obtained by "match between run" only on the mean of aligned observed retention times in MS2 fragmentation events
/ d: peak obtained by "match between run" only matching with the retention time given by other detected and quantifified MS1 apex peaks in other MS runs

/ missed: no peak detected, no quantification



#bibliography(style: "frontiers", "../biblio.bib")
