diff --git a/CycloBranch/CycloBranch.vcxproj b/CycloBranch/CycloBranch.vcxproj index 8f40608..23c88a4 100644 --- a/CycloBranch/CycloBranch.vcxproj +++ b/CycloBranch/CycloBranch.vcxproj @@ -157,9 +157,12 @@ + + + true true @@ -168,6 +171,10 @@ true true + + true + true + true true @@ -208,6 +215,10 @@ true true + + true + true + true true @@ -224,6 +235,10 @@ true true + + true + true + true true @@ -264,6 +279,10 @@ true true + + true + true + true true @@ -274,6 +293,7 @@ + @@ -283,6 +303,7 @@ + @@ -299,8 +320,47 @@ + + + + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing cSequenceDatabaseWidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing cSequenceDatabaseWidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing cSequenceDatabaseWidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing cSequenceDatabaseWidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" + + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing cBricksDatabaseWidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing cBricksDatabaseWidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing cBricksDatabaseWidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing cBricksDatabaseWidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" + $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing cLassoWidget.h... diff --git a/CycloBranch/CycloBranch.vcxproj.filters b/CycloBranch/CycloBranch.vcxproj.filters index 8b5ead7..a06dc21 100644 --- a/CycloBranch/CycloBranch.vcxproj.filters +++ b/CycloBranch/CycloBranch.vcxproj.filters @@ -212,6 +212,33 @@ Source Files\core + + Source Files\gui + + + Generated Files\Debug + + + Generated Files\Release + + + Source Files\core + + + Source Files\core + + + Source Files\core + + + Source Files\gui + + + Generated Files\Debug + + + Generated Files\Release + @@ -259,6 +286,12 @@ Header Files\gui + + Header Files\gui + + + Header Files\gui + @@ -297,5 +330,14 @@ Header Files\core + + Header Files\core + + + Header Files\core + + + Header Files\core + \ No newline at end of file diff --git a/CycloBranch/core/cBrick.cpp b/CycloBranch/core/cBrick.cpp index 504e093..4b6c764 100644 --- a/CycloBranch/core/cBrick.cpp +++ b/CycloBranch/core/cBrick.cpp @@ -127,6 +127,7 @@ void cBrick::setSummary(string& summary) { void cBrick::setAcronyms(string& acronyms) { + this->acronyms.clear(); string s = ""; int i = 0; while (i < (int)acronyms.size()) { @@ -148,6 +149,7 @@ void cBrick::setAcronyms(string& acronyms) { void cBrick::setReferences(string& references) { + this->references.clear(); string s = ""; int i = 0; while (i < (int)references.size()) { @@ -235,6 +237,18 @@ string cBrick::getAcronymsAsString() { } +string cBrick::getReferencesAsString() { + string s = ""; + for (int i = 0; i < (int)references.size(); i++) { + s += references[i]; + if (i < (int)references.size() - 1) { + s += "/"; + } + } + return s; +} + + string cBrick::getFirstAcronymAsString() { if (acronyms.size() == 0) { return ""; @@ -244,6 +258,10 @@ string cBrick::getFirstAcronymAsString() { string cBrick::getAcronymsWithReferencesAsHTMLString() { + if (acronyms.size() != references.size()) { + return ""; + } + string s = ""; regex rx; bool correctreference; @@ -278,9 +296,9 @@ string cBrick::getAcronymsWithReferencesAsHTMLString() { // PDB if (!correctreference) { - rx = "^PDB: [A-Z]+$"; + rx = "^PDB: ([A-Z]|[0-9])+$"; if (regex_search(references[i], rx)) { - s += ""; + s += ""; s += acronyms[i]; s += ""; correctreference = true; @@ -349,75 +367,23 @@ bool cBrick::isArtificial() { void cBrick::store(ofstream& os) { - int size; - - size = (int)name.size(); - os.write((char *)&size, sizeof(int)); - os.write(name.c_str(), name.size()); - - size = (int)acronyms.size(); - os.write((char *)&size, sizeof(int)); - for (int i = 0; i < (int)acronyms.size(); i++) { - size = (int)acronyms[i].size(); - os.write((char *)&size, sizeof(int)); - os.write(acronyms[i].c_str(), acronyms[i].size()); - } - - size = (int)references.size(); - os.write((char *)&size, sizeof(int)); - for (int i = 0; i < (int)references.size(); i++) { - size = (int)references[i].size(); - os.write((char *)&size, sizeof(int)); - os.write(references[i].c_str(), references[i].size()); - } - - size = (int)summary.size(); - os.write((char *)&size, sizeof(int)); - os.write(summary.c_str(), summary.size()); - + storeString(name, os); + storeStringVector(acronyms, os); + storeStringVector(references, os); + storeString(summary, os); os.write((char *)&mass, sizeof(double)); - - size = (int)composition.size(); - os.write((char *)&size, sizeof(int)); - os.write(composition.c_str(), composition.size()); - + storeString(composition, os); os.write((char *)&artificial, sizeof(bool)); } void cBrick::load(ifstream& is) { - int size; - - is.read((char *)&size, sizeof(int)); - name.resize(size); - is.read(&name[0], name.size()); - - is.read((char *)&size, sizeof(int)); - acronyms.resize(size); - for (int i = 0; i < (int)acronyms.size(); i++) { - is.read((char *)&size, sizeof(int)); - acronyms[i].resize(size); - is.read(&acronyms[i][0], acronyms[i].size()); - } - - is.read((char *)&size, sizeof(int)); - references.resize(size); - for (int i = 0; i < (int)references.size(); i++) { - is.read((char *)&size, sizeof(int)); - references[i].resize(size); - is.read(&references[i][0], references[i].size()); - } - - is.read((char *)&size, sizeof(int)); - summary.resize(size); - is.read(&summary[0], summary.size()); - + loadString(name, is); + loadStringVector(acronyms, is); + loadStringVector(references, is); + loadString(summary, is); is.read((char *)&mass, sizeof(double)); - - is.read((char *)&size, sizeof(int)); - composition.resize(size); - is.read(&composition[0], composition.size()); - + loadString(composition, is); is.read((char *)&artificial, sizeof(bool)); } diff --git a/CycloBranch/core/cBrick.h b/CycloBranch/core/cBrick.h index d586515..fcbfd9d 100644 --- a/CycloBranch/core/cBrick.h +++ b/CycloBranch/core/cBrick.h @@ -13,6 +13,7 @@ #include #include #include +#include "core/utilities.h" using namespace std; @@ -185,6 +186,13 @@ class cBrick { string getAcronymsAsString(); + /** + \brief Get all references. + \retval string references of all izomers separated by '/' + */ + string getReferencesAsString(); + + /** \brief Get the first acronym. \retval string acronym of the first izomer diff --git a/CycloBranch/core/cBricksDatabase.cpp b/CycloBranch/core/cBricksDatabase.cpp index 6e462d6..6702b0d 100644 --- a/CycloBranch/core/cBricksDatabase.cpp +++ b/CycloBranch/core/cBricksDatabase.cpp @@ -105,7 +105,7 @@ bool cBricksDatabase::nextCombination(vector& combarray, int numberofbasicb cBricksDatabase::cBricksDatabase() { - bricks.clear(); + clear(); } @@ -119,6 +119,7 @@ int cBricksDatabase::loadFromPlainTextStream(ifstream &stream, string& errormess errormessage = ""; cSummaryFormula formula; + bricks.clear(); while (stream.good()) { getline(stream,s); @@ -207,12 +208,21 @@ int cBricksDatabase::loadFromPlainTextStream(ifstream &stream, string& errormess return -1; } - sortbyMass(); - return 0; } +void cBricksDatabase::storeToPlainTextStream(ofstream &stream) { + for (int i = 0; i < bricks.size(); i++) { + stream << bricks[i].getName() << "\t"; + stream << bricks[i].getAcronymsAsString() << "\t"; + stream << bricks[i].getSummary() << "\t"; + stream << std::fixed << std::setprecision(10) << bricks[i].getMass() << "\t"; + stream << bricks[i].getReferencesAsString() << endl; + } +} + + int cBricksDatabase::size() { return (int)bricks.size(); } @@ -409,7 +419,7 @@ void cBricksDatabase::clear() { } -bool cBricksDatabase::replaceAcronymsByIDs(string& sequence) { +bool cBricksDatabase::replaceAcronymsByIDs(string& sequence, string& errormessage) { string s = ""; string acronym; bool insidebrick = false; @@ -447,6 +457,7 @@ bool cBricksDatabase::replaceAcronymsByIDs(string& sequence) { //} if (!found) { + errormessage = "Invalid brick acronym '" + acronym + "' typed in the sequence: " + sequence + "."; return false; } diff --git a/CycloBranch/core/cBricksDatabase.h b/CycloBranch/core/cBricksDatabase.h index 1d39c27..a9fd148 100644 --- a/CycloBranch/core/cBricksDatabase.h +++ b/CycloBranch/core/cBricksDatabase.h @@ -1,6 +1,6 @@ /** \file cBricksDatabase.h - \brief The representation of a database of bricks. + \brief The database of building blocks. */ @@ -12,6 +12,7 @@ #include #include #include +#include #include "core/cBrick.h" @@ -94,6 +95,13 @@ class cBricksDatabase { int loadFromPlainTextStream(ifstream &stream, string& errormessage); + /** + \brief Store the database of bricks into a plain text stream. + \param stream reference to an output file stream + */ + void storeToPlainTextStream(ofstream &stream); + + /** \brief Get the number of bricks in the database. \retval int number of bricks @@ -181,9 +189,10 @@ class cBricksDatabase { /** \brief Replace acronyms of bricks by ids. \param sequence reference to an input/output string containing acronyms/ids of bricks + \param errormessage reference to a string where an error message is stored when \a sequence contains an unknown building block \retval bool true when the replacement was successful, false when an acronym of a brick is unknown */ - bool replaceAcronymsByIDs(string& sequence); + bool replaceAcronymsByIDs(string& sequence, string& errormessage); /** diff --git a/CycloBranch/core/cCandidate.cpp b/CycloBranch/core/cCandidate.cpp index 7c96f73..80b391f 100644 --- a/CycloBranch/core/cCandidate.cpp +++ b/CycloBranch/core/cCandidate.cpp @@ -244,6 +244,7 @@ void cCandidate::clear() { branchstart = -1; branchend = -1; path.clear(); + name = ""; } @@ -699,6 +700,10 @@ double cCandidate::getPrecursorMass(cBricksDatabase& brickdatabasewithcombinatio case lasso: mass = parameters->fragmentdefinitions[cyclic_precursor_ion].massdifference + parameters->searchedmodifications[middlemodifID].massdifference; break; + case other: + break; + default: + break; } for (int i = 0; i < (int)bricks.size(); i++) { @@ -873,7 +878,7 @@ void cCandidate::getLassoRotations(vector& lassorotations, bool incl } -string cCandidate::getSummaryFormula(cParameters& parameters) { +string cCandidate::getSummaryFormula(cParameters& parameters, peptideType peptidetype) { cBrick b; vector bricks; b.setComposition(internalcomposition, false); @@ -882,7 +887,7 @@ string cCandidate::getSummaryFormula(cParameters& parameters) { cSummaryFormula formula; string summary; - switch (parameters.peptidetype) + switch (peptidetype) { case linear: case linearpolysaccharide: @@ -903,6 +908,10 @@ string cCandidate::getSummaryFormula(cParameters& parameters) { case lasso: formula.addFormula(parameters.searchedmodifications[middlemodifID].summary); break; + case other: + break; + default: + break; } bool partial = false; @@ -934,17 +943,9 @@ void cCandidate::store(ofstream& os) { path[i].store(os); } - size = (int)composition.size(); - os.write((char *)&size, sizeof(int)); - for (int i = 0; i < (int)composition.size(); i++) { - size = (int)composition[i].size(); - os.write((char *)&size, sizeof(int)); - os.write(composition[i].c_str(), composition[i].size()); - } - - size = (int)internalcomposition.size(); - os.write((char *)&size, sizeof(int)); - os.write(internalcomposition.c_str(), internalcomposition.size()); + storeString(name, os); + storeStringVector(composition, os); + storeString(internalcomposition, os); os.write((char *)&numberofinternalbricks, sizeof(int)); } @@ -965,22 +966,24 @@ void cCandidate::load(ifstream& is) { path[i].load(is); } - is.read((char *)&size, sizeof(int)); - composition.resize(size); - for (int i = 0; i < (int)composition.size(); i++) { - is.read((char *)&size, sizeof(int)); - composition[i].resize(size); - is.read(&composition[i][0], composition[i].size()); - } - - is.read((char *)&size, sizeof(int)); - internalcomposition.resize(size); - is.read(&internalcomposition[0], internalcomposition.size()); + loadString(name, is); + loadStringVector(composition, is); + loadString(internalcomposition, is); is.read((char *)&numberofinternalbricks, sizeof(int)); } +void cCandidate::setName(string& name) { + this->name = name; +} + + +string& cCandidate::getName() { + return name; +} + + bool operator == (cCandidate const& a, cCandidate const& b) { return ((cCandidate &)a).isEqualTo((cCandidate &)b); } diff --git a/CycloBranch/core/cCandidate.h b/CycloBranch/core/cCandidate.h index f9f06fd..110a3f8 100644 --- a/CycloBranch/core/cCandidate.h +++ b/CycloBranch/core/cCandidate.h @@ -134,6 +134,7 @@ class cCandidate { int branchstart; int branchend; vector path; + string name; vector composition; string internalcomposition; @@ -413,9 +414,10 @@ class cCandidate { /** \brief Get the summary formula of the peptide sequence candidate. \param parameters a reference to the parameters of the application + \param peptidetype the type of peptide \retval string the summary formula */ - string getSummaryFormula(cParameters& parameters); + string getSummaryFormula(cParameters& parameters, peptideType peptidetype); /** @@ -431,6 +433,20 @@ class cCandidate { */ void load(ifstream& is); + + /** + \brief Set the name of peptide. + \param name name + */ + void setName(string& name); + + + /** + \brief Get the name of peptide. + \retval string name + */ + string& getName(); + }; diff --git a/CycloBranch/core/cDeNovoGraph.cpp b/CycloBranch/core/cDeNovoGraph.cpp index cf97657..c9c1039 100644 --- a/CycloBranch/core/cDeNovoGraph.cpp +++ b/CycloBranch/core/cDeNovoGraph.cpp @@ -22,23 +22,34 @@ cDeNovoGraph::cDeNovoGraph() { } -bool cDeNovoGraph::findPath(int sourcenodeid, int edgeid, int targetnodeid, string& composition, string brickspath, int maximumbricksincombination, int depth) { +bool cDeNovoGraph::findPath(int sourcenodeid, int edgeid, int targetnodeid, string& composition, string brickspath, int maximumbricksincombination, vector& path) { string localbrickpath; - + bool found; + bool badpath; int count = getNumberOfBricks(brickspath); - if ((depth > 1) && (sourcenodeid == targetnodeid)) { + if ((path.size() > 1) && (sourcenodeid == targetnodeid)) { cBrick b; b.setComposition(brickspath, true); if (composition.compare(b.getComposition()) == 0) { - //*os << endl << "brick: " << brickspath << " path: " << sourcenodeid << " "; + //*os << " path: " << graph[sourcenodeid].getMZRatio() << " "; return true; } } if (count < maximumbricksincombination) { for (int i = 0; i < (int)graph[sourcenodeid].size(); i++) { - if ((i == edgeid) && (depth == 0)) { + if ((i == edgeid) && (path.size() == 0)) { + continue; + } + badpath = false; + for (int j = 0; j < (int)path.size(); j++) { + if (path[j] == sourcenodeid) { + badpath = true; + break; + } + } + if (badpath) { continue; } localbrickpath = brickspath; @@ -46,8 +57,11 @@ bool cDeNovoGraph::findPath(int sourcenodeid, int edgeid, int targetnodeid, stri localbrickpath += '-'; } localbrickpath += graph[sourcenodeid][i].composition; - if (findPath(graph[sourcenodeid][i].targetnode, i, targetnodeid, composition, localbrickpath, maximumbricksincombination, depth + 1)) { - //*os << sourcenodeid << " "; + path.push_back(sourcenodeid); + found = findPath(graph[sourcenodeid][i].targetnode, i, targetnodeid, composition, localbrickpath, maximumbricksincombination, path); + path.pop_back(); + if (found) { + //*os << graph[sourcenodeid].getMZRatio() << " "; return true; } } @@ -124,13 +138,13 @@ int cDeNovoGraph::createGraph(bool& terminatecomputation) { sortedpeaklist.removeChargeVariants(parameters->precursorcharge, parameters->fragmentmasserrortolerance); *os << "Number of nodes after deconvolution: " << sortedpeaklist.size() << endl; - // remove water loss peaks + // remove dehydrated peaks sortedpeaklist.removeNeutralLoss(- H2O, parameters->precursorcharge, parameters->fragmentmasserrortolerance); - *os << "Number of nodes when water loss ions are removed: " << sortedpeaklist.size() << endl; + *os << "Number of nodes when dehydrated ions are removed: " << sortedpeaklist.size() << endl; - // remove ammonia loss peaks + // remove deamidated peaks sortedpeaklist.removeNeutralLoss(- NH3, parameters->precursorcharge, parameters->fragmentmasserrortolerance); - *os << "Number of nodes when ammonia loss ions are removed: " << sortedpeaklist.size() << endl; + *os << "Number of nodes when deamidated ions are removed: " << sortedpeaklist.size() << endl; // insert system nodes switch (parameters->peptidetype) @@ -317,6 +331,9 @@ int cDeNovoGraph::createGraph(bool& terminatecomputation) { lastsystemnode = (int)graph.size() - 1; startnode = 1; break; + case other: + *os << "Invalid peptide type 'Other'." << endl; + return -1; default: *os << "Undefined peptide type." << endl; return -1; @@ -832,6 +849,7 @@ int cDeNovoGraph::removePathsWhichCanBeSubstitutedByLongerPath(bool& terminateco *os << "Removing edges forming paths which can be substituted by longer paths... "; int edgesremoved = 0; int j; + vector path; for (int i = startnode; i < (int)graph.size(); i++) { @@ -844,8 +862,9 @@ int cDeNovoGraph::removePathsWhichCanBeSubstitutedByLongerPath(bool& terminateco while (j < (int)graph[i].size()) { cBrick b; b.setComposition(graph[i][j].composition, true); - if (findPath(i, j, graph[i][j].targetnode, b.getComposition(), "", parameters->maximumbricksincombination, 0)) { - //*os << endl << "removing edge: " << i << "->" << graph[i][j].targetnode << " "; + path.clear(); + if (findPath(i, j, graph[i][j].targetnode, b.getComposition(), "", parameters->maximumbricksincombination, path)) { + //*os << "removing edge: " << graph[i].getMZRatio() << "->" << graph[graph[i][j].targetnode].getMZRatio() << " " << bricksdatabasewithcombinations.getTagName(b.getComposition()) << endl; graph[i].removeEdge(j); edgesremoved++; } @@ -862,9 +881,9 @@ int cDeNovoGraph::removePathsWhichCanBeSubstitutedByLongerPath(bool& terminateco } -void cDeNovoGraph::startGraphReader(cCandidateSet& candidates, bool& terminatecomputation) { +void cDeNovoGraph::startGraphReader(cCandidateSet& candidates, long long unsigned& count, int scanmode, bool& terminatecomputation) { graphreaderthread = new cGraphReaderThread(); - graphreaderthread->initialize(graph, bricksdatabasewithcombinations, candidates, parameters, os, lastsystemnode, terminatecomputation); + graphreaderthread->initialize(graph, bricksdatabasewithcombinations, candidates, parameters, os, lastsystemnode, count, scanmode, terminatecomputation); os->connect(graphreaderthread, SIGNAL(finished()), os, SLOT(graphReaderFinished())); os->setGraphReaderIsWorking(true); graphreaderthread->start(); diff --git a/CycloBranch/core/cDeNovoGraph.h b/CycloBranch/core/cDeNovoGraph.h index 92cadcb..422bf77 100644 --- a/CycloBranch/core/cDeNovoGraph.h +++ b/CycloBranch/core/cDeNovoGraph.h @@ -25,6 +25,12 @@ class cMainThread; using namespace std; +/** + \brief Maximum number of candidates to be read from the graph. +*/ +const long long unsigned maximumcandidates = 1000000000; + + /** \brief Compare two nodes. \param node1 reference to the first node @@ -49,7 +55,7 @@ class cDeNovoGraph { cGraphReaderThread* graphreaderthread; - bool findPath(int sourcenodeid, int edgeid, int targetnodeid, string& composition, string brickspath, int maximumbricksincombination, int depth); + bool findPath(int sourcenodeid, int edgeid, int targetnodeid, string& composition, string brickspath, int maximumbricksincombination, vector& path); // create vectors of edges from temporary unordered_sets void createVectorsOfEdges(); @@ -124,9 +130,11 @@ class cDeNovoGraph { /** \brief Start the graph reader. \param candidates output set of candidates + \param count an output number of peptide sequence candidates + \param scanmode 0 = get candidates; 1 = calculate the number of peptide sequence candidates \param terminatecomputation reference to a variable determining that the computation must be stopped */ - void startGraphReader(cCandidateSet& candidates, bool& terminatecomputation); + void startGraphReader(cCandidateSet& candidates, long long unsigned& count, int scanmode, bool& terminatecomputation); /** diff --git a/CycloBranch/core/cFragmentIons.cpp b/CycloBranch/core/cFragmentIons.cpp index 82758cf..9531dbc 100644 --- a/CycloBranch/core/cFragmentIons.cpp +++ b/CycloBranch/core/cFragmentIons.cpp @@ -3,6 +3,7 @@ cPeriodicTableMap::cPeriodicTableMap() { table["H"] = H; + table["D"] = D; table["Li"] = Li; table["Be"] = Be; table["B"] = B; @@ -46,6 +47,59 @@ int cPeriodicTableMap::count(string& element) { } +peptideType getPeptideTypeFromString(string s) { + if (s.compare("linear") == 0) { + return linear; + } + if (s.compare("cyclic") == 0) { + return cyclic; + } + if (s.compare("branched") == 0) { + return branched; + } + if (s.compare("lasso") == 0) { + return lasso; + } + if (s.compare("linearpolysaccharide") == 0) { + return linearpolysaccharide; + } + if (s.compare("other") == 0) { + return other; + } + + return other; +} + + +string getStringFromPeptideType(peptideType peptidetype) { + switch (peptidetype) + { + case linear: + return "linear"; + break; + case cyclic: + return "cyclic"; + break; + case branched: + return "branched"; + break; + case lasso: + return "lasso"; + break; + case linearpolysaccharide: + return "linearpolysaccharide"; + break; + case other: + return "other"; + break; + default: + break; + } + + return "other"; +} + + double charge(double mass, int charge) { return (mass + ((double)(charge - 1))*Hplus)/(double)charge; } @@ -57,38 +111,26 @@ double uncharge(double mass, int charge) { void fragmentDescription::store(ofstream& os) { - int size; - - size = (int)name.size(); - os.write((char *)&size, sizeof(int)); - os.write(name.c_str(), (int)name.size()); - - size = (int)summary.size(); - os.write((char *)&size, sizeof(int)); - os.write(summary.c_str(), (int)summary.size()); - + storeString(name, os); + storeString(summary, os); os.write((char *)&massdifference, sizeof(double)); os.write((char *)&nterminal, sizeof(bool)); os.write((char *)&cterminal, sizeof(bool)); os.write((char *)&parent, sizeof(fragmentIonType)); + os.write((char *)&positive, sizeof(bool)); + os.write((char *)&multiplier, sizeof(int)); } void fragmentDescription::load(ifstream& is) { - int size; - - is.read((char *)&size, sizeof(int)); - name.resize(size); - is.read(&name[0], name.size()); - - is.read((char *)&size, sizeof(int)); - summary.resize(size); - is.read(&summary[0], summary.size()); - + loadString(name, is); + loadString(summary, is); is.read((char *)&massdifference, sizeof(double)); is.read((char *)&nterminal, sizeof(bool)); is.read((char *)&cterminal, sizeof(bool)); is.read((char *)&parent, sizeof(fragmentIonType)); + is.read((char *)&positive, sizeof(bool)); + is.read((char *)&multiplier, sizeof(int)); } @@ -352,6 +394,150 @@ void cFragmentIons::recalculateFragments(bool cyclicnterminus, bool cyclicctermi fragmentions[ms_cterminal_ion_kplus].massdifference = H2O + Kplus; fragmentions[ms_cterminal_ion_kplus].parent = ms_cterminal_ion_kplus; + // initialize ion H+ + fragmentions[ms_hplus].nterminal = true; + fragmentions[ms_hplus].cterminal = true; + fragmentions[ms_hplus].name = "[M+H]+"; + fragmentions[ms_hplus].massdifference = Hplus; + fragmentions[ms_hplus].parent = ms_hplus; + fragmentions[ms_hplus].positive = true; + fragmentions[ms_hplus].multiplier = 1; + + // initialize ion Na+ + fragmentions[ms_naplus].nterminal = true; + fragmentions[ms_naplus].cterminal = true; + fragmentions[ms_naplus].name = "[M+Na]+"; + fragmentions[ms_naplus].massdifference = Naplus; + fragmentions[ms_naplus].parent = ms_naplus; + fragmentions[ms_naplus].positive = true; + fragmentions[ms_naplus].multiplier = 1; + + // initialize ion K+ + fragmentions[ms_kplus].nterminal = true; + fragmentions[ms_kplus].cterminal = true; + fragmentions[ms_kplus].name = "[M+K]+"; + fragmentions[ms_kplus].massdifference = Kplus; + fragmentions[ms_kplus].parent = ms_kplus; + fragmentions[ms_kplus].positive = true; + fragmentions[ms_kplus].multiplier = 1; + + // initialize ion H- + fragmentions[ms_hminus].nterminal = true; + fragmentions[ms_hminus].cterminal = true; + fragmentions[ms_hminus].name = "[M-H]-"; + fragmentions[ms_hminus].massdifference = -Hplus; + fragmentions[ms_hminus].parent = ms_hminus; + fragmentions[ms_hminus].positive = false; + fragmentions[ms_hminus].multiplier = 1; + + // initialize ion [3M+2Fe-5H]+ + fragmentions[ms_3M2Fe5H].nterminal = true; + fragmentions[ms_3M2Fe5H].cterminal = true; + fragmentions[ms_3M2Fe5H].name = "[3M+2Fe-5H]+"; + fragmentions[ms_3M2Fe5H].massdifference = 2*Fe - 6*H + Hplus; + fragmentions[ms_3M2Fe5H].parent = ms_3M2Fe5H; + fragmentions[ms_3M2Fe5H].positive = true; + fragmentions[ms_3M2Fe5H].multiplier = 3; + + // initialize ion [2M+Fe-2H]+ + fragmentions[ms_2MFe2H].nterminal = true; + fragmentions[ms_2MFe2H].cterminal = true; + fragmentions[ms_2MFe2H].name = "[2M+Fe-2H]+"; + fragmentions[ms_2MFe2H].massdifference = Fe - 3*H + Hplus; + fragmentions[ms_2MFe2H].parent = ms_2MFe2H; + fragmentions[ms_2MFe2H].positive = true; + fragmentions[ms_2MFe2H].multiplier = 2; + + // initialize ion [3M+Fe-2H]+ + fragmentions[ms_3MFe2H].nterminal = true; + fragmentions[ms_3MFe2H].cterminal = true; + fragmentions[ms_3MFe2H].name = "[3M+Fe-2H]+"; + fragmentions[ms_3MFe2H].massdifference = Fe - 3*H + Hplus; + fragmentions[ms_3MFe2H].parent = ms_3MFe2H; + fragmentions[ms_3MFe2H].positive = true; + fragmentions[ms_3MFe2H].multiplier = 3; + + // initialize ion [M+Fe-2H]+ + fragmentions[ms_MFe2H].nterminal = true; + fragmentions[ms_MFe2H].cterminal = true; + fragmentions[ms_MFe2H].name = "[M+Fe-2H]+"; + fragmentions[ms_MFe2H].massdifference = Fe - 3*H + Hplus; + fragmentions[ms_MFe2H].parent = ms_MFe2H; + fragmentions[ms_MFe2H].positive = true; + fragmentions[ms_MFe2H].multiplier = 1; + + // initialize ion [3M+2Fe-6H+Na]+ + fragmentions[ms_3M2Fe6HNa].nterminal = true; + fragmentions[ms_3M2Fe6HNa].cterminal = true; + fragmentions[ms_3M2Fe6HNa].name = "[3M+2Fe-6H+Na]+"; + fragmentions[ms_3M2Fe6HNa].massdifference = 2*Fe - 6*H + Naplus; + fragmentions[ms_3M2Fe6HNa].parent = ms_3M2Fe6HNa; + fragmentions[ms_3M2Fe6HNa].positive = true; + fragmentions[ms_3M2Fe6HNa].multiplier = 3; + + // initialize ion [2M+Fe-3H+Na]+ + fragmentions[ms_2MFe3HNa].nterminal = true; + fragmentions[ms_2MFe3HNa].cterminal = true; + fragmentions[ms_2MFe3HNa].name = "[2M+Fe-3H+Na]+"; + fragmentions[ms_2MFe3HNa].massdifference = Fe - 3*H + Naplus; + fragmentions[ms_2MFe3HNa].parent = ms_2MFe3HNa; + fragmentions[ms_2MFe3HNa].positive = true; + fragmentions[ms_2MFe3HNa].multiplier = 2; + + // initialize ion [3M+Fe-3H+Na]+ + fragmentions[ms_3MFe3HNa].nterminal = true; + fragmentions[ms_3MFe3HNa].cterminal = true; + fragmentions[ms_3MFe3HNa].name = "[3M+Fe-3H+Na]+"; + fragmentions[ms_3MFe3HNa].massdifference = Fe - 3*H + Naplus; + fragmentions[ms_3MFe3HNa].parent = ms_3MFe3HNa; + fragmentions[ms_3MFe3HNa].positive = true; + fragmentions[ms_3MFe3HNa].multiplier = 3; + + // initialize ion [M+Fe-3H+Na]+ + fragmentions[ms_MFe3HNa].nterminal = true; + fragmentions[ms_MFe3HNa].cterminal = true; + fragmentions[ms_MFe3HNa].name = "[M+Fe-3H+Na]+"; + fragmentions[ms_MFe3HNa].massdifference = Fe - 3*H + Naplus; + fragmentions[ms_MFe3HNa].parent = ms_MFe3HNa; + fragmentions[ms_MFe3HNa].positive = true; + fragmentions[ms_MFe3HNa].multiplier = 1; + + // initialize ion [3M+2Fe-7H]- + fragmentions[ms_3M2Fe7H].nterminal = true; + fragmentions[ms_3M2Fe7H].cterminal = true; + fragmentions[ms_3M2Fe7H].name = "[3M+2Fe-7H]-"; + fragmentions[ms_3M2Fe7H].massdifference = 2*Fe - 6*H - Hplus; + fragmentions[ms_3M2Fe7H].parent = ms_3M2Fe7H; + fragmentions[ms_3M2Fe7H].positive = false; + fragmentions[ms_3M2Fe7H].multiplier = 3; + + // initialize ion [2M+Fe-4H]- + fragmentions[ms_2MFe4H].nterminal = true; + fragmentions[ms_2MFe4H].cterminal = true; + fragmentions[ms_2MFe4H].name = "[2M+Fe-4H]-"; + fragmentions[ms_2MFe4H].massdifference = Fe - 3*H - Hplus; + fragmentions[ms_2MFe4H].parent = ms_2MFe4H; + fragmentions[ms_2MFe4H].positive = false; + fragmentions[ms_2MFe4H].multiplier = 2; + + // initialize ion [3M+Fe-4H]- + fragmentions[ms_3MFe4H].nterminal = true; + fragmentions[ms_3MFe4H].cterminal = true; + fragmentions[ms_3MFe4H].name = "[3M+Fe-4H]-"; + fragmentions[ms_3MFe4H].massdifference = Fe - 3*H - Hplus; + fragmentions[ms_3MFe4H].parent = ms_3MFe4H; + fragmentions[ms_3MFe4H].positive = false; + fragmentions[ms_3MFe4H].multiplier = 3; + + // initialize ion [M+Fe-4H]- + fragmentions[ms_MFe4H].nterminal = true; + fragmentions[ms_MFe4H].cterminal = true; + fragmentions[ms_MFe4H].name = "[M+Fe-4H]-"; + fragmentions[ms_MFe4H].massdifference = Fe - 3*H - Hplus; + fragmentions[ms_MFe4H].parent = ms_MFe4H; + fragmentions[ms_MFe4H].positive = false; + fragmentions[ms_MFe4H].multiplier = 1; + // initialize B-2H ion //fragmentions[b_ion_2H_loss].nterminal = true; //fragmentions[b_ion_2H_loss].cterminal = false; diff --git a/CycloBranch/core/cFragmentIons.h b/CycloBranch/core/cFragmentIons.h index 77597c7..66cda9b 100644 --- a/CycloBranch/core/cFragmentIons.h +++ b/CycloBranch/core/cFragmentIons.h @@ -14,6 +14,7 @@ #include #include #include +#include "core/utilities.h" using namespace std; @@ -24,6 +25,7 @@ const double Hplus = 1.00727645; const double Naplus = 22.989222; const double Kplus = 38.963158; const double H = 1.0078250321; +const double D = 2.014102; const double Li = 7.016004; const double Be = 9.012182; const double B = 11.009306; @@ -54,6 +56,7 @@ const double Se = 79.916519; const double Br = 78.918327; const double Mo = 97.905411; const double I = 126.904457; +const double e = H - Hplus; /** @@ -64,7 +67,7 @@ class cPeriodicTableMap { map table; public: - + /** \brief The constructor. @@ -113,10 +116,27 @@ enum peptideType { cyclic = 1, branched = 2, lasso = 3, - linearpolysaccharide = 4 + linearpolysaccharide = 4, + other = 5 }; +/** + \brief Convert a string to peptide type. + \param s string + \retval peptideType type of peptide +*/ +peptideType getPeptideTypeFromString(string s); + + +/** + \brief Convert the peptide type to a string. + \param peptidetype type of peptide + \retval string string +*/ +string getStringFromPeptideType(peptideType peptidetype); + + /** \brief Register peptideType by Qt. */ @@ -179,6 +199,22 @@ enum fragmentIonType { ms_cterminal_ion_hplus = 31, ms_cterminal_ion_naplus = 32, ms_cterminal_ion_kplus = 33, + ms_hplus = 34, + ms_naplus = 35, + ms_kplus = 36, + ms_hminus = 37, + ms_3M2Fe5H = 38, + ms_2MFe2H = 39, + ms_3MFe2H = 40, + ms_MFe2H = 41, + ms_3M2Fe6HNa = 42, + ms_2MFe3HNa = 43, + ms_3MFe3HNa = 44, + ms_MFe3HNa = 45, + ms_3M2Fe7H = 46, + ms_2MFe4H = 47, + ms_3MFe4H = 48, + ms_MFe4H = 49, //b_ion_2H_loss = 34, fragmentIonTypeEnd }; @@ -231,6 +267,18 @@ struct fragmentDescription { fragmentIonType parent; + /** + \brief True when the fragment is charged positively; false when the fragment is charged negatively. + */ + bool positive; + + + /** + \brief The multiplier (n) of M in [nM + H]+. + */ + int multiplier; + + /** \brief The default constructor. */ @@ -241,6 +289,8 @@ struct fragmentDescription { nterminal = false; cterminal = false; parent = fragmentIonTypeEnd; + positive = true; + multiplier = 1; } @@ -251,15 +301,19 @@ struct fragmentDescription { \param summary summary formula of the fragment \param nterminal true when the fragment is N-terminal \param cterminal true when the fragment is C-terminal + \param positive true when the fragment is charged positively; false when the fragment is charged negatively + \param multiplier the multiplier (n) of M in [nM + H]+ \param parent parent fragment type */ - fragmentDescription(string name, double massdifference, string summary, bool nterminal, bool cterminal, fragmentIonType parent = fragmentIonTypeEnd) { + fragmentDescription(string name, double massdifference, string summary, bool nterminal, bool cterminal, fragmentIonType parent = fragmentIonTypeEnd, bool positive = true, int multiplier = 1) { this->name = name; this->massdifference = massdifference; this->summary = summary; this->nterminal = nterminal; this->cterminal = cterminal; this->parent = parent; + this->positive = positive; + this->multiplier = multiplier; } diff --git a/CycloBranch/core/cParameters.cpp b/CycloBranch/core/cParameters.cpp index 46bb8d3..a6ee67f 100644 --- a/CycloBranch/core/cParameters.cpp +++ b/CycloBranch/core/cParameters.cpp @@ -30,7 +30,7 @@ void cParameters::clear() { maximumcumulativemass = 0; generatebrickspermutations = true; maximumnumberofthreads = 1; - mode = 0; + mode = denovoengine; scoretype = b_ions; clearhitswithoutparent = false; cyclicnterminus = false; @@ -46,6 +46,8 @@ void cParameters::clear() { searchedsequenceTmodif = ""; maximumnumberofcandidates = 50000; blindedges = 2; + sequencedatabase.clear(); + sequencedatabasefilename = ""; searchedmodifications.clear(); searchedmodifications.push_back(fragmentDescription("", 0, "", true, true)); @@ -61,6 +63,7 @@ int cParameters::checkAndPrepare() { string errormessage = ""; ifstream peakliststream; ifstream bricksdatabasestream; + ifstream sequencedatabasestream; regex rx; ePeakListFileFormat peaklistfileformat; string s; @@ -68,184 +71,199 @@ int cParameters::checkAndPrepare() { // peaklist check if (!error) { - if (peaklistfilename == "") { - error = true; - errormessage = "A peaklist is not specified."; - } - else { - peaklistfileformat = txt; + + peaklistfileformat = txt; - try { + try { - rx = "\\.[mM][gG][fF]$"; - // Mascot Generic Format - if (regex_search(peaklistfilename, rx)) { - peaklistfileformat = mgf; - } + rx = "\\.[mM][gG][fF]$"; + // Mascot Generic Format + if (regex_search(peaklistfilename, rx)) { + peaklistfileformat = mgf; + } - rx = "\\.[mM][zZ][mM][lL]$"; - // mzML - if (regex_search(peaklistfilename, rx)) { - peaklistfileformat = mzML; - } + rx = "\\.[mM][zZ][mM][lL]$"; + // mzML + if (regex_search(peaklistfilename, rx)) { + peaklistfileformat = mzML; + } - rx = "\\.[mM][zZ][xX][mM][lL]$"; - // mzXML - if (regex_search(peaklistfilename, rx)) { - peaklistfileformat = mzXML; - } + rx = "\\.[mM][zZ][xX][mM][lL]$"; + // mzXML + if (regex_search(peaklistfilename, rx)) { + peaklistfileformat = mzXML; + } - rx = "\\.[bB][aA][fF]$"; - // Bruker Analysis File - if (regex_search(peaklistfilename, rx)) { - peaklistfileformat = baf; + rx = "\\.[bB][aA][fF]$"; + // Bruker Analysis File + if (regex_search(peaklistfilename, rx)) { + peaklistfileformat = baf; + } + + } + catch (std::regex_error& e) { + error = true; + errormessage = "cParameters::checkAndPrepare: regex_search failed, error no. " + to_string((int)e.code()) + "\n"; + } + + if (!error) { + + switch (peaklistfileformat) + { + case txt: + peakliststream.open(peaklistfilename); + break; + case mgf: + peakliststream.open(peaklistfilename); + break; + case mzML: + case mzXML: + *os << "Converting the file " + peaklistfilename + " to .mgf ... "; + s = "External\\any2mgf.bat \"" + peaklistfilename + "\""; + if (system(s.c_str()) != 0) { + error = true; + errormessage = "The file cannot be converted.\n"; + errormessage += "Does the file '" + peaklistfilename + "' exist ?\n"; + errormessage += "Do you have OpenMS installed ?\n"; + errormessage += "Do you have path to the OpenMS/bin/FileConverter.exe in your PATH variable ?\n"; + errormessage += "Is the directory with the file '" + peaklistfilename + "' writable ?\n"; + errormessage += "Do you have 'any2mgf.bat' file located in the 'External' folder ?\n"; } - } - catch (std::regex_error& e) { - error = true; - errormessage = "cParameters::checkAndPrepare: regex_search failed, error no. " + to_string((int)e.code()) + "\n"; + if (!error) { + *os << "ok" << endl << endl; + peakliststream.open(peaklistfilename + ".mgf"); + } + break; + case baf: + *os << "Converting the file " + peaklistfilename + " ... "; + s = "External\\baf2csv.bat \"" + peaklistfilename + "\""; + if (system(s.c_str()) != 0) { + error = true; + errormessage = "The file cannot be converted.\n"; + errormessage += "Does the file '" + peaklistfilename + "' exist ?\n"; + errormessage += "Do you have Bruker Daltonik's CompassXport installed ?\n"; + errormessage += "Do you have path to the CompassXport.exe in your PATH variable ?\n"; + errormessage += "Is the directory with the file '" + peaklistfilename + "' writable ?\n"; + errormessage += "Do you have 'baf2csv.bat' file located in the 'External' folder ?\n"; + } + + if (!error) { + *os << "ok" << endl << endl; + peakliststream.open(peaklistfilename + ".csv"); + } + break; + default: + break; } - if (!error) { + } + - switch (peaklistfileformat) - { + if (!error) { + if (!peakliststream.good()) { + error = true; + errormessage = "Cannot open the file '" + peaklistfilename + "'."; + } + else { + if (os) { + *os << "Loading the peak list... "; + } + switch (peaklistfileformat) { case txt: - peakliststream.open(peaklistfilename); - break; - case mgf: - peakliststream.open(peaklistfilename); + peaklist.loadFromPlainTextStream(peakliststream); break; case mzML: case mzXML: - *os << "Converting the file " + peaklistfilename + " to .mgf ... "; - s = "External\\any2mgf.bat \"" + peaklistfilename + "\""; - if (system(s.c_str()) != 0) { - error = true; - errormessage = "The file cannot be converted.\n"; - errormessage += "Does the file '" + peaklistfilename + "' exist ?\n"; - errormessage += "Do you have OpenMS installed ?\n"; - errormessage += "Do you have path to the OpenMS/bin/FileConverter.exe in your PATH variable ?\n"; - errormessage += "Is the directory with the file '" + peaklistfilename + "' writable ?\n"; - errormessage += "Do you have 'any2mgf.bat' file located in the 'External' folder ?\n"; - } - - if (!error) { - *os << "ok" << endl << endl; - peakliststream.open(peaklistfilename + ".mgf"); - } + case mgf: + peaklist.loadFromMGFStream(peakliststream); break; case baf: - *os << "Converting the file " + peaklistfilename + " ... "; - s = "External\\baf2csv.bat \"" + peaklistfilename + "\""; - if (system(s.c_str()) != 0) { - error = true; - errormessage = "The file cannot be converted.\n"; - errormessage += "Does the file '" + peaklistfilename + "' exist ?\n"; - errormessage += "Do you have Bruker Daltonik's CompassXport installed ?\n"; - errormessage += "Do you have path to the CompassXport.exe in your PATH variable ?\n"; - errormessage += "Is the directory with the file '" + peaklistfilename + "' writable ?\n"; - errormessage += "Do you have 'baf2csv.bat' file located in the 'External' folder ?\n"; - } - - if (!error) { - *os << "ok" << endl << endl; - peakliststream.open(peaklistfilename + ".csv"); - } + peaklist.loadFromBAFStream(peakliststream); break; default: break; } - - } - - - if (!error) { - if (!peakliststream.good()) { - error = true; - errormessage = "Cannot open the file '" + peaklistfilename + "'."; - } - else { - if (os) { - *os << "Loading the peak list... "; - } - switch (peaklistfileformat) { - case txt: - peaklist.loadFromPlainTextStream(peakliststream); - break; - case mzML: - case mzXML: - case mgf: - peaklist.loadFromMGFStream(peakliststream); - break; - case baf: - peaklist.loadFromBAFStream(peakliststream); - break; - default: - break; - } - if (os) { - *os << "ok" << endl << endl; - } + if (os) { + *os << "ok" << endl << endl; } - peakliststream.close(); } + peakliststream.close(); } + } // bricksdatabase check - if (!error) { - if (bricksdatabasefilename == "") { + if (!error && ((mode == denovoengine) || (mode == singlecomparison) || (mode == databasesearch))) { + + bricksdatabasestream.open(bricksdatabasefilename); + if (!bricksdatabasestream.good()) { error = true; - errormessage = "A database of bricks is not specified."; + errormessage = "Cannot open the file '" + bricksdatabasefilename + "'."; } else { - bricksdatabasestream.open(bricksdatabasefilename); - if (!bricksdatabasestream.good()) { + if (os) { + *os << "Loading the database of bricks... "; + } + if (bricksdatabase.loadFromPlainTextStream(bricksdatabasestream, errormessage) == -1) { error = true; - errormessage = "Cannot open the file '" + bricksdatabasefilename + "'."; } else { if (os) { - *os << "Loading the database of bricks... "; - } - if (bricksdatabase.loadFromPlainTextStream(bricksdatabasestream, errormessage) == -1) { - error = true; - } - else { - if (os) { - *os << "ok" << endl << endl; - } + *os << "ok" << endl << endl; } } - bricksdatabasestream.close(); + } + bricksdatabasestream.close(); - // check for redundant acronyms and [] - for (int i = 0; i < (int)bricksdatabase.size(); i++) { - for (int j = 0; j < (int)bricksdatabase[i].getAcronyms().size(); j++) { + bricksdatabase.sortbyMass(); - if ((bricksdatabase[i].getAcronyms()[j].find('[') != string::npos) || (bricksdatabase[i].getAcronyms()[j].find(']') != string::npos)) { - error = true; - errormessage = "Forbidden symbol '[' or ']' used in the acronym '" + bricksdatabase[i].getAcronyms()[j] + "' of the brick no. " + to_string(i + 1) + ".\n\n"; - } + // check for redundant acronyms and [] + for (int i = 0; i < (int)bricksdatabase.size(); i++) { + for (int j = 0; j < (int)bricksdatabase[i].getAcronyms().size(); j++) { - for (int k = i; k < (int)bricksdatabase.size(); k++) { - for (int m = j; m < (int)bricksdatabase[k].getAcronyms().size(); m++) { - if ((i == k) && (j == m)) { - continue; - } - if (bricksdatabase[i].getAcronyms()[j].compare(bricksdatabase[k].getAcronyms()[m]) == 0) { - error = true; - errormessage = "Redundant acronym '" + bricksdatabase[i].getAcronyms()[j] + "' used in brick no. " + to_string(i + 1) + " and brick no. " + to_string(k + 1) + ".\n\n"; - } + if ((bricksdatabase[i].getAcronyms()[j].find('[') != string::npos) || (bricksdatabase[i].getAcronyms()[j].find(']') != string::npos)) { + error = true; + errormessage = "Forbidden symbol '[' or ']' used in the acronym '" + bricksdatabase[i].getAcronyms()[j] + "' of the brick no. " + to_string(i + 1) + ".\n\n"; + } + + for (int k = i; k < (int)bricksdatabase.size(); k++) { + for (int m = j; m < (int)bricksdatabase[k].getAcronyms().size(); m++) { + if ((i == k) && (j == m)) { + continue; + } + if (bricksdatabase[i].getAcronyms()[j].compare(bricksdatabase[k].getAcronyms()[m]) == 0) { + error = true; + errormessage = "Redundant acronym '" + bricksdatabase[i].getAcronyms()[j] + "' used in brick no. " + to_string(i + 1) + " and brick no. " + to_string(k + 1) + ".\n\n"; } } } } + } + + } + + // sequencedatabase check + if (!error && ((mode == databasesearch) || (mode == dereplication))) { + + sequencedatabasestream.open(sequencedatabasefilename); + if (!sequencedatabasestream.good()) { + error = true; + errormessage = "Cannot open the file '" + sequencedatabasefilename + "'."; } + else { + if (os) { + *os << "Loading the database of sequences... "; + } + sequencedatabase.loadFromPlainTextStream(sequencedatabasestream); + if (os) { + *os << "ok" << endl << endl; + } + } + sequencedatabasestream.close(); + } @@ -269,6 +287,10 @@ int cParameters::checkAndPrepare() { case linearpolysaccharide: initializeFragmentIonsForDeNovoGraphOfLinearPolysaccharide(fragmentionsfordenovograph); break; + case other: + error = true; + errormessage = "Invalid peptide type 'other'.\n\n"; + break; default: error = true; errormessage = "Undefined peptide type.\n\n"; @@ -312,6 +334,9 @@ string cParameters::printToString() { case linearpolysaccharide: s += "Linear polysaccharide (beta version)\n"; break; + case other: + s += "Other\n"; + break; default: break; } @@ -340,12 +365,18 @@ string cParameters::printToString() { } s += "Mode: "; - switch (mode) { - case 0: + switch ((modeType)mode) { + case denovoengine: s += "De Novo Search Engine"; break; - case 1: - s += "Compare Spectrum of Searched Sequence with Peaklist"; + case singlecomparison: + s += "Compare Peaklist with Spectrum of Searched Sequence"; + break; + case databasesearch: + s += "Compare Peaklist with Database - MS/MS data"; + break; + case dereplication: + s += "Compare Peaklist with Database - MS data"; break; default: break; @@ -360,10 +391,10 @@ string cParameters::printToString() { s += "Number of b-ions"; break; case b_ions_and_b_water_loss_ions: - s += "Number of b-ions + water loss b-ions"; + s += "Number of b-ions + dehydrated b-ions"; break; case b_ions_and_b_ammonia_loss_ions: - s += "Number of b-ions + ammonia loss b-ions"; + s += "Number of b-ions + deamidated b-ions"; break; case y_ions_and_b_ions: s += "Number of y-ions + b-ions (not for cyclic peptides)"; @@ -430,6 +461,8 @@ string cParameters::printToString() { } s += "\n"; + s += "Sequence Database File: " + sequencedatabasefilename + "\n"; + s += "Searched Peptide Sequence: " + originalsearchedsequence + "\n"; s += "N-terminal Modification of Searched Peptide Sequence: " + searchedsequenceNtermmodif + "\n"; s += "C-terminal Modification of Searched Peptide Sequence: " + searchedsequenceCtermmodif + "\n"; @@ -463,10 +496,7 @@ void cParameters::store(ofstream& os) { os.write((char *)&peptidetype, sizeof(peptideType)); - size = (int)peaklistfilename.size(); - os.write((char *)&size, sizeof(int)); - os.write(peaklistfilename.c_str(), peaklistfilename.size()); - + storeString(peaklistfilename, os); peaklist.store(os); os.write((char *)&precursormass, sizeof(double)); @@ -477,10 +507,7 @@ void cParameters::store(ofstream& os) { os.write((char *)&minimumrelativeintensitythreshold, sizeof(double)); os.write((char *)&minimummz, sizeof(double)); - size = (int)bricksdatabasefilename.size(); - os.write((char *)&size, sizeof(int)); - os.write(bricksdatabasefilename.c_str(), bricksdatabasefilename.size()); - + storeString(bricksdatabasefilename, os); bricksdatabase.store(os); os.write((char *)&maximumbricksincombinationbegin, sizeof(int)); @@ -490,7 +517,7 @@ void cParameters::store(ofstream& os) { os.write((char *)&maximumcumulativemass, sizeof(double)); os.write((char *)&generatebrickspermutations, sizeof(bool)); os.write((char *)&maximumnumberofthreads, sizeof(int)); - os.write((char *)&mode, sizeof(int)); + os.write((char *)&mode, sizeof(modeType)); os.write((char *)&scoretype, sizeof(scoreType)); os.write((char *)&clearhitswithoutparent, sizeof(bool)); os.write((char *)&cyclicnterminus, sizeof(bool)); @@ -498,37 +525,20 @@ void cParameters::store(ofstream& os) { os.write((char *)&enablescrambling, sizeof(bool)); os.write((char *)&hitsreported, sizeof(int)); - size = (int)sequencetag.size(); - os.write((char *)&size, sizeof(int)); - os.write(sequencetag.c_str(), sequencetag.size()); - - size = (int)originalsequencetag.size(); - os.write((char *)&size, sizeof(int)); - os.write(originalsequencetag.c_str(), originalsequencetag.size()); - - size = (int)searchedsequence.size(); - os.write((char *)&size, sizeof(int)); - os.write(searchedsequence.c_str(), searchedsequence.size()); - - size = (int)originalsearchedsequence.size(); - os.write((char *)&size, sizeof(int)); - os.write(originalsearchedsequence.c_str(), originalsearchedsequence.size()); - - size = (int)searchedsequenceNtermmodif.size(); - os.write((char *)&size, sizeof(int)); - os.write(searchedsequenceNtermmodif.c_str(), searchedsequenceNtermmodif.size()); - - size = (int)searchedsequenceCtermmodif.size(); - os.write((char *)&size, sizeof(int)); - os.write(searchedsequenceCtermmodif.c_str(), searchedsequenceCtermmodif.size()); - - size = (int)searchedsequenceTmodif.size(); - os.write((char *)&size, sizeof(int)); - os.write(searchedsequenceTmodif.c_str(), searchedsequenceTmodif.size()); + storeString(sequencetag, os); + storeString(originalsequencetag, os); + storeString(searchedsequence, os); + storeString(originalsearchedsequence, os); + storeString(searchedsequenceNtermmodif, os); + storeString(searchedsequenceCtermmodif, os); + storeString(searchedsequenceTmodif, os); os.write((char *)&maximumnumberofcandidates, sizeof(int)); os.write((char *)&blindedges, sizeof(int)); + storeString(sequencedatabasefilename, os); + sequencedatabase.store(os); + size = (int)searchedmodifications.size(); os.write((char *)&size, sizeof(int)); for (int i = 0; i < (int)searchedmodifications.size(); i++) { @@ -558,10 +568,7 @@ void cParameters::load(ifstream& is) { is.read((char *)&peptidetype, sizeof(peptideType)); - is.read((char *)&size, sizeof(int)); - peaklistfilename.resize(size); - is.read(&peaklistfilename[0], peaklistfilename.size()); - + loadString(peaklistfilename, is); peaklist.load(is); is.read((char *)&precursormass, sizeof(double)); @@ -572,10 +579,7 @@ void cParameters::load(ifstream& is) { is.read((char *)&minimumrelativeintensitythreshold, sizeof(double)); is.read((char *)&minimummz, sizeof(double)); - is.read((char *)&size, sizeof(int)); - bricksdatabasefilename.resize(size); - is.read(&bricksdatabasefilename[0], bricksdatabasefilename.size()); - + loadString(bricksdatabasefilename, is); bricksdatabase.load(is); is.read((char *)&maximumbricksincombinationbegin, sizeof(int)); @@ -585,7 +589,7 @@ void cParameters::load(ifstream& is) { is.read((char *)&maximumcumulativemass, sizeof(double)); is.read((char *)&generatebrickspermutations, sizeof(bool)); is.read((char *)&maximumnumberofthreads, sizeof(int)); - is.read((char *)&mode, sizeof(int)); + is.read((char *)&mode, sizeof(modeType)); is.read((char *)&scoretype, sizeof(scoreType)); is.read((char *)&clearhitswithoutparent, sizeof(bool)); is.read((char *)&cyclicnterminus, sizeof(bool)); @@ -593,37 +597,20 @@ void cParameters::load(ifstream& is) { is.read((char *)&enablescrambling, sizeof(bool)); is.read((char *)&hitsreported, sizeof(int)); - is.read((char *)&size, sizeof(int)); - sequencetag.resize(size); - is.read(&sequencetag[0], sequencetag.size()); - - is.read((char *)&size, sizeof(int)); - originalsequencetag.resize(size); - is.read(&originalsequencetag[0], originalsequencetag.size()); - - is.read((char *)&size, sizeof(int)); - searchedsequence.resize(size); - is.read(&searchedsequence[0], searchedsequence.size()); - - is.read((char *)&size, sizeof(int)); - originalsearchedsequence.resize(size); - is.read(&originalsearchedsequence[0], originalsearchedsequence.size()); - - is.read((char *)&size, sizeof(int)); - searchedsequenceNtermmodif.resize(size); - is.read(&searchedsequenceNtermmodif[0], searchedsequenceNtermmodif.size()); - - is.read((char *)&size, sizeof(int)); - searchedsequenceCtermmodif.resize(size); - is.read(&searchedsequenceCtermmodif[0], searchedsequenceCtermmodif.size()); - - is.read((char *)&size, sizeof(int)); - searchedsequenceTmodif.resize(size); - is.read(&searchedsequenceTmodif[0], searchedsequenceTmodif.size()); + loadString(sequencetag, is); + loadString(originalsequencetag, is); + loadString(searchedsequence, is); + loadString(originalsearchedsequence, is); + loadString(searchedsequenceNtermmodif, is); + loadString(searchedsequenceCtermmodif, is); + loadString(searchedsequenceTmodif, is); is.read((char *)&maximumnumberofcandidates, sizeof(int)); is.read((char *)&blindedges, sizeof(int)); + loadString(sequencedatabasefilename, is); + sequencedatabase.load(is); + is.read((char *)&size, sizeof(int)); searchedmodifications.resize(size); for (int i = 0; i < (int)searchedmodifications.size(); i++) { diff --git a/CycloBranch/core/cParameters.h b/CycloBranch/core/cParameters.h index 2680a99..119a10d 100644 --- a/CycloBranch/core/cParameters.h +++ b/CycloBranch/core/cParameters.h @@ -11,12 +11,24 @@ #include #include "core/cPeaksList.h" #include "core/cBricksDatabase.h" +#include "core/cSequenceDatabase.h" class cMainThread; using namespace std; +/** + \brief Running modes of the application. +*/ +enum modeType { + denovoengine = 0, + singlecomparison = 1, + databasesearch = 2, + dereplication = 3 +}; + + /** \brief Peak list file formats supported by the application. */ @@ -58,7 +70,7 @@ class cParameters { /** - \brief An internal structure representing a peak list. + \brief A structure representing a peak list. */ cPeaksList peaklist; @@ -112,7 +124,7 @@ class cParameters { /** - \brief An internal structure representing a database of bricks. + \brief A structure representing a database of bricks. */ cBricksDatabase bricksdatabase; @@ -162,7 +174,7 @@ class cParameters { /** \brief Program mode. */ - int mode; + modeType mode; /** @@ -255,6 +267,18 @@ class cParameters { int blindedges; + /** + \brief A file name of a sequence database. + */ + string sequencedatabasefilename; + + + /** + \brief A structure representing a database of sequences. + */ + cSequenceDatabase sequencedatabase; + + /** \brief A vector of searched N-terminal and C-terminal modifications. */ diff --git a/CycloBranch/core/cPeak.cpp b/CycloBranch/core/cPeak.cpp index 20fbc2b..605ced6 100644 --- a/CycloBranch/core/cPeak.cpp +++ b/CycloBranch/core/cPeak.cpp @@ -31,19 +31,10 @@ bool cPeak::empty() { void cPeak::store(ofstream& os) { - int size; - os.write((char *)&mzratio, sizeof(double)); os.write((char *)&intensity, sizeof(double)); - - size = (int)description.size(); - os.write((char *)&size, sizeof(int)); - os.write(description.c_str(), description.size()); - - size = (int)matchdescription.size(); - os.write((char *)&size, sizeof(int)); - os.write(matchdescription.c_str(), matchdescription.size()); - + storeString(description, os); + storeString(matchdescription, os); os.write((char *)&iontype, sizeof(fragmentIonType)); os.write((char *)&matched, sizeof(int)); os.write((char *)&matchedid, sizeof(int)); @@ -57,19 +48,10 @@ void cPeak::store(ofstream& os) { void cPeak::load(ifstream& is) { - int size; - is.read((char *)&mzratio, sizeof(double)); is.read((char *)&intensity, sizeof(double)); - - is.read((char *)&size, sizeof(int)); - description.resize(size); - is.read(&description[0], description.size()); - - is.read((char *)&size, sizeof(int)); - matchdescription.resize(size); - is.read(&matchdescription[0], matchdescription.size()); - + loadString(description, is); + loadString(matchdescription, is); is.read((char *)&iontype, sizeof(fragmentIonType)); is.read((char *)&matched, sizeof(int)); is.read((char *)&matchedid, sizeof(int)); diff --git a/CycloBranch/core/cSequence.cpp b/CycloBranch/core/cSequence.cpp new file mode 100644 index 0000000..b488a28 --- /dev/null +++ b/CycloBranch/core/cSequence.cpp @@ -0,0 +1,189 @@ +#include "core/cSequence.h" + + +cSequence::cSequence() { + clear(); +} + + +void cSequence::clear() { + peptidetype = linear; + sequence = ""; + nterminalmodification = ""; + cterminalmodification = ""; + branchmodification = ""; + name = ""; + summary.clear(); + reference = ""; +} + + +void cSequence::store(ofstream& os) { + os.write((char *)&peptidetype, sizeof(peptideType)); + storeString(sequence, os); + storeString(nterminalmodification, os); + storeString(cterminalmodification, os); + storeString(branchmodification, os); + storeString(name, os); + summary.store(os); + storeString(reference, os); +} + + +void cSequence::load(ifstream& is) { + is.read((char *)&peptidetype, sizeof(peptideType)); + loadString(sequence, is); + loadString(nterminalmodification, is); + loadString(cterminalmodification, is); + loadString(branchmodification, is); + loadString(name, is); + summary.load(is); + loadString(reference, is); +} + + +peptideType cSequence::getPeptideType() { + return peptidetype; +} + + +string& cSequence::getSequence() { + return sequence; +} + + +string& cSequence::getName() { + return name; +} + + +string& cSequence::getReference() { + return reference; +} + + +void cSequence::setPeptideType(peptideType peptidetype) { + this->peptidetype = peptidetype; +} + + +void cSequence::setSequence(string& sequence) { + this->sequence = sequence; +} + + +void cSequence::setName(string& name) { + this->name = name; +} + + +void cSequence::setReference(string& reference) { + this->reference = reference; +} + + +void cSequence::setNTterminalModification(string& modification) { + nterminalmodification = modification; +} + + +void cSequence::setCTterminalModification(string& modification) { + cterminalmodification = modification; +} + + +void cSequence::setBranchModification(string& modification) { + branchmodification = modification; +} + + + +string& cSequence::getNTterminalModification() { + return nterminalmodification; +} + + +string& cSequence::getCTterminalModification() { + return cterminalmodification; +} + + +string& cSequence::getBranchModification() { + return branchmodification; +} + + +string cSequence::getNameWithReferenceAsHTMLString() { + regex rx; + string s = ""; + bool correctreference = false; + + try { + + // ChemSpider + if (!correctreference) { + rx = "^CSID: [0-9]+$"; + if (regex_search(reference, rx)) { + s += ""; + s += name; + s += ""; + correctreference = true; + } + } + + // PubChem + if (!correctreference) { + rx = "^CID: [0-9]+$"; + if (regex_search(reference, rx)) { + s += ""; + s += name; + s += ""; + correctreference = true; + } + } + + // Norine + if (!correctreference) { + rx = "^NOR[0-9]+$"; + if (regex_search(reference, rx)) { + s += ""; + s += name; + s += ""; + correctreference = true; + } + } + + // Lipidmaps (undocumented) + if (!correctreference) { + rx = "^LM([A-Z]|[0-9])+$"; + if (regex_search(reference, rx)) { + s += ""; + s += name; + s += ""; + correctreference = true; + } + } + + } + catch (std::regex_error& e) { + e; + // nothing to do + } + + if (!correctreference) { + s = name; + } + + return s; +} + + +void cSequence::setSummaryFormula(string& formula) { + summary.setFormula(formula); +} + + +string& cSequence::getSummaryFormula() { + return summary.getFormula(); +} + diff --git a/CycloBranch/core/cSequence.h b/CycloBranch/core/cSequence.h new file mode 100644 index 0000000..d23d904 --- /dev/null +++ b/CycloBranch/core/cSequence.h @@ -0,0 +1,186 @@ +/** + \file cSequence.h + \brief The representation of a sequence. +*/ + + +#ifndef _CSEQUENCE_H +#define _CSEQUENCE_H + +#include +#include +#include +#include +#include "core/utilities.h" +#include "core/cFragmentIons.h" +#include "core/cSummaryFormula.h" + + +using namespace std; + + +/** + \brief The class representing a sequence. +*/ +class cSequence { + + peptideType peptidetype; + string sequence; + string nterminalmodification; + string cterminalmodification; + string branchmodification; + string name; + cSummaryFormula summary; + string reference; + +public: + + + /** + \brief The constructor. + */ + cSequence(); + + + /** + \brief Clear the structure. + */ + void clear(); + + + /** + \brief Store the structure into an output stream. + \param os an output stream + */ + void store(ofstream& os); + + + /** + \brief Load the structure from an input stream. + \param is an input stream + */ + void load(ifstream& is); + + + /** + \brief Get peptide type. + \retval peptideType peptide type + */ + peptideType getPeptideType(); + + + /** + \brief Get sequence. + \retval string sequence + */ + string& getSequence(); + + + /** + \brief Get name. + \retval string name + */ + string& getName(); + + + /** + \brief Get reference. + \retval string reference + */ + string& getReference(); + + + /** + \brief Set peptide type. + \param peptidetype peptide type + */ + void setPeptideType(peptideType peptidetype); + + + /** + \brief Set sequence. + \param sequence sequence + */ + void setSequence(string& sequence); + + + /** + \brief Set name. + \param name name + */ + void setName(string& name); + + + /** + \brief Set reference. + \param reference reference + */ + void setReference(string& reference); + + + /** + \brief Set N-terminal modification. + \param modification name of an N-terminal modification + */ + void setNTterminalModification(string& modification); + + + /** + \brief Set C-terminal modification. + \param modification name of a C-terminal modification + */ + void setCTterminalModification(string& modification); + + + /** + \brief Set branch modification. + \param modification name of a branch modification + */ + void setBranchModification(string& modification); + + + /** + \brief Get N-terminal modification. + \retval string name of N-terminal modification + */ + string& getNTterminalModification(); + + + /** + \brief Get C-terminal modification. + \retval string name of C-terminal modification + */ + string& getCTterminalModification(); + + + /** + \brief Get branch modification. + \retval string name of a branch modification + */ + string& getBranchModification(); + + + /** + \brief Get name of sequence as a HTML link to sequence reference. + \retval string HTML link + */ + string getNameWithReferenceAsHTMLString(); + + + /** + \brief Set the summary formula. + \param formula summary formula + */ + void setSummaryFormula(string& formula); + + + /** + \brief Get the summary formula. + \retval string summary formula + */ + string& getSummaryFormula(); + +}; + + +#endif \ No newline at end of file diff --git a/CycloBranch/core/cSequenceDatabase.cpp b/CycloBranch/core/cSequenceDatabase.cpp new file mode 100644 index 0000000..0f364d1 --- /dev/null +++ b/CycloBranch/core/cSequenceDatabase.cpp @@ -0,0 +1,194 @@ +#include "core/cSequenceDatabase.h" + + +#include "gui/cMainThread.h" + + +cSequenceDatabase::cSequenceDatabase() { + clear(); +} + + +void cSequenceDatabase::loadFromPlainTextStream(ifstream &stream) { + string s, type; + cSequence sequence; + size_t pos; + + sequences.clear(); + while (stream.good()) { + getline(stream,s); + + // skip a comment + if ((s.length() > 0) && (s[0] == '#')) { + continue; + } + + sequence.clear(); + + // load the peptide type + pos = s.find('\t'); + if (pos != string::npos) { + type = s.substr(0, pos); + if (type.compare("linear") == 0) { + sequence.setPeptideType(linear); + } + if (type.compare("cyclic") == 0) { + sequence.setPeptideType(cyclic); + } + if (type.compare("branched") == 0) { + sequence.setPeptideType(branched); + } + if (type.compare("lasso") == 0) { + sequence.setPeptideType(lasso); + } + if (type.compare("linearpolysaccharide") == 0) { + sequence.setPeptideType(linearpolysaccharide); + } + if (type.compare("other") == 0) { + sequence.setPeptideType(other); + } + s = s.substr(pos + 1); + } + else { + break; + } + + // load name + pos = s.find('\t'); + if (pos != string::npos) { + sequence.setName(s.substr(0, pos)); + s = s.substr(pos + 1); + } + else { + break; + } + + // load summary formula + pos = s.find('\t'); + if (pos != string::npos) { + sequence.setSummaryFormula(s.substr(0, pos)); + s = s.substr(pos + 1); + } + else { + break; + } + + // load mass + pos = s.find('\t'); + if (pos != string::npos) { + // the value is ignored + s = s.substr(pos + 1); + } + else { + break; + } + + // load sequence + pos = s.find('\t'); + if (pos != string::npos) { + sequence.setSequence(s.substr(0, pos)); + s = s.substr(pos + 1); + } + else { + break; + } + + // load N-terminal modification + pos = s.find('\t'); + if (pos != string::npos) { + sequence.setNTterminalModification(s.substr(0, pos)); + s = s.substr(pos + 1); + } + else { + break; + } + + // load C-terminal modification + pos = s.find('\t'); + if (pos != string::npos) { + sequence.setCTterminalModification(s.substr(0, pos)); + s = s.substr(pos + 1); + } + else { + break; + } + + // load branch modification + pos = s.find('\t'); + if (pos != string::npos) { + sequence.setBranchModification(s.substr(0, pos)); + s = s.substr(pos + 1); + } + else { + break; + } + + // load reference + sequence.setReference(s); + + sequences.push_back(sequence); + } + +} + + +void cSequenceDatabase::storeToPlainTextStream(ofstream &stream) { + cSummaryFormula formula; + for (int i = 0; i < (int)sequences.size(); i++) { + stream << getStringFromPeptideType(sequences[i].getPeptideType()) << "\t"; + stream << sequences[i].getName() << "\t"; + stream << sequences[i].getSummaryFormula() << "\t"; + formula.setFormula(sequences[i].getSummaryFormula()); + stream << std::fixed << std::setprecision(10) << formula.getMass() << "\t"; + stream << sequences[i].getSequence() << "\t"; + stream << sequences[i].getNTterminalModification() << "\t"; + stream << sequences[i].getCTterminalModification() << "\t"; + stream << sequences[i].getBranchModification() << "\t"; + stream << sequences[i].getReference() << endl; + } +} + + +int cSequenceDatabase::size() { + return (int)sequences.size(); +} + + +cSequence& cSequenceDatabase::operator[](int position) { + return sequences[position]; +} + + +void cSequenceDatabase::clear() { + sequences.clear(); +} + + +void cSequenceDatabase::push_back(cSequence& sequence) { + sequences.push_back(sequence); +} + + +void cSequenceDatabase::store(ofstream& os) { + int size; + + size = (int)sequences.size(); + os.write((char *)&size, sizeof(int)); + + for (int i = 0; i < (int)sequences.size(); i++) { + sequences[i].store(os); + } +} + + +void cSequenceDatabase::load(ifstream& is) { + int size; + + is.read((char *)&size, sizeof(int)); + sequences.resize(size); + + for (int i = 0; i < (int)sequences.size(); i++) { + sequences[i].load(is); + } +} + diff --git a/CycloBranch/core/cSequenceDatabase.h b/CycloBranch/core/cSequenceDatabase.h new file mode 100644 index 0000000..6937550 --- /dev/null +++ b/CycloBranch/core/cSequenceDatabase.h @@ -0,0 +1,97 @@ +/** + \file cSequenceDatabase.h + \brief The database of sequences. +*/ + + +#ifndef _CSEQUENCEDATABASE_H +#define _CSEQUENCEDATABASE_H + +#include +#include +#include +#include +#include "core/cSequence.h" + + +using namespace std; + + +class cMainThread; + + +/** + \brief The class representing a database of sequences. +*/ +class cSequenceDatabase { + + vector sequences; + +public: + + + /** + \brief The constructor. + */ + cSequenceDatabase(); + + + /** + \brief Load the database of sequences from a plain text stream. + \param stream reference to an input file stream + */ + void loadFromPlainTextStream(ifstream &stream); + + + /** + \brief Store the database of sequences into a plain text stream. + \param stream reference to an output file stream + */ + void storeToPlainTextStream(ofstream &stream); + + + /** + \brief Get the number of sequences in the database. + \retval int number of sequences + */ + int size(); + + + /** + \brief Overloaded operator []. + \param position of the sequence in the vector of sequences + \retval cSequence reference to a sequence + */ + cSequence& operator[](int position); + + + /** + \brief Clear the vector of sequences. + */ + void clear(); + + + /** + \brief Push a new sequence into the vector of sequences. + \param sequence an inserted sequence + */ + void push_back(cSequence& sequence); + + + /** + \brief Store the structure into an output stream. + \param os an output stream + */ + void store(ofstream& os); + + + /** + \brief Load the structure from an input stream. + \param is an input stream + */ + void load(ifstream& is); + +}; + + +#endif \ No newline at end of file diff --git a/CycloBranch/core/cSummaryFormula.cpp b/CycloBranch/core/cSummaryFormula.cpp index 8cca1e4..fd90ed0 100644 --- a/CycloBranch/core/cSummaryFormula.cpp +++ b/CycloBranch/core/cSummaryFormula.cpp @@ -246,19 +246,11 @@ double cSummaryFormula::getMass() { void cSummaryFormula::store(ofstream& os) { - int size; - - size = (int)formula.size(); - os.write((char *)&size, sizeof(int)); - os.write(formula.c_str(), formula.size()); + storeString(formula, os); } void cSummaryFormula::load(ifstream& is) { - int size; - - is.read((char *)&size, sizeof(int)); - formula.resize(size); - is.read(&formula[0], formula.size()); + loadString(formula, is); } diff --git a/CycloBranch/core/cTheoreticalSpectrum.cpp b/CycloBranch/core/cTheoreticalSpectrum.cpp index 3280311..94432ab 100644 --- a/CycloBranch/core/cTheoreticalSpectrum.cpp +++ b/CycloBranch/core/cTheoreticalSpectrum.cpp @@ -13,9 +13,7 @@ void visualSeries::store(ofstream& os) { os.write((char *)&series[i], sizeof(int)); } - size = (int)name.size(); - os.write((char *)&size, sizeof(int)); - os.write(name.c_str(), name.size()); + storeString(name, os); } @@ -28,9 +26,7 @@ void visualSeries::load(ifstream& is) { is.read((char *)&series[i], sizeof(int)); } - is.read((char *)&size, sizeof(int)); - name.resize(size); - is.read(&name[0], name.size()); + loadString(name, is); } @@ -77,6 +73,7 @@ void cTheoreticalSpectrum::searchForPeakPairs(cPeaksList& theoreticalpeaks, int void cTheoreticalSpectrum::computeSomeStatistics(bool writedescription) { experimentalpeaksmatched = 0; + scrambledpeaksmatched = 0; if (writedescription) { unmatchedpeaks = ""; } @@ -85,7 +82,15 @@ void cTheoreticalSpectrum::computeSomeStatistics(bool writedescription) { if (experimentalpeaks[i].matched > 0) { experimentalpeaksmatched++; intensityweightedscore += experimentalpeaks[i].intensity; - matchedions[experimentalpeaks[i].iontype]++; + + if (parameters && ((parameters->mode == denovoengine) || (parameters->mode == singlecomparison) || (parameters->mode == databasesearch))) { + if (!experimentalpeaks[i].scrambled) { + matchedions[experimentalpeaks[i].iontype]++; + } + else { + scrambledpeaksmatched++; + } + } } else { if (writedescription) { @@ -181,10 +186,10 @@ void cTheoreticalSpectrum::generateScrambledIons(cBricksDatabase& bricksdatabase scrambledspeaksrealsize++; } } + scrambledpeaks.resize(scrambledspeaksrealsize); // erase all scrambled peaks whose mz ratios collide with common fragment ions // eraseAll - time consuming 55.8% - // scrambledpeaks.resize(scrambledspeaksrealsize); // scrambledpeaks.sortbyMass(); // for (int i = 0; i < theoreticalpeaksrealsize; i++) { // scrambledpeaks.eraseAll(theoreticalpeaks[i].mzratio); @@ -311,6 +316,7 @@ void cTheoreticalSpectrum::clear(bool clearpeaklist) { candidate.clear(); experimentalpeaksmatched = 0; + scrambledpeaksmatched = 0; peakstested = 0; experimentalpeaksmatchedratio = 0; unmatchedpeaks = ""; @@ -1256,7 +1262,7 @@ int cTheoreticalSpectrum::compareLasso(cPeaksList& sortedpeaklist, cBricksDataba } // all permmutations except 3 and 5 have invalid c-terms - if (parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[i]].cterminal && ((k == 3) || (k == 5) || ((k == 0) && (trotationsoflassorotations[j][k].endsWithBracket())) || ((k == 2) && (trotationsoflassorotations[j][k].startsWithBracket())))) { + if (parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[i]].cterminal && ((k == 3) || (k == 5) /*|| ((k == 0) && (trotationsoflassorotations[j][k].endsWithBracket())) || ((k == 2) && (trotationsoflassorotations[j][k].startsWithBracket()))*/)) { // if the end modification is cterminal, generate c-terminal ions (**) if (parameters->searchedmodifications[trotationsoflassorotations[j][k].endmodifID].cterminal) { generateCTerminalFragmentIons(parameters->precursorcharge, theoreticalpeaksrealsize, stringcomposition, trotationsoflassorotations[j][k].bricks, parameters->fragmentionsfortheoreticalspectra[i], bricksdatabasewithcombinations, writedescription, j, splittingsites, parameters->searchedmodifications, lasso, &trotationsoflassorotations[j][k]); @@ -1580,6 +1586,64 @@ int cTheoreticalSpectrum::compareLinearPolysaccharide(cPeaksList& sortedpeaklist } +void cTheoreticalSpectrum::compareMSSpectrum(cParameters* parameters) { + experimentalpeaks = parameters->peaklist; + experimentalpeaks.sortbyMass(); + + cPeak peak; + cSummaryFormula formula; + theoreticalpeaks.resize((int)parameters->fragmentionsfortheoreticalspectra.size()*parameters->sequencedatabase.size()*parameters->precursorcharge); + for (int i = 0; i < parameters->sequencedatabase.size(); i++) { + peak.clear(); + formula.clear(); + + formula.setFormula(parameters->sequencedatabase[i].getSummaryFormula()); + + for (int j = 0; j < (int)parameters->fragmentionsfortheoreticalspectra.size(); j++) { + for (int k = 0; k < parameters->precursorcharge; k++) { + peak.mzratio = (double)parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].multiplier*formula.getMass() + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].massdifference; + if (parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].positive) { + peak.mzratio += (double)k*Hplus; + } + else { + peak.mzratio -= (double)k*Hplus; + } + peak.mzratio = peak.mzratio/(double)(k + 1); + peak.description = parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(0, parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.size() - 1) + " "; + peak.description += to_string(k + 1); + if (parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].positive) { + peak.description += "+"; + } + else { + peak.description += "-"; + } + peak.description += " " + parameters->sequencedatabase[i].getName() + " (" + parameters->sequencedatabase[i].getSummaryFormula() + "): "; + + theoreticalpeaks[(i*(int)parameters->fragmentionsfortheoreticalspectra.size() + j)*parameters->precursorcharge + k] = peak; + } + } + } + theoreticalpeaks.sortbyMass(); + + vector > experimentalpeakmatches; + searchForPeakPairs(theoreticalpeaks, theoreticalpeaks.size(), experimentalpeaks, experimentalpeakmatches, parameters->fragmentmasserrortolerance); + + // fill annotations of peaks + for (int i = 0; i < (int)experimentalpeaks.size(); i++) { + for (set::iterator it = experimentalpeakmatches[i].begin(); it != experimentalpeakmatches[i].end(); ++it) { + + if (experimentalpeaks[i].description.compare("") != 0) { + experimentalpeaks[i].description += ","; + } + experimentalpeaks[i].description += theoreticalpeaks[*it].description.substr(0,theoreticalpeaks[*it].description.find(':')); + theoreticalpeaks[*it].matchdescription += ", measured mass " + to_string((long double)experimentalpeaks[i].mzratio) + " matched with " + to_string((long double)ppmError(experimentalpeaks[i].mzratio, theoreticalpeaks[*it].mzratio)) + " ppm error"; + } + } + + computeSomeStatistics(true); +} + + int cTheoreticalSpectrum::getNumberOfPeaks() { return theoreticalpeaks.size(); } @@ -1590,6 +1654,11 @@ int cTheoreticalSpectrum::getNumberOfMatchedPeaks() { } +int cTheoreticalSpectrum::getNumberOfScrambledPeaks() { + return scrambledpeaksmatched; +} + + int cTheoreticalSpectrum::getNumberOfMatchedPeaks(fragmentIonType iontype) { return matchedions[iontype]; } @@ -1621,6 +1690,8 @@ void cTheoreticalSpectrum::printMatch(ofstream& os, peptideType peptidetype) { case lasso: os << "Composition: " << candidate.getTComposition(); break; + case other: + break; default: break; } @@ -1702,11 +1773,16 @@ void cTheoreticalSpectrum::printMatch(ofstream& os, peptideType peptidetype) { break; case linearpolysaccharide: break; + case other: + break; default: break; } os << "Matched peaks: " << experimentalpeaksmatched << endl; + if (peptidetype == cyclic) { + os << "Scrambled peaks matched: " << scrambledpeaksmatched << endl; + } os << "Total peaks: " << peakstested << endl; os << "Sum of Relative Intensities: " << intensityweightedscore << endl; os << "Ratio of matched peaks: " << experimentalpeaksmatchedratio*100.0f << "%" << endl << endl; @@ -1748,6 +1824,8 @@ void cTheoreticalSpectrum::generateNTerminalFragmentIons(int maxcharge, int& pea case linearpolysaccharide: peak.rotationid = rotationid; break; + case other: + break; default: break; } @@ -1873,6 +1951,8 @@ void cTheoreticalSpectrum::generateCTerminalFragmentIons(int maxcharge, int& pea case linearpolysaccharide: peak.rotationid = rotationid; break; + case other: + break; default: break; } @@ -1997,6 +2077,7 @@ void cTheoreticalSpectrum::setRealPeptideName(cBricksDatabase& bricksdatabase, p case lasso: realpeptidename = candidate.getRealNameTComposition(bricksdatabase); break; + case other: default: realpeptidename = ""; break; @@ -2016,6 +2097,7 @@ void cTheoreticalSpectrum::setAcronymPeptideNameWithHTMLReferences(cBricksDataba case lasso: acronympeptidename = candidate.getAcronymsTComposition(bricksdatabase); break; + case other: default: acronympeptidename = ""; break; @@ -2215,6 +2297,7 @@ void cTheoreticalSpectrum::store(ofstream& os) { candidate.store(os); os.write((char *)&experimentalpeaksmatched, sizeof(int)); + os.write((char *)&scrambledpeaksmatched, sizeof(int)); size = (int)matchedions.size(); os.write((char *)&size, sizeof(int)); @@ -2226,13 +2309,8 @@ void cTheoreticalSpectrum::store(ofstream& os) { os.write((char *)&peakstested, sizeof(int)); os.write((char *)&experimentalpeaksmatchedratio, sizeof(double)); - size = (int)unmatchedpeaks.size(); - os.write((char *)&size, sizeof(int)); - os.write(unmatchedpeaks.c_str(), unmatchedpeaks.size()); - - size = (int)coveragebyseries.size(); - os.write((char *)&size, sizeof(int)); - os.write(coveragebyseries.c_str(), coveragebyseries.size()); + storeString(unmatchedpeaks, os); + storeString(coveragebyseries, os); os.write((char *)&valid, sizeof(bool)); os.write((char *)&intensityweightedscore, sizeof(double)); @@ -2248,41 +2326,12 @@ void cTheoreticalSpectrum::store(ofstream& os) { os.write((char *)&reversevalidposition, sizeof(int)); os.write((char *)&seriescompleted, sizeof(int)); - size = (int)realpeptidename.size(); - os.write((char *)&size, sizeof(int)); - os.write(realpeptidename.c_str(), realpeptidename.size()); - - size = (int)acronympeptidename.size(); - os.write((char *)&size, sizeof(int)); - os.write(acronympeptidename.c_str(), acronympeptidename.size()); - - size = (int)acronyms.size(); - os.write((char *)&size, sizeof(int)); - for (int i = 0; i < (int)acronyms.size(); i++) { - size = (int)acronyms[i].size(); - os.write((char *)&size, sizeof(int)); - os.write(acronyms[i].c_str(), acronyms[i].size()); - } - - size = (int)backboneacronyms.size(); - os.write((char *)&size, sizeof(int)); - for (int i = 0; i < (int)backboneacronyms.size(); i++) { - size = (int)backboneacronyms[i].size(); - os.write((char *)&size, sizeof(int)); - os.write(backboneacronyms[i].c_str(), backboneacronyms[i].size()); - } - - size = (int)branchacronyms.size(); - os.write((char *)&size, sizeof(int)); - for (int i = 0; i < (int)branchacronyms.size(); i++) { - size = (int)branchacronyms[i].size(); - os.write((char *)&size, sizeof(int)); - os.write(branchacronyms[i].c_str(), branchacronyms[i].size()); - } - - size = (int)path.size(); - os.write((char *)&size, sizeof(int)); - os.write(path.c_str(), path.size()); + storeString(realpeptidename, os); + storeString(acronympeptidename, os); + storeStringVector(acronyms, os); + storeStringVector(backboneacronyms, os); + storeStringVector(branchacronyms, os); + storeString(path, os); } @@ -2298,6 +2347,7 @@ void cTheoreticalSpectrum::load(ifstream& is) { candidate.load(is); is.read((char *)&experimentalpeaksmatched, sizeof(int)); + is.read((char *)&scrambledpeaksmatched, sizeof(int)); is.read((char *)&size, sizeof(int)); matchedions.clear(); @@ -2310,13 +2360,8 @@ void cTheoreticalSpectrum::load(ifstream& is) { is.read((char *)&peakstested, sizeof(int)); is.read((char *)&experimentalpeaksmatchedratio, sizeof(double)); - is.read((char *)&size, sizeof(int)); - unmatchedpeaks.resize(size); - is.read(&unmatchedpeaks[0], unmatchedpeaks.size()); - - is.read((char *)&size, sizeof(int)); - coveragebyseries.resize(size); - is.read(&coveragebyseries[0], coveragebyseries.size()); + loadString(unmatchedpeaks, is); + loadString(coveragebyseries, is); is.read((char *)&valid, sizeof(bool)); is.read((char *)&intensityweightedscore, sizeof(double)); @@ -2332,40 +2377,11 @@ void cTheoreticalSpectrum::load(ifstream& is) { is.read((char *)&reversevalidposition, sizeof(int)); is.read((char *)&seriescompleted, sizeof(int)); - is.read((char *)&size, sizeof(int)); - realpeptidename.resize(size); - is.read(&realpeptidename[0], realpeptidename.size()); - - is.read((char *)&size, sizeof(int)); - acronympeptidename.resize(size); - is.read(&acronympeptidename[0], acronympeptidename.size()); - - is.read((char *)&size, sizeof(int)); - acronyms.resize(size); - for (int i = 0; i < (int)acronyms.size(); i++) { - is.read((char *)&size, sizeof(int)); - acronyms[i].resize(size); - is.read(&acronyms[i][0], acronyms[i].size()); - } - - is.read((char *)&size, sizeof(int)); - backboneacronyms.resize(size); - for (int i = 0; i < (int)backboneacronyms.size(); i++) { - is.read((char *)&size, sizeof(int)); - backboneacronyms[i].resize(size); - is.read(&backboneacronyms[i][0], backboneacronyms[i].size()); - } - - is.read((char *)&size, sizeof(int)); - branchacronyms.resize(size); - for (int i = 0; i < (int)branchacronyms.size(); i++) { - is.read((char *)&size, sizeof(int)); - branchacronyms[i].resize(size); - is.read(&branchacronyms[i][0], branchacronyms[i].size()); - } - - is.read((char *)&size, sizeof(int)); - path.resize(size); - is.read(&path[0], path.size()); + loadString(realpeptidename, is); + loadString(acronympeptidename, is); + loadStringVector(acronyms, is); + loadStringVector(backboneacronyms, is); + loadStringVector(branchacronyms, is); + loadString(path, is); } diff --git a/CycloBranch/core/cTheoreticalSpectrum.h b/CycloBranch/core/cTheoreticalSpectrum.h index c6d791d..3c3100f 100644 --- a/CycloBranch/core/cTheoreticalSpectrum.h +++ b/CycloBranch/core/cTheoreticalSpectrum.h @@ -99,6 +99,7 @@ class cTheoreticalSpectrum { cPeaksList experimentalpeaks; cCandidate candidate; int experimentalpeaksmatched; + int scrambledpeaksmatched; map matchedions; int peakstested; double experimentalpeaksmatchedratio; @@ -242,6 +243,13 @@ class cTheoreticalSpectrum { int compareLinearPolysaccharide(cPeaksList& sortedpeaklist, cBricksDatabase& bricksdatabasewithcombinations, bool writedescription, regex& sequencetag, regex& searchedsequence); + /** + \brief Compare theoretical peaks with an experimental spectrum. + \param parameters a pointer to the parameters of the application + */ + void compareMSSpectrum(cParameters* parameters); + + /** \brief Get the number of matched peaks between an experimental and a theoretical spectrum. \retval int number of matched peaks @@ -249,6 +257,13 @@ class cTheoreticalSpectrum { int getNumberOfMatchedPeaks(); + /** + \brief Get the number of matched scrambled peaks between an experimental and a theoretical spectrum. + \retval int number of matched scrambled peaks + */ + int getNumberOfScrambledPeaks(); + + /** \brief Get the number of matched peaks between an experimental and a theoretical spectrum of a specified fragment ion type. \param iontype a fragment ion type diff --git a/CycloBranch/core/cTheoreticalSpectrumList.cpp b/CycloBranch/core/cTheoreticalSpectrumList.cpp index e439544..ad3a3ea 100644 --- a/CycloBranch/core/cTheoreticalSpectrumList.cpp +++ b/CycloBranch/core/cTheoreticalSpectrumList.cpp @@ -90,7 +90,24 @@ int cTheoreticalSpectrumList::parallelCompareAndStore(cCandidateSet& candidates, regex rxsequencetag, rxsearchedsequence; cSpectrumComparatorThread* comparatorthread; string stmp; - cBricksDatabase* bricksdb = (parameters->mode == 0) ? graph->getBrickDatabaseWithCombinations() : ¶meters->bricksdatabase; + + cBricksDatabase* bricksdb = 0; + switch (parameters->mode) + { + case denovoengine: + bricksdb = graph->getBrickDatabaseWithCombinations(); + break; + case singlecomparison: + bricksdb = ¶meters->bricksdatabase; + break; + case databasesearch: + bricksdb = ¶meters->bricksdatabase; + break; + default: + return -1; + break; + } + vector resultspectra; //int pos; @@ -142,7 +159,7 @@ int cTheoreticalSpectrumList::parallelCompareAndStore(cCandidateSet& candidates, return -1; } - if (parameters->mode == 0) { + if ((parameters->mode == denovoengine) || (parameters->mode == databasesearch)) { QThreadPool::globalInstance()->setMaxThreadCount(parameters->maximumnumberofthreads); @@ -176,7 +193,8 @@ int cTheoreticalSpectrumList::parallelCompareAndStore(cCandidateSet& candidates, } if ((i % 10000 == 0) && (i > 0)) { - *os << "(Remaining candidates in buffer: " << size << "; Are they all ?: " << (os->isGraphReaderWorking() ? "no" : "yes") << ")" << endl; + //*os << "(Remaining candidates in buffer: " << size << "; Are they all ?: " << (os->isGraphReaderWorking() ? "no" : "yes") << ")" << endl; + *os << endl; } i++; @@ -235,6 +253,7 @@ int cTheoreticalSpectrumList::parallelCompareAndStore(cCandidateSet& candidates, case linearpolysaccharide: theoreticalpeaksrealsize = tsp.compareLinearPolysaccharide(peaklist, *bricksdb, true, rxsequencetag, rxsearchedsequence); break; + case other: default: break; } @@ -261,7 +280,7 @@ int cTheoreticalSpectrumList::parallelCompareAndStore(cCandidateSet& candidates, theoreticalspectra[i].setBackboneAcronyms(*bricksdb); theoreticalspectra[i].setBranchAcronyms(*bricksdb); } - if (parameters->mode == 0) { + if (parameters->mode == denovoengine) { theoreticalspectra[i].setPath(*graph); } // parameters must not be used by viewer, they are not stored/loaded diff --git a/CycloBranch/core/utilities.cpp b/CycloBranch/core/utilities.cpp new file mode 100644 index 0000000..9bf5d8f --- /dev/null +++ b/CycloBranch/core/utilities.cpp @@ -0,0 +1,36 @@ +#include "core/utilities.h" + + +void storeString(string& s, ofstream& os) { + int size = (int)s.size(); + os.write((char *)&size, sizeof(int)); + os.write(s.c_str(), size); +} + + +void loadString(string& s, ifstream& is) { + int size; + is.read((char *)&size, sizeof(int)); + s.resize(size); + is.read(&s[0], size); +} + + +void storeStringVector(vector& v, ofstream& os) { + int size = (int)v.size(); + os.write((char *)&size, sizeof(int)); + for (int i = 0; i < (int)v.size(); i++) { + storeString(v[i], os); + } +} + + +void loadStringVector(vector& v, ifstream& is) { + int size; + is.read((char *)&size, sizeof(int)); + v.resize(size); + for (int i = 0; i < (int)v.size(); i++) { + loadString(v[i], is); + } +} + diff --git a/CycloBranch/core/utilities.h b/CycloBranch/core/utilities.h new file mode 100644 index 0000000..21a3272 --- /dev/null +++ b/CycloBranch/core/utilities.h @@ -0,0 +1,51 @@ +/** + \file utilities.h + \brief Auxiliary funtions and structures. +*/ + + +#ifndef _UTILITIES_H +#define _UTILITIES_H + +#include +#include +#include + + +using namespace std; + + +/** + \brief Store a string into an output stream. + \param s reference to a string + \param os reference to an output stream +*/ +void storeString(string& s, ofstream& os); + + +/** + \brief Load a string from an input stream. + \param s reference to a string + \param is reference to an input stream +*/ +void loadString(string& s, ifstream& is); + + +/** + \brief Store a vector of strings into an output stream. + \param v reference to a vector of strings + \param os reference to an output stream +*/ +void storeStringVector(vector& v, ofstream& os); + + +/** + \brief Load a vector of strings from an input stream. + \param v reference to a vector of strings + \param is reference to an input stream +*/ +void loadStringVector(vector& v, ifstream& is); + + +#endif + diff --git a/CycloBranch/gui/cBricksDatabaseWidget.cpp b/CycloBranch/gui/cBricksDatabaseWidget.cpp new file mode 100644 index 0000000..bae78d0 --- /dev/null +++ b/CycloBranch/gui/cBricksDatabaseWidget.cpp @@ -0,0 +1,456 @@ +#include "gui/cBricksDatabaseWidget.h" +#include "gui/cMainThread.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int numberOfOccurrences(string& s, char c) { + int count = 0; + for (int i = 0; i < (int)s.size(); i++) { + if (s[i] == c) { + count++; + } + } + return count; +} + + +cBricksDatabaseWidget::cBricksDatabaseWidget(QWidget* parent) { + this->parent = parent; + + setWindowTitle("Building Blocks Editor"); + + insertrow = new QPushButton(tr("Add Row")); + insertrow->setToolTip("Add a new row."); + removechecked = new QPushButton(tr(" Remove Rows ")); + removechecked->setToolTip("Remove selected rows."); + + close = new QPushButton(tr("Close")); + close->setToolTip("Close the window."); + load = new QPushButton(tr("Load")); + load->setToolTip("Load the database of building blocks."); + save = new QPushButton(QString("Save")); + save->setToolTip("Save the database of building blocks in the current file. When a file has not been loaded yet, the \"Save As ...\" file dialog is opened."); + saveas = new QPushButton(tr("Save As...")); + saveas->setToolTip("Save the database of building blocks into a file."); + + buttons = new QHBoxLayout(); + buttons->addWidget(close); + buttons->addStretch(1); + buttons->addWidget(insertrow); + buttons->addWidget(removechecked); + buttons->addStretch(10); + buttons->addWidget(load); + buttons->addWidget(save); + buttons->addWidget(saveas); + + database = new QTableWidget(0, 0, this); + database->setColumnCount(7); + database->setHorizontalHeaderItem(0, new QTableWidgetItem("")); + database->setHorizontalHeaderItem(1, new QTableWidgetItem("Name(s)")); + database->setHorizontalHeaderItem(2, new QTableWidgetItem("Acronym(s)")); + database->setHorizontalHeaderItem(3, new QTableWidgetItem("Residue Summary")); + database->setHorizontalHeaderItem(4, new QTableWidgetItem("Monoisotopic Residue Mass")); + database->setHorizontalHeaderItem(5, new QTableWidgetItem("Reference(s)")); + database->setHorizontalHeaderItem(6, new QTableWidgetItem("Preview")); + database->horizontalHeader()->setStretchLastSection(true); + for (int i = 0; i < database->columnCount(); i++) { + database->resizeColumnToContents(i); + } + + headersort.resize(database->columnCount()); + for (int i = 0; i < database->columnCount(); i++) { + headersort[i] = -1; + } + + mainlayout = new QVBoxLayout(); + mainlayout->addWidget(database); + mainlayout->addLayout(buttons); + + progress = new QProgressDialog(this); + progress->setCancelButton(0); + progress->setMinimumDuration(1000); + progress->setWindowModality(Qt::WindowModal); + + connect(database->horizontalHeader(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(headerItemDoubleClicked(int))); + connect(database, SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(itemChanged(QTableWidgetItem *))); + connect(insertrow, SIGNAL(released()), this, SLOT(addRow())); + connect(removechecked, SIGNAL(released()), this, SLOT(removeEmptyRows())); + connect(close, SIGNAL(released()), this, SLOT(closeWindow())); + connect(load, SIGNAL(released()), this, SLOT(loadDatabase())); + connect(save, SIGNAL(released()), this, SLOT(saveDatabase())); + connect(saveas, SIGNAL(released()), this, SLOT(saveDatabaseAs())); + + setLayout(mainlayout); + + resize(1280, 700); + + databasefile = ""; + lastdir = "./BrickDatabases/"; + bricks.clear(); +} + + +cBricksDatabaseWidget::~cBricksDatabaseWidget() { + deleteTable(false); + + for (int i = 0; i < database->columnCount(); i++) { + delete database->horizontalHeaderItem(i); + } + + database->setColumnCount(0); + + delete insertrow; + delete removechecked; + delete close; + delete load; + delete save; + delete saveas; + delete database; + delete buttons; + delete mainlayout; + delete progress; +} + + +void cBricksDatabaseWidget::closeEvent(QCloseEvent *event) { + closeWindow(); +} + + +void cBricksDatabaseWidget::deleteTable(bool enableprogress) { + if (enableprogress) { + progress->setLabelText("Clearing the table..."); + progress->setMinimum(0); + progress->setValue(1); + progress->setMaximum(database->rowCount()); + progress->show(); + } + + for (int i = 0; i < database->rowCount(); i++) { + for (int j = 0; j < database->columnCount(); j++) { + if ((j == 0) || (j == 6)) { + delete database->cellWidget(i, j); + } + else { + delete database->item(i, j); + } + } + + if (enableprogress && ((i == 0) || ((i - 1)/100 != i/100))) { + progress->setValue(i); + } + } + + if (enableprogress) { + progress->setValue(database->rowCount()); + progress->hide(); + } + database->setRowCount(0); +} + + +void cBricksDatabaseWidget::removeRow(int row) { + for (int i = 0; i < database->columnCount(); i++) { + if ((i == 0) || (i == 6)) { + delete database->cellWidget(row, i); + } + else { + delete database->item(row, i); + } + } + database->removeRow(row); +} + + +bool cBricksDatabaseWidget::checkTable() { + // the fields name, acronym and reference must contain the same numbers of '/' + int checkslash; + for (int i = 0; i < database->rowCount(); i++) { + checkslash = numberOfOccurrences(database->item(i, 1)->text().toStdString(),'/'); + if ((checkslash != numberOfOccurrences(database->item(i, 2)->text().toStdString(),'/')) || (checkslash != numberOfOccurrences(database->item(i, 5)->text().toStdString(),'/'))) { + QMessageBox msgBox; + QString errstr = "Syntax error in the row no. "; + errstr += to_string(i + 1).c_str(); + errstr += ":\nThe number of '/' must be equal in the fields Name(s), Acronym(s) and Reference(s) !\n\nNote: The symbol '/' separates izomers of a building block."; + msgBox.setText(errstr); + msgBox.exec(); + return false; + } + } + + // check summary formulas + for (int i = 0; i < database->rowCount(); i++) { + if (!checkFormula(i, database->item(i, 3)->text().toStdString())) { + return false; + } + } + + return true; +} + + +bool cBricksDatabaseWidget::checkFormula(int row, string& summary) { + cSummaryFormula formula; + string errmsg; + formula.setFormula(summary); + if (!formula.isValid(errmsg)) { + QMessageBox msgBox; + QString errstr = "Syntax error in the row no. "; + errstr += to_string(row + 1).c_str(); + errstr += ": "; + errstr += errmsg.c_str(); + msgBox.setText(errstr); + msgBox.exec(); + return false; + } + if (database->item(row, 4)) { + database->item(row, 4)->setData(Qt::DisplayRole, formula.getMass()); + } + return true; +} + + +void cBricksDatabaseWidget::closeWindow() { + hide(); +} + + +void cBricksDatabaseWidget::loadDatabase() { + QString filename = QFileDialog::getOpenFileName(this, tr("Load the Database of Building Blocks"), lastdir, tr("Database of Building Blocks (*.txt)")); + lastdir = filename; + string errormessage; + + if (filename.toStdString().compare("") != 0) { + + databasefile = filename; + save->setText(QString(" Save '") + QString(databasefile.toStdString().substr(databasefile.toStdString().rfind('/') + 1, databasefile.toStdString().size()).c_str()) + QString("' ")); + + inputstream.open(filename.toStdString().c_str()); + + if (!inputstream.good()) { + QMessageBox msgBox; + msgBox.setText("Cannot open the file '" + databasefile + "'."); + msgBox.exec(); + } + else { + + bricks.clear(); + bricks.loadFromPlainTextStream(inputstream, errormessage); + + deleteTable(true); + + progress->setLabelText("Loading the Databatase of Building Blocks..."); + progress->setMinimum(0); + progress->setValue(1); + progress->setMaximum(bricks.size()); + progress->show(); + + database->setRowCount(bricks.size()); + for (int i = 0; i < bricks.size(); i++) { + QCheckBox* checkbox = new QCheckBox(); + database->setCellWidget(i, 0, checkbox); + + database->setItem(i, 1, new QTableWidgetItem(bricks[i].getName().c_str())); + database->setItem(i, 2, new QTableWidgetItem(bricks[i].getAcronymsAsString().c_str())); + database->setItem(i, 3, new QTableWidgetItem(bricks[i].getSummary().c_str())); + + database->setItem(i, 4, new QTableWidgetItem()); + database->item(i, 4)->setData(Qt::DisplayRole, bricks[i].getMass()); + + database->setItem(i, 5, new QTableWidgetItem(bricks[i].getReferencesAsString().c_str())); + + database->setCellWidget(i, 6, new QLabel(bricks[i].getAcronymsWithReferencesAsHTMLString().c_str())); + ((QLabel *)database->cellWidget(i, 6))->setTextFormat(Qt::RichText); + ((QLabel *)database->cellWidget(i, 6))->setTextInteractionFlags(Qt::TextBrowserInteraction); + ((QLabel *)database->cellWidget(i, 6))->setOpenExternalLinks(true); + + if ((i == 0) || ((i - 1)/100 != i/100)) { + progress->setValue(i); + } + } + + for (int i = 0; i < database->columnCount(); i++) { + database->resizeColumnToContents(i); + } + + progress->setValue(bricks.size()); + progress->hide(); + + } + + inputstream.close(); + + } +} + + +void cBricksDatabaseWidget::saveDatabase() { + + if (!checkTable()) { + return; + } + + if (databasefile.compare("") == 0) { + saveDatabaseAs(); + return; + } + + outputstream.open(databasefile.toStdString().c_str()); + if (!outputstream.good()) { + QMessageBox msgBox; + msgBox.setText("Cannot open the file '" + databasefile + "'."); + msgBox.exec(); + } + else { + + progress->setLabelText("Saving the Databatase of Building Blocks..."); + progress->setMinimum(0); + progress->setMaximum(100); + progress->setValue(1); + progress->show(); + + cBrick b; + bricks.clear(); + + removeEmptyRows(); + + progress->setMaximum(database->rowCount()); + + for (int i = 0; i < database->rowCount(); i++) { + b.clear(); + for (int j = 0; j < database->columnCount(); j++) { + switch (j) + { + case 0: + // nothing to do + break; + case 1: + b.setName(database->item(i,j)->text().toStdString()); + break; + case 2: + b.setAcronyms(database->item(i,j)->text().toStdString()); + break; + case 3: + b.setSummary(database->item(i,j)->text().toStdString()); + break; + case 4: + b.setMass(database->item(i,j)->data(Qt::DisplayRole).toDouble()); + break; + case 5: + b.setReferences(database->item(i,j)->text().toStdString()); + break; + default: + break; + } + } + bricks.push_back(b); + + if ((i == 0) || ((i - 1)/100 != i/100)) { + progress->setValue(i); + } + } + + bricks.storeToPlainTextStream(outputstream); + + progress->setValue(database->rowCount()); + progress->hide(); + + } + outputstream.close(); +} + + +void cBricksDatabaseWidget::saveDatabaseAs() { + + if (!checkTable()) { + return; + } + + QString filename = QFileDialog::getSaveFileName(this, tr("Save Settings As..."), lastdir, tr("Database of Building Blocks (*.txt)")); + lastdir = filename; + + if (filename.toStdString().compare("") != 0) { + databasefile = filename; + save->setText(QString(" Save '") + QString(databasefile.toStdString().substr(databasefile.toStdString().rfind('/') + 1, databasefile.toStdString().size()).c_str()) + QString("' ")); + saveDatabase(); + } +} + + +void cBricksDatabaseWidget::addRow() { + int row = database->rowCount(); + database->insertRow(row); + + QCheckBox* checkbox = new QCheckBox(); + database->setCellWidget(row, 0, checkbox); + + database->setItem(row, 1, new QTableWidgetItem()); + database->setItem(row, 2, new QTableWidgetItem()); + database->setItem(row, 3, new QTableWidgetItem()); + database->setItem(row, 4, new QTableWidgetItem()); + database->setItem(row, 5, new QTableWidgetItem()); + + database->setCellWidget(row, 6, new QLabel()); + ((QLabel *)database->cellWidget(row, 6))->setTextFormat(Qt::RichText); + ((QLabel *)database->cellWidget(row, 6))->setTextInteractionFlags(Qt::TextBrowserInteraction); + ((QLabel *)database->cellWidget(row, 6))->setOpenExternalLinks(true); +} + + +void cBricksDatabaseWidget::removeEmptyRows() { + int i = 0; + while (i < database->rowCount()) { + if (((QCheckBox *)(database->cellWidget(i, 0)))->isChecked()) { + removeRow(i); + } + else { + i++; + } + } +} + + +void cBricksDatabaseWidget::itemChanged(QTableWidgetItem* item) { + // recalculate mass when formula is changed + if (item->column() == 3) { + checkFormula(item->row(), item->text().toStdString()); + } + + // update references preview + if (((item->column() == 2) || (item->column() == 5)) && database->cellWidget(item->row(), 6)) { + cBrick b; + b.setAcronyms(database->item(item->row(), 2)->text().toStdString()); + b.setReferences(database->item(item->row(), 5)->text().toStdString()); + ((QLabel *)database->cellWidget(item->row(), 6))->setText(b.getAcronymsWithReferencesAsHTMLString().c_str()); + } +} + + +void cBricksDatabaseWidget::headerItemDoubleClicked(int index) { + if (headersort[index] == -1) { + database->sortByColumn(index, Qt::AscendingOrder); + headersort[index] = 1; + return; + } + + if (headersort[index] == 0) { + database->sortByColumn(index, Qt::AscendingOrder); + headersort[index] = 1; + } + else { + database->sortByColumn(index, Qt::DescendingOrder); + headersort[index] = 0; + } +} + diff --git a/CycloBranch/gui/cBricksDatabaseWidget.h b/CycloBranch/gui/cBricksDatabaseWidget.h new file mode 100644 index 0000000..ade57cc --- /dev/null +++ b/CycloBranch/gui/cBricksDatabaseWidget.h @@ -0,0 +1,116 @@ +/** + \file cBricksDatabaseWidget.h + \brief Visualization of the database of building blocks. +*/ + + +#ifndef _CBRICKSDATABASEWIDGET_H +#define _CBRICKSDATABASEWIDGET_H + +#include +#include +#include "core/cBricksDatabase.h" + +using namespace std; + + +// forward declaration +class QHBoxLayout; +class QVBoxLayout; +class QTableWidget; +class QTableWidgetItem; +class QDialogButtonBox; +class QPushButton; +class QLabel; +class QProgressDialog; + + +/** + \brief Number of occurrences of a char in a string. + \param s string + \param c char + \retval int number of occurrences of \a c in \a s +*/ +int numberOfOccurrences(string& s, char c); + + +/** + \brief The widget representing the dialog 'About'. +*/ +class cBricksDatabaseWidget : public QWidget +{ + Q_OBJECT + +public: + + + /** + \brief The constructor. + \param parent pointer to a parent widget + */ + cBricksDatabaseWidget(QWidget* parent = (QWidget *)0); + + + /** + \brief The destructor. + */ + ~cBricksDatabaseWidget(); + + + /** + \brief Handle the window close event. + \param event pointer to QCloseEvent + */ + void closeEvent(QCloseEvent *event); + + +private: + QWidget* parent; + QPushButton* insertrow; + QPushButton* removechecked; + QPushButton* close; + QPushButton* load; + QPushButton* save; + QPushButton* saveas; + QTableWidget* database; + QHBoxLayout* buttons; + QVBoxLayout* mainlayout; + QProgressDialog* progress; + + QString databasefile; + QString lastdir; + ifstream inputstream; + ofstream outputstream; + cBricksDatabase bricks; + + vector headersort; + + void deleteTable(bool enableprogress); + + void removeRow(int row); + + bool checkTable(); + + bool checkFormula(int row, string& summary); + +private slots: + + void closeWindow(); + + void loadDatabase(); + + void saveDatabase(); + + void saveDatabaseAs(); + + void addRow(); + + void removeEmptyRows(); + + void itemChanged(QTableWidgetItem* item); + + void headerItemDoubleClicked(int index); + +}; + +#endif \ No newline at end of file diff --git a/CycloBranch/gui/cGraphWidget.cpp b/CycloBranch/gui/cGraphWidget.cpp index 0cc512c..ba9ccfc 100644 --- a/CycloBranch/gui/cGraphWidget.cpp +++ b/CycloBranch/gui/cGraphWidget.cpp @@ -50,20 +50,12 @@ void cGraphWidget::closeEvent(QCloseEvent *event) { void cGraphWidget::store(ofstream& os) { - int size; - - size = (int)htmlstring.size(); - os.write((char *)&size, sizeof(int)); - os.write(htmlstring.c_str(), htmlstring.size()); + storeString(htmlstring, os); } void cGraphWidget::load(ifstream& is) { - int size; - - is.read((char *)&size, sizeof(int)); - htmlstring.resize(size); - is.read(&htmlstring[0], htmlstring.size()); + loadString(htmlstring, is); textbrowser->setHtml(htmlstring.c_str()); } diff --git a/CycloBranch/gui/cGraphWidget.h b/CycloBranch/gui/cGraphWidget.h index 338ade3..4809917 100644 --- a/CycloBranch/gui/cGraphWidget.h +++ b/CycloBranch/gui/cGraphWidget.h @@ -10,6 +10,7 @@ #include #include #include +#include "core/utilities.h" using namespace std; diff --git a/CycloBranch/gui/cMainThread.cpp b/CycloBranch/gui/cMainThread.cpp index fe106a9..e7464a0 100644 --- a/CycloBranch/gui/cMainThread.cpp +++ b/CycloBranch/gui/cMainThread.cpp @@ -2,7 +2,170 @@ QString appname = "CycloBranch"; -QString appversion = "v. 1.0.739 (64-bit)"; +QString appversion = "v. 1.0.850 (64-bit)"; + + +bool cMainThread::checkModifications(cParameters& parameters, cSequence& sequence, int& startmodifid, int& endmodifid, int& middlemodifid, string& errormessage) { + startmodifid = 0; + endmodifid = 0; + middlemodifid = 0; + errormessage = ""; + + if ((parameters.peptidetype == linear) || (parameters.peptidetype == branched) || (parameters.peptidetype == lasso) || (parameters.peptidetype == linearpolysaccharide)) { + + if ((parameters.peptidetype == linear) || (parameters.peptidetype == branched) || (parameters.peptidetype == linearpolysaccharide)) { + startmodifid = -1; + endmodifid = -1; + } + + if ((parameters.peptidetype == branched) || (parameters.peptidetype == lasso)) { + middlemodifid = -1; + } + + for (int i = 0; i < (int)parameters.searchedmodifications.size(); i++) { + + if ((parameters.peptidetype == linear) || (parameters.peptidetype == branched) || (parameters.peptidetype == linearpolysaccharide)) { + if (parameters.searchedmodifications[i].name.compare(sequence.getNTterminalModification()) == 0) { + startmodifid = i; + } + + if (parameters.searchedmodifications[i].name.compare(sequence.getCTterminalModification()) == 0) { + endmodifid = i; + } + } + + if ((parameters.peptidetype == branched) || (parameters.peptidetype == lasso)) { + if (parameters.searchedmodifications[i].name.compare(sequence.getBranchModification()) == 0) { + middlemodifid = i; + } + } + + } + + if (startmodifid == -1) { + errormessage = "The N-terminal modification in the sequence " + sequence.getSequence() + " is not listed in the field 'N-terminal and C-terminal modifications': " + sequence.getNTterminalModification(); + + return false; + } + + if (endmodifid == -1) { + errormessage = "The C-terminal modification in the sequence " + sequence.getSequence() + " is not listed in the field 'N-terminal and C-terminal modifications': " + sequence.getCTterminalModification(); + return false; + } + + if (middlemodifid == -1) { + errormessage = "The branch modification in the sequence " + sequence.getSequence() + " is not listed in the field 'N-terminal and C-terminal modifications': " + sequence.getBranchModification(); + return false; + } + + } + + return true; +} + + +void cMainThread::parseBranch(peptideType peptidetype, string& composition, vector& vectorcomposition, int& branchstart, int& branchend) { + string s = composition; + cBrick b; + branchstart = -1; + branchend = -1; + + if ((peptidetype == branched) || (peptidetype == lasso)) { + int i = 0; + while (i < (int)s.size()) { + if (s[i] == '\\') { + s.erase(s.begin() + i); + } + else { + i++; + } + } + + for (int i = 0; i < (int)s.size(); i++) { + if (s[i] == '(') { + if (i > 0) { + b.clear(); + b.setComposition(s.substr(0, i - 1), false); + branchstart = getNumberOfBricks(b.getComposition()); + s[i] = '-'; + } + else { + s.erase(s.begin()); + branchstart = 0; + } + break; + } + } + + for (int i = 0; i < (int)s.size(); i++) { + if (s[i] == ')') { + b.clear(); + b.setComposition(s.substr(0, i - 1), false); + branchend = getNumberOfBricks(b.getComposition()) - 1; + if (i < (int)s.size() - 1) { + s[i] = '-'; + } + else { + s.erase(s.begin() + i); + } + break; + } + } + + if (branchend <= branchstart) { + branchstart = -1; + branchend = -1; + } + } + + b.clear(); + b.setComposition(s, false); + b.explodeToStringComposition(vectorcomposition); +} + + +bool cMainThread::checkRegex(cParameters& parameters, string& sequence, string& errormessage) { + errormessage = ""; + + if (sequence.compare("") == 0) { + errormessage = "The sequence is empty."; + return false; + } + + regex rx; + // [^\\[\\]]+ is used instead of .+ to prevent from a too complex regex error + switch (parameters.peptidetype) + { + case linear: + case cyclic: + case linearpolysaccharide: + rx = "^\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*$"; + break; + case branched: + rx = "^\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*\\\\\\(\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*\\\\\\)\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*$"; + break; + case lasso: + rx = "(^(\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*)?\\\\\\(\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*\\\\\\)\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*$|^\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*\\\\\\(\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*\\\\\\)(\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*)?$)"; + break; + case other: + default: + rx = ".*"; + break; + } + + try { + if (!(regex_search(sequence, rx))) { + errormessage = "The format of sequence is invalid: " + sequence + "."; + return false; + } + } + catch (std::regex_error& e) { + errormessage = "cMainThread::checkRegex: regex_search failed, error no. " + to_string(e.code()); + return false; + } + + return true; +} cMainThread::cMainThread(cParameters& parameters, bool enablelogwindow, bool enablestdout) { @@ -74,6 +237,7 @@ void cMainThread::run() { emitStartSignals(); cMainThread* os = this; + string errormessage; cCandidateSet candidates; candidates.getSet().clear(); @@ -92,77 +256,58 @@ void cMainThread::run() { } *os << parameters.printToString(); - if (!parameters.bricksdatabase.replaceAcronymsByIDs(parameters.sequencetag)) { - *os << "Error: invalid brick acronym typed in the sequence tag." << endl; - emit safeExit(); - return; + if ((parameters.mode == denovoengine) || (parameters.mode == singlecomparison) || (parameters.mode == databasesearch)) { + if (!parameters.bricksdatabase.replaceAcronymsByIDs(parameters.sequencetag, errormessage)) { + *os << "Error: " << errormessage << endl; + emit safeExit(); + return; + } } - if (parameters.mode == 1) { - if (parameters.searchedsequence.compare("") == 0) { - *os << "Error: Searched sequence is empty." << endl; - safeExit(); - return; + if (parameters.mode == singlecomparison) { + errormessage = ""; + if (!checkRegex(parameters, parameters.searchedsequence, errormessage)) { + *os << "Error: " << errormessage << endl; + emit safeExit(); + return; } + } - regex rx; - // [^\\[\\]]+ is used instead of .+ to prevent from a too complex regex error - switch (parameters.peptidetype) - { - case linear: - case cyclic: - case linearpolysaccharide: - rx = "^\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*$"; - break; - case branched: - rx = "^\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*\\\\\\(\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*\\\\\\)\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*$"; - break; - case lasso: - rx = "(^(\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*)?\\\\\\(\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*\\\\\\)\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*$|^\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*\\\\\\(\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*\\\\\\)(\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*)?$)"; - break; - default: - rx = ""; - break; + if ((parameters.mode == denovoengine) || (parameters.mode == singlecomparison) || (parameters.mode == databasesearch)) { + if (!parameters.bricksdatabase.replaceAcronymsByIDs(parameters.searchedsequence, errormessage)) { + *os << "Error: " << errormessage << endl; + emit safeExit(); + return; } + } - try { - if (!(regex_search(parameters.searchedsequence, rx))) { - *os << "Error: The format of searched sequence is invalid." << endl; - safeExit(); - return; + if ((parameters.mode == denovoengine) || (parameters.mode == singlecomparison) || (parameters.mode == databasesearch)) { + if (parameters.peptidetype != cyclic) { + // check summary formulas of modifications + errormessage = ""; + cSummaryFormula formula; + for (int i = 0; i < (int)parameters.searchedmodifications.size(); i++) { + formula.clear(); + formula.setFormula(parameters.searchedmodifications[i].summary); + if (formula.isValid(errormessage)) { + parameters.searchedmodifications[i].massdifference = formula.getMass(); + } + else { + *os << errormessage << endl; + emit safeExit(); + return; + } } } - catch (std::regex_error& e) { - *os << "cMainThread::run: regex_search failed, error no. " << e.code() << endl; - safeExit(); - return; - } } - if (!parameters.bricksdatabase.replaceAcronymsByIDs(parameters.searchedsequence)) { - *os << "Error: invalid brick acronym typed in the searched sequence." << endl; - emit safeExit(); - return; - } + parameters.peaklist.sortbyMass(); + parameters.peaklist.cropMinimumMZRatio(parameters.minimummz); - string errormessage = ""; - cSummaryFormula formula; - for (int i = 0; i < (int)parameters.searchedmodifications.size(); i++) { - formula.clear(); - formula.setFormula(parameters.searchedmodifications[i].summary); - if (formula.isValid(errormessage)) { - parameters.searchedmodifications[i].massdifference = formula.getMass(); - } - else { - *os << errormessage << endl; - emit safeExit(); - return; - } + if ((parameters.mode == denovoengine) || (parameters.mode == singlecomparison) || (parameters.mode == databasesearch)) { + parameters.peaklist.cropMaximumMZRatio(uncharge(parameters.precursormass, parameters.precursorcharge)); } - parameters.peaklist.sortbyMass(); - parameters.peaklist.cropMinimumMZRatio(parameters.minimummz); - parameters.peaklist.cropMaximumMZRatio(uncharge(parameters.precursormass, parameters.precursorcharge)); if (parameters.peaklist.normalizeIntenzity() == -1) { *os << "Error: the spectrum cannot be normalized; the maximum intensity is <= 0." << endl; emit safeExit(); @@ -177,8 +322,9 @@ void cMainThread::run() { parameters.peaklist.removeIsotopes(parameters.precursorcharge, parameters.masserrortolerancefordeisotoping, this); } - //search engine - if (parameters.mode == 0) { + + // de novo search engine + if (parameters.mode == denovoengine) { // create the de novo graph graph.initialize(*os, parameters); @@ -228,160 +374,158 @@ void cMainThread::run() { emit setGraph(graph.printGraph()); - // process the theoretical spectra - *os << "Starting the graph reader... "; - // mode 0 = get candidates - graph.startGraphReader(candidates, terminatecomputation); - *os << "ok" << endl << endl; + *os << "Calculating the number of paths forming peptide sequence candidates... "; + long long unsigned count = 0; + long long unsigned lastcount = 0; + graph.startGraphReader(candidates, count, 1, terminatecomputation); + while (graphreaderisworking) { + while (count >= lastcount + 1000000) { + lastcount += 1000000; + *os << lastcount << " "; + if (lastcount % 10000000 == 0) { + *os << endl; + } + } + usleep(1000); + } + *os << " ok" << endl; + *os << "Number of paths found: " << count << endl << endl; + + if (count > maximumcandidates) { + *os << "The number of sequence candidates is too high. The identification would be very time-consuming. Please, change the settings and search again." << endl << endl; + *os << "Aborted." << endl; + emitEndSignals(); + endNow(); + return; + } + + count = 0; + graph.startGraphReader(candidates, count, 0, terminatecomputation); } - // comparison of a theoretical spectrum - else { + + // single comparison of a peaklist with a theoretical spectrum + if (parameters.mode == singlecomparison) { vector v; cCandidate c; - cBrick b; - string s; - int startmodifid, endmodifid, middlemodifid; - int branchstart = -1; - int branchend = -1; + int startmodifid, endmodifid, middlemodifid, branchstart, branchend; - if ((parameters.peptidetype == linear) || (parameters.peptidetype == branched) || (parameters.peptidetype == lasso) || (parameters.peptidetype == linearpolysaccharide)) { + cSequence sequence; + sequence.setNTterminalModification(parameters.searchedsequenceNtermmodif); + sequence.setCTterminalModification(parameters.searchedsequenceCtermmodif); + sequence.setBranchModification(parameters.searchedsequenceTmodif); - if ((parameters.peptidetype == linear) || (parameters.peptidetype == branched) || (parameters.peptidetype == linearpolysaccharide)) { - startmodifid = -1; - endmodifid = -1; - } - else { - startmodifid = 0; - endmodifid = 0; - } + errormessage = ""; + if (!checkModifications(parameters, sequence, startmodifid, endmodifid, middlemodifid, errormessage)) { + *os << endl << "Error: " << errormessage << endl; + emitEndSignals(); + endNow(); + return; + } - if ((parameters.peptidetype == branched) || (parameters.peptidetype == lasso)) { - middlemodifid = -1; - } - else { - middlemodifid = 0; - } + parseBranch(parameters.peptidetype, parameters.searchedsequence, v, branchstart, branchend); - for (int i = 0; i < (int)parameters.searchedmodifications.size(); i++) { + vector netmp; + c.setCandidate(v, netmp, startmodifid, endmodifid, middlemodifid, branchstart, branchend); + candidates.getSet().insert(c); + + graphreaderisworking = false; + } - if ((parameters.peptidetype == linear) || (parameters.peptidetype == branched) || (parameters.peptidetype == linearpolysaccharide)) { - if (parameters.searchedmodifications[i].name.compare(parameters.searchedsequenceNtermmodif) == 0) { - startmodifid = i; - } - if (parameters.searchedmodifications[i].name.compare(parameters.searchedsequenceCtermmodif) == 0) { - endmodifid = i; - } - } + // database search - MS/MS mode + if (parameters.mode == databasesearch) { + string composition; + vector v; + cCandidate c; + vector netmp; + int startmodifid, endmodifid, middlemodifid, branchstart, branchend; - if ((parameters.peptidetype == branched) || (parameters.peptidetype == lasso)) { - if (parameters.searchedmodifications[i].name.compare(parameters.searchedsequenceTmodif) == 0) { - middlemodifid = i; - } - } + bool calculatesummaries = false; - } + for (int i = 0; i < parameters.sequencedatabase.size(); i++) { - if (startmodifid == -1) { - *os << endl << "Error: Unknown N-terminal modification is used." << endl; - emitEndSignals(); - endNow(); - return; - } + v.clear(); + c.clear(); + netmp.clear(); + errormessage = ""; - if (endmodifid == -1) { - *os << endl << "Error: Unknown C-terminal modification is used." << endl; - emitEndSignals(); - endNow(); - return; + // check peptide type + if (!calculatesummaries && (parameters.peptidetype != parameters.sequencedatabase[i].getPeptideType())) { + continue; } - if (middlemodifid == -1) { - *os << endl << "Error: Unknown branch modification is used." << endl; - emitEndSignals(); - endNow(); - return; + // check format of sequence + if (!calculatesummaries && !checkRegex(parameters, parameters.sequencedatabase[i].getSequence(), errormessage)) { + *os << "Ignored sequence: " << errormessage << endl; + continue; } - - } - s = parameters.searchedsequence; - if ((parameters.peptidetype == branched) || (parameters.peptidetype == lasso)) { - int i = 0; - while (i < (int)s.size()) { - if (s[i] == '\\') { - s.erase(s.begin() + i); - } - else { - i++; - } + // replace acronyms of bricks by ids + composition = parameters.sequencedatabase[i].getSequence(); + if (!parameters.bricksdatabase.replaceAcronymsByIDs(composition, errormessage)) { + *os << "Ignored sequence: " << errormessage << endl; + continue; } - for (int i = 0; i < (int)s.size(); i++) { - if (s[i] == '(') { - if (i > 0) { - b.clear(); - b.setComposition(s.substr(0, i - 1), false); - branchstart = getNumberOfBricks(b.getComposition()); - s[i] = '-'; - } - else { - s.erase(s.begin()); - branchstart = 0; - } - break; - } + // check whether modification are defined + if (!checkModifications(parameters, parameters.sequencedatabase[i], startmodifid, endmodifid, middlemodifid, errormessage)) { + *os << "Ignored sequence: " << errormessage << endl; + continue; } - for (int i = 0; i < (int)s.size(); i++) { - if (s[i] == ')') { - b.clear(); - b.setComposition(s.substr(0, i - 1), false); - branchend = getNumberOfBricks(b.getComposition()) - 1; - if (i < (int)s.size() - 1) { - s[i] = '-'; - } - else { - s.erase(s.begin() + i); - } - break; - } + // parse branch of a branched or a lasso peptide + parseBranch(parameters.sequencedatabase[i].getPeptideType(), composition, v, branchstart, branchend); + + // set candidate and check precursor mass error + c.setCandidate(v, netmp, startmodifid, endmodifid, middlemodifid, branchstart, branchend); + if (!calculatesummaries && !isInPpmMassErrorTolerance(uncharge(parameters.precursormass, parameters.precursorcharge), c.getPrecursorMass(parameters.bricksdatabase, ¶meters), parameters.precursormasserrortolerance)) { + continue; } - if (branchend <= branchstart) { - branchstart = -1; - branchend = -1; + c.setName(parameters.sequencedatabase[i].getName()); + candidates.getSet().insert(c); + + if (calculatesummaries) { + *os << c.getSummaryFormula(parameters, parameters.sequencedatabase[i].getPeptideType()) << endl; } } - b.clear(); - b.setComposition(s, false); - b.explodeToStringComposition(v); - vector tmp; - c.setCandidate(v, tmp, startmodifid, endmodifid, middlemodifid, branchstart, branchend); + if (calculatesummaries) { + *os << endl << "done." << endl; + emit safeExit(); + return; + } + + *os << "Number of candidates in the precursor mass error tolerance found: " << candidates.size() << endl; - candidates.getSet().insert(c); graphreaderisworking = false; } - *os << "Comparing theoretical spectra of candidates with the peak list... " << endl; - *os << "Permutations of combinations of bricks: "; - if (parameters.generatebrickspermutations) { - *os << "on" << endl; - } - else { - *os << "off" << endl; + + // database search - MS mode + if (parameters.mode == dereplication) { + *os << "Comparing theoretical peaks with the peak list... " << endl; + cTheoreticalSpectrum ts; + ts.compareMSSpectrum(¶meters); + theoreticalspectra.initialize(*os, parameters, &graph); + theoreticalspectra.add(ts); + *os << " ok" << endl; } - theoreticalspectra.initialize(*os, parameters, &graph); - if (theoreticalspectra.parallelCompareAndStore(candidates, terminatecomputation) == -1) { - emitEndSignals(); - endNow(); - return; + + + if ((parameters.mode == denovoengine) || (parameters.mode == singlecomparison) || (parameters.mode == databasesearch)) { + *os << "Comparing theoretical spectra of candidates with the peak list... " << endl; + theoreticalspectra.initialize(*os, parameters, &graph); + if (theoreticalspectra.parallelCompareAndStore(candidates, terminatecomputation) == -1) { + emitEndSignals(); + endNow(); + return; + } + *os << " ok" << endl; } - *os << "ok" << endl; /* *os << endl << "Explanation list of peaks (m/z ratio: etc.):" << endl; @@ -437,7 +581,7 @@ void cMainThread::emitStartSignals() { emit enableStopButton(true); emit enableButtonsHandlingResults(false); - if (parameters.mode != 0) { + if (parameters.mode != denovoengine) { emit setGraph(""); } } diff --git a/CycloBranch/gui/cMainThread.h b/CycloBranch/gui/cMainThread.h index aaf9bdf..3d7c680 100644 --- a/CycloBranch/gui/cMainThread.h +++ b/CycloBranch/gui/cMainThread.h @@ -49,6 +49,12 @@ class cMainThread : public QThread { cTheoreticalSpectrumList theoreticalspectra; cParameters parameters; + bool checkModifications(cParameters& parameters, cSequence& sequence, int& startmodifid, int& endmodifid, int& middlemodifid, string& errormessage); + + void parseBranch(peptideType peptidetype, string& composition, vector& vectorcomposition, int& branchstart, int& branchend); + + bool checkRegex(cParameters& parameters, string& sequence, string& errormessage); + public: diff --git a/CycloBranch/gui/cMainWindow.cpp b/CycloBranch/gui/cMainWindow.cpp index 674b712..d4c954f 100644 --- a/CycloBranch/gui/cMainWindow.cpp +++ b/CycloBranch/gui/cMainWindow.cpp @@ -12,6 +12,7 @@ #include #include #include +#include cMainWindow::cMainWindow() { @@ -22,6 +23,7 @@ cMainWindow::cMainWindow() { // items in the menu menuFile = new QMenu(tr("&File"), this); menuSearch = new QMenu(tr("&Search"), this); + menuTools = new QMenu(tr("&Tools"), this); menuView = new QMenu(tr("&View"), this); menuHelp = new QMenu(tr("&Help"), this); @@ -36,6 +38,8 @@ cMainWindow::cMainWindow() { actionStop = new QAction(tr("&Stop"), this); actionStop->setEnabled(false); actionProperties = new QAction(tr("&Settings..."), this); + actionBricksDatabase = new QAction(tr("&Building Blocks Editor"), this); + actionSequenceDatabase = new QAction(tr("&Sequence Database Editor"), this); actionGraph = new QAction(tr("&Graph"), this); actionLog = new QAction(tr("&Log Window"), this); actionHTMLDocumentation = new QAction(tr("&HTML Documentation"), this); @@ -48,7 +52,10 @@ cMainWindow::cMainWindow() { splitter = new QSplitter(this); about = new cAboutWidget(this); + graph = new cGraphWidget(); + bricksdatabasewidget = new cBricksDatabaseWidget(); + sequencedatabasewidget = new cSequenceDatabaseWidget(); parameterswidget = new cParametersWidget(); // additional key shortcuts @@ -65,6 +72,8 @@ cMainWindow::cMainWindow() { connect(actionRun, SIGNAL(triggered()), this, SLOT(run())); connect(actionStop, SIGNAL(triggered()), this, SLOT(stop())); connect(actionProperties, SIGNAL(triggered()), this, SLOT(showProperties())); + connect(actionBricksDatabase, SIGNAL(triggered()), this, SLOT(showBricksDatabase())); + connect(actionSequenceDatabase, SIGNAL(triggered()), this, SLOT(showSequenceDatabase())); connect(actionGraph, SIGNAL(triggered()), this, SLOT(showGraph())); connect(actionLog, SIGNAL(triggered()), this, SLOT(showHideLog())); connect(actionHTMLDocumentation, SIGNAL(triggered()), this, SLOT(showHTMLDocumentation())); @@ -84,7 +93,10 @@ cMainWindow::cMainWindow() { menuSearch->addAction(actionStop); menuSearch->addSeparator(); menuSearch->addAction(actionProperties); + menuTools->addAction(actionBricksDatabase); + menuTools->addAction(actionSequenceDatabase); menuView->addAction(actionGraph); + menuView->addSeparator(); menuView->addAction(actionLog); menuHelp->addAction(actionHTMLDocumentation); menuHelp->addAction(actionPDFManual); @@ -94,6 +106,7 @@ cMainWindow::cMainWindow() { // add items to the main menu menuBar->addMenu(menuFile); menuBar->addMenu(menuSearch); + menuBar->addMenu(menuTools); menuBar->addMenu(menuView); menuBar->addMenu(menuHelp); @@ -110,6 +123,8 @@ cMainWindow::cMainWindow() { about->hide(); graph->hide(); + bricksdatabasewidget->hide(); + sequencedatabasewidget->hide(); parameterswidget->hide(); splitter->setOrientation(Qt::Vertical); @@ -127,6 +142,7 @@ cMainWindow::cMainWindow() { resultsbasecolumncount = 8; resultsspecificcolumncount = 0; + dbsearchspecificcolumncount = 0; resultsDetails.clear(); @@ -161,6 +177,18 @@ void cMainWindow::showAbout() { } +void cMainWindow::showBricksDatabase() { + bricksdatabasewidget->show(); + bricksdatabasewidget->activateWindow(); +} + + +void cMainWindow::showSequenceDatabase() { + sequencedatabasewidget->show(); + sequencedatabasewidget->activateWindow(); +} + + void cMainWindow::showGraph() { graph->show(); graph->activateWindow(); @@ -214,7 +242,7 @@ void cMainWindow::enableRunButtonAndSettings(bool enable) { actionRun->setEnabled(enable); actionProperties->setEnabled(enable); - parameterswidget->hide(); + parameterswidget->close(); } @@ -240,61 +268,89 @@ void cMainWindow::sendTheoreticalSpectrum(cTheoreticalSpectrum theoreticalspectr results->setItem(row, 1, new QTableWidgetItem()); results->item(row, 1)->setData(Qt::DisplayRole, results->rowCount()); - results->setItem(row, 2, new QTableWidgetItem(stripHTML(theoreticalspectrum.getAcronymPeptideNameWithHTMLReferences()).c_str())); - results->setItem(row, 3, new QTableWidgetItem()); - results->item(row, 3)->setData(Qt::DisplayRole, theoreticalspectrum.getCandidate().getSummaryFormula(parameters).c_str()); + if ((parameters.mode == denovoengine) || (parameters.mode == singlecomparison) || (parameters.mode == databasesearch)) { - results->setItem(row, 4, new QTableWidgetItem()); - results->item(row, 4)->setData(Qt::DisplayRole, getNumberOfBricks(theoreticalspectrum.getCandidate().getComposition())); + if (parameters.mode == databasesearch) { + results->setItem(row, 2, new QTableWidgetItem(theoreticalspectrum.getCandidate().getName().c_str())); + } - switch (parameters.peptidetype) - { - case linear: - results->setItem(row, 5, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getStartModifID()].name.c_str())); - results->setItem(row, 6, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getEndModifID()].name.c_str())); - break; - case branched: - results->setItem(row, 5, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getStartModifID()].name.c_str())); - results->setItem(row, 6, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getMiddleModifID()].name.c_str())); - results->setItem(row, 7, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getEndModifID()].name.c_str())); - break; - case cyclic: - results->setItem(row, 5, new QTableWidgetItem()); - results->item(row, 5)->setData(Qt::DisplayRole, theoreticalspectrum.getNumberOfMatchedBricks()); - break; - case lasso: - results->setItem(row, 5, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getMiddleModifID()].name.c_str())); - break; - case linearpolysaccharide: - results->setItem(row, 5, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getStartModifID()].name.c_str())); - results->setItem(row, 6, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getEndModifID()].name.c_str())); - break; - default: - break; - } + results->setItem(row, 2 + dbsearchspecificcolumncount, new QTableWidgetItem(stripHTML(theoreticalspectrum.getAcronymPeptideNameWithHTMLReferences()).c_str())); + + results->setItem(row, 3 + dbsearchspecificcolumncount, new QTableWidgetItem()); + results->item(row, 3 + dbsearchspecificcolumncount)->setData(Qt::DisplayRole, theoreticalspectrum.getCandidate().getSummaryFormula(parameters, parameters.peptidetype).c_str()); + + results->setItem(row, 4 + dbsearchspecificcolumncount, new QTableWidgetItem()); + results->item(row, 4 + dbsearchspecificcolumncount)->setData(Qt::DisplayRole, getNumberOfBricks(theoreticalspectrum.getCandidate().getComposition())); + + switch (parameters.peptidetype) + { + case linear: + results->setItem(row, 5 + dbsearchspecificcolumncount, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getStartModifID()].name.c_str())); + results->setItem(row, 6 + dbsearchspecificcolumncount, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getEndModifID()].name.c_str())); + break; + case branched: + results->setItem(row, 5 + dbsearchspecificcolumncount, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getStartModifID()].name.c_str())); + results->setItem(row, 6 + dbsearchspecificcolumncount, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getMiddleModifID()].name.c_str())); + results->setItem(row, 7 + dbsearchspecificcolumncount, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getEndModifID()].name.c_str())); + break; + case cyclic: + results->setItem(row, 5 + dbsearchspecificcolumncount, new QTableWidgetItem()); + results->item(row, 5 + dbsearchspecificcolumncount)->setData(Qt::DisplayRole, theoreticalspectrum.getNumberOfMatchedBricks()); + break; + case lasso: + results->setItem(row, 5 + dbsearchspecificcolumncount, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getMiddleModifID()].name.c_str())); + break; + case linearpolysaccharide: + results->setItem(row, 5 + dbsearchspecificcolumncount, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getStartModifID()].name.c_str())); + results->setItem(row, 6 + dbsearchspecificcolumncount, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getEndModifID()].name.c_str())); + break; + case other: + default: + break; + } - results->setItem(row, 5 + resultsspecificcolumncount, new QTableWidgetItem()); - results->item(row, 5 + resultsspecificcolumncount)->setData(Qt::DisplayRole, theoreticalspectrum.getNumberOfMatchedPeaks()); + results->setItem(row, 5 + dbsearchspecificcolumncount + resultsspecificcolumncount, new QTableWidgetItem()); + results->item(row, 5 + dbsearchspecificcolumncount + resultsspecificcolumncount)->setData(Qt::DisplayRole, theoreticalspectrum.getNumberOfMatchedPeaks()); - results->setItem(row, 6 + resultsspecificcolumncount, new QTableWidgetItem()); - results->item(row, 6 + resultsspecificcolumncount)->setData(Qt::DisplayRole, theoreticalspectrum.getRatioOfMatchedPeaks()*100); + results->setItem(row, 6 + dbsearchspecificcolumncount + resultsspecificcolumncount, new QTableWidgetItem()); + results->item(row, 6 + dbsearchspecificcolumncount + resultsspecificcolumncount)->setData(Qt::DisplayRole, theoreticalspectrum.getRatioOfMatchedPeaks()*100); - results->setItem(row, 7 + resultsspecificcolumncount, new QTableWidgetItem()); - results->item(row, 7 + resultsspecificcolumncount)->setData(Qt::DisplayRole, theoreticalspectrum.getWeightedIntensityScore()); + results->setItem(row, 7 + dbsearchspecificcolumncount + resultsspecificcolumncount, new QTableWidgetItem()); + results->item(row, 7 + dbsearchspecificcolumncount + resultsspecificcolumncount)->setData(Qt::DisplayRole, theoreticalspectrum.getWeightedIntensityScore()); - for (int i = 0; i < (int)parameters.fragmentionsfortheoreticalspectra.size(); i++) { - results->setItem(row, resultsbasecolumncount + resultsspecificcolumncount + i, new QTableWidgetItem()); - results->item(row, resultsbasecolumncount + resultsspecificcolumncount + i)->setData(Qt::DisplayRole, theoreticalspectrum.getNumberOfMatchedPeaks(parameters.fragmentionsfortheoreticalspectra[i])); - } + for (int i = 0; i < (int)parameters.fragmentionsfortheoreticalspectra.size(); i++) { + results->setItem(row, resultsbasecolumncount + dbsearchspecificcolumncount + resultsspecificcolumncount + i, new QTableWidgetItem()); + results->item(row, resultsbasecolumncount + dbsearchspecificcolumncount + resultsspecificcolumncount + i)->setData(Qt::DisplayRole, theoreticalspectrum.getNumberOfMatchedPeaks(parameters.fragmentionsfortheoreticalspectra[i])); + } - if (theoreticalspectrum.isValid()) { - results->item(row, 0)->setData(Qt::DisplayRole, "*"); - for (int i = 0; i < results->columnCount(); i++) { - results->item(row, i)->setBackground(Qt::yellow); + if ((parameters.peptidetype == cyclic) && parameters.enablescrambling) { + results->setItem(row, results->columnCount() - 1, new QTableWidgetItem()); + results->item(row, results->columnCount() - 1)->setData(Qt::DisplayRole, theoreticalspectrum.getNumberOfScrambledPeaks()); + } + + if (theoreticalspectrum.isValid()) { + results->item(row, 0)->setData(Qt::DisplayRole, "*"); + for (int i = 0; i < results->columnCount(); i++) { + results->item(row, i)->setBackground(Qt::yellow); + } } + + } + + + if (parameters.mode == dereplication) { + results->setItem(row, 2, new QTableWidgetItem()); + results->item(row, 2)->setData(Qt::DisplayRole, theoreticalspectrum.getNumberOfMatchedPeaks()); + + results->setItem(row, 3, new QTableWidgetItem()); + results->item(row, 3)->setData(Qt::DisplayRole, theoreticalspectrum.getRatioOfMatchedPeaks()*100); + + results->setItem(row, 4, new QTableWidgetItem()); + results->item(row, 4)->setData(Qt::DisplayRole, theoreticalspectrum.getWeightedIntensityScore()); } + cSpectrumDetailWidget sd; sd.initialize(¶meters, theoreticalspectrum); sd.setWindowTitle(("Theoretical Spectrum No. " + to_string(row+1)).c_str()); @@ -326,52 +382,88 @@ void cMainWindow::prepareColumns() { case linearpolysaccharide: resultsspecificcolumncount = 2; break; + case other: default: break; } - string s; - results->setColumnCount(resultsbasecolumncount + resultsspecificcolumncount + (int)parameters.fragmentionsfortheoreticalspectra.size()); + if (parameters.mode == databasesearch) { + dbsearchspecificcolumncount = 1; + } + else { + dbsearchspecificcolumncount = 0; + } - results->setHorizontalHeaderItem(0, new QTableWidgetItem("*")); - results->setHorizontalHeaderItem(1, new QTableWidgetItem("Result ID")); - results->setHorizontalHeaderItem(2, new QTableWidgetItem("Peptide Sequence")); - results->setHorizontalHeaderItem(3, new QTableWidgetItem("Neutral Formula")); - results->setHorizontalHeaderItem(4, new QTableWidgetItem("Number of Bricks")); - switch (parameters.peptidetype) - { - case linear: - results->setHorizontalHeaderItem(5, new QTableWidgetItem("N-terminal Modification")); - results->setHorizontalHeaderItem(6, new QTableWidgetItem("C-terminal Modification")); - break; - case branched: - results->setHorizontalHeaderItem(5, new QTableWidgetItem("N-terminal Modification")); - results->setHorizontalHeaderItem(6, new QTableWidgetItem("Branch Modification")); - results->setHorizontalHeaderItem(7, new QTableWidgetItem("C-terminal Modification")); - break; - case cyclic: - results->setHorizontalHeaderItem(5, new QTableWidgetItem("Matched Bricks")); - break; - case lasso: - results->setHorizontalHeaderItem(5, new QTableWidgetItem("Branch Modification")); - break; - case linearpolysaccharide: - results->setHorizontalHeaderItem(5, new QTableWidgetItem("N-terminal Modification")); - results->setHorizontalHeaderItem(6, new QTableWidgetItem("C-terminal Modification")); - break; - default: - break; - } + if ((parameters.mode == denovoengine) || (parameters.mode == singlecomparison) || (parameters.mode == databasesearch)) { + + results->setColumnCount(resultsbasecolumncount + dbsearchspecificcolumncount + resultsspecificcolumncount + (int)parameters.fragmentionsfortheoreticalspectra.size()); + + if ((parameters.peptidetype == cyclic) && parameters.enablescrambling) { + results->setColumnCount(results->columnCount() + 1); + } + + results->setHorizontalHeaderItem(0, new QTableWidgetItem("*")); + results->setHorizontalHeaderItem(1, new QTableWidgetItem("Result ID")); + if (parameters.mode == databasesearch) { + results->setHorizontalHeaderItem(2, new QTableWidgetItem("Name")); + } + results->setHorizontalHeaderItem(2 + dbsearchspecificcolumncount, new QTableWidgetItem("Peptide Sequence")); + results->setHorizontalHeaderItem(3 + dbsearchspecificcolumncount, new QTableWidgetItem("Summary Formula")); + results->setHorizontalHeaderItem(4 + dbsearchspecificcolumncount, new QTableWidgetItem("Number of Bricks")); + + switch (parameters.peptidetype) + { + case linear: + results->setHorizontalHeaderItem(5 + dbsearchspecificcolumncount, new QTableWidgetItem("N-terminal Modification")); + results->setHorizontalHeaderItem(6 + dbsearchspecificcolumncount, new QTableWidgetItem("C-terminal Modification")); + break; + case branched: + results->setHorizontalHeaderItem(5 + dbsearchspecificcolumncount, new QTableWidgetItem("N-terminal Modification")); + results->setHorizontalHeaderItem(6 + dbsearchspecificcolumncount, new QTableWidgetItem("Branch Modification")); + results->setHorizontalHeaderItem(7 + dbsearchspecificcolumncount, new QTableWidgetItem("C-terminal Modification")); + break; + case cyclic: + results->setHorizontalHeaderItem(5 + dbsearchspecificcolumncount, new QTableWidgetItem("Matched Bricks")); + break; + case lasso: + results->setHorizontalHeaderItem(5 + dbsearchspecificcolumncount, new QTableWidgetItem("Branch Modification")); + break; + case linearpolysaccharide: + results->setHorizontalHeaderItem(5 + dbsearchspecificcolumncount, new QTableWidgetItem("N-terminal Modification")); + results->setHorizontalHeaderItem(6 + dbsearchspecificcolumncount, new QTableWidgetItem("C-terminal Modification")); + break; + case other: + default: + break; + } - results->setHorizontalHeaderItem(5 + resultsspecificcolumncount, new QTableWidgetItem("Matched Peaks")); - results->setHorizontalHeaderItem(6 + resultsspecificcolumncount, new QTableWidgetItem("Ratio of Matched Peaks [%]")); - results->setHorizontalHeaderItem(7 + resultsspecificcolumncount, new QTableWidgetItem("Sum of Relative Intensities")); + results->setHorizontalHeaderItem(5 + dbsearchspecificcolumncount + resultsspecificcolumncount, new QTableWidgetItem("Matched Peaks")); + results->setHorizontalHeaderItem(6 + dbsearchspecificcolumncount + resultsspecificcolumncount, new QTableWidgetItem("Ratio of Matched Peaks [%]")); + results->setHorizontalHeaderItem(7 + dbsearchspecificcolumncount + resultsspecificcolumncount, new QTableWidgetItem("Sum of Relative Intensities")); + + for (int i = 0; i < (int)parameters.fragmentionsfortheoreticalspectra.size(); i++) { + results->setHorizontalHeaderItem(resultsbasecolumncount + dbsearchspecificcolumncount + resultsspecificcolumncount + i, new QTableWidgetItem(parameters.fragmentdefinitions[(fragmentIonType)parameters.fragmentionsfortheoreticalspectra[i]].name.c_str())); + } + + if ((parameters.peptidetype == cyclic) && parameters.enablescrambling) { + results->setHorizontalHeaderItem(results->columnCount() - 1, new QTableWidgetItem("Scrambled Peaks")); + } + + } + - for (int i = 0; i < (int)parameters.fragmentionsfortheoreticalspectra.size(); i++) { - results->setHorizontalHeaderItem(resultsbasecolumncount + resultsspecificcolumncount + i, new QTableWidgetItem(parameters.fragmentdefinitions[(fragmentIonType)parameters.fragmentionsfortheoreticalspectra[i]].name.c_str())); + if (parameters.mode == dereplication) { + results->setColumnCount(5); + results->setHorizontalHeaderItem(0, new QTableWidgetItem("*")); + results->setHorizontalHeaderItem(1, new QTableWidgetItem("Result ID")); + results->setHorizontalHeaderItem(2, new QTableWidgetItem("Matched Peaks")); + results->setHorizontalHeaderItem(3, new QTableWidgetItem("Ratio of Matched Peaks [%]")); + results->setHorizontalHeaderItem(4, new QTableWidgetItem("Sum of Relative Intensities")); } + + results->resizeColumnsToContents(); resultsheadersort.resize(results->columnCount()); @@ -556,7 +648,7 @@ void cMainWindow::exportToHTML() { out << "

\n" << parameters.printToString().c_str() << "

"; - if (parameters.mode == 0) { + if (parameters.mode == denovoengine) { out << "

De Novo Graph

\n"; @@ -600,6 +692,12 @@ void cMainWindow::saveResultsFile() { if (outfile.is_open()) { int size; + // write the application name and version + QString appinfo = appname + " " + appversion; + size = (int)appinfo.toStdString().size(); + outfile.write((char *)&size, sizeof(int)); + outfile.write(appinfo.toStdString().c_str(), size); + // store graph window graph->store(outfile); @@ -643,6 +741,23 @@ void cMainWindow::openResultsFile() { string s; cTheoreticalSpectrum theoreticalspectrum; + // read the application name and version + infile.read((char *)&size, sizeof(int)); + s.resize(size); + infile.read(&s[0], s.size()); + QString appinfo = appname + " " + appversion; + if (appinfo.toStdString().compare(s) != 0) { + QMessageBox msgBox; + QString errstr = "The results file cannot be read because it was created by different version "; + errstr += s.c_str(); + errstr += "."; + msgBox.setText(errstr); + msgBox.exec(); + + infile.close(); + return; + } + deleteResults(); resultsDetails.clear(); @@ -696,6 +811,7 @@ cMainWindow::~cMainWindow() { delete menuFile; delete menuSearch; + delete menuTools; delete menuView; delete menuHelp; @@ -706,6 +822,8 @@ cMainWindow::~cMainWindow() { delete actionQuit; delete actionProperties; delete actionRun; + delete actionBricksDatabase; + delete actionSequenceDatabase; delete actionGraph; delete actionLog; delete actionHTMLDocumentation; @@ -718,6 +836,8 @@ cMainWindow::~cMainWindow() { delete about; delete graph; + delete bricksdatabasewidget; + delete sequencedatabasewidget; delete parameterswidget; } diff --git a/CycloBranch/gui/cMainWindow.h b/CycloBranch/gui/cMainWindow.h index 779a713..6a780ee 100644 --- a/CycloBranch/gui/cMainWindow.h +++ b/CycloBranch/gui/cMainWindow.h @@ -16,6 +16,8 @@ #include "gui/cGraphWidget.h" #include "gui/cParametersWidget.h" #include "gui/cSpectrumDetailWidget.h" +#include "gui/cBricksDatabaseWidget.h" +#include "gui/cSequenceDatabaseWidget.h" #include "gui/cMainThread.h" // forward declaration @@ -54,6 +56,7 @@ class cMainWindow : public QMainWindow // items in the menu QMenu* menuFile; QMenu* menuSearch; + QMenu* menuTools; QMenu* menuView; QMenu* menuHelp; @@ -66,6 +69,8 @@ class cMainWindow : public QMainWindow QAction* actionRun; QAction* actionStop; QAction* actionProperties; + QAction* actionBricksDatabase; + QAction* actionSequenceDatabase; QAction* actionGraph; QAction* actionLog; QAction* actionHTMLDocumentation; @@ -82,10 +87,13 @@ class cMainWindow : public QMainWindow cAboutWidget* about; cGraphWidget* graph; + cBricksDatabaseWidget* bricksdatabasewidget; + cSequenceDatabaseWidget* sequencedatabasewidget; cParametersWidget* parameterswidget; int resultsbasecolumncount; int resultsspecificcolumncount; + int dbsearchspecificcolumncount; vector resultsheadersort; @@ -103,6 +111,10 @@ private slots: void showAbout(); + void showBricksDatabase(); + + void showSequenceDatabase(); + void showGraph(); void showProperties(); diff --git a/CycloBranch/gui/cParametersWidget.cpp b/CycloBranch/gui/cParametersWidget.cpp index f5b17b8..6848117 100644 --- a/CycloBranch/gui/cParametersWidget.cpp +++ b/CycloBranch/gui/cParametersWidget.cpp @@ -16,6 +16,7 @@ #include #include #include +#include cParametersWidget::cParametersWidget() { @@ -25,6 +26,7 @@ cParametersWidget::cParametersWidget() { oldsettingsfile = ""; peaklistfilename = ""; brickdatabasefilename = ""; + sequencedatabasefilename = ""; stdbuttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel); stdbuttons->button(QDialogButtonBox::Ok)->setToolTip("Accept changes and hide window."); @@ -54,6 +56,7 @@ cParametersWidget::cParametersWidget() { peptidetype->addItem(tr("Branched")); peptidetype->addItem(tr("Lasso")); peptidetype->addItem(tr("Linear polysaccharide (beta version)")); + //peptidetype->addItem(tr("Other")); peaklistformlayout->addRow(tr("Peptide Type: "), peptidetype); peaklistline = new QLineEdit(); @@ -201,9 +204,11 @@ cParametersWidget::cParametersWidget() { applicationformlayout = new QFormLayout(); mode = new QComboBox(); - mode->setToolTip("De Novo Search Engine (identification mode) - the default mode of the application.\nCompare Spectrum of Searched Sequence with Peaklist (annotation mode) - a theoretical spectrum is generated for an input \"Searched Peptide Sequence\" and it is compared with the peaklist."); + mode->setToolTip("De Novo Search Engine (identification mode) - the default mode of the application.\nCompare Peaklist with Spectrum of Searched Sequence (annotation mode) - a theoretical spectrum is generated for an input \"Searched Peptide Sequence\" and it is compared with the peaklist.\nCompare Peaklist with Database - MS/MS data (identification mode) - the peaklist is compared with theoretical spectra generated from a database of sequences.\nCompare Peaklist with Database - MS data (identification mode) - the peaklist is compared with theoretical peaks generated from a database of sequences."); mode->addItem(tr("De Novo Search Engine")); - mode->addItem(tr("Compare Spectrum of Searched Sequence with Peaklist")); + mode->addItem(tr("Compare Peaklist with Spectrum of Searched Sequence")); + mode->addItem(tr("Compare Peaklist with Database - MS/MS data")); + mode->addItem(tr("Compare Peaklist with Database - MS data")); applicationformlayout->addRow(tr("Mode: "), mode); maximumnumberofthreads = new QSpinBox(); @@ -215,8 +220,8 @@ cParametersWidget::cParametersWidget() { scoretype = new QComboBox(); scoretype->setToolTip("A score for peptide-spectrum matches."); scoretype->addItem(tr("Number of b-ions")); - scoretype->addItem(tr("Number of b-ions + water loss b-ions")); - scoretype->addItem(tr("Number of b-ions + ammonia loss b-ions")); + scoretype->addItem(tr("Number of b-ions + dehydrated b-ions")); + scoretype->addItem(tr("Number of b-ions + deamidated b-ions")); scoretype->addItem(tr("Number of y-ions + b-ions (not for cyclic peptides)")); scoretype->addItem(tr("Number of y-ions (not for cyclic peptides)")); scoretype->addItem(tr("Sum of relative intensities of matched peaks")); @@ -240,7 +245,7 @@ cParametersWidget::cParametersWidget() { applicationformlayout->addRow(tr("Fragment Ion Types in Theoretical Spectra: "), fragmentiontypes); clearhitswithoutparent = new QCheckBox(); - clearhitswithoutparent->setToolTip("When checked, a hit of a peak is not considered when corresponding parent peak is not hit (e.g., a hit of a water loss b-ion is not considered as a hit when corresponding b-ion has not been hit)."); + clearhitswithoutparent->setToolTip("When checked, a hit of a peak is not considered when corresponding parent peak is not hit (e.g., a hit of a dehydrated b-ion is not considered as a hit when corresponding b-ion has not been hit)."); applicationformlayout->addRow(tr("Remove Hits of Fragments without Hits of Parent Fragments: "), clearhitswithoutparent); cyclicnterminus = new QCheckBox(); @@ -272,10 +277,25 @@ cParametersWidget::cParametersWidget() { denovographgroupbox->setLayout(denovographformlayout); + databasesearchformlayout = new QFormLayout(); + + sequencedatabaseline = new QLineEdit(); + sequencedatabaseline->setToolTip("Select the txt file containing a database of sequences."); + sequencedatabasebutton = new QPushButton("Select"); + sequencedatabasebutton->setToolTip("Select the txt file containing a database of sequences."); + sequencedatabaselayout = new QHBoxLayout(); + sequencedatabaselayout->addWidget(sequencedatabaseline); + sequencedatabaselayout->addWidget(sequencedatabasebutton); + databasesearchformlayout->addRow(tr("Sequence Database File: "), sequencedatabaselayout); + + databasesearchgroupbox = new QGroupBox("Database Search"); + databasesearchgroupbox->setLayout(databasesearchformlayout); + + searchedsequenceformlayout = new QFormLayout(); searchedsequence = new QLineEdit(); - searchedsequence->setToolTip("A peptide sequence which you are searching for or a peptide sequence tag.\nA peptide sequence must be entered when \"Mode\" is set up to \"Compare Spectrum of Searched Sequence with Peaklist\".\nOtherwise, it is similar to the option \"Peptide Sequence Tag\" with a difference that a peptide sequence candidate is not removed from the search but it is just highlighted in an output report of peptide sequence candidates."); + searchedsequence->setToolTip("A peptide sequence which you are searching for or a peptide sequence tag.\nA peptide sequence must be entered when \"Mode\" is set up to \"Compare Peaklist with Spectrum of Searched Sequence\".\nOtherwise, it is similar to the option \"Peptide Sequence Tag\" with a difference that a peptide sequence candidate is not removed from the search but it is just highlighted in an output report of peptide sequence candidates."); searchedsequence->setMaxLength(1024*1024); searchedsequenceformlayout->addRow(tr("Sequence: "), searchedsequence); @@ -303,6 +323,7 @@ cParametersWidget::cParametersWidget() { vlayout2 = new QVBoxLayout(); vlayout2->addWidget(applicationgroupbox); vlayout2->addWidget(denovographgroupbox); + vlayout2->addWidget(databasesearchgroupbox); vlayout2->addWidget(searchedsequencegroupbox); vlayout2->addStretch(1); @@ -334,6 +355,7 @@ cParametersWidget::cParametersWidget() { connect(peptidetype, SIGNAL(currentIndexChanged(int)), this, SLOT(updateSettingsWhenPeptideTypeChanged(int))); connect(mode, SIGNAL(currentIndexChanged(int)), this, SLOT(updateSettingsWhenModeChanged(int))); connect(fragmentiontypes, SIGNAL(resetReleased()), this, SLOT(resetFragmentIonTypes())); + connect(sequencedatabasebutton, SIGNAL(released()), this, SLOT(sequenceDatabaseButtonReleased())); updateSettingsWhenPeptideTypeChanged(peptidetype->currentIndex()); @@ -346,6 +368,7 @@ cParametersWidget::cParametersWidget() { lastdirsavesettings = "./Settings/"; lastdirselectpeaklist = "./PeakLists/"; lastdirselectbricksdatabase = "./BrickDatabases/"; + lastdirselectsequencedatabase = "./SequenceDatabases/"; } @@ -412,6 +435,12 @@ cParametersWidget::~cParametersWidget() { delete denovographformlayout; delete denovographgroupbox; + delete sequencedatabaseline; + delete sequencedatabasebutton; + delete sequencedatabaselayout; + delete databasesearchformlayout; + delete databasesearchgroupbox; + delete searchedsequence; delete searchedsequenceNtermmodif; delete searchedsequenceCtermmodif; @@ -572,6 +601,8 @@ void cParametersWidget::loadSettings() { blindedges->setCurrentIndex(settings.value("blindedges", 2).toInt()); + sequencedatabaseline->setText(settings.value("sequencedatabase", "").toString()); + searchedsequence->setText(settings.value("searchedsequence", "").toString()); searchedsequenceNtermmodif->setText(settings.value("searchedsequenceNtermmodif", "").toString()); searchedsequenceCtermmodif->setText(settings.value("searchedsequenceCtermmodif", "").toString()); @@ -651,6 +682,8 @@ void cParametersWidget::saveSettings() { settings.setValue("blindedges", blindedges->currentIndex()); + settings.setValue("sequencedatabase", sequencedatabaseline->text()); + settings.setValue("searchedsequence", searchedsequence->text()); settings.setValue("searchedsequenceNtermmodif", searchedsequenceNtermmodif->text()); settings.setValue("searchedsequenceCtermmodif", searchedsequenceCtermmodif->text()); @@ -683,7 +716,7 @@ void cParametersWidget::peaklistButtonReleased() { void cParametersWidget::brickDatabaseButtonReleased() { - QString filename = QFileDialog::getOpenFileName(this, tr("Select Brick Database..."), lastdirselectbricksdatabase, tr("Text Files (*.txt)")); + QString filename = QFileDialog::getOpenFileName(this, tr("Select Building Blocks Database..."), lastdirselectbricksdatabase, tr("Text Files (*.txt)")); lastdirselectbricksdatabase = filename; if (filename.toStdString().compare("") != 0) { @@ -693,6 +726,17 @@ void cParametersWidget::brickDatabaseButtonReleased() { } +void cParametersWidget::sequenceDatabaseButtonReleased() { + QString filename = QFileDialog::getOpenFileName(this, tr("Select Sequence Database..."), lastdirselectsequencedatabase, tr("Text Files (*.txt)")); + lastdirselectsequencedatabase = filename; + + if (filename.toStdString().compare("") != 0) { + sequencedatabasefilename = filename.toStdString(); + sequencedatabaseline->setText(filename); + } +} + + void cParametersWidget::modificationsInsertButtonReleased() { modificationsTableInsertRow(); } @@ -703,7 +747,31 @@ void cParametersWidget::modificationsRemoveButtonReleased() { } -void cParametersWidget::updateParameters() { +bool cParametersWidget::updateParameters() { + QMessageBox msgBox; + QString errstr; + + if (peaklistline->text().toStdString().compare("") == 0) { + errstr = "A peaklist must be specified."; + msgBox.setText(errstr); + msgBox.exec(); + return false; + } + + if ((brickdatabaseline->text().toStdString().compare("") == 0) && (((modeType)mode->currentIndex() == denovoengine) || ((modeType)mode->currentIndex() == singlecomparison) || ((modeType)mode->currentIndex() == databasesearch))) { + errstr = "A database of building blocks must be specified."; + msgBox.setText(errstr); + msgBox.exec(); + return false; + } + + if ((sequencedatabaseline->text().toStdString().compare("") == 0) && (((modeType)mode->currentIndex() == databasesearch) || ((modeType)mode->currentIndex() == dereplication))) { + errstr = "A sequence database must be specified."; + msgBox.setText(errstr); + msgBox.exec(); + return false; + } + parameters.peptidetype = (peptideType)peptidetype->currentIndex(); parameters.peaklistfilename = peaklistline->text().toStdString(); parameters.precursormass = precursormass->value(); @@ -740,7 +808,7 @@ void cParametersWidget::updateParameters() { i++; } - parameters.mode = mode->currentIndex(); + parameters.mode = (modeType)mode->currentIndex(); parameters.maximumnumberofthreads = maximumnumberofthreads->value(); parameters.scoretype = (scoreType)scoretype->currentIndex(); parameters.hitsreported = hitsreported->value(); @@ -749,23 +817,30 @@ void cParametersWidget::updateParameters() { parameters.fragmentionsfortheoreticalspectra.clear(); int start; - switch ((peptideType)peptidetype->currentIndex()) - { - case linear: - case branched: - start = b_ion; - break; - case cyclic: - start = b_ion; - break; - case lasso: - start = b_ion; - break; - case linearpolysaccharide: - start = ms_nterminal_ion_hplus; - break; - default: - break; + + if ((modeType)mode->currentIndex() == dereplication) { + start = ms_hplus; + } + else { + switch ((peptideType)peptidetype->currentIndex()) + { + case linear: + case branched: + start = b_ion; + break; + case cyclic: + start = b_ion; + break; + case lasso: + start = b_ion; + break; + case linearpolysaccharide: + start = ms_nterminal_ion_hplus; + break; + case other: + default: + break; + } } for (int i = 0; i < fragmentiontypes->getList()->count(); i++) { @@ -783,6 +858,8 @@ void cParametersWidget::updateParameters() { parameters.blindedges = blindedges->currentIndex(); + parameters.sequencedatabasefilename = sequencedatabaseline->text().toStdString(); + parameters.searchedsequence = searchedsequence->text().toStdString(); parameters.originalsearchedsequence = parameters.searchedsequence; parameters.searchedsequenceNtermmodif = searchedsequenceNtermmodif->text().toStdString(); @@ -790,12 +867,15 @@ void cParametersWidget::updateParameters() { parameters.searchedsequenceTmodif = searchedsequenceTmodif->text().toStdString(); oldsettingsfile = settingsfile; + + return true; } void cParametersWidget::updateParametersAndHide() { - updateParameters(); - hide(); + if (updateParameters()) { + hide(); + } } @@ -845,23 +925,29 @@ void cParametersWidget::restoreParameters() { sequencetag->setText(parameters.sequencetag.c_str()); int start; - switch (parameters.peptidetype) - { - case linear: - case branched: - start = b_ion; - break; - case cyclic: - start = b_ion; - break; - case lasso: - start = b_ion; - break; - case linearpolysaccharide: - start = ms_nterminal_ion_hplus; - break; - default: - break; + if (parameters.mode == dereplication) { + start = ms_hplus; + } + else { + switch (parameters.peptidetype) + { + case linear: + case branched: + start = b_ion; + break; + case cyclic: + start = b_ion; + break; + case lasso: + start = b_ion; + break; + case linearpolysaccharide: + start = ms_nterminal_ion_hplus; + break; + case other: + default: + break; + } } for (int i = 0; i < (int)parameters.fragmentionsfortheoreticalspectra.size(); i++) { @@ -875,6 +961,8 @@ void cParametersWidget::restoreParameters() { blindedges->setCurrentIndex(parameters.blindedges); + sequencedatabaseline->setText(parameters.sequencedatabasefilename.c_str()); + searchedsequence->setText(parameters.searchedsequence.c_str()); searchedsequenceNtermmodif->setText(parameters.searchedsequenceNtermmodif.c_str()); searchedsequenceCtermmodif->setText(parameters.searchedsequenceCtermmodif.c_str()); @@ -943,6 +1031,7 @@ void cParametersWidget::updateSettingsWhenPeptideTypeChanged(int index) { cycliccterminus->setDisabled(true); enablescrambling->setDisabled(true); break; + case other: default: break; } @@ -951,11 +1040,15 @@ void cParametersWidget::updateSettingsWhenPeptideTypeChanged(int index) { void cParametersWidget::updateSettingsWhenModeChanged(int index) { - switch (index) + switch ((modeType)index) { - case 0: + case denovoengine: + peptidetype->setDisabled(false); precursormass->setDisabled(false); + precursorcharge->setDisabled(false); precursormasserrortolerance->setDisabled(false); + brickdatabaseline->setDisabled(false); + brickdatabasebutton->setDisabled(false); maximumbricksincombinationbegin->setDisabled(false); maximumbricksincombinationmiddle->setDisabled(false); maximumbricksincombinationend->setDisabled(false); @@ -965,11 +1058,69 @@ void cParametersWidget::updateSettingsWhenModeChanged(int index) { scoretype->setDisabled(false); hitsreported->setDisabled(false); sequencetag->setDisabled(false); + fragmentiontypes->setDisabled(false); + clearhitswithoutparent->setDisabled(false); denovographgroupbox->setDisabled(false); + databasesearchgroupbox->setDisabled(true); + searchedsequence->setDisabled(false); + + updateSettingsWhenPeptideTypeChanged(peptidetype->currentIndex()); + break; + case singlecomparison: + peptidetype->setDisabled(false); + precursormass->setDisabled(true); + precursorcharge->setDisabled(false); + precursormasserrortolerance->setDisabled(true); + brickdatabaseline->setDisabled(false); + brickdatabasebutton->setDisabled(false); + maximumbricksincombinationbegin->setDisabled(true); + maximumbricksincombinationmiddle->setDisabled(true); + maximumbricksincombinationend->setDisabled(true); + maximumcumulativemass->setDisabled(true); + generatebrickspermutations->setDisabled(true); + maximumnumberofthreads->setDisabled(true); + scoretype->setDisabled(true); + hitsreported->setDisabled(true); + sequencetag->setDisabled(true); + fragmentiontypes->setDisabled(false); + clearhitswithoutparent->setDisabled(false); + denovographgroupbox->setDisabled(true); + databasesearchgroupbox->setDisabled(true); + searchedsequence->setDisabled(false); + + updateSettingsWhenPeptideTypeChanged(peptidetype->currentIndex()); + break; + case databasesearch: + peptidetype->setDisabled(false); + precursormass->setDisabled(false); + precursorcharge->setDisabled(false); + precursormasserrortolerance->setDisabled(false); + brickdatabaseline->setDisabled(false); + brickdatabasebutton->setDisabled(false); + maximumbricksincombinationbegin->setDisabled(true); + maximumbricksincombinationmiddle->setDisabled(true); + maximumbricksincombinationend->setDisabled(true); + maximumcumulativemass->setDisabled(true); + generatebrickspermutations->setDisabled(true); + maximumnumberofthreads->setDisabled(false); + scoretype->setDisabled(false); + hitsreported->setDisabled(false); + sequencetag->setDisabled(false); + fragmentiontypes->setDisabled(false); + clearhitswithoutparent->setDisabled(false); + denovographgroupbox->setDisabled(true); + databasesearchgroupbox->setDisabled(false); + searchedsequence->setDisabled(false); + + updateSettingsWhenPeptideTypeChanged(peptidetype->currentIndex()); break; - case 1: + case dereplication: + peptidetype->setDisabled(true); precursormass->setDisabled(true); + precursorcharge->setDisabled(false); precursormasserrortolerance->setDisabled(true); + brickdatabaseline->setDisabled(true); + brickdatabasebutton->setDisabled(true); maximumbricksincombinationbegin->setDisabled(true); maximumbricksincombinationmiddle->setDisabled(true); maximumbricksincombinationend->setDisabled(true); @@ -979,7 +1130,21 @@ void cParametersWidget::updateSettingsWhenModeChanged(int index) { scoretype->setDisabled(true); hitsreported->setDisabled(true); sequencetag->setDisabled(true); + fragmentiontypes->setDisabled(false); + clearhitswithoutparent->setDisabled(true); denovographgroupbox->setDisabled(true); + databasesearchgroupbox->setDisabled(false); + searchedsequence->setDisabled(true); + + resetFragmentIonTypes(); + + modificationsgroupbox->setDisabled(true); + searchedsequenceNtermmodif->setDisabled(true); + searchedsequenceCtermmodif->setDisabled(true); + searchedsequenceTmodif->setDisabled(true); + cyclicnterminus->setDisabled(true); + cycliccterminus->setDisabled(true); + enablescrambling->setDisabled(true); break; default: break; @@ -992,26 +1157,34 @@ void cParametersWidget::resetFragmentIonTypes() { fragmentiontypes->getList()->clear(); fragmentIonType start, end; - switch ((peptideType)peptidetype->currentIndex()) { - case linear: - case branched: - start = b_ion; - end = y_ion_water_and_ammonia_loss; - break; - case cyclic: - start = b_ion; - end = a_ion_water_and_ammonia_loss; - break; - case lasso: - start = b_ion; - end = y_ion_water_and_ammonia_loss; - break; - case linearpolysaccharide: - start = ms_nterminal_ion_hplus; - end = ms_cterminal_ion_kplus; - break; - default: - break; + + if ((modeType)mode->currentIndex() == dereplication) { + start = ms_hplus; + end = ms_MFe4H; + } + else { + switch ((peptideType)peptidetype->currentIndex()) { + case linear: + case branched: + start = b_ion; + end = y_ion_water_and_ammonia_loss; + break; + case cyclic: + start = b_ion; + end = a_ion_water_and_ammonia_loss; + break; + case lasso: + start = b_ion; + end = y_ion_water_and_ammonia_loss; + break; + case linearpolysaccharide: + start = ms_nterminal_ion_hplus; + end = ms_cterminal_ion_kplus; + break; + case other: + default: + break; + } } for (int i = start; i <= end; i++) { diff --git a/CycloBranch/gui/cParametersWidget.h b/CycloBranch/gui/cParametersWidget.h index c2ece92..b5661da 100644 --- a/CycloBranch/gui/cParametersWidget.h +++ b/CycloBranch/gui/cParametersWidget.h @@ -35,6 +35,7 @@ class QGroupBox; class QCheckBox; class QTableWidget; class QListWidget; +class QMessageBox; /** @@ -148,6 +149,13 @@ class cParametersWidget : public QWidget QFormLayout* denovographformlayout; QComboBox* blindedges; + QGroupBox* databasesearchgroupbox; + QFormLayout* databasesearchformlayout; + QLineEdit* sequencedatabaseline; + QPushButton* sequencedatabasebutton; + QHBoxLayout* sequencedatabaselayout; + string sequencedatabasefilename; + QGroupBox* searchedsequencegroupbox; QFormLayout* searchedsequenceformlayout; QLineEdit* searchedsequence; @@ -159,6 +167,7 @@ class cParametersWidget : public QWidget QString lastdirsavesettings; QString lastdirselectpeaklist; QString lastdirselectbricksdatabase; + QString lastdirselectsequencedatabase; void deleteRow(int number); @@ -181,11 +190,13 @@ private slots: void brickDatabaseButtonReleased(); + void sequenceDatabaseButtonReleased(); + void modificationsInsertButtonReleased(); void modificationsRemoveButtonReleased(); - void updateParameters(); + bool updateParameters(); void updateParametersAndHide(); diff --git a/CycloBranch/gui/cSequenceDatabaseWidget.cpp b/CycloBranch/gui/cSequenceDatabaseWidget.cpp new file mode 100644 index 0000000..819b1ea --- /dev/null +++ b/CycloBranch/gui/cSequenceDatabaseWidget.cpp @@ -0,0 +1,534 @@ +#include "gui/cSequenceDatabaseWidget.h" +#include "gui/cMainThread.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +cSequenceDatabaseWidget::cSequenceDatabaseWidget(QWidget* parent) { + this->parent = parent; + + setWindowTitle("Sequence Database Editor"); + + insertrow = new QPushButton(tr("Add Row")); + insertrow->setToolTip("Add a new row."); + removechecked = new QPushButton(tr(" Remove Rows ")); + removechecked->setToolTip("Remove selected rows."); + + close = new QPushButton(tr("Close")); + close->setToolTip("Close the window."); + load = new QPushButton(tr("Load")); + load->setToolTip("Load the database of sequences."); + save = new QPushButton(QString("Save")); + save->setToolTip("Save the database of sequences in the current file. When a file has not been loaded yet, the \"Save As ...\" file dialog is opened."); + saveas = new QPushButton(tr("Save As...")); + saveas->setToolTip("Save the database of sequences into a file."); + + buttons = new QHBoxLayout(); + buttons->addWidget(close); + buttons->addStretch(1); + buttons->addWidget(insertrow); + buttons->addWidget(removechecked); + buttons->addStretch(10); + buttons->addWidget(load); + buttons->addWidget(save); + buttons->addWidget(saveas); + + database = new QTableWidget(0, 0, this); + database->setColumnCount(11); + database->setHorizontalHeaderItem(0, new QTableWidgetItem("")); + database->setHorizontalHeaderItem(1, new QTableWidgetItem("Type")); + database->setHorizontalHeaderItem(2, new QTableWidgetItem("Name")); + database->setHorizontalHeaderItem(3, new QTableWidgetItem("Summary Formula")); + database->setHorizontalHeaderItem(4, new QTableWidgetItem("Monoisotopic Mass")); + database->setHorizontalHeaderItem(5, new QTableWidgetItem("Sequence")); + database->setHorizontalHeaderItem(6, new QTableWidgetItem("N-terminal Modification")); + database->setHorizontalHeaderItem(7, new QTableWidgetItem("C-terminal Modification")); + database->setHorizontalHeaderItem(8, new QTableWidgetItem("Branch Modification")); + database->setHorizontalHeaderItem(9, new QTableWidgetItem("Reference")); + database->setHorizontalHeaderItem(10, new QTableWidgetItem("Preview")); + database->horizontalHeader()->setStretchLastSection(true); + for (int i = 0; i < database->columnCount(); i++) { + database->resizeColumnToContents(i); + } + + headersort.resize(database->columnCount()); + for (int i = 0; i < database->columnCount(); i++) { + headersort[i] = -1; + } + + mainlayout = new QVBoxLayout(); + mainlayout->addWidget(database); + mainlayout->addLayout(buttons); + + progress = new QProgressDialog(this); + progress->setCancelButton(0); + progress->setMinimumDuration(1000); + progress->setWindowModality(Qt::WindowModal); + + connect(database->horizontalHeader(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(headerItemDoubleClicked(int))); + connect(database, SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(itemChanged(QTableWidgetItem *))); + connect(insertrow, SIGNAL(released()), this, SLOT(addRow())); + connect(removechecked, SIGNAL(released()), this, SLOT(removeEmptyRows())); + connect(close, SIGNAL(released()), this, SLOT(closeWindow())); + connect(load, SIGNAL(released()), this, SLOT(loadDatabase())); + connect(save, SIGNAL(released()), this, SLOT(saveDatabase())); + connect(saveas, SIGNAL(released()), this, SLOT(saveDatabaseAs())); + + setLayout(mainlayout); + + resize(1280, 700); + + databasefile = ""; + lastdir = "./SequenceDatabases/"; + sequences.clear(); +} + + +cSequenceDatabaseWidget::~cSequenceDatabaseWidget() { + deleteTable(false); + + for (int i = 0; i < database->columnCount(); i++) { + delete database->horizontalHeaderItem(i); + } + + database->setColumnCount(0); + + delete insertrow; + delete removechecked; + delete close; + delete load; + delete save; + delete saveas; + delete database; + delete buttons; + delete mainlayout; + delete progress; +} + + +void cSequenceDatabaseWidget::closeEvent(QCloseEvent *event) { + closeWindow(); +} + + +void cSequenceDatabaseWidget::deleteTable(bool enableprogress) { + if (enableprogress) { + progress->setLabelText("Clearing the table..."); + progress->setMinimum(0); + progress->setValue(1); + progress->setMaximum(database->rowCount()); + progress->show(); + } + + for (int i = 0; i < database->rowCount(); i++) { + for (int j = 0; j < database->columnCount(); j++) { + if ((j == 0) || (j == 1) || (j == 10)) { + delete database->cellWidget(i, j); + } + else { + delete database->item(i, j); + } + } + + if (enableprogress && ((i == 0) || ((i - 1)/100 != i/100))) { + progress->setValue(i); + } + } + + if (enableprogress) { + progress->setValue(database->rowCount()); + progress->hide(); + } + database->setRowCount(0); +} + + +void cSequenceDatabaseWidget::removeRow(int row) { + for (int i = 0; i < database->columnCount(); i++) { + if ((i == 0) || (i == 1) || (i == 10)) { + delete database->cellWidget(row, i); + } + else { + delete database->item(row, i); + } + } + database->removeRow(row); +} + + +bool cSequenceDatabaseWidget::checkTable() { + + // check summary formulas + for (int i = 0; i < database->rowCount(); i++) { + if (!checkFormula(i, database->item(i, 3)->text().toStdString())) { + return false; + } + } + + // check sequences + for (int i = 0; i < database->rowCount(); i++) { + if (!checkSequence(i)) { + return false; + } + } + + return true; +} + + +bool cSequenceDatabaseWidget::checkFormula(int row, string& summary) { + cSummaryFormula formula; + string errmsg; + formula.setFormula(summary); + if (!formula.isValid(errmsg)) { + QMessageBox msgBox; + QString errstr = "Syntax error in the row no. "; + errstr += to_string(row + 1).c_str(); + errstr += ": "; + errstr += errmsg.c_str(); + msgBox.setText(errstr); + msgBox.exec(); + return false; + } + if (database->item(row, 4)) { + database->item(row, 4)->setData(Qt::DisplayRole, formula.getMass()); + } + return true; +} + + +bool cSequenceDatabaseWidget::checkSequence(int row) { + regex rx; + // [^\\[\\]]+ is used instead of .+ to prevent from a too complex regex error + switch ((peptideType)((QComboBox *)database->cellWidget(row, 1))->currentIndex()) + { + case linear: + case cyclic: + case linearpolysaccharide: + rx = "^\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*$"; + break; + case branched: + rx = "^\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*\\\\\\(\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*\\\\\\)\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*$"; + break; + case lasso: + rx = "(^(\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*)?\\\\\\(\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*\\\\\\)\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*$|^\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*\\\\\\(\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*\\\\\\)(\\[[^\\[\\]]+\\](-\\[[^\\[\\]]+\\])*)?$)"; + break; + case other: + default: + rx = ".*"; + break; + } + + try { + if (!(regex_search(database->item(row, 5)->text().toStdString(), rx))) { + QMessageBox msgBox; + QString errstr = "Row no. "; + errstr += to_string(row + 1).c_str(); + errstr += ". The format of sequence '"; + errstr += database->item(row, 5)->text().toStdString().c_str(); + errstr += "' does not correspond to the sequence type '"; + errstr += getStringFromPeptideType((peptideType)((QComboBox *)database->cellWidget(row, 1))->currentIndex()).c_str(); + errstr += "'."; + msgBox.setText(errstr); + msgBox.exec(); + return false; + } + } + catch (std::regex_error& e) { + QMessageBox msgBox; + QString errstr = "Row no. "; + errstr += to_string(row + 1).c_str(); + errstr += ". cSequenceDatabaseWidget::checkSequence: regex_search failed, error no. "; + errstr += to_string(e.code()).c_str(); + errstr += ". Please, check the sequence: '"; + errstr += database->item(row, 5)->text().toStdString().c_str(); + errstr += "'."; + msgBox.setText(errstr); + msgBox.exec(); + return false; + } + + return true; +} + + +void cSequenceDatabaseWidget::closeWindow() { + hide(); +} + + +void cSequenceDatabaseWidget::loadDatabase() { + QString filename = QFileDialog::getOpenFileName(this, tr("Load the Database of Sequences"), lastdir, tr("Database of Sequences (*.txt)")); + lastdir = filename; + + if (filename.toStdString().compare("") != 0) { + + databasefile = filename; + save->setText(QString(" Save '") + QString(databasefile.toStdString().substr(databasefile.toStdString().rfind('/') + 1, databasefile.toStdString().size()).c_str()) + QString("' ")); + + inputstream.open(filename.toStdString().c_str()); + + if (!inputstream.good()) { + QMessageBox msgBox; + msgBox.setText("Cannot open the file '" + databasefile + "'."); + msgBox.exec(); + } + else { + + deleteTable(true); + + sequences.clear(); + sequences.loadFromPlainTextStream(inputstream); + + progress->setLabelText("Loading the Sequence Databatase..."); + progress->setMinimum(0); + progress->setValue(1); + progress->setMaximum(sequences.size()); + progress->show(); + + cSummaryFormula formula; + database->setRowCount(sequences.size()); + for (int i = 0; i < sequences.size(); i++) { + QCheckBox* checkbox = new QCheckBox(); + database->setCellWidget(i, 0, checkbox); + + QComboBox* combo = new QComboBox(); + for (int j = 0; j <= (int)other; j++) { + combo->addItem(QString(getStringFromPeptideType((peptideType)j).c_str())); + } + combo->setCurrentIndex((int)sequences[i].getPeptideType()); + database->setCellWidget(i, 1, combo); + + database->setItem(i, 2, new QTableWidgetItem(sequences[i].getName().c_str())); + database->setItem(i, 3, new QTableWidgetItem(sequences[i].getSummaryFormula().c_str())); + formula.setFormula(sequences[i].getSummaryFormula()); + database->setItem(i, 4, new QTableWidgetItem()); + database->item(i, 4)->setData(Qt::DisplayRole, formula.getMass()); + database->setItem(i, 5, new QTableWidgetItem(sequences[i].getSequence().c_str())); + database->setItem(i, 6, new QTableWidgetItem(sequences[i].getNTterminalModification().c_str())); + database->setItem(i, 7, new QTableWidgetItem(sequences[i].getCTterminalModification().c_str())); + database->setItem(i, 8, new QTableWidgetItem(sequences[i].getBranchModification().c_str())); + database->setItem(i, 9, new QTableWidgetItem(sequences[i].getReference().c_str())); + + database->setCellWidget(i, 10, new QLabel(sequences[i].getNameWithReferenceAsHTMLString().c_str())); + ((QLabel *)database->cellWidget(i, 10))->setTextFormat(Qt::RichText); + ((QLabel *)database->cellWidget(i, 10))->setTextInteractionFlags(Qt::TextBrowserInteraction); + ((QLabel *)database->cellWidget(i, 10))->setOpenExternalLinks(true); + + if ((i == 0) || ((i - 1)/100 != i/100)) { + progress->setValue(i); + } + } + + for (int i = 0; i < database->columnCount(); i++) { + database->resizeColumnToContents(i); + } + + progress->setValue(sequences.size()); + progress->hide(); + + } + + inputstream.close(); + + } +} + + +void cSequenceDatabaseWidget::saveDatabase() { + + if (!checkTable()) { + return; + } + + if (databasefile.compare("") == 0) { + saveDatabaseAs(); + return; + } + + outputstream.open(databasefile.toStdString().c_str()); + if (!outputstream.good()) { + QMessageBox msgBox; + msgBox.setText("Cannot open the file '" + databasefile + "'."); + msgBox.exec(); + } + else { + + progress->setLabelText("Saving the Sequence Databatase..."); + progress->setMinimum(0); + progress->setMaximum(100); + progress->setValue(1); + progress->show(); + + cSequence seq; + sequences.clear(); + + removeEmptyRows(); + + progress->setMaximum(database->rowCount()); + + for (int i = 0; i < database->rowCount(); i++) { + seq.clear(); + for (int j = 0; j < database->columnCount(); j++) { + switch (j) + { + case 0: + // nothing to do + break; + case 1: + seq.setPeptideType((peptideType)(((QComboBox *)database->cellWidget(i,j))->currentIndex())); + break; + case 2: + seq.setName(database->item(i,j)->text().toStdString()); + break; + case 3: + seq.setSummaryFormula(database->item(i,j)->text().toStdString()); + break; + case 4: + // nothing to do + break; + case 5: + seq.setSequence(database->item(i,j)->text().toStdString()); + break; + case 6: + seq.setNTterminalModification(database->item(i,j)->text().toStdString()); + break; + case 7: + seq.setCTterminalModification(database->item(i,j)->text().toStdString()); + break; + case 8: + seq.setBranchModification(database->item(i,j)->text().toStdString()); + break; + case 9: + seq.setReference(database->item(i,j)->text().toStdString()); + break; + default: + break; + } + } + sequences.push_back(seq); + + if ((i == 0) || ((i - 1)/100 != i/100)) { + progress->setValue(i); + } + } + + sequences.storeToPlainTextStream(outputstream); + + progress->setValue(database->rowCount()); + progress->hide(); + + } + outputstream.close(); +} + + +void cSequenceDatabaseWidget::saveDatabaseAs() { + + if (!checkTable()) { + return; + } + + QString filename = QFileDialog::getSaveFileName(this, tr("Save Settings As..."), lastdir, tr("Database of Sequences (*.txt)")); + lastdir = filename; + + if (filename.toStdString().compare("") != 0) { + databasefile = filename; + save->setText(QString(" Save '") + QString(databasefile.toStdString().substr(databasefile.toStdString().rfind('/') + 1, databasefile.toStdString().size()).c_str()) + QString("' ")); + saveDatabase(); + } +} + + +void cSequenceDatabaseWidget::addRow() { + int row = database->rowCount(); + database->insertRow(row); + + QCheckBox* checkbox = new QCheckBox(); + database->setCellWidget(row, 0, checkbox); + + QComboBox* combo = new QComboBox(); + for (int i = 0; i <= (int)other; i++) { + combo->addItem(QString(getStringFromPeptideType((peptideType)i).c_str())); + } + combo->setCurrentIndex((int)other); + database->setCellWidget(row, 1, combo); + + database->setItem(row, 2, new QTableWidgetItem()); + database->setItem(row, 3, new QTableWidgetItem()); + database->setItem(row, 4, new QTableWidgetItem()); + database->setItem(row, 5, new QTableWidgetItem()); + database->setItem(row, 6, new QTableWidgetItem()); + database->setItem(row, 7, new QTableWidgetItem()); + database->setItem(row, 8, new QTableWidgetItem()); + database->setItem(row, 9, new QTableWidgetItem()); + + database->setCellWidget(row, 10, new QLabel()); + ((QLabel *)database->cellWidget(row, 10))->setTextFormat(Qt::RichText); + ((QLabel *)database->cellWidget(row, 10))->setTextInteractionFlags(Qt::TextBrowserInteraction); + ((QLabel *)database->cellWidget(row, 10))->setOpenExternalLinks(true); +} + + +void cSequenceDatabaseWidget::removeEmptyRows() { + int i = 0; + while (i < database->rowCount()) { + if (((QCheckBox *)(database->cellWidget(i, 0)))->isChecked()) { + removeRow(i); + } + else { + i++; + } + } +} + + +void cSequenceDatabaseWidget::itemChanged(QTableWidgetItem* item) { + // recalculate mass when formula is changed + if (item->column() == 3) { + checkFormula(item->row(), item->text().toStdString()); + } + + // check sequence + if (item->column() == 5) { + checkSequence(item->row()); + } + + // update references preview + if (((item->column() == 2) || (item->column() == 9)) && database->cellWidget(item->row(), 10)) { + cSequence seq; + seq.setName(database->item(item->row(), 2)->text().toStdString()); + seq.setReference(database->item(item->row(), 9)->text().toStdString()); + ((QLabel *)database->cellWidget(item->row(), 10))->setText(seq.getNameWithReferenceAsHTMLString().c_str()); + } +} + + +void cSequenceDatabaseWidget::headerItemDoubleClicked(int index) { + if (headersort[index] == -1) { + database->sortByColumn(index, Qt::AscendingOrder); + headersort[index] = 1; + return; + } + + if (headersort[index] == 0) { + database->sortByColumn(index, Qt::AscendingOrder); + headersort[index] = 1; + } + else { + database->sortByColumn(index, Qt::DescendingOrder); + headersort[index] = 0; + } +} + diff --git a/CycloBranch/gui/cSequenceDatabaseWidget.h b/CycloBranch/gui/cSequenceDatabaseWidget.h new file mode 100644 index 0000000..d568f39 --- /dev/null +++ b/CycloBranch/gui/cSequenceDatabaseWidget.h @@ -0,0 +1,110 @@ +/** + \file cSequenceDatabaseWidget.h + \brief Visualization of the database of sequences. +*/ + + +#ifndef _CSEQUENCEDATABASEWIDGET_H +#define _CSEQUENCEDATABASEWIDGET_H + +#include +#include +#include "core/cSequenceDatabase.h" + +using namespace std; + + +// forward declaration +class QHBoxLayout; +class QVBoxLayout; +class QTableWidget; +class QTableWidgetItem; +class QDialogButtonBox; +class QPushButton; +class QLabel; +class QComboBox; +class QProgressDialog; + + +/** + \brief The widget representing the dialog 'About'. +*/ +class cSequenceDatabaseWidget : public QWidget +{ + Q_OBJECT + +public: + + + /** + \brief The constructor. + \param parent pointer to a parent widget + */ + cSequenceDatabaseWidget(QWidget* parent = (QWidget *)0); + + + /** + \brief The destructor. + */ + ~cSequenceDatabaseWidget(); + + + /** + \brief Handle the window close event. + \param event pointer to QCloseEvent + */ + void closeEvent(QCloseEvent *event); + + +private: + QWidget* parent; + QPushButton* insertrow; + QPushButton* removechecked; + QPushButton* close; + QPushButton* load; + QPushButton* save; + QPushButton* saveas; + QTableWidget* database; + QHBoxLayout* buttons; + QVBoxLayout* mainlayout; + QProgressDialog* progress; + + QString databasefile; + QString lastdir; + ifstream inputstream; + ofstream outputstream; + cSequenceDatabase sequences; + + vector headersort; + + void deleteTable(bool enableprogress); + + void removeRow(int row); + + bool checkTable(); + + bool checkFormula(int row, string& summary); + + bool checkSequence(int row); + +private slots: + + void closeWindow(); + + void loadDatabase(); + + void saveDatabase(); + + void saveDatabaseAs(); + + void addRow(); + + void removeEmptyRows(); + + void itemChanged(QTableWidgetItem* item); + + void headerItemDoubleClicked(int index); + +}; + +#endif \ No newline at end of file diff --git a/CycloBranch/gui/cSpectrumDetailWidget.cpp b/CycloBranch/gui/cSpectrumDetailWidget.cpp index bd8881b..a3b82b3 100644 --- a/CycloBranch/gui/cSpectrumDetailWidget.cpp +++ b/CycloBranch/gui/cSpectrumDetailWidget.cpp @@ -59,19 +59,24 @@ string cSpectrumDetailWidget::getDetailsAsHTMLString() { string s = ""; if (theoreticalspectrum) { - s += "Acronym Peptide Name:
"; - s += theoreticalspectrum->getAcronymPeptideNameWithHTMLReferences(); - s += "

"; - s += "Full Peptide Name:
"; - s += theoreticalspectrum->getRealPeptideName() + "
"; - if ((int)theoreticalspectrum->getPath().size() > 0) { + if (parameters && ((parameters->mode == denovoengine) || (parameters->mode == singlecomparison) || (parameters->mode == databasesearch))) { + + s += "Acronym Peptide Name:
"; + s += theoreticalspectrum->getAcronymPeptideNameWithHTMLReferences(); + s += "

"; + s += "Full Peptide Name:
"; + s += theoreticalspectrum->getRealPeptideName() + "
"; + + if ((int)theoreticalspectrum->getPath().size() > 0) { + s += "
"; + s += "Path in the De Novo Graph:
"; + s += theoreticalspectrum->getPath(); + } + s += "
"; - s += "Path in the De Novo Graph:
"; - s += theoreticalspectrum->getPath(); + } - - s += "
"; s += "Unmatched Measured Peaks:
" + theoreticalspectrum->getUnmatchedPeaks() + "

"; s += "Theoretical Peaks:
" + theoreticalspectrum->getTheoreticalPeaks()->print(true); @@ -90,7 +95,10 @@ cSpectrumDetailWidget::~cSpectrumDetailWidget() { delete graphicalspectrum; delete graphicalspectrumscroll; - delete textedit; + if (parameters && ((parameters->mode == denovoengine) || (parameters->mode == singlecomparison) || (parameters->mode == databasesearch))) { + delete textedit; + } + delete textbrowser; delete zoomin; @@ -118,7 +126,8 @@ cSpectrumDetailWidget::~cSpectrumDetailWidget() { delete formlayout; delete formwidget; - if (parameters) { + if (parameters && ((parameters->mode == denovoengine) || (parameters->mode == singlecomparison) || (parameters->mode == databasesearch))) { + switch (parameters->peptidetype) { case linear: @@ -135,9 +144,12 @@ cSpectrumDetailWidget::~cSpectrumDetailWidget() { break; case linearpolysaccharide: break; + case other: + break; default: break; } + } delete vsplitter1; @@ -168,24 +180,28 @@ void cSpectrumDetailWidget::prepareToShow(peptideType peptidetype) { vsplitter2 = new QSplitter(); vsplitter2->setOrientation(Qt::Vertical); - switch (peptidetype) - { - case linear: - linearwidget = new cLinearWidget(); - break; - case cyclic: - cyclicwidget = new cCyclicWidget(); - break; - case branched: - branchedwidget = new cBranchedWidget(); - break; - case lasso: - lassowidget = new cLassoWidget(); - break; - case linearpolysaccharide: - break; - default: - break; + if (parameters && ((parameters->mode == denovoengine) || (parameters->mode == singlecomparison) || (parameters->mode == databasesearch))) { + switch (peptidetype) + { + case linear: + linearwidget = new cLinearWidget(); + break; + case cyclic: + cyclicwidget = new cCyclicWidget(); + break; + case branched: + branchedwidget = new cBranchedWidget(); + break; + case lasso: + lassowidget = new cLassoWidget(); + break; + case linearpolysaccharide: + break; + case other: + break; + default: + break; + } } graphicalspectrumscroll = new QScrollArea(); @@ -193,10 +209,12 @@ void cSpectrumDetailWidget::prepareToShow(peptideType peptidetype) { graphicalspectrumscroll->setWidget(graphicalspectrum); //graphicalspectrumscroll->setWidgetResizable(true); - textedit = new QTextEdit(); - textedit->setReadOnly(true); - textedit->setFont(QFont("Courier", 9)); - textedit->setLineWrapMode(QTextEdit::NoWrap); + if (parameters && ((parameters->mode == denovoengine) || (parameters->mode == singlecomparison) || (parameters->mode == databasesearch))) { + textedit = new QTextEdit(); + textedit->setReadOnly(true); + textedit->setFont(QFont("Courier", 9)); + textedit->setLineWrapMode(QTextEdit::NoWrap); + } textbrowser = new QTextBrowser(); textbrowser->setReadOnly(true); @@ -260,77 +278,81 @@ void cSpectrumDetailWidget::prepareToShow(peptideType peptidetype) { formlayout->addRow(tr("Hide matched peaks: "), hidematched); formlayout->addRow(tr("Hide unmatched peaks: "), hideunmatched); - // cyclic - if (parameters && theoreticalspectrum && (parameters->peptidetype == cyclic)) { - int r = (int)theoreticalspectrum->getAcronyms().size(); - int hint = (int)theoreticalspectrum->getVisualCoverage().size()/(2*r); + if (parameters && ((parameters->mode == denovoengine) || (parameters->mode == singlecomparison) || (parameters->mode == databasesearch))) { - rotation = new QComboBox(); - rotation->addItem(tr("all")); + // cyclic + if (parameters && theoreticalspectrum && (parameters->peptidetype == cyclic)) { + int r = (int)theoreticalspectrum->getAcronyms().size(); + int hint = (int)theoreticalspectrum->getVisualCoverage().size()/(2*r); - string s; - if (theoreticalspectrum->getVisualCoverage().size() > 0) { - for (int i = 0; i < 2*r; i++) { - s = theoreticalspectrum->getVisualCoverage()[i*hint].name.substr(0, theoreticalspectrum->getVisualCoverage()[i*hint].name.rfind('_')); - rotation->addItem(tr(s.c_str())); + rotation = new QComboBox(); + rotation->addItem(tr("all")); + + string s; + if (theoreticalspectrum->getVisualCoverage().size() > 0) { + for (int i = 0; i < 2*r; i++) { + s = theoreticalspectrum->getVisualCoverage()[i*hint].name.substr(0, theoreticalspectrum->getVisualCoverage()[i*hint].name.rfind('_')); + rotation->addItem(tr(s.c_str())); + } } - } - connect(rotation, SIGNAL(currentIndexChanged(int)), graphicalspectrum, SLOT(rotationChanged(int))); - connect(rotation, SIGNAL(currentIndexChanged(QString)), graphicalspectrum, SLOT(rotationChanged(QString))); - connect(rotation, SIGNAL(currentIndexChanged(int)), cyclicwidget, SLOT(rotationChanged(int))); - formlayout->addRow(tr("Ring break up point: "), rotation); - } + connect(rotation, SIGNAL(currentIndexChanged(int)), graphicalspectrum, SLOT(rotationChanged(int))); + connect(rotation, SIGNAL(currentIndexChanged(QString)), graphicalspectrum, SLOT(rotationChanged(QString))); + connect(rotation, SIGNAL(currentIndexChanged(int)), cyclicwidget, SLOT(rotationChanged(int))); + formlayout->addRow(tr("Ring break up point: "), rotation); + } - // branched - if (parameters && (parameters->peptidetype == branched)) { - trotation = new QComboBox(); - trotation->addItem(tr("all")); - trotation->addItem(tr("1 (left-to-right)")); - trotation->addItem(tr("2 (top-to-right)")); - trotation->addItem(tr("3 (right-to-left)")); - trotation->addItem(tr("4 (left-to-top)")); - trotation->addItem(tr("5 (top-to-left)")); - trotation->addItem(tr("6 (right-to-top)")); - - connect(trotation, SIGNAL(currentIndexChanged(int)), graphicalspectrum, SLOT(trotationChanged(int))); - connect(trotation, SIGNAL(currentIndexChanged(int)), branchedwidget, SLOT(trotationChanged(int))); - formlayout->addRow(tr("Linearized sequence: "), trotation); - } + // branched + if (parameters && (parameters->peptidetype == branched)) { + trotation = new QComboBox(); + trotation->addItem(tr("all")); + trotation->addItem(tr("1 (left-to-right)")); + trotation->addItem(tr("2 (top-to-right)")); + trotation->addItem(tr("3 (right-to-left)")); + trotation->addItem(tr("4 (left-to-top)")); + trotation->addItem(tr("5 (top-to-left)")); + trotation->addItem(tr("6 (right-to-top)")); + + connect(trotation, SIGNAL(currentIndexChanged(int)), graphicalspectrum, SLOT(trotationChanged(int))); + connect(trotation, SIGNAL(currentIndexChanged(int)), branchedwidget, SLOT(trotationChanged(int))); + formlayout->addRow(tr("Linearized sequence: "), trotation); + } - // lasso - if (parameters && theoreticalspectrum && (parameters->peptidetype == lasso)) { - int r = (int)theoreticalspectrum->getAcronyms().size() - (int)theoreticalspectrum->getCandidate().getBranchSize(); - int hint = (int)theoreticalspectrum->getVisualCoverage().size()/(2*r); + // lasso + if (parameters && theoreticalspectrum && (parameters->peptidetype == lasso)) { + int r = (int)theoreticalspectrum->getAcronyms().size() - (int)theoreticalspectrum->getCandidate().getBranchSize(); + int hint = (int)theoreticalspectrum->getVisualCoverage().size()/(2*r); - rotation = new QComboBox(); - rotation->addItem(tr("all")); + rotation = new QComboBox(); + rotation->addItem(tr("all")); - string s; - if (theoreticalspectrum->getVisualCoverage().size() > 0) { - for (int i = 0; i < 2*r; i++) { - s = theoreticalspectrum->getVisualCoverage()[i*hint].name.substr(0, theoreticalspectrum->getVisualCoverage()[i*hint].name.find('_')); - rotation->addItem(tr(s.c_str())); + string s; + if (theoreticalspectrum->getVisualCoverage().size() > 0) { + for (int i = 0; i < 2*r; i++) { + s = theoreticalspectrum->getVisualCoverage()[i*hint].name.substr(0, theoreticalspectrum->getVisualCoverage()[i*hint].name.find('_')); + rotation->addItem(tr(s.c_str())); + } } + + connect(rotation, SIGNAL(currentIndexChanged(int)), graphicalspectrum, SLOT(rotationChanged(int))); + connect(rotation, SIGNAL(currentIndexChanged(QString)), graphicalspectrum, SLOT(rotationChanged(QString))); + connect(rotation, SIGNAL(currentIndexChanged(int)), lassowidget, SLOT(rotationChanged(int))); + formlayout->addRow(tr("Ring break up point: "), rotation); + + trotation = new QComboBox(); + trotation->addItem(tr("all")); + trotation->addItem(tr("1 (left-to-right)")); + trotation->addItem(tr("2 (top-to-right)")); + trotation->addItem(tr("3 (right-to-left)")); + trotation->addItem(tr("4 (left-to-top)")); + trotation->addItem(tr("5 (top-to-left)")); + trotation->addItem(tr("6 (right-to-top)")); + + connect(trotation, SIGNAL(currentIndexChanged(int)), graphicalspectrum, SLOT(trotationChanged(int))); + connect(trotation, SIGNAL(currentIndexChanged(int)), lassowidget, SLOT(trotationChanged(int))); + formlayout->addRow(tr("Linearized sequence: "), trotation); } - connect(rotation, SIGNAL(currentIndexChanged(int)), graphicalspectrum, SLOT(rotationChanged(int))); - connect(rotation, SIGNAL(currentIndexChanged(QString)), graphicalspectrum, SLOT(rotationChanged(QString))); - connect(rotation, SIGNAL(currentIndexChanged(int)), lassowidget, SLOT(rotationChanged(int))); - formlayout->addRow(tr("Ring break up point: "), rotation); - - trotation = new QComboBox(); - trotation->addItem(tr("all")); - trotation->addItem(tr("1 (left-to-right)")); - trotation->addItem(tr("2 (top-to-right)")); - trotation->addItem(tr("3 (right-to-left)")); - trotation->addItem(tr("4 (left-to-top)")); - trotation->addItem(tr("5 (top-to-left)")); - trotation->addItem(tr("6 (right-to-top)")); - - connect(trotation, SIGNAL(currentIndexChanged(int)), graphicalspectrum, SLOT(trotationChanged(int))); - connect(trotation, SIGNAL(currentIndexChanged(int)), lassowidget, SLOT(trotationChanged(int))); - formlayout->addRow(tr("Linearized sequence: "), trotation); } formwidget = new QWidget(); @@ -341,86 +363,102 @@ void cSpectrumDetailWidget::prepareToShow(peptideType peptidetype) { vsplitter1->setStretchFactor(0, 7); vsplitter1->setStretchFactor(1, 3); - switch (peptidetype) - { - case linear: - vsplitter2->addWidget(formwidget); - vsplitter2->addWidget(linearwidget); - vsplitter2->addWidget(textedit); - vsplitter2->setStretchFactor(0, 2); - vsplitter2->setStretchFactor(1, 3); - vsplitter2->setStretchFactor(2, 5); - break; - case cyclic: - vsplitter2->addWidget(formwidget); - vsplitter2->addWidget(cyclicwidget); - vsplitter2->addWidget(textedit); - vsplitter2->setStretchFactor(0, 2); - vsplitter2->setStretchFactor(1, 3); - vsplitter2->setStretchFactor(2, 5); - break; - case branched: - vsplitter2->addWidget(formwidget); - vsplitter2->addWidget(branchedwidget); - vsplitter2->addWidget(textedit); - vsplitter2->setStretchFactor(0, 2); - vsplitter2->setStretchFactor(1, 3); - vsplitter2->setStretchFactor(2, 5); - break; - case lasso: - vsplitter2->addWidget(formwidget); - vsplitter2->addWidget(lassowidget); - vsplitter2->addWidget(textedit); - vsplitter2->setStretchFactor(0, 2); - vsplitter2->setStretchFactor(1, 3); - vsplitter2->setStretchFactor(2, 5); - break; - case linearpolysaccharide: - vsplitter2->addWidget(formwidget); - vsplitter2->addWidget(textedit); - vsplitter2->setStretchFactor(0, 2); - vsplitter2->setStretchFactor(1, 8); - break; - default: - break; - } - - hsplitter->addWidget(vsplitter1); - hsplitter->addWidget(vsplitter2); - hsplitter->setStretchFactor(0, 6); - hsplitter->setStretchFactor(1, 4); - - mainbox = new QHBoxLayout(); - mainbox->addWidget(hsplitter); - setLayout(mainbox); - - resize(1280, 700); - - if (parameters && theoreticalspectrum) { + if (parameters && ((parameters->mode == denovoengine) || (parameters->mode == singlecomparison) || (parameters->mode == databasesearch))) { switch (peptidetype) { case linear: - linearwidget->initialize(parameters, theoreticalspectrum); + vsplitter2->addWidget(formwidget); + vsplitter2->addWidget(linearwidget); + vsplitter2->addWidget(textedit); + vsplitter2->setStretchFactor(0, 2); + vsplitter2->setStretchFactor(1, 3); + vsplitter2->setStretchFactor(2, 5); break; case cyclic: - cyclicwidget->initialize(parameters, theoreticalspectrum); + vsplitter2->addWidget(formwidget); + vsplitter2->addWidget(cyclicwidget); + vsplitter2->addWidget(textedit); + vsplitter2->setStretchFactor(0, 2); + vsplitter2->setStretchFactor(1, 3); + vsplitter2->setStretchFactor(2, 5); break; case branched: - branchedwidget->initialize(parameters, theoreticalspectrum); + vsplitter2->addWidget(formwidget); + vsplitter2->addWidget(branchedwidget); + vsplitter2->addWidget(textedit); + vsplitter2->setStretchFactor(0, 2); + vsplitter2->setStretchFactor(1, 3); + vsplitter2->setStretchFactor(2, 5); break; case lasso: - lassowidget->initialize(parameters, theoreticalspectrum); + vsplitter2->addWidget(formwidget); + vsplitter2->addWidget(lassowidget); + vsplitter2->addWidget(textedit); + vsplitter2->setStretchFactor(0, 2); + vsplitter2->setStretchFactor(1, 3); + vsplitter2->setStretchFactor(2, 5); break; case linearpolysaccharide: + vsplitter2->addWidget(formwidget); + vsplitter2->addWidget(textedit); + vsplitter2->setStretchFactor(0, 2); + vsplitter2->setStretchFactor(1, 8); + break; + case other: break; default: break; } + + } + + if (parameters && (parameters->mode == dereplication)) { + vsplitter2->addWidget(formwidget); + } + + hsplitter->addWidget(vsplitter1); + hsplitter->addWidget(vsplitter2); + hsplitter->setStretchFactor(0, 6); + hsplitter->setStretchFactor(1, 4); + + mainbox = new QHBoxLayout(); + mainbox->addWidget(hsplitter); + setLayout(mainbox); + + resize(1280, 700); + + if (parameters && theoreticalspectrum) { + + if ((parameters->mode == denovoengine) || (parameters->mode == singlecomparison) || (parameters->mode == databasesearch)) { + + switch (peptidetype) + { + case linear: + linearwidget->initialize(parameters, theoreticalspectrum); + break; + case cyclic: + cyclicwidget->initialize(parameters, theoreticalspectrum); + break; + case branched: + branchedwidget->initialize(parameters, theoreticalspectrum); + break; + case lasso: + lassowidget->initialize(parameters, theoreticalspectrum); + break; + case linearpolysaccharide: + break; + case other: + break; + default: + break; + } - graphicalspectrum->initialize(parameters, theoreticalspectrum); + textedit->setHtml(theoreticalspectrum->getCoverageBySeries().c_str()); + + } - textedit->setHtml(theoreticalspectrum->getCoverageBySeries().c_str()); + graphicalspectrum->initialize(parameters, theoreticalspectrum); textbrowser->setHtml(getDetailsAsHTMLString().c_str()); } diff --git a/CycloBranch/parallel/cGraphReaderThread.cpp b/CycloBranch/parallel/cGraphReaderThread.cpp index 6697502..17f4316 100644 --- a/CycloBranch/parallel/cGraphReaderThread.cpp +++ b/CycloBranch/parallel/cGraphReaderThread.cpp @@ -3,7 +3,7 @@ #include "gui/cMainThread.h" -int cGraphReaderThread::getTheoreticalSpectraIter(bool cterminalstartingnode, cCandidateSet* candidates, int nodeid, vector& composition, double precursormass, long long &count, int startmodifID, int endmodifID, int middlemodifID, int middlepos, vector& perspectivepath, double cummass, bool* terminatecomputation) { +int cGraphReaderThread::getTheoreticalSpectraIter(bool cterminalstartingnode, cCandidateSet* candidates, int nodeid, vector& composition, double precursormass, int startmodifID, int endmodifID, int middlemodifID, int middlepos, vector& perspectivepath, double cummass, bool* terminatecomputation) { nodeEdge ne; int tmpmiddlemodifID = 0; int finish; @@ -52,7 +52,7 @@ int cGraphReaderThread::getTheoreticalSpectraIter(bool cterminalstartingnode, cC } composition.push_back((*graph)[nodeid][i].composition); - finish = getTheoreticalSpectraIter(cterminalstartingnode, candidates, (*graph)[nodeid][i].targetnode, composition, precursormass, count, startmodifID, (*graph)[nodeid][i].endmodifID, tmpmiddlemodifID, middlepos, perspectivepath, cummass + (*graph)[nodeid][i].massdifference, terminatecomputation); + finish = getTheoreticalSpectraIter(cterminalstartingnode, candidates, (*graph)[nodeid][i].targetnode, composition, precursormass, startmodifID, (*graph)[nodeid][i].endmodifID, tmpmiddlemodifID, middlepos, perspectivepath, cummass + (*graph)[nodeid][i].massdifference, terminatecomputation); composition.pop_back(); perspectivepath.pop_back(); @@ -78,34 +78,48 @@ int cGraphReaderThread::getTheoreticalSpectraIter(bool cterminalstartingnode, cC if ((parameters->peptidetype == branched) || (parameters->peptidetype == lasso)) { result.getSet().clear(); candidate.prepareBranchedCandidate(result, parameters->peptidetype, terminatecomputation); - candidates->lock(); - for (auto i = result.getSet().begin(); i != result.getSet().end(); ++i) { - candidates->getSet().insert(*i); + if (scanmode == 0) { + candidates->lock(); + for (auto i = result.getSet().begin(); i != result.getSet().end(); ++i) { + candidates->getSet().insert(*i); + } + candidates->unlock(); + } + else { + *count += (long long unsigned)result.getSet().size(); + if (*count > maximumcandidates) { + return -1; + } } - candidates->unlock(); } else { - candidates->lock(); - candidates->getSet().insert(candidate); - candidates->unlock(); - } - - count++; - - candidates->lock(); - size = candidates->size(); - candidates->unlock(); - - while (size >= parameters->maximumnumberofcandidates) { - usleep(1000); - - if (*terminatecomputation) { - return -1; + if (scanmode == 0) { + candidates->lock(); + candidates->getSet().insert(candidate); + candidates->unlock(); + } + else { + *count += 1; + if (*count > maximumcandidates) { + return -1; + } } + } + if (scanmode == 0) { candidates->lock(); size = candidates->size(); candidates->unlock(); + while (size >= parameters->maximumnumberofcandidates) { + usleep(1000); + + if (*terminatecomputation) { + return -1; + } + candidates->lock(); + size = candidates->size(); + candidates->unlock(); + } } } @@ -118,11 +132,11 @@ int cGraphReaderThread::getTheoreticalSpectraIter(bool cterminalstartingnode, cC } -int cGraphReaderThread::reverseCTerminalCandidates(int nodeid, cCandidateSet* candidates, double precursormass, long long &count, int startmodifID, bool* terminatecomputation) { +int cGraphReaderThread::reverseCTerminalCandidates(int nodeid, cCandidateSet* candidates, double precursormass, int startmodifID, bool* terminatecomputation) { vector composition; vector perspectivepath; - if (getTheoreticalSpectraIter((*graph)[nodeid].checkIonAnnotation(y_ion), candidates, nodeid, composition, precursormass, count, startmodifID, 0, 0, -1, perspectivepath, (*graph)[nodeid].getMZRatio(), terminatecomputation) == -1) { + if (getTheoreticalSpectraIter((*graph)[nodeid].checkIonAnnotation(y_ion), candidates, nodeid, composition, precursormass, startmodifID, 0, 0, -1, perspectivepath, (*graph)[nodeid].getMZRatio(), terminatecomputation) == -1) { return -1; } @@ -137,22 +151,24 @@ cGraphReaderThread::cGraphReaderThread() { parameters = 0; os = 0; lastsystemnode = 0; - mode = 0; + scanmode = 0; terminatecomputation = 0; + count = 0; // delete thread when run is finished connect(this, SIGNAL(finished()), this, SLOT(deleteLater())); } -void cGraphReaderThread::initialize(vector& graph, cBricksDatabase& bricksdatabasewithcombinations, cCandidateSet& candidates, cParameters* parameters, cMainThread* os, int lastsystemnode, bool& terminatecomputation) { +void cGraphReaderThread::initialize(vector& graph, cBricksDatabase& bricksdatabasewithcombinations, cCandidateSet& candidates, cParameters* parameters, cMainThread* os, int lastsystemnode, long long unsigned& count, int scanmode, bool& terminatecomputation) { this->graph = &graph; this->bricksdatabasewithcombinations = &bricksdatabasewithcombinations; this->candidates = &candidates; this->parameters = parameters; this->os = os; this->lastsystemnode = lastsystemnode; - this->mode = mode; + this->count = &count; + this->scanmode = scanmode; this->terminatecomputation = &terminatecomputation; } @@ -160,15 +176,14 @@ void cGraphReaderThread::initialize(vector& graph, cBricksData void cGraphReaderThread::run() { vector composition; vector perspectivepath; - long long count = 0; int startmodifID = 0; double unchargedprecursormass = uncharge(parameters->precursormass, parameters->precursorcharge); switch (parameters->peptidetype) { case cyclic: - if (getTheoreticalSpectraIter(false, candidates, 0, composition, unchargedprecursormass, count, 0, 0, 0, -1, perspectivepath, (*graph)[0].getMZRatio(), terminatecomputation) == -1) { - // terminated by user + if (getTheoreticalSpectraIter(false, candidates, 0, composition, unchargedprecursormass, 0, 0, 0, -1, perspectivepath, (*graph)[0].getMZRatio(), terminatecomputation) == -1) { + // terminated return; } break; @@ -178,8 +193,8 @@ void cGraphReaderThread::run() { if (i - 2 > 0) { startmodifID = i - 2; } - if (reverseCTerminalCandidates(i, candidates, unchargedprecursormass, count, startmodifID, terminatecomputation) == -1) { - // terminated by user + if (reverseCTerminalCandidates(i, candidates, unchargedprecursormass, startmodifID, terminatecomputation) == -1) { + // terminated return; } } @@ -189,8 +204,8 @@ void cGraphReaderThread::run() { if (i - 1/*2*/ > 0) { startmodifID = i - 1/*2*/; } - if (reverseCTerminalCandidates(i, candidates, unchargedprecursormass, count, startmodifID, terminatecomputation) == -1) { - // terminated by user + if (reverseCTerminalCandidates(i, candidates, unchargedprecursormass, startmodifID, terminatecomputation) == -1) { + // terminated return; } } @@ -200,12 +215,14 @@ void cGraphReaderThread::run() { if (i - 1 > 0) { startmodifID = i - 1; } - if (reverseCTerminalCandidates(i, candidates, unchargedprecursormass, count, startmodifID, terminatecomputation) == -1) { - // terminated by user + if (reverseCTerminalCandidates(i, candidates, unchargedprecursormass, startmodifID, terminatecomputation) == -1) { + // terminated return; } } break; + case other: + break; default: break; } diff --git a/CycloBranch/parallel/cGraphReaderThread.h b/CycloBranch/parallel/cGraphReaderThread.h index 4084b04..fbaa489 100644 --- a/CycloBranch/parallel/cGraphReaderThread.h +++ b/CycloBranch/parallel/cGraphReaderThread.h @@ -40,12 +40,13 @@ class cGraphReaderThread : public QThread { cParameters* parameters; cMainThread* os; int lastsystemnode; - int mode; + long long unsigned* count; + int scanmode; bool* terminatecomputation; - int getTheoreticalSpectraIter(bool cterminalstartingnode, cCandidateSet* candidates, int nodeid, vector& composition, double precursormass, long long &count, int startmodifID, int endmodifID, int middlemodifID, int middlepos, vector& perspectivepath, double cummass, bool* terminatecomputation); + int getTheoreticalSpectraIter(bool cterminalstartingnode, cCandidateSet* candidates, int nodeid, vector& composition, double precursormass, int startmodifID, int endmodifID, int middlemodifID, int middlepos, vector& perspectivepath, double cummass, bool* terminatecomputation); - int reverseCTerminalCandidates(int nodeid, cCandidateSet* candidates, double precursormass, long long& count, int startmodifID, bool* terminatecomputation); + int reverseCTerminalCandidates(int nodeid, cCandidateSet* candidates, double precursormass, int startmodifID, bool* terminatecomputation); public: @@ -64,9 +65,11 @@ class cGraphReaderThread : public QThread { \param parameters pointer to program parameters \param os pointer to the main thread of the application \param lastsystemnode position of the last system node in the de novo graph + \param count an output number of peptide sequence candidates + \param scanmode 0 = get candidates; 1 = calculate the number of peptide sequence candidates \param terminatecomputation reference to a variable determining that the thread must be stopped */ - void initialize(vector& graph, cBricksDatabase& bricksdatabasewithcombinations, cCandidateSet& candidates, cParameters* parameters, cMainThread* os, int lastsystemnode, bool& terminatecomputation); + void initialize(vector& graph, cBricksDatabase& bricksdatabasewithcombinations, cCandidateSet& candidates, cParameters* parameters, cMainThread* os, int lastsystemnode, long long unsigned& count, int scanmode, bool& terminatecomputation); protected: diff --git a/CycloBranch/parallel/cSpectrumComparatorThread.cpp b/CycloBranch/parallel/cSpectrumComparatorThread.cpp index 1ea74cd..f519934 100644 --- a/CycloBranch/parallel/cSpectrumComparatorThread.cpp +++ b/CycloBranch/parallel/cSpectrumComparatorThread.cpp @@ -106,7 +106,7 @@ void cSpectrumComparatorThread::run() { double score; permutations.getSet().clear(); - if ((parameters->mode == 0) && (parameters->generatebrickspermutations)) { + if ((parameters->mode == denovoengine) && (parameters->generatebrickspermutations)) { candidate.getPermutations(permutations, terminatecomputation); } else { @@ -145,6 +145,8 @@ void cSpectrumComparatorThread::run() { case linearpolysaccharide: theoreticalpeaksrealsize = tsp.compareLinearPolysaccharide(peaklist, *bricksdatabasewithcombinations, false, *rxsequencetag, *rxsearchedsequence); break; + case other: + break; default: break; } diff --git a/CycloBranch/parallel/cSpectrumComparatorThread.h b/CycloBranch/parallel/cSpectrumComparatorThread.h index b716ec4..5431536 100644 --- a/CycloBranch/parallel/cSpectrumComparatorThread.h +++ b/CycloBranch/parallel/cSpectrumComparatorThread.h @@ -26,7 +26,7 @@ bool compareBandAllIonsDesc(cTheoreticalSpectrum& a, cTheoreticalSpectrum& b); /** - \brief Compare scores of two theoretical spectra (number of b-ions + water loss b-ions and all ions as a secondary score). + \brief Compare scores of two theoretical spectra (number of b-ions + dehydrated b-ions and all ions as a secondary score). \param a first theoretical spectrum \param b second theoretical spectrum \retval bool true if the score of \a a is greater than the score of \a b @@ -35,7 +35,7 @@ bool compareBBwaterLossAndAllIonsDesc(cTheoreticalSpectrum& a, cTheoreticalSpect /** - \brief Compare scores of two theoretical spectra (number of b-ions + ammonia loss b-ions and all ions as a secondary score). + \brief Compare scores of two theoretical spectra (number of b-ions + deamidated b-ions and all ions as a secondary score). \param a first theoretical spectrum \param b second theoretical spectrum \retval bool true if the score of \a a is greater than the score of \a b