/*
* EuroCarbDB, a framework for carbohydrate bioinformatics
*
* Copyright (c) 2006-2009, Eurocarb project, or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
* A copy of this license accompanies this distribution in the file LICENSE.txt.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* Last commit: $Rev: 1930 $ by $Author: david@nixbioinf.org $ on $Date:: 2010-07-29 #$
*/
/**
@author Alessio Ceroni (a.ceroni@imperial.ac.uk)
*/
package org.eurocarbdb.application.glycoworkbench.plugin;
import org.eurocarbdb.application.glycanbuilder.*;
import org.eurocarbdb.application.glycoworkbench.*;
import java.util.*;
public class AnnotationThread extends Thread implements GeneratorListener {
protected int progress = 0;
protected final int FRAGMENTER = 1;
protected final int COLLECTION = 2;
protected final int GENERATOR = 3;
protected int mode = FRAGMENTER;
protected int no_structures = 0;
protected boolean has_fuzzy = false;
protected boolean has_not_fuzzy = true;
protected AnnotatedPeakList annotated_peaks = null;
protected PeakList peaks = null;
protected PeakAnnotationCollection match_coll = null;
Vector<IonCloud> ion_clouds = null;
protected Collection<Glycan> structures = null;
protected Fragmenter fragmenter = null;
protected FragmentDocument frag_doc = null;
protected Generator generator = null;
protected AnnotationOptions ann_opt = null;
public AnnotationThread(PeakList _peaks, Collection<Glycan> _structures,
Fragmenter _fragmenter, AnnotationOptions _ann_opt) {
annotated_peaks = new AnnotatedPeakList();
match_coll = new PeakAnnotationCollection();
peaks = _peaks;
structures = _structures;
fragmenter = _fragmenter;
frag_doc = null;
generator = null;
ann_opt = _ann_opt;
mode = FRAGMENTER;
}
public AnnotationThread(PeakList _peaks, Glycan _structure,
FragmentCollection _frag_coll, AnnotationOptions _ann_opt) {
annotated_peaks = new AnnotatedPeakList();
match_coll = new PeakAnnotationCollection();
peaks = _peaks;
structures = Collections.singleton(_structure);
fragmenter = null;
frag_doc = new FragmentDocument();
frag_doc.addFragments(_structure, _frag_coll);
generator = null;
ann_opt = _ann_opt;
mode = COLLECTION;
}
public AnnotationThread(PeakList _peaks, FragmentDocument _frag_doc,
AnnotationOptions _ann_opt) {
annotated_peaks = new AnnotatedPeakList();
match_coll = new PeakAnnotationCollection();
peaks = _peaks;
structures = _frag_doc.getStructures();
fragmenter = null;
frag_doc = _frag_doc;
generator = null;
ann_opt = _ann_opt;
mode = COLLECTION;
}
public AnnotationThread(PeakList _peaks, Generator _generator,
AnnotationOptions _ann_opt) {
annotated_peaks = new AnnotatedPeakList();
match_coll = new PeakAnnotationCollection();
peaks = _peaks;
structures = _generator.getMotifs();
fragmenter = null;
frag_doc = null;
generator = _generator;
ann_opt = _ann_opt;
mode = GENERATOR;
}
public AnnotatedPeakList getAnnotatedPeaks() {
return annotated_peaks;
}
public int getProgress() {
return progress;
}
public int getTarget() {
return (structures != null && peaks != null) ? (structures.size() * peaks
.size())
: 0;
}
public int getNoStructures() {
return (structures != null) ? structures.size() : 0;
}
public int getNonEmptyStructures() {
return no_structures;
}
public boolean hasFuzzyStructures() {
return has_fuzzy;
}
public boolean hasNonFuzzyStructures() {
return has_not_fuzzy;
}
public void run() {
progress = 0;
no_structures = 0;
has_fuzzy = false;
has_not_fuzzy = true;
if (peaks == null
|| ann_opt == null
|| (fragmenter == null && frag_doc == null && generator == null)
|| (fragmenter != null && structures == null)) {
interrupted();
return;
}
// compute possible charges
if (!ann_opt.DERIVE_FROM_PARENT || mode != FRAGMENTER)
ion_clouds = IonCloudUtils.getPossibleIonClouds(ann_opt);
// annotate
if (mode == FRAGMENTER) {
// annotate with computed fragments
annotated_peaks.clear();
for (Glycan structure : structures) {
if (structure != null) {
no_structures++;
if (structure.isFuzzy(true)) {
has_fuzzy = true;
progress += peaks.size();
} else {
has_not_fuzzy = true;
// compute fragments if requested
FragmentCollection frag_coll = fragmenter
.computeAllFragments(structure);
// derive annotation options from parent if requested
AnnotationOptions der_ann_opt = ann_opt;
if (ann_opt.DERIVE_FROM_PARENT) {
der_ann_opt = ann_opt.derive(structure);
ion_clouds = IonCloudUtils
.getPossibleIonClouds(der_ann_opt);
}
// annotate fragments
match_coll = match(peaks, frag_coll, ion_clouds,
der_ann_opt);
annotated_peaks.addPeakAnnotations(structure,
match_coll, false);
}
} else
progress += peaks.size();
}
} else if (mode == COLLECTION) {
// annotate with pre-computed fragments
annotated_peaks.clear();
for (int i = 0; i < frag_doc.getNoStructures(); i++) {
match_coll = match(peaks, frag_doc.getFragments(i), ion_clouds,
ann_opt);
annotated_peaks.addPeakAnnotations(frag_doc.getStructure(i),
match_coll, false);
}
} else if (mode == GENERATOR) {
// annotate with generated structures
annotated_peaks.clear();
int ind = 0;
for (Glycan s : structures) {
// generate and match
match_coll = new PeakAnnotationCollection();
generator.generate(ind, this);
// check if all peaks have matched
for (Peak p : peaks.getPeaks()) {
if (!match_coll.isAnnotated(p))
match_coll.addPeakAnnotation(p);
}
progress += peaks.size();
// save annotations
annotated_peaks.addPeakAnnotations(s, match_coll, false);
ind++;
}
}
progress = getTarget();
}
static public Collection<FragmentEntry> computeChargesAndExchanges(
Glycan structure, Collection<FragmentEntry> fragments,
AnnotationOptions ann_opt) {
// compute possible charges
if (ann_opt.DERIVE_FROM_PARENT)
ann_opt = ann_opt.derive(structure);
Vector<IonCloud> ion_clouds = IonCloudUtils
.getPossibleIonClouds(ann_opt);
// compute charges and exchanges
return computeChargesAndExchanges(fragments, ion_clouds, ann_opt);
}
static public Collection<FragmentEntry> computeChargesAndExchanges(
Collection<FragmentEntry> fragments,
Collection<IonCloud> ion_clouds, AnnotationOptions ann_opt) {
Vector<FragmentEntry> ret = new Vector<FragmentEntry>();
for (FragmentEntry fe : fragments) {
if (ann_opt.COMPUTE_EXCHANGES) {
Vector<IonCloud> neutral_exchanges = IonCloudUtils
.getPossibleNeutralExchanges(
fe.fragment.countCharges(), ann_opt);
for (IonCloud nex : neutral_exchanges) {
for (IonCloud cloud : ion_clouds) {
if (cloud.and(nex).isRealistic())
ret.add(fe.and(cloud, nex));
}
}
} else {
for (IonCloud cloud : ion_clouds)
ret.add(fe.and(cloud));
}
}
return ret;
}
public boolean generatorCallback(FragmentEntry fe) {
if (ann_opt.COMPUTE_EXCHANGES) {
Vector<IonCloud> neutral_exchanges = IonCloudUtils
.getPossibleNeutralExchanges(fe.fragment.countCharges(),
ann_opt);
for (IonCloud nex : neutral_exchanges) {
for (IonCloud cloud : ion_clouds) {
if (cloud.and(nex).isRealistic()) {
for (Peak p : peaks.getPeaks()) {
if (match(p, fe, cloud, nex, ann_opt))
match_coll.addPeakAnnotation(p, fe.and(cloud,
nex));
}
}
if (interrupted())
return false;
}
}
} else {
for (IonCloud cloud : ion_clouds) {
for (Peak p : peaks.getPeaks()) {
if (match(p, fe, cloud, ann_opt))
match_coll.addPeakAnnotation(p, fe.and(cloud));
}
if (interrupted())
return false;
}
}
return true;
}
public PeakAnnotationCollection match(PeakList peaklist,
FragmentCollection fc, Vector<IonCloud> ion_clouds,
AnnotationOptions ann_opt) {
// match
PeakAnnotationCollection matched = new PeakAnnotationCollection();
for (int i = 0; i < peaklist.size() && !interrupted(); i++, progress++) {
Peak p = peaklist.getPeak(i);
boolean has_matched = false;
for (FragmentEntry fe : fc.getFragments()) {
//System.err.println("Peak: "+p.getCharge()+"|fragment: "+fe.getCharges().getNoCharges());
if(p.getCharge()!=Integer.MIN_VALUE &&
p.getCharge()!=fe.getCharges().getNoCharges()){
continue;
}
if (ann_opt.COMPUTE_EXCHANGES) {
Vector<IonCloud> neutral_exchanges = IonCloudUtils
.getPossibleNeutralExchanges(fe.fragment
.countCharges(), ann_opt);
for (IonCloud nex : neutral_exchanges) {
for (IonCloud cloud : ion_clouds) {
if (cloud.and(nex).isRealistic()) {
if (match(p, fe, cloud, nex, ann_opt)) {
matched.addPeakAnnotation(p, fe.and(cloud,
nex));
has_matched = true;
}
}
}
}
} else {
for (IonCloud cloud : ion_clouds) {
if (match(p, fe, cloud, ann_opt)) {
matched.addPeakAnnotation(p, fe.and(cloud));
has_matched = true;
}
}
}
}
if (!has_matched)
matched.addPeakAnnotation(p);
}
return matched;
}
static public boolean match(double fmz, double mz_ratio,
AnnotationOptions ann_opt) {
if (ann_opt.MASS_ACCURACY_UNIT.equals(ann_opt.MASS_ACCURACY_PPM))
return (Math.abs(1. - fmz / mz_ratio) < (0.000001 * ann_opt.MASS_ACCURACY));
return (Math.abs(mz_ratio - fmz) < ann_opt.MASS_ACCURACY);
}
static public boolean match(Peak p, FragmentEntry fe,
AnnotationOptions ann_opt) {
double fmz = fe.mz_ratio;
double mz_ratio = p.getMZ();
return match(fmz, mz_ratio, ann_opt);
}
static public boolean match(Peak p, FragmentEntry fe, IonCloud ions,
AnnotationOptions ann_opt) {
double fmz = ions.computeMZ(fe.mass);
double mz_ratio = p.getMZ();
return match(fmz, mz_ratio, ann_opt);
}
static public boolean match(Peak p, FragmentEntry fe, IonCloud ions,
IonCloud neutral_exchange, AnnotationOptions ann_opt) {
double fmz = ions.computeMZ(neutral_exchange.getIonsMass() + fe.mass);
double mz_ratio = p.getMZ();
return match(fmz, mz_ratio, ann_opt);
}
}